top of page

検索結果

空の検索で52件の結果が見つかりました。

  • Google CloudでLangfuse v3の構築手順(推奨設定/GKE)

    はじめに GAOの遠矢です。普段はLLMアプリケーションの開発を主にしております。 このガイドでは、LangfuseというLLMOpsの基盤となるツールを Google Cloud 上で セルフホスティングする手順を紹介します。 Google Cloud 上のKubernetes (GKE) でLangfuse v3を安全かつ推奨される構成でデプロイする手順を解説します。 Langfuse v2からv3への主な変更点 V3では以下のような重要な改善が行われています アーキテクチャの最適化 キューに入れられたトレースの取り込み トレースはバッチ処理され、S3に直接保存 APIキーのキャッシュング Redisを活用した高速なAPI認証 プロンプトのキャッシュ(SDK・API) リードスルーキャッシュによる応答時間の改善 OLAPデータベース(ClickHouse)の採用 分析処理の高速化 信頼性の向上 S3/Blobストレージを活用したイベントの回復可能性 バックグラウンド移行のサポート マルチモーダルトレースのサポート コンポーネント構成 アプリケーションコンテナ(Web・Worker) ストレージコンポーネント(Postgres, ClickHouse, Redis/Valkey, S3/Blob) オプショナルなLLM API/ゲートウェイ 注記: この手順はLangfuse v3のデプロイに焦点を当てています。v2のデプロイについては、v2のドキュメントを参照してください。 注意事項: 本番環境で使用する前に、セキュリティとパフォーマンスを考慮して構成を見直すことを強く推奨します。 システム要件と構成 アーキテクチャ図 推奨構成 GKE(コンテナアプリケーション) 2つのCPUと4 GB の RAM 高可用性を実現するには、Langfuse Web コンテナのインスタンスを少なくとも 2 つ Cloud SQL(PostgreSQL) 特に指定なし Redis 1GB以上 ClickHouse: 3レプリカ構成 Cloud Storage(S3) 特に指定なし 注意事項: 今回はClickhouseをGKE上に構築する場合の手順のため、GKEノード(GCE)のマシンスペックが低いとClickhouseを構築できない可能性があるためご注意ください。 構築手順 本手順では、主にターミナルを利用して構築を行います。 構築準備 まず、Google Cloudプロジェクトの設定から始めます。 以下のコマンドでプロジェクトを設定します。 gcloud config set project [YOUR_PROJECT_ID] ネットワークインフラの構築 セキュアな環境を構築するため、専用のVPCネットワークとサブネットを作成します。 これにより、リソース間の安全な通信が可能になります。 # VPCネットワークの作成 gcloud compute networks create langfuse-network --subnet-mode=custom # サブネットの作成 gcloud compute networks subnets create langfuse-subnet \ --network=langfuse-network \ --region=asia-northeast1 \ --range=10.0.0.0/20 # VPCピアリングの設定 gcloud compute addresses create google-managed-services-range \ --global \ --purpose=VPC_PEERING \ --prefix-length=16 \ --network=langfuse-network gcloud services vpc-peerings connect \ --service=servicenetworking.googleapis.com \ --ranges=google-managed-services-range \ --network=langfuse-network # 内部通信用のファイアウォールルール gcloud compute firewall-rules create langfuse-allow-internal \ --network=langfuse-network \ --allow=tcp,udp,icmp \ --source-ranges=10.0.0.0/20 Kubernetesクラスターの構築 GKEクラスターを作成します。 本番環境では可用性を考慮して、複数のノードを配置することを推奨します。 gcloud container clusters create langfuse-cluster \ --network=langfuse-network \ --subnetwork=langfuse-subnet \ --region=asia-northeast1 \ --num-nodes=1~2 \ --machine-type=e2-standard-2 \ --enable-ip-alias # 認証設定 gcloud container clusters get-credentials langfuse-cluster --region=asia-northeast1 PostgreSQLの構築 PostgreSQLデータベースをCloud SQLで構築します。本番環境では十分なリソースと冗長性を確保することが重要です。 パスワード等は本来であれば、シークレット等で管理してください。 # PostgreSQL作成 gcloud sql instances create langfuse-postgres \ --database-version=POSTGRES_15 \ --tier=db-g1-small \ --region=asia-northeast1 \ --root-password=[YOUR_ROOT_PASSWORD] \ # 今回設定する箇所は特にないので任意で --database-flags=max_connections=100 \ --network=langfuse-network \ --no-assign-ip # データベース作成 gcloud sql databases create langfuse --instance=langfuse-postgres # ユーザの作成 gcloud sql users create langfuse --instance=langfuse-postgres --password=langfuse1234 また、プライベートIPはこの後Langfuse側で設定する必要があるのでメモしておいてください。 # プライベートIPの取得 gcloud sql instances describe langfuse-postgres \ --format="get(ipAddresses[0].ipAddress) Redisの構築 Redisをマネージドサービスである、Memorystore for Redisを利用して構築を行います。 しかし、コスト等の兼ね合いがある場合マネージドサービスを利用せずコンテナ上で構築することも可能です。 # Redisインスタンスの作成 gcloud redis instances create langfuse-redis \ --size=1 \ --region=asia-northeast1 \ --redis-version=redis_7_0 \ --network=langfuse-network \ --enable-auth \ --redis-config maxmemory-policy=noeviction Redisでは、認証用の文字列(REDIS_AUTH)、ホスト(REDIS_HOST)、ポート(REDIS_PORT)をこの後Langfuse側で設定する必要があるので、メモしておいてください # Redis認証文字列の取得 gcloud redis instances get-auth-string langfuse-redis --region=asia-northeast1 # Redisホストの取得 gcloud redis instances describe langfuse-redis \ --region=asia-northeast1 \ --format="get(host)" # Redisポートの取得 gcloud redis instances describe langfuse-redis \ --region=asia-northeast1 \ --format="get(port)" Cloud Storage (S3) の 構築 # バケットの作成 gcloud storage buckets create gs://$BUCKET_NAME \ --location=asia-northeast1 HMAC キーの作成手順 Cloud Storage > 設定 > 相互運用性タブに移動 サービスアカウント or ユーザーアカウントを選択しHMACキーを作成します。 アクセスキーとシークレットを安全に保存(これらは後でLangfuseの設定で使用) ClickHouseの 構築 今回はGKE上にClickHouseをデプロイする手法で行います。 # Helmのインストール curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash # Helmリポジトリの追加 helm repo add bitnami https://charts.bitnami.com/bitnami helm repo update 次に以下のclickhouse-values.yamlを作成します。 shards: 1 replicaCount: 3 auth: username: default password: changeme resourcesPreset: large persistence: size: 100Gi shards: シャード数(この場合は1) replicaCount: レプリカ数(本番では3以上推奨) YAML作成後、Clickhouseのデプロイを行います。 helm install clickhouse bitnami/clickhouse \ -f clickhouse-values.yaml \ --namespace default その後以下のコマンドで、正常に起動することを確認します。 # Podの状態確認 kubectl get pods | grep clickhouse # サービスの確認 kubectl get svc -l app.kubernetes.io/name=clickhouse # ログの確認 kubectl logs clickhouse-0 # デプロイされたリソース一覧の確認 kubectl get all -l app.kubernetes.io/name=clickhouse . Kubernetes(helm)でのLangfuseのデプロイ # Langfuseリポジトリのクローン git clone https://github.com/langfuse/langfuse-k8s.git cd langfuse-k8s/charts/langfuse git checkout lfe-1348-v3-chart リポジトリをクローン後、以下の内容でlangfuse-values.yamlを作成してください。 また、その際に変数等は適宜変更してください。 langfuse-values.yaml replicaCount: 1 image: repository: langfuse/langfuse pullPolicy: Always tag: 3 imagePullSecrets: [] nameOverride: "" fullnameOverride: "" langfuse: port: 3000 nodeEnv: development next: healthcheckBasePath: "" nextauth: url: "http://localhost:3000" secret: "openssl rand -base64 32で作成" salt: "openssl rand -base64 32で作成" telemetryEnabled: true nextPublicSignUpDisabled: false enableExperimentalFeatures: true extraContainers: [] extraVolumes: [] extraInitContainers: [] extraVolumeMounts: [] web: replicas: 1 worker: replicas: 1 additionalEnv: - name: "LANGFUSE_LOG_FORMAT" value: "json" # Experimental v3 feature flags - name: "LANGFUSE_ENABLE_EXPERIMENTAL_FEATURES" value: "true" - name: "ENCRYPTION_KEY" value: "openssl rand -hex 32で作成" - name: "LANGFUSE_ASYNC_INGESTION_PROCESSING" value: "true" - name: "LANGFUSE_ASYNC_CLICKHOUSE_INGESTION_PROCESSING" value: "true" - name: "LANGFUSE_READ_DASHBOARDS_FROM_CLICKHOUSE" value: "true" - name: "LANGFUSE_READ_FROM_POSTGRES_ONLY" value: "false" - name: "LANGFUSE_RETURN_FROM_CLICKHOUSE" value: "true" # Database connections - name: DATABASE_URL value: "postgresql://langfuse:langfuse1234@[DB_IP]:5432/langfuse" - name: "REDIS_HOST" value: "[REDIS_HOST]" - name: "REDIS_PORT" value: "[REDIS_PORT]" - name: "REDIS_AUTH" value: "[REDIS_AUTH]" - name: "CLICKHOUSE_URL" value: "http://clickhouse:8123" - name: "CLICKHOUSE_MIGRATION_URL" value: "clickhouse://clickhouse:9000" - name: "CLICKHOUSE_USER" value: "default" - name: "CLICKHOUSE_PASSWORD" value: "changeme" - name: CLICKHOUSE_CLUSTER_ENABLED value: "false" # Cloud Storage settings - name: "LANGFUSE_S3_EVENT_UPLOAD_ENABLED" value: "true" - name: "LANGFUSE_S3_EVENT_UPLOAD_BUCKET" value: "[BUCKET_NAME]" - name: "LANGFUSE_S3_EVENT_UPLOAD_REGION" value: "auto" - name: "LANGFUSE_S3_EVENT_UPLOAD_ACCESS_KEY_ID" value: "[HMAC_ACCESS_KEY]" - name: "LANGFUSE_S3_EVENT_UPLOAD_SECRET_ACCESS_KEY" value: "[HMAC_SECRET_ACCESS_KEY]" - name: "LANGFUSE_S3_EVENT_UPLOAD_ENDPOINT" value: "https://storage.googleapis.com" - name: "LANGFUSE_S3_EVENT_UPLOAD_FORCE_PATH_STYLE" value: "true" - name: "LANGFUSE_S3_EVENT_UPLOAD_PREFIX" value: "events/" serviceAccount: create: true annotations: {} name: "" podAnnotations: {} podSecurityContext: {} securityContext: {} service: enabled: true type: NodePort port: 3000 targetPort: 3000 ingress: enabled: false # ローカル環境では無効化 resources: {} autoscaling: enabled: false nodeSelector: {} tolerations: [] affinity: {} postgresql: deploy: false # 外部PostgreSQLを使用 auth: username: "langfuse" password: "langfuse1234" database: "langfuse" clickhouse: deploy: false # 外部Clickhouseを使用 valkey: deploy: false minio: deploy: false # 外部ストレージを使用 extraManifests: [] 主に変更する箇所は以下です。 パラメータ 作成方法/説明 nextauth.secret openssl rand -base64 32で作成 salt openssl rand -base64 32で作成 ENCRYPTION_KEY openssl rand -hex 32で作成 [DB_IP] PostgreSQLデータベースのIPアドレス [REDIS_HOST] Redisサーバーのホスト名 [REDIS_PORT] Redisサーバーのポート番号 [REDIS_AUTH] Redisの認証パスワード [BUCKET_NAME] Cloud Storageのバケット名 [HMAC_ACCESS_KEY] Cloud StorageアクセスのHMACアクセスキー [HMAC_SECRET_ACCESS_KEY] Cloud StorageアクセスのHMACシークレットキー LANGFUSE_EE_LICENSE_KEY Langfuse Enterprise プランのライセンスキー(オプション) ない場合は特に追加の必要なし 以下のコマンドでhelmでLangfuseをlangfuse-values.yamlに沿って作成します。 # Langfuseのデプロイ helm dependency update helm install langfuse . -f langfuse-values.yaml デプロイができたら、以下のコマンドでログとポッドの状態を確認します。 # podの状態確認 kubectl get pods -l app.kubernetes.io/instance=langfuse # ログの確認 kubectl logs -f deployment/langfuse-web kubectl logs -f deployment/langfuse-worker どちらとも起動することを確認したら、ポートフォワーディングをして、localhost:3000でLangfuseのログイン画面が出力されることを確認します。 ポートフォワーディングのコマンド # ポートフォワーディングの設定 kubectl port-forward svc/langfuse-web 3000:3000 その後、トレースなどを行い動作に問題がないか確認したらデプロイ完了です。 応用編 (外部IP付与 GCLB) GoogleのGlobal Load Balancerを利用して、HTTPS通信を可能にします。 まずは、Google マネージドのSSL証明書を作成します。 以下のmanaged-cert.yamlを作成します。 apiVersion: networking.gke.io/v1 kind: ManagedCertificate metadata: name: langfuse-cert spec: domains: - YOUR_DOMAIN # 実際のドメインに変更 その後マネージド証明書の適用を行います。 # マネージド証明書の適用 kubectl apply -f managed-cert.yaml 次に外部IPアドレスを予約しておきます # 静的外部IPアドレスの予約 gcloud compute addresses create langfuse-ip --global ここで予約したIPアドレスを DNS の A レコードとして設定してください。 次に、langfuse-values.yamlを更新します。 主な変更点としては環境変数の更新・追加とIngressの追加を行います。 # 主な更新箇所のみ抜粋 langfuse: nextauth: url: "https://YOUR_DOMAIN" # 外部アクセス用のドメインに更新 additionalEnv: - name: "LANGFUSE_CSP_ENFORCE_HTTPS" value: "true" # HTTPSを強制的に使用 # 新規追加のIngress設定 ingress: enabled: true annotations: kubernetes.io/ingress.global-static-ip-name: langfuse-ip networking.gke.io/managed-certificates: langfuse-cert kubernetes.io/ingress.class: "gce" kubernetes.io/ingress.allow-http: "false" hosts: - host: YOUR_DOMAIN paths: - path: / pathType: Prefix Langfuseの更新 # Langfuseの更新 helm upgrade langfuse . -f langfuse-values.yaml 確認コマンド # 証明書の状態確認 kubectl describe managedcertificate # AtiveになったらOK # ロードバランサーの確認 kubectl get ingress # HOST名が設定したドメイン名、アドレスが langfuse-ipの値になってたらOK # GUIでGCLBが作成できるかどうかも確認 以上の設定が完了したら、https://YOUR_DOMAINにアクセスして、LangfuseUIにログインできたら成功です。 トレースなどができるか確認してみてください。 できない場合は helm unistallなどをしてください また、以下の画面はenterpriseEditionのライセンスキーの有効化を行なっているため、左上がv3.2.0 EEとなっています。 EEとなっており、Playground等の機能も画面に出力されている状態になっております。 クリーンアップ 必要に応じて、以下の手順でリソースを削除します # Langfuseの削除 helm uninstall langfuse helm uninstall clickhouse # GKEクラスターの削除 gcloud container clusters delete langfuse-cluster \ --region=asia-northeast1 \ --async # Cloud SQLインスタンスの削除 gcloud sql instances delete langfuse-postgres # Redisインスタンスの削除 gcloud redis instances delete langfuse-redis \ --region=asia-northeast1 # Cloud Storageバケットの削除 gsutil rm -r gs://$BUCKET_NAME # ファイアウォールルールの削除 gcloud compute firewall-rules delete langfuse-allow-internal # VPCピアリング接続の削除 gcloud services vpc-peerings disconnect \ --service=servicenetworking.googleapis.com \ --network=langfuse-network # 予約したIPレンジの削除 gcloud compute addresses delete google-managed-services-range \ --global # サブネットの削除 gcloud compute networks subnets delete langfuse-subnet \ --region=asia-northeast1 # VPCネットワークの削除 gcloud compute networks delete langfuse-network トラブルシューティング Redis接続エラーについて "Redis connection error: ERR unknown command 'client'"という警告は、Google CloudのMemoryStoreの制限によるものです。 この警告は表示されても、Redisとの接続自体は正常に行われています。 証明書のプロビジョニング マネージド証明書のプロビジョニングには数分から数十分かかる場合があります。 kubectl describe managedcertificate で状態を確認できます。 注意事項 すべてのパスワードとシークレットは適切に管理してください。 本番環境ではより強力なセキュリティ設定と、より多くのリソースを割り当てることを検討してください。 環境変数の値は実際の値に置き換えてください。 Langfuseの公式ドキュメントも参照し、最新の情報を確認してください。 最後に このガイドが、Google Cloud上でのLangfuse v3の安全なデプロイに役立つことを願っています。 また企業向けサポートとして、 ガオ株式会社 を通じてLangfuse ProおよびEnterpriseプランを日本円で購入し、日本語でサポートを受けることが可能です。 ご興味ある方は、contact@gao-ai.comまでご連絡ください。

  • Langfuse の Self-hosted インストールのパターンと解説

    Langfuse v3 になって、「Self-hosting は良さそうだけど、結構インストール面倒なんでしょう?」という声をよく聞きます。もちろん複雑な構成を作ることも可能ではありますが、一方でLangfuse には簡単なものもふくめて幾つかのインストール方法が用意されており、利用用途や条件に合わせた選択が可能です。 この記事では、各インストールオプションおよび公式ページのリンク、使い分けについて解説します。まず簡単なケースごとのフローチャートは以下のような形になります。当てはまりそうなオプションを中心にぜひご確認ください。 インストールオプションのパターン 実際のインストールコマンドは、各オプションのリンクから公式をご参照ください。 Langfuse のインストールオプション 1. ローカルインストール Docker と docker compose を利用したローカル環境でのセットアップ方法です。 特筆すべきものはなく、非常にシンプルな手順で利用可能なもので、個人利用や簡単なテスト環境向きです。Mac やWindows でDocker をインストールしたら、docker compose upコマンド一つで起動します。特に悩むところもないです。 使用するケース 手元のアプリ開発の可視化やテスト目的で手軽にLangfuse を試してみたい このLangfuse を本番環境に使う予定はない 2. Docker Composeを使ったインストール 公式ドキュメントとしては区別されていますが、1と基本的には一緒です。ただしAWS/Google Cloud/Azure などで仮想マシン (EC2 など) をつかうことが想定されており、公式ページにはdockerパッケージの導入手順などについても記載してあります 大規模なトラフィックがなく、可用性が許容されるのであれば本番環境にも適用可能です。また一部にマネージドサービスを使うといった方法で可用性も向上できます。 使用するケース 小〜中規模のチームでの本番やステージング環境を構築したい Trace などの欠損リスクがある程度は許容できる VM の構築や管理ができる人がいる インフラ構築をシンプルに管理したい 必要なリソース 4Core 16GiB メモリなどが推奨 (それ以下でも立ち上がりはする) 100GiB ストレージ, 外部から接続できるNW設定 (Public IPなど) 本番利用に向けて、可用性を高める応用例 Object storage はVMではなくS3 / blob /GCS などに変更 プロンプト取得の可用性を高めるため、Web server のコンテナとPostgreSQL だけをマネージドサービス利用する またdocker-compose.yml を修正することで、ディスクやデータベースの接続など各種設定を変更することもできます。langfuse ディレクトリ直下にありますので必要に応じてご確認ください。 3. Dockerを使ったインストール Docker composeではなくDocker コンテナを使ってカスタマイズした構成を作るパターンです。利点は複数のコンポーネントで構成されているLangfuse をクラウドサービス側のマネージドサービスを利用して、高い可用性を保つことができることなどにあります。 PostgreSQL, Redis, Clickhouse をマネージドサービスで起動しておいて、docker コマンドの引数として指定しましょう。 使用するケース Kubernetes は使いたくないが、VM単体よりも可用性を高く保ちたい 一方でクラウドサービスのマネージドサービスを使って、手はかけたくない クラウドサービスのネットワークなどを構築・管理できる 改善したい可用性と構成例 プロンプト取得における可用性を向上させたい Web server のコンテナをECS やCloudRun で稼働 PostgreSQL をAurora や CloudSQL で稼働 Traceデータの可用性を高めたい Object Strage にS3, GCS などを活用 Clickhouse としてClickhouse Cloud などを使う、あるいはECSや GCE container optimized OS 上で動かす Async worker のコンテナをECS やCloud Run などで稼働 RedisにElasticashe や Memorystore などを活用する 最近ではTeraform, CDK, あるいはマニュアル などで比較的簡単 (あるいはほぼ自動) で構築できるようにリソースを公開しているものもあります。ご自身のケースに当てはまるかもご確認ください。 参考リンク AWS tuboneさん ( Blog ) リソース https://github.com/tubone24/langfuse-v3-terraform   mazyu36さん ( Blog ) リソース https://github.com/mazyu36/langfuse-with-aws-cdk Google Cloud クラウドエース株式会社 高木さん ( Blog ) * マニュアルでのインストール手順 4. Kubernetes Helmを使ったインストール Kubernetes クラスタにHelm を使ってLangfuseを導入する方法です。可用性やスケーラビリティを確保しつつ、運用をKubernetesに任せたいケースに利用可能です。 使用するケース 比較的大規模なチームやエンタープライズ環境 高い可用性とスケーラビリティを求める Kubernetesクラスタを運用することができる なお、Langfuse 公式で Helm Chart がリリースされており、特に理由がなければこれを使うことが最初の入口として良いと思います。その上で、さらに可用性を向上させたい場合には以下のオプションなどが有益です。 Traceを格納するClickhouse自体の可用性や保守性などを高めたい コストや諸条件が合えばClickhouse Cloud など利用を検討する プロンプト取得における可用性を向上させたい PostgreSQL をAurora や CloudSQL などで稼働 以下の記事では、Langfuse をKubernetes + マネージドサービスの構成でデプロイをした構成について言及しています。 参考リンク Google Cloud GAO 遠矢 ( Blog ) 本記事がインストール方法の決定における参考になれば幸いです。 もし企業における導入サポートなどが必要でしたら、 お気軽にお問い合わせください。 https://www.gao-ai.com/contact

  • [前半] ゼロからスケールへ:Langfuseのインフラストラクチャの進化 (和訳)

    このBlog記事はガオ株式会社による Langfuse GmbH "From Zero to Scale: Langfuse's Infrastructure Evolution" の日本語訳 前半となります。原文は こちら をご確認ください。 ゼロからスケールへ:Langfuseの インフラストラクチャの進化 Langfuseのインフラストラクチャをシンプルなプロトタイプからスケーラブルな Observability プラットフォームへと進化させた過程を詳しくご紹介します。 Steffen Schmitz Max Deichmann オープンソースのLLM Observerbility プラットフォームであるLangfuseは、Y Combinator 2023年Winter バッチから誕生しました。 私たちは、多くのLLMアプリケーションを自分たちで構築し、デモから本番環境への移行が難しいことを実感した後、バッチメイトの数名と緊密に協力し、LLM可視化プラットフォームのv0を迅速に開発しました。 当初は、いくつかのコア機能に的を絞りました。SDKは非同期、Langfuseはトレースをベースとし、すべてのコンポーネントはオープンソースで簡単にセルフホスティングできるものでした。最初のバージョンは、NextJs、Vercel、Postgresで書かれていました。私たちは、この実験が1分あたり数万件のイベントを処理するまでに急速に進化するとは、夢にも思っていませんでした。 Langfuseがすべてのユーザーに対してスケーリングできることを確実にするという点において、私たちの最近のV3リリースは重要なマイルストーンとなりました。私たちはすでにLangfuse Cloudでこれらの変更の多くを試験的に導入しており、v3リリースではオンライン評価、非同期/キューイング取り込み、キャッシュされたプロンプトなど、セルフホスティングユーザーにもそれらを利用できるようにしました。 本記事では、Langfuseの開発中に直面したスケーリングの課題と、私たちの「仮説 - 実験 - フィードバック」のループがLangfuse v3の開発にどのように役立ったかについてご説明します。もし、私たちと一緒に同様の課題の解決に取り組みたいとお考えであれば、ベルリンで人材を募集しています! Where it all started 当初の私たちのアーキテクチャは、単一のコンテナとPostgresデータベースであり、運用とセルフホスティングは非常にシンプルでしたが、スケーリングが非常に困難な構成でした。 私たちは、アーキテクチャを再考せざるを得ないような、いくつかの重要な課題に直面しました。最も重要な課題は次の通りです。 課題 1: 耐障害性が高く、高スループットを取り込めるパイプラインの構築 目標: Ingestion API は、予測不可能な負荷パターン下でも、大量のイベントを受け入れ、一貫して低レイテンシを維持する Langfuse の可視化プラットフォームの中核は、SDK および API による効率的なイベントデータ収集に依存しています。 これらの SDK は、ユーザーのアプリケーションへのパフォーマンスへの影響を最小限に抑えるように設計されていますが、取り込みサーバーコンポーネントは、規模を拡大するにつれて、重大な課題に直面しました。 当初の課題: 2023年夏には、急激なトラフィックパターンにより、取り込みAPIのレスポンスタイムが最大50秒まで急上昇しました。 重要な要件: Ingestion API は、SDKからのイベントの円滑なフラッシングを確保するために、常に低レイテンシを維持する必要があります。そうでないと、ユーザーのアプリケーションに悪影響が及ぶ可能性があります。 課題は、大量のデータを処理することだけではありませんでした。予測不可能な負荷パターン下で信頼性を維持しながら、ユーザーのアプリケーションパフォーマンスへの影響を最小限に抑えることでした。この技術的なハードルは、トラフィックの急増をより適切に処理するための取り込みアーキテクチャを再考することを迫る、当社にとって最初の大きなスケーリングの課題となりました。 課題 2:実稼働時のワークロードに合わせたプロンプトの最適化 目標: Prompt API は常に高い可用性とパフォーマンスを維持する Langfuse の重要な機能のひとつがプロンプト管理システムであり、ユーザーは UI を通じてプロンプトを定義し、SDK を通じて取得することができます。これにより、プロンプトを変更するためにアプリケーションを再デプロイする必要がなくなります。 Trace は非同期かつノンブロッキングですが、プロンプトはLLMアプリケーションのクリティカルパスとなります。このため、一見単純な機能が複雑なパフォーマンス上の課題となりました。取り込みが集中する時間帯には、プロンプト取得の p95 レイテンシが7秒にまで上昇しました。この状況には、他の操作によるシステム負荷が重い場合でも、一貫した低レイテンシのパフォーマンスを維持できるアーキテクチャ上のソリューションが必要でした。 課題 3:高速な分析読み取り(ダッシュボード、テーブルフィルター) 目標: 大規模な観測データにも対応するダッシュボードとテーブルフィルター 当初のデータベースとしてPostgresを選択したことは、初期の段階ではうまくいきましたが、当社の最大顧客がシステムを通じてより多くのObserverbility データを送信するようになると、重大なパフォーマンスのボトルネックにぶつかりました。クエリを最適化しても、当社のダッシュボードとテーブルフィルターの操作は、企業ユーザーにとっては遅すぎました。LLMの分析データは多くの場合、大きなblobで構成されており、何百万行ものデータをスキャンする際には、行指向のストレージがディスク上で重荷となっていました。皮肉なことに、当社の分析機能を最も必要としているお客様が、最もパフォーマンスの低下を経験していました。この成長に伴う問題は、当初のアーキテクチャが迅速な開発には最適であったものの、企業規模の分析作業負荷に対応するには根本的な再考が必要であることを示していました。 課題4:簡単なセルフホスティング 目標: 簡単にセルフホスティングできるだけでなく、運用上の労力をほとんど必要とせずに拡張できること Langfuseをオープンソースプロジェクトとして構築することは、意図的な選択でした。私たちのビジョンはシンプルでした。誰もが簡単なdocker-compose upでLangfuseを利用し始めるべきであると同時に、Langfuseは同時に、毎分何百ものユーザーと何千ものLLMのやり取りがあるエンタープライズ規模の展開にも対応できなければなりません。このアプローチは、私たち自身が開発者として好むものを反映しています。私たちは、評価や展開が容易なソリューションを重視しています。 しかし、実稼働環境に耐えうるオープンソースのObserverbility プラットフォームを構築するには、特有の課題があります。 汎用性:当社のインフラは、開発者のLaptopからさまざまなクラウド事業者へのデプロイまで、多様な環境でシームレスに動作する必要があります。 オープンソースへの依存:当社はオープンソースコンポーネントのみを使用することで、無制限のセルフホスティング機能を確保することを約束しています。 ゼロタッチ操作:企業ユーザーは、メンテナンスとアップグレードの自動化を必要としています。手動操作ではエラーが発生しやすく、拡張性にも欠けます。 このシンプルさとエンタープライズ対応のバランスが、当社のアーキテクチャ上の決定を形作り、アクセスしやすく拡張性のあるソリューションの作成を後押ししました。 新しい構成要素 これらの課題に対処するために、私たちはスタックに複数のビルディングブロックを追加しました。本記事では、私たちがどのようにスタックを繰り返し改良していったかをご紹介します。 ビルディングブロック1:取り込みデータの非同期処理 同期処理から非同期処理へ 私たちは当初、APIコールごとに多数のイベントを受信し、それらを繰り返し処理し、各イベントを個別に処理するIngestionパイプラインから始めました。処理中、まず同じIDを持つ履歴行を検索し、LLMコールのプロンプトと補完をトークン化し、コストを計算し、データベース内のイベントをupsertします。しかし私たちのテレメトリを調査したところ、2つの大きなボトルネックがあることが分かりました。PostgresのIOPSの枯渇と、長い文字列をトークン化する際のCPU消費です。これらはどちらも、当社のアプリケーションの稼働時間とレイテンシに影響を及ぼすリスクです。最悪の場合、当社の取り込みAPIでEvent が失われ、HTTP 500エラーが返されることになりました。 ソリューションを検討するにあたり、単にコンテナの数を増やすだけでは効果的ではないことに気づきました。個々のユーザーが大規模なバッチジョブを実行すると、取り込みトラフィックが大幅に急増することがよくあります。その結果、ユーザーからの API トラフィックは非常に予測が難しくなり、コンテナインスタンスではこうした急増に対応するのに十分な速さでスケールすることができません。そこで最終的に、すべての取り込みトラフィックを Redis のメッセージキューにルーティングすることにしました。Kafkaとは異なり、Redisは簡単に自己ホストでき、当社の要件を満たすように拡張できます。そして次に、別のLangfuseコンテナ (Worker) が非同期でこのデータをConsumeし、レート制限を適用して、当社のデータベースの負荷とコンテナのCPU使用率を低減します。この変更により、認証と本文の形式のみを確認する軽量な取り込みエンドポイントを作成しました。このWorkerコンテナは、トークン化やデータベースへの書き込みなどのより集中的なタスクを処理します。 Clickhouseから読み込まずにClickhouseに更新を書き込む 私たちは、APIパフォーマンスを短期的に改善する必要があったため、上記のステップのみを行いました。しかし、作業はまだ終わっていませんでした。Worker コンテナがすべての処理を非同期で行っていたとしても、私たちの取り込みパイプラインのロジックを動作させるには、多くのPostgresのIOPSが引き続き必要でした。この問題についても、セルフホスティングユーザーから問い合わせがありました。同時に、私たちは読み取りクエリのAPIレイテンシを改善するという課題にも直面しており、最終的に、TraceデータをPostgresからClickhouseに移行することを決定しました。Clickhouseは、Observerbility分野において多くの新規参入者が使用しているOLAPデータベースで、Apacheライセンスが適用されており、当社の概念実証(PoC)で卓越したパフォーマンスが確認されていました。列指向のストレージレイアウトは、私たちが期待する分析クエリに適しており、大規模なバイナリ列を持つ単一行の検索でも高いパフォーマンスを発揮します。しかし、本番環境への導入は容易ではありませんでした LangfuseのSDKは、指定されたオブジェクトIDの更新をバックエンドに送信するように設計されています。Postgresにおける単一の行の読み取りと更新は高速かつ簡単ですが、 ClickHouseにおけるすべての行の更新は非常にコストのかかる操作 です。そこで私たちは更新を新しい挿入に変換し、ClickHouseのReplacingMergeTreeテーブルエンジンを使用して、最終的にバックグラウンドで行の重複を排除しています。 つまり、常に行の最新の状態を取得し、更新を適用し、それをClickhouseに書き戻す必要があるということです。 私たちはトラフィックを分析し、すべての更新の90%が10秒以内にデータベースに書き込まれることを認識しました。つまりこれは、同時実行性とデータの整合性に気を配らなければならないことを意味します。しかし、Clickhouse から行の最新の状態を取得するのは現実的ではありませんでした。Clickhouse は、クエリ結果を返す前に全てのデータが Clickhouse ノード間で同期されることを保証する、非常にコストの高い "select_sequential_consistency" 設定を使用した場合にのみ、書き込み後の読み取りの一貫性が保たれます。したがって、私たちの規模では、Clickhouse から既存のデータを読み取れる保証はありませんでした。また、同じIDに対する2つのイベントが並行して処理され、競合状態が発生する可能性もありました。 そこでこの問題を緩和するために、承認された全てのイベントを Redis にキャッシュすることにしました。そして、Worker コンテナにイベントを送信し、Worker コンテナはオブジェクト ID に関連する全てのイベントを取得して、Clickhouse から読み込む必要なしに、確実に新しい Clickhouse の行を作成します。私たちは新しい取り込みパイプラインを実装し、Postgres 取り込みパイプラインと並行してイベントの処理を開始しました。 しかし非常に大きなインスタンスを利用しても、AWS ElastiCache のネットワーク容量には限界があるという事実がすぐに判明しました。また、Redis のもう一つの欠点は、インメモリ型のアーキテクチャと、保存されたデータが一時的な性質 (ephemeral) であることです。S3 をイベントのPersistent ストレージとして導入することで、Redis には参照情報のみを保持できるようになりました。この変更により、エラーが発生した場合にイベントを再生することも可能になり、さらに驚くことに、Redis 用にイベントをシリアライズする処理が高コストだったため、Web コンテナの CPU 使用率が大幅に低下しました。Kafka の方が取り込みにはより適していたかもしれませんが、新しいマルチモーダル機能のために、Redis のキャッシュ機能と S3 を活用することで、コンポーネント数を少なく保つことを選択しました。これらの調整により、Clickhouse にデータを一貫して、かつ大規模に挿入することに成功しました。

  • [後半] ゼロからスケールへ:Langfuseのインフラストラクチャの進化 (和訳)

    このBlog記事はガオ株式会社による Langfuse GmbH "From Zero to Scale: Langfuse's Infrastructure Evolution" の日本語訳 後半となります。原文は こちら をご確認ください。 前半記事は こちら 。 ビルディングブロック2: キャッシュと分離型のインフラストラクチャ Clickhouseへのデータ取り込み問題を解決する一方で、プロンプト管理機能を利用するユーザーの状況も改善する必要がありました。Observerbility データ分析の結果、プロンプトAPIにはいくつかの問題があることが判明しました。具体的には、それらが大量の取り込みトラフィックがデータベースのIOPSやコンテナのCPUを枯渇させる可能性がありました。 最初に、プロンプトを取得するためのPostgresデータベースへの問い合わせを回避しようと試みました。ここで、Redisをキャッシュとして利用することの強力さと、それがもたらす影響を実感しました。プロンプトが更新されるタイミングは把握しているため、古い結果を返すリスクなく効率的にキャッシュを無効化できます。 次に、プロンプトや認証など、レイテンシーと可用性に敏感なインフラを専用のデプロイメントに分離しました。AWS ECSの特定のエンドポイントに対して、LoadBalancerルールと専用のTargetGroupを使用することで、取り込みトラフィックをアプリケーションの他の部分から隔離できます。さらに、専用ルートによって可観測性が向上するという追加のメリットも得られました。この構成はまだHelm Chartには含まれていませんが、必要であれば主要なクラウドプロバイダーやKubernetes全体でエミュレートできます。 これらの2つの変更により、プロンプトAPIのp99(99パーセンタイル)のレスポンスタイムを7秒から100ミリ秒に短縮することに成功しました。 3つ目に、SDKを更新して、ゼロレイテンシのプロンプトフェッチングを使用するようにしました。以前にAPIからプロンプトのバージョンが取得されている場合は、そのバージョンを次のLLM呼び出しに使用し、LangfuseのAPIへの呼び出しはバックグラウンドで実行します。これにより、プロンプトがユーザーのアプリケーションのクリティカルパスから取り除かれました。 ビルディングブロック3:OLAPデータベース+クエリ最適化 Langfuse V3への移行における最後の課題は、読み取りクエリを最適化し、すべてのユーザーに対して一貫して低いレイテンシーを実現することでした。この取り組みを開始した時点で、すでにPostgresと並行してClickhouseにデータを書き込んでいました。これにより、Clickhouseからのデータの保存方法と取得方法を実験することができました。何度も「これでうまくいった」と思ったものの、そのたびにさらに多くのデータが到着しました。 当初、過去1週間以内のデータに対するすべての呼び出し(単一レコードのルックアップを含む)はp99で1秒以内に完了し、1週間以上のデータについては4秒以内であれば許容できると考えていました。Datadogでの通常のトレーシングに加えて、PostgresとClickHouseの読み取りを同時に実行し、それらのレイテンシーの違いを測定するためのフレームワークを構築しました。一貫して改善された結果を確認することで、正しい方向に進んでいるという確信を得ました。 まず最初に正しく行う必要があったのは、テーブルスキーマ、パーティショニング、およびデータの並び順キーでした。これらを変更するには、テーブル全体の書き換えが必要となり、つまり、すべての更新に数日かかる可能性がありました。他のClickhouseユーザーとの会話やClickhouseのドキュメントを参照し、早い段階でprojectIdと日付を並び順キーの最初の2つの列にすることにしました。さらに、フィルタリングによく使用される列にスキップインデックスを設定して、アイテムIDも追加しました。Postgresとは異なり、Clickhouseでは効率的な行ルックアップのためのB-Treeインデックスを保持できません。常にディスクレイアウトに基づいてデータを検索する必要があります 次に最適化する必要があったのは結合処理 (Join) でした。Oberverbility データへの結合を行う際に、処理に数秒かかり、Clickhouseノードで使用可能なすべてのメモリを使い果たすことが頻繁に発生していました。Clickhouseは、結合の右側 (The right side of a join) を効果的にフィルタリングするのが苦手だということを学びました。そこで可能な限り結合を避け、Common Table Expressions (CTE) を使用して、できる限りフィルターを手動でプッシュダウンしました。場合によっては、単一のトレースやObserverbility データのルックアップで並び順キーをより有効に活用するために、タイムスタンプなどの追加情報をフロントエンドAPIの呼び出しに追加しました。 これらは私たちが想定していた課題でしたが、ここからはClickhouseの特異な性質について掘り下げていきます。まず、ReplacingMergeTree内でデータを重複排除する方法を見つける必要がありました。Clickhouseは最終的には行を重複排除しますが、挿入後数分から数時間以内に多くの重複が発生し、短期間のメトリクスやダッシュボードがほぼ使い物にならないことがわかりました。FINALキーワードを使用すると改善されましたが、クエリ実行中のリソース消費量が増加したり、スキップインデックスの最適化がまったく利用されなくなったりするという新たな問題が発生しました。書き込みタイムスタンプによる重複排除(order byとlimit by)、FINALキーワード、およびdistinct集計を組み合わせて、信頼性の高いメトリクス、テーブル、およびビューを作成しました。 スキーマ設計に多くの時間を費やしたことが、Clickhouseへの移行において大きな成果をもたらしました。プロセス全体を通してわずかな調整しか必要なく、PostgresからClickhouseへの1回のデータインポートで済みました。残りの最適化については、特定のユースケースで何がうまくいくかを予測できなかったため、迅速な反復が功を奏しました。優れた可観測性と堅牢な実験フレームワークは、反復と新しい仮説の形成に迅速なフィードバックを提供しました。昔から言われているように、「変更が難しいことについては時間をかけて考え、できる限り迅速に動く」ということが重要です。 これらにより、以前は大規模プロジェクトでの外れ値によって悪化していたフロントエンドおよびバックエンドAPI呼び出しにおけるパフォーマンスが向上しました。 V3 Architecture まとめ:Langfuse v3のアーキテクチャに施した主な変更点は以下の通りです。 Worker コンテナ:イベントを非同期に処理する S3/Blob store: ラージオブジェクトを保存するため Clickhouse: Trace, Observations, Scoreを保存する Redis/Valkey: Eventキューイングとデータキャッシュ V3構成 V2構成 (参考) 結論 (Conclusion) Langfuse v3のリリースに非常に満足しています。Langfuse Cloud ユーザーからのポジティブなフィードバック、最初の1週間でのセルフホストユーザーの高い導入率、そしてわずかな問題点リストは、プロジェクト全体を通して多くの正しい決断を下したことを示しています。新しいアイデアを迅速にテストし、明確なデータに基づいた強力な仮説に導かれることで、大きな進歩を遂げることができました。 しかし、プロジェクト中、しばしばスケジュールを見誤っていました。今後の取り組みについては、スコープを最大1か月に制限し、途中でより多くのマイルストーンを導入する予定です。さらに、Langfuseが急速に成長しているため、このプロジェクトの進行中、主要な担当者が継続的なインシデントやバグ修正の対応に手が取られることが多くありました。 私たちはデータ駆動型の文化、本番データのサブセットで実験を行うためのシンプルな方法、そしてスタック全体にわたる優れた可観測性を維持します。これらの要素は、費やした各時間の価値を最大化し、セルフホストとクラウドベースの両方の顧客を満足させ続けるのにとって重要な意味を持つものとなります。 原文:  Langfuse GmbH "From Zero to Scale: Langfuse's Infrastructure Evolution" 日本語: Langfuse 日本語サイト 本ブログにおけるお問い合わせは こちら まで。

bottom of page