Rewrite in Finagle

7a1631691f372ed25308ba9ccd727b2d?s=47 iwagami
August 01, 2015
910

Rewrite in Finagle

7a1631691f372ed25308ba9ccd727b2d?s=128

iwagami

August 01, 2015
Tweet

Transcript

  1. finagle のすすめ iwag 2015/08/01 Scala Kansai 2015

  2. 自己紹介 名前:iwag @iwag_org Scala歴:1年半くらい(Scala 力低 い) Scalaのコンパイル時間気になら ない派 技術:C++11, Ruby,

    elasticsearch, Java
  3. 発表について • finagle で検索システムを置き換えをやったので得られた知 見を話します •

  4. 流れ • finagle 紹介 • ケーススタディ紹介 • 感想

  5. finagle とは一言で言うと • twitter が作ってるScala の並列 RPC フレームワーク

  6. 歴史 • 2007年 twitter 開始 ◦ Rails のモノリシックなアプリ • 2009年

    クジラでまくり期 • 2011年 Ruby から Scala または Java に移行している ◦ https://blog.twitter.com/2011/finagle-a-protocol-agnostic-rpc- system ◦ http://readwrite.com/2011/07/06/twitter-java-scala ◦ ちなみにこのときは Scala 2.9.X
  7. finagle は何でないか? • Web Application Framework ではない ◦ Play Framework

    とは違う ◦ ネットワーク・分散システムのフレームワーク ◦ Play にはあるのにな〜が多々ある • ただの Netty のラッパではない ◦ netty.io ▪ あらゆるところで使われる非同期ネットワークライブラリ ◦ 豊富な謎機能 ▪ loadbalancer, serversets, stats,
  8. finagle とはなにか • Future, Service, Filter という中心教義 • それらを使ったスタック群 ◦

    finagle-core ◦ finagle-httpx ◦ finagle-thrift ◦ finagle-mysql ◦ finagle-redis ◦ finagle-memcached ◦ finagle-stats ◦ finagle-serversets
  9. Future • Future は将来手に入る値を持つオブジェクト〜 ◦ Scala 界では常識なので省略 • finagle で使うのは

    scala.concurrent.Future ではなく com. twitter.util.Future • scala.*.Future と同じ機能と考えてよい http://docs.scala- lang.org/ja/overviews/core/futures.html ◦ 同じものが2つあるがどうするつもりなのだろうか…
  10. Service Req 型をうけてFuture[Rep] を返す関数を持つクラス abstract class Service[Req, Rep] { def

    apply(req: Req): Future[Rep] // apply() はリクエストが来 た時に呼ばれる }
  11. Service (2) • 適用範囲が広い ◦ HTTPサーバ:Service[HttpRequest, HttpResponse] ◦ Controller: Service[HttpRequest,

    HttpRequest] ◦ MySQLクライアント:Service[MySQLRequest, MySQLResponse]
  12. 一番簡単なサーバ class Hello extends Service[Request, Response] { override def apply(request:

    Request): Future[Response] = { val resp = Response() resp.contentString = "Hello" Future(resp) } } object Foo extends App { def main = { Await.all( Httpx.serve("0.0.0.0:8080", new Hello)) }
  13. テスト class HelloTest in Specification { "Hellooooo" should { "reply

    hello" in { val res = Await.result(service(Request())) res.contentString must_== "Hello" } } }
  14. Filter abstract class Filter[RepI, RepO, ReqO, ReqI] { def apply(r:ReqI,

    next:Service[ReqO, RepI]): Future[RepO] } abstract class SimpleFilter[Rep, Rep] { def apply(r:Req, next:Service[Req, Rep]): Future[Rep] }
  15. 図解 Filter Service ReqI ReqO RepO RepI Req Rep 組み合わせたものはService

  16. Service と Filter の組み合わせ • andThen で Service と Filter

    とまとめられる val httpStatsFilter = new HttpxStatsFilter[HttpRequest](stats) val statsFilter = new StatsFilter[HttpRequest, HttpResponse](stats) val logging = new QueryLoggingFilter() val retry = new RetryingFilter[HttpRequest, HttpResponse](RetryPolicy.tries(3), new NullTimer) val httpServiceWithFilter: Service[HttpRequest, HttpResponse] = statsFilter andThen httpStatsFilter andThen retry andThen logging andThen mux
  17. いつ使うか • Service に重要じゃない機能を足したい ◦ ログ出力したい、リトライしたい 、リクエスト量の制御をしたい… etc • ⇒

    これらはFilterにして Service と分離することでコア機能 に集中できる
  18. なにがうれしいか • 重要じゃない機能をフィルタにして外にだせる… • Filter&Service は独立してるので • つけたりはずしたりが容易 • テストしやすい

  19. もっと知りたい方は • ドキュメント ◦ http://twitter.github.io/finagle/guide/ • はじめに(自分のqiita記事) ◦ http://www.qiita. com/iwag@github/items/7d03292749d78c145112

    • SmartNews での事例と紹介 ◦ http://www.slideshare.net/ShigekazuTakei/jissenscala- 20150221-smartnews • 詳解 twitter のシステム ◦ http://www.slideshare.net/maruyama97/twitter-49709690
  20. 事例紹介

  21. ケーススタディ • 検索システムのAPIサーバ置き換えプロジェクト • 元:C++で書かれた独自分散フレームワーク

  22. 構成 elasticsearch cluster MySQL cluster zookeeper RPC (zeromq, msgpack) LB

    http 分散フ レーム ワークの ノード クエリ生成 部 (Scala)
  23. 元のシステム • 使ってるミドルウェア ◦ RPC:zeromq, msgpack, 一部 thrift ◦ 名前解決:zookeeper

    ◦ リクエストから内部クエリに変換部:Scala ◦ 検索:elasticsearch ◦ データストア:MySQL • 詳しい話は「ドワンゴ elasticsearch」で検索 • 代替 RPCフレームワークを探した
  24. 余談:libchan • 有力だったの docker/libchan ◦ 説明 http://yugui.jp/articles/881 • go の

    ネットワーク越しに使えるgoroutine • spdy, msgpack • きかなくなっちゃいましたね… ◦ 開発止まっている
  25. finagle 選択の理由 • zookeeper, thrift, Scala ◦ finagle が想定しているシステムに近い •

    内部クエリ生成部(Scala)を発展させてアプリにする • 真の理由: 社内がPlayだらけだったので違うのが使いた かった
  26. service と filter のつくり • parse andThen buildQuery andThen render

    andThen searchES andThen fetchMysql
  27. 最終的には • 分散させなくてよくね?となり ◦ thrift, zookeeper なし • モノリシックなアプリになりましたとさ

  28. 最終的な図 elasticsearch cluster MySQL cluster finagle app LB http finagle

    app finagle app
  29. パフォーマンスアップ • QPS 20% up • JVM最高 • 教訓:C++ だからといって速いわけではない

    ◦ 本システムはレイテンシよりはスループットを重視しており、レイテン シを重視するアプリがだったら別の結果になったと思います
  30. まとめ • finagle よかった • 分散システム→モノリシックアプリ

  31. おまけ:デプロイ方法 • sbt-assembly で jar にまとめて scp • activator なんてものはない

  32. おまけ:使っているライブラリ • finagle 6.24.0 ◦ 2015/08/01時点の最新は 6.25.0 ◦ finagle-httpx ◦

    finagle-mysql ◦ finagle-stats • twitter-server 1.10.0 • elasticsearch 1.4 • play-json 2.3.8 • specs 2 2.4.1 ◦ ちなみにfinagle推奨はscalatestなのでscalatest使ったほうがよい
  33. 感想(よかった点)

  34. Scala最高 • C++比でいいところ ◦ IDE がある ▪ IntelliJ を使用 ◦

    コンパイルが速い ◦ デバッガがある ◦ ライブラリがたくさんある ◦ Scala書けるエンジニアはたくさんいる ▪ もちろんC++を書けるエンジニアもいます
  35. 基本ドキュメントはない(英語にも) • テスト(使い方を知るにはテスト) • ソース • finatraもかなり参考になる • google group

  36. ソースがモナモナしてない • Future, Service, Filter 以外難しい概念なし • ソースも全然モナモナしてなくて読みやすい

  37. 細かいフィルタ作るのが楽しい • テストしやすくてよい • 作ったもの ◦ MaintenanceFilter ◦ LoggingFilter ◦

    RequestIdAppenderFilter ◦ ExceptionCatchingFilter
  38. finagle全部入り • 例えばscala は mysql のライブラリでもいろいろあって悩む がfinagle-mysql で選ばなくていい • finagle-xxx

    ◦ http ◦ redis ◦ mysql ◦ memcached ◦ thrift • なかったら諦める
  39. 他のライブラリを使いたい • finagle では com.twitter.util.Future • 普通のライブラリだと scala.concurrent.Future なんで混ぜ て使うのは難しそう

    • twitter/bijection/ を使えばいいらしい(やってません)
  40. フィルタ間のデータ受け渡し • フィルタを細かくしたい • 機能が複数のフィルタにまたがることがある • 例:リクエストIDをレスポンス、ヘッダ、ログに含めたい ◦ リクエストIDを作るところ、レスポンスを作るところ、ログを出すところ が全部別

    ◦ 1つのフィルタにまとめたら楽なのだが ◦ 入力HttpRequest のヘッダにIDを付加するようにした ▪ でも入力を加工するのはどうなのよと思った
  41. 例:リクエストID val service = … andThen appendId andThen …. andThen

    logging andThen render andThen search • HttpRequestのヘッダに X-Request-Id を追加 • search まではHttpRequest • logging と render ではヘッダからX-Request-Id フィールドから値を取得して • いい方法あったら教えて下さい
  42. DDD的な視点 • Service = ドメインサービス ◦ ドメインサービス多用には批判が多い ◦ aka ドメインモデル貧血症

    • 今回のシステムは”””検索”””しか提供していない ◦ ビジネスロジックは利用側に持ってもらっている • なのでDDDやるぞってところとは合わないかも…
  43. finagle-stats • 各種メトリクスを自動で採集 • twitter-server をいれていると /admin/metrics.json でメトリ クスが見れる •

    よさ ◦ 調査がやりやすい ◦ 障害の検知 ◦ レイテンシが見えるのでSLAの監視に用いる予定
  44. twitter-sever • http://twitter.github.io/twitter-server/ • 全部入り ◦ flag, logging, lifecycle, metrics,

    ◦ いらない機能も入ってる…例えば zipkin ◦
  45. finatra twitter/finatra • sinatra ライクな finagle クローン • finagle にないものがある

    ◦ router ◦ mustache template ◦ logging ◦ twitter-server • finatra 2.0.0のリリース前で使わなかったけど今だったら 使ってもいいと思う(というか使った方がいい) • https://twitter.github.io/finatra/assets/FinatraSFScala.pdf
  46. 感想(よくなかった点)

  47. Play ならな〜 • JSON • Validation • 社内事情

  48. JSONライブラリ • play-json ◦ 単体で使えるようになってるのでよい

  49. Validation and mapping • Validationとモデルへのマッピングに Play の Forms が使い たい

    ◦ ほんとうに欲しかった… ◦ play-jsonみたいに独立して使うことができない • 結局機能の一部しか使わないだろうということで自作したが よくなかった
  50. 社内的な事情 • 社内の便利ライブラリがPlay 前提で辛い

  51. 高負荷時の動作が不安 • 稼働しておくとロードアベレージが上がり続けるという問題 が発生 •

  52. メトリクスを観察 • /admin/metrics.json のメトリクスを観察 • MySQLクライアントのpool_waiterが増えるとロードが爆発 していた "clnt/192.168.122.184:3306/failure_accrual/revivals" : 0,

    "clnt/192.168.122.184:3306/load" : 8.0, "clnt/192.168.122.184:3306/loadbalancer/adds" : 1, "clnt/192.168.122.184:3306/loadbalancer/available" : 1.0, "clnt/192.168.122.184:3306/loadbalancer/load" : 91.0, "clnt/192.168.122.184:3306/loadbalancer/removes" : 0, "clnt/192.168.122.184:3306/loadbalancer/size" : 1.0, "clnt/192.168.122.184:3306/pending" : 7.0, "clnt/192.168.122.184:3306/pool_num_too_many_waiters" : 0, "clnt/192.168.122.184:3306/pool_num_waited" : 6410914, "clnt/192.168.122.184:3306/pool_size" : 64.0, "clnt/192.168.122.184:3306/pool_waiters" : 83.0, "clnt/192.168.122.184:3306/received_bytes" : 16468576884,
  53. 解決 • MySQL コネクションプールのコネクション数が少なかった ◦ 32 ⇒ 256 にして解決 ◦

    解決? ◦ 今はさばけているがこの負荷を超えても大丈夫なん?? ▪ 機材の関係で詳しく調べられず ▪ https://github.com/twitter/finagle/blob/develop/finagle- core/src/main/scala/com/twitter/finagle/pool/WatermarkPool .scala
  54. まとめ • finagle について紹介した ◦ 重要なのは Servie と Filter ◦

    finagle モナモナしてなくてわかりやすい • 検索システムの書き直しをした ◦ Scala は最高(C++ 比で) ◦ パフォーマンスも上がったしよかった • 不安はないわけではない ◦ ドキュメント ◦ 高負荷時の動作