公開日:

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

Authors
  • author image
    Name
    代表取締役 宮永邦彦
    Twitter
    @miyanaga
  • 画像軽量化とWebフロントエンドのスピード改善の専門家です。Web系のIT技術大好き。

    このサイトではスピード改善のリアルや、日々の技術的な気づきを共有します。

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

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

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


全体像

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

Difyの全体像(v0.9.1)

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

AWS上では

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

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

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が次の役割を担っている。

  • リバースプロキシ 後述するコンテナapiwebへのリクエスト分配
  • セキュアゲートウェイ コンテナ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)に展開し、柔軟なスケーリングを可能にしたい。

apiwebについては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日時点)は安価に思えなくもない。