Posted at

Norikra でライブ配信サービスのなんちゃって同時視聴者数カウンタを作った話

More than 3 years have passed since last update.

スマホ動画サービスなどのライブストリーミング配信とかやってると、NOW ON AIR なユーザ番組のリアルタイム視聴数の確認・ロギングを行いたかったりする。

しかしながら視聴側が CloudFront などの CDN 業者を介した配信だったりする場合、配信番組ごとの視聴数を直接取得するのが難しかったりするので(簡単に取れたりするのかな・・汗)、視聴数取得用に別の常時接続システムを入れたりすることになるのではと思う。


なぜ Norikra

今回は配信に紐づくチャットルームはあるものの、WebSocket や MQTT などのナウいものではなく愚直な 5 秒間隔での HTTP ポーリングで更新チェックを行っているシステムが対象のため、常時接続環境下では容易に行えるであろう現在の接続数のカウントアップが少し難しい。

シンプルなソケット通信で常時接続を張るようなサーバを新たに構築してもよいのだけれど、クライアントアプリ側での追加実装・リリースも必要だったりするため今あるシステムでなんとかできないかと考えたところ Norikra に行き着いた。

Norikra はログなどのイベントストリームに対し、専用クエリをショートスパンでバッチ処理する JRuby 製のツール。

巷では各アプリサーバに配置した fluentd と組み合わせて異常値検知や監視を自前で組み立てる際などによく使われてるみたいですね。

前々から気になってはいたのだけれどなかなか使う機会がなかったため、ここぞとばかりに取り入れてみることに。


構成

シンプルにアプリサーバに配置された fluentd から Norikra サーバにアクセスログを集約し、さらにそこからクエリ結果をフェッチし続けることで直近の同時接続数を確認できるようにする。


Norikra サーバ側設定 1


Norikra インストール

当たり前だけど Norikra をインストールしておく。

さらに下記のように起動してデーモナイズしておく。

$ norikra start -d 

これで公式ページに紹介されているような WebUI や norikra-client コマンドが利用できるようになるので軽く確認しておくと良いかもしれない。


アプリサーバ側設定

ログ転送元のアプリサーバには予め fluentd および fluent-plugin-norikra をインストールしておく。

fluentd に下記のような設定を追記することでアプリサーバが吐いたログを Norikra に転送できる。

<source>

type tail
format json
path /var/log/api/access.log # アクセスログファイル
tag api_access.server01
pos_file /var/log/td-agent/tmp/tail_api_access.pos
</source>

<match api_access.**>
type norikra
norikra norikra.local:26571
target_string api_access
target_map_tag false
</match>

もちろん設定後には fluentd の再起動を忘れずに。


Norikra サーバ側設定 2

上記設定でアプリサーバのアクセスログが正常に Norikra に送られてきている場合、自動的に api_access という target が作成されているはず。

$ norikra-client target list

TARGET AUTO_FIELD
api_access true
1 targets found.

この target に対し query を追加する。

WebUI から下記のような EPL を count_audience のような名前で登録すれば簡単。

SELECT

uri.substring(xx, xx) AS stream_id, -- IDだけ抜き出し
COUNT(*) AS cnt -- 5 秒間に各配信番組に対してリクエストされたポーリング回数
FROM
api_access.win:time_batch(5 sec) -- 5 秒の間隔でクエリを実行する
WHERE
method = 'GET' AND
uri like '/streams/%/messages%' -- メッセージポーリングを識別できるパス
GROUP BY
uri.substring(xx, xx)

このクエリの実行結果は WebUI からもサンプルとして確認できるけど

$ norikra-client event fetch count_audience

とすることで

{"time":"2015/09/27 00:12:08","stream_id":"[stream_id.001]","cnt":35}

{"time":"2015/09/27 00:12:08","stream_id":"[stream_id.002]","cnt":201}
{"time":"2015/09/27 00:12:08","stream_id":"[stream_id.003]","cnt":170}
{"time":"2015/09/27 00:12:13","stream_id":"[stream_id.001]","cnt":40}
{"time":"2015/09/27 00:12:13","stream_id":"[stream_id.002]","cnt":199}
{"time":"2015/09/27 00:12:13","stream_id":"[stream_id.003]","cnt":171}
{"time":"2015/09/27 00:12:18","stream_id":"[stream_id.001]","cnt":39}
.
.
.

のような結果セットをすべて得ることが出来、単位時間あたりのなんちゃって同時視聴者数をカウントすることができる。

もちろんポーリングされてる間クエリ結果もどんどん溜まっていくので定期的に event fetch することで最新の結果が得られるようになる。


まとめ

正直後ろ向きなアプローチではあるけどこんなこともできるよ、的な事例レベルで Norikra の紹介してみた。

各種インストールとか公式ページでわかることはあえて端折ったけど、fluent-plugin-norikra の NorikraInput とか使って結果を他のデータソースにさらに横流しすることでよりシームレスなシステムになると思う。