游戏服务器和中间件

2021-11-08 16:04:53 +08:00
 goforwardv2

一直对中间件感兴趣,想把它应用到自己的项目中。本人是做游戏服务器的。但好像场景有点不符合。我的场景大致如下:

接入服务器 AccessSvr(用户通过 tcp 连接)和游戏服务器 GameSvr 之间通过 proxy 进行消息的通信。且消息都是双向的(request/response)。AccessSvr 和 GameSvr 都可以部署多台。AccessSvr 转发用户请求到 Gamesvr 时 proxy 负责负载均衡到某一个 Gamesvr 。Gamesvr 处理完成后要回发 response 到对应的 Accesssvr(哪个 AccessSvr 发出的就回发到哪个 AccessSvr ,因为要找到对应的用户 tcp 连接)。但这样做有一个问题就是 proxy 存在单点故障。所以我尝试把 proxy 替换成了阿里云的 AMQP 中间件。但是这种中间件基本都是单向的。向后发的时候支持负载均衡。但后面处理完成,回发 response 时就找不到对应的服务器了。请问有什么好的办法既解决局了单点故障的问题,又能实现分布式部署

2721 次点击
所在节点    程序员
23 条回复
iClass
2021-11-08 16:10:43 +08:00
我们的服务器是参考这个实现的: https://github.com/88-degrees/speaker.app
CivAx
2021-11-08 16:41:19 +08:00
配个 session sticky?
MrEatChicken
2021-11-08 16:41:21 +08:00
proxy 服可以不用啊
AccessSvr 内部做负载均衡到对应的 Gamesvr
就需要加个服务发现:比如 consul
goforwardv2
2021-11-08 16:52:17 +08:00
@MrEatChicken 那这个服务发现 consul 不是单点吗
hellodudu86
2021-11-08 16:54:56 +08:00
如果我没理解错的话,楼主说的 AccessSvr 和 proxy 是一个类似具有负载均衡的网关服务,主要功能是转发客户端请求到对应的 GameSvr 、并且返回 GameSvr 的结果给客户端?

这种情况下用 MQ 确实是不合适的,因为你的用户所在 AccessSvr 和 GameSvr 是一一对应的,MQ 并不能保证消费者是哪一个节点。如果没有延迟返回结果或者持久化用户请求的需求的话可以考虑用 rpc 替代 proxy 服务。

至于你所说的网关存在单点故障的问题,我不觉得这个和分布式部署有何矛盾之处,AccessSvr+proxy 的本质就是建立一条客户端和 GameSvr 的连接并且转发双方的数据,这条连接应该是没有状态的,就算挂掉了一个 AccessSvr 服务,客户端重连后在另一台 AccessSvr 重新建立连接即可,对于用户来说几乎是无感知的。唯一需要处理的是同一个用户 id 只能在 AccessSvr 集群上有一条连接,这个用一致性哈希可以保证。引入 MQ 并不能解决这个问题
MrEatChicken
2021-11-08 16:55:59 +08:00
@goforwardv2
consul 保证 cp , 使用 raft 算法, 具有强数据一致性
不是单点的
goforwardv2
2021-11-08 17:18:58 +08:00
@hellodudu86 大致就是这个意思 不过我的单点故障指的是 proxy 因为 proxy 只有一个实例 另外用户现在是通过一个类似于 DNS 的服务器来获取有哪些 AccessSvr 这个 DNS 服务器也是单点
goforwardv2
2021-11-08 17:20:06 +08:00
@hellodudu86 另外 如果是 RPC 是怎么做到负载均衡的
fkdtz
2021-11-08 17:27:14 +08:00
在单点的地方搞个 LSV 那种主备,对外调用暴露一个虚拟 IP ,当发生故障或是主备切换时对调用方无感知,调用方也不需要引入配置中心。
fkdtz
2021-11-08 17:27:44 +08:00
@fkdtz LSV => LVS
flycloud
2021-11-08 17:36:27 +08:00
AccessSvr 存在的意义是啥?为什么用户不是和 proxy 建立 tcp 连接呢?

我现在做的游戏后端,用的 nats 在内部服务之间转发消息。
hellodudu86
2021-11-08 17:54:24 +08:00
个人觉得没必要存在这个 proxy 服务,尤其是是单点的情况,十分危险。

rpc 的 load balance 有很多种算法,一般调用的时候选择作为参数就行,或者有需求可以自定义一个负载均衡算法。

GameSvr 无状态的话可以 roundrobin 。有状态的话应该是要保证同一个用户 id 数据转发到同一个 GameSvr 节点上,用一致性哈希或者自己定义一套用户 id 映射 GameSvr 节点 id 的算法。
th00000
2021-11-08 18:18:52 +08:00
proxy 应该是只需要第一次建立连接的时候告诉前后两台服务器你们谁去找谁就可以了, 然后前后两台服务器自行建立 TCP 连接即可, 中间不用靠 proxy 转发
这样 proxy 只需要自己维护一个列表记录谁连了谁
当其中一台服务器出问题了, 重新上线的时候只需要再找 proxy 问我要去找谁重新建立连接即可

proxy 可以不用单点, 考虑使用 Raft 协议实现一个有状态的服务, 如果觉得麻烦, 一样可以写成无状态的服务
我个人推荐使用 Raft 协议实现, 因为这样他的内存里就有一个全局的视图, 可以清楚的知道整体流量情况, 快速做出反应
goforwardv2
2021-11-08 20:40:58 +08:00
@hellodudu86 有好的开源的 rpc 吗 或者你平时用的 rpc 能实现自定义负载均衡算法的 我这边就需要实现自定义的负载均衡 比如我这里的 proxy 需要解包提取信息 然后再根据提取的信息去选择 GameSvr
luoqeng
2021-11-09 01:05:05 +08:00
游戏和 web 最大区别就是有状态,实时性要求高。不需要 proxy ,proxy 的唯一优点相当于做了服务发现的工作,
luoqeng
2021-11-09 01:16:18 +08:00
但是就像你说的有单点故障问题。通过高可用的 ETCD 来做服务发现,通信双方直接建立连接比较好。
用 MQ 也可以实现 RPC ,性能肯定没直接通信好,MQ 本身高可用,相当于高可用版本 proxy 吧。
https://github.com/nats-rpc/nrpc
dcoder
2021-11-09 01:56:11 +08:00
没看懂你定义的术语
一般游戏这种 real-time 双向的链接, 是接到一个叫 Gate Way 的 cluster 上, 然后你系统需要有个 routing table 来 track 每个 client 连接着的 Gate Way 机器的 IP. 比如, 把 routing table {client_id: IP} 存在 Redis 里面.
byaiu
2021-11-09 09:11:18 +08:00
老哥有做过游戏开发么……这种情况下延时怎么搞?
goforwardv2
2021-11-09 10:09:49 +08:00
@MrEatChicken 你们的 consul 是自己部署 还是买对应的云产品
goforwardv2
2021-11-09 10:10:18 +08:00
@luoqeng 你们的 etcd 是自己部署 还是买对应的云产品

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/813897

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX