IM专题:分层架构IM系统(1)— 架构解读

今天开始,进入 IM 系统的【分层架构】阶段!

在日活只有几千的时候,IM 系统采用【单体架构】方式进行实现,是完全没有问题的。在单体架构 IM 系统(如下图)这种方式下,如果用户的规模逐步增大,比如几万日活、十几万日活的时候,通常应该如何应对呢?

图片

大家应该会很容易想到,不断横向扩展 server 节点即可,是的,这种方式会非常快捷和有效;但是,随着 server 节点数量的不断增多,大家会感觉到投入和产出的 ROI 越来越低,为什么会这样呢?

横向扩展 server 节点,其实是一种粒度非常粗的解决方案。server 程序在实现的时候,一般会包含用于前端连接的部分、实现业务逻辑的部分和访问数据库与缓存的部分,这三部分到底是哪一部分的资源紧张才需要横向扩展 server 节点呢?日活量增大,有可能是前端连接逻辑需要扩容,也有可能是业务逻辑需要扩容,但是在横向扩展 server 节点时,通常不会考虑这么细。这是单体架构系统一个非常关键的问题。

另外,单体架构系统的技术栈非常单一,只能垂直扩展;举个例子:假设单体架构的系统最初选型用 C++ 语言进行实现,前端连接的部分如果想改用 SpringMVC 进行实现,肯定不行的,访问数据库和缓存的部分如果想改用MyBatis 进行实现,也肯定不行;没办法,只能在 C++ 这个技术栈范围内死磕到底。

同时,单体架构的系统,随着业务迭代越多,其逻辑实现会愈加臃肿;任何一个小地方的改动,都会导致整个系统重新编译和重新部署。

所以,在大家遇到以上问题时,通常会采用【水平分层架构】进行实现。水平分层架构是在单体架构的基础上横向切几刀形成,是在技术的驱动之下,由单体架构演化而来;分层架构的 IM 系统见下图。

图片

分层架构的 IM 系统,整体上包含:【终端层】、【入口层】、【业务逻辑层】、【路由层】、【数据访问层】和【存储层】,该分层架构的 IM 系统运行在日活百万级别的电商场景下;下面分层介绍。

一、终端层

终端层负责与用户进行交互,获取用户的操作行为,转换成访问后端具体接口的动作;终端层具体包括安卓和 IOS 移动手机上运行的客户端,即 APP。

二、入口层

入口层,也叫做入口网关层,即 Entry进程,Entry 的职责只有一条,即负责维护与终端之间的长连接,不负责任何的业务逻辑。为什么要这样设计呢?

我们必须保证 Entry 的实现足够简单,简单到 “一次实现,终生不迭代”,也就是 Entry 实现完进行部署之后,可以做到 100 年不重启;Entry 是负责维护与客户端之间的长连接的,Entry 如果重启,将会影响连接该 Entry 节点的所有的客户端。

对长连接的维护,通常采用 “心跳” 方式;也就是,对于客户端发送的所有请求中, Entry 只负责处理心跳请求,其他请求 Entry 会全部转发给业务逻辑层进行处理。

三、业务逻辑层

业务逻辑层,即 Logic 进程,其负责处理 IM 系统的所有的业务逻辑,比如:登录、点对点消息、群消息、联系人等;可想而知,Logic 进程是因为业务升级迭代,重启最频繁的。

四、路由层

路由层,即 Router 进程,通过名称可以很容易明白它的核心职责是实现用户的路由,怎么理解呢?我们已经知道Entry 负责和客户端建立长连接,为了提高 IM 系统的吞吐量和避免单点问题,Entry 肯定是集群化部署的;客户端与后端建立连接时,会根据策略将客户端分配给特定的 Entry 节点;Entry 节点之间如果通信,代价太大,所以哪一个客户端由哪一个 Entry 节点来管理,必须要有一个中央存储来负责维护,该中共存储即是 Router。

Router 是一个内存数据库,其本质是一个很大的 Map<uid, EntryIp>,该 Map 的 key 是用户的 uid,该  Map 的 value 是客户端所连接到的 Entry 的 ip;当 IM 系统要主动向用户推送消息时,可以先查询 Router,如果用户记录不存在,说明该用户不在线;如果用户在线,获取到用户连接到了哪一个 Entry 节点,然后由 Logic 将消息推送到该 Entry 节点。

描述到这里,Entry 的本质也是一个很大的 Map<uid,  fd>,该 Map 的 key 是用户的  uid,该 Map 的 value 是长连接的文件描述符 fd;通过查找该 Map,获取到用户对应的 socket 的 fd,然后基于 fd 将消息推送给用户。

通过思考路由层和入口层的本质,我们基本可以想清楚完整的消息推送流程的主要框架(后面的技术短文中会详细分析)。

五、数据访问层

数据访问层,即 Das 进程,该层的核心职责即负责访问数据库和缓存。理解该层的核心职责,不是最关键的,关键问题是数据访问层的架构意义何在呢?是不是说,在分层架构系统中,一定需要数据访问层,没有该层整个系统就不能干活了?答案肯定是否定的。

数据访问层是在 “业务逻辑层” 和 “存储层” 之间,大家在设计任何系统的时候都需要注意这种情况,两层之间若还有一层,那么该层的架构意义往往就是起到 “解耦” 的作用,也就是:数据访问层的存在是为了解耦业务逻辑层和存储层。具体怎么理解呢?

我们都知道,存储层是非常复杂的:为了提高抗读的压力,我们会加一个 “缓存”;如果单表的数据量超过限制,我们会 “分库分表”;为了进一步优化读库,我们会对数据库进行 “读写分离”;我们也有可能会将 MongoDB 替换成 MySQL,将 MySQL 替换成 TiDB 等等等等。存储层这一系列的复杂性,如果没有数据访问层的存在,势必会影响到业务逻辑层,而业务逻辑层是进行业务迭代的,如果我们正在进行 “分库分表” 的操作,还有精力迭代业务吗?但是如果有了数据访问层,它统统屏蔽了存储层的复杂性,业务逻辑层只管向数据访问层要数据即可,不用关注存储层的数据存储模式。这就是数据访问层的架构意义。

六、存储层

存储层负责对业务数据进行持久化存储,通常包括数据库和缓存。

最后,总结文中关键:

1、 单体架构系统,横向扩展 server 节点方案,粒度很粗,ROI 很低;

2、 分层架构 IM 系统,包括【终端层】、【入口层】、【业务逻辑层】、【路由层】、【数据访问层】和【存储层】;

3、 入口层 Entry 只负责维护与终端之间的长连接;

4、 路由层 Router 是一个内存数据库,是用户在线状态的中央存储,其本质是一个很大的 Map<uid, EntryIp>;Entry 的本质也是一个很大的 Map<uid,  fd>;

5、数据访问层 Das 存在的架构意义在于向业务逻辑层屏蔽存储层的复杂性,解耦业务逻辑层和存储层。

大家思考一下:分层架构的 IM 系统,在业务逻辑越来越复杂,为了引流而经常进行各种运营活动时,业务逻辑层需要进行怎样的调整呢?

作者:棕生,来源:公众号——架构之魂

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

(0)

相关推荐

发表回复

登录后才能评论