0x00单线程
多进程单线程与单进程多线程的目的都是想尽可能的利用CPU,减少CPU的空闲时间,特别是多核环境,今天咱不做深度解读,跳过...
0x01线程池+锁
最早的一部分游戏服务器是采用线程池的方式来处理玩家的业务请求,以达最大限度的利用多核优势来提高处理业务能力。
但线程池同时也带来了并发问题,为了解决同一玩家多个业务请求不被并发,引入了锁的方式,每个Session一把锁,锁住业务处理逻辑,从而解决同步问题
0x02串行化设计
借鉴了Netty的串行化设计理念,业务线程池也采用了串行化设计,这就意外着整个流程如同单线程一下顺序执行,也不会进行线程上下文的切换,数据也不会面临被并发修改的风险
那如何实现玩家与线程绑定关系呢?
我们只要简单的取模运算,映射到固定的线程上执行即可,比如我们有N个业务线程
public Executor balanceExecutor(long playerId) {
return executors[playerId % N];
}
以前上线的游戏都是基于串行化的方式,在大量数据统计下,玩家ID或场景ID以及模块划分都不能作为负载均衡的条件,在活动期,是很不均衡,虽然能满足日常运营活动体验.
0x03抽象的Actor模型
服务器游戏需要什么?指定逻辑有序执行...
可以把服务抽象为玩家队列,模块队列等等,一个队列就是一个Actor的Mailbox,从而进行有序的执行指定业务逻辑...
Noark内置了@Controller注解,threadGroup为玩家线程组所有逻辑则以玩家ID来分组执行,如果是模块线程组则以模块名来分组执行...
A玩家请求1,2,3协议,则会以先后顺序进行有序执行... B玩家的请求也会有序执行,只要线程池有空闲线程,就不会受到A玩家的延迟影响...
同理,各模块划分都是独立的,互不影响,就这解决了串行化设计中模块Hash定位不受控制问题.
有序执行的功能请参考
xyz.noark.core.thread.TaskQueue.complete()
小结:多线程处理多队列,有序而已...