そもそも整合性ってほんとに大事なの?PF立ち上げの中で悩んだ整合性の話
こんにちは。Showcase Gigでエンジニアをしている田坂@yuuuutskです。
この記事は、Showcase Gig Advent Calendar 2021 3日目の記事です。
今日は以前開催された合同勉強会で話した内容を内容を拡充して記事化しました。
この勉強会はShowcase Gig, Alpさん, LegalForceさんの3社とソフトウェア設計で著名な増田亨さんをお招きし、各社の日ごろソフトウェア設計における悩みや実践していることをインプットをもらいながらざっくばらんに話す座談会形式で開催されました。
その中の弊社のパートでプラットフォーム開発をする中での整合性と向き合った話をしています。
整合性はソフトウェア開発をするにあたって意識せざるを得ない重要なトピックで、主に一連の処理の途中の失敗などの異常系の時に設計の良し悪しが試されます。
クラウドネイティブなこの時代では、アーキテクチャの結合度にかかわらず整合性を意識しなくてはならないケースが多いです。
そこで今回は勉強会の内容に沿って整合性に関して弊社の事例に沿って思考したことや実践していることに関して書いていきます。
弊社の作っているプロダクトやシステムの概要
弊社の作っているプロダクトやシステムの概要について触れさせてもらいます。 弊社では次世代の創出プラットフォーム(O:der Platform)とプロダクトを開発しています。
O:der Platformには飲食に関する「価値あるマスターデータ」と「ID」を軸にしたAPI群で構成されいて、それらは各プロダクトが使いやすいように、より高凝集かつ疎結合さを求めなければなりません。
飲食のプロダクトはイートインやテイクアウト、KIOSKなどさまざまな提供手法がありますが、これらのプロダクトを構成する機能はプリミティブに分解すると「マスターデータ操作系」「注文」「会計」「決済」などに抽象化されます。
注文を例に整合性について考える
ユースケース(プロダクト)毎に注文の一連の処理の流れや順序は異なるので、この例ではテイクアウトを例とします。
注文はテイクアウトのユースケースにおいて、「注文」→ 「会計」→ 「決済」→ 「完了メール」の順で手続きが行われます。
一連の手続きではそれぞれ事実の記録を1:1:1でされます。この中で注文と会計だけ永続化できていて決済ができてなかったり、決済はできているが注文が通っていないなどの状態は不整合が起きている状態と言えます。
一連の手続きの中で事実の記録や不整合がどんな状況で起こるか、分散トランザクションで実装した場合とそうでない場合で振る舞いが異なるのでそれぞれシーケンスをもとに解説します。
分散トランザクションをしない実装かつプロダクトバックエンドで処理が簡潔する場合においては 一連の処理のどこで失敗しても一気にロールバックできるので、「強い一貫性」を担保しやすいです。つまり整合性についてあまり気にとどめる必要はありません。
例えば、この手続きの中で外部のAPIを読んだとすると大きく状況は変わります。 一連の手続きにおいて処理がサーバで分かれているつまり分散システムのときには否が応でも分散トランザクションになってしまいます。
弊社のシステムは以下の図のようにバックエンドサーバがプロダクトとプラットフォームサーバで分かれていたり、決済代行APIを利用するような分散システムで構成されています。
一連の処理のどこかで失敗したときに不整合発生するケースがあります。
処理の始まりのプロダクトバックエンドの手続き2-5の間で失敗した場合は、同一DBトランザクション内であれば一括ロールバックが可能で一貫性を保つことは難しくありません。
一方、手続き3以降はどこで失敗しても一括でロールバックする難易度が格段に上がります。
例えば、手続き6で決済結果をDBに永続化する処理で失敗した場合にリトライなどで一定回数試行することで最終的に成功にできるケースも多いですが、リトライにも上限はあるので上限を超えたときのことも考えなくてはなりません。
最終的に失敗した場合、事実の記録の組み合わせの整合性があっていない状態になります。 整合性があっていない状態になったとき不整合を解消する必要あるケースもあります。
不整合の解消責務と戦略
分散システムでは不整合の解消責務と戦略も考える必要があります。 弊社のようなプラットフォームとプロダクトから構成されるシステムでは、プロダクト側から利用されるプラットフォームの機能群はユースケースによって呼ぶ順序が変わってきます。
弊社のテイクアウトのユースケースでは注文と会計決済はすべて完了していないとお客様に商品をお渡しできない「都度会計」形式ですが一方で、イートインプロダクトでは注文を繰り返し行い最後に会計する形式なので事実の記録の対応関係は異なります。
こういった背景から整合性の定義や解消責務はプロダクト側にあると言えます。
分散システムにおける、不整合解消はTCCパターンやSagaパターンなどのトランザクション制御パターンの選択肢がありますが向き合うコストはとても高い課題です。
そもそも整合性ってほんとに大事なの?
設計勉強会の中でこの課題に対してヒントをもらうべく、増田さんから前提を問う質問(そもそも質問)をいただきました。
(増田さんを交えた勉強会ではそもそも質問がたびたびあり、その度よい学びとできる非常に有意義な問いかけで弊社の中で名物化しています)
それは、「そもそも整合性ってほんとに大事なの?」「ほかにもっと大事なことがあるんじゃないの?」といった質問でした。
我々は、エンジニアとしてシステムで整合性を担保することに固執していたことに気付きました。
今一度考えたところ、システムはまだ立ち上げ初期であり大規模システムでもなく改善サイクルを回していくフェーズな前提で考えたとき
結論、一連の処理において不整合が起きた時に機能的に使えていれば良く、解消すべき不整合があったときに解消できれば問題はなく
以下の3つが大事なことだとわかりました。
不整合に気付けること
不整合を解消できること
手動や必要に応じて自動
そして学びからの実践として、以下の対応を実施しました。
失敗時のアラートを仕込むことで不整合に気付ける体制を作る
不整合が起きるケースをもとに、どんな時にどのように不整合を解消すべきかを整理
プラットフォーム側が提供しているAPIを利用して不整合解消機能をプロダクト側で実装した
不整合解消に不足していたプラットフォーム機能を追加
終わりに
弊社のシステムを例に整合性をテーマにあげました。
近年のクラウドネイティブの時代に分散システム(分散トランザクション)は避けられないケースが多く関心毎として一度はとおる道のエンジニアも多いのではないでしょうか。
その中で整合性との向き合い方はフェーズにはよって違ったものなるということは当初の我々としては大きな学びでした。
エンジニアとして完成度を求めたい部分はあるものの、事業や組織またはシステムの開発フェーズに応じてあるべき姿と現状どこまでやるかを常に問いかけすることは大切な議題です。
今回の弊社の事例がほかの方の悩みの解消につながると良いです。
以上、Showcase Gig Advent Calendar 2021 3日目でした。 また明日の記事をお楽しみに。
この記事が気に入ったらサポートをしてみませんか?