【参加レポ】Akka ActorとAMQPでLINEのメッセージングパイプラインをリプレースした話【LINE DEVELOPER DAY_2015】 #linedevday

公開日: 

4/28に開催されたLINEのエンジニアチームの様々な経験を、未解決の課題も含めて共有する技術カンファレンス、

LINE DEVELOPER DAY_2015 Tokyo

に参加してきたのでその時のまとめ。

 

メッセージングパイプラインについてのお話です。

ムズイッス…

 

他のセッションは以下からどうぞ

sponcer link

 

Yuichi Ono様

linedevday-pipeline1

 

概要

LINEのメッセージングは人と人とやるのと、人とシステムとでやるものの2種類ある

linedevday-pipeline2

 

公開型のアカウントから一般の人に送るときは20億メッセージおくったりする

一斉送信を解決するためにつくったのがメッセージングパイプライン

linedevday-pipeline3

  • システムに対してメッセージを送るときは、Featcherが受信キューに送ってPusherが外部システムにおくる
  • 公開アカウントが送るときは送信キューにいれて、FanOutというサービスが一斉に送る
  • 受信キューはRabbitMQを使っている

 

受信キューについて

  • メッセージングの記法要件として送信した順序で受信側に到達しなければならない
  • 普通MQベースで使うときはひとつのキューに対して複数のコンシューマをわりあてるが、処理順が保証されていないので、1キューに対して1コンシューマでやらないといけない
  • 1Q1Cの問題
    • コンシューマのフェイルオーバーをどう実現するか
    • 1キューに対して正確に1コンシューマーを割り当てる方法

linedevday-pipeline4

 

補足:AMQPのACKの仕組みについて

AMQPのACKはコンシューマに応じて必ずメッセージを処理するという仕組み

linedevday-pipeline5

ACKが来なかった場合は別のコンシューマにメッセージを送信する

linedevday-pipeline6

 

1Q1Cのフェイルオーバー方法

AMQP ACKを活用して1Q1Cのフェイルオーバーを編み出した!!

コーディネーションキューにコンシューマーの名前を書いたキューをいれておく

linedevday-pipeline7

肝は死ぬまでackを返さないようにすることで1Q1Cを実現できた

linedevday-pipeline8

  • コンシューマがダウンしたらメッセージをダウンしたコンシューマに即座に送り直す

結果として、RabbitMQのみでフェイルオーバー可能に。またスケーラビリティも上がった

linedevday-pipeline9

 

スループットを改善したPusherについて

linedevday-pipeline10

  • フェイルオーバーを考慮した1Q1Cの実装
    • ライブラリの持ってる再接続機能だけじゃできないので自前で実装しないといけない
  • 送信元アカウントごとにメッセージをバッファリングしないと順序保証ができない
  • 計算リソースを完全に使い切りつつ、限界を超えないようにリアルタイム処理の実現 – 宛先システムの遅延が全体に影響を及ばさないようにスレッディングしないといけない

 

前はmicro batchという少しずつ処理するようにしていたが、stream batch処理するようにした

linedevday-pipeline11

 

アクターモデル

  • アクターはスレッドやロックの代わりに使うもので、それぞれが独立したスレッドないしプロセスでうごいており、それらがメッセージを非同期に行うことで並行処理をモデル化する
  • 送ったメッセージはアクターのメールボックスに入り、送られたアクターはそのメールボックスに入った処理を処理していく
  • アクター自身はシングルスレッドで記述できるのでロック処理を書かなくていい

linedevday-pipeline13

 

Akkaについて

  • Akkaはアクターモデルを実現するためのScalaおよびJavaむけの並行プログラミングライブラリ
  • 重要なこと1:ステートマシンの実装が簡単
    • ReceiveFunctionの切り替えが可能
    • いったん状態遷移図かいてからステートマシンにおとしこむことができた
  • 重要なこと2:Supervisorにより、エラー処理とデータフローをきりわけられることができる

Pusher

Pusherの中身

linedevday-pipeline14

  • RabbitMQがメッセージキューとコンディションキューを管理する
  • ここのアクターがコンシューマとして動く

 

一旦中継用のアダプターを書いて、次に1つのAMQPアクターにすべて集約している

AMQPのライブラリ自体に再接続の機能があるが、複数のコネクション管理だと、逆に実装しづらくなるので、集約することで簡潔にかけた

linedevday-pipeline15

 

 

AMQP ActorはFlow Control Actorにわたしている

  • アクターのインプットとアウトプットさえ合っていれば様々なパイプライン処理ができる

linedevday-pipeline16

 

 

処理がおわったらAckをきた順序に返していく

linedevday-pipeline17

 

  • バッファーサイズは気をつけないといけない
    • BackPressureというのが必要になる
    • 各アクターに各バッファーのサイズを監視させて、Aというバッファーがたまっていたら、A宛のメッセージングをとめてという通知をするようにしている
    • 問題なくなったら送信していいよという通知も行う

linedevday-pipeline18

 

 

Metrics Actorのなかでサンプリングなどをして外部に送信を行ったりしている

linedevday-pipeline19

 

7秒単位に、アクター別、サーバー別にメトリックスをみれるようになったりしている

linedevday-pipeline20

 

結果として

linedevday-pipeline21

  • フロントにRabbitMQを建てることでActorの仕組みで再送信できるようになった

 

FanOutについて

複数のアカウントに一斉に送信することがある -> ラウンドロビンアルゴリズムを採用した

linedevday-pipeline22

 

メッセージのフローを一旦ためて、カーソルを順番に操作して順番にメッセージを送信している

linedevday-pipeline24 linedevday-pipeline25

 

結果として

linedevday-pipeline26

  • ラウンドロビンアルゴリズムのおかげでQoSの目標を実現!

 

おわりに

linedevday-pipeline27

非同期技術スタックを検討すべき理由

  • マイクロサービスの採用により、サービス間通信の重要性が高まった
    • どんな技術を使うのかが大事になってきた
    • 同期RPCの罠は、連鎖的障害を残しやすい
      • 同期RPCを通じてシステム全体に連鎖的に影響をおよぼす
  • ウェブサービスの時代からスマートフォン・ウェアラブルの時代へ
    • アプリの比重が増えたことで、ユーザーの生活にサービスが深く入り込むようになった
    • 同期処理では賄えなくなってきている
    • 非同期処理をうまく抽象化して並行処理を簡単にかける環境は整ってきているので新しい武器として使おう!

 

LINEの注力分野

linedevday-pipeline28

所感

マルチスレッドプログラミングについての知識が恐ろしく乏しいのを感じたため、少し勉強したほうがいいのではという危機を感じた。

もしマルチスレッドプログラミングするときはアクターモデルを試してみます!!

  • このエントリーをはてなブックマークに追加
  • Pocket
PAGE TOP ↑