PHPカンファレンス2020 レポート

PHPカンファレンス2020 レポート[後編]

この記事を読むのに必要な時間:およそ 5 分

12月12日(土⁠⁠,PHPカンファレンス2020が開催されました。PHPカンファレンスは今年20周年の節目を迎え,初のオンライン開催となりました。前編に続き,本稿ではその模様をお伝えしていきます。

竹澤有貴さん「事業のスケールアウトを支えるPHPで作る分散アーキテクチャ」

スターフェスティバルの竹澤有貴さんは,これまで大規模データを扱う業務に多く携わってきました。その中での経験を基に,事業を支える大規模アプリケーションをどのようなパターンで構築していくかについて話しました

「Event Sourcing」「CQRS」をキーワードに上げ,これらと同列に語られることの多いドメイン駆動設計についても紹介しました。

画像

ビジネスの成長と組織

アプリケーションは小さなアプリケーション,小さなチームから始まります。当初は意思疎通が取りやすいのでコードベースの統一も容易に取れますが,大きいチームになると,意思疎通もコードベースの統一も難しくなっていきます。やがて,パフォーマンスの悪いコードが量産されるようになります。

具体的な例として,N+1問題を挙げました。アプリケーションが小さいうちは顕在化しないものの,アプリケーションが大きくなってくると,これらの問題が顕在化してきます。その際,取ってしまいがちな対応として,垂直スケールやテーブルの非正規化が行われますが,これを成長途上のプロダクトで行ってしまうと後から切り札がなくなってしまうなど,サービスの成長に悪影響を及ぼすと述べました。

また,アプリケーションが大きくなるにつれて機能要件が困難になっていき,データ取得のコストもどんどん上がっていきます。

こうしている間にもビジネスは止まらず開発を進めていくしかなく,継ぎ足されるコードがどんどん増えていき,さまざまなサービスが絡みあう大きなサービスになっていきます。アプリケーションの負荷も高まっていきます。対症療法的にキャッシュ機構を導入してしまうと,サービス間のデータの整合性が徐々に取れなくなっていき,コードベースの修正だけでなくアーキテクチャの抜本的な改善が必要になると述べました。

大規模アプリケーションで顕在化する,データ設計に起因する問題は次の3点です。

  • 大量データのフルスキャンが走っている
  • INDEXが適切に設定されていないことによるパフォーマンス低下
  • テーブルがシンプルであるが故に複雑なクエリが走る
    ※具体例として,新しい機能を実現しようとした場合に他のテーブルをJOINしなければ実装できない場合を挙げました。

このような問題を多く抱えたアプリケーションでは,機能追加時のソースコード調査に長期間かかってしまったり,複雑なソースコードによるエンジニアのモチベーションダウンを招いてしまうこと,場合によっては実装する時間がかかりすぎるが故に機能追加が見送りになることを挙げました。このことは機会損失による競合優位性の低下を招き,ビジネスがスケールしなくなることに直結し,会社全体に悪影響を及ぼすことを指摘しました。

様々な可能性を考慮したデータ設計を初期のうちに考慮はできないとして,非正規形のテーブルによって対処することの危うさについても言及しました。非正規化テーブルでは,特定の要件だけにしか対応できないテーブルになりがちです。それ以外の要件に対応するのは難しく,仕様変更やサービス拡大が難しくなると述べました。

また,定期的にデータベースやアプリケーションのリファクタリングを行うことは労力的に難しくなります。高速または高性能なデータベースを使うなどの場合でも,ミドルウェアレベルではアプリケーションの複雑さを解決できないことに触れた上で,ミドルウェアの検討と合わせてアプリケーションの改善が必要であることを指摘しました。

DDD(ドメイン駆動設計)

要件分析を行わない設計では,誤った汎用化が行われがちです。そこで,DDDで用いられる手法である「境界づけられたコンテキストを意識したドメイン分割」を行うことになります。これにより,アプリケーション内のドメインを意識できる点,ドメイン内に存在するモデルの属性がどのようなものかを洗い出すことができると言います。また,各ドメインによって必要な読み込み/書き込みモデルを意識することで,要件の複雑に立ち向かえることも指摘しました。

後述するCQRSではこのドメインの知識を前提としており,ここの理解なしにはCQRSを実践できません。

CQRS

業務要件とデータ構造の差分は必ずあると述べた上で,どちらも分離できればシンプルな設計になると述べました。これに対抗する手段としてCQRSを挙げました。

読み込み/書き込みモデルによってデータベースを分離することが可能となるため,それぞれのモデルでパフォーマンスの出やすいデータベースを採用できます。

書き込みに強いデータベース
  • Cassandra
  • DynamoDB
読み込みに強いデータベース
  • 基本的にはDBMSで十分
  • LIKE検索に強いのはElastic Search,Solrなど

CQRSを導入するメリットとデメリットとして,次の点を挙げました。

CQRSを導入するメリット
  • 読み書きのデータベースを分離することによる耐障害性の向上
  • スケーラビリティの向上や,読み込み/書き込みモデルで効率の良いデータベース(RDBMS,NoSQL)を選択できる
  • Command/Queryの関心を徹底的に分離できる
  • 書き込み時の正規化を崩す必要がない
  • 読み込みのスケーラビリティを確保できる
CQRSを導入するデメリット
  • アプリケーションを構成する要素が増えるため,全体の設計が増える
    • Create,Update,Delete アプリケーション
    • Read アプリケーション
  • 扱うデータベースが増えるにつれて運用コストが増える
  • データベースが分離することにより,レプリケーションのタイムラグが増える

EventSourcing

CQRSでデータベースを分離する際,データベース間のデータ整合性を担保するために使います。データ更新(書き込み)のイベントをイベントストアに逐次記録して,再現するパターンです。

PHPの場合はMessage Brokerを導入する必要があり,次の要件を満たす必要があると話しました。

  • Pub/Subに対応していること
  • イベントストアに揮発性がないこと
  • スケーラブルであること

この要件を満たすものとして,竹澤さんはApatche Kafkaを推薦しています。

分散トランザクション

分散トランザクションについて,導入コストやシステムが複雑化するという問題から,基本的には導入することは勧めませんでした。

極力,1プロセスで複数データベースにまたがる更新処理を行わない対策を示した上で,どうしても避けられない場合はマイクロサービスアーキテクチャの1つであるSagaパターンを導入する方法を示しました。

例として,コレオグラフィとオーケストレーションの2種類の分散トランザクションの実装パターンを紹介しました。竹澤さんは「小規模な分散処理はPHPで実装できるものの,大規模になるにつれて別言語の採用を視野に入れていくことが重要」と述べ,すべてPHPで実装することは勧めず,分散処理に向いた言語を取り入れて実装する方法を勧めていました。

EventSourcingとCQRSの発展

近年の大規模データ処理向けアーキテクチャとして,⁠Lambdaアーキテクチャ」「Kappaアーキテクチャ」の具体例を挙げました。将来的に, 機械学習を導入していきたい場合にも柔軟に対応できます。

最後に竹澤さんは,⁠後からメンテナンスしやすいコードを書いていくために,実装だけではなくビジネスに関心を持つこと」⁠規模に応じて適材適所な技術を見極めていくこと」が大事だと結びました。

著者プロフィール

西祐太郎(にしゆうたろう)

株式会社アドベンチャーでエンジニアとして勤務。WordPressでPHPを触り始め,その後Laravel,独自フレームワークと複数のPHPプロジェクトを経験。最近は開発の傍ら,プロジェクトリーダーやエンジニア採用などにも携わる。レガシーコードのモダン化とマイクロサービスアーキテクチャにご執心。

Facebook:https://www.facebook.com/profile.php?id=100028405416669
GitHub:https://github.com/yuta-ron

バックナンバー

PHPカンファレンス2020 レポート