Screaming Loud

日々是精進

spray-canで何故か同時に接続できずconnection reset by peerが発生する

sprayフレームワークを使っていると、HTTPリクエストの部分はspray-canを利用すると思います。

しばらく、spray-canを使っていたのですが、いくつか重い処理を走らせるとCPUを使い切っていないのに、sprayがリクエストを受け付けなくなってしまい、502 BadGateway を出すようになってしまいました。

そこで色々試したのですが、結果として設定のconfをいじるのではなく、responseを非同期にすればできました。

発生した現象

負荷をかけると以下のような connection reset by peerという502エラーが発生しました。

read: connection reset by peer

パラメータ変更

application.confを色々いじってみましたが、結局実装が間違っていたため、根本的なパフォーマンスは変わりませんでした。

spray/application.conf at master · spray/spray · GitHub
が、本家のベンチマークに使っているconf設定です。

sprayのconfは、

  • reference.conf:デフォルトでsprayに読み込まれているconf。いじれません。
  • application.conf:TypesafeConfigを使っていると自動で起動時に読み込まれるconf。起動時に -Dconfig.file=hoge で変更可能。includeを使うと、他の別confファイルも呼び出せます。

以下のようにいじりました。
spray-stress/application.conf at master · moc-yuto/spray-stress · GitHub


が計測してもパフォーマンスは変わらず。。。

解決策

FutureDirectiveを使うことでした。
使い方は、
spray | Documentation » 1.2.2 / 1.3.2 » spray-routing » Predefined Directives (by trait) » List of predefined directives by trait » FuturesDirectives » onComplete
です。

レスポンスにFutureを組み込むことで、502エラーが発生していたものが一切発生しなくなり、パフォーマンスを一気にあげることができました。

負荷実施

負荷にはvegetaを使用しました。
https://github.com/tsenart/vegeta

vegeta attack -rate=100 -duration=30s -targets=st.txt > st.bin

#st.txt
GET http://localhost:8080/st

Get http://localhost:8080/st に対する結果

Requests      [total, rate]            3000, 100.03
Duration      [total, attack, wait]    44.486880886s, 29.989999801s, 14.496881085s
Latencies     [mean, 50, 95, 99, max]  7.155629141s, 4.389581282s, 22.700462005s, 30.001109336s, 30.003361727s
Bytes In      [total, mean]            0, 0.00
Bytes Out     [total, mean]            0, 0.00
Success       [ratio]                  0.00%
Status Codes  [code:count]             0:3000
Error Set:
Get http://localhost:8080/st: dial tcp 0.0.0.0:0->[::1]:8080: getsockopt: connection refused
Get http://localhost:8080/st: dial tcp 0.0.0.0:0->[::1]:8080: i/o timeout

Get http://localhost:8080/st2 に対する結果

Requests      [total, rate]            3000, 100.03
Duration      [total, attack, wait]    43.215084995s, 29.989999893s, 13.22508510
2s
Latencies     [mean, 50, 95, 99, max]  6.767752449s, 2.182035276s, 30.002461808s
, 30.005316637s, 30.074779909s
Bytes In      [total, mean]            30691, 10.23
Bytes Out     [total, mean]            0, 0.00
Success       [ratio]                  31.10%
Status Codes  [code:count]             200:933  0:2067
Error Set:
Get http://localhost:8080/st2: dial tcp 0.0.0.0:0->[::1]:8080: getsockopt: connection refused
Get http://localhost:8080/st2: EOF
Get http://localhost:8080/st2: read tcp 127.0.0.1:54219->127.0.0.1:8080: read: c
onnection reset by peer
Get http://localhost:8080/st2: read tcp 127.0.0.1:54217->127.0.0.1:8080: read: c
onnection reset by peer

以上のような結果になりました。
さらにパラメータをチューニングした値は、また別途検証したいと思います。

負荷を受けさせたソースはこちら
github.com

ドメイン駆動を実践してみた

以前(http://yuutookun.hatenablog.com/entry/2015/04/04/190539)、ドメイン駆動に関して調べてみてから、ちょこちょこ勉強しつつ、ちょうど自分の新規プロジェクトが動き始めたので、反映させてみた感想をまとめてみました。

概要

・採用したDDD手法
・言語
・パッケージ構成
・どうやって作っていったか
・良かったところ
・悪かったところ

採用したDDD手法

昔ながらのレイヤードであったり、オニオンだったり、ヘキサゴナルだったりありますが、
今回はクリーンアーキテクチャを採用しました。

言語

Scalaで実装しています

パッケージ構成

以下を参考に作成しました。
https://speakerdeck.com/yoskhdia/ddd-plus-clean-architecture-plus-ucdom-fullban
http://qiita.com/kondei/items/41c28674c1bfd4156186
https://speakerdeck.com/usrnameu1/genbafalsekurinakitekutiya-scala-play-puroziekutoshe-ji-falseohua

|- domain # データモデル
     L enum # ドメインに定数
 |- usecase # コアロジック(旧Model), 別パッケージからは呼び出さない
 |- util or service  # 状態を持たないutil系
 L  adaptor #  各usecaseとcontrollerと橋渡し (daoとのやり取りなど)
      |- repository # DBとのアクセス
     |- input # リクエストを受け取る型の定義
     |- output # レスポンスを受け取る型の定義
          L  transformer # repository層とuse case層の型変換
   |- controller # リクエスト受け取り部分
     |- input # リクエストを受け取る型の定義
     |- output # レスポンスを受け取る型の定義
          L  transformer # controller層とuse case層の型変換

進め方

ドメイン駆動開発(以下DDD)は、ドメインエキスパート(そのビジネス領域に関してのエキスパート)との対話によって、設計を行う手法です。
まずは、何がエンティティで何が値オブジェクトかを確定させます。
エンティティに応じた操作をusecaseで記述します。
DBとのアクセスはrepositoryを通じて行います。
http ⇔ controller ⇔ use case ⇔ repository ⇔ DB
entity

良かった点

DBで使うオブジェクトとフロントで使うオブジェクトがキレイに切り離されるので、影響範囲が特定しやすいです。
Entityをベースに考えるので、アウトプットを変えたいと言う時に、アウトプットのオブジェクトを作って、そこにEntityの情報を突っ込むだけで追加できるというのが変更に強いです。

悪かった点

やはり、モデルの変換が多いため、実装がどうしても多くなってしまいます。

所感

まだそこまで大きな範囲には適用していないのですが、DDDの威力が垣間見れました。
特にScalaは、DDDと相性がいいなーと思った次第です。

チームをスケールさせる

社会的にはチームで働くということが多いです。
一般的には一人で働くより複数人で働くほうがスケールするからです。
しかし、チームとは単純な足し算ではなく、マネジメントコストがかかったり、コミュニケーションコストがかかったりするため、悪くなるとマイナスな部分すら出てきます。

自分なりにチームをスケールさせる指針をまとめました。

失敗を受け入れる

リーダーとはメンバーの失敗を受け入れて、チームの成長の責任を負うものです。
メンバーの挑戦を阻害してはいけない。
メンバーの挑戦による失敗はチームでリカバリーをする。

育てるという考えを捨てる

チームを「育てる」という観点で見てしまうと、メンバーがリーダー以上にスケールしない。
チームの成長とは相乗効果で学びあうものだと思っている。
リーダーは持っている知識を惜しみなく出す、メンバーはその知識に対して常に批判的な目を忘れない。
そのサイクルが回っていれば、チームとしての成長は加速するはず。

振り返りの時間を作る

チーム内での違和感や不満をすぐに出せる雰囲気を作るというのは難しい。
なぜなら、言われる人に時間がなくて言うタイミングすら無いときもあるからだ。
そもそも振り返りの時間自体を取るべきである。

雑談をする

人間とは感情の生き物なので、仕事以外の雑談も挟む必要があると思う。
そういう雑談からコミュニケーションのハードルは下がるので。

ここに書いてあることは、結構当たり前ではありますが、逆に出来ていないとチームがギクシャクしてしまいかねないです。

csshxでマルチスクリーンの場合に裏側に隠れてしまう問題

みなさんはcsshxつかってますか??

csshxの素晴らしさに関しては、以下で共有されてます。
人間とウェブの未来 - csshXが素晴らしすぎる件
csshXを使ってリモートホストの一括操作を行う | Developers.IO
複数のサーバーに ssh ログインして一括操作できる csshx を使ってみた感想とメモ |

ただすでにメンテが止まってしまっています。
github.com

なんと、LastUpdateが2012年!

ということで、iTermとか代替品は色々あるのですが、なんだかんだ使いやすいのでcsshxを使ってしまうのですが、
Marveriksにアップデートした辺りから裏っかわに隠れてしまったりして、無理やり持ってきたり、一度出したりしてたんですが、
調べてみたら、issueに上がってました。。。
github.com

解決法

ということで、解消法は以下です!
ここのチェックを外すだけでうごきましたぁぁ。
f:id:yuutookun:20160325111958p:plain

今まで何で調べなかったんだろう。。

追記:自分がよく使うcsshx

csshx --login yuto gate001+5