首页
学习
活动
专区
圈层
工具
发布
50 篇文章
1
图文并茂VLAN详解,让你看一遍就理解VLAN
2
做了几年的网工也未必了解VLAN和VXLAN的区别,今天我来告诉你!
3
全网内容最全,质量最高的MPLS及MPLS VPN技术详解,瑞哥力荐!
4
Google BBR拥塞控制算法背后的数学解释 | 深度
5
QUIC 0-RTT实现简析及一种分布式的0-RTT实现方案
6
AGPS定位基本原理浅析
7
Golang语言情怀-第56期 Go 语言标准库翻译 crypto/cipher
8
神锁离线版插件端到端加密比HTTPS更安全
9
基于 TLS 1.3的微信安全通信协议 mmtls 介绍(上)
10
基于 TLS 1.3的微信安全通信协议 mmtls 介绍(下)
11
24位腾讯云专家精彩演讲,4万字《腾讯云技术实践精选集 2021》发布!(附合集下载)
12
浅谈VPC二三,秒懂秒透
13
提速 30%!腾讯TQUIC 网络传输协议
14
25 张图,一万字,拆解 Linux 网络包发送过程
15
nginx http模块数据存储结构
16
多机房多活,多机房平滑迁移架构方案全集(上+中+下)
17
小孩都看得懂的多臂老虎机和汤姆森采样
18
什么是 Go runtime.KeepAlive?
19
Rust 热点| Discord 为什么从 Go 切换到了 Rust
20
用户态 tcpdump 如何实现抓到内核网络包的?
21
一文读懂 | coredump文件是如何生成的
22
网工知识大扫盲——三层交换技术
23
聊聊 top 命令中的 CPU 使用率
24
什么是HDFS的纠删码
25
Linux ptrace 的实现
26
天天讲路由,那 Linux 路由到底咋实现的!?
27
Linux系统研究 - 操作系统是如何管理tcp连接的 (2)
28
一个有关tcp的非常有意思的问题
29
对上一篇文章中tcp问题的进一步思考
30
epoll和shutdown使用不当可能导致死循环
31
socket的SO_REUSEADDR参数全面分析
32
多进程可以监听同一端口吗
33
golang | 是返回struct还是返回struct的指针
34
​TCP 拥塞控制详解
35
C|网络|TCP-BBR拥塞控制剖析
36
如何使用 Go 语言写游戏服务器?
37
Nginx 日志 worker_connections are not enough while connecting to upstream
38
如何用九条命令在一分钟内检查Linux服务器性能?
39
服务器病了吗? Linux 服务器的那些性能参数指标
40
边缘计算比云计算强在哪里?终于有人讲明白了
41
详解边缘计算系统逻辑架构:云、边、端协同
42
边缘计算成为下一个爆发点,云计算巨头和CDN巨头谁会赢?
43
告知你不为人知的 UDP:连接性和负载均衡
44
为什么需要智能网卡?
45
从CDN到边缘计算,近水楼台是否先得月?
46
经典网络还是VPC,开发者作何选择?
47
Linux内核网络udp数据包发送(二)——UDP协议层分析
48
有没有人告诉你—写时拷贝的真相
49
[linux][network]net bridge技术分析
50
软硬件融合技术内幕 进阶篇 (1) —— 从小霸王到云计算

如何使用 Go 语言写游戏服务器?

之前先后用Erlang,nodejs做过tcp,http的游戏服务器。接触了golang一两个月(纯新手),想在最近的tcp网游项目中使用,但又担心以下问题: # 如何高性能的搭建tcp底层,并且能负载到同时在线N多人 # 如何架构整个服务器端(包括网络层,缓存层,持久化层,日志层,逻辑分发处理层,通信协议层,以及如何有效部署) # goroutine间如何高效通信 # 担心go1.5版本及以后的gc问题 # 如何调试程序和快速定位线上问题 # 压力测试负载能力 希望用过golang的前辈给出一些建议~~

作者:达达 链接:http://www.zhihu.com/question/35385236/answer/62654548 来源:知乎 著作权归作者所有,转载请联系作者获得授权。

谢邀,昨天就有看到这问题,因为题太大不知道从何答起,所以就没答,今天易伟前辈邀请,不答不行了。 真有趣团队是从Go 1.0开始使用Go开发游戏服务端的,所以小经验有点,但是我们还处在不断学习摸索的阶段,所以太高深的学问不多,下面我就按题主的问题顺序尝试一个个的回答吧: # 如何高性能的搭建tcp底层,并且能负载到同时在线N多人 Go自身在特定平台会使用对应平台的io重用方案,比如epoll,kqueue等,所以底层部分效率已经不错了,比起自己用C/C++去封装底层或调用libevent之类的库,优势是Go将事件机制封装成了CSP模式,编程变得方便了,但是需要付出goroutine调度的开销,在游戏项目上实践的经验是调度开销可接受,无需做额外工作来优化。如果自己要在Go里面调用epoll重新封装一个网络层,这样做所能提升的效率和付出的代价对比起来,性价比太低了,不值得这么做。 所以用Go搭建TCP底层是很省事的,主要关注几个点: 1. 尽量减少系统的IO调用次数,比如使用bufio这个包来减少实际IO次数 2. 尽量减少不必要的数据拷贝,比如消息的封包解包过程,细心点设计是可以做到极少的数据拷贝的 3. IO阻塞时的边界情况处理,比如一个请求处理过程中,如果消息回发导致处理过程阻塞,是否会影响到其他后续请求,又或者广播过程中消息发送阻塞,是否应该把阻塞的连接关闭等 我这有个简单的库可以提供参考:funny/link · GitHub # 如何架构整个服务器端(包括网络层,缓存层,持久化层,日志层,逻辑分发处理层,通信协议层,以及如何有效部署) 这个议题挺大的,但是题主已经明确罗列出了这些项目层级和模块划分,说明是已经有经验的了。Go语言跟其他语言一样分层分模块,没太大特别之处。 Go在组织游戏项目的时候有一点需要提前预防,就是业务模块间的递归引用。Go从语法上是禁止包递归引用的。但是游戏的业务模块很多,交叉是很平常的事情,所以需要提前设计一个项目结构来防止业务上的交叉碰到Go的语法限制。 具体的代码我就不写在这边了,思路就是通过公共接口的注册来解耦包的引用关系,我这边有个演示项目可以参考一下,并没有什么高深的设计在里面,就是一个脑筋急转弯而已。funny/go-project-demo · GitHub 缓存层、持久层的实现方式不同团队差异巨大,这边我能分享的经验只有一点,就是尽量不要人工去维护缓存和持久化之间的关系,尽量做成自动的,这样才不会人工引发BUG导致数据损坏。 如果要说具体说法,我们目前是MySQL做持久存储,这样做数据分析和备份什么的都比较方便也比较可靠。缓存则是根据MySQL的结构自动生成代码映射到Go里边的。 Go做大数据量的缓存的时候需要小心GC的负载,如果你的缓存设计是内存吃得多但是对象很少,就不用担心这一点。如果是像我一样一条MySQL数据对应一个Go对象到内存里的,就要小心处理,要嘛做成按需加载的,减少对象数量。要嘛就是干脆用堆外内存来存储缓存数据,这样GC不会有负担。堆外内存的一些技巧我之前网上也有分享过了,原理比较简单,就是用cgo机制让C来分配内存。 通讯层也是各个项目差异很大的部分,我们团队是自己实现一套二进制协议格式,也有团队是用protobuf,也有用json,各式各样都有。这个按个人喜好和传统来做就可以了,差异不会差到哪里去的。 如果做自定义格式的协议,我这有个二进制操作的库可以用用:funny/binary · GitHub 部署方面其实跟语言无关,单进程的结构都很好运维和部署,多进程都会麻烦一些,所有语言都一样的,这方面我没有太值得分享的经验。 # goroutine间如何高效通信 goroutine就是靠chan通讯了,没什么好办法。如果关心goroutine通讯的各种开销,最好是按自己的应用场景测试看看。 有些场景下chan通讯是不划算的,比如一个简单的map数据获取,可能用锁就可以了。有些场景用chan是必须的,比如做个多人互动功能。 还有就是带buffer的chan和不带buffer的chan的差异,最好通过试验来让自己有个直观认识,除了异步和同步的差异,还会有边界情况的处理差异,比如带buffer的chan阻塞了,在功能设计上需要考虑,否则可能引发严重问题,这个上面其实也讲了。 # 担心go1.5版本及以后的gc问题 如果有这个担心,就最好从项目初期就提前预防,比如从设计上就避免产生大量对象,或者就是前面说的堆外内存分配,或者是通过多进程结构来分散负担。 还有就是提前做好测试,对量级有个心理预期。 游戏已经比实时交易系统好很多了,正常的用Go是不用担心GC延迟导致服务质量不符合需求的,游戏会产生大量对象的地方就是缓存了,这个地方小心设计基本上就没什么问题了。 1.5版本的GC我还没测试过,因为用了堆外内存,现在不怎么关心这个了。。。 # 如何调试程序和快速定位线上问题 调试Go确实有点麻烦,如果要用GDB调试Go,你最好关掉Go的编译优化,否则可能出现调试不了的情况。另外就是靠打印了,所以我们项目里面有这样一个模块:funny/debug · GitHub 线上问题定位要靠提前留好定位措施来实现,最常用的就是排查死锁和排查内存泄漏,可以参考一下这个模块:funny/pprof · GitHub 死锁的时候通过lookup goroutine来获取所有goroutine的堆栈跟踪信息,然后排查死锁的原因。 内存泄漏或者效率问题通过cpuprof和memprof来定位问题:Go语言程序的状态监控 保存cpuprof和memprof的工具函数在 funny/pprof 包里也有。 # 压力测试负载能力 游戏的完整压力测试我没做过,感觉没法做,游戏操作逻辑太复杂了。所以我的测试方式是对逐个可能成为瓶颈的点做benchmark或对算法做benchmark,来估计一个整体的效果。 另外就是开发期间持续监控所有请求的响应时间,我们团队的要求是在小于1毫秒,实际线上平均是30多微秒(不包含IO过程),有这样的响应速度,应该不用担心负载问题,如果有负载问题,会在请求执行时间上暴露出来。 用来监控请求执行时间的模块也在这个包里:funny/pprof · GitHub 能力范围内只能回答这些了,我最近在研究怎么进一步提高开发和运维的整体效率,所以感觉自己还很多东西不懂,懂的只是一些皮毛的东西,当抛砖引玉了。

下一篇
举报
领券