对golang服务器开发模式的一些思考
多线程+同步阻塞模型
在我们的游戏项目中使用的golang服务器开发方式如下
1.多线程逻辑
2.同步阻塞. 也就是说, 每个人一个线程(goroutine), io线程=逻辑线程
这种方式的优点:
1. 同步阻塞方式与人的思维方式类同
2. 逻辑处理性能有一定提升
在大规模使用这种模式编写逻辑后, 我们发现了这种模式只有1个缺点: 编写者需要处理多线程关系
但这本身确实直接致命的, 回想C++时代, 多线程处理时, 调试重现的困难… 脑补景象太惨不敢直视
单线程+异步多进程模型
在C++时代, 我曾经编写过一套asio的C++服务器框架. 采用io多线程, 逻辑单线程, 依赖着C++高性能的优势, 让开发便捷简单且无需关心线程问题.
那么到了golang时代, 为什么不能试下单线程异步多进程方式来编写逻辑?
与多线程同步阻塞对比后, 我们发现, 两者优缺点互补. 那这就回到了领域选型问题了. 对于游戏服务器需要的上手简单, 开发便捷, 压力降低(非MMO)这些特点来说, 单线程异步多进程再合适不过了
那么, 我们在用golang编写单线程异步多进程服务器应该注意哪些点呢?
1. socket处理完全封装, 只通过channel抛出到逻辑线程排队处理
2. 数据库, rpc及其他io处理, 一律改为异步回调模式, 不使用同步接口
3. 玩家存盘提交数据可以考虑复制并提交到存盘线程方式, 提高性能.
4. 采用多进程架构, 比如设网关进程, 把io压力分散到进程中
5. 逻辑编写中, 不允许使用go开线程及channel, 有需要提高性能部分需要单独编写
Actor模型的痛
cellnet在开发时本来考虑使用actor模型来进一步简化多线程逻辑的麻烦, 经历了一段时间的原型开发后, 发现了一些问题, 列举如下:
1. golang的强类型不适合actor模型这种经常需要动态生成各类消息的模型, 但skynet(C+lua)/erlang就有天生优势
2. actor模型本身不是万能的, 不能解决所有需求, 特别是游戏
3. actor模型理解到应用有一定的难度. 本身还需要搭建框架, 上手复杂
总之, 看过一些erlang及skynet的用例, 没有应用的很纯正且成熟的成功actor模型案例, 从传统socket服务器框架跨越到actor模型会扯到蛋, 因此, 后期cellnet会考虑回归到成熟的socket服务器框架. 把架构做到简单上手, 高扩展上.