負荷分散と冗長化について

これはMisskey Advent Calendar 2020の24日目の記事です。

私は世界最大のMisskeyインスタンス、Misskey.ioを運営しています。(物は言いよう)

この記事ではMisskey.ioの負荷分散や冗長化(主にDB)についてお話します。

Misskey.ioとは

Misskey.ioは登録者数4,000人、アクティブユーザー数2,500人/月程度の世界最大のMisskeyインスタンスで全体の約80%、DBやMisskey本体は100%オンプレミスで稼働しています。

Misskey.ioは人数が多くても快適に使えるインスタンスを目指しており、サーバー設備に新車のワゴン車が買える程度のお金をかけて運営していますが、うっかりちゃっかりミス(?)でたまに落ちたりするそんなインスタンスです。

そもそも上記のような問題はクラウドを使えば発生しないじゃないか!と言うお話ですが、Misskey.ioの規模をクラウドで運用すると毎月軽自動車が買えてしまうぐらい掛かるので、比較的安いオンプレミス方式での運用をメインとしています。

Misskey.ioの構成

まず負荷分散や冗長化についてお話するにはMisskey.ioの構造から説明する必要があります。
※長くなるので今回はサーバーの詳細スペックについては省きます

リージョン

Misskey.ioはオンプレですが、協力者によってマルチリージョンで運営しています。
– 札幌第一 (自宅)
– 札幌第二 (友人宅)
– 東京 (友人宅)
※中継サーバー等もありますが今回は割愛しています。

まず一番スペックが高く、帯域幅が広いのが札幌第一で僕の自宅でもあります。

Misskey運営を始めた当時はこのリージョンだけでしたが、2018年9月6日に発生した最大震度7の北海道胆振東部地震によって壊滅的な被害を受けた(自宅は最上階でそのエリアの震度は6強でした)ので、それ以降徐々にリージョンを増やしていきました。

PostgreSQL

まずなんと言っても一番大事なのは投稿やユーザー情報等のすべてが保存されるデータベース、PostgreSQLです。

実は一番負荷が掛かるのはMisskey本体ではなくコイツなので、Misskey.ioではプライマリDBにCPU48コア RAM768GBのマシンを導入し、後ほど出てくるレプリカにもCPU12コア RAM32GB程度のスペックを割り当てています。

Misskeyは非常に多機能で使いやすい反面、人数が増えると大量のDBクエリを必要とします。

例えばMisskey.ioではユーザー1人程度に対して平均10回/sのクエリ程度発行するのでサーバー全体で見ると平均1,500回/s、イベントやゴールデンタイムでは10,000回/sものクエリを処理する事もあります。
(バルスとあけおめはマジでヤバい)

この大量のクエリに耐えるため、Misskey.ioではいろんな方法を使って負荷分散を行っています。

利用している技術

  • VPN
  • Pgpool-II
  • PostgreSQL ストリーミングレプリケーション
  • Kubernetes

VPN

Misskeyはほぼすべての処理でRedisやPostgreSQLと通信しますが、それらもレプリケーションを行っているので膨大な量の通信を毎日行っています。
(プライマリルーターの情報だと1日あたり約1TBほど)

Misskey.ioでは上記の様なやり取りをカバーするため、プライマリ側にはRTX3500、レプリカ側にはRTX830なハードウェアVPNを導入しています。

最初はOpenVPNで稼働していましたがパケットロスや遅延が酷く、高速で安定した通信を行うためにはそこそこ高いマシンを導入しなければいけなかったため、それならハードウェアに任せようという事で安定性とコスパ最強なYAMAHAルーターになりました。

プライマリ側には元々RTX1210を利用していてスペック的にも十分でしたが、何を血迷ったかボーナスでRTX3500(35万円ぐらい)を衝動買いしてしまい、おそらく一番負荷がかかる部分なのでRTX1210から置き換えました。

Pgpool-II

これはPostgreSQLのロードバランシングやキャッシュ等を行ってくれるソフトウェアです。

非常に柔軟な設定や拡張ができるというのがメリットですが、コイツを通すと何故かかなりスループットが下がります。

1つのPgpool-IIではMisskey.ioのクエリに耐えられなかったため、Pgpool-IIのWatchdog機能を使ってPgpool-II自体を冗長化し、KubernetesでPodが起動するたび、ランダムなPgpool-IIに接続されるようになっています。

また、Pgpool-IIにはキャッシュ機能があり、頻繁にアクセスされるクエリの応答速度を大幅に短くすることができます。
Pgpool-IIのキャッシュ機能は優秀で、関連するカラムが変更されると自動的にそのキャッシュを破棄するため、データの不整合が起きない仕組みになっています。

ただし、キャッシュ機能は共有メモリモードとMemcachedモードがあり、何故かMemcachedにするとデータの不整合が発生するので共有メモリモードで利用するようにしています。

PostgreSQL ストリーミングレプリケーション

PostgreSQLにデフォルトでついているレプリケーション機能で、その名の通りリアルタイムに各レプリカと通信してデータを共有するものです。

変更された差分データをVPNを経由して送信し、リアルタイムに同期することによって、各リージョンとの接続が切断された場合でもプライマリとの不整合が起こる可能性が減ります。

また、バックアップとしても活用していて、すべての接続されているDBはスタンバイとして機能してプライマリがダウンした場合にはPgpool-IIによってどれか一つのDBがプライマリへと昇格されます。

データベース周り全体

中々言葉にまとめるのは難しいですが、上記の状態を図に表すとこのようになります。

DB全体

Kubernetes

Misskey本体を冗長化しているアプリケーション(というか仕組み?)で、複数のサーバーをまたいでDockerのコンテナを大量に立ち上げそれらの連携を行ってくれます。

また、ただ連携を行うだけではなく、内部にロードバランサを作り負荷の少ないコンテナへトラフィックを割り当てたり、動的に必要な数コンテナを増やしたりすることも可能です。

Kubernetesに関しては検索したら色々出てくるので省略します。

今後のMisskey.io

実はM1 MacBook Airを購入しまして、コスパと安定性に非常に驚いています。

現状は脳筋マシンばかり稼働しており電気代がすごいことになっているので、近いうちにMisskey.ioの全サーバーをM1 MacMiniに置き換える予定です。

PostgreSQLに関してはM1対応と発表されていますが今の所メモリ16GBモデルしかないため、MacMiniをまずは買ってみて快適に動作するかテストしたいと考えています。

コメント

タイトルとURLをコピーしました