Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Sidekiq to Kafka ストリームベースのmicro services

Sidekiq to Kafka ストリームベースのmicro services

Kaigi On Rails 2020 発表資料。

ActiveJob(sidekiq)の限界とKafkaを採用してサービス分割する上での戦い方の例について紹介する。

Tomohiro Hashidate

October 03, 2020
Tweet

More Decks by Tomohiro Hashidate

Other Decks in Programming

Transcript

  1. 自己紹介 Repro inc. CTO Tomohiro Hashidate a.k.a @joker1007 asakusa.rb 最近はKafkaとKafka

    Streamsを用いて セミリアルタイムストリーミングシステムを 構築している。 その他、satisfactoryで工場作ったり。 気付いたんですが、マジ仕事と変わらんよねこれ。
  2. Reproの特徴 • データ量が多い (秒間5万件ぐらいの書き込みが発生する) • エンドユーザーは通信自体を意識しない • サービス利用者のアクションもすぐに結果は出ない ◦ 数百万ユーザーにpushメッセージを配信する

    ◦ アプリケーション内にキャンペーン情報を配信し結果を待つ ◦ 特定条件に合致するユーザー集合を exportする • 集計処理が多い ◦ 日に数千万ユーザー * 100ぐらいの集計結果が必要 ◦ 出来る限り短時間で結果を出す つまり、同期的に結果を返すことが重要ではない大規模なデータを扱う。 非同期処理の重要度が高い。
  3. ActiveJobの特徴 • モデルのメソッドを呼び出すことを非同期化することに特化している。 • キューイングの管理を隠蔽している。 ◦ 基本的にキャンセル機構が無い。 • スケジューラは簡易的である。 ◦

    再帰的なスケジュールを設定できない • 複数のgemの最大公約数となるインターフェースである ◦ Backend固有の機能については考慮しない 端的に言って、ユーザーからのWebリクエストを受けて、多少時間がかかる処理(数 秒〜数分)の結果を待たずにレスポンスを返すのが、主な用途である。
  4. ActiveJobの限界 • 定期実行が面倒 • コードベースが密結合する ◦ ファットモデルと結合すると分離が困難 • 1台で処理できるジョブを越えると非常に面倒 ◦

    長時間実行する処理だとリトライ粒度がコントロールできない ◦ redisがスケール限界になる (通常ここまでは早々到達しないけど ) • 複数段階にジョブが分かれている場合、依存関係が分かりにくい 一定以上複雑化すると対応に困る要素が多くなる。特にActiveJobはRailsの中でも限 界が早くやってくる。 選択する際には、かなり簡易的な非同期ジョブ実行基盤であることを意識しなければな らない。 ぶっちゃけ個人的には生でbackend使う方が…
  5. 例: Push Message配信 Push Campaign (Rails) Push sender (Go) Sidekiq

    CronoTrigger (Scheduler) 1. Fetch user informations 2. Store user informations Amazon Aurora SQS 3. Queue execution 別のActiveJob 4. Poll execution 5. Fetch user informations 6. External Service 7. Feedback results パッと見でややこしい。 工程毎の責任分離が出来ていない。 Redisとsidekiqワーカーの限界までしかスケールしない
  6. やりたいこと • 工程毎に責任範囲を明確にしたい ◦ サービス分割も視野 ◦ 言語非依存なメッセージング • スケーラビリティの確保 (特に集計のスケーラビリティ)

    ◦ 一台のノードだけに処理が閉じない様にする ◦ データの入口から保持する場所まで全てを分散可能にしないと結局データストアがシングルポイン トになる ◦ 数分で数千万件〜数億件がキューイングされることを想定する • 耐久性の確保 ◦ sidekiqとredisは最悪の場合キューがロストする。 (proは解決可能らしい) ◦ SQSでも解決可能だけど shoryukenはコードベースが読み辛い ……。
  7. Apache Kafkaとは Kafkaは公式ドキュメントによるとDistributed Streaming Platformと呼ばれている。 • レコードのストリームをpub/subする ◦ キューとは似て非なるもの •

    対障害性を持った方法でレコードを永続 化する. • パーティショニングされたトピックという 単位でレコードを保持する ◦ パーティション毎にデータの時系列は保証さ れる from https://kafka.apache.org/intro
  8. キューとの相違点 • Subscribers (Consumers) はレコードを削除(消費)しない • SubscribersはKafka Brokerに保持されているoffsetの値を基に取得するレコード の位置を決める。 •

    Publishers (Producers) がパーティショニングの責任を持つ ◦ Kafka brokerは到着したレコードをパーティショニングするロジックを持っていない ◦ パーティショニングのアルゴリズムはクライアントライブラリに実装されていて、各々のクライアント 実装によって異なる • 複数のワーカーが同じレコードを処理しない様にするためにConsumerGroupと いう概念を用いる。 from
  9. Kafkaを利用したproducer/consumerモデルの利点 • Avroを利用したスキーマフルで言語非依存なメッセージ伝達 ◦ 任意の言語で独立したサービスを実装可能 ◦ Kafka関連ツールの中にSchema Registryがありスキーマ管理がしやすい • producer,

    broker, consumer全てが分散処理可能 ◦ 適切な仕事の切り分けは必要 • メッセージはストレージに永続化され、レプリカによって保護される ◦ 必要であればidempotentなキューイングやトランザクションも実装できる • キューでは無いため、一つのメッセージを元に複数のサービスを起動できる ◦ 各サービスはメッセージの取得先とスキーマが分かれば良い ◦ Avroのスキーママイグレーションと組み合わせると、サービス追加時に必要な変更を最小限に出来 る
  10. 例: Push Message配信の改善 Push Campaign (Rails) Push sender (Go) CronoTrigger

    (Scheduler) Amazon Aurora Return queueing Control the pace of delivery 6. External Service Queueing Service Fetch user informations Delivery Scheduler Send event それぞれのサービスは任意の言語で実装可能 一つ一つの工程で完結しておりお互いを知る必要は無い それぞれの仕事の結果をお互いが知る必要も無い 任意の箇所からリトライ可能 (但しストリームとして ) Fetch targets Send event
  11. 参考: CQRSとは Command and Query Responsibility Segregationの略。 副作用を伴うDomain Specificな処理をCommand、参照をQueryとしてそれぞれ独立し たデータモデルを利用するアーキテクチャを指す。

    同一のサービス内で分離することもあるし、サービスレベルで分割されているケースもあ る。 ワークロードの違いや複雑さを分離したり、個別にスケーラビリティをコントロールするこ とが主な目的。 一方で、状態を同期的に収束させるのが困難になるので、処理フローの工程数は増え るし、システム構成そのものは複雑化する。
  12. RubyからKafkaに送信する クライアントライブラリ • ruby-kafka • rdkafka-ruby (C extension) • Waterdrop

    (wrapper of rdkafka) シリアライズ • avro_turf (Schema Registryに対応したavroシリアライズを行う) fluentd • fluent-plugin-kafka, fluent-plugin-avro_turf フレームワーク • karafka
  13. Storage Layer User Identification Reproのイベントストリーム概要 Event Acception (API) User Identify

    User Profile Persistence Event Tracking API Event Acception (Amazon S3 -> SQS) Event Aggregation Event with property Counting Data Arrangement リアルタイムのイベントの集計、ユーザープロフィールの 保存等を行いストレージレイヤーに保存している Compatibility Layer Native and Web SDK API Kafka Streams User Activities User Activities
  14. 参考: その他の手段 ある程度複雑な非同期処理を構築するには他にもいくつか手段がある。 単機能なコンテナ化されたコマンドとワークフローエンジンの組み合わせが最近のオス スメ。 AWSだとStep FunctionsとFargate (or AWS Batch)を組み合わせるとスケーラビリティ

    を確保しやすい。(最近採用しようとしている) GCPだとGCP Workflow辺りを活用できそう。 kafkaとRailsを組み合わせる利点についてはこの記事が参考になる。 https://mensfeld.pl/2017/11/kafka-on-rails-using-kafka-with-ruby-on-rails-part-1-kaf ka-basics-and-its-advantages/