現実のシステムはそんなに単純ではなく、処理の途中で外部のシステムへアクセスしたり、データベースへの書き込みや更新を複数回行うものがほとんどです。データベースへの永続化以外のすべての処理が終わってから永続化すれば原子性を担保することはできますが、トランザクションが非常に大きくなってしまうので、ある一つの処理が失敗しただけではじめからやり直すことになってしまい現実的ではありません。そこで、ステートマシンパターンを使うとトランザクションをより粒度の細かい単位に分割して、リトライの単位をそれぞれに分離することができます。トランザクション開始時に初期状態をデータベースに永続化します。クライアントがリトライをしてきた場合は、まずトランザクションの今の状態を取り出します。状態が終了状態ではない場合、以前の処理が正常に完了しなかったことを意味するので今の状態から次の状態に遷移できるように処理を再開します。冪等性もステートの単位で担保すれば良くなります。よりデータ不整合を修復できるようにはなりましたが、それでもリトライ試行時間内で解決できなかったケースは発生します。エラーハンドリングにバグがありリトライ不可能なエラーとしてクライアントに返してしまったためリトライされなかったようなケースもあるかもしれません。通常の処理とは独立して非同期で動き、データ不整合を修復する仕組みです。確認し、不整合があれば修復します。上記のようにトランザクションの状態管理をステートマシンにより行っている場合は終了状態になっていないトランザクションを取り出し、終了状態に進めるように処理を再開することでデータの修復を行うことができるケースもあります。考え方は非常にシンプルですが、システムが提供しているメインの処理とのデータ競合に気をつける必要があります。リクエストの処理結果をバッチが上書きしてしまうといったことが起こりえます。そのため、バッチの実装や実行タイミングを設計するときはデータ競合を十分に考えなければなりません。実行をしているとも限りません。ドキュメントには以下のような記述があります。回」を基本に処理を行うよう設計されています。まれに、同じジョブの複数のインスタンスがリクエストされる可能性があります。ハンドラはべき等である必要があります。コードを記述する際は、このような状態が発生した場合に有害な副作用が発生しないようにする必要があります。バッチが複数同時に起動したことにより新たなデータ不整合が発生したら元も子もありません。パターンアプリケーションのユースケースの都合により、「確実に処理できる」と事前に分かった上で別のタイミングでその処理を実行したいようなケースがあります。つのインターフェースです。最終的には必ず成功しなければなりません。時にデータベースがダウンしていたとしても、データベースが復帰した際の処理の確定を保証しなければなりません。呼び出し、処理を中止することになります。サービスを模した図を元に、分散システムではいかに予測できないエラーが起こりうるかを見てきました。データ不整合が発生した場合、どのようにしてそれを修復し、結果整合性を担保するかの一例を紹介しました。自分の働いている会社ではマイクロサービスアーキテクチャを採用しており、上記で紹介したことのほぼ全てを実際に経験してきています。マイクロサービスアーキテクチャはまさに数多くのサービスがネットワークを通じて接続されている分散システムです。マイクロサービスアーキテクチャを採用するということはこういった大きな複雑さと常に向き合っていかないといけないことを意味しています。いえ、これらの複雑さと向き合うということは難しくも非常にチャレンジングで楽しいのでぜひ体験してみてください。系の会社で働いているのであれば必ず遭遇することになると思います。最後にこれらへの知識を深めるために役に立った記事や本を紹介します。いう知見の塊のようなサイトの一記事です。シングルマシンでは単純に動くアプリケーションであっても分散システム上に構築するとどれだけ複雑になるかが書いてあります。マイクロサービスを開発する前に読んでおくとコーディングの際に意識できるようになるかもしれません。おいて多重決済を防ぐためにどういった基盤を構築しているかを紹介した記事です。関する詳細な説明もあるのでぜひ一読してみることをおすすめします。docs.microsoft.comクラウドネイティブなアプリケーションをつくる上で役に立つ設計パターン集です。それぞれのパターンの使い所、メリットとデメリットが詳しく書いてあります。あるので聞いたことがあるパターンや興味のあるパターンをかいつまんで見ていくといいかもしれません。単行本(ソフトカバー)データベースをはじめとするデータシステムのアーキテクチャについて非常に広い範囲にわたって書かれている本です。章の「一貫性と合意」あたりを読むと分散システムの難しさと面白さが嫌というほどわかると思います。キャッシュ用途のみに使用している場合など*4:逆にリトライを実装しないアプリケーションは一度のタイムアウトによりアプリケーションの可用性を落としてしまうことになるため、現実的ではありません*5:あるリクエストを複数回投げたとしても常に同じ結果を返す性質*6:常に一回だけ実行されるということ。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。