前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【原创】开源OpenIM:高性能、可伸缩、易扩展的即时通讯架构

【原创】开源OpenIM:高性能、可伸缩、易扩展的即时通讯架构

原创
作者头像
OpenIM
修改2021-07-28 18:03:17
1.7K0
修改2021-07-28 18:03:17
举报
文章被收录于专栏:IM即时通讯技术IM即时通讯技术

开源OpenIM:高性能、可伸缩、易扩展的即时通讯架构

代码语言:javascript
复制
本文属于OpenIM技术团队原创,转载请注明出处,谢谢

网上有很多关于IM的教程和技术博文,有亿级用户的IM架构,有各种浅谈原创自研IM架构,也有微信技术团队分享的技术文章,有些开发者想根据这些资料自研IM。理想很丰满,现实很骨感,最后做出来的产品很难达到商用标准。事实上,很多架构没有经过海量用户的考验,当然我们也不会评判某种架构的好坏,如果开发者企图根据网上教程做出一个商用的IM,可能有点过于乐观了。本文主要从我个人角度深度剖析100%开源的OpenIM架构。当然,世界上没有最完美的架构,只有最合适的架构,也没有所谓的通用方案,不同的解决方案都有其优缺点,只有最满足业务的系统才是一个好的系统。而且,在有限的人力、物力,综合考虑时间成本,通常需要做出很多权衡。我们OpenIM的设计初衷,充分考虑了中小企业的需求,轻量级部署,同时也支持集群扩展,能支持几万用户,也能轻松扩展到上亿用户,是一个可信赖的开源项目。

IM系统技术挑战

可靠性

IM消息系统的可靠性,通常就是指消息投递的可靠性,即我们经常听到的“消息必达”,通常用消息的不丢失和不重复两个技术指标来表示。确保消息被发送后,能被接收者收到。由于网络环境的复杂性,以及用户在线的不确定性,消息的可靠性(不丢失、不重复)无疑是IM系统的核心指标,也是IM系统实现中的难点之一。总体来说,IM系统的消息“可靠性”,通常就是指聊天消息投递的可靠性(准确的说,这个“消息”是广义的,因为还存用户看不见的各种指令和通知,包括但不限于进群退群通知、好友添加通知等,为了方便描述,统称“消息”)。

从消息发送者和接收者用户行为来讲,消息“可靠性”应该分为以下几种情况:

(1)发送失败,对于这种情况IM系统必须要感知到,明确反馈发送方。如果此消息没有发送成功,发送方可以选择重试或者稍后再试。

(2)发送成功,如果接收方处在“在线”状态,应该立即收到此消息。如果接收方处在“离线”状态不能收到消息,一旦上线则立刻收到消息。

(3)消息不能重复,用数学术语表示:“有且仅有这条消息”,如果重复了,可能表达的意思就变了。 总之,一个商用 IM系统,必须包含消息“可靠性”逻辑,才能谈基本可用,这是IM系统最基本也是最核心的逻辑。

有序性(一致性)

IM系统中,特别需要考虑消息时序问题,如果后发送的消息先显示,可能严重扰乱聊天消息所要表达的意义,会造成聊天语义不连贯,引起误会。消息的时序性,也称为消息收发一致性,主要目标是:保证聊天消息的绝对时序。IM系统中消息时序的一致性问题看似简单,实则是非常有难度的技术热点话题之一。为什么会出现时序问题 1、分布式系统的出现导致时序不一致。IM系统模块众多,接入层、消息逻辑层等、每层都分布式集群化,这些应用分布在不同的机器上,如何保证时序是个难点。2、网络传输延迟导致时序不一致。不同用户发送的消息到达服务器的延时差异较大,给消息时序性带来挑战。

消息时序是分布式系统架构设计中非常难的问题,一个分布式的IM系统必须要解决这个问题,如何高效、低成本解决这个问题,是我们OpenIM要考虑的方向。

实时性

实时性,即消息实时到达接收方,如果用户在线,则实时可达,如果用户不在线,则登录时可达。由于网络波动,以及移动端操作系统对应用前后台切换的管理,如何实现用户连接管理、消息实时推送,推送失败的处理方式,客户端重连机制,消息如何补齐等,都是需要IM系统考虑,同时要结合移动端的特点,兼顾耗电量,网络,性能等。由于TCP开发略微复杂,早期的基于HTTP短轮询、长轮询的低效的技术方案,也无法达到实时性的要求。

扩展性

一般来说互联网系统的扩展性包含多个含义,我们侧重讲解关于IM消息的扩展性。IM业务特性多,功能丰富,从聊天类型来看,分为:单聊、群聊,聊天室等;从消息类型来看,分为:文本、图片、视频、地理位置、自定义消息等;从消息功能来看,分为:撤回、在线状态、对方正在输入、阅后即焚等;从通知角度来看,分为:进群、退群、添加好友、验证好友等各种通知。如何有效支撑、扩展功能,高效实现,是考验IM扩展性的一个方面,也是对系统架构设计能力的考验。为了更好地提高数据通道对业务支撑的扩展性,我们首创了“一切皆消息”的消息模型,即通讯双方产生的所有消息、通知,服务端以消息统一处理,扮演了消息通道的角色,客户端针对不同消息类型做不同的UI展示,完美解决了扩展性问题。

IM系统术语以及本文档专有名词解释

conversationId:会话Id,会话是指用户和用户之间,以及用户和群之间,进行通讯后产生的关联。

userId:用户Id:注册使用IM的用户Id,从消息的发送和接收来看有两个身份:发送者和接收者

sendId:消息发送者Id

receiverId :消息接收者Id

msg:消息是指用户之间的沟通内容,一般指用户主动产生的。同时也包括用户看不见的各种指令和通知,包括但不限于进群退群通知、好友添加通知等

inbox:用户收件箱,给某人发送消息,实际上是往接收者“信箱”写入消息,这个信箱就是收件箱

seq:用户收件箱中消息序列号,分为local seq,和server seq,前者表示app本地消息seq,后者表示服务端消息seq,seq是连续且递增的。

conn:登录用户的连接信息,用于消息推送;

MQ:消息队列,一般用来解决应用解耦,异步消息,流量削峰等问题,实现高性能,高可用,可伸缩和最终一致性架构,本文采用kafka组件。

OpenIM的诞生

随着移动互联网的蓬勃发展, IM 作为一种通讯能力,已经成为互联网上的基础设施,也是许多 APP 不可或缺的功能。如何让每一个应用都具备IM功能,同时考虑企业的接入成本、服务器资源以及最重要的数据安全性和私密性。本人从微信离职后,创办了开源OpenIM,是全球首家100%开源、免费项目,并提供IMSDK,覆盖所有主流开发平台,iOS、Android、Flutter、react native、Windows、Linux、Unity、web、小程序等。

开源IM现状

github 上 IM 开源项目不少,但开发者却难以使用,主要有几点原因(1)个人项目居多,但近几年都无人维护,遇到问题无人解决,企业商业化产品不敢冒险使用(2)大部分项目不是 IM 技术专业团队完成的,技术实力和技术架构存疑,也没有经过大项目和海量用户检验;(3)只开源服务端或者客户端,只开源某一端,需要开发者实现另外一端,研发成本同样不小,另外,开源项目大部分都是以聊天app形式开源,开发者如何把 IM 集成到自身 app 中,同样存在大量的修改和适配成本。(4)部分项目打着开源的旗号,社区版免费,但核心功能缺失,商业版收费。

云服务商的弊端

IM 云服务商提供 IM SDK 和 API ,让开发者简单集成 IM 功能,当然这里也存在明显的问题(1)成本问题:企业每年额外支付上万乃至数十万的云服务费用,从长期来看是个不小的成本;(2)数据隐私问题:企业的用户数据、聊天记录等核心数据托管在 IM 云服务商,如何保证客户的数据隐私和安全性;(3)需求定制问题:IM 需求多样化,IM 功能只能由 IM 云服务商通过 SDK 的形式提供给大家使用,开发受限,所有功能都需要封装成接口;(4)捆绑问题:一旦使用 IM 云服务,形成捆绑关系,迁移成本高,受制于人。

自研的尴尬

IM 是一个看起来门槛很低的项目,网上有很多所谓的 IM 开发教程,甚至很多毕业设计也是做一个 IM 系统。由于这个误区的存在,很多企业盲目乐观组建 3-5 人的 IM 团队,历时一年半载,最后只完成了一个 demo 版本。由于架构设计不合理,demo 版本存在消息丢失、系统异常等 bug,无法达到商用的要求。IM系统除了面临互联网业务系统本身的挑战,还存在上文分析的可靠性、时序性、扩展性等问题,所以,自研IM,对于中小企业来说,可能是最糟糕的选择。

OpenIM的整体架构

OpenIM分为两大块

(一)Open-IM-SDK-Core 采用golang实现客户端逻辑,主要负责本地db存储及更新;断网重连及管理;消息及各种通知回调。本地消息、会话等数据存储,通过通知机制完成本地数据实时同步,同时兼顾客户端缓存的作用,有效缓解了服务端压力。另外,golang跨平台的特性,使得各移动平台都能无缝调用,开发者只需根据产品需求编写UI界面,通过回调机制和SDK完成数据交互和通知。

(二)Open-IM-Server 由接入层、逻辑层和存储层组成,好处在于各层能够依据业务特点专注于自己的事情,提高系统复用性,降低业务间的耦合。

(1)接入层:消息通过 websocket 协议接入,其他业务通过 http/https 协议提供REST API实现。消息是高频及核心功能,通过双协议路由,体现了轻重分离的设计思想。

(2)逻辑层:通过 rpc 实现无状态逻辑服务,易于平行扩展,模块通过 MQ 解耦。

(3)存储层:redis 存储 token 和 seq;mongodb 存储离线消息,并定时删除 14 天内(可自行配置)数据;mysql 存储全量历史消息以及用户相关资料。数据分层存储,充分利用不同存储组件的特性。

(4)Etcd:服务注册和发现、以及分布式配置中心。

消息网关msg_gateway

消息接入层,采用websocket协议接入,import gorilla具体实现,服务模块无状态,柔性伸缩,运维简单。通过MQ让业务模块之间解耦,消息写入MQ即表示发送成功。

(1)负责用户连接管理,保持长连接,存储uid->conn映射关系;

(2)负责消息接收落地,成功写入MQ后给客户端返回成功;

(3)负责把消息推送给在线状态的接收者;

下图是客户端发送消息流程

消息转发msg_transfer

消息处理rpc,作为消费者从MQ中消费(读取)消息,递增接收者收件箱seq,关联seq和msg,并存储到mongodb。全量历史消息无收件箱概念,消息作为流水记录落地mysql即可,两者通过协程独立处理,双方互不影响。msg作为无状态服务节点,如果消息量增加,可以启动冗余节点服务,加快消息处理流程。

(1)负责消费MQ中的消息,作为消费者,实时感知新信息达到,并触发回调逻辑;

(2)生成msgId作为全局消息Id;

(3)读取receiver userId,并通过redis的incr操作递增服务端对应的seq;

(4)关联seq和msgid,并存入以receiver userid为key的mongodb中,作为离线消息,一般在14天后会删除;

(5)同时,把消息作为历史记录存入mysql中,作为消息备份,或其他用途。

(4)和(5)是两个独立的协程并行执行的,mysql写入快慢不会影响mongodb的写入,这样既完成了冷热数据分离,也充分利用了机器资源。

下图是消息处理入库流程

消息推送push

msg_transfer完成存储消息到后,向push发起消息推送任务,msg_gateway查询本地userId->conn表,如果用户在线则推送给接收者,对于msg_gateway的推送架构设计,做成了“半状态”服务,即在节点本地存储了用户连接信息,作为局部信息,没有通过redis全局共享。push推送消息时,向所有msg_gateway发送推送请求,带来一定的“惊群效应”,由于msg_gateway节点不多,所以影响有限,带来的好处则是在不影响性能的前提下,msg_gateway设计和实现简单,运维也更简单。

(1)msg_transfer把消息写入mongodb后,发送push消息推送请求;

(2)push提供rpc推送服务,通过etcd找到所有注册的msg_gateway,并发送推送请求;

(3)msg_gateway从本节点内存中查询userId->conn,如果找到conn,则向客户端推送消息;

(4)如果消息接收者不在线,msg_gateway无法推送消息,但客户端网络重连时会及时同步历史消息,进行消息补齐;

下图是消息实时推送流程:

消息同步及对齐seq

由于网络的波动以及负责的网络环境,导致消息推送存在不确定性。OpenIM采用local seq和server seq消息对齐,同时结合拉取和推送的方式,简单高效地解决了消息的可靠性问题。这里分两种场景进行表述:

(1)客户端接收推送消息时,比如客户端收到推送消息的seq为100,如果local seq为99,因为seq递增且连续,所以消息正常显示即可。如果local seq大于100,说明重复推送了消息,抛弃此消息即可。如果local seq小于99,说明中间有历史消息丢失,拉取(local seq+1, 100)的消息,进行补齐即可;

(2)用户在登录、或者断网重连时,客户端会从服务端拉取最大seq(max seq),读取客户端本地seq(local seq),如果local seq 小于 max seq,说明存在历史消息未同步的情况,调用接口同步自身收件箱[local seq+1, max seq]的数据完成消息对齐。

下图是消息同步流程图

本文主要简单阐述了OpenIM的架构以及消息流程,让开发者对其有初步认识,在接下来的文章中,我们会详细讲解OpenIM服务端消息架构,OpenIM客户端架构,同时会详细分析OpenIM如何简单高效解决消息的可靠性、实时性、一致性和扩展性问题。

更多阅读

基于Tablestore Timeline的IM(即时通讯)消息系统架构 - 架构篇

OpenIM官网

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 开源OpenIM:高性能、可伸缩、易扩展的即时通讯架构
    • IM系统技术挑战
      • 可靠性
      • 有序性(一致性)
      • 实时性
      • 扩展性
    • IM系统术语以及本文档专有名词解释
      • OpenIM的诞生
        • 开源IM现状
        • 云服务商的弊端
        • 自研的尴尬
      • OpenIM的整体架构
        • OpenIM分为两大块
        • 消息网关msg_gateway
        • 消息转发msg_transfer
        • 消息推送push
        • 消息同步及对齐seq
    相关产品与服务
    即时通信 IM
    即时通信 IM(Instant Messaging)基于腾讯二十余年的 IM 技术积累,支持Android、iOS、Mac、Windows、Web、H5、小程序平台且跨终端互通,低代码 UI 组件助您30分钟集成单聊、群聊、关系链、消息漫游、群组管理、资料管理、直播弹幕和内容审核等能力。适用于直播互动、电商带货、客服咨询、社交沟通、在线课程、企业办公、互动游戏、医疗健康等场景。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档