Plack ベースで作った Web サービスとそのシステムアーキテクチャ

本日、TVTalk という Web サービスをリリースしました。

Twitter 上で、テレビ局のハッシュタグが付いているツイートを拾って、放送中の番組情報と紐付けるという、アグリゲーターサービスです。リアルタイムにタイムラインを追うにも、放送済み番組の内容をチェックするのにも使えますので、みなさんぜひ使ってみてください。ブックマークやいいね!も良かったらお願いします!

今日は、この Web サービスの裏側のシステム構成を紹介したいと思います。

構成

Web サーバー

Web はフロントに nginx をおいて、静的ファイルは nginx にサーブさせ、拡張子がついていない URL のみバックエンドの Starman に渡しています。nginx の設定ファイルは以下のようになっています。

    location / {
        root /home/tt/repos/tvtalk/static;
    }

    location = / {
        access_log  /var/log/tvtalk/nginx_service/access.log;
        proxy_pass http://localhost:8081;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
    }

    location ~ /stream/ {
        access_log  /var/log/tvtalk/nginx_stream/access.log;
        proxy_pass http://localhost:8082;
    }

    location ~ /[^/.]*(\?|$) {
        access_log  /var/log/tvtalk/nginx_service/access.log;
        proxy_pass http://localhost:8081;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
    }

上記設定から分かるように、ページを生成するのは Starman プロセス、ツイートのストリームを吐き出すのは Twiggy と分けています。

放送中のタイムラインは、jquery.ev.js から long-poll で Twiggy + Tatsumaki に繋いで実現しています。

Streaming API との自動再接続処理

Twitter の Streaming API は、何時間か毎に接続が切れるので、自動再接続する処理を施しています。ツイートをアーカイブするクロウラープロセスは、普通に while ループで回し、ストリームを吐き出すプロセスは、AE::timer で接続状態をチェックしつつ、自動再接続処理をし、Twiggy::Server->register_service でハンドラ登録して、AE::cv->recv でブロックしています。

Streaming API の接続制限

Streming API を利用するにあたって注意する点は、Streaming API に複数のコネクションを張ると切られまくるので、複数のトラックワードを指定したい場合、複数のコネクションを張るのではなく、単一のコネクションを張って、on_tweet 時に、どのワードをトラックしたかアプリケーション側で判別する必要があるということです。この辺の注意事項は公式の API ドキュメントに書いてあります。

コネクションを張る前に、Tatsumaki::MessageQueue->instance でトラックワード数ぶんのキューを用意してあります。

現時点では、タイムラインは jquery.ev + long-poll で実装していますが、そのうち、DUI.js + multipart/mixed に置き換えたいと思っています。

自作フレームワークについて

Airy というオレオレフレームワークを作って使っています。
Moose などには依存しないように、なるべく汎用的にせずに、機能を限定してなるべく薄くなるように作っています。まだ色々と実装途中ですが、機能・実装でアドバイスあればぜひお願いします。