GoCN第一期《老司机带你看Go风景》——游戏达人达达

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,达达会在空闲时间上来给大家一一回答。

已邀请:

dada

赞同来自: wener chengzhi astaxie su21

@wener




  • 关于大服游戏架构


    对于大服游戏,你可以在架构上把它简化成分服游戏,把玩家和游戏服对应关系交给账号服务器去记录,这样直接就把大服游戏的复杂度拉到分服游戏的水平线了。否则的话,考虑扩容,一致性哈希,故障转移,复杂度就几何级数增长上去了,你就会觉得hold不住。我的建议是先hold住,再优化。




  • 关于计算逻辑


    实时游戏的计算逻辑,可以有多种做法,最严格的是服务端计算,但是有时候由于网络条件限制,我们会选择客户端计算。


    客户端计算又有两种不同的验证模式。


    一种是强验证模式,客户端和服务端有一样的计算逻辑,只是服务端延后计算,这种模式的严格性基本等同于服务端计算,但是开发上需要小心规避通用逻辑服务端客户端各做一遍的情况,最好是把逻辑用C或Lua剥离出来实习,然后客户端服务端共享同一份代码。


    还有一种是弱验证模式,弱验证模式就需要策划和程序一起想办法,安插检查点和关键数据监控。
    对于你说到的分布式访问数据问题,大家都不喜欢分布式事务,因为很复杂又很难保证一致性,所以我们通常是通过一些取巧的方式规避掉分布式事务。


    比如玩家大部分的数据操作其实是对自身数据的操作,所以我们把这部分业务定义为非互动业务,非互动业务固定只发生在玩家所属服务器,玩家所属服务器就是我前面说的账号服务器来记录的,这样玩家永远都在同一个服上游戏,缓存命中率是百分百,并且通过对玩家ID的分段处理,可以做到互动时通过玩家ID就可以对玩家所在服务器发起RPC。


    对于互动型业务,像多人副本这种,我们目前是让玩家所在服务器告诉客户端应该到那个服务器上游戏,客户端连接到互动服务器上游戏,就免掉了消息转发和频繁的RPC,多人副本结果出来的时候一次RPC发放奖励到玩家所在服务器。




  • 关于状态同步


    对于你说的状态同步,如果是arpg类游戏,通常会做帧同步,大场景通常会做场景分割,这方面的资料网上有一些,可以搜索了解一下。有的项目不需要像arpg一样严格的位置同步,而只是希望制造一种互动体验,那就可以做一些延迟处理或者模拟移动。不同的实时性实现成本不一样,具体要根据业务需求来,不要盲目追求实时。




  • 客户端和服务端通讯问题


    因为客户端的表现不能被通讯阻塞,所以我们是异步的通讯模型。对于gRPC的使用,目前我们的顾虑是手游的热更新需求无法满足,对于不需要热更新或者配套的客户端热更新技术有了,gRPC是没什么问题的。如果要做实时性很高的互动游戏,要实现帧同步又要实现可靠UDP,那可能就需要自己造轮子了。




  • 实时游戏的延迟


    人可以感受到的延迟大概是100ms,所以最好控制在100ms以内,超过了,可能玩的时候回觉得卡顿。




  • 接口问题


    游戏的业务接口非常多,基本上一个模块就会有十来个接口。每个业务的接口都是按需做的,没有通用的设计。




  • 聊天服务器


    聊天服务器有点像我前面说的互动业务的设计,如果玩家进入某个聊天服务器,是会把自身数据带一些过去的,比如昵称,等级,聊天消息中会带这部分数据,所以不会有分布式访问数据的问题。




  • 最后总结


    总的来说,有很多问题是可以简化的,不需要硬啃需求,有一些需求只是体验需要,制造同样的体验可以有很多变通做法,怎么简单怎么做,简单的东西好调整好维护,一开始就做复杂了反而比较危险,特别是需求还没出现的时候就自己想象将来会有某种需求,那样很容易就过度设计导致不必要的复杂性。



dada

赞同来自: xiao_song lanslot chengzhi

@xiao_song


以下是我之前在知乎上的回答。


项目立项时选择Go是有以下一些考虑的:



  1. 前一个项目用Erlang开发的,活动时间一到,密集运算CPU就受不了,这点很不满意

  2. 项目过程中出现过补人难的情况,听过Erlang并愿意转Erlang的人少,招来了培训到加入开发又要一段时间

  3. 因为前两点,所以新项目想找一个解决性能问题又解决人员问题的技术方案

  4. 我自身没有C/C++项目经验,只会点皮毛语法,短时间要上手并拿出可用的框架不现实

  5. C/C++开发人员我们这也不好招

  6. 那会正好Go 1.0即将发布,我估摸着项目上线后Go还会更完善,有点赌一把的意思

  7. 我给自己设想的最坏情况是Go不行的时候可以用CGO补救,当时考虑比较多的是性能,但实际上性能没问题,倒是用CGO做了GC优化,补救了自己最初设计上的不合理。

  8. Go的语法元素非常之少,并且是类C的命令式语音,又有Google这个开发人员心中形象完美的亲爹,人员补充上应该比Erlang容易

wener

赞同来自: itfanr astaxie

你好,最近也在了解游戏服务器端的开发,感觉遇到很多问题



  1. 现在服务器架构的时候会有分布式的情况么,比如整个游戏就在一个大服务器上,而不是分区分服务,在大服中可能有大量的在线玩家.

  2. 实时游戏的计算是否都是在内存中演算出来的

    • 比如说动作类游戏,只是将动作传输内后台,然后由后台计算出新的玩家状态还是在客户端计算好最终结果传递给后端 ?

    • 这两者之间有什么明确的界限么,该如何进行选择 ?

    • 如果全都在内存中演算,那么是否就无法做到分布式,因为计算这样的内容需要非常迅速,就必须需要分服?


  3. 玩家在游戏地图中的位置在服务器端是如何处理的呢

    • 如果基于上一条理论,那么玩家在游戏中的位置也是实时更新和跟踪的,那么是否和 geo 的处理也类似呢?

    • 是如何做到快速的为玩家位置进行跟踪查询的 ?

    • 如何更新玩家视野中其他玩家的位置 ?

    • 推送给玩家的数据时什么样的 ?

    • 你们一般是怎么做的呢 ?


  4. 客户端与服务器的交互一般是同步的还是异步的 ?

    • 我想使用 gRPC 来做通讯协议有什么问题么 ?


  5. 实时游戏时,延迟一般控制在多少合适 ?

    • 一般延迟最主要会花费在哪里?


  6. 游戏服务器开发时是否会有多套接口 ?

    • 比如实时的接口,推送地图上的其他玩家位置更新 - 由服务器端推送

    • 获取用户详情的接口 - 请求响应

    • 玩家交互操作(攻击?),这类操作比较特殊?

    • 聊天服务器


  7. 聊天服务器在做分布式时,主要会遇到什么样的问题?

    • 我理想中的聊天服务器是会把用户关联 ID 全都加载到内存中的,比如用户有哪些好友,房间中有哪些好友,主要是为了方便判断,处理分发等

    • 这样能够很容易的做分布式,但是也会受到最大量的限制


dada

赞同来自: foreversmart lintBai

@Elson


基本功越扎实越好,语言特性,语言运行时库,数据结构和算法,计算机组成原理,网络相关知识。


另外非常重要的是要喜欢游戏。

dada

赞同来自: bingohuang

@bingohuang


Go在游戏行业的优势有以下几点:



  1. CPS模型对并发业务的简化作用

  2. 语法要素少,历史包袱少,项目容易控制,容易培养人

  3. 配套的线上调优工具齐全,产品上线后容易及时发现问题并调整

  4. 环境依赖极低,部署简单方便


但是我提倡技术选型要按团队实际情况来,不能单看技术本身的优点,有时候优点在一定条件下也会变成缺点。


选型时需要考虑团队人员配置是怎么样的,以往项目经验是怎么样的,所要开发的项目是怎么样的,从成本、风险、回报的角度综合的判断一项新技术的引入。


选型时主要就是内心想清楚一个问题:我想要达到哪些目的,为这些目的我要付出哪些代价。想清楚了就没问题。


对于开源框架,国外的我没有了解,国内的因为圈子比较小我倒是有了解一些,比如gonet,leaf等,还有我目前在整理的,应该算不少,我在leaf群里是管理员,每天都有人加群,可见大家学习热情很高。


对于框架我有一点想要说,我不推荐新手使用框架,如果是在项目上有熟悉框架的老手带那是另一回事,如果是自己做学习研究,建议是拿框架代码来学习,揣摩框架的设计意图,但不要上来就用框架,框架毕竟是层层封装过的,会让新手远离基本知识,基础没打好对将来进一步成长很不利。


因为目前Go新手会比较多,经常在群里看到一些基本知识没掌握导致的框架使用问题,我对此表示比较担心。

dada

赞同来自: gameogre

@gameogre


protobuf可以的,具体可以参考leaf中的示例。

chengzhi - 我本楚狂人,凤歌笑孔丘

赞同来自: itfanr

达达大神,最近用leaf框架做游戏开发,遇到很多坑。之前我是写一般应用的,和游戏有很大区别。可以推荐本书看看吗

dada

赞同来自: xiao_song

@lkm1107


Go的IO接口设计直接就决定了要实现IO和业务逻辑异步,就必须用独立的两个goroutine,一个负责读,一个负责写,至于读以后是交给另外一个goroutine处理还是直接就处理,可以自行选择。


至于业务要不要支持并行,也看自己选择,目前我们为了简化项目复杂度,采用的是顺序处理所有请求的结构,这种结构有一个前提,每个请求处理必须够快,并且不受IO阻塞影响,否则就会出现一个请求卡了整个游戏服的情况。

bingohuang - bingohuang.com

赞同来自: itfanr

@haozibi 是 达达在 Gopher China 2015 上的演讲吧:《Go 语言在游戏项目上的应用》 附上演讲地址:http://www.imooc.com/video/7915

chenqinghe - Gopher/PHPer

赞同来自:

来支持一下!


之前就在知乎上看到过@达达的这个回答Go 的垃圾回收机制在实践中有哪些需要注意的地方,感觉挺好的,受益匪浅,就果断收藏了。没想象到又在这里见到达达大大了。


顶达达,顶谢大!

domac - life should be func

赞同来自:

一路走来,经常看达达的黑魔法。除了游戏,以前学协议相关的,也是学习 达达 的 link

dada

赞同来自:

欢迎提问

bingohuang - bingohuang.com

赞同来自:

我先来热个场,@达达

Go 在做游戏开发方面有什么优势吗?国内外是否有用 Go 开发的游戏开源框架?

astaxie - 创造、获取、分享、传播和应用Go

赞同来自:

一直想在CGO方面有所提升,虽然CGO不那么好用,但是掌握这方面知识也是为了知道什么时候该用CGO,什么时候不该用CGO,请问有什么资料或者学习资料可以参考的吗?

endless

赞同来自:

请问开发仙侠道项目的时候服务器的人员配置大概是几人

dada

赞同来自:

@astaxie


对于之前没有做过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就是这样做的。

gameogre - 游戏魔兽

赞同来自:

如果做长链接的手游,与Unity 和 cocos2d-x 做的客户端,网络通信有什么比较好的解决方案吗? google 的 protobuf 理论上可以的,有方面的实践经验吗?谢谢。

xiao_song - 小宋—成都

赞同来自:

请问下达达,之前我了解,你们用过erlang。能不能谈谈为什么切换到golang,以及两者在游戏开发中的优点,缺点。

Elson - Go开发者

赞同来自:

请问一下达达,如果新手要进入开发游戏服务器端,那么应该具备哪些知识呢~

zituocn

赞同来自:

@dada
只能是学习了,空闲时间学习下游戏的东东。

lkm1107

赞同来自:

@dada


对于Go来说, 实现长连接卡牌手游, 是采用单用户一个或者多个协程处理该用户的逻辑模式, 还 是和传统c/c++模式一样, 一个主逻辑线程, 处理本服内所有玩家的逻辑? 这两种方式哪种更合适?

lanslot - 80后IT

赞同来自:

请问达达大神,入门游戏圈,需要哪些知识,是不是还有分方向,像你做服务端的是不是完全不用学习前端的东西:smile:

dada

赞同来自:

@lanslot


不是的啊,前端最好也是要懂的,要不然把握不了整体设计。

有鱼

赞同来自:

说的 leaf 是啥,给个链接?

owen

赞同来自:

老司机

xuej

赞同来自:

请问下游戏服务器热更新有什么解决方案?

erbajie - 程序员接私活请戳:http://www.mayigeek.com/

赞同来自:

我喜欢玩游戏

zituocn

赞同来自:

想问下,做游戏后端,和做web有什么不异同点...也许这问题问的有些白痴 :)

有鱼

赞同来自:

看开源了很多类库,有没有把这些类库整合的example项目?

有鱼

赞同来自:

图片看了下,放GIthub了,加载真慢

dada

赞同来自:

@xuej


对于有状态的游戏服务器,目前没有低成本热更新方案,除非进程的状态保存和恢复可以做到简单又高效。


对于无状态的游戏服务器,可以像http服务器一样用grace机制,就像apache的graceful指令,可以试试facebook开源的这个库:https://github.com/facebookgo/grace


对于有状态的游戏服,目前我们能做到的是提供一些机制重新加载模板数据和玩家数据,要重启只能靠运营发公告了。

dada

赞同来自:

@有鱼


文档和示例会陆续加上。

dada

赞同来自:

@zituocn


web服务通常是无状态的,游戏通常会有持续的状态,所以游戏业务逻辑除了对数据的增删改查之外,跟web服务最显著的区别就是经常会跟持续状态打交道。


游戏因为实时性的需求,通常会有更重的缓存机制,甚至直接影响业务开发的方式,比如我们的游戏业务逻辑是直接操作缓存的。web则通常是直接操作数据,缓存只是降低数据库查询压力。


游戏在通讯过程中通常还会需要用到二进制数据处理相关知识,这部分知识通常做web开发是不需要用到的。


游戏有很多需求实现是需要技巧的,比如一个天赋树的实现,需要同时满足数据可以结构化存储和操作,游戏内战斗时可以快速汇总数值等多个需求,这些经常需要脑筋急转弯变着法子实现,这一点跟应用开发和网站开发也有很大区别。

fengche

赞同来自:

go不能热更是怎么弄的呢?
比如突然出现一个漏洞被人刷道具,需要紧急修复。这个时候要紧急停服吗?

Elson - Go开发者

赞同来自:

请问达达,如果要那有什么学习渠道进入游戏服务器端吗~~

dada

赞同来自:

@fengche


是的

dada

赞同来自:

@Elson


找相关工作,呵呵

Elson - Go开发者

赞同来自:

问题是找不到吧,如果是别的转过来,没经验,别人也不要你...关键是看完了书,没需求练手,也是学不会的,自己摸索了1个月,理论的东西是看完了,但是....你懂的~求达神指条明路.

haozibi - 会Go的母猪饲养员

赞同来自:

昨天晚上刚看了达达在Gopher China 2016 上面的演讲~

hoosin - Gopher

赞同来自:

记得达达原来是搞 PHP 的啊

要回复问题请先登录注册