ニコニコ大百科のアーキテクチャ

Twitter
mongrelP: @tasukuchan グニャラくーん、ニコ百の鯖がEeePCという話が持ち上がってますがただの監視用ですよね(しんぱいそうなめでみている)

ニコニコ大百科アーキテクチャについてメモしておきます。


本当は、このネタでRuby Kaigiに申し込もうと思ったけど、すっかり忘れていたのでエントリを起こしておきます。Rubyあんま関係なかったし。

全てのリクエストを受付、セッション情報も保持するEeePC

次世代サーバプラットフォーム EeePC

ニコニコ大百科宛ての全てのリクエストは、全てEeePCに送られます。
実物の写真を載せておきます。

EeePCは2台稼動しており、1台はホットスタンバイです。


EeePCは、SSDUPSを備えた次世代サーバプラットフォームです。
メンテナンスの際、キーボードやモニタをつなぐ必要もありません。
また、各種Linuxの導入情報が充実しています。
メモリ増設などを行っても5万未満で調達を行うことができます。
消耗品として扱えるため、減価償却の必要もありません。
ラック内占有体積も少ないです。
というわけで、サーバにオススメだと思うのですが、あんまり受け入れられないんですよねー…

        ____
       / \  /\ キリッ
.     / (ー)  (ー)\
    /   ⌒(__人__)⌒ \   <EeePCは、SSDとUPSを備えた
    |      |r┬-|    |      次世代サーバプラットフォーム
     \     `ー'´   /

     クスクス  ___
       /      \
      /ノ  \   u. \ !?
    / (●)  (●)    \
    |   (__人__)    u.   |
     \ u.` ⌒´      /
    ノ           \
  /´               ヽ
 |    l              \
 ヽ    -一''''''"~~``'ー--、   -一'''''''ー-、.
  ヽ ____(⌒)(⌒)⌒) )  (⌒_(⌒)⌒)⌒))

ワラワラ
         ____
       /      \!??
      /  u   ノ  \
    /      u (●)  \
    |         (__人__)|
     \    u   .` ⌒/
    ノ           \
  /´               ヽ
 |    l              \
 ヽ    -一''''''"~~``'ー--、   -一'''''''ー-、.
  ヽ ____(⌒)(⌒)⌒) )  (⌒_(⌒)⌒)⌒))

注意点として、

  • メモリは増設する。
  • LANも必要ならばUSBで増設する。
  • ログ関係はほとんど止めておく。
  • ext3だったら、noatimeを設定しておく。
  • 液晶のバックライトは消しておく。
  • どうしてもファイルに何かを一時的に書き出したいときには、tmpfsを使う。

って感じでしょうか。
あとは、最近リリースされたLinuxディストリビューションならすんなり導入できるでしょう。


このEeePCは、PLANEXのUSB LANコネクタを付けてあります。
Amazonで3,000円くらいで買いました。
メモリも、EeePC用のテキトーなのを数千円で買いました。

EeePC上で動いているサービス

LVSフロントが後ろに控えるWebサーバにリクエストを振り分けます。Webサーバとは、USB LANケーブルを通じて内側のLAN経由で接続されます。また、Webサーバはセッション情報をはじめとしたデータを、memcached互換サーバであるrepcachedに保存します。


repcachedは、弊社で開発しているgroongaに置き換え予定です。groongaでは、memcachedのバイナリプロトコル互換のサーバ機能を有します。(casとかflagsも対応する)

安価だがバランスのとれたPowerEdge 860

Webサーバ

Webサーバは、DellPowerEdge 860です。もちろん10万円未満で調達したものです。10万超えると、消耗品じゃなくなって減価償却必要になっちゃうからです。OSは、Debianのtestingです。Webサーバは3台存在し、LVSフロントからリクエストが振り分けられます。

httpdは、lighttpd 1.4.19です。mod_nicodhという、ニコニコ大百科専用のlighttpdモジュールを組み込んでいます。mod_nicodhは、C言語で簡単なアクセスハンドリングなどを行うモジュールです。ニコニコミュニティ掲示板の認証なども、mod_nicodhで処理します。


ニコニコ大百科は、ほとんどのコンテンツが静的になるように注意深く設計してあります。動的な要素が欲しい場合でも、Cookie/AJAXなどを用いてローカルで動的にページを生成できるようにします。たとえば、ニコニコ大百科の右メニューはログイン時・非ログイン時で表示が変わりますが、これはCookieの「login」という値を見てブラウザ側が動的に生成します。


静的なページは、ファイルとして保存されています。lighttpdは、そのファイルをそのまま返したり、gzip圧縮したりして返します。非常にシンプルで、かつパフォーマンスも悪くありません。


静的なページがファイルで保存されていなかったり、全体が動的なページがリクエストされたりした場合には、mod_nicodhで判定を行い、FastCGI経由でRubyに処理を渡します。FastCGIは、プロセスがWebサーバと分かれるのでハンドルしやすいです。ただ、プロセスが複数立ち上がるので、mmapなどをして論理空間・物理空間の浪費を防ぐ必要があります。


ニコニコ大百科Rubyを使って構築した、と言うと「Railsなんですね〜」とよく言われます。しかし、Railsは使っていません。ニコニコ大百科専用に、テキトーなフレームワークを書き起こしました。


FastCGIのハンドリング部分は、fcgiモジュールを使って書いています。また、Ruby標準のcgiモジュールは使わず、桑田誠さんがリライトしたcgi/cgiextモジュールを改造して使っています。テンプレートエンジンは、桑田誠さんのErubisを使っています。O/Rマッパは、テーブルごとに手で書いています。今であれば、FastCGIのハンドリング部分はRackを使いたいところですね。


ニコニコ大百科には、キーワードの自動リンク機能があります。以下のエントリにもあるように、Sennaは高速にキーワードの自動リンクを生成することができます。

キーワードリンクを行うRubyモジュールをC言語で書いて、利用しています。


静的なコンテンツで、キャッシュファイルが存在しない場合には、それを生成します。次回から、同じコンテンツに対するリクエストはlighttpdのみで処理されます。


Rubyを用いたのは、当時Rubyをほとんど使ってなかったので復習のために使いたかったのと、同僚にRubyが書ける人がいたからです。Rubyは遅いといわれますが、実用上困っていません。遅い部分は、C言語で書いたlighttpdのモジュールやRubyのモジュールが処理しているためです。むしろ、Hpricotのメモリリークや、libxml-rubyメモリリークやバグや仕様変更、libmemcachedのRubyバインディングの挙動に悩まされました。今だったらNokogiri使えっていう話なんでしょうけど…


ちなみに、webサーバの種別は、Apache Baseball Armyにしてあります。

DBサーバ

DBサーバも、DellPowerEdge 860です。もちろん10万円未満で調達したものです。OSは、FreeBSD 7.0です。弊社では、多くのデータベースサーバがFreeBSDで稼動しています。RDBMSは、MySQL 5.0 + Tritonnを使っています。マスタ1台+スレーブ1台の構成です。


SELECTを含めた、ほとんどのリクエストは「マスタ」に対して行われます。Webサーバでは、生成したhtmlなどを静的なファイルでキャッシュするため、マスタに対してリクエストを送ってもパフォーマンス上全く差し支えないし、レプリケーション遅れを気にする必要がないからです。


スレーブのみに、全文検索用のインデックスを付与したテーブルが存在します。スレーブは、主に全文検索クエリ用に用いています。


「データベースにリクエストが届いた時点で負け」という思想で、データベースについては目立ったチューニングは行っていません。負荷的にはまだ余裕があります。

APIサーバ

APIサーバは、libeventのevhttpというWebサーバ機構を用いて全てC言語で書かれています。Sennaとlibmysqlにリンクしています。APIサーバは、物理的にはWebサーバと同じです。ポートを分けています。


ニコニコ動画watchページでは、動画タイトルとタグの横に「百」「?」というマークが出ます。動画のタイトル/タグそれぞれ1つずつに対して存在するかどうか確認するリクエストが行われます。ニコ動のwatchページのPVの数倍のリクエストが来ることになります。


その他、ニコニコ動画の検索ページに大百科の記事のサマリーを出したり、ニコニコ市場に大百科の記事を出したり、さまざまなAPIを実装しています。


昔のバージョンのlibeventでは、evhttpが高負荷時に挙動が怪しかったです。というわけで、evhttpを使って書いたWebサーバに対して、リバースプロキシとしてVarnishでキャッシュを行っています。Varnishでは、これまたC言語を用いて拡張を行っています。


Varnishのキャッシュサーバは2台存在します。これもまた、DellPowerEdge 860で、OSはFreeBSDです。キャッシュサーバは同僚に書かせました。


現在のevhttpは高負荷時の挙動が安定してきているので、直にリクエストを受けてもいいのかもしれません。

まとめ

EeePCすばらしい。