blog

DeNAのエンジニアが考えていることや、担当しているサービスについて情報発信しています

2024.10.22 技術記事

LLMアプリ開発プラットフォームOSS Difyのスケーラブル・高可用な運用

by Sota Oizumi

#dify #sai #generative-ai #llm #google-cloud #terraform

はじめに

はじめまして。24卒でデータ基盤部に配属されたMLエンジニアの大泉です。この記事では、DeNA の社内生成 AI サービス「SAI」のバックボーンとして用いられているオープンソースの LLM アプリ開発プラットフォームである Dify を DeNA でどのように運用しているかをお話しします。

Dify を本記事の構成で Google Cloud 上で立ち上げるためのコードを GitHub 上で OSS として公開しております。Google Cloud 環境をお持ちの方はぜひお試しください。

GitHub

背景

4月の共通研修を終えた新卒エンジニアの中で、有志で集まった8名の新卒が、 「DeNA が日本で一番生成 AI を活用している企業になる!」という Vision を掲げ、社内プロダクトを作る新卒エンジニア研修のプロダクトのひとつとして社内生成 AI サービス SAI の開発に取り組みました。私はその中で、バックエンド開発と、 Google Cloud を用いたインフラの設計と運用を担当しており、注目度の高いオープンソースの LLM アプリ開発プラットフォームである Dify をクラウド上で実運用するという貴重な経験をすることができました。

本記事では、アーキテクチャに加え、運用する上で見えてきた勘所や、低コストかつスケーラブル・高可用に運用するための工夫などをお話しします。

SAI

SAIは基本的なLLMチャットサービスの機能に加え、各チームのスライドやドキュメントをシェアしてRAGが可能なナレッジ機能、よく使われるユースケースをテンプレート化したアプリ機能をサポートし、画像やPDFの入力も可能となっています。

技術スタック

  • Google Cloud
    • Cloud Run (Sidecars)
    • Cloud SQL
    • Cloud Storage
    • Memorystore
  • GitHub Actions (CI/CD)
  • Terraform
  • Azure OpenAI API

今回の記事では触れませんが Next.js と Go を用いて SAI は実装されています。

Difyとは

Dify は、オープンソースで開発が進められている LLM アプリ開発プラットフォームです。 Azure OpenAI API などを用いて LLM に接続することで、基本的な対話に加えて、プロンプトテンプレートを設定したアプリや、 Retrieval Augmented Generation (RAG) による文章検索を用いた対話、複雑なワークフロー、エージェント機能などを作成・利用可能です。特筆すべき点はそれらを API 化でき、他のサービスに組み込むことが容易である点です。

Dify Cover

Difyのクラウドアーキテクチャ設計

私たちは全社で社員が利用する生成 AI サービスとして Dify をそのまま採用はしていません。 Dify の UI はあくまでも生成 AI にある程度詳しく、自身でカスタマイズ可能な開発者向けのものであると考えるからです。そのため、 SAI のフロントエンドは一から作成しています。

SAI のほとんどの機能は、新卒エンジニア研修の5月頭の立ち上げから7月末の成果発表までの3ヶ月間で開発されました。私たちが限られた期間内で開発スピードを上げられた大きな要因として、早い段階で Dify の導入を決めたことがあります。

Dify は LLM を用いた基本的な機能の多くを API として発行可能であり、 SAI では Dify の API を叩くことでアプリやナレッジを作成しています。 SAI の安定稼働には Dify の安定稼働が欠かせないという状況で、自分は Dify の運用を段階的に強化していきました。

Dify のアプリケーション全体像は公式リポジトリにある以下の図でシンプルに表現されています。各コンテナーは以下の役割を持ちます。

Dify Docker 引用: https://github.com/langgenius/dify/blob/main/docker/docker-compose.png

  • web
    • アプリケーションのフロントエンドサービス
  • api
    • アプリケーションのバックエンドサービス。 LLM へのリクエストや、非同期タスクを redis を介して worker に割り振る、コード実行を含むワークフローで sandbox を呼び出すなど多くの役割を持つ
  • nginx
    • web と api にリクエストを振り分けるリバースプロキシ
  • worker
    • redis を介して非同期タスクを受け取り、タスク実行後、 db や vector db にデータを保存する
  • redis
    • 非同期タスクのキューと、キャッシュの役割
  • db
    • アプリケーションのデータベースの役割
  • weaviate (vector db)
    • RAG で用いる文書埋め込みを保存する役割、 Dify は他の多くの vector db にも対応している
  • sandbox
    • 図にはないが、 Python や JavaScript のコード実行環境

公式リポジトリのデフォルトでは、ローカルマシンや単一の VM ですべての Docker コンテナーを立ち上げる設定となっているため、スケーラビリティ・可用性のどちらの観点でも実運用に耐える構成ではなく、社内で Dify を SAI のバックボーンとしてプロダクション運用するためには、アーキテクチャの再設計が必要でした。

データの永続化

SAI のバックエンドでは Dify のデータベースを直接呼ぶ処理も多く、 Dify のデータベースを安全に永続化することは最優先の課題でした。また、デフォルトの設定ではモデル情報を管理する秘密鍵やアップロードされた画像を保存するストレージがローカルディレクトリになっており、ストレージと DB をセットで安全に管理することが必要でした。

ストレージは Cloud Storage 一択なのですが、 DB には考慮すべき点があります。 Dify の DB は RDB (Postgres SQL) であり、 Google Cloud で候補に上がるのは Cloud SQL と Alloy DB です。ここではコスト重視で Cloud SQL を選択しましたが、今後のパフォーマンス次第では AlloyDB への移行を検討予定です。

また、 Dify では RAG に用いるベクトル DB が必要なので、その選定も必要です。 Dify は多くのベクトル DB をサポートしていますが、ここもコスト観点で Postgres SQL の拡張である pgvector を選択し、 Cloud SQL で一括で管理をしています。

各コンテナーのスケーラビリティ

コンテナベースで構成される Dify は適切なコンテナオーケストレーションによってスケーラビリティを向上させることができます。 Kubernetes を用いてフルマネージドに管理することもできますが、常に SAI の運用チームに Kubernetes に精通したエンジニアがいるとは限らないため、継続的な運用の観点から、サーバーレスで運用コストが低い Cloud Run を選択しました。

DB 、ベクトル DB 、ストレージを除くと、 Dify を稼働させるのに必要な残りのコンテナーは nginx, web, api, worker, redis, sandbox となります。

nginxはフロントエンドのwebとバックエンドのapiのコンテナーへリクエストを捌くリバースプロキシとして機能し、 worker は redis から文書埋め込み生成などの匿名非同期タスクのキューを受け取り、 DB やベクトル DB へその結果を保存します。

Cloud Run Sidecars ですべてのコンテナーをまとめて扱う、もしくは Compute EngineのManaged Instance Group として扱い、スケールさせるのがもっとも楽で作業の少ないスケーラブルなデプロイ方法ですが、以下の観点から Cloud Run Service の分離と Redis の分離を行いました。

Redis に入るデータは、一見永続化が必要ではないため、コンテナーでの運用を考えることもできます。しかし、タスクキューとしての機能以外に、ストレージのデータをキャッシュして一定時間保持するなどの機能も備えており、コンテナーで運用すると、スケールした際にそれらへの各ユーザーからのアクセス性能は低下します。このため、 Memorystore の Redis インスタンスとして分離することにしました。

Dify は1 Pod での稼働時、とくに巨大な文書埋め込み生成をしている最中にパフォーマンスが悪化することが実験的にわかっていました。このときは worker コンテナーで大量の処理を捌いており、 worker コンテナーが単独でスケールできる状態が理想です。また、 sandbox コンテナーは Python や JavaScript の実行環境が入っており、 workflow でスクリプト実行をする際に呼ばれます。現状のSAIでは、 workflow でのスクリプト実行を伴うユースケースは少ないため、単独でゼロスケールすることが望ましいです。

以上の観点から、nginx, web, api を1 Pod に入れた Sidecars と、 worker と sandbox コンテナーをそれぞれ単独で持つ Cloud Run サービスの3つにアプリケーションを分離しました。

SAI というサービスのスケーラビリティ

SAI は現在全社運用が行われていますが、事業部ごとにリソースを分離したいといった要望が今後出てくる可能性があります。 SAI の運用可能性を向上させるには環境の再現性が重要になるため、 IaC でのリソース管理ができるように Terraform を導入しました。

以上の検討の結果、現在の SAI は以下のようなアーキテクチャで運用され、 Terraform でリソース管理を行なっています。

アーキテクチャ図

おわりに

本記事ではオープンソースの LLM アプリ開発プラットフォームである Dify を Google Cloud 上に構築し、 スケーラブル・高可用に実際に運用するための検討とアーキテクチャ設計を紹介しました。

私は、新卒エンジニア研修終了後も継続して SAI の運用・開発に取り組んでいます。私たちは「 DeNA が日本で一番生成 AI を活用している企業になる!」という Vision に向かい、新卒一年目から全社に大きな影響を与えられる本プロジェクトに引き続き尽力していきたいと考えています。今後、 SAI に関する発信も積極的に行っていきますので、ぜひご覧ください。

最後まで読んでいただき、ありがとうございます!
この記事をシェアしていただける方はこちらからお願いします。

recruit

DeNAでは、失敗を恐れず常に挑戦し続けるエンジニアを募集しています。