読者です 読者をやめる 読者になる 読者になる

mixi engineer blog

ミクシィ・グループで、実際に開発に携わっているエンジニア達が執筆している公式ブログです。様々なサービスの開発や運用を行っていく際に得た技術情報から採用情報まで、有益な情報を幅広く取り扱っています。

期間限定の新機能「エコー」登場

echo mixi MySQL Q4M

こんにちは。mixi開発部のyouheiです。
今回は先日8月4日にリリースした「エコー」について書きたいと思います。

エコーとは

まずはエコーとはどういう機能かのご紹介ですが、プロモーションページがございますのでそちらをご覧いただければ幸いでございます。
http://mixi.jp/guide_echo.pl

いくつか抜粋しますと、

あなたの"今"を一言にしてみませんか?誰かに伝えたいこと、ひとりごと等、何でもOK! 気軽な新コミュニケーション機能です。
たとえば、「今日はいい天気だな〜」という、ひとりごとから、「お腹すいたー!誰かランチにいこうよ!」というメッセージ的な使い方まで、「エコー」の楽しみ方はあなた次第! マイミクシィ同士で「エコー」を使うとホームにお互いの書きこみが表示されます。
気になった書きこみには、返信することもできちゃいます。あなたがふと書きこんだ一言に、思わぬ返信があるかも!?

といった機能です。

当エンジニアブログではエコーの機能的な側面よりも、裏側はどうなっているのか、そのあたりをメインに書きたいと思います。

基本はLevel2分散

mixiの分散アーキテクチャは今までにも様々な場で紹介させていただいておりますが、mixi社内では分散の方法を

  • 「日記」「コミュニティ」など、機能ごとにDBを分割する垂直分散をLevel1分散
  • さらにそれをユーザーごとに別のDBに分割する水平分散をLevel2分散

と呼んでいたりします。 今回のエコーも例によってLevel2の分散を行っています。 即ち、

  • 各ユーザーのエコー投稿を貯め込むEcho Node DB
  • どのユーザーがどのノードに書かれているのかマッピングを管理するEcho Manager DB

基本的にはこの2つのDBを立てることでLevel2分散が実現できます。

Level2分散が仇になる点

ところがLevel2分散をすると逆に実装しづらくなる機能として、「みんなのエコー」という機能があります。これは、自分や自分のマイミクたちの発言をタイムライン上で一気に見れるページなのですが、この機能を実装するにあたっては、複数のDBにデータを分散するLevel2分散では、一度データを収集した後でそれを並び替える、という工程が発生しコストがかかってしまうため逆に仇となってしまいます。
同様な機能のページとしては「マイミクシィ最新日記」等のページもそうです。

Recent DB

これらのページを実現するにあたって、Echoでは「Recent DB」と呼ぶものを用意しています。
このDBはその名の通り、最近のみなさんの書き込みを貯め込むDBで、すべてのユーザーの発言が集約されています。
「すべてのユーザーの発言」という表現をするとデータ量が肥大化しそうに感じますが、その点においてはプロモーションページにも明記していますが、「みんなのエコー」ページに表示される書きこみは直近2日分のみという仕様なのでそれほど膨らむことはありません。

また、すべてのユーザーが「みんなのエコー」のページを表示する度にこのDBにアクセスしてくるためreadの負荷が高そうにも感じますが、その点についてはMySQLのレプリケーションを利用しSlaveを多数用意するという通常の方法をとることで単純にスケールアウトできるため、それほど問題になることはありません。
また、断トツに高いページビューのhome.plですが、こちらに表示されている最新エコー5件のRead負荷についてはmemcachedから取得しているため、こちらも負荷対策が出来ています。

問題は、このRecent DBへのWriteの負荷です。
MySQLのレプリケーションは基本的にはWriteはMaster1台に行う必要があります。
そしてこのDBはすべてのユーザーの発言時にWriteされるDBです。
ここがスケールアウトしづらいポイントとなり、高負荷時にはボトルネックとなりやすいポイントになります。
特にお正月の「明けましておめでとうー!」書き込み時などは負荷が非常に高い状態になります。

Q4Mでのピーク負荷平滑化

前述の問題は日記等でも同様ですが、投稿量で考えると圧倒的にエコーの方が高くなると予想されるため、エコーでは高負荷時でもRecent DBへのWriteがボトルネックとならないように、本エンジニアブログにも何度も登場しています弊社運用チームのkazeburoや、タンポポ開発チーム(という名前のチームが実際に存在するのです)のエンジニアと議論の結果、Q4Mを導入し高負荷に耐えられうる構成にしてみようということになりました。

Q4Mについては、MySQL5.1のプラガブルストレージエンジンの1つで、サイボウズ・ラボ株式会社の奥一穂氏が開発されています。

Q4M (Queue for MySQL) は MySQL 5.1 のプラガブル・ストレージ・エンジンとして動作するメッセージキューであり、堅牢・高速・柔軟であるよう設計されています。昨年12月遅くに開発が開始され、まだ非常に原始的ですが、かなり高速に動作します。

http://labs.cybozu.co.jp/blog/kazuho/archives/2008/01/q4m.php より抜粋

エコーではこのQ4Mをバッファリングする機構として導入することにより、Recent DBの能力を超えてしまうようなWrite負荷が発生した場合でも、一度Q4M上にキューイングされ、その後コンスタントにRecent DBへ伝播していくようにして、ピーク負荷を平滑化することができるような構成にしました。

エコーシステム構成

結果、エコーのシステム構成図は下記のようになりました。

echo_system

※実際のサーバー数は図のとおりではありません

キュー反映スクリプトからRecent DB (Master)への接続数は、今後、キューのたまり具合やRecent DBの負荷を見つつ、数を調整していきたいと思っています。

まとめ

今回のエコーでは負荷対策として、日記のように各投稿に対して一意なidを発行する採番部分を排除し、member_idとpost_timeで一意キーとするなどして負荷の集中を避ける等の細かな工夫も随所にしていますが、Q4Mを導入してみたというところが新たな試みとして一番大きな点です。まだQ4Mが本領発揮するほどの負荷は発生していないのですが、引き続き高負荷時のQ4Mの働きに注目していきたいと思います。

Q4Mは非常に有用かつ興味深いストレージエンジンだと思いますので皆さん是非試されてみてはいかがと思います。

最後に、素晴らしいエンジンを 開発下さった奥一穂氏に改めてお礼申し上げます。