さくらインターネット移行記#2 VPN越しのMySQLレプリケーション

前回さくらiDCに移転し始めた、ということを書いたのですが、あれから一ヶ月ちょっとが経過しましてその後も順調に iDC への移転が進んでいます。すでにラックもいくつか借りて、サーバーも数十台がさくら iDC で稼動しています。回線がこれまでよりも高速なバックボーンに接続されつつ、帯域幅も大きくなったことから、移転したサービスによってはこれまでよりもパフォーマンスが出ているサービスもあります。うち比較的大きなデータを扱うフォトライフも移転を完了していますが、おかげさまで画像の読み出しがかなり速くなったのが体感できるぐらいスループットが向上しました。

既存サービスを移転するにあたって、どういった構成でそれを行っているかをちょっと紹介してみようと思います。

移転当初は、既存のはてなのサービスとはあまり関係していないサーバー群から手を付けました。例えば広告のシステムといった、はてなのデータベースを直接覗いたりしない類のものです。これらは既存のサーバー群とのネットワークをほとんど利用しません。一方フォトライフのようなサービスの場合、古いサーバールームにあるデータベースに対してある程度依存したまま iDC を移転する必要が出てきます。そのため、さくらインターネットの技術チームの協力を得て旧サーバールームとさくらiDCの間を VPN で接続してあります。

無理やり絵にするとこんな感じでしょうか。

旧サーバールームとさくらiDCの間はインターネットを経由していますが、サーバー管理者から見た場合は同一のネットワークに接続されているように見えます。従って旧サーバールームから直接さくらiDCに置いた新しいサーバーへネットワーク接続できます。また、この VPN の回線が何らかの原因で切れてしまうと困るので、二回線を使って冗長化してあります。VPN で接続することができるので、新しいサーバーのログインアカウント等々は旧サーバーネットワークで利用していた LDAP と同じドメインで一元管理したものが使えるので、新しくアカウントを作り直したりですとか ssh の鍵を配置しなおしたりですとか、その辺のわずらわしい作業も必要ありません。

この VPN はインターネット越しなのでさすがにネットワークの速度は遅いです。管理系の通信にはこの VPN を経由しても問題になりませんが、実際のサービスとなると話は別です。例えば新しいデータセンター側にアプリケーションサーバーがあって、旧サーバー側の DB サーバーに VPN 経由で SQL を投げる、なんてことをしているとパフォーマンスも落ちますし、VPN の帯域をあっという間に使い果たしてしまいます。

二つのデータセンターに置いたそれぞれのアプリケーションから同一のデータベースに接続しにいきたい (例えばユーザーアカウントのためのデータを格納したデータベースなど)、という場合にどうするか。どちらかのデータセンターにしか DB がない場合 VPN を経由した通信が必要になってしまいます。そこで、MySQLレプリケーションを使います。いずれか一方のネットワークにマスタを置いておき、VPN を経由してスレーブを立てて、各アプリケーションサーバーは各々自分のネットワークにあるスレーブへ接続しにいく、という構成です。

MySQL スレーブの Slave I/O スレッドからマスタへの polling で一部 VPN での通信が発生しますが、アプリケーションから各スレーブに接続しにいく接続に比べるとデータ量、接続回数ともに最小限で済みます。またその polling にはそこまでシビアなレスポンスタイムは要求されません。大きな遅延なしにマスタと同期さえできれば OK です。一方マスタの配置ですが、この方法では分散できない CRUD の CUD のクエリがどこから発生してどのくらいの割合があるかで、どちらの iDC にマスタを置くかを決めます。例えばフォトライフのマスタDBを更新するのはフォトライフアプリケーションの役割で、それはさくらiDC側にあるのでマスタもさくらiDCに、フォトライフのデータを引く必要のある既存のサーバー用に旧サーバールームにもフォトライフDBのレプリカを置いておく、という具合です。

この方法で徐々に移転を進めており、今月中にははてなブックマークのサーバー数十台もさくらiDCに持っていこうかなと思っています。移転に伴ってある程度インフラの刷新も行い、これまでよりも高速なサーバー、高速な回線上でサービスを提供できるようになる予定です。

ところで、この MySQL スレーブを VPN 越しに作って云々、というのはちょっとアプリケーションの設計が悪いというのがそもそもあります。このように物理的に分散した環境でサービスを提供することを想定すると、やはりサービス間同士のインタフェースは直接データベースに接続しにいったりという密結合を発生させずに、Web API などでラッピングして疎結合にしておくべきです。