読者です 読者をやめる 読者になる 読者になる

athome-developer’s blog

不動産情報サービスのアットホームの開発者が発信するブログ

HoloLensが届きました

こんにちは、情報システム部の高野です。

タイトルの通り、弊社にもHoloLens届きました。
ということで開封の儀的なエントリーです。

まず箱
ゲームみたいな箱ですね
f:id:taktak1974:20170126163553j:plain


箱を開けるとこんなオブジェクトが
f:id:taktak1974:20170126163709j:plain


この妙なオブジェクトの中にすべて入ってます。
f:id:taktak1974:20170126163748j:plain


そして本体
f:id:taktak1974:20170126185012j:plain


まだ具体的なアイデアは無いですし
現状のHoloLensでは、弊社サービスとしてなにかをリリースするのは難しいですが
来るべき時に備えて触ってみようかと思ってます。
※ちなみに初日はセットアップだけでクタクタでした。


一緒に開発してみたい方は下記からエントリーをどうぞ
athome-inc.jp

Xamarinを始めてみようかと思います

こんにちは! 情報システム部の高野です。
微妙なタイトルなのは、弊社のモバイルアプリをXamarin化していくぞって決めたわけじゃなく
Xamarinでも行けるか検証し始めたのでこんなタイトルなのです。
ちゃんとXamarinで作ることが決まれば「Xamarin始めました」になりますね。

ということで既存のiOSアプリ、Androidアプリと同様のものをXamarinで作り始めています。
まだまだ慣れていないので悪戦苦闘中です。

iOSアプリをビルドするにもデバッグするにもmacOSが必要ってことで
会社で買ってもらいました。


Mac Book Pro late 2016、13インチのTouch Barなしモデルです。*1
ポートがUSB-Cしかないのは結構きびしいですね。
あと個人的には、キーストロークが浅すぎてつらい。

なにはともあれXamarinがんばろう!

*1:MBPの写真撮って載せようと思ったけど全然いい写真が撮れない

ASP.NET Coreのパフォーマンス検証

こんにちは! 情報システム部の高野です。
前回、予告した通りASP.NET Coreのパフォーマンス検証をしました。
dblog.athome.co.jp

検証環境
  1. IISにAspNetCoreModuleを使ってホスト
  2. IISからKestrelへリバースプロキシ
  3. WindowsのNginxからKestrelへリバースプロキシ
  4. CentOSのNginxからKestrelへリバースプロキシ

の4種類です。

OSは、
Windows 2016 server
CentOS7.2
です。

.NET Coreのバージョンは1.0.1です。

チューニングは基本的になにもせずデフォルト値でなにが速いのかを検証します。
リバースプロキシしている3つは、Webサーバとアプリケーションは同サーバで実行しています。
CentOSの方は、Kestrelもサービス化して常駐するようにしました。
Windowsのリバースプロキシしている方は、サービス化がちょっと面倒だったので
コンソールから起動している状態です。

負荷

tsungというツールで1秒ごとに100ユーザずつ増やしながら
1ユーザが10リクエストするようにして1分間流します。

検証項目

tsungの結果とASP.NET Core、各Webサーバのログから出しています。
ASP.NET Coreのログは、NLogを使い
Asyncにしてバッファリングもしてログの書き出しがパフォーマンスになるべく影響のないようにしてあります。

検証するプログラムは、下記のただ文字列を返すだけのものです。

public class PerfTestController : Controller
{
    public string Greeting()
    {
        return "Hello World!";
    }
}
結果

各ログの平均値

tsung Webログ APログ
01.IISホスト 1.81 ms 1ms 0.14ms
02.IISリバプロ 5,310ms 5,260ms 1.54ms
03.Win+Nginx 530ms 832ms 1.63ms
04.CentOS+Nginx 1.90ms 0.74ms 0.09ms

Windowsでのリバースプロキシが間違ってるんじゃないってくらい遅いです。
特にWindowsのNginxの方は、Webサーバのログの方がtsungより大きくなっているので
明らかにおかしいのですが、何回やってもこのような結果になりました。
Webサーバのログを見てもIISにホストした場合やCentOS+Nginxに比べて
1秒間に半分ほどしかリクエストを捌けてません。

なんで同じようにリバースプロキシしているのにWindowsの方が圧倒的に遅いのか
納得いかなかったので
CentOSの方もサービス化せずにコンソールで起動して検証をしてみました。

tsung Webログ APログ
CentOS+Nginx 11,1640ms 5,572ms 757ms

やっぱりコンソールで起動するとかなり遅くなりました。*1

まとめ

この結果だけを見るとASP.NET Coreを動かすのは
ちゃんとサービス化して動かした方が良いってことですね。
まあ上でも書いた通りWindowsでサービス化するのはちょっと面倒なので
IISにAspNetCoreModuleを入れてホストするか
Linuxでリバースプロキシするのが良さそうです。

今回は、文字列を返すだけのAPIで検証してみたのですが
今度は普通にありそうなユースケースで検証してみたいと思います。

*1:上記は、dotnet run -c Release で起動した結果ですがpublishしてから dotnet sample.dllで起動しても同様の結果になりました。

CentOS7でASP.NET Coreを動かす

こんにちは、情報システム部の高野です。
.Net CoreをLinuxで動かす事例は、Ubuntuが多いのですが
弊社は基本的にRed Hat Enterprise Linuxを利用しているので
検証も同様にRed Hat Enterprise Linuxで行うべく
CentOS上にASP.NET Coreの環境を構築したのですが
結構、はまったので手順を残しておきます。*1

環境

CentOS7.2
dotnet Core1.0.1
nginx 1.10.2

dotnetのセットアップ

.NET - Powerful Open Source Development
ここに書いてある通りにやれば動かすことはできました。
Webのプロジェクトを作成してdotnet runをすればWebサイトも普通に動くはずです。
※この時点ではkestrelをターミナルで実行して動かしてます。

nginxのセットアップ

軽く動作を確認するだけならkestrelだけでも問題ないのですが
ちゃんと運用する際には、nginxなどのWebサーバが必要になります。

yumでnginxをインストールします。

> sudo yum install http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
> sudo yum install --enablerepo=nginx nginx

設定ファイルを修正します。
/etc/nginx/conf.d/default.confをテキストエディタで開き下記のように修正します。
※locationの部分だけです

server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/log/host.access.log  main;

    location / {
        proxy_pass http://localhost:5000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection keep-alive;
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
   ・・・
}


SELinuxを停止します。
(本番環境では停止せずにちゃんと設定してください)

> sudo setenforce 0

※再起動後も停止したままにするなら /etc/selinux/config を書き換えます。

nginxを起動します

> sudo systemctl start nginx.service
> sudo systemctl enable nginx.service

2行目は、再起動時もnginxが起動するようにするためのものなので
必要に応じて実行してください。

dotnet runでkestrelを実行します。
curlでもブラウザでもいいので80番ポートにアクセスします。
作成したWebサイトが表示されればリバースプロキシの設定は完了です。

kestrelをバックグラウンドで実行する

このままだとターミナルを閉じるとWebサイトが利用できなくなってしまうので
バックグラウンドでkestrelを実行するようにします。

Publish to a Linux Production Environment
当初はこちらにあるようにSuperVisorを使って常駐化しようとしたのですが
CentOS7では、どうやらSuperVisorなどをインストールしなくても常駐化が簡単にできるようなので
そちらのやり方で実行しました。

/etc/systemd/systemにkestrel.serviceというファイルを作成します。
(ファイル名は、任意なのでkestrelでなくても良いです)

[Unit]
Description=kestrel server
After=syslog.target network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/dotnet /home/hoge/sampleApp/SampleApp.dll
WorkingDirectory=/home/hoge/sampleApp
KillMode=process
Restart=always
User=hoge
Group=hoge

[Install]
WantedBy=multi-user.target

ExecStartとWorkingDirectoryは任意のパスです。
dotnet publishでデプロイしたディレクトリを指定します。*2

あとは、nginx同様起動します

> sudo systemctl start kestrel.service
> sudo systemctl enable kestrel.service


これでターミナルを閉じても再起動後でもWebサイトにアクセスできます。
分かってしまえば結構簡単ですね

*1:現在、AzureでもRHELは選択できるのですが、つい癖でCentOSを選択してしまいました

*2:通常のテンプレートだとdotnet publishをするときにnpm等が必要になります

.NET Coreのパフォーマンスが気になる件

こんにちは! 情報システム部の高野です。
.NET Coreは、WindowsLinuxMacで動く新しい.NETの環境です。
気になっているのは、Webアプリケーションを動かすならWindowsLinuxどちらが速いのかってことです。
折角、マルチプラットフォームに対応したのでより良い環境で動かしたいですからね
(まあ速いってのは1つの要素に過ぎないですけどね)

今回は、序章としてコンソールアプリケーションでパフォーマンスの確認をしてみたいと思います。

環境

Azure上にWindows2016 ServerとCentOS7.2を構築。
どちらもDS2_V2 Standard(CPU:2コア・メモリ:7GB)でSSDを選択。
※特に設定などは弄らずに素のままで検証してます。

.NET Coreのバージョンは1.0.1です。

検証用プログラム

適当に負荷が、かかれば良いのでかなり適当ですが

public static void Main(string[] args)
{
    var a = Enumerable.Range(1, 10000);

    for(var i = 1; i <= 10000; i++)
    {
        var b = a.Where(x => x % i == 0).ToArray();
    }
}
検証結果

上記プログラムを10回実行した平均です。

Windows2016:1,204.4ms
CentOS7.2:1,125.5ms

まあ誤差の範囲ですね
でも何回かやってもCentOSの方が速かったです。
ちなみに自分のSurface Pro3で実行したら3秒以上かかりました。
(自分のPCの遅さが浮き彫りに!)

上記は、dotnet runコマンドで実行した結果なのですが、
これだとdebugモードで実行しているってことに気付いたので
dotnet run -c Release で実行してみた結果、こうなりました。

Windows2016:997.7ms
CentOS7.2:945.9ms

ちゃんと速くなってる!(当たり前ですね)


次回は、本題のASP.NET Coreの検証を実施してみたいと思います。

LodashとLINQの対応表にRubyを足してみる(そしてSymbol#to_proc)

情報システム部の山田です。こんにちは。
先日当社の高野さんがこんな記事を書いてくれたので乗っかってみよう!というわけで一覧表に、Rubyだとこれだよっ!を追加してみました。

Rubyだとこのメソッド

LINQ Lodash Ruby
射影 Select map map, collect
フィルター Where filter select, find_all
昇順ソート OrderBy orderBy sort, sort_by
降順ソート OrderByDescending orderBy sort, sort_by
グループ化 GroupBy groupBy group_by
存在確認 Any some any?
最初の要素取得 First find first
最後の要素取得 Last findLast last
一意の要素取得 Distinct uniq uniq
和集合 Union union Set#union, Set#+
差集合 Except difference Set#difference, Set#-
積集合 Intersect intersection Set#intersection, Set#&
平坦化 SelectMany flatten flatten
スキップ Skip drop delete, delete_at
指定数要素取得 Take take take
合計計算 Sum sum inject(&:+), reduce(&:+), sum*1
最大値取得 Max max max
最小値取得 Min min min
集合関連のメソッドについて

集合に関してはArrayクラスではなくSetクラスのメソッドになります。
Setもうまく使うとかなり便利なので、この機に見直しておくのもおすすめです。
library set (Ruby 2.3.0)

合計計算について

合計計算のsumメソッドはRuby本体にはないのですが、RailsというかActiveSupportにはsumがあります。
Rails全部じゃなく、ActiveSupportだけ導入するのもアリだと思いますし、逆にRailsからRuby始めましたという人にとっては、当たり前にあるメソッドが実はActiveSupportのものだったという点を把握しておくと、後々役立つのではないかと思います。
ほかにも便利なメソッドが追加されるので、こちらも一度見ておくと色々捗りますよ。
Active Support コア拡張機能 | Rails ガイド

Symbol$to_procの話

で、「合計計算」がなんだかよくわからない感じになっているのですが、sumを使わない(使えない)場合はinject(もしくは別名のreduce)というたたみこみを行うメソッドを使います。
実はActiveSupportsumメソッドの実装もそうなってるのですけど。

injectメソッドを普通に書き下すと

[1, 2, 3, 4, 5].inject {|result, item| result += item }

みたいな感じになるのですが、ブロック内で単純なメソッドを適用するような場合に使われるinstance method Symbol#to_proc (Ruby 2.3.0)というものがあります。
それを使うと

[1, 2, 3, 4, 5].inject(&:+)

と、かなり短くかけちゃうので、結構使われてます。
injectに限らず、例えば微妙な例ですが、数値をすべて文字列にしたい場合も

[1, 2, 3, 4, 5].map { |item| item.to_s }

ではなく

[1, 2, 3, 4, 5].map(&:.to_s)

となります。
上のSymbol#to_procじゃない書き方すると、レビューで指摘されること間違いなしでしょう。

では。

*1:ActiveSupport使用時

LodashとLINQの対応表

こんにちは! 情報システム部の高野です。
前回、Lodashについて書きましたがその続きです。

Lodashを使ってるとLINQと同様の処理が名前違いで存在するので
サーバー処理とクライアント処理を行ったり来たり書いているとよく、あれ?
ってなることがあります。*1
(じゃ~linq.jsを使えばいいじゃないって意見はそっと棚の上に置いておくことにします)


ということで備忘録的に対応表を作っておこうじゃないかと。
(私がよく使う関数限定ですけど)

LINQ Lodash
射影 Select map
フィルター Where filter
昇順ソート OrderBy orderBy
降順ソート OrderByDescending orderBy
グループ化 GroupBy groupBy
存在確認 Any some
最初の要素取得 First find
最後の要素取得 Last findLast
一意の要素取得 Distinct uniq
和集合 Union union
差集合 Except difference
積集合 Intersect intersection
平坦化 SelectMany flatten
スキップ Skip drop
指定数要素取得 Take take
合計計算 Sum sum*2
最大値取得 Max max*3
最小値取得 Min min*4

名前だけ上げておくだけだとイマイチなので特徴的なものをいくつか掘り下げてみます。

使い方

まずは、この関数達をどのように使うのかって話なんですけど


LINQ

var result = src.Where(x => x.Name == "Hoge");


Lodash*5

var result = _(src).filter(x => x.name === "Hoge");

このように基本的にはLINQでもLodashでもほぼ同じような書き方になります。
一部、全然書き方が異なったり他の関数と混同しそうなものがあるのでご紹介します。

ソート

ソートは、LINQとLodashで大きく異なります。


LINQの場合は、昇順と降順で異なる関数を使うことになります。

var asc = src.OrderBy(x => x.Id);
var desc = src.OrderByDescending(x => x.Id);


そして結構はまるポイントなのが、複数キーによるソートです。

var result = src.OrderByDescending(x => x.Name).ThenBy(x => x.Id);

ThenByが正しいのですが、OrderByを重ねてもエラーにはならないので慣れてない人は間違うことが多いです。


一方、Lodash

var result = _(src).orderBy(["name", "id"], ["desc", "asc"]);

1つの関数で昇順・降順も書けますし複数ソートキーも1つの関数で書くことができます。
(文字列での指定なのがちょっと気になるところではありますが)

存在確認

コレクションの中身が存在するかどうかの確認を行うのが
LINQだとAny、Lodashだとsomeになります。
こちらは両方とも条件指定しなければコレクションが空かどうか判断できますし
条件を指定すればその条件に合致するものがあるかどうか判断できます。
Lodashには、これとは別にincludesという関数があります。


someの場合は、条件を式で渡すことができます。

var result = _(src).some(x => x.name === "Hoge"); // Hogeという名前があればtrue


includesの場合は、単純でその値があるかどうかだけを判定します。

var result = _([1,2,3]).includes(2); // この場合はtrue
最初の要素取得

最初の要素を取得するのは、LINQだとFirstかFirstOrDefaultです。
こちらは名前的には分かりやすいのですが
Lodashはfindになります。ちょっと分かりづらいですね。
これらは両方とも条件指定がなければコレクションの最初の要素を取得します。
条件指定すればその条件に合致する最初の要素を取得します。

その他にLodashには、headという関数があり
これがLINQのFirstと同じ動きをするように思えるのですが
こちらは、条件指定ができません。

var result = _([1,2,3]).head(); // この場合は1

紛らわしい……。

ページング

所謂、ページングを行う時に使う関数でLINQではSkipとTakeを使います。
Skipでシーケンスを読み飛ばしTakeで必要数だけ要素を取り出します。
これをLodashでやるには、dropとtakeを使うと同じように書けます。

_([0,1,2,3,4,5,6,7,8,9]).drop(2).take(5).forEach(x => console.log(x));
//  2 3 4 5 6

Skipとdropが同じとは思えなかったので探すのが大変でした。

まとめ

このような感じでLINQとLodashは、同じ名前の関数もあれば
全然違う名前で同じ処理をするものがあります。
また同じ処理を実行する関数でも指定方法が違ったりします。
LINQの関数名はSQLに影響されているものが多く
どちらかと言うとLINQの方が異端なのかもしれませんね。

*1:よく考えればJavaScript標準の集合関数も同じことが言えますね

*2:公式サイトのドキュメントだとMathというカテゴリになっているので注意

*3:sum同様

*4:sum同様

*5:ES5以前のJavaScriptだと書き方が異なります。ES2015かTypeScriptでお試しください。