LINE STORE 技術スタック l 開発⾔語︓ l Java, Kotlin (JVMで動作する⾔語) l フレームワーク︓ l Spring Boot l Armeria/Central Dogma/Decaton(LINE OSS) l ストレージ︓ l MySQL, MongoDB, Elasticsearch, Redis l インフラストラクチャ︓ l Verda (プライベートクラウド) l VM(仮想マシン), Kubernetes
モノレポ l すべてのコンポーネントを1つのGitHubリポジトリで管理 l メリット︓ l 横断したコンポーネントの開発 l 共通モジュールの構成のしやすさ l ライブラリやフレームワークのバージョンを統⼀ l デメリット︓ l コンポーネント数が増えてくると、可視性が低下、 管理が複雑化 l ビルド、CIの遅延 l 意図しないバージョンアップによる不具合、障害の発⽣ Component A Component B Component C Repository
コンポーネント数の過多 l 問題︓ l マイクロサービスやコードベースの学習が困難 l それぞれのコンポーネントがどのプロダクト、機能を担当するのか不明確 l 各コンポーネントの担当者が不明確 l コンポーネントについて質問したい時、 何か変更を⾏ってソースレビューしてほしいとき、だれが適切なのか︖ l 既存メンバーであっても、よくわかってないケースが多い
コンポーネントのモノリス化 l 問題︓ l 開発やリリースの⼿軽さから、既存のコンポーネントに 責務が異なる機能が追加される l モノリシックで、⾊々な機能をもったゴッドコンポーネントが発⽣ l モノリシックなコンポーネントは、機能や依存関係が複雑 l 開発、テスト、デプロイメントも複雑化 l 単⼀障害点になり、信頼性が低下する可能性
コンポーネントのパフォーマンス、信頼性低下 l 問題︓ l マイクロサービスを⻑期間運⽤していると、初期に想定していた キャパシティと実際のデータ数やデータ量が乖離する場合がある l 要因︓ l ユーザ数の増加や需要の変化 l ストレージのデータの増加 l 結果︓ l 特定のコンポーネントで、レイテンシ・パフォーマンスの低下 エラー数の増加 l 問題が継続すると、マイクロサービス全体が不安定になり 信頼性が低下
コンポーネントドメインの定義⽅法 l ドメインが所有するデータやストレージを明確にする l ドメイン内のコンポーネントのみが、所有するストレージに直接アクセスに制限 l メリット︓ l 内部・外部の依存関係の明確化 l セキュリティ対策やアクセス制御などの追加が容易 l ストレージ変更時・障害時の影響範囲が明確で、円滑に対応できる
課題 複数ドメインでストレージを共有している場合はどう対応するか︖ コンポーネントドメインの定義⽅法 l リアーキテクチャが必要 l ⾮所有ドメインからは公開API経由でデータにアクセス l データベースをドメインごとに分割 複数ドメインでストレージを共有 リアーキテクチャ データベース分割 公開API経由に変更
⾮同期メッセージングアーキテクチャ l 送信者と受信者は直接通信を⾏わず、メッセージングキューを介して データをやりとりする l メリット︓ l 応答性の向上︓送信者がメッセージを送ると、直ちに応答が返る。 結果を待たない。 l 疎結合・独⽴性︓メッセージキューにデータが⼀時保存されるので、 受信者側でリトライ処理やレートリミットが可能 = 信頼性の向上
KafkaとDecaton l Apache Kafka l 分散メッセージングシステム l ⾼い信頼性・スケーラブル l LINE共通のKafkaクラスタが使⽤できる l Decaton l Kafka Consumerライブラリ l LINEのOSS https://github.com/line/decaton l パーティションをマルチスレッドで同時に処理 l リトライ、レートリミッター機能が標準装備で、別途開発する必要がない
⾮同期メッセージングアーキテクチャの活⽤例 l 活⽤例︓LINE公式アカウントからのメッセージ配信 l LINEのMessaging APIを使って、アプリケーションからメッセージを配信 l メリット︓ l スケーラブルで、信頼性の⾼いサービスの構築 l エラー発⽣時のリトライとレートリミットへの対策 Consumer(受信者)は Decatonを使って開発 リトライ⽤トピック 送信者
開発を⾏う上で⼯夫した点 l 各コンポーネントの役割を明確にして、機能を実装 Producer(送信者) l Kafkaにメッセージ送信 l LINEメッセージのデータ(JSON)の作成 Consumer(受信者) l Messaging APIのコール l リトライ・レートリミット 配信するLINEメッセージのデータに新規追加や変更が発⽣しても、 Producerのみの開発、デプロイで対応可能 = Consumerの再利⽤性が向上 メリット
CQRS l CQRS = Command Query Responsibility Segregation l データ更新(コマンド)とデータ取得(クエリ)を分離、別のモデルとして扱う l CQRSを使って、コマンドの役割を持つコンポーネントとクエリの役割を持つ コンポーネントで、マイクロサービスを構成する l メリット︓ l コマンドとクエリに対して、異なるスケーリングやアーキテクチャの適⽤が 可能
CQRSの活⽤例 l 活⽤例︓スタンプのデータ管理 l クエリのクライアントはLINEのユーザ、コマンドのクライアントはスタンプ制作者 l コマンド数よりも圧倒的にクエリー数が多い l クエリのパフォーマンス向上のため、Elasticsearch(Read Storage)とRedis(Cache)を使⽤ l MySQLとElasticsearchはバッチ処理で⾮同期にデータ同期 登録完了から参照可能までに遅延が 発⽣するが、機能要件として許容
CQRSの活⽤例 l 活⽤例︓あけおめスパイクへの対策 l 新年0時のタイミングで、毎年クエリ数のスパイクが発⽣する l 対策として、Elasticsearchを⼀定期間デュアル構成にして負荷分散 1/1の0時あたりのRPS︓ コマンドのアーキテクチャ変更なしに クエリ側をより柔軟に変更可能 メリット
CQRSの活⽤例 l 活⽤例︓データの同期に⾮同期メッセージングアーキテクチャを適⽤ l リアルタイムに同期することで、参照可能までの遅延を⼩さくする l Kafkaのトピックを公開して、スタンプ作成通知を他のチームでも受信可能 MySQLに登録完了後、 Kafkaにメッセージを送信 Elasticsearchの同期を リアルタイムに実施
発表の流れ まとめ l コンポーネント数過多による複雑さを解消するために、 コンポーネントドメインを導⼊ l コードベースの階層化でドメインを表現 l コードオーナーを設定して担当者を明確化 l コンポーネントやドメインの役割・責務を明確にして、 コンポーネントのモノリス化を防ぐ l ⾮同期メッセージングアーキテクチャやCQRSを活⽤して、 信頼性⾼い、かつ柔軟なマイクロサービスを構築
E2Eテストの⾃動化 l リアーキテクチャでは基本、プロダクトの表⾯的な機能は変更されない l 機能が変わっていないこと、壊れていないことをリグレッションテストで担保 l E2E⾃動化テストの整備は⼈的リソースを節約できて、より効率的にテストを実施が可能 Seleniumや商⽤のテスト⾃動化 サービスを使⽤して、 ⾃動化テストを整備
パーセンテージリリース l 処理の切り替えをパーセンテージを指定することでリリースする(1%→10%→100%) l あらかじめアプリケーションに対して、この制御の実装が必要 l コストがかかるため、⼤規模な機能・変更のリリース時に使⽤するか検討 処理切り替えのパーセンテージは 構成管理サーバで管理 ex. Central Dogma
Central Dogmaの活⽤ l Central Dogma l サービス構成管理リポジトリ l LINEのOSS https://line.github.io/centraldogma/ l 設定ファイルを可⽤性⾼く、サーバ上でバージョン管理 l GitとZookeeperベースのフレームワーク l クライアントをアプリケーションに組み込んでおくと、リアルタイムで 設定値を⾃動で同期 l 設定ファイルをGitHub上で管理可能
Armeria l JVM, Netty ベースのフレームワーク l LINEのOSS https://armeria.dev/ l マイクロサービス(サーバ, クライアント)を構築する上での機能を提供 l Non-Blocking I/O l HTTP/2 l RPC(Thrift, gRPC), RESTサーバ/クライアント, GraphQL l Spring Boot, Spring MVCとの統合 l Micrometerによるメトリクス収集 l Zipkinによる分散トレーシング l クライアントサイドロードバランシング l ⾃動リトライ、レイトリミッター、サーキットブレーカー