Open24

時雨堂クラウドサービスを支える技術 v1

voluntasvoluntas

v2 へ移行中です

円安の影響や、自社製品がスケールアウトに対応したこと、Cloudflare LB の WebSocket の挙動が残念だったことなどを踏まえ、サービス構成を変更を検討中です。

  • 脱 Vultr
    • Egress 料金が Linode だと Vultr の半額
    • Linode へ移行
  • 脱 Cloudflare LB
    • Linode の NodeBalancers へ移行
    • マルチリージョンでの利用は Linode の Akamai Global Load Balancer 公開待ち
  • 脱 Cloudflare
    • サポートに不安があるため Akamai へ移行
  • 脱 TimescaledB
    • 移行は Linode PostgreSQL の提供開始待ち
    • OLAP は DuckDB + S3 互換オブジェクトストレージへ移行
    • ログ保存は VictoriaLogs へ移行予定
  • 脱 DataPacket
    • Linode Dedicated CPU へ移行
    • 自社製品が Raft ベースの分散システムになったため小さなサーバをたくさん上げた方が効率がいい

設計しつつ、少しずつ移行中です。そのうち v2 を書こうと思います。


自社パッケージ製品のクラウド版 を開発していて、色々やりたい放題やってるのでメモ。

方針

  • 遠回り駆動開発
  • やりたい放題やる
  • 王道は無視して「じぶんのかんがえたさいきょうの」をでいく
  • 可能な限り OSS 開発元が提供しているクラウドサービスを利用する
  • ベアメタルサーバーを使う
  • 三大クラウドサービス (AWS, GCP, Azure) を使わない

なぜ利用している技術を公開するのか

自社で使って良かった OSS やサービスはより多くの人に知って欲しいと考えています。
また、特に隠す理由がないというのもあります、むしろ大きな声で Tailscale や TimescaleDB 、 VictoriaMetrics 、Cloudflare 、DataPacket など、ほんとうに素晴らしい使わせて頂いていると言っていきたい。

voluntasvoluntas

HTTP アプリ

  • Cloudflare Load Balancing を利用したラウンドロビンを行う
  • 宛先は VultrAkamai Connected Cloud
  • Cloudflare オリジンサーバ証明書を利用
  • DNS は指定なし 、LB からは IP での指定
  • App は Cloudflare からのみリクエストを受け付ける

Vultr と Akamai Connected Cloud

App が Vultr と Akamai Connected Cloud。

自社パッケージ製品 WebRTC SFU Sora

Cloudflare

ウェブフック署名

Stripe の 時間+JSON への HMAC を利用したシンプルな署名の仕組みを採用。

HTTP テストクライアント

HTTP API のドキュメント例には HTTPie – API testing client that flows with you を採用。

voluntasvoluntas

バックエンド

テスト

go.mod

go 1.22.0

require (
	github.com/conduitio/bwlimit v0.1.0
	github.com/coreos/go-oidc/v3 v3.9.0
	github.com/getsentry/sentry-go v0.27.0
	github.com/go-playground/validator/v10 v10.18.0
	github.com/gofrs/uuid/v5 v5.0.0
	github.com/jackc/pgx/v5 v5.5.3
	github.com/labstack/echo-contrib v0.15.0
	github.com/labstack/echo/v4 v4.11.4
	github.com/lestrrat-go/jwx/v2 v2.0.20
	github.com/meilisearch/meilisearch-go v0.26.2
	github.com/minio/minio-go/v7 v7.0.67
	github.com/rs/zerolog v1.32.0
	github.com/shogo82148/go-clockwork-base32 v1.1.0
	github.com/slack-go/slack v0.12.4
	github.com/urfave/cli/v2 v2.27.1
	golang.org/x/exp v0.0.0-20240222234643-814bf88cf225
	golang.org/x/sync v0.6.0
	gopkg.in/ini.v1 v1.67.0
	gopkg.in/natefinch/lumberjack.v2 v2.2.1
)

// テストのみ
require (
	github.com/ory/dockertest/v3 v3.10.0
	github.com/stretchr/testify v1.8.4
)
voluntasvoluntas

自社パッケージ製品以外は Vultr と Akamai Connected Cloud をマルチクラウドとして採用。

Vultr

  • SSD VPS Servers, Cloud Servers and Cloud Hosting by Vultr - Vultr.com
    • 証明書は Cloudflare のオリジン証明書を利用するので更新の必要性なし
      • デフォルト 15 年
    • Vultr Block Storage
      • HDD と NVMe SSD が選べる
      • NVMe SSD は VictoriaMetrics のストレージとして利用
      • HDD は MinIO のストレージとして利用
  • FW や LB などは利用していない
  • Tokyo リージョンがあり、シンプルで使いやすい、そして安い

Akamai Connected Cloud

voluntasvoluntas

DataPacket

自社製品は DataPacket 上にクラスターを構築している。

  • 10Gbps Unmetered Dedicated Servers | DataPacket.com
    • IPMI (ntelligent Platform Management Interface) を利用可能
  • Discord が利用している転送量無制限のベアメタルサーバ
  • 帯域で課金される
    • かなり柔軟に対応してくれる
  • IPv6 は無料で取得可能
  • AMD EPYC 7443P 24 Cores, 48 Threads, 2.85 GHz / MEM 128 GB / SSD 1.92 TB x 2
  • 1 回線を複数サーバで契約する Bandwidth Pool を利用

詳細は別途記事にしてある。
DataPacket 雑感

OS

  • Ubuntu 22.04 LTS を採用
  • Ubuntu Pro (Infra-only) を契約し Livepatch を利用することで WebRTC SFU のダウンタイムを減らしている

Bandwidth pool

Bandwith pool allows you to have single traffic plan for servers within same continent (or between EU & US servers). For example, your servers can share 20 Gbps regardless of their individual consumption.

Bandwithプールにより、同一大陸内のサーバー(またはEUとUSのサーバー)に対して、単一のトラフィックプランを設定することができます。例えば、各サーバーの消費量に関係なく20Gbpsを共有することができます。

https://www.datapacket.com/use-cases

Video streaming services
To meet the infrastructure challenges associated with delivering video content to thousands of simultaneous viewers, our 32 or 64-core streaming servers are equipped with dual 40GE ports and come with scalable bandwidth pools of 10–900 Gbps. Each video packet is delivered efficiently using uncongested optical fibre paths.

何千人もの視聴者に同時にビデオコンテンツを配信するというインフラの課題に対応するため、32コアまたは64コアのストリーミングサーバーには、40GEのデュアルポートが装備され、10~900Gbpsのスケーラブルな帯域プールが付属しています。各ビデオパケットは、混雑していない光ファイバー経路を使用して効率的に配信されます。

voluntasvoluntas

サーバ間通信

voluntasvoluntas

マルチクラウド

Cloudflare の後ろにいるアプリサーバをマルチクラウド化する。VultrAkamai Cloud で構成することにした。これでどちらかのアプリが落ちたりメンテナンスになっても稼働し続けられる。

構成はシンプルで Cloudflare LB でそれぞれのアプリにたいしてラウンドロビンをするだけ。

  • Cloudflare Workers -> Cloudflare LB -> Vultr App -> Managed Service for TimescaleDB (GCP)
  • Cloudflare Workers -> Cloudflare LB -> Akamai Cloud App -> Managed Service for TimescaleDB (GCP)

これで Vultr と Akamai Cloud のどちらかが落ちてもなんとかなる。セッションは Cloudflare Workers KV で管理しているので、気にしなくて良い。

監視はそれぞれに Tailscale をインストールしてうまいことやる。

voluntasvoluntas

DNS ラウンドロビン

Cloudflare Cloudflare Load Balancing を利用した DNS ラウンドロビンを利用して バックエンドを Vutlr と Akamai Connected Cloud のマルチクラウド。

Load balancing with DNS records · Cloudflare DNS docs

Beyond reducing requests to your origin server, this setup allows your application to take advantage of Cloudflare’s Zero downtime failover. When a request to one IP address fails, Cloudflare automatically retries the request to other IP addresses associated with the same hostname. This behavior prevents end users from experiencing downtime.

オリジンサーバーへのリクエストを減らすだけでなく、この設定によりアプリケーションはCloudflareのゼロダウンタイムフェイルオーバーを活用できます。一つのIPアドレスへのリクエストが失敗すると、Cloudflareは自動的に同じホスト名に関連付けられた他のIPアドレスへリクエストを再試行します。この挙動により、エンドユーザーがダウンタイムを経験することが防がれます。

voluntasvoluntas

E2E テスト

E2E テストは Python の pytest + Playwright + HTTPX を採用。

GitHub Actions の手動実行を利用してる。

voluntasvoluntas

データベース

PostgreSQL + TSDB の TimescaleDB を採用

Go + pgx + sqlc

  • pg ドライバーは jackc/pgx の pgxpool を利用
    • pgx/v5 を利用
  • sqlc 経由でのみ利用

ジョブキュー

負荷はほとんど無いため PostgreSQL の SKIP LOCKED 機能を利用して実現。

詳細は別途記事にしてある。
PostgreSQL で SKIP LOCKED を利用する

voluntasvoluntas

S3 互換オブジェクトストレージ

Cloudflare R2

R2の一般提供を開始しました
ストレージ 月額 $0.015 / GB

MinIO

  • 社内向けに Docker Compose で R2 の代わりに MinIO を利用
  • プロダクション検証環境向けに R2 と併用で Vultr で 1 Server 1 Drive で立てて MinIO を利用
    • Tailscale 経由でのみ利用可能にしている
    • DataPacket <-> Vultr

特定のフォルダを監視し、ファイルが追加されたら S3 互換ストレージにアップロードする仕組み

voluntasvoluntas

検索

  • オンラインドキュメントの全文検索
    • Sphinx がターゲット
  • ログの検索
    • TimescaleDB や R2 に保存しているログの全文検索
  • 検索サーバーとして

Meilisearch

Rust で書かれた全文検索エンジン Meilisearch を採用。2022 年に入って日本語にも対応。

ドキュメント全文検索

Sphinx をターゲットとして docs-scraper を利用してインデックスを作成し、Sphinx 側で docs-searchbar.js を利用して、インスタント検索を実現する。

Meilisearch と Sphinx による全文検索は別途記事にまとめてある。

Meilisearch を利用して Sphinx で日本語全文検索を実現する

構成

  • Cloudflare DNS Proxy + Nginx + Meilisearch
    • Nginx に Cloudflare Origin 証明書利用
    • Nginx は HTTP/2 対応
  • Vultr Optimized Cloud Compute
    • CPU Optimized
    • 2C/ 4G
    • 50G NVMe
    • Ubuntu 22.04 LTS

docs-scraper

synonyms

類義語は Meilisearch API を叩くことで実現可能。

Synonyms | Meilisearch Documentation

synonyms.json を更新すると GitHub Actions 経由で PUT する仕組みを用意した。

ページネーション

ページネーションが必要になるデータは TimescaleDB は引かずに、
Meilisearch をブラウザが引くようにする。

Melisearch + JWT

Cloudflare Workers で JWT を生成してブラウザへ払い出し、ブラウザ側で直接に見に行く。

検索

RDB や TSDB は検索には向いていないので Meilisearch を利用する。

構成

  • Cloudflare DNS Proxy + Nginx + Meilisearch
    • Nginx に Cloudflare Origin 証明書利用
    • Nginx は HTTP/2 対応
  • Vultr Optimized Cloud Compute
    • CPU Optimized
    • 2C/ 4G
    • 75G NVMe
    • Ubuntu 22.04 LTS

Meilisearch を利用してマルチテナントを実現する方法

Meilisearch の方針としては一時的なトークンを発行するという考えの模様。トークンは JWT 方式でその中に index と filter が設定できる。そのためそのトークンは ~ しか検索できないという縛りが可能になる。

Melisearch + JWT

Cloudflare Workers で JWT を生成してブラウザへ払い出し、ブラウザ側で直接に見に行く。

定期削除

顧客向けのログ検索は一定期間が過ぎたインデックスは削除するようにしたいが、それには Delete documents by batch を利用する。

Documents | Meilisearch Documentation

Meilisearch Cloud

日本リージョンはないので手が出せない。

https://www.meilisearch.com/pricing

voluntasvoluntas

ログ

ログの収集は Fluent Bit を採用。

JSON Lines 形式

Erlang VM 特殊形式

Erlang が出力する crash.log と erl_crash.dump はかなり特殊なフォーマットなため、JSONL のようには扱えない。さらに、これらのログでた場合は基本的にはバグなので効率よく共有したい。

マルチテナント向けログ

fluent-bit 側から JSONL ログをフィルターして TimescaleDB (Postgres) のジョブキューを経由して Meilisearch に追加しています。

ToDo

  • ログ検索システムを Cloudflare Pages + Cloudflare Zero Trust で用意
Hidden comment
Hidden comment