游戏服务器端架构简述

来源:互联网 发布:在线反馈系统php源码 编辑:程序博客网 时间:2024/05/18 15:55

一、确定下来的游戏服务器端架构方案如下

QQ20160621-1@2x


这里简单说明下:

broker (worker)

其实broker就是原来的worker,只是功能完全变成了路由的作用。负责将请求转发到对应的处理server上面去。

broker与server之间使用tcp连接,broker不关心也不等待server的响应。

server

server则是真正进行真正的业务处理,比如我们现在线上业务大体分为: auth_server(登录), play_server(打牌), hall_server(大厅), common_server(其他)。

这样不同的业务逻辑在部署上就完全分离了,而由于broker本身是不阻塞的,所以即时auth_server变慢,也不会影响到play_server了。

而每一个server内部,是支持消息分组的,每个分组单独一个消息队列,只要将不同优先级的命令字分到不同的分组中去,就不用担心阻塞了。

trigger

trigger在V2时代就存在,只是当时他的角色还没有那么重要,因为worker本身是可以直接和gateway进行交互的,所以trigger当时只是在非worker中进行使用(比如web层)。

而在V3中,trigger变成了一个关键角色,因为broker(即原来的worker)不再处理业务逻辑,而server本身与gateway之间是没有连接的,所以trigger就变成了server与gateway通信的唯一桥梁。

OK,现在我们看看到了这一步,我们已经解决了哪些问题。

  1. 业务模块之间容易互相影响 YES
  2. 限制了游戏逻辑的实现方式 NO
  3. 要保持server支持热重启的特性 NO
  4. 要架构足够简单,不要增加研发成本 YES
  5. 要消息处理路径不能太长,防止变慢 YES

我们来看看没有完成的两个问题:

要保持server支持热重启的特性

  1. server本身的实现是支持 kill -HUP 的,能够优雅的重启server内的worker进程。

    需要特殊说明一下的是,由于业务逻辑的复杂性,一个新worker启动时需要导入的模块太多,从而导致worker的启动极慢,尤其当十几个worker同时启动时更是如此。

    所以我们做了一个优化,当worker启动后,直到完全启动成功前,不会替换现有的worker来分配任务。当所有模块都导入结束之后,再进入替换worker的逻辑。

    这样的逻辑是极有必要的,因为之前gateway对应的worker是无状态无差别的,所以当一组worker启动很慢时,可能还有另一个组worker可以帮助处理业务。

    而server内的worker是分组的,一旦worker启动很慢导致消息被堵住,那么是没有其他worker可以帮忙分担的。

  2. 一旦需要重启整个server而不只是server的worker进程时,对于不同的server我们可以在broker中配置不同的处理方案。

    比如play_server的重启,我们可以要求broker必须等待到连接正常建立,并发送成功后再处理下一个消息;而auth_server的请求比较低,那么就可以直接重启,broker发现连接断开后尝试连接一次,再失败就直接报错。

在保证了上面的两种情况之后,我们基本可以保证业务的热重启了。

限制了游戏逻辑的实现方式

其实在引入了server的模式后,业务开发想使用单个进程做本地存储已经不再受限制了。

我们重点来说一下给桌子废弃掉锁的问题。

  1. 我们会给play_server启动多个分组,每个分组内一个worker。
  2. broker层在给play_server做转发的时候,会将用户所在桌子ID取出来放在包头中
  3. server在收到请求后,会把消息通过取模或者其他方式路由到对应的worker上。由于一个桌子的所有消息都会被路由到一个固定的worker上,所以锁就可以彻底废弃了。

而进桌、换桌、挑战等特殊逻辑的实现会比较复杂,需要将消息做内部的转发处理。不过其实方式是一样的。

二、 可能的问题

  1. 消息的路由可能不均匀,比如对于打牌消息的路由,在桌子数比较少的情况下,每个worker的繁忙程度很可能是不一样的。

    如果要解决的话,要在路由函数那里记录每个worker的繁忙程度。

    目前解决的优先级并不高

三、总结

我始终相信无论服务器端还是客户端的架构,都是要不断演进的。

而每一次在实践中摸索出来的重构,都会是架构的一次升华。

原创粉丝点击