GoCN 本期老司机系列我们请来了游戏后端开发的达人,之前也分享过很多游戏开发经验 —— @ 达达 为大家解答关于 Go 游戏开发方面的问题。
达达是来自真有趣信息科技有限公司的 CTO,非科班老司机,在游戏和互联网行业摸爬滚打十余载,擅长各种降低研发难度和成本的奇技淫巧,曾负责《神仙道》、《仙侠道》等项目的服务端架构设计和研发,目前正在逐步整理并开源真有趣团队的游戏服务端技术架构和开发流程,请关注 https://github.com/funny/ 了解最新进展,欢迎广大同行参与开源框架的研发。
不欢迎任何与主题无关的讨论和喷子。
下面欢迎大家对 Go 游戏开发方面的问题向 @ 达达 提问,请直接回帖提问!
> 达达的个人博客:http://1234n.com/ > 知乎的专栏:https://zhuanlan.zhihu.com/idada > 最热门的一个回答:Go 的垃圾回收机制在实践中有哪些需要注意的地方?https://www.zhihu.com/question/21615032/answer/18781477
本次活动持续两天,2016-10-17 至 2016-10-18,达达会在空闲时间上来给大家一一回答。
一路走来,经常看达达的黑魔法。除了游戏,以前学协议相关的,也是学习 达达 的 link
欢迎提问
我先来热个场,@ 达达
Go 在做游戏开发方面有什么优势吗?国内外是否有用 Go 开发的游戏开源框架?
一直想在 CGO 方面有所提升,虽然 CGO 不那么好用,但是掌握这方面知识也是为了知道什么时候该用 CGO,什么时候不该用 CGO,请问有什么资料或者学习资料可以参考的吗?
请问开发仙侠道项目的时候服务器的人员配置大概是几人
Go 在游戏行业的优势有以下几点:
但是我提倡技术选型要按团队实际情况来,不能单看技术本身的优点,有时候优点在一定条件下也会变成缺点。
选型时需要考虑团队人员配置是怎么样的,以往项目经验是怎么样的,所要开发的项目是怎么样的,从成本、风险、回报的角度综合的判断一项新技术的引入。
选型时主要就是内心想清楚一个问题:我想要达到哪些目的,为这些目的我要付出哪些代价。想清楚了就没问题。
对于开源框架,国外的我没有了解,国内的因为圈子比较小我倒是有了解一些,比如 gonet,leaf 等,还有我目前在整理的,应该算不少,我在 leaf 群里是管理员,每天都有人加群,可见大家学习热情很高。
对于框架我有一点想要说,我不推荐新手使用框架,如果是在项目上有熟悉框架的老手带那是另一回事,如果是自己做学习研究,建议是拿框架代码来学习,揣摩框架的设计意图,但不要上来就用框架,框架毕竟是层层封装过的,会让新手远离基本知识,基础没打好对将来进一步成长很不利。
因为目前 Go 新手会比较多,经常在群里看到一些基本知识没掌握导致的框架使用问题,我对此表示比较担心。
对于之前没有做过 c 项目的同学,建议开始 cgo 前,先补一下 c 的知识,掌握基本的编译链接知识,推荐《linux c 编程一站式学习》这本书。
然后就是看 go 的官方 cgo 文档了。
实际开发时候要注意 C 字符串的释放问题,Go 的野指针问题以及调用比例问题。
cgo 提供的 C.CString() 是会申请内存并拷贝 go 的字符串内容的,所以用完需要 C.free(),这个文档上其实有说,但这里还是要提醒一下。
Go 的野指针问题通常是因为 C 的指针指向的 C 结构体中某个字段引用了 Go 的指针,并且等着某个时候要用,但是 Go 这边已经没有任何地方再引用这个指针指向的内存了。这块内存会被 GC 判定成可回收,接着 C 这边再拿来用的时候就会出现各种奇怪问题。
新版 cgo 加强了严格性,但是如果黑魔法用太多还是容易失控的,需要小心。
如果实际项目对 c/c++ 的库采用 1:1 的 API 封装,需要小心评估调用频率,如果是高频次调用,建议换成 1:N 封装,就是在 c/c++ 这边把调用合并了,go 只要一次 cgo 调用的开销,这样可以降低开销又可以简化代码,我们游戏里面调用 lua 就是这样做的。
如果做长链接的手游,与 Unity 和 cocos2d-x 做的客户端,网络通信有什么比较好的解决方案吗? google 的 protobuf 理论上可以的,有方面的实践经验吗?谢谢。
请问下达达,之前我了解,你们用过 erlang。能不能谈谈为什么切换到 golang,以及两者在游戏开发中的优点,缺点。
protobuf 可以的,具体可以参考 leaf 中的示例。
以下是我之前在知乎上的回答。
项目立项时选择 Go 是有以下一些考虑的:
你好,最近也在了解游戏服务器端的开发,感觉遇到很多问题
请问一下达达,如果新手要进入开发游戏服务器端,那么应该具备哪些知识呢~
关于大服游戏架构
对于大服游戏,你可以在架构上把它简化成分服游戏,把玩家和游戏服对应关系交给账号服务器去记录,这样直接就把大服游戏的复杂度拉到分服游戏的水平线了。否则的话,考虑扩容,一致性哈希,故障转移,复杂度就几何级数增长上去了,你就会觉得 hold 不住。我的建议是先 hold 住,再优化。
关于计算逻辑
实时游戏的计算逻辑,可以有多种做法,最严格的是服务端计算,但是有时候由于网络条件限制,我们会选择客户端计算。
客户端计算又有两种不同的验证模式。
一种是强验证模式,客户端和服务端有一样的计算逻辑,只是服务端延后计算,这种模式的严格性基本等同于服务端计算,但是开发上需要小心规避通用逻辑服务端客户端各做一遍的情况,最好是把逻辑用 C 或 Lua 剥离出来实习,然后客户端服务端共享同一份代码。
还有一种是弱验证模式,弱验证模式就需要策划和程序一起想办法,安插检查点和关键数据监控。 对于你说到的分布式访问数据问题,大家都不喜欢分布式事务,因为很复杂又很难保证一致性,所以我们通常是通过一些取巧的方式规避掉分布式事务。
比如玩家大部分的数据操作其实是对自身数据的操作,所以我们把这部分业务定义为非互动业务,非互动业务固定只发生在玩家所属服务器,玩家所属服务器就是我前面说的账号服务器来记录的,这样玩家永远都在同一个服上游戏,缓存命中率是百分百,并且通过对玩家 ID 的分段处理,可以做到互动时通过玩家 ID 就可以对玩家所在服务器发起 RPC。
对于互动型业务,像多人副本这种,我们目前是让玩家所在服务器告诉客户端应该到那个服务器上游戏,客户端连接到互动服务器上游戏,就免掉了消息转发和频繁的 RPC,多人副本结果出来的时候一次 RPC 发放奖励到玩家所在服务器。
关于状态同步
对于你说的状态同步,如果是 arpg 类游戏,通常会做帧同步,大场景通常会做场景分割,这方面的资料网上有一些,可以搜索了解一下。有的项目不需要像 arpg 一样严格的位置同步,而只是希望制造一种互动体验,那就可以做一些延迟处理或者模拟移动。不同的实时性实现成本不一样,具体要根据业务需求来,不要盲目追求实时。
客户端和服务端通讯问题
因为客户端的表现不能被通讯阻塞,所以我们是异步的通讯模型。对于 gRPC 的使用,目前我们的顾虑是手游的热更新需求无法满足,对于不需要热更新或者配套的客户端热更新技术有了,gRPC 是没什么问题的。如果要做实时性很高的互动游戏,要实现帧同步又要实现可靠 UDP,那可能就需要自己造轮子了。
实时游戏的延迟
人可以感受到的延迟大概是 100ms,所以最好控制在 100ms 以内,超过了,可能玩的时候回觉得卡顿。
接口问题
游戏的业务接口非常多,基本上一个模块就会有十来个接口。每个业务的接口都是按需做的,没有通用的设计。
聊天服务器
聊天服务器有点像我前面说的互动业务的设计,如果玩家进入某个聊天服务器,是会把自身数据带一些过去的,比如昵称,等级,聊天消息中会带这部分数据,所以不会有分布式访问数据的问题。
最后总结
总的来说,有很多问题是可以简化的,不需要硬啃需求,有一些需求只是体验需要,制造同样的体验可以有很多变通做法,怎么简单怎么做,简单的东西好调整好维护,一开始就做复杂了反而比较危险,特别是需求还没出现的时候就自己想象将来会有某种需求,那样很容易就过度设计导致不必要的复杂性。
@dada 只能是学习了,空闲时间学习下游戏的东东。
达达大神,最近用 leaf 框架做游戏开发,遇到很多坑。之前我是写一般应用的,和游戏有很大区别。可以推荐本书看看吗
对于 Go 来说, 实现长连接卡牌手游, 是采用单用户一个或者多个协程处理该用户的逻辑模式, 还 是和传统 c/c++ 模式一样, 一个主逻辑线程, 处理本服内所有玩家的逻辑? 这两种方式哪种更合适?
Go 的 IO 接口设计直接就决定了要实现 IO 和业务逻辑异步,就必须用独立的两个 goroutine,一个负责读,一个负责写,至于读以后是交给另外一个 goroutine 处理还是直接就处理,可以自行选择。
至于业务要不要支持并行,也看自己选择,目前我们为了简化项目复杂度,采用的是顺序处理所有请求的结构,这种结构有一个前提,每个请求处理必须够快,并且不受 IO 阻塞影响,否则就会出现一个请求卡了整个游戏服的情况。
请问达达大神,入门游戏圈,需要哪些知识,是不是还有分方向,像你做服务端的是不是完全不用学习前端的东西
不是的啊,前端最好也是要懂的,要不然把握不了整体设计。
说的 leaf 是啥,给个链接?
老司机
请问下游戏服务器热更新有什么解决方案?
我喜欢玩游戏
想问下,做游戏后端,和做 web 有什么不异同点...也许这问题问的有些白痴 :)
看开源了很多类库,有没有把这些类库整合的 example 项目?
图片看了下,放 GIthub 了,加载真慢
对于有状态的游戏服务器,目前没有低成本热更新方案,除非进程的状态保存和恢复可以做到简单又高效。
对于无状态的游戏服务器,可以像 http 服务器一样用 grace 机制,就像 apache 的 graceful 指令,可以试试 facebook 开源的这个库:https://github.com/facebookgo/grace
对于有状态的游戏服,目前我们能做到的是提供一些机制重新加载模板数据和玩家数据,要重启只能靠运营发公告了。
@ 有鱼
文档和示例会陆续加上。
web 服务通常是无状态的,游戏通常会有持续的状态,所以游戏业务逻辑除了对数据的增删改查之外,跟 web 服务最显著的区别就是经常会跟持续状态打交道。
游戏因为实时性的需求,通常会有更重的缓存机制,甚至直接影响业务开发的方式,比如我们的游戏业务逻辑是直接操作缓存的。web 则通常是直接操作数据,缓存只是降低数据库查询压力。
游戏在通讯过程中通常还会需要用到二进制数据处理相关知识,这部分知识通常做 web 开发是不需要用到的。
游戏有很多需求实现是需要技巧的,比如一个天赋树的实现,需要同时满足数据可以结构化存储和操作,游戏内战斗时可以快速汇总数值等多个需求,这些经常需要脑筋急转弯变着法子实现,这一点跟应用开发和网站开发也有很大区别。
go 不能热更是怎么弄的呢? 比如突然出现一个漏洞被人刷道具,需要紧急修复。这个时候要紧急停服吗?
请问达达,如果要那有什么学习渠道进入游戏服务器端吗~~
是的
找相关工作,呵呵
问题是找不到吧,如果是别的转过来,没经验,别人也不要你...关键是看完了书,没需求练手,也是学不会的,自己摸索了 1 个月,理论的东西是看完了,但是....你懂的~求达神指条明路.
昨天晚上刚看了达达在 Gopher China 2016 上面的演讲~
@haozibi 是 达达在 Gopher China 2015 上的演讲吧:《Go 语言在游戏项目上的应用》附上演讲地址:http://www.imooc.com/video/7915
记得达达原来是搞 PHP 的啊
之前我是写一般应用的,和游戏有很大区别。geometry dash
请问你们游戏的自动化测试是怎么做的?