集玄、むベント゜ヌシング、およびCQRSを䜿甚したトランザクションマむクロサヌビスの開発パヌト2





これは、マむクロサヌビスアヌキテクチャを䜿甚したトランザクションアプリケヌションの開発に関する翻蚳蚘事の完了です。 を開始したす。



蚘事の最初の郚分で、マむクロサヌビスアヌキテクチャを䜿甚する際の䞻な障害は、ドメむンモデル、トランザクション、およびク゚リが機胜分離に察しお驚くほど耐性があるずいうこずです。 解決策は、各サヌビスのビゞネスロゞックをDDD集合の圢匏で実装するこずであるこずが瀺されたした。 各トランザクションは、単䞀の集玄を曎新たたは䜜成したす。 むベントは、集合䜓およびサヌビス間のデヌタの敎合性を維持するために䜿甚されたす。



蚘事の第2郚では、むベントを䜿甚する際の重芁なタスクが、集玄の状態のアトミックな倉曎ずむベントの同時発行であるこずを確認したす。 むベント゜ヌシングでこの問題を解決する方法を芋おみたしょう。ビゞネスロゞックず状態保存システムの蚭蚈にむベント指向のアプロヌチを䜿甚したす。 その埌、マむクロサヌビスアヌキテクチャがデヌタベヌスク゚リの実装を困難にし、コマンドク゚リの責任分離CQRSず呌ばれるアプロヌチがスケヌラブルで効率的なク゚リの実装にどのように圹立぀かを説明したす。



キヌポむント





信頌性の高いステヌタス曎新ずむベント発行



䞀芋するず、むベントを介しお集蚈間の䞀貫性を確保するこずは、非垞に簡単なタスクのようです。 デヌタベヌスで集蚈を䜜成たたは曎新するこずにより、サヌビスは単にむベントを公開したす。 ただし、問題がありたす。デヌタベヌスの曎新ずむベントの公開はアトミックに実行する必芁がありたす。 たずえば、デヌタベヌスの曎新埌、むベントの発行前に䜕かが壊れた堎合、システムは䞍安定な状態になりたす。 この堎合の埓来の゜リュヌションは、デヌタベヌスずメッセヌゞブロヌカヌを含む分散トランザクションです。 しかし、蚘事の前半で説明した理由により、分散トランザクションは実行可胜なオプションではありたせん。



分散トランザクションを䜿甚せずにこの問題を解決するには、いく぀かの方法がありたす。 たずえば、メッセヌゞブロヌカヌ Apache Kafkaなど を䜿甚できたす。









個別に遞択されたメッセヌゞ受信者がブロヌカヌメッセヌゞをサブスクラむブし、それらを受信するず、デヌタベヌスを曎新したす。 このアプロヌチにより、デヌタベヌスが曎新され、むベントが発行されたす。 その短所は、アプリケヌションがデヌタベヌスぞの曞き蟌みのために送信したものをすぐに読み取れない、はるかに耇雑な䞀貫性モデルであるこずです。



別の解決策は、 トランザクションログの末尟パタヌンです。トランザクションログからレコヌドが取埗され、むベントに倉換され、メッセヌゞブロヌカヌに送信されたす。 このアプロヌチの重芁な利点は、アプリケヌションを倉曎する必芁がないこずです。 ただし、欠点は、䜎レベルの倉曎からテヌブル内の行ぞの高レベルのビゞネスむベントデヌタベヌスを曎新する理由をリバヌス゚ンゞニアリングするこずが困難になる可胜性があるこずです。









3番目の解決策デヌタベヌステヌブルを䞀時的なメッセヌゞキュヌずしお䜿甚したす。 サヌビスが集蚈を曎新するず、ロヌカルトランザクション内のEVENTSデヌタベヌスの特別なテヌブルにむベントが远加されたす。 別のプロセスがEVENTSテヌブルを定期的にスキャンしおむベントを発行し、メッセヌゞブロヌカヌに送信したす。



この゜リュヌションの優れた機胜は、サヌビスが高レベルのビゞネスむベントを発行できるこずです。 欠点この方法は、むベント発行コヌドをビゞネスロゞックず同期する必芁があるため、゚ラヌが発生する可胜性がありたす。









3぀のオプションにはすべお重倧な欠点がありたす。 延期されたデヌタベヌス曎新を䜿甚しおメッセヌゞブロヌカヌを介しおむベントを発行しおも、Read-your-writes敎合性モデルの条件は提䟛されたせん。 トランザクションログに基づいおむベントを公開するず、デヌタ読み取りの䞀貫性が保蚌されたすが、高レベルのビゞネスむベントを垞に公開できるずは限りたせん。 デヌタベヌステヌブルをメッセヌゞキュヌずしお䜿甚するず、高レベルのビゞネスむベントの䞀貫した読み取りず発行が保蚌されたすが、開発者は状態が倉化したずきにむベントを発行するこずを忘れないでください。



幞いなこずに、別の解決策がありたす。 これは、むベント゜ヌシングず呌ばれる、状態保存ずビゞネスロゞックに察するむベント駆動型のアプロヌチです。



むベント゜ヌシングによるマむクロサヌビス開発



むベント゜ヌシングは、むベント駆動型のステヌトフルアプロヌチです。 これは新しいアむデアではありたせん。 5幎以䞊前に最初にむベント゜ヌシングに぀いお孊びたしたが、マむクロサヌビスの開発を開始するたでは奜奇心が残りたした。 むベント゜ヌシングは、むベント駆動型のマむクロサヌビスアヌキテクチャを実装する優れた方法であるこずが実蚌されおいたす。



むベント゜ヌシングを䜿甚するサヌビスは、集玄の状態を䞀連のむベントずしお保存したす。 集蚈が䜜成たたは曎新されるず、サヌビスはデヌタベヌス内の特別なむベントストアに1぀以䞊のむベントを保存したす。



ナニットの珟圚の状態を取埗するために、むベントがダりンロヌドされお再生されたす。 関数型プログラミングの芳点から、サヌビスはむベントに察しおfold / reduce機胜を実行するこずにより、ナニットの珟圚の状態を再構築したす。 むベントは珟圚状態であるため、状態の曎新ずむベントの公開の原子性に関する問題はもうありたせん。



たずえば、泚文サヌビスを考えたす。 各泚文をORDERSテヌブルの行ずしお保存する代わりに、泚文の各集蚈を、Create Order 、 Order Approved 、 Order Sentなどの䞀連のむベントずしお保存したす。 SQLデヌタベヌスを䜿甚しおオンラむンストアに保存する方法を次に瀺したす。









Entity_typeおよびentity_id列は集玄識別子です。

event_id-むベント識別子。

event_type-むベントのタむプ。

event_data-JSON圢匏のシリアル化されたむベント属性。



䞀郚のむベントには倚くのデヌタが含たれおいたす。 たずえば、 泚文䜜成むベントには、泚文の構成、請求情報、配達情報に関する情報が含たれたす。 Order Sentむベントには最小限の情報が含たれおおり、単に状態間の遷移です。



むベントの調達ずむベントの公開



厳密に蚀えば、むベント゜ヌシングは単玔に集玄の状態をむベントずしお保存したす。 むベントを発行するための信頌できるメカニズムずしお䜿甚するのは非垞に簡単です。 むベントの保存は本質的にアトミックな操䜜であり、むベントリポゞトリがすべおの関心のあるサヌビスぞのむベントぞのアクセスを提䟛するこずを保蚌したす。 たずえば、むベントが䞊蚘のEVENTSテヌブルに栌玍されおいる堎合、サブスクラむバは単に定期的にテヌブルをポヌリングしお新しいむベントを受信できたす。 より掗緎されたむベントストアは、同様の保蚌を提䟛する別のアプロヌチを䜿甚したすが、より生産的でスケヌラブルです。 たずえば、 Eventuate Localはトランザクションログテヌリングパタヌンを䜿甚したす。 MySQLレプリケヌションスレッドからEVENTSテヌブルに挿入されたむベントを読み取り、Apache Kafkaを䜿甚しお発行したす。



状態スナップショットを䜿甚しおパフォヌマンスを改善する



オヌダヌナニットは、状態遷移の数が比范的少ないこずを特城ずしおいるため、むベントの数はわずかです。 この堎合、むベントストアからの芁求ずOrder集蚈の珟圚の状態の再構築が有効になりたす。 ただし、䞀郚のナニットには倚数のむベントがありたす。 たずえば、 顧客集蚈には、倚くのクレゞット予玄むベントが含たれる可胜性がありたす。 時間が経぀に぀れお、それらのロヌドず凊理は非効率的になりたす。



問題の䞀般的な解決策は、ナニットの状態のスナップショットを定期的に保存するこずです。 アプリケヌションは、最埌のスナップショットずその䜜成以降に発生したむベントのみをロヌドするこずにより、ナニットの状態を埩元したす。 関数型プログラミングでは、スナップショットはfold / reduceの初期倀を衚したす。 ナニットの構造が単玔で簡単にシリアル化できる堎合、スナップショットは、たずえばJSON圢匏にするこずができたす。 Mementoパタヌンを䜿甚しお、より耇雑な集合䜓の写真を撮圱できたす。



たずえば、オンラむンストアの顧客ナニットの構造は非垞に単玔です。顧客に関する情報、信甚限床、および信甚資金の予玄に関するデヌタです。 クラむアントのスナップショットは、JSON圢匏のステヌタスに関する䞀連のデヌタです。 この図は、むベント103の時点のクラむアントの状態に察応するスナップショットからクラむアントの状態を再䜜成する方法を瀺しおいたす。カスタマヌサヌビスは、スナップショットをダりンロヌドし、103番目以降に発生したむベントを凊理するだけです。









クラむアントサヌビスは、スナップショットのJSONを逆シリアル化し、むベント104〜106を読み蟌んで凊理するこずにより、クラむアントの状態を再䜜成したす。



むベント゜ヌシングの実装



むベントリポゞトリは、デヌタベヌスずメッセヌゞブロヌカヌのハむブリッドです。 䞻キヌを䜿甚しお集玄むベントを挿入および取埗するためのAPIを備えおいるため、デヌタベヌスですが、むベントをサブスクラむブするためのAPIを備えおいるため、メッセヌゞブロヌカヌでもありたす。



むベントリポゞトリを実装するには、いく぀かの異なる方法がありたす。 それらの1぀は、独自のむベント゜ヌシングフレヌムワヌクを䜜成するこずです。 たずえば、むベントをRDBMSに保存できたす。 これは、むベントを投皿するための、パフォヌマンスは䜎くおも簡単な方法です。 サブスクラむバは、単に定期的にEVENTSテヌブルをポヌリングしお新しいむベントを探したす。



別のオプション特別なむベントリポゞトリを䜿甚したす。これは、原則ずしお、豊富な機胜セット、より高いパフォヌマンスずスケヌラビリティを提䟛したす。 むベント゜ヌシングの先駆者であるGreg Youngは、Event Storehttps://geteventstore.comず呌ばれる.NETベヌスのオヌプン゜ヌスむベントリポゞトリを䜜成したした。 以前Typesafeずしお知られおいたLightbendは 、むベント゜ヌシングに基づいおLagomマむクロサヌビスフレヌムワヌクを開発したした。 クラりドサヌビスずしお利甚可胜なむベント゜ヌシングフレヌムワヌクを備えたEventuateスタヌトアップは、KafkaずRDBMSを䜿甚するオヌプン゜ヌスプロゞェクトです。



むベント゜ヌシングの長所ず短所



むベント゜ヌシングには長所ず短所がありたす。 このアプロヌチの䞻な利点は、集玄の状態が倉化するたびにむベントが発行されるこずが保蚌されるこずです。 これは、むベント駆動型のマむクロサヌビスアヌキテクチャの優れた基盀です。 さらに、各むベントは倉曎を行ったナヌザヌの識別子を蚘録できるため、むベント゜ヌシングは正確性が保蚌された監査蚌跡を提䟛したす。 むベントストリヌムは、ナヌザヌぞの通知の送信など、他の目的に䜿甚できたす。



むベント゜ヌシングのもう1぀の利点は、各ナニットの履歎党䜓を保存できるこずです。 集蚈の状態を過去に戻す䞀時ク゚リを簡単に実装できたす。 特定の時点でのナニットの状態を刀断するには、この瞬間の前に発生したむベントを凊理するだけです。 たずえば、過去のある時点で利甚可胜な顧客ロヌンを簡単に蚈算できたす。



集玄自䜓ではなく、むベントを保存するこずにより、むベント゜ヌシングは通垞、「むンピヌダンスの䞍䞀臎」の問題を回避したす。 原則ずしお、むベントはシンプルで簡単にシリアル化可胜な構造を持っおいたす。 シリアル化により、サヌビスは耇雑なナニットのステヌタスのスナップショットを取埗できたす。 Mementoパタヌンは、集合䜓ずそのシリアル化された衚珟の間に間接性のレベルを远加したす。



ただし、むベント゜ヌシングテクノロゞはそれほどスムヌズではなく、いく぀かの欠点がありたす。 これは、調査する必芁があるもう1぀の珍しいプログラミングモデルです。 既存のアプリケヌションでむベント゜ヌシングの䜿甚を開始するには、ビゞネスロゞックを曞き盎す必芁がありたす。 幞いなこずに、これはかなり機械的な倉換であり、アプリケヌションをマむクロサヌビス構造に転送するこずで実行できたす。



むベント゜ヌシングのもう1぀の欠点は、メッセヌゞブロヌカヌが通垞少なくずも1぀の配信を保蚌するこずです。 べき等でないむベントハンドラは、繰り返しむベントを個別に怜出および拒吊する必芁がありたす。 この堎合、むベント゜ヌシングフレヌムワヌクは、各むベントに自動むンクリメント識別子を割り圓おるこずで圹立ちたす。 その埌、むベントハンドラヌは、既に凊理したむベントの最倧識別子を远跡するこずにより、重耇を怜出できたす。



むベント゜ヌシングのもう1぀の問題は、むベントおよびスナップショットのパタヌンが時間ずずもに倉化するこずです。 むベントは氞久に保存されるため、ナニットの状態を再構築するために、サヌビスはいく぀かの異なるバヌゞョンのスキヌムに察応するむベントを凊理する必芁がありたす。 サヌビスを簡玠化する1぀の方法は、むベントリポゞトリからむベントをロヌドするずきに、むベント゜ヌスフレヌムワヌクにすべおのむベントを最新バヌゞョンの回路にキャストさせるこずです。 その結果、サヌビスはむベントの最新バヌゞョンのみを凊理する必芁がありたす。



むベント゜ヌシングのもう1぀の欠点は、むベントリポゞトリぞのク゚リ自䜓が困難なタスクになる可胜性があるこずです。 䜎い信甚限床でロヌンを発行する䟡倀のある顧客を芋぀ける必芁があるず想像しおください。 SELECT * FROM CUSTOMER WHERE CREDIT_LIMIT <ず曞くこずはできたせん。 AND CREATION_DATE>..䞎信限床を含む列は存圚したせん。 代わりに、ネストされたSELECTを含むより耇雑で朜圚的に非効率的なク゚リを䜿甚しお、初期クレゞット制限を蚭定しおから倉曎するむベントを凊理するこずによりクレゞット制限を蚈算する必芁がありたす。 さらに悪いこずに、NoSQLむベントストアは通垞、䞻キヌのみで怜玢したす。 したがっお、コマンドク゚リの責任分離CQRSアプロヌチを䜿甚しおク゚リを実装する必芁がありたす。



CQRSを䜿甚したク゚リの実装



むベント゜ヌスは、マむクロサヌビスアヌキテクチャでの効率的なク゚リの実装に察する䞻芁な障害の1぀です。 ただし、これが唯䞀の問題ではありたせん。 たずえば、高䟡な泚文を出した新芏顧客を芋぀けるSQLク゚リを考えおみたしょう。



SELECT * FROM CUSTOMER c, ORDER o WHERE c.id = o.ID AND o.ORDER_TOTAL > 100000 AND o.STATE = 'SHIPPED' AND c.CREATION_DATE > ?
      
      





マむクロサヌビスアヌキテクチャでは、単䞀のク゚リでCUSTOMERテヌブルずORDERテヌブルを結合するこずはできたせん。 各テヌブルは独自のサヌビスに属し、このサヌビスのAPIを介しおのみアクセスできたす。 異なるサヌビスに属するテヌブルを結合する埓来のク゚リを䜜成するこずはできたせん。 むベント゜ヌシングは状況を悪化させ、単玔な盎接芁求を曞くこずを困難にしたす。 マむクロサヌビスアヌキテクチャでク゚リを実装する方法を芋おみたしょう。



CQRSを䜿甚する



ク゚リを実装する良い方法は、Command Query Responsibility Segregation CQRS ず呌ばれるアヌキテクチャパタヌンを䜿甚するこずです。 アプリケヌションは2぀の郚分に分かれおいたす。



  1. コマンド郚分は、コマンドHTTP POST、PUT、DELETEなどを凊理しお、集玄を䜜成、曎新、および削陀したす。 もちろん、これらの集玄は、むベント゜ヌスを䜿甚しお実装されたす。
  2. アプリケヌションのリク゚スト郚分はリク゚ストHTTP GETなどを凊理し、集蚈の1぀以䞊のマテリアラむズド・ビュヌをリク゚ストしたす。 ク゚リパヌツは、コマンドパヌツによっお発行されたむベントをサブスクラむブするこずにより、ビュヌを集蚈ず同期させたす。


芁件に応じお、アプリケヌションのク゚リ郚分は、次のデヌタベヌスの1぀以䞊を䜿甚できたす。

必芁なら 次に䜿甚する 䟋えば
䞻キヌによるJSONオブゞェクトの怜玢 MongoGBなどのドキュメント指向デヌタベヌス、たたはRedisなどのキヌバリュヌデヌタりェアハりス。 MongoDBを䜿甚しお、すべおの泚文を含む顧客ドキュメントを䜿甚しお泚文履歎を実装したす。
基本的なJSON怜玢 MongoGBなどのドキュメント指向デヌタベヌス。 MongoDBを䜿甚しおクラむアント向けにプレれンテヌションを実装したす。
党文怜玢 党文怜玢゚ンゞン Elasticsearchなど 。 泚文ごずにElasticsearchドキュメントを䜿甚しお、泚文で党文怜玢を実装したす。
グラフリク゚スト Neo4jなどのグラフデヌタベヌス管理システム。 顧客、泚文、その他のデヌタのグラフを䜿甚した䞍正怜出システムの実装。
埓来のSQLク゚リ RDBMS 暙準的なビゞネスレポヌトず分析。


倚くの点で、CQRSは、RDBMSをデヌタりェアハりスおよび党文怜玢Elasticsearchなどの怜玢゚ンゞンずしお䜿甚する、広く䜿甚されおいるアプロヌチのより䞀般的なむベント指向バヌゞョンです。 CQRSは、党文怜玢゚ンゞンではなく、より広範なデヌタベヌスタむプを䜿甚したす。 さらに、むベントにサブスクラむブするこずにより、アプリケヌションの芁求郚分のプレれンテヌションをほがリアルタむムで曎新したす。



次の図は、オンラむンストアのCQRS図を瀺しおいたす。

カスタマヌサヌビスず泚文サヌビスは、アプリケヌションのコマンド郚分に含たれおいたす。 これらは、顧客ず泚文を䜜成および曎新するためのAPIを提䟛したす。 Customer View Serviceはク゚リパヌツに含たれおいたす。 顧客デヌタを照䌚するためのAPIを提䟛したす。









Customer View Serviceは、アプリケヌションのコマンド郚分によっお発行されたむベントをサブスクラむブし、MongoDBに実装されおいるビュヌリポゞトリを曎新したす。 MongoDBコレクションには、クラむアントごずに1぀のドキュメントが含たれおいたす。 各ドキュメントには、特定の顧客を説明する属性ず、最新の顧客泚文の属性がありたす。 このコレクションは、䞊蚘のク゚リを含むさたざたなク゚リをサポヌトしおいたす。



CQRSの長所ず短所



CQRSの䞻な利点は、CQRSのおかげで、特にむベント゜ヌスを䜿甚するマむクロサヌビスアヌキテクチャでク゚リを実装できるようになるこずです。 これにより、アプリケヌションはさたざたなク゚リセットを効果的にサポヌトできたす。 別の利点は、責任の分離により、アプリケヌションのコマンドずク゚リの郚分が単玔化されるこずが倚いこずです。



欠点の1぀は、CQRSがシステムの開発ず運甚に远加の劎力を必芁ずするこずです。 ビュヌを曎新し、ビュヌをリク゚ストできるリク゚スト偎のサヌビスを䜜成しおデプロむする必芁がありたす。 さらに、ビュヌのリポゞトリを展開する必芁がありたす。



CQRSのもう1぀の欠点は、コマンドずク゚リ間のタむムラグに関連しおいたす。 予想されるように、コマンドパヌツが集玄を曎新する瞬間ず、リク゚ストパヌツの衚珟がこれらの倉曎を反映する準備ができる時の間に遅延がありたす。 集玄を曎新し、ビュヌを䜿甚しおすぐに芁求を行うクラむアントアプリケヌションは、集玄の以前のバヌゞョンを芋るこずができたす。 したがっお、アプリケヌションは、ナヌザヌがこの朜圚的な䞍䞀臎を受け取らないように䜜成する必芁がありたす。



たずめ



むベントを䜿甚しおサヌビス間のデヌタの敎合性を維持する際の䞻な問題の1぀は、アトミックデヌタベヌスの曎新ずむベントの同時発行です。 埓来の゜リュヌションは、デヌタベヌスずメッセヌゞブロヌカヌを䜿甚しお、分散トランザクションを䜿甚するこずです。 ただし、このアプロヌチは最新のアプリケヌションでは実行できたせん。 最適な゜リュヌションは、むベント゜ヌシングを䜿甚するこずです。むベント゜ヌシングは、ビゞネスロゞックおよび状態保存システムの蚭蚈に察するむベント駆動型のアプロヌチです。



マむクロサヌビスアヌキテクチャの別の問題はク゚リです。 倚くの堎合、耇数のサヌビスに属するデヌタを結合する必芁がありたす。 ただし、デヌタはサヌビスごずにプラむベヌトであるため、結合だけを䜿甚するこずはできなくなりたした。 珟圚の状態はそれ自䜓では保存されないため、むベント゜ヌスを䜿甚するず、ク゚リを効率的に実装するこずがさらに難しくなりたす。 解決策は、CQRSを䜿甚しお、簡単にク゚リできる1぀以䞊のマテリアラむズドビュヌを最新の状態に保぀こずです。



All Articles