2024.12.19
システムの穴を運用でカバーしようとしてミス多発… バグが大量発生、決算が合わない状態から業務効率化を実現するまで
リンクをコピー
記事をブックマーク
加藤潤一氏(以下、加藤):「なぜEvent Sourcingなのか」という話で、Event Sourcingの場合はどうなっているかというと、CRUDのステートソーシングは、最新のエンティティを上書きする考え方です。Event Sourcingは、そのとき発生した変更を追記していく考え方になります。
「状態はどういうふうに作るの?」という話ですが、イベントから状態を導出する考え方です。関数にイベントをapplyしていくと、そのときの状態に対してイベントをapplyするかたちになるので、どんどん状態を作って更新していける。すべてのイベントがapplyされると最新状態になるような考え方です。
そのイベントの必要性はコマンドとクエリが分離されていますが、結果的に統合しないといけないので、イベントが使わるような話です。
“イベント”と言っているものは、もともとはDDDのドメインイベントという考え方からきていて、イベントそのものは過去に起きたできごと、ドメイン上のイベントを意味します。一般的には動詞の過去形で表現され、イベントからコマンドを想起可能です。例えば「貨物の出荷みたいなものだと、過去形を現在形に直せばだいたい想起可能ですよね」みたいな話があります。
コマンドとイベントは似ています。コマンドもアクターみたいなものに投げられて、そこでコマンドが拒否されることがあります。アクターの中で、このコマンドは受理できるとなった場合に、拒否されずに受理されると、状態が変わってイベントが生成されます。そのイベントはEvent Sourcingだとディスクとかに保存されます。そのため、コマンドは拒否されるかもしれませんが、イベントはすでに起こったことを示します。
なぜイベントを使うかは簡単で、コマンド側からクエリ側に変更を伝搬させないとインテグレーションできないからです。一番わかりやすい方法としては「ポーリングしたらええやん」という話がありますが、変更がないときもポーリングで負荷をかけてしまうので、ポーリングは絶対スケールしません。
同時接続数が増えて、ポーリング自体も増えると、なにもタスクがないのにコマンド側に負荷をかけている。相手側のポーリング先に負荷をかけてしまうので、スケールしないと言われています。そのためどうするかというと、イベントをPub/Subする。「コマンド側からクエリ側を呼び出すので、クエリ側はなにもしないてもいいよ」「待っててね」という話です。
こういった考え方は、連携する方法としては「Event Sourcingを使うといいよ」みたいものがありますが、ほかにもCDCとOutboxを使うパターンがあります。今日は紹介しませんが、興味があったら検索してみてください。結局はEvent Sourcingとほとんど同じになっちゃいます。
僕のブログにも書きましたが、Event Sourcing以外に現実的な選択肢はない感じです。そのため、CQRSやるということは、ほぼEvent Sourcingをやることになります。
利点と欠点です。、先ほども話しましたが、イベントは更新されず追記のみなので、ロックが不要です。ロックはどこかでトランザクション管理みたいなものをやらないと、不正なイベントが追加されたりしたらまずいと思います。例えば、create したあとにupdateがこないといけないのに、updateが先にきてcreateがきちゃうようなイベントの並びは許容できないと思います。Akkaの場合は、アクターがそれを管理します。
そういった問題はありますが、それをクリアしたあとのイベントの保存、永続化という部分でいうと、ロックが不要で追記のみになるので、スケーラビリティを確保しやすいです。
特定の時点のReadModelをイベントから導出できます。先ほど言ったような考え方で、いつでもReadModelを、その時点のReadModelを取り出せます。
ドメインイベントがあればReadModelの設計はいつでもやり直せます。イベントを絶対消してしまうことはできませんが、ReadModelの設計をミスしてしまったのであれば、もちろん再構築コストはかかりますが、いつでもイベントからReadModelの新しい設計に基づいて作り直すことはできます。
こういったイベントが監査ログや行動履歴の分析に利用しやすい副次的な効果もあります。ただし、大量のイベントから状態をリプレイする際に時間がかかってしまうことはあるので、Akkaではアクターの最新状態をスナップショットとして保存する機能があります。
スナップショットに加え、それ以降の差分イベントでリプレイ時間を短縮できる機能が備わっています。原則的にすべてのイベントをストレージに保存する必要があるところが、抵抗を感じるところです。
一応、スナップショット保存時に古いイベントを消すこともできます。本当にそれを消しても大丈夫かは、ビジネス的な観点で考える必要はありますが、技術的には古いイベントを消すことは可能です。
やっと新アーキテクチャの話です。リアクティブシステムとCQRSを反映したアーキテクチャを考えています。これは検証環境で開発中のもののアーキテクチャ図です。一番左側にAkka-Clusterがあり、Write APIという枠があると思いますが、これがそのコマンドサイドです。
コマンドサイドとクエリサイド、ちょうどその真ん中より右のRMU(Read Model Updater)で境界が切れていて。左側のWrite API、Message BusまでがWrite APIのチームで、右側のRMUとRead APIとClientがクライアントサイドのチームというかたち。今の実際のチームはクライアントサイドのチームがRead APIも開発する構成になっています。
コマンドサイドはドメインロジックを実行してドメイン状態を変える機能のみを提供します。例えば、でメッセージ投稿やタイトルの変更はChatworkのルームなどのWrite API側で受けます。真ん中にRoomAggregateActorがいますが、PostMessageみたいものを受け取ると、Write API側からこのRoomAggregateActorにPostMessageというメッセージが届きます。
このアクターは軽量プロセスなので、起動している状態になっています。そのメッセージが届いたら、起動している状態に対してメッセージがきて、ロジックが反応します。ステートはオンメモリでもっているので、PostMessageというコマンドが受理されたら、MessagePostedというイベントがJournal DBに保存されます。
今のところDynamoDBでやっていますが、DynamoDBの場合だと、DynamoDB Streamsなどを使って、Message BusというStreamを流す中間のメッセージのバスみたいなものがあって。Kafkaを使っていますが、KafkaからRMUにメッセージをconsumeして、ReadModelを構築します。メッセージのDTOなどをメッセージDBから取り出して、Read APIがクライアントからの要求に応じて結果を返すようなことをやっています。
このアクターが起動している状態のなにがうれしいのか。1つ特徴的なものが、Journal DBはイベントがどんどん蓄積されていきますが、データベースの状態とRoomAggregateActorの状態は完全に同期されている状態なので、Postであれはあまり関係ありませんが、UpdateMessageなどだと、既存のエンティティを取得して、それに対して状態を変えて、新しい状態をDBに保存し直すみたいなことがよく起きます。
最初にReadが発生して、そのエンティティの状態を変えてもう1回アップデートし直すようなことをよくやると思いますが、Akkaの場合はデータベースと状態が完全に同期されているので、最初の読み込みがなくなります。
そのため、コマンドを受信したらビジネスロジックをそのまま実行して、変わった状態はEvent Sourcingなので保存しない。アクターがオンメモリでもっているのが正しい状態なので、データベースはイベントを保存するだけです。
真の状態というのはアクターがもっていて、データベースはただのバックアップという扱いです。メモリでドメインの状態がすぐ手元にあるからこそ、ビジネスロジックが書きやすかったり、設計しやすかったりする特徴があります。そういった利点を活かして、ドメインモデルを作って実装していけるのは1つ魅力的なところです。今考えているものは、ざっくりこういう考え方に基づいています。
先ほども話がありましたが、本日紹介した技術はアメリカとかだと「キャズムを超えてる」みたいな、「なんだと?」みたいな話があって。弊社で使っている技術を囲ってみました。「この技術を使ったからどうだ」という話でもないんですが、トレンド的に「なんか日本とアメリカでは、だいぶギャップがあるな」みたいな話はあります。
日本語の書籍が出ないと、みんな手を動かさないようなところがあるのかもしれませんが、書籍が5年・10年遅れたりはよくあることなので、日本でも事例の1つになっていければいいかなと思っています。
リアクティブシステムを目指すには、それなりに複雑な仕組みが必要になってきます。もちろん高い技術力も求められます。全体が複雑になりすぎないように気をつけることもしないといけないので、濃淡つけていけるように、というところで四苦八苦しながらやっているところですね。
あと、技術の話ばかりをしましたが、技術的な話だけではなくて。いきなりマイクロサービスでわかってないのに最初から分けて始めるのではなく、はじめは分けやすいように1つから始めて、事業やビジネスやユーザーのことをわかっていきながら分けていくみたいことが好ましいと思っていて。
そういった部分で、組織的な問題もあると思っています。こういったことは組織戦略の問題と合わせて考えていかないといけないので、まだまだやることはけっこういっぱいあるなという印象です。
事業的にも、技術的にも成長の余地がけっこうあるので、プロダクトをともに支えてくれるエンジニアを募集中です。仕事はいろいろあるので、なにかあれば気軽に相談ください。
今日はありがとうございましたということで、ご清聴ありがとうございました。
司会者:ありがとうございました。Twitterからもいくつか感想などをもらっているので、私からちょっとだけピックアップしたいと思っています。
司会者:「メッセージパッシング、非同期、失敗を受け入れる……。Bulkheadingの考え方という最近のソフトウェアの思想が、どんどんErlangの思想に近くなってますね」というコメントが、私としてもすごく印象的だなと思っていて。
私は個人的にこの手のプログラミングを温故知新で勉強したいなと思って、最近『すごいErlangゆかいに学ぼう! 』とかを買っているので、このあたりを読んでいるとね。
加藤:そうなんですよね。Erlangの仕様とか見るとけっこうびっくりしますが、そういった昔から可用性を考えて言語とかを設計すると、こういうふうになるのかなって。そういう意味では、本当に学ぶべきところはあると思います。
司会者:そうですね。コロナ禍でなかなか家の外に出られないと思いますが、こういう本などをぜひ読んで時間を過ごしてもらえるといいのかな、なんて思っています。
関連タグ:
2024.12.20
日本の約10倍がん患者が殺到し、病院はキャパオーバー ジャパンハートが描く医療の未来と、カンボジアに新病院を作る理由
2024.12.19
12万通りの「資格の組み合わせ」の中で厳選された60の項目 532の資格を持つ林雄次氏の新刊『資格のかけ算』の見所
2024.12.16
32歳で成績最下位から1年でトップ営業になれた理由 売るテクニックよりも大事な「あり方」
2023.03.21
民間宇宙開発で高まる「飛行機とロケットの衝突」の危機...どうやって回避する?
PR | 2024.12.20
モンスター化したExcelが、ある日突然崩壊 昭和のガス工事会社を生まれ変わらせた、起死回生のノーコード活用術
2024.12.12
会議で発言しやすくなる「心理的安全性」を高めるには ファシリテーションがうまい人の3つの条件
2024.12.18
「社長以外みんな儲かる給与設計」にした理由 経営者たちが語る、優秀な人材集め・会社を発展させるためのヒント
2024.12.17
面接で「後輩を指導できなさそう」と思われる人の伝え方 歳を重ねるほど重視される経験の「ノウハウ化」
2024.12.13
ファシリテーターは「しゃべらないほうがいい」理由 入山章栄氏が語る、心理的安全性の高い場を作るポイント
2024.12.10
メールのラリー回数でわかる「評価されない人」の特徴 職場での評価を下げる行動5選
Climbers Startup JAPAN EXPO 2024 - 秋 -
2024.11.20 - 2024.11.21
『主体的なキャリア形成』を考える~資格のかけ算について〜
2024.12.07 - 2024.12.07
Startup CTO of the year 2024
2024.11.19 - 2024.11.19
社員の力を引き出す経営戦略〜ひとり一人が自ら成長する組織づくり〜
2024.11.20 - 2024.11.20
「確率思考」で未来を見通す 事業を成功に導く意思決定 ~エビデンス・ベースド・マーケティング思考の調査分析で事業に有効な予測手法とは~
2024.11.05 - 2024.11.05