这周的工做主要是写代码。 html
开发计划制定好后,咱们便分头写代码去了。咱们但愿一期早点作出能够运行的东西来,一切都从简。总体的代码量并很少,若是硬拆成不少份让不少人来作的话,估计设计拆分方案,安排工做,协调每一个人写的东西这些比一我的所有实现一遍的工做量还要大的多。 java
因此,最终就是两我的在作。怪物公司在弄客户端的东西,蜗牛同窗包干了服务器。好吧,基本没个人事了,我就是那个打酱油的,好听点说,就是设计方案。固然,事情没多少,空下来的时间也能够干活。训练本身能够找到事情作,并真的作有用的事情,仍是很难的。 程序员
话说回来,咱们在这么一个简单的框架下,一开始肯定了要采用一些现成的技术方案,即要用到 Redis , Google Protobuffer , ZeroMQ 。 正则表达式
Redis 和 ZeroMQ 是我最先选的,想了好久。 数据库
采用 Redis 是由于历史上,我参与的项目都没有大规模使用 SQL 数据库的传统。这和 MMO 这种特定应用有关。在 Web 开发中,面对的用户是临时的,不依赖固定链接的。你不肯定用户在不在那里,你不肯定同时要面对的用户有多少。你须要从小到大,采用一种可扩展容量的方案。这个时候,成熟的 SQL 数据库方案是首选。 服务器
从软件开发角度看,数据库是 MVC 模式中的 M 。以 MVC 模式解决问题,M 如何实现,采用 SQL 方案只是一种可能,毫不是惟一选择。换个角度考虑,若是是一个桌面软件,为何大部分的 M 却没有采用数据库,而更多的是在内存中直接构建数据结构呢?性能恐怕只是一个缘由,更重要的缘由是面对的用户的行为不一样。 网络
为何 MMORPG 服务器,至少在网易历史上的多款游戏,没有使用 SQL 服务作 M 。一部分缘由是,网易游戏的开发源头是 Mud ,Mudos 并无使用 SQL 做为 M ,另外一部分缘由是,MMORPG 面对的,同时须要服务的用户有限。而用户须要操做的数据大部分限制在用户相关的数据体内。以外的数据体很是少。及时数据总量很大,但一层索引简单(以用户 id 为索引)。每一个用户都是为它持续服务,数据易变。这种行为下,从 MVC 角度看,更接近网络应用以前的软件设计。 数据结构
固然你甚至能够把 M 只在逻辑上划分出来,物理上并不切换,也就是没有独立意义上的数据库服务器。这样绝对性能最高,其实只是实现了一个简单的单机游戏,容许经过网络输入多条操做流,并把行为反馈经过网络发送回去罢了。甚至比单机游戏更简单,由于没有图形控制部分。 框架
若是程序不出问题,机房不停电,能够一直的跑下去,不用考虑数据储存问题。数据持久化不过是为了容灾罢了。把一些结构化数据持久化到硬盘上,最简洁的方案就是写操做系统层面的文件,必定比再使用一个数据库要轻量,干净的多。 工具
有了以上背景,就不难理解,为何我对 Redis 天生有好感。咱们并无改变设计思路,它是一直延续下来的。Redis 帮助了咱们将数据服务拆分出来。固然,MMORPG 也在发展,以上提到的用户应用环境也在逐步变化,咱们在软件设计上也会跟进这些变化。这些就是后话了。
ZeroMQ 呢,我是但愿有一个稳健,简洁的多进程通信方案的基础。ZeroMQ 是不错的一个。至少比 OS 的 Socket 库要实用的多。它提供了更好的模式 。这是我最为看中的。另外,这是一个 C 接口的库,容易 binding 到不一样的语言下使用。
在这个问题上,蜗牛同窗是反对使用 ZeroMQ 的。对他的全部反对意见,我都持保留态度。但我尊重开发人员的意愿。毕竟许多代码不会是我本身来写。蜗牛同窗但愿采用 Erlang + C Driver 的方式来驱动整个框架。也就是用 Erlang 来作通信上的数据交换。其它可能采用的开发语言,都经过 Driver 的方式插入到 Erlang 的框架中去。
我我的以为这样作的确可行,加上蜗牛同窗有好几年 Erlang 开发经验,他能担负起实现框架的责任。我不是特别喜欢这个方案是由于,Erlang 这个东西仍是太庞大了。我对庞大的东西天生反感。虽然以蜗牛同窗的原话说,Erlang 以及他的 OTP 能写出这么多行代码来有他的必要性。咱们用 C/C++(Python/Lua/Golang 等等) + ZeroMQ 实现一个拙劣的方案出来,只会漏洞百出。
我我的是不觉得然的,毕竟已经作了 10 年的网络游戏,对这个领域已经很熟悉了。对于陌生领域,咱们会面对许多未知的问题;但在熟悉领域,不管怎么作,方案都不可能太拙劣。只要保持最基本的简洁,我是有信心保证能够解决 MMORPG 中的各类需求的。作出来的东西也能很稳定。关键点在于,它会足够简单,能轻松的理解实现的每一行代码。
不过争论都放在一边。个人原则是,最终采用实现者自选的方案,只要它没有明显的问题。
咱们最终不采用 ZeroMQ 。
Google Protobuffer 我不是很喜欢的。但采用它是多个角度妥协的结果。其实我更愿意自定义一套协议。而只是裁剪 GPB 的功能。
我认为,GPB 在最底层的协议编码定义上,作的仍是不错的。改进它是多余的。做为一种协议定义,协议描述语言也算定义的不错。但只到此为止。接下来的部分就不甚满意。
GPB 协议自己,默认也是用 GPB 自己定义编码出来的。这看起来很 Cool ,但我不甚喜欢。固然全部完备的相似协议都应该有描述本身的能力。对于描述本身这件事情来讲,GPB 仍是稍显复杂了。
好比,若是你不借助已经有的 GPB 代码和工具,很难解析一个 GPB 协议。就比如,若是世界上第一款 C 编译器,就是最难实现的 C 编译器。由于大部分的 C 编译器是用 C 写的,实现一个 C 编译器,就陷入了先有鸡仍是先有蛋的问题。
在这类问题上,听说 Lisp 比 C 要干的漂亮。不过我仍是和世界上大多数程序员同样,用 C 多一些。好吧,咱们仍是继续用 GPB 好了。
google 在实现和使用 GPB 的时候,默认采用了一种为每一个协议,生成一组代码的方式。而不是提供一套 C/C++ 库,供其它语言作 binding 。这也是我所不喜的。或许是为了性能考虑,但总以为别扭。若是把 GPB 换成正则表达式来看,你就能理解个人心情。
现存的大多数正则表达式的实现,都是提供一组 API ,容许使用者把须要的模式以一种人类可读的串形式,编译为另外一种计算机方便处理的数据结构。当你须要的时候,使用这个数据结构,交给库,就能够匹配,替换字符串了。若是默认的选择是把正则表达式编译成 C 代码,而后你用的时候再 link 到你的项目中,恐怕用的人要疯掉了。固然,生成代码这种能够带来更高的运行性能。
唔,其实这只是怎样使用 GPB 这种协议的问题,和协议定义关系不大。惋惜 google 在开源之初就给出了官方的方案,引导其它语言也如法泡制,成了 GPB 的惯用法。老实说,对于 C++ ,这么作性能是不错的(其实也未必)。换到 Python 里,就很是低下了。去年我按个人思路实现了 lua 的 protobuf 解析库 ,性能能够达到和 C++ 版本差距不到一个数量级,甚至快过 java 版。
这周的剩余时间我都在写一个纯粹的 C 版的 protobuf 库,不依靠代码生成器的。但愿可以做为它语言使用 GPB 的基础。别的语言只须要作 binding 就够了。这玩意挺难写,光接口设计我就改了两版。今天终于快收工了。过两天再写一篇文章专门谈谈这个问题吧。固然,还有开源。
既然在 GPB 上花了这么多功夫,固然,采用 GPB 就是最后的决定了。