この記事は 株式会社うるる(ULURU) Advent Calendar 2023 の5日目の記事です。
今年もこの季節がやってきましたが、年末の振り返りということで今年読んだ書籍で納得感が強く、個人的に興味深かった内容を、数年前のしくじりと照らし合わせって振り返ってみます。
『ソフトウェアアーキテクチャ・ハードパーツ』という書籍で説明がされている、12章:トランザクショナルサーガの内容について触れていきます。
ソフトウェアアーキテクチャ・ハードパーツ
ソフトウェアアーキテクチャ・ハードパーツとは、オライリーより出版されている、ソフトウェアアーキテクチャに関するハードパーツ(難しい側面)への対峙の仕方について記載された書籍です。
ソフトウェアのアーキテクチャは、後から変更することが難しいこと、事業や組織に影響を与えるため難しい判断になることがあり、そういった難しさをハードパーツとして捉え、その難しさの説明と対峙の仕方が記載されています。
12章:トランザクショナルサーガ
12章では、トランザクショナルサーガとして8つのパターンを紹介している。
サーガ(Saga)は、マイクロサービスにおけるローカルトランザクションの順次処理として説明されている概念で、複数の処理を実行する中でいずれかの処理が失敗したときに補償トランザクションをもって整合性を保ちにいく概念です。
このサーガについて、3次元のマトリクスを用いて8つのパターンを整理して解説をしているのがこの章の内容です。
トランザクショナルサーガパターン
まず、8つのパターンを以下のように表で整理しています。
パターン名 | 通信 | 整合性 | 調整 |
---|---|---|---|
エピックサーガ(sao) | 同期 | アトミック | オーケストレーション |
伝言ゲームサーガ(sac) | 同期 | アトミック | コレオグラフィ |
おとぎ話サーガ(seo) | 同期 | 結果整合性 | オーケストレーション |
タイムトラベルサーガ(sec) | 同期 | 結果整合性 | コレオグラフィ |
ファンタジーサーガ(aao) | 非同期 | アトミック | オーケストレーション |
ホラーストーリーサーガ(aac) | 非同期 | アトミック | コレオグラフィ |
パラレルサーガ(aeo) | 非同期 | 結果整合性 | オーケストレーション |
アンソロジーサーガ(aec) | 非同期 | 結果整合性 | コレオグラフィ |
パターン名に記載されるアルファベット表記については、各次元における値の頭文字を組み合わせたものです。
※各次元におけるそれぞれの説明は省略します
- 通信
- 同期(synchronous) / 非同期(asynchronous)
- 整合性
- アトミック(atomic) / 結果整合性(eventual consistency)
- 調整
- オーケストレーション(orchestrated) / コレオグラフィ(choreography)
数年前のしくじりについて
数年前に、一度リリースおよびproduction環境での稼働まで持ち込んだデータ連携アーキテクチャを切り戻して停止させる判断を行ったことがありました。
この内容の詳細については、2022年の Developers CAREER Boost にて弊社メンバーの @KawamotoShuji が登壇した際に触れており、そちらをご参照ください。
「非常に残念ですが、 切り戻しましょう...」 システムリプレイスのアンチパターンに立ち向かったリーダーの話
このときに語られているアーキテクチャとして、オープンソースのRDB同期ツール(SymmetricDS)を使ったアーキテクチャを紹介しています。
このツールはRDB同期ツールという性質を前提としながら、細やかなトランスフォームを実現できることを謳っていたりとETLのツールとしても利用できる算段がありました。
そのため、スキーマの違うデータベース間を連携するプロジェクトにおいて採用をしました。
SymmetricDS 自体のアーキテクチャ説明をした記事も載せておきます。
何がしくじりだったのか
SymmetricDS を使ったアーキテクチャは、全体として SymmetricDS を中心におきながら各データベースとの連携処理を担う形となっていました。
つまり、SymmetricDS 自体がオーケストレーションを担う役割でした。
次に、MySQLの trigger 機能を活用し Extract, Transform, Load までを担う機構ではあったのですが、それぞれの処理においてエラーが発生するとそのエラーを解消もしくは無視するなどの対応を行わない限りその他の処理が進まない制御が行われていました。
データの整合性についてアトミック性を担保するような思想を持ち合わせていました。
一方で、各 trigger で起動される処理は、他の trigger との優先順位などを気にすること無く、それぞれが非同期で処理がされるような機構になっていました。
例えば trigger A による処理が参照するテーブルレコードが多いことで参照処理に時間がかかっている間に、外部キー制約のあるテーブルとの連携を行う trigger B による処理のほうが早く進行するようなことが起こり得ました。
これらをトランザクショナルサーガパターンに当てはめると、
- 非同期(asynchronous)
- アトミック(atomic)
- オーケストレーション(orchestrated)
の3要素が揃っており、ファンタジーサーガと呼ばれるパターンに該当します。
このファンタジーサーガパターンは、書籍の中で下記のように言及されています。
次元の組み合わせが存在するからといって、それが魅力的なパターンを形成するわけではない。 とはいえ、この比較的ありえない組み合わせには用途がある。このパターンは、通信以外のすべての面でエピックサーガ (sao) に似ているが、通信は同期ではなく非同期となっている。従来、分散システムの応答性を高める方法の一つとして、非同期性を利用して、操作を連続的ではなく並行して行う場合があった。これは、エピックサーガ (sao) のパフォーマンスを向上させるのに良い方法だと考えられている。
しかし、非同期性は単純な変化ではない。アーキテクチャに何層もの複雑さをもたらし、特に調整に関しては、オーケストレーターにさらに多くの複雑さを要求する。たとえば、トランザクション型のワークフローαが始まったとしよう。すべてが非同期なので、ワークフローαが保留されている間に、ワークフローβが始まる。ここで、オーケストレーターは保留状態にある進行中の全トランザクションの状態を把握しなければならない。
さらに悪いことがある。ワークフローγが始まったとして、ドメインサービスへの最初の呼び出しは、まだ保留中のαの結果に依存しているとしたら、この動作を果たしてモデル化できるだろうか。可能ではあるだろうが、複雑さは増すばかりだろう。
オーケストレーションベースのワークフローが非同期に行われると、非同期なトランザクションの状態が存在することになり、順序性を前提とできなくなるばかりでなく、デッドロックやレースコンディションをはじめとした並列システムが持つ課題が発生する可能性がある。
※ソフトウェアアーキテクチャ・ハードパーツ 12章 12.1.5 より引用
「この比較的ありえない組み合わせ」とは、なんということでしょう。
とは言え、説明されている内容はまさに運用を始めた段階で痛いほど痛感したことと一致する内容でした。
当時、書かれているようなパフォーマンス向上のためにこのパターンを選んだわけではないのですが、結果的にこのパターンに該当するアーキテクチャを採用した形となっていました。
だからあれだけしんどい状況を起こしたのだと、納得のいく内容でした。
また、当時はSagaパターンについての知識がなく、補償トランザクションを行うなどの観点がまったく持てていなかったことも思い出されます。
こういった、知識と経験に裏打ちされた書籍の内容は非常に参考になること感心の限りでした。
最後に
当時にソフトウェアアーキテクチャ・ハードパーツの書籍が存在していたらこのパターンを回避できていた自信があるかを問われても、正直自信はありません。
失敗した経験があったからこの書籍の内容が身にしみて理解でき、参考になったと捉えている節は大きいです。
実際、アーキテクチャを考える必要がある場面ではソリューションありきで思考が進むことが多いのですが、その前提となるポイントを抑えることが非常に大事で、この書籍を囲みながら議論をすることでトレードオフの選択をくぐり抜け、最悪の選択を避けることに役立てられると感じることができました。
さて次回は数日間あいてしまいますが、@DoueKazuna 氏による記事をお楽しみにお待ちください!