V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
goforwardv2
V2EX  ›  程序员

游戏服务器和中间件

  •  
  •   goforwardv2 · 2021-11-08 16:04:53 +08:00 · 2714 次点击
    这是一个创建于 1136 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

    23 条回复    2021-11-17 17:19:11 +08:00
    iClass
        1
    iClass  
       2021-11-08 16:10:43 +08:00 via Android
    我们的服务器是参考这个实现的: https://github.com/88-degrees/speaker.app
    CivAx
        2
    CivAx  
       2021-11-08 16:41:19 +08:00
    配个 session sticky?
    MrEatChicken
        3
    MrEatChicken  
       2021-11-08 16:41:21 +08:00
    proxy 服可以不用啊
    AccessSvr 内部做负载均衡到对应的 Gamesvr
    就需要加个服务发现:比如 consul
    goforwardv2
        4
    goforwardv2  
    OP
       2021-11-08 16:52:17 +08:00
    @MrEatChicken 那这个服务发现 consul 不是单点吗
    hellodudu86
        5
    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
        6
    MrEatChicken  
       2021-11-08 16:55:59 +08:00
    @goforwardv2
    consul 保证 cp , 使用 raft 算法, 具有强数据一致性
    不是单点的
    goforwardv2
        7
    goforwardv2  
    OP
       2021-11-08 17:18:58 +08:00
    @hellodudu86 大致就是这个意思 不过我的单点故障指的是 proxy 因为 proxy 只有一个实例 另外用户现在是通过一个类似于 DNS 的服务器来获取有哪些 AccessSvr 这个 DNS 服务器也是单点
    goforwardv2
        8
    goforwardv2  
    OP
       2021-11-08 17:20:06 +08:00
    @hellodudu86 另外 如果是 RPC 是怎么做到负载均衡的
    fkdtz
        9
    fkdtz  
       2021-11-08 17:27:14 +08:00
    在单点的地方搞个 LSV 那种主备,对外调用暴露一个虚拟 IP ,当发生故障或是主备切换时对调用方无感知,调用方也不需要引入配置中心。
    fkdtz
        10
    fkdtz  
       2021-11-08 17:27:44 +08:00
    @fkdtz LSV => LVS
    flycloud
        11
    flycloud  
       2021-11-08 17:36:27 +08:00
    AccessSvr 存在的意义是啥?为什么用户不是和 proxy 建立 tcp 连接呢?

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

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

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

    proxy 可以不用单点, 考虑使用 Raft 协议实现一个有状态的服务, 如果觉得麻烦, 一样可以写成无状态的服务
    我个人推荐使用 Raft 协议实现, 因为这样他的内存里就有一个全局的视图, 可以清楚的知道整体流量情况, 快速做出反应
    goforwardv2
        14
    goforwardv2  
    OP
       2021-11-08 20:40:58 +08:00
    @hellodudu86 有好的开源的 rpc 吗 或者你平时用的 rpc 能实现自定义负载均衡算法的 我这边就需要实现自定义的负载均衡 比如我这里的 proxy 需要解包提取信息 然后再根据提取的信息去选择 GameSvr
    luoqeng
        15
    luoqeng  
       2021-11-09 01:05:05 +08:00
    游戏和 web 最大区别就是有状态,实时性要求高。不需要 proxy ,proxy 的唯一优点相当于做了服务发现的工作,
    luoqeng
        16
    luoqeng  
       2021-11-09 01:16:18 +08:00
    但是就像你说的有单点故障问题。通过高可用的 ETCD 来做服务发现,通信双方直接建立连接比较好。
    用 MQ 也可以实现 RPC ,性能肯定没直接通信好,MQ 本身高可用,相当于高可用版本 proxy 吧。
    https://github.com/nats-rpc/nrpc
    dcoder
        17
    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
        18
    byaiu  
       2021-11-09 09:11:18 +08:00 via iPhone
    老哥有做过游戏开发么……这种情况下延时怎么搞?
    goforwardv2
        19
    goforwardv2  
    OP
       2021-11-09 10:09:49 +08:00
    @MrEatChicken 你们的 consul 是自己部署 还是买对应的云产品
    goforwardv2
        20
    goforwardv2  
    OP
       2021-11-09 10:10:18 +08:00
    @luoqeng 你们的 etcd 是自己部署 还是买对应的云产品
    MrEatChicken
        21
    MrEatChicken  
       2021-11-09 10:52:04 +08:00
    @goforwardv2 自己部署
    hellodudu86
        22
    hellodudu86  
       2021-11-09 11:12:27 +08:00
    @goforwardv2 我用的 gRPC ,想自定义负载均衡算法的话可以参考下官方的文档 https://github.com/grpc/grpc-go/tree/master/examples/features/load_balancing
    goforwardv2
        23
    goforwardv2  
    OP
       2021-11-17 17:19:11 +08:00
    @MrEatChicken 有时间帮看下这个问题 https://v2ex.com/t/816091#reply0
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1188 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 23:18 · PVG 07:18 · LAX 15:18 · JFK 18:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.