基于Tars高并发IM系统的设计与实现–基础篇1
作者简介
兰怀玉
毕业于中央民族大学计算机专业
先后供职国内外多家公司软件研发设计岗位,有丰富的软件研发经验。
从事IM领域设计研发十余年,先后领衔多个IM通讯系统设计与研发发,拥有丰富的IM系统设计研发经验。
综述
我曾经做过一个比喻,IM(即时通信)系统好比发动机,是一个系统的核心。
我国在导弹领域能够独立自主,而且很厉害,但是在飞机方面一直略逊一筹;都是飞行器,为什么呢?
因为要求不同,火箭发动机属于一次性产品,不可重复利用,只要把火箭送上天使命就完成了;飞机则不同,飞机对发动机的要求比火箭高很多,要既能飞出去,还能飞回来,重复使用不能出故障。
所以能做好火箭发动机不一定能做好飞机发动机,飞机发动机要像火箭发动机那样会出人命的。
同样的道理,你研发一款低频使用系统和高频使用的系统对技术的要求也不一样。
IM是一个要求很高的高频低延时系统,要求越高,研发门槛自然就越高;
现在我就IM的技术,带领大家一探究竟。
后续将内容分基础篇,进阶篇,实战篇三部分逐步刨析IM设计实现。
基础篇
IM简介
IM定义
InstantMessaging 即时通讯、实时传讯,能以最快的速度把信息从一方传递到另外一方。
即时通信系统(IM,Instant Messenger)是一款跨平台(Linux Server,Windows Server),可定制的 P2P 即时通信系统(集成多人视频会议功能),为各行业门户网站和企事业单位提供“一站式”定制解决方案,打造一个稳定,安全,高效,可扩展的即时通信系统.(来自百度百科)
IM软件
- ICQ
- 腾讯QQ
- 微信
- 易信
- 钉钉
- 飞书
- 百度HI
- 飞信
- 阿里旺旺
- Skype
- Google Talk
- Whatsapp等
IM发展历程
-
第一款即时通讯的诞生
随着互联网的发展,人们迫切地需要一个在线聊天系统,以解决工作中遇到的一些问题。
1973年,Doug Brown 和 David R. Woolley在伊利诺伊大学的柏拉图系统上创建了Talkomatic,它是世界上第一款即时通讯系统。
Talkomatic提供了六个频道,每个频道允许最多五名用户在线聊天,后来这一系统被应用在世界上第一个网络论坛PLATO Notes上,直到上世纪80年代,这个论坛才逐渐消失在人们的视野中。
Talkomatic的信息发送方式,与如今的QQ、微信等即时通讯软件不同。我们使用微信进行交流时,需要先将文本消息打出来,再点击“发送”按钮,对方才能看到消息。而Talkomatic却是实时的,发送方每键入一个字,接收方能立即收到。
你可能以为这么古老的东西,应该早就经消失了吧?然而,就是这么一款远古级的东西,在2018年还发布了第4个版本,以支持更多种类的现代浏览器和显示分辨率.
随着互联网的发展,即时通讯软件开始出现。其中由三个以色列青年开发的ICQ最为出名,它是世界上第一款即时通讯软件。
ICQ一经推出,在短短6个月的时间,便成为当时世界上用户量最大的即时通讯软件,即便在当时互联网比较不发达的亚洲,市场占有量也超过了70%。
1998年,ICQ用户量达到1200万,被AOL看中,以2.87亿美元收购。 -
QQ
几乎与此同时,身在中国的马化腾,看到了即时通讯的巨大商业价值,将为寻呼台建立网上寻呼系统的主要业务,变更为开发即时通讯工具——OICQ。
就在OICQ席卷中国即时通讯市场之时,ICQ母公司美国在线起诉腾讯侵权,这才有了后来大名鼎鼎的腾讯QQ。 -
移动IM
手机等移动设备的普及迎来即时通讯软件发展的第二春,各个国家均派生出不同的即时通讯软件,例如美国的Whatsapp、日本的LINE、韩国的Kakao Tall,以及中国的米聊,微信。 -
广义IM
现在即时通讯与近代即时通讯的不同之处,在于领域更加细分化。既有面向个人的即时通讯工具,也出现了企业级即时通讯工具。
与个人不同,企业级即时通讯软件更强调安全性、实用性、稳定性和扩展性,有的企业级即时通讯软件还支持定制,极大提高了企业内部的沟通效率。
即时通讯软件的发展,仅仅是互联网信息洪流中的一个产物,但其从诞生到兴盛,也经历了漫长的五十多年的发展,如今即时通讯已经成为人们工作和生活的一部分。
IM对技术的要求
说起IM,每个人的理解都不通,有些说不就是个即时通讯吗,很简单;也有人说IM对技术要求很高,很不容易。
这两种说法都没错,只是观察角度和要求不同。
持前一种说法的人,要么就是扫地僧水平的高手,要么就是一个新入行的新手,只是开发一个demo而已。
持后一种说法的人跟IM系统有个亲密接触,有一些这方面的经验,也遇到过一些棘手的问题。
国内做IM最厉害的公司是腾讯,以IM起家,统治互联网流量数十年;在2011年前后也遇到过危机,就是移动互联网兴起的时候,国内雷军同学搞了个米聊当时很火,很快就拥有几百万用户,当用户上升到一定程度之后,米聊出现用户量暴涨导致宕机,服务不稳定等因素,最终导致腾讯的微信后来居上,一举超越奠定了今天微信移动互联网江湖的统治地位;当然微信的超越不仅仅是因为米聊宕机不稳定一个原因,但是这个不稳定也是很重要的一个因素;就好比两军对战时,你的导弹发射系统老出现问题,对方一定会抓住战机猛攻,如果不能快速恢复,对方攻击直至你最终战败.感兴趣的朋友可以再网上找找相关资料。
腾讯微信的快速发展,并且超越,用户高速增长,稳定服务跟腾讯在IM领域的长期积累密不可分,IM作为高频使用的系统对服务的稳定性非常敏感,有一点延迟或者不稳定用户都可以感受到,从而影响用户体验。
IM技术体系
经过多年IM系统开发设计工作,本人对IM的技术总结为一句话“IM技术一二三四五”;
具体如下:
- 一个通讯协议
- 两个架构
- 客户端端
- 服务端端
- 三大指标
- 高可用
- 高并发
- 低延时
- 四大模块
- 连接管理
- 用户及好友管理
- 消息管理
- 离线推送
- 五大难题
- 连接稳定
- 消息一致性
- 历史消息
- 未读数
- 超大群
后续篇章主要针对以上5个方面进行详细阐述,一步一步教您如何构建一个高并发IM系统。
一个通讯协议
通信协议解释
通信协议是指双方实体完成通信或服务所必须遵循的规则和约定。
通过通信信道和设备互连起来的多个不同地理位置的数据通信系统,要使其能协同工作实现信息交换和资源共享,它们之间必须具有共同的语言。交流什么、怎样交流及何时交流,都必须遵循某种互相都能接受的规则。
这个规则就是通信协议。
IM通讯方式
IM系统需要把信息或者数据从A发给B,一般都有2种方式:
端对端方案
直接从A发给B。
图1 端对端方案
服务器中转方案
A通过服务器S将信息发给B
该特点主要有:
- 服务稳定性依赖于S服务器的稳定性,而不是依赖于A,B
- 消息集中处理,存储更易维护监管
- B客户端不在线时,不影响消息A客户端消息发送
- 可以存储查看历史消息
- 消息时序,未读数计算,多端同步等更方便
当前市场上主流IM系统基本都采用此方案。
通信协议要素
不管用前文中的方案1还是方案2,当消息A发送的到B时,都需要对方能识别,要做到识别就需要制定一通信协议来约束;
要确定IM通信协议,主要根据以下几个要点要素进行展开:
- 通讯方式
- 协议类型
- 协议结构及编码方式
- 协议包含的业务
通讯方式
常见的通讯方式主要分为TCP和UDP两种,两种方式各有千秋,都可以使用;
-
TCP是有连接的数据传输方式,能保证数据的可靠到达,开发者只需要做好业务逻辑即可;
-
UDP是无连接点对点发送数据,不能保证数据可靠到达,开发者需要自己进行数据可靠到达做相应的工作;
为了减少前期工作的复杂程度和工作量,大多数都会选择用TCP进行通讯。
TCP又分为长连接和短链接,IM系统为了能准时及时发送收取数据,基本都使用长连接;
协议类型
主要有文本类型和二进制类型;
文本类型协议主要载体就是普通文本进行描述和解析,比如HTTP协议;
二进制协议以二进制形势进行描述和解析,比如MQTT、QQ,微信都是二进制协议;
协议结构及编码方式
二进制协议一般都会将协议分为三部分,报文长度,协议头,协议体;
字段 | 说明 |
---|---|
Length | 报文长度(包含本字段4字节) |
Header | 报文头,所有控制报文都包含 |
Payload | 消息体,以报文头中定义的格式(json、xml、pb、tars)二进制传输 |
协议头包含数据包版本号,业务类型,唯一标识,协议体数据的编码方式等信息;
协议体主要包含针对具体业务所包含的数据;
字段 | 长度 | 说明 |
---|---|---|
type | 2字节 | OMTP控制报文的类型, |
version | 2字节 | OMTP控制报文的版本号, |
flag | 4字节 | 详见下文flag说明 |
packId | 16字节 | 报文Id,建议为UUID |
协议包含的业务
IM协议的定义主要包含如下业务:
- 用户登录及身份认证
- 退出登录
- 用户被踢
- 心跳
- 业务通知消息发送/响应
- 单聊消息发送/响应
- 群聊消息发送/响应
- 最新消息会话,未读数获取请求/响应
- 历史消息获取/响应
- 数据同步请求/响应
- 开始旁听会话请求/响应
- 结束旁听会很请求/响应
- 群聊创建请求/响应
- 群聊解散请求/响应
- 群聊加人请求/响应
- 群聊减人请求/响应
- 群聊名称,头像等修改请求/响应
以上是对协议要点进行简单表述,具体协议详见文章《OMTP协议说明文档》。
OMTP协议说明文档
https://github.com/lanhy/otim/blob/main/doc/OMTP协议说明文档.md
两个架构
主要指客户端架构跟服务端架构,针对这两个架构分别进行说明
客户端架构
架构方案概述
目前App的开发主要有如下四个方案:
- H5 方案
- 纯原生方案
- 跨平台SDK+原生UI交互
- 跨平台SDK+跨平台UI交互
以上4个方案各有千秋,下面逐一进行分析;
方案一:H5 方案
该方案一般采用websocket长连接或者http短链接与IM服务端交互(具体交互细节此处不再赘述)。
此方案优缺点分析;
- 优点:是开发速度快,跨平台性好,一套代码各个平台都可以使用,升级方便;
- 缺点:依赖js引擎和浏览器渲染,H5+js做端链接低频应用勉强可以;对于IM这种高频大数据量的应用,加上js对于存储和本地资源访问的限制,后期对卡顿,加载慢,动画效果差等缺点没有好的方案来优化解决,大多数团队都会转到后面的3个方案上。
方案二:纯原生方案
每个App端独立开发,实现各自的通讯,协议栈,数据存储,业务逻辑和UI交互;
优缺点分析;
- 优点:
此方案利用每个操作系统的特性,在用户体验上很容易达到用户期望,也是使用较广的一个方案; - 缺点:
ios,android,windows,MacOS,Linux每个操作系统都一个团队来开发,所有业务逻辑和数据处理针对每个平台都需要实现一遍,浪费开发测试资源,从成本上来算不经济。
采用此方案没有技术障碍,如果选择的开发框架提供的组件库不能满足要求,还可以通过访问操作系统底层API来解决问题。
方案三:跨平台SDK+原生UI交互
SDK负责实现通讯,协议栈,数据存储,业务逻辑;每个平台单独实现部分高频UI交互,比如登录,会话列表,单聊会话,群聊会话,会话设置等。
SDK一般用c/c++实现,跨平台性好,效率高,每个操作系统对c/c++的支持都很好,底层直接调用std标准库和操作系统API实现相应的功能需求;通过在各个平台进行交叉编译,实现一次代码,到处编译的状况。
此方案用户体验没问题,解决了方案二的人员浪费问题,底层通讯,协议栈,数据存储,业务逻辑在DK中实现,不用每个平台自己实现,节省不少人力资源。
-
客户端架构图
-
客户端SDK架构图
优缺点分析;
- 优点:用户体验最佳,团队成员减少。
- 缺点:对SDK开发人员要求门槛较高,需要熟悉C++语言及每个平台特性。
方案四:跨平台SDK+跨平台UI交互;
此方案是对上一个方案三的局部优化。
SDK实现了底层通讯,数据,逻辑的统一化。
有些同学说了,既然底层通讯数据处理,业务逻辑可以做成跨平台SDK,那UI能不能也做成跨平台的,当然能了。
主要有如下跨平台UI可以选择:
Flutter
Flutter 是 Google推出并开源的移动应用开发框架,主打跨平台、高保真、高性能。
开发者可以通过 Dart语言开发 App,一套代码同时运行在 iOS 和 Android平台。 Flutter提供了丰富的组件、接口,开发者可以很快地为 Flutter添加 native扩展。
同时 Flutter还使用 Native引擎渲染视图,这无疑能为用户提供良好的体验。
Flutter属于新技术,在IM领域目前没有成熟先例,需要预研如下问题:
- 系统原生API的兼容性与支持,一些原生化问题要能解决,比如每个平台UI交互流畅和动画的支持,桌面图标角标,push提醒等
- 高频,大量数据刷新的性能;
- 长时间运行内存和性能是否能达到指标;
Qt
Qt是一个1991年由Qt Company开发的跨平台C++图形用户界面应用程序开发框架。它既可以开发GUI程序,也可用于开发非GUI程序,比如控制台工具和服务器。Qt是面向对象的框架,使用特殊的代码生成扩展(称为元对象编译器(Meta Object Compiler, moc))以及一些宏,Qt很容易扩展,并且允许真正的组件编程。
针对windows,Mac 平台个人比较推荐使用Qt开发UI,技术成熟,性能好,既能满足Windows,Mac,也能够将来兼容UOS(Linux);一套代码三个平台,爽否?
通过以上分析,方案三和方案四无疑是较好的选择;
从投入产出比来看,如果方案四中Flutter能解决ABC问题属于最佳方案;具体情况各位同学可以根据自己团队实际情况来选择。
服务端架构
服务端架构的发展到目前为止单体结构已被淘汰,以微服务架构为主流,IM服务端架构也不例外,采用微服务架构进行设计开发。
目前开源的微服务架构有很多,比较适合IM服务开发个人推荐腾讯的Tars框架;毕竟站在巨人肩上,少走弯路;
本人使用Tars框架有将近7年,基础通讯能力很稳定,未出现大问题;
Tars微服务架构
- Tars是一款高性能、多语言的微服务治理框架。
- TTars在腾讯内部名为TAF,内部从08年开始使用,到现在将近10个年头了,目前该框架在腾讯内部,有100多个业务、1.6多万台服务器上运行使用,服务内部使用TARS协议通讯。
- TTARS 协议采用接口描述语言(IDL)来支持多种编程语言,C++、Java、Node.JS、PHP、Python、Golang等,使不同平台、不同语言编写的程序能够相互通信交流,打破语言屏障。
下文简要介绍其特点。
TARS协议:
采用接口描述语言(IDL)来实现,它是一种二进制、可扩展、支持多平台、多开发语言的协议, 主要应用在后台服务之间的RPC通信协议,以及对象的序列化和反序列化等方面。
-
调用方式
通过定义服务提供的接口,自动生成客户端和服务端的相关通信代码,只需实现业务逻辑即可对外提供服务,服务间调用支持同步调用、异步调用和单向调用三种模式。 -
负载均衡
框架通过名字服务来实现服务的注册与发现,客户端通过访问名字服务获取到被调服务的地址信息列表,并根据需要选择轮询、hash、权重等多种负载均衡方式来调用服务。 -
IDC/SET分组
为了减少网络资源消耗及网络故障带来的影响,框架提供了跨地区、跨机房、就近接入的IDC分组功能。为了方便对业务服务部署管理进行标准化和容量化,框架提供了互不干扰、故障隔离的Set部署能力。 -
集中配置
对业务配置进行集中管理并且操作web化,使配置修改更容易,通知更及时,配置变更更安全,服务只需调用配置服务的接口即可获取到配置文件。 -
容错保护
容错保护通过两种方式实现:名字服务排除和客户端主动屏蔽。名字服务将把连接失败的服务器从地址列表中去除。同时,客户端会把持续连接超时的服务器从地址列表去除。 -
过载保护
为了防止业务因为访问量突增或服务器故障造成系统整体的繁忙,进而导致全部服务的不可用,框架内部实现请求队列,服务调用通过非阻塞方式实现异步系统,从而达到提升系统处理能力的目的。 -
消息染色
框架提供了对某服务某接口的特定请求进行染色的能力,染色的消息可以透传到后面需要访问的所有服务上,使用者只需在染色服务器上即可分析请求访问的路径,方便跟踪定位问题。 -
数据监控
为了更好反映和监控小到服务进程、大到业务的运行质量情况,框架提供了服务模块间调用信息统计、用户自定义属性数据、服务状态变更和异常信息上报的功能。
Tars具体详见:https://tarscloud.org/
IM服务需要的能力
- 客户端接入管理及长连接维护
- 登录认证
- 单聊消息转发
- 群聊消息转发
- 业务消息处理
- 群聊业务处理
- 消息存储,未读数计算
- 消息撤回,消息覆写
- 离线Push推送
- 开放平台及接口(供其他业务系统调用)
- 用户资料及好友关系管理
IM服务架构及模块
要完成以上能力需要一些服务来处理相应的业务,下图中蓝色区域内为IM子服务:
-
IM子服务及外部交互图
-
接入服务:
负责客户端接入及长连接维护,客户端App与接入服务保持长连接,用OMTP自定义二进制系协议进行通讯; -
认证服务:
负责用户登录合法性认证 -
单聊服务:
负责单聊消息的处理及转发 -
群聊服务:
负责与群聊相关的业务,有群聊消息的处理,转发,群聊创建,群成员维护等。 -
通知消息服务:
业务通知及数据同步消息的处理 -
离线消息服务:
主要负责历史消息,未读数的存储,处理 -
用户好友服务:
主要负责好友维护,用户信息维护 -
开放平台及接口服务:
对外提供发送消息的http服务,其他业务服务通过该服务提供的restful接口进行通讯的
服务间交互与通讯方式
服务间交互关系图:
- 接入服务,开放平台及接口服务提供对外接入和服务,其他服务都是内部服务,外部服务或app不可以直接访问;
- 接入服务提供TCP长连接维护,客户端App通过TCP长连接用OMTP自定义二进制系协议进行通讯交互;
- 开放平台及接口服务为Http网关服务,负责对其他业务线提供IM服务,其他业务线通过该服务提供的restful接口进行接口调用。
- 内部服务间通过RPC调用进行交互,RPC调用分为同步调用和异步调用,具体根据业务情况来确定,对于一个IM系统来说,大多数业务都是异步完成的,为了提高系统的处理能力建议采用异步来进行处理。
IM服务部署
IM服务部署完全遵守Tars框架部署方式,接入服务器之前用nginx做负载均衡服务;具体见下图;
至此,对于IM服务端和客户端基本有清晰的认识了,如何处理业务,如何支撑百万并发等问题,后续一一讲解。