美文网首页
dispatcher 设计

dispatcher 设计

作者: pcgreat | 来源:发表于2020-09-19 12:01 被阅读0次
    attach_166cb75a42945105 (1).png

    二期 msg dispather ,im server 。

    目前我们公司 go im server 基于 https://github.com/googollee/go-socket.io 做开发的 。
    同时 go im server 是 将 im server , msg dispatcher 融合在了一起 。职责单一原则 ,我认为拆成 msg dispatcher , im server 会更加合理。 msg dispatcher 可以支持多队列,屏蔽上层队列不同,也更容易去做背压设计 。

    当前架构最大的问题

    1. 吞吐量问题 ,目前tqmq 是单队列传输消息 。将来可以通过多队列提升消息的吞吐量。巨量的数据,如果是kafka ,完全可以通过单队列,多数据分片来解决 ,如果是 tqmq ,只能通过多tqmq队列扩展其吞吐量性能。
    2. 消息顺序问题。目前同时发送两个消息,go im server 有一定概率,顺序是颠倒的。
    3. 当流量到达一定程度情况下 ,难免会出现不同地区用户,消息实时性,可达率,可能存在较大差别 ,这个当前架构体系是无法改变。不同地区到ecs 路由时间本来就存在较大差别。im 消息稳定性也是如此。期待公司未来吧
    1. 过去有离线消息表 ,用户不在线或者im消息失败,会发到业务,业务在入离线消息表,然后发送推送。离线消息表本身被已读索引优化掉了。其实没有必要把消息推送到业务平台,在通过业务平台调用推送。可以直接推送 即可。

    2. java 其实可以通过groovy 脚本引擎,提供动态编程的能力 ,无需重启,即可提供更新代码的能力,提供更加可靠的稳定性。比如不同版本消息协议解析或者转换成统一格式 ,或统一格式的变化,dispatcher 是可以不重启的。(第3期做比较好)

    下面是第二期设计的消息下发的架构图
    [图片上传失败...(image-4c54c7-1628040115137)]

    解决消息完全有序

    当前go im server , 如果是自己msg 就不转发, 如果不是就转发,连续的msg 被分到了不同的机器 ,机器处理时间有不一致 。这里极有可能出现消息乱序问题。

    通过kafka 可以保证,分片数据一定被唯一一个消费者消费 ,不会存在tqmq的多消费者问题。也就不存在乱序可能性。

    消息验证

    我希望能够将消息下发验证流程都都到 java server ,而不是说 到了im server 还要效验消息的合法性 。目前 go 通过ticket 作为登录验证过程,如果ticket 验证通过后 ,登录成功 ,消息可以下发。否则 不能下发 。 但是这个过程 已经 经过 消息队列 。到达im server ,那之前的流程 不是白走了?
    如果 我们把msg 验证 放到 push server ,流程更加合理 。

    背压设计背景

    比如 某个im server 已经 满负荷运行了 , 这时候 其他im server 依然不断配发属于你的msg 给你 , 可以想象结局会是如何 。
    分离的话 ,这块逻辑会很好处理 。消息入im server队列 ,队列满后,告知dispatcher ,别给我发了 ,消息入拥塞队列。并告警阻塞 。 更加合理

    这一块比上面说的,其实要复杂 。因为场景 n 生成者与n消费者问题,对于消费者1而言 ,我可能需要m 个产品 ,而 m个产品 对于n个生产者而言,但是真实业务的场景,显然是不均衡的。某些消费者必然会比其他消费者消费更多的消息 。

    服务背压和tcp 滑动窗口 本质上是相同的 ,针对上面的问题,dispatcher 与im server 间,类似于tcp连接滑动窗口。

    dispatcher 会将msg 分发到指定 im server 队列中, 等待im server 授权,授权后,将消息发送给im server 。
    当im server 队列满后, 需要阻塞消息的消费 ,并告警哪条im server队列已满。通知下游im server 开启服务降级 ,新的用户会登陆其他im server 。同时 3次发送重试入离线消息,变成一次未确认,入离线队列 。

    重点是要保障 消费能力 大于生成能力

    未来可能会有多协议队列

    msg dispatcher 会从不同类别队列拉取msg ,然后根据用户登录meta data (appcode , uuid ) ,找到登录im server 。 将消息分发到指定im server 发送队列上。批量推送给 im server 待发队列, im server 待发队列满了之后 。im server 会告知 msg dispatcher 不要给我发了 ,im server 发送队列满了后,多的消息暂时保存在rocksdb中 ,告警中,rocksdb 保存该条连接消息超过2w 消息 ,告警高,直接走离线下发流程。这样msg dispatcher 永远不会内存溢出 挂掉。第二我们优化了消息下发流程。之前消息都是通过soa 一个一个下发消息。消息批量下推方式。效率更高。
    im server 有一待发队列 ,在待发满之前 。 可以通过rsocket 告知dispatcher 一次可以推送的最大消息数量 。达到背压效果 。im server 永远不会内存溢出 挂掉。im server demo 下推消息方式其实是不合理的。 必须基于netty 进行开发。(第3期做会比较好)

    im proxy 属于第3期内容

    类似于智能dns 选址 。im proxy 观察后端im server负载,负载较低情况下,通过hash 方式,将后端ip直接分发给客户端,允许客户端和对应im server 创建连接。负载中情况下 (有im server 存在msg 推送不完的情况) ,新建连接到负载小的 im server 上 , 负载高 。必须要扩展imserver ,将连接创建到新的imserver 。 或者 禁止 用户登录 。im proxy 尽量解决 im server 热点问题 。 (第三期开发)

    rsocket rpc

    im server 列表更新后 ,etcd 推送给所有dispatcher ,dispatcher 和新的imserver 初始化队列,建立连接。 对于下掉im server ,检测 im server 连接,连接正常不做任何操作 。
    rsocket https://rsocket.io/
    RSocket 是传输无关的,支持 TCP、WebSocket 和 Aeron UDP 协议,并支持无语义损失的混合传输协议——回压和流量控制仍然有效。
    基于tcp 长链 ,支持回压 ,重连,双向流。具有较高性能,benchmark强于 http2 grpc 是必然的 。 天生响应式编程都是他的优点。

    dispatcher metadata

    im dispatcher metadata
    key : tqmsg:dispatcher:metadata:%s id
    value:

     [ 
        address : ip,
        port : 8080,
        tps: ,
        offline_tps,
        online_tps,
        rt:
        offline_rt,
        online_rt,
       risk_level,
       unvalid_msg_num,
     ]
    

    dispatcher connection metadata

    im dispatcher connection metadata
    key : tqmsg:dispatcher:connection:metadata:%s id_id
    value:

    [
        im server id ,
        im server ip ,
        im server port ,
        status ,
        sendQueue,
        recieveQueue,
        rocksDb ,
        tps,
        rt,
    ]
    

    相关文章

      网友评论

          本文标题:dispatcher 设计

          本文链接:https://www.haomeiwen.com/subject/skafkktx.html