モゞュラモノリスに移行する理由 â”€ ãƒžã‚€ã‚¯ãƒ­ã‚µãƒŒãƒ“スの自埋性ずモノリスの䞀貫性を䞡立させるア゜ビュヌの取り組み

倧芏暡な゜フトりェア開発においおモノリシックかマむクロサヌビスかずいうアヌキテクチャの議論がありたすが、近幎は第3の遞択肢ずしおモゞュラモノリスが話題になっおいたす。いったんマむクロサヌビス化に舵を切りながら珟圚はモゞュラモノリスに取り組むア゜ビュヌの考え方や進め方に぀いお、VPoEの兌平倧資disc99さんによる寄皿です。

モゞュラモノリスに移行する理由 â”€ ãƒžã‚€ã‚¯ãƒ­ã‚µãƒŒãƒ“スの自埋性ずモノリスの䞀貫性を䞡立させるア゜ビュヌの取り組み

ア゜ビュヌでは、珟圚の事業状況にマッチしおいるこずや過去の経緯から、モゞュラモノリスを䞭心ずしたアヌキテクチャを採甚しおいたす。 今回は、なぜその遞択をし、どのように実珟しおいるかを玹介したす。

蚘事の前半では、ア゜ビュヌが提䟛する事業や、アヌキテクチャに察する考え方、開発組織の歩みなどを説明したす。 䞭盀以降は、ア゜ビュヌにおけるモゞュラモノリスぞの取り組みの詳现に぀いお解説したす。

ア゜ビュヌの事業の特城ずこれたでの歩み

ア゜ビュヌ株匏䌚瀟では、倧きく分けお2぀の事業を運営しおいたす。

1぀は䞀般の利甚者に向けお、遊びの予玄サむト「ア゜ビュヌ!」などを運営するサヌビスEC事業です。もう1぀は、レゞャヌ事業者に電子チケット・予玄管理サヌビス「りラカタ」などを提䟛するSaaS事業です。

asoview1-
ア゜ビュヌの事業抂芁「asoview! Company Deck for engineer」より

むメヌゞずしおは、楜倩やAmazonのようなモヌル型EC事業ず、ShopifyのようなD2C事業の䞡面を1瀟で運営しおいる状態です。 他にも、䞻軞の事業で培ったアセットや蓄積したデヌタを生かし、さたざたな呚蟺事業やサヌビス、倖郚連携を展開しおいたす。

それぞれの事業で業務内容や向き合うナヌザヌは異なりたすが、扱うマスタデヌタは同じものをベヌスにしおいたす。 そのため、衚向きはそれぞれの事業が独立しお動いおいるように芋えたすが、裏偎では情報を共有・連携しお事業を展開しおいたす。

asoview2

䞖の䞭に耇数の事業を展開する䌁業は数倚く存圚したすが、それらも匊瀟ず同じように、ナレッゞやデヌタを瀟内で暪展開し぀぀サヌビスを提䟛する堎合が倚いのではないでしょうか。

倉化し続ける環境・開発組織・アヌキテクチャ

ア゜ビュヌで立ち䞊げるさたざたな事業には、柱になるものもあれば、別事業ず統合されたり終了するサヌビスもありたす。 新型コロナりむルスの流行のように倖郚環境が䞀瞬にしお倉わったり、M&Aなども内郚芁因によっお組織や技術芁玠が短期間で倧幅に倉化するこずもありたす。

こうした倉化に適応し続けながら事業を成長させるには、開発組織ずアヌキテクチャの関係性を適切な状態に保぀必芁がありたす。 コンりェむの法則が瀺すように、組織ずアヌキテクチャは密接に関係するためです。

しかし、ここで泚目しなければいけないのは、䞡者のラむフサむクルの違いです。 組織やチヌム配眮は、その気になれば䌚瀟の方針次第で翌日から倉曎できたす。 しかしアヌキテクチャやシステムは、組織のようにすぐ倉曎するこずが困難です。

この課題を解決するには、䜕らかの方法でアヌキテクチャやシステムの倉曎容易性を高めるこずが必芁になっおきたす。 倉化の激しい垂堎環境や事業状況の䞭で、技術的な制玄により成長が鈍化するこずは避けなければなりたせん。 たた、事業や組織の成長に察しお玠早くシステムを適甚させるこずや、その過皋で発生する技術的負債をリファクタリング・リプレむスできるこずも重芁な芁玠になっおきたす。

ア゜ビュヌのアヌキテクチャの倉遷ずそこから孊んだこず

前掲の情報を螏たえお、これたでア゜ビュヌがどのようなアヌキテクチャを遞んできたのか、そしおこれからどのようなアヌキテクチャを目指しおいるのかを解説したす。

ア゜ビュヌのシステムは、モノリスなアヌキテクチャから始たりたした。 䌚瀟が成長するに䌎い新芏事業を立ち䞊げる際には、システムも新芏構築しおきたした。 この遞択によっお、事業やチヌム、システムが独立性を保ち、自埋自走できたのです。 その結果、耇数のサヌビスが事業の柱ずしお成長したした。

こういった成果ず組織拡倧に䌎い、よりアゞリティを䞊げお自己組織化を進めるため、2017幎ごろからマむクロサヌビス化ぞず舵を切りたした。 このアヌキテクチャ倉曎には、圓時のマむクロサヌビスの流行も圱響しおいたす。 マむクロサヌビス化は、玠早いサヌビスの立ち䞊げや、短期的な成長には効果的でした。

しかし、長期的な芳点で芋るず課題も残りたした。 サむロ化の促進や、党䜓最適化の難易床の䞊昇、組織䜓制ずのアンマッチ、オヌバヌヘッドなどの問題が倚々発生するこずになったのです。

私たちがモノリスずマむクロサヌビスの運甚を経隓しお孊んだこずは「どのように集玄ず分散をコントロヌルするかが重芁」ずいうこずでした。 この詳现は、「マむクロサヌビスによっお起こったサむロ化に察する取り組み」ずしお匊瀟のテックブログにたずめおいたす。ご興味あればご芧ください。

これからのア゜ビュヌが目指す姿ずアヌキテクチャの遞択

事業䌚瀟においお事業の成長はもちろん重芁ですが、そのためにはプロダクト、組織、そしお関わる䞀人䞀人のメンバヌの成長も重芁です。

しかし環境や組織が倉化し続ける䞭で、初めから正解が分かっおいるこずはめったにありたせん。 成長を続けるには、チャレンゞを繰り返すこずができる環境を䜜り、PDCAのサむクルの䞭で正解を芋぀けおいく必芁がありたす。 このサむクルを実珟するには、組織が拡倧しおもそれぞれのチヌムが必芁以䞊のコミュニケヌションコストを支払うこずなく、自埋自走できる状態が重芁です。

たた組織が拡倧しおも、個々の開発者には䌁業の歯車のような状態になっおほしくありたせん。 広い領域に関わっお胜力を最倧化し、むノベヌションを起こしたりサヌビスを䜜り倉えたりできるだけの倧きな暩限ず裁量を、党おのメンバヌに䞎えたいず考えおいたす。

䞀方、ア゜ビュヌのシステム的な特城ずしお、事業が倚角化しおもサヌビス間でデヌタの共有・連携が倚いずいうこずがありたした。

こうした経隓を螏たえおこれから目指す姿を考えるず、マむクロサヌビスの自埋性ず、モノリスの䞀貫性や党䜓適甚のスピヌドずいう双方のメリットを取り入れるこずが理想でした。 そのため有力なアヌキテクチャ候補ずしお、䞡方のメリットを生かすこずができるモゞュラモノリスが挙がりたした。

そこで私たちは、モゞュラモノリスぞの取り組みを2020幎ごろに始めたのです。

モノリスずマむクロサヌビスの特城、そしおモゞュラモノリス

ア゜ビュヌにおけるモゞュラモノリスぞの取り組みの前に、モノリスやマむクロサヌビス、そしおモゞュラモノリスにはそもそもどのような特城があるのかに぀いおも觊れおおく方がよいでしょう。 ア゜ビュヌの話からいったん離れお、䞀般論ずしおアヌキテクチャの解説をしおいきたす。

モノリシックアヌキテクチャのメリット

モノリシックアヌキテクチャ以降、モノリスは、他の遞択肢ず比べお実装が簡単なアヌキテクチャです。 開発にフレヌムワヌクを利甚し、意図的にシステムを分離するアヌキテクチャを適甚しなければ、モノリスな構成になるこずがよくありたす。

創業圓初のア゜ビュヌがそうだったように、ほずんどのサヌビスでは開発の初期フェヌズにおいお、少人数の開発者だけがプロゞェクトに関䞎したす。 そしお、短期間でシステムを構築するこずが重芁ですし、事業ずしお安定するたでに倚くの砎壊的倉曎を繰り返すこずが倚いでしょう。

モノリスはこういった、少人数で玠早く倧芏暡な倉曎を繰り返す開発スタむルの堎合に、非垞に有力な遞択肢です。 ゜ヌスコヌドが1぀のリポゞトリに集玄されたすから、すぐに党䜓を怜玢できたす。 開発環境の構築も容易ですし、サヌビス党䜓の理解・倉曎も最小限のオヌバヌヘッドで行えたす。

テストやデプロむなども、単䞀のアプリケヌションに察しお実斜するだけですし、DevOpsなどの事業成長に盎結しにくい䜜業の時間も、最小限にしやすいです。 デヌタベヌス以䞋、DBも単䞀になるこずが倚く、シンプルなク゚リヌで必芁な情報を扱うこずができたす。

モノリスの倧きなメリットずしお、APIを介した通信を必芁ずせず、他のコンポヌネントを盎接呌び出すこずができたす。 これにより、APIのバヌゞョン管理や埌方互換性、ネットワヌクの゚ラヌハンドリングなどを意識する必芁がありたせん。 デヌタの䞀貫性も、DBのトランザクションなどで容易に実珟できたす。

モノリシックアヌキテクチャのデメリット

さたざたなメリットがあるモノリスですが、倧きな欠点は党おが密結合になるこずです。

容易にコンポヌネントを再利甚できるメリットは、その反面、結合床が自然ず高くなっおしたうデメリットをもたらしたす。 そのため、アプリケヌションや組織がスケヌルしおくるず、1぀の倉曎による圱響範囲が倧きくなり、どのような副䜜甚が生じるかを芋通しづらくなりたす。 結果、゜ヌスコヌドベヌスで党おを理解する必芁性が高くなっおしたい、開発速床の䜎䞋やバグ発生のリスクなどが急速に増加したす。

こうした課題は、機械的に解決できるものばかりではありたせん。 耇数のステヌクホルダヌが情報連携しなければ、うたく解決できない課題も倚いです。 そのため、必然的にチヌムや組織間をたたいだコミュニケヌションが増えたすし、集団的な意思決定を必芁ずするため自埋性の䜎䞋にも぀ながりたす。

たた、システムが単䞀のアプリケヌションずしお実行されおいるため、局所的なバグや負荷が党䜓に波及しやすくなりたす。 たった1機胜の障害が党サヌビスダりンを匕き起こしおしたうなど、倧芏暡障害に陥りやすくなりたす。

マむクロサヌビスのメリット

モノリスの課題を解決するための遞択肢に、マむクロサヌビスアヌキテクチャ以降、マむクロサヌビスがありたす。 マむクロサヌビスでは小さなアプリケヌションを独立しお開発・デプロむし、APIによっお盞互の連携を行うこずで協調動䜜したす。

1぀1぀のアプリケヌションがランタむムレベルで分離されおいるため、各アプリケヌションで任意の技術を利甚可胜です。 実珟したい芁件や開発者のスキルずニヌズに合わせお、適切な技術遞定を行えたすただし、特定䌁業内の各開発チヌムであたりにもバラバラな技術遞定をしおしたうず孊習コストや運甚コストが増倧したすし、党瀟暪断的な技術斜策を実斜するハヌドルも高くなりたす。 そのため実際には、マむクロサヌビス化を掚進しおいる䌁業であっおも、採甚する技術に䞀定の制玄を蚭けるケヌスが倚いです。 ア゜ビュヌもそうでした。

たた、各アプリケヌションを独立しおデプロむできるのも利点です。 APIなど倖郚に公開されたむンタフェヌスに倉曎がなければ、他のアプリケヌションぞの圱響を気にするこずなくデプロむが可胜であり、特定機胜の障害が党䜓に波及する可胜性が䜎いです。 理想的にはDBなども分離するこずで、倉曎の圱響床を最小化し、アプリケヌション単䜍で柔軟にスケヌルできたす。

アプリケヌションずいう明確な境界ができ䞊がるこずにより、必然的に疎結合な蚭蚈を匷制されるずいう傟向もありたす。 結果的に、チヌムや組織で自埋性が高たり、アゞリティの䞊昇が期埅できたす。

マむクロサヌビスがはやりはじめた圓初は、各瀟が手探りで適切な構築・運甚方法を暡玢しおいたした。珟圚ではナレッゞや゚コシステムが広く浞透し、経隓者も増えおいるため、構築・運甚のコストは以前より圧倒的に䞋がっおいたす。

マむクロサヌビスのデメリット

䞀方で、マむクロサヌビスに移行するこずで発生する問題もありたす。

APIによる通信を行うず、ネットワヌクを経由するためパフォヌマンス劣化や信頌性の䜎䞋が発生し、通信の゚ラヌハンドリングも必芁になりたす。 API間の敎合性を担保する必芁もあるため、゜ヌスコヌド䞊の関数呌び出しず比べお圧倒的に高い技術ず高コストな䜜業が求められたす。

たた、DBなどのトランザクションも䜿えないため、アプリケヌションレむダヌで分散トランザクションを実珟する必芁性もあり、DBを分離しおいる堎合には必芁なデヌタを参照するコストも高たりたす。

各アプリケヌションのデプロむも分割されるため、䟝存関係や互換性を意識したリリヌスやテストを行うには、パむプラむンの䜜り蟌みやモニタリングの拡充などのDevOpsの負担も増したす。

開発組織党䜓ずしお䞀定以䞊のサヌビス品質や開発効率を実珟するには、特定の機胜を提䟛するアプリケヌションやラむブラリ、サヌビスメッシュの導入などが必芁になり、サヌビスの䟡倀ぞ盎結しない䜜業に芁する時間が増える傟向にありたす。

党䜓のアヌキテクチャを理解する難易床も高たりたす。 E2Eの機胜を確認するための、開発環境の構築やデバッグなども難しくなりたす。 特にアプリケヌションをたたぐような修正は、修正難易床が高いだけでなく、耇数のチヌム間の合意やデプロむ䜜業の調敎が必芁ずなりたす。

これらのデメリットを最小化するには、自埋性を高められる最適なアプリケヌション境界を芋極める必芁がありたす。 しかし、倉化する環境や事業、組織の䞭で適切な答えを出すのは盞圓な難易床です。 アプリケヌション境界を誀っおしたうず、モノリスずマむクロサヌビスの悪いずこ取りをした「分散モノリス」ずいうアンチパタヌンに陥りたす。

モゞュラモノリスモノリスの䞀貫性マむクロサヌビスのモゞュヌル性

モゞュラモノリスずは、モノリスのような䞀貫性ず、マむクロサヌビスのようなモゞュヌル性を持ったアヌキテクチャです。 デプロむするアプリケヌションずしおは1぀ですが、システム内郚は耇数のモゞュヌルに分割されおいたす。

asoview3

有名な事䟋ずしおは、ECプラットフォヌムのShopifyが挙げられたす。 モノリスだったRuby on Railsのアプリケヌションをモゞュラモノリスに移行し、2019幎時点で1,000人以䞊の開発者が迅速か぀継続的に新機胜を構築できる環境動画を支えおいたす。

たた、曞籍『モノリスからマむクロサヌビスぞ』2020幎、オラむリヌ・ゞャパンでは、以䞋のように玹介されおいたす。

モノリスをモゞュヌルに分割しお独立しお開発できるようにするこずで、マむクロサヌビスアヌキテクチャの課題の倚くを回避し぀぀、倚くのメリットを提䟛できる。これは、倚くの組織にずっおスむヌトスポットになる可胜性がある。
最終的にはマむクロサヌビスアヌキテクチャに移行するこずを目的ずしおモノリスをモゞュラヌモノリスに分解し始めたものの、モゞュラヌモノリスで問題のほずんどを解決できるこずが分かったずいう話を、これたでに耇数のチヌムから聞いたこずがある。

モゞュラモノリスの特城 ─ モノリスおよびマむクロサヌビスずの比范

モゞュラモノリスは優秀なアヌキテクチャですが、モノリスやマむクロサヌビスの課題を党お解決するわけではありたせん。 そのため、モゞュラモノリスを有効掻甚するには、どういった特城を持っおいるかを理解する必芁がありたす。

開発容易性

1぀1぀のアプリケヌションがランタむムレベルで分離されたマむクロサヌビスず比范するず、モゞュラモノリスは同䞀のランタむムで動䜜するため、モゞュヌル間のアクセスではモノリス同様、以䞋のようなメリットがありたす。

  • ネットワヌクを利甚しない単玔な関数呌び出し
  • 察象モゞュヌルが垞に利甚可胜
  • 呌び出し時の通信がないため、セキュリティなどの考慮が䞍芁
  • モゞュヌルを超えた倉曎が䞀床に可胜

マむクロサヌビスの堎合、゜ヌスコヌド䞊もネットワヌク凊理を意識するような凊理を蚘述する堎合が倚く、REST APIやgRPCのような専甚のプロトコルを利甚する必芁がありたす。 たた、呌び出し先のモゞュヌルやネットワヌクがダりンする可胜性、セキュリティなども考慮が必芁ずなりたす。

そのため、これらを満たすためのむンフラやミドルりェアなどが必芁ずなる堎合も倚く、耇雑床が高たる傟向にありたす。 耇雑床が高いず、保守性、可読性、可芳枬性が䜎䞋し、高いスキルセット、高床なむンフラ、維持するためのカルチャヌなどが必芁になりたす。

たた、モゞュラモノリスはコヌドベヌスが単䞀になるため、システム党䜓のロヌカル環境実行が容易です。 そしお、玠早く倉曎やデバッグをしたり、モゞュヌルをたたいだリファクタリングしたりずいったこずを、IDEの機胜で安党に実斜できたす。 E2Eテストなどのシステム党䜓の動䜜怜蚌も、モノリス同様に1぀のアプリケヌションを起動するだけで実斜できたす。

自埋性

モノリスは倚くの堎合、それぞれの凊理が密結合になり、成長過皋で倉曎コストが増倧し、自埋性を倧幅に䞋げおいく傟向にありたす。 この特城は、組織が拡倧しおチヌムが自埋自走する䞊で倧きな足かせずなりたす。

モゞュラモノリスではマむクロサヌビスず同様に、チヌムが自埋するための論理的な境界をアプリケヌション内で䜜成し、モゞュヌルずしお分割したす。 適切にモゞュヌル分割すれば、各チヌムの担圓箇所が明確になり組織のメンバヌが自埋的に動ける状態になりたす。 それに加えお、境界を利甚するこずで圱響範囲を最小化でき、゜ヌスコヌド修正のコンフリクトも回避できたすただし、この状態を実珟するにはモゞュヌル境界を適切に定め、共有郚分をできるだけ䜜らないずいう蚭蚈䞊の泚意が必芁になりたす。

オプションの遞択肢ずしお、トランザクションやDBなどを分離すれば、さらなる自埋を促すこずもできたす。 たた、マむクロサヌビスず違い、モゞュラモノリスの境界は同䞀のコヌドベヌスに存圚するものであるため、分割をやり盎すこずも容易です。

䞀方で、マむクロサヌビスのように匷い分離を匷制できたせん。そのため境界の管理が曖昧だず、それぞれの凊理が密結合な状態を生み出す可胜性もありたす。

パフォヌマンス

モゞュラモノリスは1プロセスや1スレッド䞊の関数呌び出しで凊理が完結するため、マむクロサヌビスず比べおパフォヌマンスは非垞に高くなりたす。

マむクロサヌビスでは、ネットワヌク通信、シリアラむズや暗号化など耇数のオヌバヌヘッドが発生するだけでなく、ネットワヌク障害なども含めたリトラむ凊理、サヌキットブレむカヌなども必芁ずなりたす。

モノリスず比范するず、モゞュヌルが分かれる分パフォヌマンス面ではモゞュラモノリスの方が䞍利になりたすが、同䞀のランタむム内なので極端にパフォヌマンスぞの圱響が出る堎合は少ないです。

デプロむ

デプロむに関しおはモノリスず同様です。 システム内郚的にはモゞュヌル分割されおいおも、パッケヌゞング埌は単䞀のアプリケヌションずなるため、実行環境に容易に展開できたす。

党おのモゞュヌルが同時にデプロむされるため、圓然ながらマむクロサヌビスのようにモゞュヌル間の互換性を意識したり、高床なデプロむパむプラむンなどを䜜ったりする必芁はありたせん。

たた、デプロむ䜜業が䞀床で完了するため、開発者ごずやPull Requestごずに環境を䜜るなど、テスト環境の構築も容易になりたす。 結果的に、DevOpsのような事業䟡倀に盎結しにくい時間を倧幅に短瞮できたす。

スケヌラビリティ

モゞュラモノリスでは、モノリス同様に氎平たたは垂盎にスケヌル可胜です。

ただし、ランタむムには党おのモゞュヌルが展開されるため、マむクロサヌビスのように特定のモゞュヌルのみスケヌルさせるこずは困難です。

マむクロサヌビスでは、特定のアプリケヌションだけをスケヌルさせるこずが可胜なため、リ゜ヌスを効果的に䜿甚可胜です。

asoview4

可甚性

モゞュラモノリスは単䞀のランタむムで実行されるため、バグが混入しおいたり、ランタむムのリ゜ヌスを䜿い果たすモゞュヌルがあったりする堎合には、システムの党䜓障害ぞず発展しやすくなりたす。

マむクロサヌビスではランタむムが分離されおいるため、䟝存モゞュヌルがあらかじめ切り離しできるように蚭蚈されおいれば、障害点を局所化可胜です。 ただし泚意が必芁なのはマむクロサヌビスの䟝存蚭蚈で、この蚭蚈にあたり匷く䟝存しおしたっおいる状態になるず、それぞれのアプリケヌションの皌働率が掛け合わされおしたい、単䞀のアプリケヌションの可甚性より䞋回っおしたいたす。

asoview5

モゞュラモノリスでも氎平スケヌルなどにより可甚性を高めるこずはできたすが、マむクロサヌビスのような機胜単䜍の分離は困難です。

組織ずアヌキテクチャの適合性

アヌキテクチャの遞択にあたっおは、それぞれの特城や開発組織の芏暡やステヌゞなどによっおいく぀か考慮すべきこずがありたす。

ごく少人数での開発や仮蚭怜蚌を繰り返すタむミングでは、スピヌディヌに修正できお凊理の再利甚や砎壊的倉曎が容易で、DevOpsやむンフラ管理なども単玔なモノリスが効果的な可胜性が高いです。

しかし、開発人数やチヌムがある皋床増えおきたタむミングでは、モノリスは修正やデリバリヌのコンフリクト、認知負荷の向䞊などが発生しやすくなりたす。 モゞュラモノリスはそういった、自埋性や圱響範囲の局所化の重芁性が高たった堎合に、効果的な遞択肢になりえたす。

たたShopifyのように、モノリスの課題を解決するための移行パスずしお遞択される堎合もありたす。 マむクロサヌビスぞの切り出しをモゞュヌル単䜍でしやすくなるため、組織やシステムの状態に合わせお柔軟な倉曎がしやすいのも特城です。

技術的自由床

モゞュラモノリスは同䞀のランタむムで実行されるため、マむクロサヌビスのようにモゞュヌルごずに任意の蚀語やフレヌムワヌク、ラむブラリなどを䜿うこずが困難です耇数蚀語を利甚できるようなVMなどを利甚すれば䞀郚緩和はできたすが、それでも制玄は倚いです。

特定の課題に特化した技術が必芁な堎合、この制玄が問題になるこずがありえたす。 たた、超倧手䌁業のように人材が豊富なケヌスにおいおは、技術スタックの自由床を高くした方がむノベヌションに぀ながりやすくなる堎合も存圚したす。

しかし、マむクロサヌビス化を進めおいる䌁業であっおも、実際には技術スタックや環境を統䞀しおナレッゞの共有をしおいるこずが倚いです。 自由床を高めるこずにはコストがかかるこずを理解した䞊で、技術を遞択する必芁がありたす。

モゞュヌル分割ず自埋性

モゞュラモノリスではモゞュヌル性を維持するために、いく぀か重芁な芁玠がありたす。 たず、マむクロサヌビスのように自己完結したビゞネスドメむンに合わせたモゞュヌルを䜜るこずが重芁です。

モノリスなアヌキテクチャでよく利甚されるのは、UIやビゞネスロゞック、デヌタアクセスなど技術的な機胜をもずにした氎平方向ぞのモゞュヌル分割です。 レむダヌドアヌキテクチャやクリヌンアヌキテクチャ、ヘキサゎナルアヌキテクチャなども同様に、圹割によっお氎平に分割されおいたす。

こういった分割のメリットは、ビゞネスロゞックず技術芁玠を切り離し、技術的倉曎に察する圱響や責務を明確にしやすいこずです。 䞀方で、ビゞネス的な機胜远加や倉曎がある堎合には、それぞれのモゞュヌルに远加や倉曎が発生したす。

実際の開発では、技術的な倉曎よりビゞネス的な倉曎の方が圧倒的に倚く発生するため、こういった倉曎がそれぞれのモゞュヌルに圱響を䞎えたす。 耇数モゞュヌルに圱響を䞎えずに単䞀のモゞュヌルで修正を完結させるため、モゞュラモノリスでは必芁な技術芁玠を垂盎方向に党お含んだモゞュヌルずしお定矩したす。

このように分割するこずで、各モゞュヌルがビゞネス的倉曎に察しお自埋的な状態を維持し、安定した倉曎が可胜になりたす。

asoview6

モゞュヌルの独立性高凝集、疎結合

システムをモゞュヌルずしお分割する䞊で、重芁なのが“独立性”です。 この条件を満たすには、いく぀かの芁玠がありたす。

䟝存関係の数

それぞれのモゞュヌルを完党に独立させるのは珟実的に䞍可胜ですが、䟝存関係は最小限に抑える必芁がありたす。 倚数の䟝存が発生するようなモゞュヌルは、それだけ独立性が䜎くなっおおり、倖郚の倉曎に圱響を受けたり䞎えたりしやすくなりたす。

䟝存の匷さ

モゞュヌルの独立性を維持するには、モゞュヌル間の結合床も重芁になりたす。 モゞュヌル間の呌び出しが高頻床だったり、双方向で呌び出しが発生する堎合には、密結合なモゞュヌルずなっおいる可胜性が高いです。

こういったモゞュヌルは単䜓で機胜を完結させにくく、倉曎の圱響床が倧きくなりたす。 このようなモゞュヌルは境界を誀っおいる可胜性があるため、モゞュヌルのマヌゞや切り出しなどを怜蚎する必芁がありたす。

䟝存モゞュヌルの安定性

開発を進めおいく過皋で、モゞュヌルの倉曎は垞に発生したす。 倉曎頻床が少ないモゞュヌルず比べお、倉曎頻床の倚いモゞュヌルに䟝存した他のモゞュヌルは、独立性の圱響を受ける可胜性が高くなりたす。 ぀たり、䟝存元のモゞュヌルに倉曎が加わるず、䟝存先のモゞュヌルにも倉曎やテストが必芁ずなりたす。

asoview7

モゞュヌルの公開むンタフェヌス

モゞュラモノリスでは、モゞュヌル間での契玄ずなる公開むンタフェヌスが必芁になりたす。 この契玄を定めずに開発した堎合、モゞュラモノリスは最終的にモノリスず同様に1぀のランタむムに集玄されたすから、モゞュヌル内郚ぞのアクセスが容易に可胜になり、自埋性を維持できなくなりたす。

そのため各モゞュヌルでは、その゚ントリヌポむントずなる公開むンタフェヌスを定矩したす。 これはいわゆるカプセル化であり、モゞュヌルではこの定矩を安定させるこずで、むンタフェヌスが倉わらない限り、内郚倉曎を自由に行うこずが可胜です。

asoview8

公開むンタフェヌスにはいく぀かのパタヌンがあり、単玔な関数呌び出しや、REST APIなどを利甚した同期的なもの、Pub/Subなどを利甚した非同期のものなども含たれたす。

どのアヌキテクチャを遞ぶのか

モゞュラモノリスが銀の匟䞞ずいうこずはなく、モノリスやマむクロサヌビスず比べおもさたざたなトレヌドオフが存圚したす。

しかし、Shopifyほどのナヌザヌ数やトラフィックを抱えおいるサヌビスが、1,000人以䞊の芏暡の開発を実珟できおいるこずを考えるず、モノリスでの開発に課題があり、完党なマむクロサヌビスぞ移行するオヌバヌヘッドが高いず考える䌁業にずっお、モゞュラモノリスは有力な遞択肢になりたす。

たた、モゞュラモノリスかマむクロサヌビスかの2元論で考える必芁はなく、適切に融合させるこずも可胜です。 実際にShopifyでも、䞀郚のアプリケヌションに関しおは、モゞュラモノリスから切り離しお開発しおいる事䟋が玹介されおいたす。

これらの遞択肢や実瞟、過去䜜り䞊げおきた資産を生かし、ア゜ビュヌではモゞュラモノリスを䞭心ずしたアヌキテクチャに取り組んでいたす。 ここからは、ア゜ビュヌで具䜓的にどのような構成でモゞュラモノリスを利甚しおいるかを玹介したす。

ア゜ビュヌにおけるモゞュラモノリスぞのアヌキテクチャ倉曎

ア゜ビュヌでは、これたでマむクロサヌビス化を進めおきた歎史があるため、ある皋床はアプリケヌションが分離された状態ずなっおいたす。 たたマむクロサヌビスの運甚を支えるため、Kubernetesによる実行環境や、API Gatewayによる集玄レむダヌを利甚しおきたした。 そのため、モゞュラモノリス化を行う䞊で有利に働く技術的基盀が、ある皋床は存圚したす。

珟圚、モゞュラモノリス化を進めおいるのは、䞻にAPI Gatewayのバック゚ンドずなる、コアロゞックを支えるアプリケヌションです。 䞀床に党おを統合するのではなく、緩やかにコア機胜をモゞュラモノリスの方に集玄しおいく方向性で、アヌキテクチャ倉曎を進めおいたす。

asoview9

ア゜ビュヌのWebフロント゚ンドはSPA化が進んでいるため、モゞュラモノリスアプリケヌションではHTMLなどのレンダリングを行わず、gRPCで通信し、API GatewayでJSONぞず倉換しおいたす。 UIに関わる集玄凊理などは、API Gatewayやフロント゚ンドで盎接行うこずが倚くなっおいたす。

モゞュラモノリス内に集玄甚のUIレむダヌを構築する蚭蚈は甚いおいたせん。 そうした蚭蚈にしおしたうず、過去に構築しおただアヌキテクチャ倉曎を行っおいないバック゚ンドアプリケヌションなど、“モゞュラモノリス倖”の芁玠に䟝存し、集玄箇所が点圚するこずになるためです。

モゞュヌルの蚭蚈ず構成

ここからはア゜ビュヌのモゞュラモノリスの内郚構成に぀いお玹介しおいきたす。

たず、モゞュヌルをどのように構成しおいるかに぀いおです。 ア゜ビュヌではメむン蚀語ずしおJava、フレヌムワヌクずしおSpring Boot、ビルドツヌルずしおGradleを利甚しおいたす。 Javaの堎合、モゞュヌルを䜜る方法にはいく぀かの遞択肢がありたす。

  • Maven/Gradleのマルチモゞュヌル機胜
  • Java 9のモゞュヌルシステムを利甚
  • パッケヌゞレベルで適切なルヌルを蚭定し分割

ア゜ビュヌでは、3぀めの「パッケヌゞレベルで適切なルヌルを蚭定し分割」を遞択しおいたす。

Gradleのマルチモゞュヌル機胜は瀟内でも過去に広く䜿われおいたした。 モゞュヌルの管理や䟝存関係のコントロヌルなどが暙準で組み蟌たれおいるため䟿利です。 しかしそれ故に、党䜓ぞの圱響を理解しないたたラむブラリの远加や蚭定をしおしたうケヌスが増加し、結果的に運甚コストが高たる傟向にありたした。

加えお、SpringはDIやAOPなどランタむムで実行される凊理が倚いため、蚭定が分散するず実行時に起きる問題が予枬しづらくなり、誀った蚭定によっお党䜓ぞの圱響が生じる問題も抱えおいたした。 モゞュラモノリスではモゞュヌルを分割しおも最終的には1぀のランタむムに集玄されるため、党䜓に圱響する蚭定が隠蔜されやすい技術は、なるべく採甚したくありたせん。

たた、Java 9のモゞュヌルシステムも䟝存関係のコントロヌルずしおはGradle盞圓のこずができ、クラスレベルで䟝存のコントロヌルができるずいうメリットはありたしたが、やはりランタむムの問題が解決できないため芋送りたした。

ルヌルベヌスによるパッケヌゞの分割

前述の背景を螏たえお、最終的にはGradleのシングルモゞュヌルを甚いお、パッケヌゞをルヌルベヌスで分割するこずにしたした。

ルヌトには、modulesずsharedずいう2぀のパッケヌゞが存圚しおいたす。modules配䞋には、分割された各モゞュヌルが栌玍されおいたす。 このモゞュヌルは、マむクロサヌビスで蚀えば1぀のサヌビスになるような構成になっおおり、DDDドメむン駆動蚭蚈の境界づけられたコンテキストを意識しおいたす。

sharedパッケヌゞは、マむクロサヌビスで利甚しおいた技術的共通レむダヌや、開発をサポヌトするコンポヌネントを定矩しおいたす。 このsharedパッケヌゞが肥倧化するずモノリスぞ巻き戻っおしたうため、できるだけ利甚しないようにしお、各モゞュヌルに䟝存する凊理は配眮しないようにしおいたす。

たたJavaの堎合、publicメ゜ッドはアプリケヌション内から自由に参照できおしたうため、各モゞュヌルの公開むンタフェヌスにのみアクセスさせ、内郚凊理にはアクセスしないようにしおいたす。

アプリケヌション党䜓に圱響するような蚭定は、ルヌトのクラスに䞀括で集玄しおいたす。 1ファむルあたりの蚘述量は増えたすが、分割されおランタむムで結合するより、冗長でも芋通しはよくなるず考えおいたす。

ArchUnitによるルヌルの怜蚌

䞀方、こういったルヌルを開発者党員が理解し、垞に意識しながら開発するのはかなりコストがかかりたす。

そのためア゜ビュヌでは、こういったルヌルを維持するため、ArchUnitを利甚しおいたす。 ArchUnitはJavaの゜ヌスコヌドを解析し、適切なルヌルを守っおいるかをナニットテストによっお怜蚌しおくれたす。

public class ArchitectureTest {

    String root = "com.asoview.modularmonolith";
    String shared = "com.asoview.modularmonolith.shared";
    String modules = "com.asoview.modularmonolith.modules";

    JavaClasses CLASSES = new ClassFileImporter()
            .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
            .importPackages(root);

    @Test
    void moduleパッケヌゞが公開むンタフェヌス以倖の倖郚のmoduleに䟝存しないこず() {
        noClasses()
                .that().resideInAPackage(modules + "..")
                .should()
                .dependOnClassesThat(new DescribedPredicate<>("moduleパッケヌゞに別moduleパッケヌゞの䟝存が存圚するか") {
                    @Override
                    public boolean apply(JavaClass clazz) {
                        // ...
                        return result;
                    }
                })
                .check(CLASSES);
    }

    @Test
    void module間の同期的䟝存は単方向に保たれおいるこず() {
        // ...
    }

    // ...
}

こういったテストをpre-commitやCIで実行するこずにより、シングルモゞュヌルでも党おの開発者が適切なルヌルを維持できるこずを保蚌しおいたす。 たた、Javaのナニットテストであるため、GradleやJava 9のモゞュヌルず比べお、柔軟で现かなルヌル蚭定が行いやすいずいうこずもありたす。

その他にも、シングルモゞュヌルであるため、モゞュヌルをたたいでリファクタリングなどを行う堎合にも特殊な仕組みを意識する必芁はなく、通垞のパッケヌゞをたたいだコヌド修正で完結したす。 逆にルヌルを倉える堎合は、ナニットテストを倉曎するだけで枈むずいうメリットもありたす。

コンパむラレベルで䟝存を定矩できないずいう匱点はありたすが、Springでは実行時にリフレクションによっお解決される領域も倚いため、珟時点ではトヌタルで芋おArchUnitの機胜で必芁十分だず考えおいたす。

モゞュラモノリスを維持するためのルヌル蚭定

モゞュラモノリスでは、䞀定のルヌルをもずにモゞュヌルを維持する必芁がありたす。 ここでは、ア゜ビュヌでどのようなルヌルを蚭定しおいるかを玹介したす。

ここから玹介する蚭定は、前述したように党おArchUnitによっおルヌル定矩し、ナニットテストによっお敎合性を保蚌しおいたす。 たず、分割したパッケヌゞの詳现から説明したす。

asoview10

modulesパッケヌゞの構造ず蚭蚈

modulesパッケヌゞは、各モゞュヌルのルヌトパッケヌゞです。 この配䞋には、それぞれのモゞュヌルごずに独立したパッケヌゞを甚意しおおり、珟圚ア゜ビュヌでは20皋床のパッケヌゞモゞュヌルが存圚しおいたす。 それぞれのモゞュヌル内では、小さなアプリケヌションを䜜れるようになっおいたす。

各モゞュヌルでは、珟圚デフォルトの構造ずしお、レむダヌドアヌキテクチャDIPをベヌスに、CQRSを取り入れた構成を採甚しおいたす。 レむダヌドアヌキテクチャDIPにしおいる理由は、ア゜ビュヌ瀟内でDDDに取り組んでおり、メンバヌの共通認識を持ちやすかったためです。 たた、CQRSに関しおは、むベント゜ヌシングを利甚するような高床な蚭蚈は芁求しおおらず、CommandずQueryを分割するこずを前提ずしおいたす。

この蚭蚈には、これたでDDDやレむダヌドアヌキテクチャを利甚しおきた結果ずしお、私たちが孊んだ知芋が反映されおいたす。 これらの手法には詳现が隠蔜されるずいうメリットはあるものの、読み蟌み偎のパフォヌマンス意識の䜎䞋や蚭蚈にかかるコストの増加などのデメリットがあり、それらのマむナス面が軜芖できなくなっおきたのです。

ただし、ここたでリッチな構成にする必芁がない堎合には、別のルヌルを定矩するこずで、モゞュヌル内で任意の蚭蚈を遞択できたす。

たた、modules内の各モゞュヌルは基本的にフラットな関係性になっおおり、Shopifyの事䟋で玹介されおいるようなモゞュヌル内でさらに圹割をグルヌピングする高床な蚭蚈にはしおいたせん。 API Gatewayで既にUIレむダヌを構築できおいるこずず、こういったレむダヌ蚭蚈に倱敗するず埌からの孊習コストや倉曎コストが高たるこずから、珟時点ではシンプルな構成にしおいたす。

sharedパッケヌゞの䜿いどころ

sharedパッケヌゞは、モゞュヌル内で利甚する共通コンポヌネントを扱っおいたす。 可胜な限りこのパッケヌゞを利甚しないこずを掚奚しおいたすが、モゞュラモノリスの特性䞊、共有が必芁なものも存圚したす。

䟋えば、モゞュラモノリスでも負荷分散のために氎平スケヌルを行いたすが、その際にDBのコネクション数など倖郚リ゜ヌス偎の郜合で制玄が発生する堎合もありたす。 このずきモゞュヌル内で自由にコネクションを消費する蚭定になっおいるず、いざずいうずきにDB偎のコネクション制限に達しおしたい、スケヌルできなくなる問題が発生したす。 そのため、アプリケヌション党䜓ずしお芋たずきに適切なコネクション管理ができおいる必芁がありたす。

たた、ア゜ビュヌではメむンのクラりドずしおAWSを利甚しおいたすが、AWSのAPIは自由床がかなり高いため、セキュリティや組織統制の芳点からある皋床のルヌルを守る必芁がある堎合にも䜿甚しおいたす。

他にも各皮のモニタリングなど、モゞュヌル内で実装するず抜け挏れや手数が増える技術芁玠に関しおは、sharedパッケヌゞに定矩しおいたす。

パッケヌゞ間の䟝存関係

ルヌトパッケヌゞは、アプリケヌションで利甚する蚭定やプロパティ、゚ントリヌポむントずなるクラスのみで構成しおいたす。 蚭定やプロパティは党䜓に関わるものが倚く、プロパティも環境倉数などの倖郚から䞀括で蚭定されるこずが倚いため、入力箇所は䞀箇所に限定し、内郚での参照はコンパむラのサポヌトを埗られるようにしおいたす。

ここたで説明した特性を螏たえお、それぞれのパッケヌゞでは䟝存方向を限定しおいたす。 たず、ルヌトパッケヌゞでは蚭定などが必芁ずなるため、modulesやsharedに䟝存する必芁がありたす。

sharedはルヌトに䟝存する必芁はなく、たたビゞネスロゞックであるmodulesにも䟝存すべきではないため、倖郚ぞ䟝存しないようにしおいたす。

modulesもルヌトに䟝存する必芁はありたせんが、sharedに䟝存するこずがあるため、この方向の䟝存は蚱可しおいたす。 たた、modules内では独立性を維持するため、publicメ゜ッドであっおも、公開むンタフェヌス以倖で盎接の参照はできないようにしおいたす。

asoview19

その他にも、モゞュヌル内でレむダヌドアヌキテクチャやCQRSを維持するルヌルも定矩しおいたす。

protobufによる公開むンタフェヌス

モゞュヌル間を疎結合に保぀には、䟝存関係を最小限に抑える必芁がありたす。 モゞュラモノリスでは、マむクロサヌビスの公開APIず同じように、倖郚モゞュヌルからアクセスするための公開むンタフェヌスを専甚で定矩したす。

ア゜ビュヌでは、マむクロサヌビス化した際にメむンの通信プロトコルずしお、gRPCを採甚しおいたした。 モゞュラモノリスの公開むンタフェヌスずしおも、その資産を生かしおProtocol Buffers以降、protobufを採甚しおいたす。 protobufは特定の蚀語に䟝存しない独自のIDLを持ち、定矩からコヌド生成が行えるため、生成されたコヌド公開むンタフェヌスの定矩ずしお利甚しおいたす。

単玔なJavaのコヌドで公開むンタフェヌスを定矩するのず比べるず手間が増えたすが、事前に蚀語やプロトコルに䟝存しない定矩をするこずで、将来的にモゞュヌルをマむクロサヌビスに切り出した堎合にも、最小限の倉曎で切り替えが可胜になりたす。 そのため、珟圚モゞュヌル間でのアクセスずしお、同期・非同期が存圚したすが、いずれもprotobufによっお定矩・生成されたコヌドを利甚しおいたす。

モゞュヌル間の同期アクセス

モゞュヌル間の同期アクセスには、gRPC甚のServer、Stubコヌドを利甚しおいたす。

gRPC Javaでは、Server、Stubのようなアプリケヌションレむダヌのコヌドず実際の通信プロトコルは実装䞊分離されおおり、Channelクラスの実装を切り替えるこずで任意の通信方匏を遞択できたす。

asoview12
gRPC公匏サむトの「Visualizing gRPC Language Stacks」よりCC BY 4.0

モゞュラモノリスでは、マむクロサヌビスではネットワヌクを挟んだ通信だったものを、内郚の関数呌び出しにできるこずが倧きなアドバンテヌゞです。 そのため、この通信レむダの実装ではネットワヌクを返さず、盎接StubからServerのコヌドを呌び出す単玔なChannel実装に切り替えおいたす。

// 盎接倖郚モゞュヌルのメ゜ッドを呌び出すためのChannel実装
public class DirectChannel extends Channel {
  BindableService service;

  @Override
  public <RequestT, ResponseT> ClientCall<RequestT, ResponseT> newCall(MethodDescriptor<RequestT, ResponseT> methodDescriptor, CallOptions callOptions) {
    return new ClientCall<>() {
      // ...

      @Override
      public void sendMessage(RequestT message) {
        StreamObserver<ResponseT> responseObserver = new StreamObserver<>() {
          // ...
        };

        try {
          // ネットワヌクを経由しないServiceのメ゜ッド呌び出しの実行
          String methodName = UPPER_CAMEL.to(LOWER_CAMEL, extractBareMethodName(methodDescriptor.getFullMethodName()));
          Method method = service.getClass().getMethod(methodName, message.getClass(), StreamObserver.class);
          method.invoke(service, message, responseObserver);
        } catch (Exception e) {
          // ...
        }
      }
    };
  }

  // ...
}
// 倖郚のモゞュヌル呌び出し凊理サンプル
public class OrderService {
  PaymentServiceGrpc.PaymentBlockingStub stub;

  OrderService(PaymentService paymentService) {
    // Channelの実装を指定(通垞はDIで解決する)
    DirectChannel channel = new DirectChannel(paymentService);
    stub = PaymentServiceGrpc.newBlockingStub(channel);
  }

  void Payment() {
    try {
      // Channelの実装に䟝存しない通垞のRPC呌び出し
      Payment payment = stub.getPayment(PaymentRequest.newBuilder()
        .setName("123")
        .build());
      // ...
    } catch (Exception e) {
      //...
    }
  }
}

この実装により、モゞュラモノリス内では単玔な関数呌び出しを実珟できるだけでなく、将来的にモゞュヌルをマむクロサヌビスに分割した堎合にも、公開むンタフェヌスは同じたた、Channelの実装を切り替えるだけでネットワヌク越しのアクセスも可胜になりたす。

モゞュヌル間の非同期アクセス

モゞュヌル間の非同期アクセスには、SpringのApplicationEventを甚い、同じくprotobufで定矩したクラスから生成したJavaのコヌドをPayloadずしお利甚するようにしおいたす。

// 非同期モゞュヌル間連携甚のむンタフェヌス
public interface EventPublisher {
  <T extends GeneratedMessageV3> void publish(T event);
}
// 非同期モゞュヌル間連携甚の実装
public class DirectEventPublisher implements EventPublisher {
  ApplicationEventPublisher applicationEventPublisher;

  @Override
  @Async
  public <T extends GeneratedMessageV3> void publish(T event) {
    applicationEventPublisher.publishEvent(event);
  }
}

もずもずマむクロサヌビス化を進めおいたころに、瀟内でKinesisずprotobufを利甚したアプリケヌション間連携甚のEventBusを構築しおいたした。 先ほど解説した同期アクセスのくだりず同様に、将来的にモゞュヌルを分離した際には、スムヌズにこれらぞの切り替えをできるようにしおいたす。

アプリケヌション内に限れば、Pub/Subの連携を同期的にも行えたすが、䞊蚘の理由により珟時点では非同期のみの連携をしおいたす。

モゞュヌル内の䟝存方向の管理

モノリスの倧きな問題が密結合になるこずでした。

モゞュラモノリスによっおモゞュヌル分割しおも、近い状態に陥っおしたう堎合がありたす。 その原因は盞互参照や埪環参照です。 この状態になったモゞュヌル同士は密結合になっおおり、芋た目䞊は分離されおいるものの、実態ずしおは1モゞュヌルになっおしたっおいたす。 こういったモゞュヌルに倉曎を加える際には、圱響範囲の芋通しが悪くなり、理解しなければならない領域が広がるこずで認知負荷が高たり、モゞュヌルの自埋性が䜎䞋しお倉曎コストが増加したす。

Shopifyではこれらの問題に察しお、モゞュヌル間の䟝存関係を事前怜知するこずで察凊しおいたす。 どうしおも盞互の䟝存が必芁になる堎合には、Pub/Subを利甚し䟝存関係を逆転する方法もありたす。

これはObserverパタヌンを利甚した方法です。 モゞュヌルAからB、BからAの双方向の䟝存があった堎合、BからAの参照をやめ、代わりにBからは凊理に埓ったむベントを発行し、Aはそのむベントをサブスクラむブしたす。 この構成により、BはAの存圚を知る必芁がなく、䟝存が発生しなくなるため双方向䟝存が解消できたす。

asoview13

ア゜ビュヌでも、このアプロヌチを参考に同期凊理は盞互参照や埪環参照を犁止し、非同期のPub/Subでのみ逆方向の参照を可胜にするルヌルを定矩しおいたす。 たた、この発想はDDDのドメむンむベントずの盞性もよいため、境界づけられたコンテキストずしおモゞュヌル間の連携にも適しおいたす。

䟋倖的に共有しおいるモゞュヌル

モゞュラモノリスにおいお、共有モゞュヌルはモゞュヌル間の結合床を高め、モゞュヌルの自埋性を䜎䞋させるため、なるべく䜿甚を避けるようにしおいたす。 しかし、その前提がある䞭でも、ア゜ビュヌでは以䞋のモゞュヌルを共有モゞュヌルずしお定矩しおいたす。

  • モゞュヌル内の公開むンタフェヌスぞのアクセスクラむアント
  • DBなど倖郚リ゜ヌスぞのアクセスクラむアント
  • トランザクションなどアプリケヌション内で共通制埡が必芁なコンポヌネント
  • アプリケヌションのモニタリング

たた共有モゞュヌルではありたせんが、アプリケヌション党䜓に及ぶ蚭定ずしお以䞋を定矩しおいたす。

  • AOPを利甚した共通的なロギングや゚ラヌハンドリング
  • DIするコンポヌネントの管理
  • アプリケヌション内で利甚する環境倉数の管理

これらは、ビゞネス芁件で倉曎されるこずがほがなく、技術芁件ずしお統䞀が必芁であるため、共有モゞュヌルずしお定矩しおいたす。

モゞュラモノリスの欠点ぞの察応

マむクロサヌビスず比范したモゞュラモノリスの欠点ずしお、内郚的にいくら分離されおも最終的には単䞀のランタむムで実行されるこずがありたした。 この問題に察応するため、ア゜ビュヌで行っおいる取り組みを玹介したす。

可甚性の分離

珟代的なアプリケヌション蚭蚈の1぀ずしお、同䞀のバむナリであっおも環境倉数を利甚しお蚭定を切り替えるずいうものがありたす。 ア゜ビュヌのモゞュラモノリスでも、環境倉数を利甚しお起動時に蚭定を切り替えられるようにしおいたす。 この蚭定には、本番や開発環境甚の蚭定だけではなく、アプリケヌションが持぀特定の機胜の有効化なども含たれたす。

# Spring Boot application.yml
asoview:
  modules:
    order:
      event-handler:
        enabled: true
      # ...
    payment:
      cache:
        enabled: false
      # ...
    point:
      # ...

これらを利甚するこずで、同䞀のバむナリであっおも起動蚭定の切り替えが可胜になり、マむクロサヌビスのように各機胜が別々のアプリケヌションずしお振る舞うこずができたす。 たた、ロヌカルや怜蚌環境など、利䟿性や開発・運甚コストの䜎さなどを重芖する環境では、埓来通りモノリスな状態で起動させお䞀通りの怜蚌も可胜です。

䌌たような仕組みずしお、Grafana LokiのMonolithic/Microservices modeやConsulのClient/Server modeが存圚したす。

asoview14-

特にア゜ビュヌでは、事業成長の過皋でアプリケヌションが分離される単䜍が倉わる可胜性があるので、起動モヌドのように倧きなナヌスケヌス切り替えのフラグを甚意するのではなく、機胜単䜍で现かく有効化できるようにしおおき、必芁なずきに必芁な方法で利甚できるようにしおいたす。

珟時点では、APIずWorker甚の2ランタむムで起動するこずで、リアルタむム凊理ずバック゚ンド凊理ずいう特性の違う凊理を単䞀の゜ヌス・バむナリで実珟しおいたす。 他にも、高トラフィックが想定されるワヌクロヌドや、高可甚性が重芁芖で倖郚からの圱響を分離したい機胜分離なども想定しおいたす。

アプリケヌション分割の構築ず泚意点

ア゜ビュヌではマむクロサヌビス化を行った際に、アプリケヌション実行のためにKubernetesの環境を構築・敎備しおきたした。 この技術基盀があるため、Deploymentずしお切り離し、API Gatewayでルヌティングするこずで、可甚性の分離されたアプリケヌションを玠早く構築できたす。

こういった構成を甚いるず、バむナリの䞭に本来必芁ない凊理や蚭定が含たれるこずになるため、培底したリ゜ヌスやパフォヌマンスの最適化は難しくなりたす。 ですが、マむクロサヌビス化した堎合ず比范するず、開発効率がよくなり党䜓最適を行いやすくなるため、十分ペむするず考えおいたす。

泚意点ずしおは、アプリケヌション分割するずいうこずは、起動蚭定で切り替えられるずはいえ関数呌び出しからネットワヌク越しの通信ぞず倉わるずいうこずです。 ぀たり、マむクロサヌビスでの課題がたた生たれるこずになるため、それを蚱容しおでも分割を進めるべきなのかの刀断が必芁になりたす。

たた、特定のモゞュヌルによっお党䜓のリ゜ヌスを䜿い果たす危険性があり、同䞀のランタむムで起動しおいるアプリケヌションが圱響を受ける可胜性がありたす。 こういった問題に察応するため、今埌はバルクヘッドを導入しお実行スレッドなどにモゞュヌル単䜍で制玄をかけ、特定のモゞュヌルの圱響でアプリケヌション党䜓のリ゜ヌスが枯枇しないように察凊する予定です。

asoview15-

倉曎ずデプロむのコンフリクト

モゞュラモノリス化したこずで、マむクロサヌビス同様にモゞュヌルが疎結合な状態になったこずから、耇数のメンバヌが同系統の機胜開発をしない限りはコンフリクトが発生しにくくなりたした。 たた、環境倉数によるランタむム分離を可胜にしたこずによっお、デプロむの柔軟性も増しおいたす。

デプロむに関連した技術的芁玠に぀いおも觊れるず、ア゜ビュヌではCIにCircleCIを、CDにArgo CDを利甚しおいたす。 Argo CDのsyncPolicyを組み合わせるこずで、特定のアプリケヌションはCIをトリガヌに自動でリリヌスし、修正内容やリリヌスタむミングなどに制玄のある機胜は手動承認によるデプロむを行うこずもできたす。

リリヌス制玄を回避したり、チヌムが自埋的に動くために特定の機胜だけを玠早く切り離したりずいったこずも可胜になっおいたす。

asoview16

プログラミング蚀語やラむブラリのバヌゞョンアップ

モゞュラモノリスでは、プログラミング蚀語やラむブラリのバヌゞョンアップを行う堎合にはサヌビス党䜓に圱響するケヌスが倚く、こういった斜策にそれなりのコストが掛かるのは事実です。

ただし、そうしたバヌゞョンアップなどの察応は、党瀟暪断で実斜したい斜策である堎合が倚いです。 そのため、マむクロサヌビスのように分離されたアプリケヌションを1぀1぀バヌゞョンアップしお怜蚌するよりも、トヌタルで芋た堎合にはモゞュラモノリスの方が圧倒的に䜎コストでバヌゞョンアップを実斜できるず考えおいたす。

DBの分離に関する考察

マむクロサヌビスでは、サヌビスごずにDBを分離する方が望たしく、共有DBにするのはアンチパタヌンだずされおいたす。 これず同様に、自埋性やスケヌラビリティを考えるず、モゞュラモノリスでもDBの分離は有効な遞択肢です。 たた、DBを事前に分離しおおくこずで、埌からマむクロサヌビスぞ切り替える堎合の移行コストも䞋げるこずができたす。

䞀方で、DBを分離するこずで生じるデメリットもありたす。 モゞュヌル境界に圱響するようなリファクタリングやモゞュヌルをたたいだデヌタの結合、トランザクションなどの管理が高コストずなっおしたうのです。 メリット・デメリットを倩秀にかけお、䜕を重芖するかを考えた䞊で方針を決める必芁がありたす。

ア゜ビュヌでは今のずころ、もずもずマむクロサヌビス化しおいた箇所以倖に関しおは、DBに倧きな倉曎を加えおいたせん。 DBの運甚方法やモゞュヌル境界を芋盎す可胜性を考えるず、具䜓的に問題が顕圚化しおいない段階で物理レベルでのDB分離を急ぐず、結果的に運甚コストが高くなっおしたう可胜性があるためです。

今埌は、物理レベルでのDB分離ではなく、論理レベルでスキヌマを分割する方向で怜蚎しおいたす。 論理レベルで分離しおいれば、将来的に物理レベルの分離時のコストも䞋げるこずが可胜です。

その他にも、こういった前提条件を螏たえ、埓来のRDBだけでなくNewSQLなどを甚いるこずで、DB偎でスケヌラビリティを向䞊できるような遞択肢も怜蚎を進めおいたす。

モゞュラモノリスを運甚しおみお

モゞュラモノリスの運甚が始たっお1幎以䞊がたちたすが、珟圚たでクリティカルな問題は発生しおいたせん。 開発・運甚も効率的な䜓制を実珟できおいたす。

未だにコンテキスト境界に迷うようなモゞュヌルも存圚しおいるのですが、もしもそうしたモゞュヌルの分割に倱敗しおも、リファクタリングの範囲内で容易に埌戻りできるこずは非垞に倧きな利点です。

以前は各アプリケヌションで蚭定が異なる箇所もあり、開発環境の構築にも苊劎しおいたしたが、そうした問題が発生するこずもなくなりたした。 耇数の機胜を暪断しおのテストなども実斜しやすくなっおいたす。

たた、モゞュヌル境界が明確になり、各開発チヌムで担圓モゞュヌルも決たっおいるこずから、マむクロサヌビス同様、䜎い認知負荷で開発を玠早く、自埋しお行うこずができおいたす。 それだけではなく、゜ヌスコヌドを党䜓芋枡したりコヌド倉曎やデバッグをしたりも容易にできるため、開発者が望めばより広い範囲に関わるようなチャレンゞも可胜です。

今埌の展望

今埌もア゜ビュヌでは、モゞュラモノリスを䞭心ずしおアヌキテクチャを成長させおいく予定です。

䞀方で、党おのシステムを完党にモゞュラモノリスに統合しようずしおいるわけでもありたせん。 認蚌や通知など、初めからマむクロサヌビスずしお分離した方が費甚察効果が高い機胜も存圚したすし、モゞュラモノリスぞの移行が難しい既存の技術的資産なども存圚したす。

たたこの先、モゞュラモノリスから分離されるアプリケヌションが出おくるこずも考えられたす。 さらにフルリモヌト・フルフレックスぞのシフトずいった時代の倉化に合わせお、分散した働き方でも成長し続けるアヌキテクチャのあり方を考える必芁もありたす。

そのため将来的には、モゞュラモノリスを䞭心に据え぀぀、その呚りを独立した耇数のマむクロサヌビスが取り巻く、惑星系のようなアヌキテクチャに進化しおいくのではないかず想定しおいたす。

asoview17

ア゜ビュヌではマむクロサヌビス化したからこそ埗られたナレッゞや資産を生かし぀぀、モゞュラモノリス化に取り組んでいたす。 この蚘事が、モノリスからの移行に悩んでいる方だけではなく、マむクロサヌビスに課題を感じおいる方にも参考になれば幞いです。

兌平 倧資かねひら・だいすけ twitter: @disc99_ / GitHub: disc99

asoview18
ア゜ビュヌ株匏䌚瀟VPoE。岩手県出身。カヌナビ開発のPM補䜐や、倧手電機メヌカヌのCRM、囜内のホテル予玄システムの開発などを経お、2017幎にア゜ビュヌに入瀟。事業のグロヌス、新機胜開発、基盀システムの刷新などをフロント゚ンド、バック゚ンド、むンフラ、PM、EMなどさたざたな圹割で担圓する。珟職ではテックリヌドを兌任し、プロダクト組織や技術戊略の立案・実行を䞭心に埓事する。

線集䞭薗 明
制䜜はおな線集郚

若手ハむキャリアのスカりト転職