BT

最新技術を追い求めるデベロッパのための情報コミュニティ

寄稿

Topics

地域を選ぶ

InfoQ ホームページ ニュース マイクロサービスアーキテクチャの正しい設計 - QCon NYで学んだMichael Bryzak氏の教訓

マイクロサービスアーキテクチャの正しい設計 - QCon NYで学んだMichael Bryzak氏の教訓

ブックマーク

原文(投稿日:2018/07/15)へのリンク

先日のQCon New York 2018で、Michael Bryzek氏が、マイクロサービスアーキテクチャを“正しく”設計する方法について論じた。おもな内容は次のとおりだ。1) ボイラプレートコードの自動生成を可能にするために、最初にすべてのAPIとイベントのスキーマを設計すること。2) APIの直接呼び出しよりも、イベントストリームのサブスクライブを優先すること。3) デプロイや依存性管理などの自動化に注力すること。4) 品質向上とメンテナンスの合理化、継続的デリバリを実現するため、シンプルかつ効果的なテストの作成に重点を置くこと。

Flow.ioの創設者のひとりで、同社の社長兼CTOのBryzek氏(Giltの共同創設者でもある)の講演は、システム内のURLを'foo.com/latest/bar.js'から'foo.com/1.5.3/bar.js’に変えたいと要求したところ、“変更には数週間が必要”な上、実施に必要なリソースがチームにないと返答されたという、個人的なエピソードの紹介から始まった。簡単なURLフォーマットの変更がこれほどの作業量になることに氏は驚いたが、その後、該当のURLがあるライブラリの中に実装されているため、100件単位の依存サービスを変更する必要があることや、その中のいくつかは何年も修正されておらず、ビルドと再デプロイにはさらに依存関係のアップデートが必要になることが分かったのだった。

このエピソードは、短期的な開発期間のために将来の機能的課題を犠牲にしたという点で、“いまひとつな(not so great)アーキテクチャ”の典型的な例だ。これと対照的な、優れた(great)アーキテクチャには、開発チームのスケールアップを積極的に支援し、品質を確保し、高パフォーマンスと低コストを実現すると同時に、将来的な機能についても無理なくサポートできることが必要だ。マイクロサービスアーキテクチャは、システム実装の現代的なスタイルとして定着しているが、正しい方法で設計する必要がある – “スパゲッティ”なシステム設計ではなく、“階層的”なアプローチを目指さなくてはならない。

Bryzek – Great Architecture

次にBryzek氏は、マイクロサービスにまつわる一般的な誤解について説明した。最初の誤解は、“マイクロサービスでは、各チームが自らのタスクに最適なプログラミング言語とフレームワークを選択することができる”、というものだ。現実には、これは高価なものになる可能性がある。テクノロジスタックで他の言語をサポートするか否かを判断する上では、チームの規模と投資が重要なインプットになる。

優れたエンジニアリング企業の例としてGoogleを取り上げるならば、同社には20,000~30,000人のエンジニアと、少なく数えて8つのプログラミング言語があります。ここから、[企業内の}エンジニア4,000人毎にひとつのプログラミング言語[を採用する]、と言えます。

第2の誤解は、“コードの自動生成はよくない”、という考え方だ。しかしながら実際には、“100パーセント信頼できる定義済みスキーマの生成”は、リソースやイベントにおいて重要な意味を持っている。コードの自動生成は開発作業の拡大やメンテナンスの面で極めて有用なのだ。第3の誤解である“イベントログは真実を語る資料でなければならない”というのは、イベントがインターフェース上の重要な部分である、という事実に基づくものだが、“サービスが自身のリソースの記録システムであれば問題にはならない”。そして、“開発者は3つ以上のサービスをメンテナンスすることはできない”という最後の誤解に対して氏は、事実に基づいた議論によって、これが誤った評価基準であるとして否定した。適切に実行すれば、この部分にこそ“自動化の輝ける”場所がある、とBryzek氏は言う。Flow.ioの開発者は平均5つのサービスをメンテナンスしているが、毎週のメンテナンスに必要な時間は全体の5パーセント未満なのだ。

次には、Flow.ioのアーキテクチャが紹介された。そのひとつが、JSONで記述されたリソース指向のAPI定義スキーマである。これにより、エンティティとそれに対応するプロパティをすべて、適切なメタデータとともに定義することが可能になる。スキーマ定義ファイルはGit DVCSに格納され、継続的インテグレーションが実践されている。一連のテストによってAPIセット全体の一貫性が保たれるとともに、事実上の高度なリンタ(linter)としても機能する。これらテストの目標は、“ひとりの人間がAPI全体を記述した”という認識をエンジニアがもつべきである、ということだ。

エンジニアリングチームでは、オープンソースのapibuilder.ioツールをテストと組み合わせて使用している。これによって、API設計フェーズにおけるエラーの防止と潜在的な変化点の検出が可能になる。apibuilder CLIユーティリティを使えば、リソースAPIとルート(Flow.ioでは、おもにPlay 2フレームワークで記述されている)に関連付けられたコードを生成および更新することができる。APIクライアントのコードも自動生成可能である。生成されるコードには、高品質かつ高速なテストが可能なモッククライアントも含まれる。Flow.ioのアーキテクチャ内では記録システムがAPI仕様である、とBryzek氏は述べている。コードを自動生成することで、“実際に仕様に準拠している”ことが保証されるのである。

続くデータベースアーキテクチャに関する議論では、それぞれのマイクロサービスアプリケーションに独自のデータベースを持つ方法が提案された。このデータベースには、他のサービスから直接接続することはできない – 提供されるAPIとイベントストリームからなる、サービスインターフェースのみを使用可能とするべきだ。Flow.ioのエンジニアリングチームでは、すべてのインフラストラクチャと共通的な開発タスクの管理に利用可能な、単一のCLI“開発”ツールに多くの投資を行ってきた。データベース(下記の例ではAWS RDSを使用)は、コマンドひとつで生成できる。ストレージ要件はすべてJSONスキーマを使って定義する。このスキーマは関連するAPIスキーマからは独立しているが、同じツールチェーンを使用する。テーブル生成などのデータベースのDDL操作とコンフィギュレーションは、関連するアプリケーションサービスクライアントDAO(Data Access Object)コードとして自動生成される。これによってデータベースアクセスが正規化され、最初から適切なインデックスが用意されるようになる。

次のセクションでは、コードのデプロイメントに焦点が当てられた。そのトリガとなるのは、関連するGitタグの作成だ。タグはマスタ変更(プルリクエストのマージなど)によって自動生成され、“100パーセントの自動化と、100パーセントの信頼性を実現している”。Bryzek氏は、Flow.ioの継続的デリバリ管理システムである“delta”(GitHubでコードが公開されている)をデモンストレーションして、このプラクティスの重要性について解説した。

継続的デリバリは、マイクロサービスアーキテクチャを管理するための前提条件です。

各マイクロサービスに必要なインフラストラクチャの定義構造はシンプルで、計算インスタンスのタイプやオープンするポート、OSコンフィギュレーションのバージョンなどのメタデータを定義した単一のYAMLファイルが生成される。システム内の全サービスは、標準化された“ヘルスチェック”エンドポイントを公開することで、デプロイメントや監視、アラートなどのツールがその健全性を管理できるようにしている。

講演の次のセクションでBryzek氏は、イベントとイベントストリーミングの重要性について論じた。Flow.io APIへのアクセスを希望するサードパーティは多いが、それに対して氏は、“素晴らしいAPIがありますが、代わりにイベントストリームをサブスクライブしてください”、と答えている。イベントインターフェースには重要な原則がある。1) すべてのイベントに対するファーストクラスのスキーマ提供、2) プロデューサによる最低1回のデリバリ保証、3) コンシューマによる冪等性の実現、である。Flow.ioのアーキテクチャでは、エンドツーエンドのイベントレイテンシは500ms以内で、実装はPostgreSQLをベースとしており、サービス当たり1日10億イベントまでスケール可能である。

Bryzek – principles of an event interface

イベントによるアプローチでは、プロデューサがデータベーステーブルに対するレコードの挿入、更新、削除といったすべての操作のジャーナルを生成する。イベントが生成されると、対応するジャーナルレコードが発行キューに挿入される。この処理はリアルタイムかつ同期的に実行され、ジャーナルレコードについてひとつのイベントが発行される。サービスからのイベントを再実行するには、単にジャーナルレコードを再キューすればよい。コンシューマは新たなイベントを、削除の高速化のためにパーティショニングされたローカルデータベースに格納する。イベントが到着すると、レコードがコンシューム(consume)のためにキューされる。イベントはマイクロバッチ処理される。コンシュームの実行間隔は、既定では250msである。障害の発生はローカルに記録される。このアプローチに関する詳細な情報やサンプルコードは、Gilt Technologyのdb-journalingリポジトリで参照可能である。I興味のある読者は、同様のコンセプトであるCDC(Change Data Capture)や、Debeziumなど同種のオープンソーステクノロジの例も参照するとよいだろう。

講演の最後のセクションでは、依存性管理と“最新性の維持”に重点が置かれていた。目標は、すべてのサービスが依存関係の最新バージョンを利用するように定常的かつ自動的に更新することだ。セキュリティパッチやコアライブラリのバグ修正では、これが不可欠である。オープニングで紹介されたエピソードを再び参照しながら、氏は、“これは週や月単位ではなく、数時間で行うべきだ”とした上で、社内で開発したライブラリにも外部のオープンソースと同じプロセスを適用する必要がある、と述べた。Flow.ioのエンジニアリングチームは毎週、すべてのサービスの依存関係を最新にアップデートしている。依存関係のトラッキングには、独自開発の“flowcommerce/dependency”ツール(オープンソースとしてリリースされている)を使用する。このツールは、サービスコード内で自動アップグレードを起動すると同時に、関連するプルリクエストを生成する。ビルドが完了すれば、各サービスは即時デプロイされる仕組みだ。

講演の要約として氏は、APIやイベントよりも先にスキーマを設計すべきであり、APIの直接コールよりもイベントのコンシュームを選択すべきである、と述べた。デプロイやコード生成、依存性管理といったタスクに重点を置きながら、適切かつ効果的な自動化に投資することが必要だ。また、品質を向上し、メンテナンスを合理化し、継続的デリバリを可能にするために、“驚異的かつシンプルな”テストの記述に努め、それを可能にする必要がある。

Michael Bryzek氏がQCon New Yorkでの講演“Designing Microservice Architectures the Right Way”で使用されたスライドは、SlideShareで公開されている。このプレゼンテーションを含むQCon New Yorkの講演のビデオは、今後数ヶ月間にわたってInfoQ.comでリリースされる予定である。

 
 

この記事を評価

採用ステージ
スタイル
 
 

この記事に星をつける

おすすめ度
スタイル

BT