ideaman's Notes/AI/2024.10.08

DifyをAWSでガチ目に動かすには?〜理論編

DifyのDocker Compose構成をAWSに本番移行するアーキテクチャ設計を解説。ECSでコンテナを展開し、RDS/Aurora・ElastiCache・OpenSearch・S3・SESにマッピングする全体像と、Firecrawlの組み込み方・ECSのスケーリング戦略まで理論的に考察する。

writer K. Miyanagadate 2024.10.08 (Tue)read 5分cat AI, インフラ

DifyのソースコードにはDocker Composeプロジェクトが同梱されている。

それを利用すると自分専用のDify環境をサクッとセルフホストできるのだが、それを本番運用に利用するのは心許ない。

ではAWS上で、ガチ目のDifyスタックを展開するとしたらどうするか考えてみた。


全体像 ​

Difyのソースコードは本当にセルフホストに親切で、Docker Composeプロジェクトのコンポーネント図もある。

Difyの全体像(v0.9.1)

これに加えてストレージも抽象化されており、S3などを選択できる。

AWS上では ​

だいぶ複雑だが、ざっくりこんな感じにマッピングできるだろう。

Firecrawl ECSサービス

Dify ECSサービス

Webアクセス

メインDB

メインDB

Redis

Redis

ベクトルストア

ベクトルストア

ストレージ

ストレージ

メール送信

メール送信

SSL証明書

ルーティング

ルーティング

Webクローラー

Webクローラー

Redis

Redis

sandbox

api

worker

web

ssrf_proxy

api

worker

playwrite-service

RDS/Aurora

ElastiCache

OpenSearch/RDS

S3

SES

ALB / WAF

ACM

ユーザー

データベース・ストレージ ​

DB - RDS or Aurora ​

まずはデータベースだが、PostgreSQLを利用している。

したがってRDSやAuroraを利用する。環境変数DB_*が設定項目になっている。

Redis - ElastiCache ​

Redisも中核的な役割を担っている。特にCeleryと組み合わせた非同期タスクの管理と思われる。

最近はServerless版のRedisもあるというElastiCacheに置き換える。

環境変数REDIS_*が設定項目になっている。

ベクトルデータベース - OpenSearch or RDS ​

Difyが対応するベクトルデータベースにまとめたが、多数のベクトルデータベースに対応している。

AWSにはいくつかベクトルデータベースがあるが、現時点で相性が良さそうなのはOpenSearchかpgvectorだろう。

RDSのPostgreSQLがpgvectorもサポートしているので、メインデータベースに同居する方向もありだろう。

環境変数VECTOR_STOREと、OPENSEARCH_*またはPGVECTOR_*で設定する。

ストレージ - S3 ​

デフォルトではローカルストレージを利用するが、各種クラウドのオブジェクトストレージにも対応している。

環境変数STORAGE_*とS3_*で設定する。

AWSであればS3一択となる。

Web・メール ​

Webゲートウェイ - ALB + ACM ​

nginxが次の役割を担っている。

  • リバースプロキシ 後述するコンテナapiとwebへのリクエスト分配
  • セキュアゲートウェイ コンテナcertbotと連携したSSLへの対応

ここはALB + ACMに代替可能だろう。

WAFやCloudFrontも組み合わせるとさらによいかもしれない。

メール送信 - SES ​

ぱっと見、パスワードリマインダーなどでしか利用が見られないが、メールの設定も必要となる。

デフォルトではResendが選択されているが、AWSであればSESがよいだろう。

環境変数MAIL_*とSMTP_*で設定する。

コンピューティング ​

アプリケーション - ECS ​

Docker Composeのプロジェクトには主要なコンテナが3つと、補助的なコンテナが2つある。

  • 主要なコンテナ
    • api APIアクセスをホスト
    • worker 非同期タスクを処理と思われる
    • web Webインターフェースを提供
  • 補助的なコンテナ
    • sandbox ユーザー定義のコード実行と思われる
    • ssrf_proxy SSRF防止プロキシ

これらはECS(Fargate)に展開し、柔軟なスケーリングを可能にしたい。

apiとwebについてはALBに接続し、インターネットからの接続を確保する必要がある。

sandboxはおそらくだが、ワークフロー上でユーザーが定義した任意のコードブロックを実行する環境だ。

ssrf_proxyは名前のとおり、SSRF(Server Side Request Forgery)による攻撃を防止するためのHTTPプロキシと思われる。

実装までは詳しく見られていないが、コンテナやミドルウェアが相互作用するマイクロサービス的な構成であり、LLMモデルへのAPIアクセスもある。そのためHTTPプロキシを設け、安全な相互アクセスを担保しているのだろう。

その意味で、ssrf_proxyはサイドカー的に各サービスに1つずつ設けるのが良さそうだ。

どのようにECSを設計するか ​

実はDify本体はそこまで高負荷ではないように思う。負荷が高いのはLLMでありベクトルデータベースであり、Difyの役割はあくまでオーケストレーションだからだ。

したがって状況を見ながら以下のステップで、柔軟性と設計の複雑さのトレードオフを図りながら展開するのはどうだろうか。

  1. 1サービス 各コンテナをひとつのサービスに収め、その単位で冗長化・スケーリングする
  2. apiコンテナの分離 apiはユーザー数に弾力性があるので別サービス化する
  3. 1コンテナ1サービス 順当にコンテナごとにサービスを用意し、柔軟にスケーリングする

クローラー - Firecrawl ​

せっかくなのでDifyのお供にFirecrawlも用意したい。

Redis - Elasticache ​

Firecrawlもタスク管理にRedisを利用するようだ。

Elasticacheで用意する。

コンピューティング - ECS ​

次のコンポーネントがある(役割は推測)。

  • playwright-service Playwriteによるユーザーエージェント
  • api APIホスティング
  • worker 非同期タスクワーカー

Firecrawlはナレッジの取得・更新時にしか利用されない。したがってユーザーアクセスに応じてスケールする必要はない。

おそらくこの中ではplaywrite-serviceの負荷が最も高いだろう。しかしサービスごとにインスタンス数を調整できたからと言って、コストフィットに貢献するかというと微妙な気がする。

1サービスにコンテナを詰め込んで、Redis + bullによる、非同期タスクの残タスク数に応じてスケーリングする仕組みにしたい。

まとめ ​

このように安定的な条件でDifyをセルフホストするのは、楽しそうだが、保守も考えるとなかなか骨が折れる。

そう考えると、クラウド版DifyのTEAMプラン、年額$1590(2024年10月8日時点)は十分に検討に値する価格だ。