Looyao's Blog

记录一些点滴

一个简单的弹幕服务端实现,基于nginx

| Comments

弹幕越来越火,今天介绍一种简单的弹幕服务器实现。

nginx push stream module这个模块非常适合弹幕的场景,支持多种连接方式。

安装

1
2
3
4
5
6
git clone https://github.com/wandenberg/nginx-push-stream-module.git
wget http://nginx.org/download/nginx-1.8.1.tar.gz
tar xvf nginx-1.8.1.tar.gz
cd nginx-1.8.1
./configure --prefix=/usr/local/nginx --add-module=../nginx-push-stream-module
make && make install

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
http {
    ...

    push_stream_shared_memory_size 32m; #设置共享内存大小
    push_stream_authorized_channels_only on; #只有有内容的频道才能订阅
    push_stream_max_messages_stored_per_channel 100; #每个频道最大存储消息的最大数量,达到上限之后,新的消息会取代旧的。

    server {
        listen       80;
        server_name  localhost;

        root   html;

        location / {
            index  index.html index.htm;
        }

        location ~ /ws/(.*) { 
            push_stream_subscriber websocket; #订阅使用WebSocket方式

            push_stream_channels_path                   $1;
            push_stream_message_template                "{\"id\":~id~,\"channel\":\"~channel~\",\"text\":\"~text~\"}";

            push_stream_websocket_allow_publish         off; #只允许订阅,不允许发布。

            push_stream_ping_message_interval           10s;
        }

        location /pub {
            allow 127.0.0.1; #只允许内网访问发布消息
            allow 192.168.0.0/24;
            deny all;

            push_stream_publisher admin;
            push_stream_store_messages on;

            push_stream_channels_path               $arg_id;
        }
    }

}

使用

官方文档比较详细,提供了很多使用事例,上边的的配置是订阅使用WebSocket的方式,长连接,效率更高。发布使用正常的HTTP协议,提供内网访问,这样前端逻辑收到用户发布内容可以进行过滤等处理,然后通过HTTP POST发布内容到nginx。

订阅:官方有提供html例子,我们使用C++的Client来测试。下载地址:https://github.com/dhbaird/easywsclient。修改example-client.cpp,替换WebSocket地址。

1
ws = WebSocket::from_url("ws://localhost/ws/test");

make之后,执行./example-client,需要先发布一条消息才能正常监听,不然会返回404。

发布:可以使用curl模拟测试

1
curl -X POST http://localhost/pub?id=test -d 'hello world'

这样一条消息就被发布了,订阅会得到:

1
2
3
4
./example-client
easywsclient: connecting: host=localhost port=80 path=/ws/test
Connected to: ws://localhost/ws/test
>>> {"id":5,"channel":"test","text":"hello"}

这样,一个弹幕服务端就实现了。细节可以自己调整,详细配置参数可以参考官方文档。

分布式

目前官方不提供分布式处理,但是可以通过前端逻辑来实现,可以部署多个服务,发布消息的时候每个服务都POST一次,也不是很麻烦。可以根据实际的访问量来做负载均衡。

最后

推荐一篇文章,http://highscalability.com/blog/2014/4/28/how-disqus-went-realtime-with-165k-messages-per-second-and-l.html,Disqus对于nginx push stream module的使用。

现在开源世界越来越强大,很多场景都能找到开源的解决方案,感谢开源的世界。

UPDATE(2016-04-24): 还有另外一个扩展可以选择,nchan,这个可以通过redis做集群。

Comments