1
wujianhua22 2 天前
go 没有服务端热更的方案,你说的都是开发阶段热更的方案。
|
2
DefoliationM 2 天前 via Android
无,要么 wasm ,建议结合 k8s 使用,可以滚动更新,业务不中断。
|
3
fffq 2 天前
golang+lua
|
4
MoYi123 2 天前
有状态服务更新用 erlang 热更新都挺麻烦的, go 基本不可能了.
|
5
guanzhangzhang 2 天前
mosn 的那个可以借鉴下,包括监控 metrics 都可以不听,Prometheus 监控都不会告警
|
6
htxy1985 OP @guanzhangzhang @DefoliationM 老哥能不能稍微展开说下,感谢
|
7
flyqie 2 天前 via Android
golang 因为语言特性的原因,热更不好做。
你要不试试楼上说的 lua 做 logic ,go 做 framework ? |
8
guanzhangzhang 2 天前
@htxy1985 你谷歌搜下 Mosn 热更新,有 ppt 的,之前 gopher 大会听过蚂蚁金服他们讲的,用到的技术可以看下和语言无关的
|
10
dogfood 2 天前
go+quickjs
|
11
htxy1985 OP @guanzhangzhang 感谢,大致看了一下,我理解的这个东西类似网关层的东西,抛开核心技术思路,他的解决方式是老的服务向新的服务进行无损迁移,而不是在线热修代码。这个东西可能有一定学习和落地的成本,我这边再看看。
@flyqie 可以是可以,但这里面有个改造成本问题,一时间不好弄成这样 |
12
crackidz 2 天前
K8s 或者 Kamal 都有类似的解决方案啊...
|
13
southwolf 2 天前
正常人的做法不都是滚动更新发布新版本服务? 打断几个请求不是太大问题吧, 啥业务啊这么重要还需要在线修 bug...
|
15
adoal 2 天前
可以换个思路,不热更,被中断的用户如果投诉了赔些游戏豆
|
16
standchan 2 天前
额,k8s 的滚动更新好像就可以了吧
|
17
james122333 2 天前 via Android
做成 cgi 或者全反射写法
|
18
Sendya 2 天前 via Android 4
如果是 tcp 服务,可以用 cloudflare tableflip 做热更新,新二进制替换老二进制之后,发送 USR2 信号,双进程都会服务 tcp 监听,直到老进程的 tcp 连接全部都服务完断开,由新进程完全接管。
我这边项目用了很久这相关的功能了。 就跟 nginx 的 USR2 信号行为差不多 |
19
aladdinding 2 天前
没有什么是不能在加一层就解决的
|
20
dzdh 2 天前
另外一个方案是 systemd 接管 socket tcp 数据会经过内核绕一下子。
|
21
maocat 2 天前 via Android
啊,楼主的根本问题不是排查 bug 吗,热更只是一个路子,日志埋点排查业务 bug ,程序启用 pprof 查看系统 profile 信息,这不才是正经路子吗
|
22
sagaxu 2 天前 1
hotswap 也就开发环境用用,保证不了原子性和正确性。A 任务处理到一半,然后开始热更新,系统应该怎么处理?
所以现在主流更新,都是先从网关把目标机器的流量切走再更新,再灰度把流量切过去。 |
23
ben1iu 2 天前 1
go 有状态的热更 没有很好的办法 只能架构层面把 网关拆出去 网关后面的服务 新连接走新逻辑 旧的等连接断开不再接受新请求
go plugin 方式的热更 需要从代码结构拆分 不推荐 |
24
zihuyishi 2 天前
根据网游的经验,就是先上更新的服务器,不给旧的导流量,然后在 deadline 时把旧的切掉。
实际操作就是 k8s 上新 pod ,然后下旧 pod 。 |
25
pluswu1986 2 天前 2
1. goplugin 逻辑和状态分离,2. 大状态能且成足够小的粒度,用 config_route_shard 思路迁移小粒度对象,3. 大状态无法切割用 replicate 主副代理切换 理论上 3 种都能做到无损热更, 如果逻辑和状态强耦合(游戏服务器一般都是这种) 神都救不了, 各种原地热更都是邪教
|
26
Kauruus 2 天前
这还是从架构角度去整吧。
有状态服务,无论如何都要处理断线重连、重启的状态迁移问题。 新启一个实例,状态迁移过去,例如发消息给客户端,让它们连到新的实例。 |
27
sunny352787 2 天前 3
同行告诉你,没有
我这边的做法是无状态服务器,数据都塞 redis 里,实时性比较高的拆出去,比如 PVP 单独开一服,打完就断掉连接 如果你是做 ARPG 或者大世界之类的一定要保持长连接,那就加一层网关,后面连接逻辑服可以接收信号将数据用某种方式(比如 redis 中转)迁移到新进程然后再杀掉自己,这种方法以前写 C++时候就这么干 你想完全保存内存状态的迁移本质上不现实,代码更新了内存布局肯定有变化,非脚本语言不可能完美迁移的,脚本语言也只能迁移一部分逻辑内存数据变了也是不行的 |
28
bruce0 2 天前
看很多人的回答, 应该是没做过游戏这类的服务器开发, 楼主说的热更方案我之前也查了很多, 纯 go(不用 lua 和 js 这些脚本语言辅助)写的 有状态服务, 目前应该没有好的热更方案, 看很多人说加一个中间层, 这个真没法加,因为游戏的 server 进程有太多的全局状态和数据, 没法做到无感分层(或者非常难) 还有 k8s 滚动更新,这个更不靠谱了, web 这种无状态的服务还可以
说一下我之前了解到的"热更"方案 1. 双进程.类似 Nginx 的 reload, 新开一个进程, 新玩家连接到新的进程,老进程只处理老玩家数据,等所有人都下线,自动退出. 这个方案不太可行, 像是游戏内的全局数据, 跨进程同步比较难搞, 全新设计的游戏可以尝试,老游戏没戏,约等于重写 2. 使用 go plugin, 这个方案对代码改动也不小, 而且 go 的 plugin 官方维护也不积极,还有很多不稳定的东西, 而且使用起来也不方便, 还不如 C/C++ 动态加载 .so 文件好用. 这两个是我了解到的方案, 都不太好, 再拓展一下, 其实游戏内的很多热更只是更新策划表, 一般是 json,xml 的文件, 这时候可以在游戏内做一个命令, 比如游戏主逻辑内监听一个 web 端口, 收到 web 的命令后重新加载一下所有的表格文件.如果是更新游戏内的逻辑,修复 bug, 没办法. 有一种是游戏类型决定的, 像是 吃鸡, moba 这类的房间型游戏, 其实不用考虑热更, 这局对战完成后, 新的游戏直接用新的二进制启动就行了.像是 mmo 这类的, 如果硬要热更, 只能上 lua,js 这些脚本语言来辅助了. |
29
yc8332 2 天前
好像没办法吧。。。有状态的感觉是更不了或者说成本很高,而且要一开始就是设计好。。反正现在我们是直接重启,主要是 pvp 的对战或者组队服务
|
30
hackroad 2 天前
蓝绿、A/B
|
31
p1gd0g 2 天前
有状态是大坑啊,还是早点改吧
|
32
renshengluguo 2 天前
参照英雄联盟的更新方式如何
|
33
rrfeng 2 天前
vm 都可以在线迁移,go 肯定也可以,只要你肯花时间 🐶
|
34
rrfeng 2 天前
@renshengluguo 一局游戏就是最大的不可更新时间了,完全没必要热更。MMO 才需要
|
35
luaex 2 天前
我之前用过 go plugin + hook 的方案,plugin 主要是用来加载 so ,然后 hook 要修改的函数,跳转到新的 so 里面的函数去执行
|
36
hongjic93 2 天前 via iPhone 1
goplugin (同一个进程,动态链接库),sidecar (不同进程,ipc ),wasm (进程内部 sandbox ) 。 第一个坑很多,ipc 很麻烦,wasm 最理想,但不成熟( golang 已经支持 wasi 编译)
|
37
htxy1985 OP 感谢各位的指教
|
38
realpg 1 天前
@southwolf #13
滚动更新版本,如果不涉及 websocket 超长连接,或者纯 tcp 业务,设计好都不会打断请求,都是平滑的 如果设计的好,tcp 长连接都可以不打断 这边就有业务有完全不能缺请求的要求 golang 做的 目前没问题 |
39
southwolf 1 天前 via Android 1
@realpg 所以还是有前提的嘛, rolling update 可以满足 zero downtime, 也就是旧 pod 承接现有连接,新连接去到新 pod, 但并不能保证旧连接能无缝迁移到新版本, 就是楼主要的在线更新
另外有种玩法, 就是状态信息放在外部, 然后客户端跟服务端搞个双向心跳, 挂了再由另外的服务端重新连接, 但这么一搞工作量又更大了😂 |
40
realpg 1 天前 1
@southwolf #39
我们的 api server 同时处理长短连接 在逻辑层,api server 可以接收一个外部信号 这个外部信号接收到以后,就会在 slb 的 service check api 中返回自己已经故障了 但是正常提供服务 这样 SLB 就不会发新的请求过来,这样基本只要 30 秒,就不太会有新的短 http 请求到这个 backend 了 长连接是在逻辑层实现的,一旦这个服务端接收到了外部信号,服务端的长连接就会通知客户端我要死了 你现在跟一个新的后端建立连接,建立连接后,有交接逻辑,在某个信号以后,就全跟新连接通信 这样基本上只要这个 signal 过来 60 秒,就可以完全无感停服务了 |
42
me1onsoda 1 天前
游戏热更是硬需求吧,搞不懂为啥那么多游服喜欢用 go 开发
|
45
linuxsuren 1 天前
https://github.com/LinuxSuRen/api-testing 基于 gRPC 实现的插件系统
|