我兴高采烈的把我的架构图发给一个有经验的前辈看,他指出来,也许不需要这么多逻辑进程。听他这么说,我想到这么早就把逻辑强行拆开给设计带来了不必要的复杂度,也没有让架构更加优美,甚至这种拆分可能是不必要的,过早的逻辑拆分就跟提前优化代码一样,都应该避免。
于是我去掉了 chat、mail 进程,打算把所有逻辑都放在 loc 进程进行处理,如果后期发现有拆分的必要再进行拆分。
最开始的时候,我提到过,想要服务器进程可以方便的横向动态进行改变,使用 zmq 满足了动态改变的需求,那么怎么能进行横向扩展呢?我在介绍我前一个项目的服务器架构时谈过,由于服务器进程是存在状态的,所以几乎无法进行动态增添服务器来降低压力,那么该怎么做才能把服务器写成无状态的呢?
状态信息,说白了就是数据相关,把一些热数据放在进程空间里,导致这个进程如果想要横向扩展,必须同步这部分数据,这个同步通常是困难的,甚至有的时候不太可能,而且对我来说设计起来不太容易。我的好友XY又发挥了巨大的作用,跟他聊天,他正好提到他们的web服务器用redis来保存session信息,我突然想到,可以把玩家信息保存在redis里,让进程不再拥有状态,这样就可以把服务器写成无状态的,利用redis这种内存级的数据库完全可以实现这一点。于是我在游戏服务器里又引入了redis。当然,这中间我也问过一些朋友,他们有没有在实际项目中使用,得到肯定的答复让我下定了决心。
我封装了 node-redis 模块,让处理逻辑的进程可以轻松访问 redis 服务器,这样我又可以去掉 db 进程了,每个进程单独和数据库进行通信:
这里可以看到,客户端跟服务器间的通信机制也被改掉了,客户端程序想要使用 websocket,于是我放弃了之前用 luasocket 写的网络库,改用 websocket 写了一套新的,虽然性能降低了4,5倍不止,但是算是尝了一次鲜。
nodejs 这边我使用的是 ws 模块,测试过很多别的模块,例如 socket.io、websocket等等,最后发现 ws 模块是最简单的,而且这几个模块性能都差不多,我也不需要他们提供的额外功能,我只需要一个解析 websocket 协议的功能而已。至此,服务器这方的设计算是有了一个基本的雏形,可以在其上进行逻辑开发了,当然,后期还需要不断调整,我同时也画了一下可能的服务器部署图:
redis 的数据落地策略采取的是每秒做 aof,同时每天做 rdb,aof 超过一倍就重写,主从库的设计也是不确定的,要在实践中进行修改,也要跟专业的运维人员一起商量才能确定。mysql 的重新引入是为了记录一些不变的玩家数据,这些在后面的设计可能会发生更改。
我之前的痛苦、纠结到此基本就算结束了,不过那些都是设计期的煎熬,真正的煎熬是游戏上线运营之后才会发生的,我深深的明白这一点。
下一篇我会谈一下,在这个过程中,遇到的 nodejs、redis 的一些考虑和坑。