有哪些开源?
KBEngine《暗黑战神》
最后一战
skynet
muduo
GoWorld
服务引擎要实现什么?
核心两个问题:消息的pipeline与游戏世界状态维护。
网络:
定义client到server、server到client、server到server的消息流。
我们看手边工具,socket(最好是单线程的,并且跟IO无关,可参考众多网络库)。
首先解决的一点就是,将传输层的协议转换为应用层的消息协议。
要解决的第二个问题是,为应用层建立IO模型。
要解决的第三个问题是,封装具体的连接细节。
多线程技术或多进程技术
信号
定时器
服务实体(抽象成粒度最小):
可以简单理解为一组方法集合。服务是分布式游戏服务端中的最小实体,一个服务提供了一组确定的、可供调用的方法。
skynet中,一个skynet_context唯一对应一个服务,而一个skynet节点对应一组服务;传统MMO中,一个进程对应一组服务,但是很难在其中找到“一个”服务的划分界限。
服务的概念就是为了提出一种与物理容器无关的抽象。服务可以以某个进程为容器,也可以以某个线程为容器。可以像skynet一样以一个luaState为容器,也可以像Erlang游戏服务端那样以一个actor为容器。而一个容器也可以提供多种服务。
服务中的数据定位
游戏世界的状态可以简单分为两个部分,一部分是需要存档的,比如玩家数据;一部分是不需要存档的,比如场景状态。
对于访问较频繁的部分,比如场景状态,会维护成纯内存数据;对于访问较不频繁的部分,比如玩家存档,就可以考虑维护在第三方。这个第三方,就是数据服务。
数据服务与之前所提到的场景服务、IM服务等都属于应用层的概念。数据服务通常也会依赖于一种基础设施抽象,那就是缓存。
我们可以将服务状态存放在外部设施中,比如数据服务。
无状态服务
将状态存放在外部设施的服务就是无状态服务。而与之对应的,场景服务这种状态需要在进程内维护的就是有状态服务。无状态游戏客户端意味着网络通信的成本跟内存数据访问的成本一样低——这当然是不可能实现的。游戏中可以拆分为无状态服务的业务需求其实有很多,基本上所有服务间交互需求都可以实现为无状态服务。比如切场景服务,因为切场景的请求是有限的,对时延的要求也不会特别高,同理的还有分配房间服务;或者是面向客户端的IM服务、拍卖行服务等等。
游戏服务端中的Message Queue
面对这种需求,我们需要一种消息队列中间件。
生产者消费者一直都是一种比较经典的解耦模型,而消息队列就是基于这种模型构建的。每个skynet节点本质上就是一个高度精简的消息队列,为寄宿的每个服务维护一个私有队列,对全局队列中的消息dispatch,驱动寄宿服务。
而我希望的是更纯粹的消息队列中间件
zk解决了什么问题?
就我们的游戏服务端需求来说,zk可以用来选leader,还可以用来维护dbClient的配置数据——dbClient直接去找zk要数据就行了。
简单介绍下如何基于zk实现leader election。zk提供了一个类似于os文件系统的目录结构,目录结构上的每个节点都有类型的概念同时可以存储一些数据。zk还提供了一次性触发的watch机制。leader election就是基于这几点概念实现的。
假设有某个目录节点/election,watcher1启动的时候在这个节点下面创建一个子节点,节点类型是临时顺序节点,也就是说这个节点会随创建者挂掉而挂掉,顺序的意思就是会在节点的名字后面加个数字后缀,唯一标识这个节点在/election的子节点中的id。
一个简单的方案是我们可以每个watcher都watch /election的所有子节点,然后看自己的id是否是最小的,如果是就说明自己是leader,然后告诉应用层自己是leader,让应用层进行后续操作就行了。但是这样会产生惊群效应,因为一个子节点删除,每个watcher都会收到通知,但是至多一个watcher会从follower变为leader。
优化一些的方案是每个节点都关注比自己小一个排位的节点。这样如果id最小的节点挂掉之后,id次小的节点会收到通知然后了解到自己成为了leader,避免了惊群效应。
一些思想
操作系统依赖的IO复用,线程编程,内存管理, 脚本系统。分布式服务实现
实现actor框架的思路,有Lua/C的交互以及协程实现的思路,字节码编译加载,分布式服务实现,集群间通信,超时检查,读写第三方开源服务(redis,mongo)。
entity
参考: