May 18, 2017

Lua 表的差异同步

最近同事碰到的一个需求:需要频繁把一组数据在 skynet 中跨网络传递,而这组数据实际变化并不频繁,所以做了大量重复的序列化和传输工作。

更具体一点说,他在 skynet 中设计了一个网关节点,这个网关服务可以负责把一条消息广播给一组客户端,每个客户端由内部的一个 uuid 串识别,而每条消息都附带有客户端 uuid 列表。而实际上这些 uuid 列表组有大量的重复。每条广播消息都重复打包了列表组,且列表组有大量重复信息。

一开始我想的方法是专门针对这个需求设计一组协议,给发送过的数据组编上 id ,然后在发送方和接收方都根据 id 压缩通讯数据。即,第一次发送时,发送全量信息,之后再根据数据变化发送差异;如果完全没有变化,则只需要发送 id 。

之后我想,能不能设计一种较为通用的差异同步方法,可以在跨节点传递数据组的时候,避免将相同的数据重复传输,而采用差异同步的方法同步对象。

阅读全文 "Lua 表的差异同步" »

May 08, 2017

用 gdb 分析 coredump 的一些技巧

前几天我们正在运营的一款产品发生了崩溃,我花了两天尝试用 gdb 分析了 coredump ,虽然最后还是没能找到 bug ,但还是觉得应该做一些总结。

产品是基于 skynet 开发的,由于历史原因,它基于的是 skynet 1.0 之前 2015 年中的一个版本,由于这两年一直没出过什么问题,所以维护人员懈怠而没有更新。

崩溃的时候,关于 Lua 部分的代码缺少调试符号信息,这加大了分析难度。现在的 skynet 在编译 lua 时,加入了 -g 选项,这应该可以帮助未来出现类似问题时更好的定位问题。

阅读全文 "用 gdb 分析 coredump 的一些技巧" »

April 21, 2017

MMORPG 客户端的网络消息框架

昨天和人闲扯,谈到了 MMORPG 客户端的网络消息应该基于怎样的模型。依稀记得很早写过我的观点,但是 blog 上却找不到。那么今天补上这么一篇吧。

我认为,MMO 类游戏,服务器扮演的角色是虚拟的世界,一切的状态变化都是在游戏服务器仲裁和演化的。而客户端的角色本质上是一个状态呈现器,把玩家视角看到的虚拟世界的状态,通过网络消息呈现出来。所以、在设计客户端的网络消息分发框架时,应围绕这个职责来设计。

客户端发起的请求分两种:一种是通知服务器,我扮演的角色状态发生了改变,请求服务器仲裁;另一种是,我期望获取服务器对象的最新状态。后一种有时以服务器主动推送来解决,也可以用主动请求,两者主要的区别在于流量控制。

阅读全文 "MMORPG 客户端的网络消息框架" »

April 10, 2017

为什么美术和策划在使用 git 时会遇到更多麻烦

我们公司有两个项目的客户端在使用 git 做项目管理,三个项目使用 svn 管理。程序员比较爱 git ,但是为什么 svn 还存在?主要是在做客户端开发时,策划和美术人员始终迈不那道坎。即使已经在用 git 的项目,策划们还是反应用起来比 svn 跟容易犯错误,遇到自己无法解决的问题也更多。

我是非常想在公司全部推广使用 git 做项目管理的。所以需要仔细考察到底是什么东西阻止了策划(及美术)们掌握这个工具。

思考一番后,我认为一套完整的培训机制还是得建立起来。完全靠自学和口口相传是不靠谱的。尤其是在有 svn 基础的时候,非程序开发人员接受 git 其实比程序开发人员要困难的多。如果你硬要把 svn 的概念全部适配到 git 上,其实就是在把 git 当 svn 在用,不仅获得不了好处,反而增加了很多困扰。

而实用主义者,在没有外力的情况下,只会看到表面。不可能系统的从原理上系统理解 git 到底解决了什么问题、每步操作背后到底做了什么,如果出现了问题,问题是怎么引起的。我们知道,在用 git 的时候,由于分支和提交都比 svn 方便,分布式的结构也会更容易导致版本演化图变得异常复杂。当它乱成一团乱麻的时候,任何新的合并操作都会比之前遇到更多麻烦。如果使用者心里有清晰的概念,时刻保持演化关系简单,他遇到的问题自然会少。而你遇到问题乱解决一通,只满足于把现在的问题搞定,那么下次就会面临更大的灾难。

阅读全文 "为什么美术和策划在使用 git 时会遇到更多麻烦" »

April 06, 2017

Unity3D 的大场景内存优化

我们公司的一个 MMORPG 项目最近在内存方面碰到了红线,昨天开会讨论了一下。我提出了一个改进方案,写篇 blog 记录一下。

问题是这样的。在当下的手机及平板硬件设备条件下,操作系统留给应用的可用内存并不多,大约只有 500M 左右。

和 PC 环境不同,手机上是交换分区的机制来对应一些临时突发性内存需求的。而手机必须保证一些系统服务(某些高优先级后台业务)的运行,所以在接电话、收取推送等等意外任务发生时,有可能多占用一些内存,导致操作系统杀掉前台任务让出资源。

根据实际测试,游戏想跑在当前主流高端手机上必须把自己的内存占用峰值控制在 400M 内存以下,350 M 会是一个合理的值,而这个值是远远低于 10 年前的 PC 游戏标准的。而我们的项目却是一个写实类型的 拥有大场景的 MMORPG 。

阅读全文 "Unity3D 的大场景内存优化" »

March 25, 2017

skynet cluster 模块的设计与编码协议

skynet 在最初的设计里,希望做一个分布式系统,抹平 actor 放在本机和处于网络两端的差别。所以,设计了 master/slave 模式。利用 4 个字节表示 actor 的地址,其高 8 位是节点编号,低 24 位是进程(节点)内的 id 。这样,在同一个系统中,不管处于哪个进程下,每个 actor (在 skynet 中被成为服务)都有唯一的地址。在投递消息时,无需关心目的地是在同一个进程内,还是通过网络来投递消息。

随后,我发现试图抹平网络和本地差异的想法不那么靠谱。想把一个分布式系统做得(和单一进程同样)可靠,无论如何都简单不了。而 skynet 的核心希望可以保持简单稳定。所以我打算把分布式的支持放在稍上一点的层次实现。

先来说说同一进程下的服务通讯和跨网络的通讯到底有什么不同。

  1. 进程内的内存是共享的,skynet 是用 lua 沙盒来隔离服务状态,但是可以通过 C 库来绕过沙盒直接沟通。如果一个服务生产了大量数据,想传给您一个服务消费,在同一进程下,是不必经过序列化过程,而只需要通过消息传递内存地址指针即可。这个优化存在 O(1) 和 O(n) 的性能差别,不可以无视。

  2. 同一进程内的服务从底层角度来说,是同生共死的。Lua 的沙盒可以确保业务错误能够被正确捕获,而非常规代码不可控的错误,比如断电、网络中断,不会破坏掉系统的一部分而另一部分正常工作。所以,如果两个 actor 你确定在同一进程内,那么你可以像写常规程序那样有一个共识:如果我这个 actor 可以正常工作,那么对端协作的另一个 actor 也一样在正常工作。就等同于,我这个函数在运行,我当然可以放心的调用进程内的另一个函数,你不会担心调用函数不存在,也不会担心它永远不返回或是收不到你的调用。这也是为什么我们不必为同一进程内的服务间 RPC 设计超时的机制。不用考虑对方不相应你的情况,可以极大的简化编写程序的人的心智负担。比如,常规程序中,就没有(非 IO 处理的)程序库的 API 会在调用接口上提供一个超时参数。

  3. 同一进程内所有服务间的通讯公平共享了同一内存总线的带宽。这个带宽很大,和 CPU 的处理速度是匹配的。可以基本不考虑正常业务下的服务过载问题。也就是说,大部分情况下,一个服务能生产数据的速度不太会超过另一个服务能消费数据的速度。这种情况会造成消费数据的服务过载,是我们使用 skynet 框架这几年来 bug 出现最多的类型。而跨越网络时,不仅会因为生产速度和消费速度不匹配造成过载,更会因为传递数据的带宽和生产速度不匹配而过载。如果让开发者时刻去考虑,这些数据是投递到本地、那些数据是投递到网络,那么已经违背了抹平本地和网络差异这点设计初衷。

所以我认为,除非你的业务本来就是偏重 IO 的,也就是你根本不打算利用单台硬件的多核心优势来增强计算力,抹平本机和网络的差异是没有意义的。无论硬件怎样发展,你都不可能看到主板上的总线带宽和 TCP 网络的带宽工作在同一数量级的那一天,因为这是物理基本规律决定的。

当你的业务需要高计算力,把 actor 放在一台机器上才可以正常的发挥 CPU 能力去合作;如果你的系统又需要分布式扩展,那么一定是有很多组独立无关的业务可以平行处理。这两类工作必须由构架系统的人自己想清楚,规划好怎么部署这些 actor ,而不可能随手把 actor 扔在分布式系统中,随便挑台硬件运行就够了。

恰巧网络游戏服务就是这种业务类型。多组服务器、多个游戏场景之间交互很弱,但其中的个体又需要很强的计算力。这就是 skynet 切合的应用场景。

阅读全文 "skynet cluster 模块的设计与编码协议" »

March 20, 2017

skynet 1.1 发布候选版本

skynet 1.0 于 2016 年 8 月 1 日正式发布,到今天已经有 7 个多月了。这段时间积累了很多小修改,我想是时候发布 1.1 版了。

很高兴这段时间 skynet 社区继续壮大,有更多的公司选择基于 skynet 开发。

现打算在下个月以目前 github 仓库 master 分支为基础发布 1.1 正式版,这两周如果同学们还有什么问题请尽快提 issue 。

下面是从 1.0 开始积累的更新:

阅读全文 "skynet 1.1 发布候选版本" »

Misc

Categories

Archives

Recent Comments