默认
打赏 发表评论 39
想开发IM:买成品怕坑?租第3方怕贵?找开源自已撸?尽量别走弯路了... 找站长给点建议
一套亿级用户的IM架构技术干货(上篇):整体架构、服务拆分等
微信扫一扫关注!

1、引言


经历过稍有些规模的IM系统开发的同行们都有体会,要想实现大规模并发IM(比如亿级用户和数十亿日消息量这样的规模),在架构设计上需要一些额外的考虑,尤其是要解决用户高并发、服务高可用,架构和实现细节上都需要不短时间的打磨。

我在过往的工作经历里,亲手设计和实现了一套亿级用户量的IM,平台上线并经过6年多的验证,稳定性和可用性被验证完全达到预期。

这套IM系统,从上线至今已6年有余,本人也已经离职创业近2年,但当初设计和开发这套系统时积累和收获了大量的第一手实践经验和技术心得。

因此,想借本文把当时的架构设计经历记录下来,作为同行交流和参考,希望能提供一些启发,少走弯路。

cover-opti.jpg

本文已同步发布于“即时通讯技术圈”公众号,欢迎关注。公众号上的链接是:点此进入

2、系列文章


为了更好以进行内容呈现,本文拆分两了上下两篇。

本文是2篇文章中的第1篇:


本篇主要总结和分享这套IM架构的总体设计和服务拆分等。

3、原作者


本文基于邓昀泽的“大规模并发IM服务架构设计”一文进行的扩展和修订,感谢原作者的分享。

author.jpg

邓昀泽:毕业于北京航空航天大学,现蓝猫微会创始人兼CEO,曾就职于美团、YY语音、微软和金山软件等公司,有十多年研发管理经验。

4、技术指标


在这套IM系统的架构上,技术上我们坚持高要求,经过数年的验证,也确实达到了设计预期。

这4大技术指标是:
1.jpg

具体解释就是:

  • 1)高可靠:确保不丢消息;
  • 2)高可用:任意机房或者服务器挂掉,不影响服务;
  • 3)实时性:不管用户在哪里,在线用户消息在1秒内达到(我们实际是75%消息可以做到120ms);
  • 4)有序性:确保用户消息的有序性,不会出现发送和接受的乱序。

5、架构拆分


从整体架构上来说,亿级用户量的IM架构整体上偏复杂。

传统开源的IM服务喜欢把所有服务做到1-2个服务里(Connector+Service模型),这样带来的问题比较严重。

传统开源的IM的问题主要体现在:

  • 1)服务代码复杂,难以持续开发和运维;
  • 2)单一业务逻辑出问题,可能会影响到其它逻辑,导致服务的全面不可用。

因此,我在做架构设计的时候尽量追求微服务化。即把整体架构进行分拆为子系统,然后子系统内按照业务逻辑分拆为微服务。

系统拆分如下图:
2.jpg

4个子系统的职责是:

  • 1)IM业务系统:服务IM相关的业务逻辑(比如好友关系、群关系、用户信息等);
  • 2)信令系统:负责用户登录,用户在线状态的维护,以及在线用户的下行推送;
  • 3)推送系统:负责消息的在线推送和离线推送;
  • 4)存储系统:负责消息和文件的存储和查询;

其中:信令系统和推送系统是基础设施,不只是可以为IM业务服务,也可以承载其它类似的业务逻辑(比如客服系统)。

在部署层面:采用存储3核心机房,信令和推送节点按需部署的方式(国内业务推荐8-10个点)。实际上我们只做了了北京3个机房,上海1个机房和香港一个机房的部署,就基本上满足了大陆+香港的业务需求。

下面将逐个介绍这4个子系统的细节方面。

6、IM业务系统


一说到IM,很多人脑海里跳出的第一个关键就是“即时通信”,技术上理所当然的联想到了socket,也就是大家成天嘴上说的:“长连接”。换句话说,很多对IM不了解或了解的不多的人,认为IM里的所有数据交互、业务往来都是通过“长连接”来实现的,这样话,对于本文章中拆分出的“IM业务系统”就有点不理解了。

实际上,早期的IM(比如20年前的QQ、MSN、ICQ),确实所有数据基本都是通过“长连接”(也就是程序员所说的“socket”)实现。

但如今,移动端为主端的IM时代,IM系统再也不是一个条“长连接”走天下。

现在,一个典型的IM系统数据往来通常拆分成两种服务:

  • 1)socket长连接服务(也就是本文中的“推送服务”);
  • 2)http短连接服务(就是最常用的http rest接口那些,也就是本文中的“IM业务系统”)。

通俗一点,也也就现在的IM系统,通常都是长、短连接配合一起实现的。

3.jpg

比如论坛里很多热门技术方案都是这样来做的,比如最典型的这两篇:《IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?》、《IM消息送达保证机制实现(二):保证离线消息的可靠投递》,文记里提到的“推”其实就是走的“长连接”、“拉”就上指的http短连接。

对于socket长连接服务就没什么好说,就是大家最常理解的那样。

IM业务系统详细来说,就是专注处理IM相关的业务逻辑,比如:

  • 1)维护用户数据:用户基本信息等;
  • 2)维护好友关系:好友请求、好友列表、好友信息等;
  • 3)维护群组信息:群创建、解散、成员管理等;
  • 4)提供数据:离线拉取、历史记录同步;
  • 5)其它逻辑:比如通过存储和推送系统,存储消息和发送通知;

按照微服务的原则,IM业务系统也被分拆为多个服务,比如:

  • 1)GInfo服务:群组信息维护;
  • 2)IM服务:处理1V1消息;
  • 3)GIM服务:处理群组消息。

7、信令系统


7.1基本情况


信令系统主要职责是3部分:
4.jpg

1)维护用户在线状态:

因为用户规模庞大,必然是多个集群,每个集群多台服务器为用户提供服务。

考虑到服务器运维的复杂性,我们要假定任何一个集群,任何一个服务器都可能会挂掉,而且在这种情况下要能够继续为用户提供服务。

在这种情况下,如果用户A给用户B发消息,我们需要知道用户B在哪个服务器上,才能把消息正确推送给用户B。用户在哪个信令服务,这个信息就是在线状态数据。

2)下行消息推送:

跟上一个职责有关,用户在线的时候,如果有其它用户给他发消息,那就最好不要走离线推送,而是走在线推送。

在线推送的最后一个环节,是把用户消息推送给用户设备,因为就需要知道用户登录到哪个服务器上。

3)业务分发:

信令服务不只可以处理IM请求,也可以处理其它类型的业务请求。为了处理不同的业务,就需要有分发能力。

具体做法是通过一个SVID(service id)来实现,不同的业务携带不同的SVID,信令服务就知道如何分发了。

用户通过登录服务把数据(比如IM消息)发送到信令系统,信令系统根据SVID转发给IM系统。不管后台有多少个业务,用户只需要一条链接到信令。

7.2服务拆分


信令系统为了实现以上这3个职责,同时要确保我们服务可平行扩展的能力和稳定性,在实际的技术实现上,我们实际上把信令服务分拆为3个服务模块。

如下图所示:
5.jpg

下面将逐个介绍这3个子服务。

7.3Login服务


Login服务主要负责维护用户长链接:

  • 1)每个用户一条链接到Login服务,并按时间发心跳包给Login服务;
  • 2)服务定时检查用户链接状态和心跳包,比如发现2个心跳周期都没收到心跳,就认为用户掉线了(有假在线问题,有兴趣同学可回贴讨论)。

Login服务收到用户登录请求以后,验证uid/cookie,如果成功就把这个用户的登录信息发送给online。

此过程主要记录的信息包含:

  • 1)uid(用户id);
  • 2)Login服务器IP/Port;
  • 3)Route服务器的IP/Port。

如果用户发送IM消息,先发送到Login,Login转发给Route,Route根据服务的类型(SVID),发现是IM协议就发送给后端的IM服务。

Login对并发要求比较高,一般要支持TCP+UDP+Websocket几种方式,单服务可以做到10-250万之间。从服务稳定性角度触发,建议是控制VM的CPU/内存,单服务器以20-50万为合适。

Login服务器本身没有状态,任何一个Login服务断掉,用户端检测到以后重连另一个Login服务器就可以了,对整体服务可靠性基本没有影响。

7.4Online服务


Online服务主要负责维护用户的在线信息:

  • 1)如果用户掉线,Online服务里信息就是空;
  • 2)如果用户在线,Online就能找到用户登录在哪个集群,哪个Login服务器上。

Online业务相对简单:多个Login服务器会连接到Online,定期同步用户登录和离线信息。

Online主要职责是:把用户状态信息存储在Redis集群里。因此也是无状态的,任何一个Online服务挂掉,不影响整体服务能力。

如果集群规模不大,用户规模也不大,Online服务也可以收到Login服务里去。

如果规模比较大,建议分拆出来,一方面简化Login的逻辑复杂度,同时避免写Redis的慢操作放在Login服务里。因为Login要同时处理50万以上的并发链接,不适合在循环里嵌入慢操作。

7.5Route服务


Route服务的设计核心,是作为信令系统跟其它子系统的交互层。Route下接Login服务,可以接受用户业务信息(IM),也可以往用户推送下行消息。

多个后端业务系统可以接入到Route,按照服务类型(SVID, service id)注册。比如IM服务可以接入到Route, 注册SVID_IM。这样Login接收到SVID=SVID_IM的消息,转发给Route,Route就可以根据SVID转发给IM相关的服务。

Route简单的根据SVID做转发,不处理具体的业务逻辑,因此也是无状态的。一个信令集群可以有多个Route服务,任何服务挂了不影响整体服务能力

8、推送系统


推送系统的核心任务:是接收到给用户发送下行消息的请求以后,去信令服务查询用户是否在线,如果在线走信令推送,如果不在线走离线推送(iOS的APNS、华为推送、小米推送等)。

因为推送服务可能出现大规模并发蜂拥,比如大群激烈讨论的时候,会触发亿级的TPS。因此推送服务用Kafka做了削峰

我在实际的技术实现上,将推送系统进行了如下细分:
6.jpg

具体就是:

  • 1)PushProxy:接受用户的推送请求,写入Kafka;
  • 2)Kafka:缓存推送服务;
  • 3)PushServer:从Kafka获取推送请求,判断用户是否在线;
  • 4)PushWorker:真正推送给信令或者APNS,华为推送等。

这里同样,除了Kafka以外每个服务都是无状态的,因为也可以实现平行扩展和容错,任何服务挂掉不影响整体服务可用性。

9、存储系统


存储服务主要是负责消息的存储和查询,因为消息量巨大,对存储服务的并发能力和存储量要求巨大。

为了平衡性能、空间和成本,存储服务按数据的热度进行了分级和区别对待。

具体是:

  • 1)短期消息(7天):存储在Redis里;
  • 2)近期消息(1-3个月):存储在Mysql里,以备用户实时查询;
  • 3)历史信息:存储在HBase里,作为历史数据慢查询。

同时,为了应对超大群的大量消息处理,存储服务在实际的技术实现上,也做了比较细的分拆。

存储服务具体拆分如下图:
7.jpg

具体的业务划分就是:

  • 1)MsgProxy:负责接受IM子系统的存储请求,写入Kafka;
  • 2)MsgWriter:从Kafka获取写请求,按需写入Redis和Mysql;
  • 3)MsgReader:接受用户的消息查询请求,从Redis,Mysql或者HBase读数据;
  • 4)运维工具:主要是数据库的运维需求。

消息队列(Kafka)在这里角色比较重要,因为对于高并发请求(100万人公众号),需要通过消息队列来做削峰和并行。

在具体部署上:可能是3-4个MsgProxy,后端可以对应15个左右的MsgWriter。MsgWriter是比较慢的,需要同时操作多个数据库,还要保证操作的原子性。

10、本篇小结


本篇主要总结了这套亿级用户量IM系统的总体架构设计,为了高性能和横向扩展性,基于微信的理念将整个架构在实现上分成了4个子系统,分别是:IM业务系统、信令系统、推送系统、存储系统。

针对这4个子系统,在实际的技术应用层上,又进行了进一步的服务拆分和细化,使得整个架构伸缩性大大增强。

—— 下篇《一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等》稍后发布,敬请期待 ——

附录:相关文章


浅谈IM系统的架构设计
简述移动端IM开发的那些坑:架构设计、通信协议和客户端
一套海量在线用户的移动端IM架构设计实践分享(含详细图文)》(* 力荐
一套原创分布式即时通讯(IM)系统理论架构方案》(* 力荐
从零到卓越:京东客服即时通讯系统的技术架构演进历程》(* 力荐
蘑菇街即时通讯/IM服务器开发之架构选择
腾讯QQ1.4亿在线用户的技术挑战和架构演进之路PPT
微信后台基于时间序的海量数据冷热分级架构设计实践
移动端IM中大规模群消息的推送如何保证效率、实时性?
现代IM系统中聊天消息的同步和存储方案探讨》(* 力荐
以微博类应用场景为例,总结海量社交系统的架构设计步骤
一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践》(* 力荐
社交软件红包技术解密(一):全面解密QQ红包技术方案——架构、技术实现等
社交软件红包技术解密(二):解密微信摇一摇红包从0到1的技术演进
社交软件红包技术解密(三):微信摇一摇红包雨背后的技术细节
社交软件红包技术解密(四):微信红包系统是如何应对高并发的
社交软件红包技术解密(五):微信红包系统是如何实现高可用性的
社交软件红包技术解密(六):微信红包系统的存储层架构演进实践
社交软件红包技术解密(七):支付宝红包的海量高并发技术实践
社交软件红包技术解密(八):全面解密微博红包技术方案
从游击队到正规军(一):马蜂窝旅游网的IM系统架构演进之路》(* 力荐
从游击队到正规军(二):马蜂窝旅游网的IM客户端架构演进和实践总结
从游击队到正规军(三):基于Go的马蜂窝旅游网分布式IM系统技术实践
瓜子IM智能客服系统的数据架构设计(整理自现场演讲,有配套PPT)
阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处
微信后台基于时间序的新一代海量数据存储架构的设计实践
一套亿级用户的IM架构技术干货(上篇):整体架构、服务拆分等
>> 更多同类文章 ……

即时通讯网 - 即时通讯开发者社区! 来源: - 即时通讯开发者社区!

标签:IM架构
上一篇:退出IM群聊成功后,依旧可以接收该群聊消息下一篇:一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

本帖已收录至以下技术专辑

推荐方案
评论 39
第一张技术指标的图有问题,四个特性有两个实时性
引用:登至必极 发表于 2021-03-15 21:30
第一张技术指标的图有问题,四个特性有两个实时性

画错了,马上改
卧槽,这效率太高了吧
引用:登至必极 发表于 2021-03-15 21:51
卧槽,这效率太高了吧

那必须的。。
有个问题需要咨询一下,比如连接层服务发布,或者连接层机器宕机,连接层突然断开,那么怎么向online服务同步客户端的状态信息,因为一重启,客户端连接全断了,后续有些用户不一定重登陆,导致这些用户在的redis里的状态一直是在线的,虽然不影响体验,但是总感觉不好,一种办法是,在维护在线状态的redis里用个过期key,通过客户端心跳延长过期时间,但是这样量太大的时候,对后端服务压力也比较大,有好的解决办法么?
引用:zhxh007 发表于 2021-03-16 12:09
有个问题需要咨询一下,比如连接层服务发布,或者连接层机器宕机,连接层突然断开,那么怎么向online服务同 ...

连接服务断开了,客户端一般都会重连其他连接服,
存在同时连接服崩了,客户端杀进程了,这种概率太小了。也不用考虑吧
感觉搞IM,直播类的都是这套架构
真是亿级?
引用:zhyf888 发表于 2021-03-23 22:02
真是亿级?

哈哈哈
看了好多遍,有一个问题指教一下,哈
7.3节
此过程主要记录的信息包含:
1)uid(用户id);
2)Login服务器IP/Port;
3)Route服务器的IP/Port。
这是将uid和login服务关联信息保存到online服务吧?那这个router服务器的信息保存起来有什么作用,而且用户请求登录验证的时候,也不知道router服务器信息吧
引用:bingo2021 发表于 2021-06-14 14:56
看了好多遍,有一个问题指教一下,哈
7.3节
此过程主要记录的信息包含:

login服务器主要负责接入层,router服务器负责消息的收发路由,login+router服务信息,聊天消息就可以准确定位到这个用户的通信链路
引用:JackJiang 发表于 2021-06-14 20:26
login服务器主要负责接入层,router服务器负责消息的收发路由,login+router服务信息,聊天消息就可以准 ...

记录这个login+router的通信链路,实际的意义在哪里呢
个人理解是:
上行消息:login->router,这个router是需要通信链路保存的那个吗,不需要吧,对于集群多个router节点来说,应该任何一个都可以处理吧;
下行消息: 业务系统->router->login,对于集群多个router节点,业务系统是随机找一个router节点发送的,那此时保存的login+router通信链路好像也没意义了。这个时候应该是router收到消息、查找online服务获取消息应该发送到哪个login服务即可吧。

理解可能有点偏了,希望指点一下,谢谢
引用:bingo2021 发表于 2021-06-15 14:19
记录这个login+router的通信链路,实际的意义在哪里呢
个人理解是:
上行消息:login->router,这个rou ...

就这么说,如果把login->router这两个东西合二为一,不拆分开,你仔细想想是不是就好理解了。
作者之所以分开,就是因为它的量太大了,如果没这么大量的话不拆开就清晰多了
引用:JackJiang 发表于 2021-06-15 14:47
就这么说,如果把login->router这两个东西合二为一,不拆分开,你仔细想想是不是就好理解了。
作者之所 ...

哈,明白,就怕作者的意图被我理解歪了。
另外那个推送服务,数据输入方是谁啊,业务系统调用推送服务?
推送服务需要判断用户是否在线,如果在线是不是发给router服务,正常情况下router也要判断用户在哪个login服务,这就进行了2次判断了,是否重复了?
业务系统下发信息,文中说是发给router服务,如果router发现用户不在线,那么router是否有把消息发给推送服务的功能,那此时感觉推送服务又要判断应该怎么推送,也得判断用户在线
请问一下这个推送服务的数据流是怎么样的,对接哪些微服务?
引用:bingo2021 发表于 2021-06-15 15:03
哈,明白,就怕作者的意图被我理解歪了。
另外那个推送服务,数据输入方是谁啊,业务系统调用推送服务? ...

推送服务是可以做到提供给别的服务调用的,比如开放http接口。
判断在线的问题,其实就是你上面纠结的login+router这个逻辑
引用:JackJiang 发表于 2021-06-15 15:33
推送服务是可以做到提供给别的服务调用的,比如开放http接口。
判断在线的问题,其实就是你上面纠结的lo ...

哈,再参悟参悟哈,谢谢啦
1 pushProxy为什么要单独做出来呢?直接让调用方写消费者不好吗?
2 pushServer和PushWorker为啥不合并成一个服务呢
引用:XuFengnian 发表于 2021-06-28 13:58
1 pushProxy为什么要单独做出来呢?直接让调用方写消费者不好吗?
2 pushServer和PushWorker为啥不合并成 ...

一般是可以不拆的,但他的用户量太大了,拆出来显然架构的性能压力就可以更加分散地处理了
三个月之前~Mark一波
打赏楼主 ×
使用微信打赏! 使用支付宝打赏!

返回顶部