安全可靠的、支持扩展的分布式网路服务器:maple

dwd4 10年前

maple 是一个安全可靠的、支持扩展的分布式网路服务器。

一. gateway

2个epoll_fd,分别对应 外网链接 和 内网链接(之前也考虑过将accept线程单独放出来,后来发现会导致复杂度升高)分别处于单独的线程内,这样connection的申请和释放是不用加锁的。他们内部的沟通使用 加锁的queue。在每一次循环结束后进行pop和push。并通过notify()通知epoll退出等待,进行处理而每个线程内部,有一个临时queue,只有在epoll每循环一次之后,才会复制进去,这样就可以尽量避免锁了用队列的原因是,因为worker的连接没有办法和gateway完全同步,所以这个时候需要有队列暂时存储.内网连接里面分worker和trigger,worker是可以接受任务和返回消息的,而trigger只能返回消息。

trigger可以升级为worker,在跟gateway 索要 job后。所有的数据buf,都经过一层封装,再转发出去所以,创建一个新的box类型: GWBox多了几个字段: uid, tag, conn_id, conn_ptr 等

  • uid 就是登录的用户id

  • conn_id 是一个自增的类型,long long类型,确保是唯一的

  • conn_ptr 是Conn的指针,直接转成类型就可以用。因为gw里面是不delete Conn实例的,都是放到池里去。

  • tag 则是为了防止gw重启导致之前的conn_ptr拿来强制转化,从而导致崩溃

二. worker

多进程,每个进程单线程连接gateway,获取请求就处理,然后分为响应和事件两种进行返回.

  • write_to_client

  • write_to_users

  • close_client

  • close_users

  • login_client

  • logout_client

默认worker开启了一问一答模式,即write_to_client最多调用一次。如果要修改,请修改app的rsp_once参数。

worker 可以支持安全重启,不会影响业务

安全停止所有进程:

  • kill -USR1 $pid

安全重启workers(不会重新load worker数量):

  • kill -USR2 $pid

建议的supervisor配置:

  • [program:maple_worker]

  • environment=PYTHON_EGG_CACHE=/tmp/.python-eggs/

  • directory=/maple/normal_test/

  • command=/usr/local/bin/python worker.py

  • user=dantezhu

  • autorestart=true

  • redirect_stderr=true

  • stopsignal=USR1

  • stopwaitsecs=10

三. trigger

事件触发,他支持worker的所有发送数据,因为其实在gateway端,trigger和worker是同一个Conn类型

但其实能用的只有:

  • write_to_worker

  • write_to_users

  • close_users

注意: trigger是非线程安全的

其实trigger就是一个触发器,触发worker,也可以触发client。但是常用的方法是,触发worker,让worker去做对应的事情,这样可以保证逻辑的独立

四. 扩展

目前gateway是只能支持单台的,write_to_users 没有办法跨gateway。

这样考虑有几个原因:

  1. 开发简单

  2. 大部分大型游戏,在5k个人在线就会分服,而gateway 1进程 2线程 撑到1w人应该没有问题

  3. request.write_to_users 与 request.write_to_client 之间可以强制保证调用顺序;但是 trigger.write_to_users 和 request.write_to_client 之间保证不了

如果一定要做gateway的分布式,也有两个方案:

  1. 用户按照取模链接gateway,这样trigger.write_to_users可以直接根据模来发送. 当然,request.write_to_users就不能用了

  2. 增加一个server - router,用来存储并管理用户ID与gateway的映射关系。所有用户登录和close_client的消息都要通知给router.router封装 write_to_users,内部根据用户ID与gateway的映射关系来调用 trigger.write_to_users

项目主页:http://www.open-open.com/lib/view/home/1427853198115