コズレ開発者ブログ

cozre developer's blog

【Tech02】コズレを支える技術 アプリケーション構成編

こんにちは。コズレのもっちーです。

feature.cozre.jp

最近、この界隈ではマイクロサービスにしようだのやっぱりモノリシックに戻ったほうがよいだのと盛り上がっているようですが、今回はアプリケーション構成の観点で、コズレはどう取り組んでいるのか、整理してみたいと思います。

アプリケーションの構成

マイクロサービスアーキテクチャとは

かの有名なエンジニアのマーチン・ファウラー氏らによって、数年前に以下のようなことが言われていました。

単一のアプリケーションを小さなサービスのスイートとして開発するアプローチであり、それぞれが独自のプロセスで実行され、軽量メカニズム(多くの場合、HTTPリソースAPI)と通信します。これらのサービスはビジネス機能を中心に構築されており、完全に自動化された展開機構によって個別に展開できます。これらのサービスの最小限の集中管理があり、異なるプログラミング言語で記述され、異なるデータストレージテクノロジーを使用する場合があります。 (翻訳 by Google)

出典:https://martinfowler.com/articles/microservices.html

モノリシック vs. マイクロサービス

f:id:cozre-dev:20200605182122p:plain
モノリシック vs. マイクロサービスの図

図に示したのが、いわゆるモノリシックアーキテクチャマイクロサービスアーキテクチャを模式化したものです。

左側がモノリシックの図で、プレゼンテーション層ビジネスロジックデータアクセス層の3層モデルの想定で記述しています。 対する右側がマイクロサービスの図で、プレゼンテーション層の代わりに、各サービスを束ねて、クライアントとのやり取りを担うAPIゲートウェイがあり、ビジネスロジックにあたるマイクロサービス処理の単位ごとに独立して存在し、データベースも独立して存在しています。

詳しい解説は、ぐぐってもらえばよいかと思うので割愛します。 この構成を踏まえて、コズレではどうなっているのかというところを深堀していきたいと思います。

コズレはミニサービス

ミニサービスのモデル

f:id:cozre-dev:20200605183404p:plain
ミニサービスの図

マイクロより大きいので勝手にミニサービスとつけましたが、図に示したものがコズレでのケースをモデルにしたものです。

いつか、Wikipediaミニサービスとはエンジニアもっちーが最初に言い出したと記述されると思います。

サブシステム x 内部API x MQ

コズレのサービスは、マガジンサービス、クチコミサービス、ユーザ基盤、分析基盤、メルマガツール等、複数のサブシステムの組み合わせで成り立っています。

コズレでは、Java言語で開発をしているので、WEBアプリケーションならば war ファイル、バッチ処理系アプリケーションならば jar ファイルがリリースする時のシステムの単位になります。

そして、この war(jar) の単位がサブシステムとなっています。 マガジンサービスなら magazine.war があり、ユーザ基盤なら user.war があります。 そして、前回の「システム構成編」でも紹介していますが、内部APIがあるので、ユーザAPIなら、api-user.war があり、マーケティングAPIなら api-marketing.war があるのです。

そして、それぞれのサブシステム内部APIから呼び出されるメッセージキューイングの処理は jar として複数存在しています。 画像のリサイズをしてアップロードする処理なら magazine-edit.jar 、メルマガを配信する処理なら mail.jar といった具合です。 (正確には jar の中にはメッセージを投げるパブリッシャーやメッセージを受け取るサブスクライバーがいて、キューをうけとるスレッドワーカーがコンシュマーとして各処理を担当しています)

こう見ていくと、コズレってマイクロサービスちゃうか?ってミルクボーイも言いそうですが、そこまでマイクロサービスじゃないのです。

トランザクション境界の問題

コズレではサブシステムとほぼ対になる形でデータベースが存在しています。 マガジンサービスなら magazine のDBがあり、ユーザ基盤なら user のDBがあり、メルマガツールなら mail のDBがあります。

マイクロサービスでは処理を分割しすぎるせいでトランザクション境界が問題になることがありますが、コズレのサブシステムではDBがそのまま関心事の対象で定義してあり、サブシステム内で閉じています。 トランザクションが分離されてロールバックできないとか、整合性が崩れるといったことがありません。

小さすぎず、モノリシックでもないので、ミニサービスなのです。

分割の基準は何か?

サブシステムとして設計する時に、どう世界を切り取るのかが肝かもしれないと思います。 ドメイン駆動開発の思想で関心事をまとめると結果的にそうなったということかもしれませんが、意識して分けたポイントはあります。

それは、リリースのタイミングと頻度です。

端的に言えば、大勢のユーザが利用しているサービス側と、数名の社員が使う業務機能側が同じサイクルで更新されるわけがないのです。 機能の改善や追加をするサイクルが違ってくるだろうという関心事が分割の基準になっています。

なぜ、リリース頻度を気にするかと言うと、コズレも言うに及ばず、アジャイル開発だからです。 スモールリリースをし、改善を回していくのが前提にあったので当初からサブシステムとして機能するアーキテクチャを設計したのでした。

マイクロサービスのデメリット

マイクロサービスのメリット・デメリットもぐぐれば、いろいろ出てくるのですが、ここではあるイベントでのLIFULLCTO 長沢さんの言葉を引用させてもらいます。

分割を進めることを優先して、共通部分を無視してあえてマイクロサービス化した部分があるのですが、開発が進むと共通部分に関わるオーバーヘッドが段々無視できないレベルになってきてしまいました。ログの取得やインターフェースの部分です。効率的ではなくなってしまったので、現在は全体の共通基盤を作ろうとしているところです。

出典:後編:知ってるようで知らないマイクロサービス〜様々な意思決定のロジック~マイクロサービス化に必要な要件 | flexy(フレキシー)

ちなみにですが、コズレはLIFULLさんから投資していただいております。いつか、システム連携できるといいですね。

住み替えを検討する時って、子供が生まれた時なんですよね。住居の広さもそうですし、安全性や清潔さを保つ環境は、自分のためではなく子供のためを思ってこそなのです。 だから、弊社コズレとLIFULLさんは相性がよいんだと思っています。

コズレの共通基盤

もう一度、コズレのミニサービスの図をよく見てください。

気付きました?そうなんです。各 war や jar の中の構成はプレゼンテーション層(UI, API, PUBLISHER/SUBSCRIBER)以外は同じようになっているんです。 コズレでは、パッケージ内の構成をコーディング規約に明記し、独自のフレームワークでアプリケーション内の依存関係に制約をもたせるようにしています。

各3層構造が疎結合になるようにしているので、プレゼンテーション層組み替えをするだけで、WEBアプリケーション用にも内部API用にも、バッチ処理系アプリケーション用にも、ビジネスロジック再利用できるんです。 とても美しいですね。

また、フレームワークは、APIとのやり取りMQでのやり取りをするための処理を共通化したり、上記引用での指摘があったようにログの仕組みなどをカバーしています。

また、コズレ独自のユーザセッションの仕組みがあるので、WEBサーバ上の各サブシステムは、ユーザ基盤でログイン後、そのユーザ認証情報を使えるようになっています。

名付けて、「cozre-common」というフレームワークを初期から使っています。

まとめ

コズレマガジンのアプリケーション構成について整理してみました。

個人的には、とても美しいアーキテクチャだとは思っていますが、現実にはリファクタリングしたい疎結合じゃないコードも存在しています。 時間があれば、リファクタリングしたいなぁと葛藤しています。テストケースを充実させたら、じゃんじゃんインターン生に直してもらうのもありかなぁと思う今日この頃です。

そんなコズレでは一緒に働いてくれるエンジニアを募集中です。 興味ある方は、ご連絡ください。

コズレ開発チームのTwitterアカウントはこちら