クックパッドと分散トレーシング

こんにちは、技術部の Taiki (@taiki45) です。

近年の Web サービスの開発ではマイクロサービスに代表されるように分散アーキテクチャが採用されるようになってきました。大規模でも素早いプロダクト開発をするために、クックパッドでもマイクロサービスを採用し分散アーキテクチャへの移行を進めています*1。今回は、そのような分散アーキテクチャを利用したシステム構築において必須のコンポーネントになりつつある分散トレーシングについて、クックパッドでの事例を紹介したいと思います。

分散トレーシングとは

マイクロサービスのような分散アーキテクチャでは、個々のサービス同士の通信が複雑になるため、モノリシックアーキテクチャと比較して、システム全体としての振る舞いを把握することが難しくなります。これはプロダクト開発においては、障害発生時の原因究明が難しくなったり、あるいはシステム全体でのパフォーマンスの分析が難しくなるといった問題として顕在化します。 分散トレーシングはこのような問題に対処するためのツールです。開発者が、特定のクライアントリクエストを処理するのに関わったサービスを探したり、レイテンシに関するパフォーマンスをデバッグする時に利用されます。

分散トレーシングの実現のアプローチには大きくわけて2種類あり、一つは Black-box schemes *2、もう一つが Annotation-based schemes と呼ばれています。 前者の Black-box schemes はシステム内の各サービスに手を入れる必要がないことが利点ですが、それと引き換えに特定のリクエストに対する分析はできません。後者の Annotation-based schemes は各サービスに分散トレーシング用のメタデータを下流サービス*3へと伝播させる実装を加えることが必要になるという欠点がありますが、特定のリクエストを分析することができます。Annotation-based schemes は Google の Dapper*4 や Twitter の Zipkin*5 等に採用されており、Web サービス業界では主流なようです。

Annotation-based schemes に基づく実装

Annotation-based schemes に基づいた分散トレーシングシステムの実装の仕組みを大まかに説明すると、ユーザーからリクエストをうける最初のポイントで “トレースID” という分散トレーシングシステム内で一意となる文字列を発行し、トレースIDや “アノテーション” と呼ばれる処理結果等の追加情報を含んだログをストレージに保存し、さらに下流に存在するサービスへリクエストを発行する際にトレースIDとアノテーションを伝播していきます。このような「トレースIDに紐付く一連のログのまとまり」を “トレース” と呼びます。このトレースをトレースIDをキーにしてストレージから検索することにより、特定のリクエストに関わったサービスを特定したり、また複数のトレース情報を集計することで分散システム内のコミュニケーションパターンを分析することができます。また、各サービスがリクエストの処理を開始/終了した時刻もトレースログに一緒に保存すれば、レイテンシの算出もできます。Google の Dapper や Twitter の Zipkin といった実装では、トレースログのタイムスタンプから各ログの親子関係を算出するのではなく、 各トレース内で一意となる文字列である “スパンID” をログの識別子として利用し、ログの親子関係をスパンIDで表現するようになっています。

ほとんどの分散トレーシングシステムは次のようなコンポーネントに分解できます:

f:id:aladhi:20170905163926p:plain

  • Instrumented library: 各サービスのアプリケーションに組み込み、トレースIDの採番や伝播やトレースログの送信を担うライブラリ
  • Log Collector: 各サービスインスタンスから送信されるトレースログの集約を担う
  • Storage and Query:トレースデータの保存と検索を担う
  • UI: 人間がトレースデータを検索・分析する際に利用する

Instrumented library は各言語向けに整備する必要があるので、各分散トレーシングシステム普及のボトルネックになっています。この問題を緩和すべく OpenTracing*6 のように Instrumented library API の標準化を進めているプロジェクトもあります。

クックパッドでの導入

分散トレーシングシステムの選定

クックパッドで分散トレーシングを導入するに当たり、いくつかの点を考慮して AWS が提供するマネージドサービスである AWS X-Ray*7 を採用しました。クックパッド内では一般的なユースケースを想定しているので、既存の分散トレーシング実装を利用することを決めました。分散トレーシングシステム実装として採用例も多く開発も活発な Zipkin に焦点を当てましたが、大規模な環境で Zipkin を利用するには Cassandra/HBase/Manhattan いずれかの運用が必要であり、データストアを自分たちで運用するよりは、解決したい問題にフォーカスできるマネージドサービスの利用に比較優位がありました。クックパッドでは AWS を積極的に活用するインフラストラクチャを構築していることもあり AWS X-Ray の検証を始めました。

検証開始時点では AWS X-Ray が提供する Instrumented library は Java/Node.js/Python のみのサポート*8で、クックパッドではほとんどのサービスは Ruby を用いて実装されているため、そのままでは AWS X-Ray は利用できませんでした。サードパーティ製のものも特に存在しなかったのですが、Instrumented library の実装方法については目処が立っていたこと、及び Instumentation library を自分たちで管理できることで他の分散トレーシングシステムへ低いコストで移行できる余地を残せる利点があったので、自作することにしました。自作した Instrumented library である aws-xray gem は OSS として公開しています*9

現状の構成

AWS X-Ray を利用したクックパッドでの分散トレーシングは以下のような構成で実現されています:

f:id:aladhi:20170905163959p:plain

  • Instrumented library: aws-xray gem を利用
  • Log Collector: AWS X-Ray の提供する X-Ray daemon というソフトウェア*10を利用
    • ECS を利用しているアプリケーションではいわゆる Sidecar 構成を取っています
    • EC2 インスタンス上で動作しているアプリケーションについては EC2 インスタンスの上に X-Ray daemon プロセスを動作させています
    • Instrumented library から UDP で X-Ray daemon にトレースログを送信し、X-Ray daemon がバッファリングと AWS の管理する API へのトレースログの送信を担います
  • Storage and Query: Storage はこちら側からは見えません。Query として AWS X-Ray の提供する API*11を利用します
  • UI: AWS コンソールに組み込まれています*12

aws-xray gem の実装において、トレードオフを考慮しつつモンキーパッチを活用することにより、ほとんどの Rails アプリケーションでは gem の導入と X-Ray daemon への接続情報を設定するのみで、トレースログの収集を開始できるようになっています。

今後の展望

現状はデータを AWS X-Ray に集めるところまでで、まだ本格的なトレースデータの活用には至っていません。データの収集については、社内の主要なサービスをカバーしており、サービスマップのノード数は現在約70ほどです。

f:id:aladhi:20170905164033p:plain

エラートラッカーなどに記録されているトレースIDから該当リクエストに関する分析ができるようになっています:

f:id:aladhi:20170905164117p:plain

サンプリング方式については Head-based coherent sampling*13 を採用しており、ユーザーからリクエストを受ける最初のサービスで sampled/not sampled を決めて下流サービスに伝播させています。サンプリングレートについては、特に rps の高いサービスのみ1%設定、他のサービスについては100%設定で運用しています。サンプリングについては課題があり、ミッションクリティカルなサービス*14の処理を含むトレースはトラブルシューティング用途に全件保存しておきたいですが、流量の高いサービスが上流にいるケースではサンプルされるトレースの割合が少なく、トラブルシューティングを行うユースケースで支障があります。その対策として、パス毎によるサンプリング設定等を実装・導入する予定です*15

クックパッドでは Barbeque*16 という非同期ジョブシステムを利用して非同期ジョブを実行しています。多くのジョブは Web アプリケーションのリクエストによりトリガーされているので、リクエストとジョブ実行との紐付けを記録できるようにする予定です。

また、システム全体のレイテンシ変化を検知できるように、AWS X-Ray の API を利用して監視システムを構築する予定です。監視システムについては自前で実装する以外にも AWS X-Ray の機能追加にも期待しています。

おわりに

AWS X-Ray を利用した分散トレーシングの実現について、クックパッドでの事例を紹介しました。クックパッドでは比較的大規模な Web サービス開発が行われており、分散アーキテクチャ周辺に存在する興味深い問題が多々あります。このような課題解決を一緒に取り組む仲間を積極的に募集しています

*1:http://techlife.cookpad.com/entry/2016/03/16/100043

*2:M. K. Aguilera, J. C. Mogul, J. L. Wiener, P. Reynolds, and A. Muthitacharoen. Performance Debugging for Dis- tributed Systems of Black Boxes. In Proceedings of the 19th ACM Symposium on Operating Systems Principles, December 2003.

*3:ここではユーザーからリクエストを受けるフロント側を “上流"、その反対側を "下流” と呼びます

*4:https://research.google.com/pubs/pub36356.html

*5:http://zipkin.io/

*6:http://opentracing.io/

*7:https://aws.amazon.com/xray/

*8:今では Go 言語向けのライブラリもサポートされました https://aws.amazon.com/jp/about-aws/whats-new/2017/08/aws-x-ray-sdk-for-go-beta/

*9:https://github.com/taiki45/aws-xray

*10:http://docs.aws.amazon.com/xray/latest/devguide/xray-daemon.html

*11:http://docs.aws.amazon.com/xray/latest/api/Welcome.html

*12:http://docs.aws.amazon.com/xray/latest/devguide/xray-console.html

*13:http://www.pdl.cmu.edu/PDL-FTP/SelfStar/CMU-PDL-14-102_abs.shtml

*14:例えば課金系サービス

*15:http://docs.aws.amazon.com/xray/latest/devguide/xray-sdk-java-configuration.html#xray-sdk-java-configuration-sampling

*16:https://github.com/cookpad/barbeque

クックパッド サマーインターンシップ2017 「17day 技術インターンシップ」を開催しました

いつもお世話になっております。エンジニア統括マネージャーの高井です。

クックパッドでは毎年恒例となりつつある、クックパッドのサマーインターンシップのうち「17day 技術インターンシップ」を開催しました。インターンに来てくれた学生のみなさんは本当に優秀で、毎日真剣に取り組んでくれました。本当に感謝しています!

インターンは、前半の「サービス開発講義・課題」パートと後半の「サービス開発実践」から構成されています。前半パートでの講義について資料を公開いたしますので、みなさまぜひご覧ください。

f:id:takai_naoto:20170831080358j:plain


【1日目】サービス開発

初日は、クックパッドで実践されているサービス開発の手法について学ぶワークショップです。グループでのユーザーインタビューを通じてサービスの設計をしました。

【2日目】Rails・TDD・Git

昨年に引き続き、講義初日はGit、TDD、Railsを1日で一巡りするという、忙しい構成でした。

【3日目】モバイルアプリケーション

3日目は、 iOS と Android のふたつに分かれて、 Google 社の Firebase をつかった Cookpatodon というマイクロブログ風のアプリケーションを題材に学習をしました。アプリケーションの基本部分を実装したあとは各自で自由に機能を実装してもらい、最後に成果発表会という形で発表してもらいました。皆ユニークな機能を実装して大変盛り上がりました。

【4日目】インフラストラクチャー

Web アプリケーションのインフラについてAWSをつかいながら、Railsアプリケーション動作させるところから、パフォーマンスチューニング、スケールアウト、キャッシュなどのトピックについて触れています。

(資料は公開準備中です)

【5日目】SQL

Redshiftで構築されたデータウェアハウスをつかって、分析用のSQLを書いていました。クックパッドの実際のデータをつかったので、参加者たちは億単位のレコードがあるテーブルと格闘していました。

(内部データを利用した講習のため資料の公開はありません。どのようなものだったかを知りたい方はこちらまで。こちらの書籍でも概要を知ることができます)

【6日目】機械学習

機械学習は講義と実習のセットになっており、講義では「機械学習とは何か」という概観とディープラーニング(特にCNN)を学んだうえで、実習ではクックパッドのデータを使ったレシピ分類に取り組みました。最後は各々が興味をトピックを取り組んでもらってその成果を提出しました。

【7日目】Ruby

最終日のRubyの講義では、RubyでRubyのコンパイラを実装したり、その最適化を行ないました。


番外編

前半の講義が終わった懇親会では、先輩社員による就職活動の体験談LTなどが行なわれ、参加者のみなさんが楽しんでいました。

f:id:takai_naoto:20170831080459j:plain

その後の二次会も盛り上ったようです。

施策の質と職務能力を高めたい!ディレクター会の取り組み

こんにちは。サービス開発部 ディレクターの五味です。 Android版クックパッドアプリのリリースマネージャーと、アプリ利用者に関わるいくつかのプロジェクトを担当しています。今回は私たちの部で実施している、ディレクターの定例会について紹介します。

f:id:natsuki53:20170829223631p:plain

サービス開発部

クックパッドの開発体制は、2年前に私が ディレクター知見共有会についてのエントリー *1 を書いた頃から少し変遷を経て、2017年からはサービス開発部が、レシピ検索・投稿などの基幹機能と、サービス全体のユーザー体験を一手に管轄するようになっています。

部のメンバーは現在40人ほどおり、部の注力指標からブレイクダウンしたKPIをベースに9つのプロジェクトチームに分かれています。チームの編成や人数は様々で、状況に合わせて入れ替わりもOK、KPI達成に向かっていれば、各チーム主体的に動くことが推奨される柔軟な組織を試みています。

プロジェクトチームで働く中で

このような体制の利点は、自分のチームのミッションに対して裁量を持って施策を考え取り組めることです。やりがいがある反面、以下のような悩みを感じるようになりました。

  • 部の目標に対するチーム横断での進捗度や、自分のチームの遅れが見えづらい
    • チームで決めた施策を進めるだけで、施策数や速度は本当に十分なの?
  • チームが自律的に動く反面、チーム間の情報連携や相互補完が難しい
    • 他のチームは目標をどう考えてどんな施策をしているのか、知りたいけど聞きづらい…
  • ディレクターとしての自分の成長がわからない
    • この職種に必要なスキルは何なのか、自分のパフォーマンスは足りているんだろうか?

ディレクター会の発足

これらの悩みを持ち掛けた方々から助言を得て、部のディレクターがチームを越えて集うディレクター会を始めることにしました。部内のディレクター職の他、ディレクター不在のチームからは同等の役割を担っている他職種の方にも声をかけます。

初回の開催で、会の目的とアジェンダを以下のように決めました。

  • 会の目的
    • サービス開発部でディレクターの役割を持つ人の情報・知見をチーム横断で共有する
  • 成功のイメージ(会の参加者に対して)
    • 担当施策について目標に対する成果を把握し、責任を持って報告できるようになる
    • 部内の施策の内容・効果を横断的に把握し、自分の提案に活かせる
    • 定期的に悩み相談や意見交換をする機会を得て、施策の精度が部署全体で上がる
    • ディレクターとしてのスキルアップに積極的に取り組めるようになる
  • アジェンダ(60分)
    • ① 実施した施策の共有 30分
    • ② 施策やチーム運営の相談 20分
    • ③ その他アナウンス、連絡事項 10分

意識したことは「先週これをやりました、今週これをやります」という業務進捗報告に時間を割かないことです。他のチームの施策の進捗を聞いても必要な情報や問題を見出すのは難しいことと、ディレクターなのでチームの進捗管理は各自できている前提にしたかったためです。

会議の時間は1時間、開催頻度は週1回と仮決めしてスタートしましたが、これは毎週ちょっとだけ時間が足りないくらいアジェンダがある状態が続けられているので、そのまま継続しています。

「実施施策の共有」について

ディレクター会のメインコンテンツにしている施策の共有について少し紹介します。

この会では、部で実施する施策をできるだけすべて議題にあげたいので、施策共有用に手間のかかる資料は作らないことにし、GitHub Issue に報告事項の箇条書きだけ準備する方式にしました。

ただし、箇条書きの項目はテンプレートで決まっており、報告には、仮説・試算・実数・考察・次のアクションの5項目が必要です。PDCAを回せるような設計がきちんとできていない施策はこの5つに埋められない項目が出てくるため、施策を考える人の自浄装置のような働きをしています。

例えばこのディレクター会をテンプレートに沿って報告しようとすると、下記のようになります。

# 施策名:サービス開発部のディレクター週例
- 仮説
  - ディレクターが定期的に施策情報を共有し意見交換できる場ができると、部全体の施策の精度とスピードが上がる
- 試算
  - 部の施策数が週5本(各チーム2週に1本)になる
  - 部の目標達成の進捗度が10%上がる
- 実数
  - 施策報告数:2〜3本/週
  - 部の目標達成進捗度:変化なし
- 考察
  - 定性意見より、会があることで施策/プロジェクトの成功への責任者意識は強まった
  - 他チームの成功・失敗事例やお互いの助言を担当案件に活かせる機会はできた
  - ただ、実際の施策のスピードやKPIの進捗に変化が起こるほどの成果には至っていない
- 次のアクション
  - アジェンダの見直し:参加メンバーに課題提起し、次の会で改善策を話す時間を取る

また直接この会に起因することではありませんが、最近サービス開発部では、施策結果のレポートをPull Requestで作ってチームでレビューする手法が採られ始めています。何かをリリースして完了ではなく、検証内容を振り返り次にどう進めるのかの判断にチームで取り組めることと、メンバーがレビューに入ることで、施策に対するチームの理解が揃う利点があります。

ディレクター会ではこれらの箇条書きやPull Requestを見ながら、施策共有に使える30分を週ごとの施策数で割って時間配分を決め、どんどん報告していってもらいます。報告を聞いている側の人は、気になる点や使える知見があれば自由に発言してもらい、特筆すべき意見は後で議事録に残して使ってもらいます。

ディレクター会の効果と課題

現在、この会を始めて2ヶ月ほどが経ったところです。前段の報告テンプレートの事例で少し前述していますが、現時点で良かったと感じている点は以下です。

  • 他チームの成功・失敗事例や、他のメンバーの助言など、自分の施策に活かせる第三者からの情報を得やすくなった
  • 週ごとに報告できる施策の数から、各チームの進捗スピードが推し測れるようになった
  • ディレクター:プロジェクトを成功に進める責任者という意識を合わせ、施策に取り組めるようになった

反面、まだ成果は定性的なものに止まっており、施策のスピードや部の目標達成の進捗に効果が表れるには至っていません。またディレクターのスキルアップのような長期の取り組みには手を出せていない状況です。

ちょうど先週これらを課題として改善策を相談し、次から以下の2つを変更してみる予定です。

  • 施策報告を、終了した施策だけでなく、これから実施する施策も対象にする
    • 結果だけだとチームが何を考えてその施策をしたのかわからない、終了施策にツッコミをもらっても「次頑張ります」としか言えないという意見から。施策の改善の余地に事前に気づいて検証の精度を上げられるように。
  • 進行中施策に直接紐づかない大きめのトピックも持ち込むようにする
    • 仮説定義や分析手法のノウハウなど、具体的な解がすぐ出せないから話題にしづらいが、各自悩みの深い相談を持ち掛けられるように。

このような取り組みを継続させるコツ

前回ディレクター知見共有会のエントリーを読んだ方から「うちはこういう会を始めても3回で自然消滅します…」という感想をいただいたので、大変僭越ですが、複数のメンバーを巻き込んで定常的な取り組みを行う際に意識していることを紹介させていただきます。

1. 参加者のコストを必要最小限にする

時間と手間を取りすぎないことを念頭に置いています。 今回であれば、会議が1時間を過ぎないよう時間配分することと、準備はGitHubのIssueにテンプレートに沿った箇条書きで済むようにしています。

2. 参加者がすぐ活かせる粒度の情報を入れる

「ディレクターに必要なスキルとは?」といった少し高い次元の議論だけでなく、明日から自分の業務に使える実用的な情報を得られる議題を含めることで、参加の利点を感じやすくします。 そのためディレクター会では実施施策の話題に時間を厚めに充てています。

3. “他人事” になっているメンバーを放置しない

取り組みが軌道に乗ってから1番気を配る点です。会議中ぼんやり聞いているだけの人が出てくるようになったら要注意です。敢えてその人に指名で意見を求めてみたりして反応を見ながら、会議の内容自体に原因がないか見直しを考えます。

最後に

ディレクターはエンジニアやデザイナーに比べて職務定義が難しいということをよく聞きます。また1つのプロジェクトに複数名でアサインされることは少なく、1人で複数のプロジェクトを掛け持ちすることは多いため、各自が抱える情報や知見を共有するには意識的な働きかけが必要だと感じます。

ただ、どんなプロジェクトでどのような働きをしているにせよ、ゴールに向かってチームを進めていく大事な役割を担っていることは確実だと考えます。

開発者がすごい!と言われるクックパッドですが、「ディレクターもすごいんです!」と言えるよう、今後も頑張っていきたいと思います。

そして、そんなチームに一緒に加わって頑張ってくださるメンバーを募集しておりますので、よろしくお願いいたします! https://info.cookpad.com/careers

*1:注: 「ディレクター知見共有会」はそのあと対象を広げ、今は参加者の職種は問わず様々な部署の体制や取り組みについて聞ける場として継続されています。