Slide 1

Slide 1 text

信頼性と柔軟性向上のための マイクロサービスのリアーキテクティング Kazushi Hirai

Slide 2

Slide 2 text

⾃⼰紹介 l 所属︓ l LINE Fukuoka 株式会社 l 開発1室 Kチームマネージャ l サーバサイドエンジニア l 興味︓ l 家族(娘、息⼦), 体を動かすこと, マラソン l Twitter: @hkazushi0627 ฏҪ Ұ࢙ ,";64)*)*3"*

Slide 3

Slide 3 text

アジェンダ l 背景 l マイクロサービス運⽤の問題 l リア―キテクチャの進め⽅ l リア―キテクチャのパターン

Slide 4

Slide 4 text

背景 l 担当プロダクト l 技術スタック l システムアーキテクチャ l プロダクトの歴史

Slide 5

Slide 5 text

LINE STORE 担当プロダクト LINE STORE スタンプショップ 着せかえショップ オートサジェスト おすすめスタンプOA

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

LINE STORE システムアーキテクチャ l LINE全体が⼤きなマイクロサービス l チームの構造にあわせて、マイクロサービスを構成 l 逆コンウェイの法則 l 各チーム内でもマイクロサービスで運⽤ LINE全体 Shopのマイクロサービス

Slide 8

Slide 8 text

歴史 – 2011年 2012 スタンプショップ リリース 2013 LINE STOREリリース 2014 LINE着せかえ LINEクリエイターズスタンプ 2017 年賀キャンペーン開始 LINE公式アカウントからの おすすめスタンプ⾃動配信 2018 LINE絵⽂字 2019 LINEスタンプ プレミアム 2020 メッセージスタンプ LINEスタンプ プレミアム デラックスコース 2021 LINEスタンプ プレミアム 台湾、インドネシア LINEアニメーション絵⽂字 2011 LINEリリース 2022 LINEスタンプ プレミアム LINE Music LINEMO バンドル l サーバサイドエンジニア︓10⼈未満 l エンジニアのチーム数︓2 (プロダクトチーム) l マイクロサービスのコンポーネント数︓3 サービスローンチ当初の構成

Slide 9

Slide 9 text

歴史 – 現在 2012 スタンプショップ リリース 2013 LINE STOREリリース 2014 LINE着せかえ LINEクリエイターズスタンプ 2017 年賀キャンペーン開始 LINE公式アカウントからの おすすめスタンプ⾃動配信 2018 LINE絵⽂字 2019 LINEスタンプ プレミアム 2020 メッセージスタンプ LINEスタンプ プレミアム デラックスコース 2021 LINEスタンプ プレミアム 台湾、インドネシア LINEアニメーション絵⽂字 2011 LINEリリース 2022 LINEスタンプ プレミアム LINE Music LINEMO バンドル 現在の構成 2023 現在 l サーバサイドエンジニア︓30⼈以上 l エンジニアのチーム数︓6以上 (プロダクト・フィーチャーチーム、SRE) l マイクロサービスのコンポーネント数︓80以上

Slide 10

Slide 10 text

モノレポ l すべてのコンポーネントを1つのGitHubリポジトリで管理 l メリット︓ l 横断したコンポーネントの開発 l 共通モジュールの構成のしやすさ l ライブラリやフレームワークのバージョンを統⼀ l デメリット︓ l コンポーネント数が増えてくると、可視性が低下、 管理が複雑化 l ビルド、CIの遅延 l 意図しないバージョンアップによる不具合、障害の発⽣ Component A Component B Component C Repository

Slide 11

Slide 11 text

マイクロサービス運⽤の問題 l コンポーネント数の過多 l コンポーネントのモノリス化 l コンポーネントのパフォーマンス、信頼性低下

Slide 12

Slide 12 text

コンポーネント数の過多 l 問題︓ l マイクロサービスやコードベースの学習が困難 l それぞれのコンポーネントがどのプロダクト、機能を担当するのか不明確 l 各コンポーネントの担当者が不明確 l コンポーネントについて質問したい時、 何か変更を⾏ってソースレビューしてほしいとき、だれが適切なのか︖ l 既存メンバーであっても、よくわかってないケースが多い

Slide 13

Slide 13 text

コンポーネントのモノリス化 l 問題︓ l 開発やリリースの⼿軽さから、既存のコンポーネントに 責務が異なる機能が追加される l モノリシックで、⾊々な機能をもったゴッドコンポーネントが発⽣ l モノリシックなコンポーネントは、機能や依存関係が複雑 l 開発、テスト、デプロイメントも複雑化 l 単⼀障害点になり、信頼性が低下する可能性

Slide 14

Slide 14 text

コンポーネントのパフォーマンス、信頼性低下 l 問題︓ l マイクロサービスを⻑期間運⽤していると、初期に想定していた キャパシティと実際のデータ数やデータ量が乖離する場合がある l 要因︓ l ユーザ数の増加や需要の変化 l ストレージのデータの増加 l 結果︓ l 特定のコンポーネントで、レイテンシ・パフォーマンスの低下 エラー数の増加 l 問題が継続すると、マイクロサービス全体が不安定になり 信頼性が低下

Slide 15

Slide 15 text

マイクロサービス運⽤の問題 l コンポーネント数の過多 l コンポーネントのモノリス化 l コンポーネントのパフォーマンス、信頼性低下 管理・システム両⽅のリアーキテクチャで 信頼性が⾼い、かつ柔軟なマイクロサービスを構築する

Slide 16

Slide 16 text

リアーキテクチャの進め⽅ l コンポーネントドメインの導⼊ l コードベース上でドメインを表現 l コードオーナーの導⼊ l コンポーネントドメインの定義⽅法

Slide 17

Slide 17 text

コンポーネントドメインの導⼊ l コンポーネントを論理的にグルーピングする l グループ = コンポーネントドメイン l ハイレベルな図を⽤いることで、シンプルになり全体の学習コストが下がる ドメイン図(ハイレベル) コンポーネント図(詳細)

Slide 18

Slide 18 text

コードベース上でドメインを表現 l リポジトリの階層で、ドメインとコンポーネントの関係を表現 l リポジトリのトップレベル = ドメイン l トップレベル配下 = ドメインに含まれるコンポーネント store/ + store-server + store-cms + store-decaton shop/ … subscription/ … リポジトリの構成 ドメイン コンポーネント

Slide 19

Slide 19 text

コードオーナーの導⼊ l ドメイン単位でコードオーナーを設定して、担当者を明確にする l GitHubであれば、テキストファイルにコードオーナーを設定できる l プルリクエスト作成時に、コードオーナーが⾃動でレビューワーに設定 store/ + store-server + store-cms + store-decaton shop/ … subscription/ … /store/ @kazushi-hirai @xxx @yyy /shop/ @aaa @bbb /subscription/ @ccc @ddd … リポジトリの構成 .github/CODEOWNERS プルリクエスト

Slide 20

Slide 20 text

コンポーネントドメインの定義⽅法 1. 各コンポーネントの役割、責務を明確にする l 複数の責務を持っているコンポーネントがあれば、分割の候補に加える l 過度に分割しすぎると、コンポーネントの数が増え、複雑さが増すので注意が必要 2. ビジネス機能の関連性でコンポーネントをグルーピング = ドメインを定義 課題 どのような単位、ルールでドメインを定義するのか︖

Slide 21

Slide 21 text

コンポーネントドメインの定義⽅法 l ドメインが所有するデータやストレージを明確にする l ドメイン内のコンポーネントのみが、所有するストレージに直接アクセスに制限 l メリット︓ l 内部・外部の依存関係の明確化 l セキュリティ対策やアクセス制御などの追加が容易 l ストレージ変更時・障害時の影響範囲が明確で、円滑に対応できる

Slide 22

Slide 22 text

課題 複数ドメインでストレージを共有している場合はどう対応するか︖ コンポーネントドメインの定義⽅法 l リアーキテクチャが必要 l ⾮所有ドメインからは公開API経由でデータにアクセス l データベースをドメインごとに分割 複数ドメインでストレージを共有 リアーキテクチャ データベース分割 公開API経由に変更

Slide 23

Slide 23 text

リア―キテクチャのパターン l ⾮同期メッセージングアーキテクチャ l CQRS (Command Query Responsibility Segregation)

Slide 24

Slide 24 text

⾮同期メッセージングアーキテクチャ l 送信者と受信者は直接通信を⾏わず、メッセージングキューを介して データをやりとりする l メリット︓ l 応答性の向上︓送信者がメッセージを送ると、直ちに応答が返る。 結果を待たない。 l 疎結合・独⽴性︓メッセージキューにデータが⼀時保存されるので、 受信者側でリトライ処理やレートリミットが可能 = 信頼性の向上

Slide 25

Slide 25 text

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 リトライ、レートリミッター機能が標準装備で、別途開発する必要がない

Slide 26

Slide 26 text

⾮同期メッセージングアーキテクチャの活⽤例 l 活⽤例︓LINE公式アカウントからのメッセージ配信 l LINEのMessaging APIを使って、アプリケーションからメッセージを配信 l メリット︓ l スケーラブルで、信頼性の⾼いサービスの構築 l エラー発⽣時のリトライとレートリミットへの対策 Consumer(受信者)は Decatonを使って開発 リトライ⽤トピック 送信者

Slide 27

Slide 27 text

⾮同期メッセージングアーキテクチャの活⽤例 パーティション毎にQPSを設定 Messaging APIのレートリミット (2,000QPS) への対策 最⼤30分のエラーに 耐えられるように設定 リトライ間隔と 最⼤リトライ回数を設定 課題 エラー発⽣時のリトライとレートリミットへの対策

Slide 28

Slide 28 text

開発を⾏う上で⼯夫した点 l 各コンポーネントの役割を明確にして、機能を実装 Producer(送信者) l Kafkaにメッセージ送信 l LINEメッセージのデータ(JSON)の作成 Consumer(受信者) l Messaging APIのコール l リトライ・レートリミット 配信するLINEメッセージのデータに新規追加や変更が発⽣しても、 Producerのみの開発、デプロイで対応可能 = Consumerの再利⽤性が向上 メリット

Slide 29

Slide 29 text

CQRS l CQRS = Command Query Responsibility Segregation l データ更新(コマンド)とデータ取得(クエリ)を分離、別のモデルとして扱う l CQRSを使って、コマンドの役割を持つコンポーネントとクエリの役割を持つ コンポーネントで、マイクロサービスを構成する l メリット︓ l コマンドとクエリに対して、異なるスケーリングやアーキテクチャの適⽤が 可能

Slide 30

Slide 30 text

CQRSの活⽤例 l 活⽤例︓スタンプのデータ管理 l クエリのクライアントはLINEのユーザ、コマンドのクライアントはスタンプ制作者 l コマンド数よりも圧倒的にクエリー数が多い l クエリのパフォーマンス向上のため、Elasticsearch(Read Storage)とRedis(Cache)を使⽤ l MySQLとElasticsearchはバッチ処理で⾮同期にデータ同期 登録完了から参照可能までに遅延が 発⽣するが、機能要件として許容

Slide 31

Slide 31 text

CQRSの活⽤例 l 活⽤例︓あけおめスパイクへの対策 l 新年0時のタイミングで、毎年クエリ数のスパイクが発⽣する l 対策として、Elasticsearchを⼀定期間デュアル構成にして負荷分散 1/1の0時あたりのRPS︓ コマンドのアーキテクチャ変更なしに クエリ側をより柔軟に変更可能 メリット

Slide 32

Slide 32 text

CQRSの活⽤例 l 活⽤例︓データの同期に⾮同期メッセージングアーキテクチャを適⽤ l リアルタイムに同期することで、参照可能までの遅延を⼩さくする l Kafkaのトピックを公開して、スタンプ作成通知を他のチームでも受信可能 MySQLに登録完了後、 Kafkaにメッセージを送信 Elasticsearchの同期を リアルタイムに実施

Slide 33

Slide 33 text

発表の流れ まとめ l コンポーネント数過多による複雑さを解消するために、 コンポーネントドメインを導⼊ l コードベースの階層化でドメインを表現 l コードオーナーを設定して担当者を明確化 l コンポーネントやドメインの役割・責務を明確にして、 コンポーネントのモノリス化を防ぐ l ⾮同期メッセージングアーキテクチャやCQRSを活⽤して、 信頼性⾼い、かつ柔軟なマイクロサービスを構築

Slide 34

Slide 34 text

THANK YOU!

Slide 35

Slide 35 text

マイクロサービスを安全にリリース、運⽤する⽅法 l テスト l E2Eテストの⾃動化 l ミラーリクエストを使ったパフォーマンステスト l リリース l カナリアリリース l パーセンテージリリース l 監視 l ダッシュボードの整備 l 分散トレーシングの活⽤

Slide 36

Slide 36 text

E2Eテストの⾃動化 l リアーキテクチャでは基本、プロダクトの表⾯的な機能は変更されない l 機能が変わっていないこと、壊れていないことをリグレッションテストで担保 l E2E⾃動化テストの整備は⼈的リソースを節約できて、より効率的にテストを実施が可能 Seleniumや商⽤のテスト⾃動化 サービスを使⽤して、 ⾃動化テストを整備

Slide 37

Slide 37 text

ミラーリクエストを使ったパフォーマンステスト 課題 リア―キテクチャ後のマイクロサービスに対して、パフォーマンステストしたいが 負荷テストツールでは、実際のユーザのリクエストを再現することは難しい そのため、プロダクション環境にリリースして監視するケースが多い l Nginxのミラーリング機能を使⽤して、新コンポーネントに複製されたリクエストを送る l 旧新コンポーネントの負荷やパフォーマンスを⽐較して、問題ないかを監視する ミラーリクエストは元のリクエストを ブロックしないので、既存のサービス には影響しない

Slide 38

Slide 38 text

カナリアリリース l デプロイツールを使って、サーバを段階的にリリースする(1台→数台→すべて) l 問題があれば、変更をロールバックする l ⼿動作業が必要であるが、⽐較的簡単でリスク管理も適切に実施

Slide 39

Slide 39 text

パーセンテージリリース l 処理の切り替えをパーセンテージを指定することでリリースする(1%→10%→100%) l あらかじめアプリケーションに対して、この制御の実装が必要 l コストがかかるため、⼤規模な機能・変更のリリース時に使⽤するか検討 処理切り替えのパーセンテージは 構成管理サーバで管理 ex. Central Dogma

Slide 40

Slide 40 text

Central Dogmaの活⽤ l Central Dogma l サービス構成管理リポジトリ l LINEのOSS https://line.github.io/centraldogma/ l 設定ファイルを可⽤性⾼く、サーバ上でバージョン管理 l GitとZookeeperベースのフレームワーク l クライアントをアプリケーションに組み込んでおくと、リアルタイムで 設定値を⾃動で同期 l 設定ファイルをGitHub上で管理可能

Slide 41

Slide 41 text

ダッシュボードの整備 l マイクロサービスのすべてのコンポーネントの状態を可視化 l リアーキテクチャに伴うエラーや負荷の増加、パフォーマンスの低下も 早期に発⾒

Slide 42

Slide 42 text

分散トレーシングの活⽤ l マイクロサービス上でリクエストがどのコンポーネント間で伝播し、 処理されたかを可視化 l マイクロサービスのトレーサビリティの確保に有効 l リア―キテクチャ時の調査や効率性の検討上での材料としても有効

Slide 43

Slide 43 text

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 ⾃動リトライ、レイトリミッター、サーキットブレーカー