IM专题:分层架构IM系统(5)— Entry设计

在分层架构中,Entry 向客户端提供了 TCP 长连接的接入能力,并对这些长连接的活性进行保活维护(IM专题:分层架构IM系统(1)—架构解读),所以在 Entry 服务内部有两个最核心的数据结构:

  1. Map<uid,  fd>,其 key 是描述客户端的 uid,其 value 是该客户端与服务端建立的长连接对应的描述符 fd;

  2. Map<fd, uid>,其 key 是客户端与服务端之间的长连接对应的描述符 fd,其 value 是客户端的 uid。

这两个 map 是双向的映射关系。当 Entry 需要主动向用户推送消息时,可以通过 Map<uid, fd> 映射结构,获取到 fd,然后基于 fd 推送消息; 当 Entry 收到客户端发送的消息时,可以通过 Map<fd, uid> 映射结构,获取到 uid,知道是哪一个用户发送的消息; 见下图。

Entry 所能承受的 TCP 长连接数是有上限的,当在线客户端数量超过这个上限值后,就需要对入口层 Entry 进行横向扩容,即通过 Entry 集群方式来 cover 越来越多的客户端,不同的 Entry 节点管理着不同的客户端长连接,Entry 服务是一个有状态的服务。这种情况下,当需要主动向用户推送消息时,应该如何处理呢? 使各个 Entry 节点互相通信绝不是一个好的实现方案,见下图。

不管每个 Entry 节点是保存了所有在线客户端的连接状态,还是只保存部分客户端的连接状态,这都不是关键问题,核心问题是每增加一个 Entry 节点,网络通信负载会指数级增加,最终成为瓶颈;如图所示,3个 Entry 节点需要建立 6 条连接,4个 Entry 节点时就需要建立 12 条连接。

比较优雅的解决方案是将客户端的连接状态数据单独集中化存储,见下图。由路由层 Router 集中存储所有在线客户端连接数据;Router 本质上是一个内存数据库,核心是一个很大 Map<uid, EntryIp>,其 key 是在线客户端的 uid,其 value 是该客户端连接的 Entry 节点;当客户端与 Entry 建立连接并登录后,在 Router 中进行注册;当要推送消息给用户时,先在 Router 中获取客户端连接到了哪一个 Entry 节点,然后将消息推送给该 Entry 节点。

将所有在线客户端的连接数据进行集中化存储,每一个 Entry 节点是独立的,Entry 会趋向于无状态化,这为横向扩展 Entry 集群提供了便利。


Entry 内部又是如何设计的呢?Entry 有哪些关键的内部构成组件呢?见下图。

Entry 对外与客户端直接连接,对内与业务逻辑层 Logic 直接交互。

当多个客户端同时并发访问时,通过 “IO多路复用” 机制来管理客户端连接是一个常用的解决方案,在 Linux 系统中一般基于 epoll 模型实现,在 Windows 系统中一般基于 IOCP 模型实现,在 Mac 系统中一般基于 kqueue 模型实现;所谓 “IO多路复用”,就是在一个线程中可以同时等待多个文件描述符(即连接)就绪,哪个就绪(有连接到来、有数据可读、有数据可写)了,就对哪条连接进行操作,一句话描述:在单个线程中实现对多条连接的管理。

客户端发送的请求,全部写入到 “请求队列”,然后由下游的工作线程从 “请求队列” 中获取请求进行处理。在系统设计上, “请求队列” 起到了 IO线程与工作线程交互、对高并发请求进行流量削峰、IO逻辑与业务逻辑解耦等三个关键作用。

工作线程池的业务逻辑处理非常简单,拿到客户端请求后判断,若是心跳请求,则调用 “心跳管理器” 模块来处理心跳(在上篇技术短文 IM专题:分层架构IM系统(4)—Entry心跳算法中有详细分析),若是其他请求,则全部通过 RPC 方式交由业务逻辑层 Logic 进行处理;所以 Entry 需要集成 rpc 客户端的 sdk。Logic 业务逻辑处理的结果返回到 Entry后,写入到 “发送队列”,最后仍然通过 “IO多路复用” 机制返回到客户端。

当 Logic 需要主动推送消息到客户端时,Logic 通过 RPC 调用的方式将消息发送给 Entry,此时 Entry 的角色是 RPC 服务端,所以 Entry 同时需要集成 rpc 服务端的 sdk。向客户端推送的消息到达 Entry 后,仍然写入到 “发送队列” ,复用上述流程。

另外,图中的 “在线用户管理器”,其核心就是文章开头部分所描述的两个映射关系,即 Map<uid,  fd> 和 Map<fd, uid>。

综述一下 Entry 的核心组成部分:一是实现IO多路复用机制的IO线程;二是请求队列和发送队列;三是实现与 Logic 交互的工作线程,其集成了 rpc客户端和服务端sdk; 四是心跳管理器和在线用户管理器两个逻辑模块。


最后,总结文中关键:

1、Entry 的核心数据结构是两个映射关系,即 Map<uid,  fd> 和 Map<fd, uid>;

2、Entry 集群部署时对客户端进行优雅管理的解决方案是集中存储客户端连接状态数据;

3、Entry 内部核心组成包括四部分:IO线程、请求队列和发送队列、工作线程、心跳管理器和在线用户管理器。



相关推荐

  • 中国无人飞艇误入美国领空;居民赚100块要拿50还债;顾客称711便利店包子吃出淋巴肉;印度打击童婚抓1800人...|酷玩日爆
  • 现在电视剧真敢演 | 每日一冷
  • 这个春节,中国没有“电动爹”
  • 中国最大煤老板之一,破产、牢狱,55岁离世
  • 年轻人抱怨工资低,专家:不像话!泰国越南只有你一半
  • 5 张图带你理解 RocketMQ 消费者启动过程
  • Kotlin发布2023年路线图:K2编译器、完善教程文档等
  • C++ 之父:Rust等内存安全语言的安全性并不优于C++
  • 救命!同事买的10w块大钻戒,丢了!
  • 美国首次将没收自俄罗斯的资金转交乌克兰;万人级别大裁员!硅谷员工:人心惶惶!;以巴在约旦河西岸发生交火 | 每日大新闻
  • 《情 人 节 热 恋 指 南》
  • 都知道有“高华”,可知道有“高美”吗?
  • 春晚上发布的 RTX 4090Ti 终于现身了?体积大得夸张!
  • Controller层代码这么写,简洁又优雅!
  • 我靠淘宝副业收入翻了10倍:这个风口行业,未来十年最赚钱!
  • 2022年哪种新能源车型最好卖?年度销量排行榜Top100来了!
  • 曝微软苏州大规模裁员,赔偿N+12,内部邮件回应;刘强东现身首都机场,被曝已回国工作;英特尔大幅削减管理层薪酬
  • 火爆朋友圈的Damus
  • 成都四川好公司汇总
  • 「张颂文」原型出现了!比他更猖狂,越查越震惊……