CodeZine(コードジン)

特集ページ一覧

これなら分かる!マイクロサービス(活用編)~そのアーキテクチャを実現するデザインパターンを一気に学習

  • LINEで送る
  • このエントリーをはてなブックマークに追加

目次

(2)保守性を高めるデザインパターン

データベースによる統合から卒業し、データ構造を隠蔽する:Database per Service(サービスごとのデータ)とPolyglot Persistence(多言語永続化)

 モノリスでは多くの場合、複数の機能がひとつのデータベースを操作します。マイクロサービスに分割した後もそのままだと、データ構造変更時に関連サービスへの影響考慮が必要となり、大量の回帰テストを実施する事態となります。また、多くのレガシーシステムはRDBを採用していますが、異なるデータストアを適用したくとも影響の規模が大きすぎ、採用を見送るケースも多いでしょう。

 そのような事態を避けるためにとられるのが、Database per Serviceパターンです。その名の通り、各データベースにアクセスするサービスは1個に限定します。他のサービスから参照・更新する際は、そのデータを管轄するサービスを介して行います。これによりデータそのものは隠蔽され、データ構造やデータストアの変更による影響を1つのサービスのみに局所化できます。

 なお、サービス特性にあわせて個別のデータストアを適用すべきという考え方は、Polyglot Persistence(多言語永続化[7])と呼ばれます。先に説明したPolyglot Programmingと同じように、データストアもまたパフォーマンスの重要性やトランザクション処理の要否など、サービスごとの特性や要件に合ったものを採用すべきという考え方で、こちらもシステムの最適化において重要です。

[7] 永続化:データベースやファイルなど、何らかの形式でデータを保存すること

図4:Database per Service(サービスごとのデータ)とPolyglot Persistence(多言語永続化)
図4:Database per Service(サービスごとのデータ)とPolyglot Persistence(多言語永続化)

データ管理をもう一歩細分化し、読み込みと書き込みに分離する:CQRS(Command Query Responsibility Segregation、コマンド クエリ責任分離)とEvent Sourcing(イベントソーシング)

 データベース操作はCRUD[8]という4種に分類されますが、そのうちの書き込みを意味するCUDと読み込みを意味するRでは、重視すべきことや検討すべきことが大きく異なります。具体的には、書き込みでは更新性能やデータの整合性が重視され、それらを確保するためのトランザクション制御やロックの確保などが検討されます。一方で読み込みの際は、参照性能や返却値の加工が重視され、INDEXの定義や読み込みデータによる値の計算処理などが検討されます。

[8] CRUD:CREATE(一般のSQLではINSERT文)、READ(一般のSQLではSELECT文)、UPDATE、DELETEの頭文字で、データ操作の基本的な4つをまとめた用語

 加えて、書き込みと読み込みの性能要件や処理負荷が大きく異なるサービスの場合、パフォーマンスチューニングやスケーリング[9]の検討を同じデータストアに対して行うことは、最適化を妨げる要因ともなります。

[9] スケーリング:マシンを高性能なものに入れ替えたり、台数を増やすことなどにより、システムの性能や処理能力を上げ下げする(スケールを変える)こと

 それらの課題を持つサービスに対し導入されるのがCQRSパターンです。図5のように、書き込み(=Command)と読み込み(=Query)でサービス(及びデータストア)を分離します。これにより書き込み側と読み込み側は、それぞれの処理に最適な実装及びデータ構造をとることができます。性能要件が異なれば、別の種類のデータストアを適用することや、配置先のハードウェアを分けることもできます。

注意

 2つのデータストアの同期をとるために、書き込みと同時のイベント処理にて読み込み側データへ更新をかけます。その際、(トランザクションを分けている場合は)書き込み側と読み込み側で更新のタイミングがずれるため、一時的にデータ不一致の状態となることには注意が必要です。加えて、リトライなどにより両者で不整合が出ることはないよう結果整合性[10]を保つ仕組みの適用も必要となります。

[10] 結果整合性:どこかのタイミングで「最終的には」一貫性がある状態になることを保証するという考え方

 なお、多くの場合CQRSと同時に適用されるのがEvent Sourcingパターンです。このパターンで書き込み側のサービスが行うのは、一般的に行われるように「データそのものを更新する」のではなく、「データを更新するという命令を保存する」という行為です。

 例えば、あるテーブルが持つカラムAの値を“1”に更新した状態を保存するのが一般的な更新処理ですが、Event Sourcingパターンでは「カラムAの値を“1”に更新する」という命令そのものを保存します。さらに、次の処理が“2”に更新する場合は、「カラムAの値を“2”に更新する」という命令が追加で挿入されます。

 このパターンを採用すると、書き込みの際に対象データを検索して更新する必要がないため、パフォーマンスの向上が期待できます。また、複数の処理が同一項目を更新することがなくなるため、競合が発生しにくくなります。その他には、命令が実行順に積みあがっていくため、そのままデータへの操作履歴になることもメリットのひとつです(図5の例で言えば、最終的なデータ状態だけを保存している場合見えなくなってしまう「item Aが追加し削除されたという事実」を把握することができます)。

図5:CQRS(コマンド クエリ責任分離)とEvent Sourcing(イベントソーシング)
図5:CQRS(コマンド クエリ責任分離)とEvent Sourcing(イベントソーシング)

  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:これなら分かる! エンジニアが知っておきたいIT業界用語

著者プロフィール

  • 西野 大介(SOMPOホールディングス株式会社)(ニシノ ダイスケ)

     SOMPOホールディングス株式会社デジタル戦略部(SOMPO Digital Lab)勤務。損保ジャパン日本興亜グループにおける先進技術の研究開発を担当。過去には基幹システムの開発にも従事し、SoR/SoE双方の開発において幅広い経験を持つ。本業以外では、CodeZineの連載をはじめ、国内/海外...

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5