12月1日,由58同城携手腾讯云联合举办的第2期即时通讯技术沙龙专场在望京科技园顺利举行。来自阿里、腾讯、美团等160多位技术大牛参与本次活动,现场火爆到工作人员都没地坐。值得一提的是本次活动联合58部落,在“码农俱乐部”进行图文直播,受到广大技术爱好者的好评。相比第1期,活动报名人数和到场率都有了非常大的增长,今天我们就来还原现场,干货全盘输出!来一张现场大佬们合影照片镇楼!

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(1)


本次沙龙活动的议题如下:

《58 同城面向亿级用户 IM 长连接服务设计与实践》

《IM 消息存储及多端同步的架构与设计》

《58 同城 APP 中基于 IM SDK 的应用实践》

《基于音视频的腾讯云网络创新实践》

《实时音视频的架构设计与调优实践》

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(2)


干货精选
许刚:58同城移动端架构师


干货分享:《58 同城面向亿级用户 IM 长连接服务设计与实践》

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(3)

58同城是全国最大的分类信息平台。我们有大量的C端用户,包括58同城,安居客,58部落。我们有大量B端商家,包括移动经纪人,招才猫,二手车,商家通等等。作为全连接战略的重要部分的即时通讯服务,在内部也叫微聊,为我们的用户和商家提供了一个便捷的沟通渠道。我们服务的用户量达到了上亿级别。长连接服务作为即时通讯的核心能力之一。长连接服务的背后连接着消息服务,用户服务,群组服务,帮帮服务。长连接的前面通过负债均衡TGW之后连接着Android设备,iOS设备,Web浏览器,PC应用程序。在这样场景的情况下,必然要求长连接服务需要做到高性能高并发,需要做到兼容多个平台端,需要做到连接稳定可靠。


高性能高并发

设计评估:

1.核心功能: 建立长连接,保持长连接在线,能够收发即时通讯消息。提供稳定可靠的连接服务。

2.CPU使用评估:充分使用机器的CPU资源,移动设备,Web浏览器建立连接和断开连接比较频繁,CPU负责建立连接的线程负载高。用户活跃,收发巨量消息的时候,需要用到CPU资源多。

3.内存使用评估:保持大量用户在线,每个用户需要一个session存储,需要用到大量内存。用户活跃,收发巨量消息,每个用户都需要数据缓存,需要使用大量内存。


设计目标:

1.一台机器处理尽量多连接数

2.为线程合理分配任务,CPU资源充分使用

3.设计较好的数据结构,合理分配内存


socket监听和管理的线程模型设计:

1.单线程监听模型:全局建立一个单线程socket listener,每当监听到新的socket连接时分配给一个工作线程进行处理。

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(4)

如图所示,这是一个典型的单线程长连接设计模型,使用单线程处理连接,在移动App,Web页面建立和断开场景连接较多的情况下,单线程socket处理listener将成为瓶颈,在大量连接并发的情况下,容易丢失socket。

2.多线程监听模型

所有工作线程监听同一个socket,当有一个新的连接建立时,所有的工作线程去竞争accept此socket,只有一个工作线程会成功,其他的会失败,等待下一个连接的唤醒。该模型的优点是能够充分利用多线程的优势提高服务的响应速度。

同时该模型的存在缺点也很突出:(1)采用竞争方式获取连接,导致线程间资源分配不均衡。(2)存在惊群问题,新连接到达时所有工作线程都被唤醒,但是只有一个线程能够成功获取到任务,其他线程获取任务失败后继续休眠,每次唤醒会造成系统资源的浪费;(3)在负载较高时,线程处理任务延时比较大。

3.全线程监听模型

针对上述问题,我们对多线程模型进行优化。

1) 从线程考虑,根据物理机的内核配置,确定最优的线程数,充分利用CPU;

2) 每个打开的fd均匀分配到各个线程。操作系统在分配fd资源时是以递增的方式分配的,这样我们采用fd%线程数的方式将fd均匀分配到各个工作线程实现各个工作线程的负载均衡;

3)优化socket的监听方式。我们使用全线程监听模式,每一个线程创建一个套接字,多个套接字 bind()/listen() 同一个TCP/UDP端口。这种方式避免了单线程监听的方式监听线程负载过高;也避免了使用全部线程监听的方式时线程抢占命中率低的问题。

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(5)

4)惊群问题的优化:经过优化的多线程监听方式仍然存在着前文提到的惊群问题,在建立socket连接时多个监听线程依旧会被同时唤醒。针对这个问题,我们使用Linux的端口复用技术(SO_REUSEPORT),为每个工作线程生成建立一个套接字对象,这些套接字可以同时绑定(bind),监听(listen)同一个TCP/UDP端口,这样多个工作线程在socket监听上便不存在对性能有较大影响的多线程锁竞争,同时,系统在内核层面实现了连接的负载均衡。

至此,通过这样的设计,我们实现了对线程资源的充分利用。

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(6)

有关“线程间高效通讯”、“内存管理”等更多精彩内容点击“阅读原文”查找《58 同城面向亿级用户 IM 长连接服务设计与实践》进行查看


张辉:58同城后端架构师


干货分享:《IM 消息存储及多端同步的架构与设计》

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(7)

58IM即时通讯作为互联网时代重要的沟通方式,有着不可替代的作用,58同城IM——微聊,作为58平台的即时通讯服务,为58各业务提供了即时沟通的能力。

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(8)


单聊消息存储:

传统IM系统,因为不涉及多端的问题,也不用考虑客户端的存储能力,存储时更多的只是专注离线消息存储即可;但现代IM系统,因为涉及多端,存储设计时,必须要考虑到消息的多端同步,还要考虑到web、小程序这样没有存储能力的端,对服务端的存储就有了更高的要求。因为涉及多端,所以在存储时会涉及扩散问题,在方案上,就面临是读扩散还是写扩散两种选择。

首先简单介绍下写扩散方案,这种方案下,需要给每个用户每个端设置一个收件箱,按顺序存储用户收到的消息列表,在发消息时,除了要把消息写入接收方每个端对应的收件箱外,为了解决发送方多端同步的问题,还需要写入发送方发消息之外的端的收件箱,一条消息要写入多次,但每个端都只是在自己的收件箱内读取消息,所以说这是一种写扩散的方式。

写扩散方案最大的好处就是消息同步比较简单,端上接收消息只需要去对应的收件箱取就好了,但存储空间比较浪费,发一条消息要写多次,数据库写压力也比较大,同时,因为消息是不区分会话,按顺序存储的,那么消息量大的时候,获取历史消息只能按消息顺序回溯,不能按会话获取,有一定的局限性。

下面再简单介绍下读扩散方案,这种方案下,消息按会话存储,每个会话存储一份消息列表,会话双方共享这一份消息数据,多个会话就需要存储多个消息列表,端上接收消息时,要查询每个消息列表是不是有新消息,但一般情况下,大部分会话是没有新消息的,所以有很多查询是无效的。

读扩散方案最大的好处是节约磁盘空间,最大化利用存储,同时获取历史消息也可以按会话获取,效率比较高;但消息同步逻辑相对写扩散要复杂很多,还有很多无效查询。

在读扩散还是写扩散的选择上,一般来说IM是典型的一写多读场景,适合写扩散。但在58的业务场景下,涉及业务比较多,多个业务都有多端登录的需求,同一账号可能会在几十个端上登录,扩散要比一般的IM产品严重的多,并不适合采用写扩散的方式;而且58自研的Wtable分布式数据库读的性能要远高于写的性能,所以我们选择了读扩散的方案。

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(9)

1.每个会话存储一份消息列表,消息id全局递增

2.每个用户存储一份会话列表,会话记录该会话最后一条消息id,按消息id有序存储

3.写消息同时更新双方会话

4.通过读会话列表判断会话是否有新消息

因为Wtable是KV存储,消息列表的key设计成会话id,只有消息列表没办法根据用户ID索引到具体的消息,所以还需要给每个用户建立一个会话列表,用来索引每个会话对应的消息列表;同时因为Wtable每个key对应的列表天然支持有序,只要我们保证消息id是全局递增,就可以保证消息列表有序的同时,会话列表也可以按照会话的最后一条消息排序,只是存储消息时除了更新消息列表,还需要更新会话双方的会话列表,以保证会话的顺序;同时因为会话里存储了最后一条消息的id,前端读取会话列表后,就能判断该会话有没有新消息。


群消息存储:

群消息和单聊消息相比,最大的区别就是扩散范围更大了,单聊消息只涉及会话的双方,而群聊会涉及成千上万的群成员,所以群聊的存储方案也确定为读扩散,如下图所示:

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(10)

在介绍单聊的时候我们介绍过,因为存储系统的原因,需要存储一份会话列表作为消息的索引,同时会话列表里存储了会话最后一条消息的消息id,因此存储消息的同时,需要更新消息双方的会话列表;在群聊的场景下,会话不在只涉及双方,而是所有群成员,因此需要更新所有群成员的会话列表,导致了写扩散的问题。

为了解决群聊更新会话类表写扩散的问题,我们给每个群单独设计了一个群会话,专门用来存储会话的最后一条消息,这样存储消息时只需要更新群会话,不需要去更新全部群成员的会话列表了,群成员在取会话列表时,再来读取群会话中的消息id,补充到会话列表中;通过这样一种把写扩散变成读扩散的方式,解决了这个问题。

但这样又会引入新的问题,刚才介绍单聊存储是说过,会话列表是有序的,而且就是按会话里存储的最后一条消息的消息id排序的,如果存储消息时不更新会话列表,那会话的排序就不会改变,所以我们又做了以下机制解决这个问题:

1.用户获取会话列表时,补充群会话中的消息id,然后对会话列表重新排序;

2.单聊、群聊会话分开存储,排序时只处理群聊会话,取会话列表时合并两种会话;

3.异步、延迟更新群会话列表,每隔一段时间,异步更新一次群会话列表,保证活跃群会话一定排在前面,这样排序时就可以不用全量排序所有群会话;

最终,在解决群聊会话写扩散问题的同时,也能保证用户能够及时获取会话的变更信息。


消息同步机制:

所谓消息同步,简单来说就是让消息通过一定的机制,到达客户端,让接收方能看见。

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(11)

我们可以看下上面这张图,图片中的在线推送,就是最基本的一种同步机制,可以保证在线的时候把消息推送给接收方,但接受方离线时产生的消息,又是怎么同步的呢,下面我们来详细介绍。

上面介绍消息存储时,我们也简单提到过,在读扩散的方案下,用户的会话列表中存储了最后一条消息的id,用户需要通过获取会话列表的消息id,就能判断该会话是不是有新消息,所以我们同步消息之前,首先要同步会话列表。客户端想要获取会话列表,无外乎两种方式,要么服务端推,要么客户端拉,但这两种方式都有个问题需要解决,就是两端信息不对称,双方都不知道需要推或者拉多少,如果推或者拉全量,那就太浪费资源了,所以需要有一个信息同步的过程;所以我们采用了客户端带上信息拉取的方案,客户端拉会话列表的同时,带上本身已经存在的会话信息,服务端根据客户端当前已有会话情况,选择下发客户端需要的会话。同步会话列表除了客户端主动拉取之外,我们还做了一个小的优化,就是在客户端首次登陆没有任何信息的情况下,服务端主动下发会话列表,这样可以保证客户端启动时尽快展示会话列表,同时也不会造成资源浪费。

同步完会话列表之后,就需要同步消息了,客户端拿到会话列表里最后一条消息的信息后,首先需要根据这条消息判断,本地消息列表是不是完整的,还需不需要去服务端拉取完整消息列表;这里我们设计了这样一种机制,把消息列表串成了一个链表,每条消息都有一个属性,用来记录上一条消息的id,如果客户端读到一条消息,发现他的上一条消息本地没有,那就可以肯定,需要去服务端拉取了。通过这种机制我们不光解决了是不是有新消息到达的问题,还可以解决其他任何情况导致的客户端消息不完整问题,可以说无论何种情况,只要客户端缺少消息,都可以通过这种机制判断出来,然后拉取服务端消息补充完整。同样的客户端拉取消息,也是带上现有消息信息,服务端发现客户端消息已经存在,则不再下发。

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(12)

消息列表串成链表这种机制,确实解决了客户端判断消息完整性的问题,但同时也带来了新的问题,在并发场景下,如果两条消息同时发送,那两条消息存储的上一条消息id,可能会写成同一个,这样就导致链表不完整,为了解决这个问题,我们采用了动态建立链表的机制。上面讲存储的时候,我们说过消息列表是有序存储的,那既然已经是有序的了,我们就没有必要实际记录一份链表的关系,完全可以在获取消息列表的同时,动态构建链表关系,这样只要我们通过一定的事务机制,保证会话列表里存储的消息id一定是会话里最大的,就可以通过这样动态建立的方式,解决并发问题。

最终我们的消息同步方案是这样的:

1.用户在线,实时推送消息

2.用户首次登陆,推送会话列表

3.非首次登陆,带上客户端会话信息,按需拉取会话列表

4.消息有序存储,客户端通过链表机制判断消息完整性,按需拉取

微聊消息存储因为业务的特殊性,不同于一般的IM设计,采用了读扩散的方案,结合我们存储的特点,设计了一系列的方案解决消息同步问题,虽然这里很多问题是我们存储系统特有的,但是解决问题的思路是通用的,希望读者在自身业务上也可以得到些启发。


张志新:58同城客户端架构师


干货分享:《58 同城 APP 中基于 IM SDK 的应用实践》

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(13)

背景:

目前IM即时通信对于各大应用来说都是重要的功能部分,而且地位较高,线上沟通,可提高用户体验和APP的活跃度、流量,58也是对IM系统相当重视,承载各个业务线用户的线上沟通,为了给用户更好的IM体验,我们对IM做了很深入的研发,包括公司内部的IM体系自研底层SDK和server服务,功能优化和版本迭代。将IM模块模块的框架和近期为面向并行研发IM功能实现方案、项目经验和遇到的问题及解决方案跟大家分享一下。


IM功能模块的框架:

介绍IM功能模块的框架之前先讲一下早期IM功能的情况和问题

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(14)

早期IM是由无线平台开发维护,IM功能实现不完善,消息类型少,只有文本和语音,不支持音视频通话,消息无漫游,同一个账户在夸端登陆时会出现消息无法同步到新登陆的终端上,IM作为重要的功能和主框架耦合严重,未统一底层服务,未实现SDK化。

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(15)

早期IM也出现了一些问题,主要表现在4个方面:

1)层级结构,层级结构不清晰,类的功能职责不明确,代码逻辑相互耦合严重;

2)维护扩展,可维护和扩展性差,代码边界不清楚,开发维护成本高,部分功能在实现扩展方面较差,如消息协议,添加新的类型实现成本高;

3)问题排查,问题多,排查难,代码逻辑经过长时间的迭代后出现交叉依赖,难以梳理,问题难以修复;

4)基础逻辑,客户端和PC端的基础逻辑存在不一致的情况,跨端问题很难定位,部分需求实现不对齐;

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(16)

近期公司中台为提高IM功能的质量,搭建了即时通信服务,统一IM的实现,为各业务子公司提供基础服务,面向客户端应用开发了IM SDK(微聊 SDK),随后58同城APP中集成了这套IM 服务体系,在此基础服务上开发IM相关功能,这其中遇到了一些问题和大家分享一下,并讲一下我们的解决方案。

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(17)

现IM功能模块基于微聊 SDK的框架设计采用经典的三层设计架构,包括表现层、业务逻辑层、数据访问层。

结合框架的使用,在以下的分析讲解中会分层说明在项目中的作用;

I.表现层

1)IM相关界面的逻辑,IM数据展示和界面操作交互;

2) 功能模块化,UI界面区分出消息列表、会话列表、用户连接状态、消息未读数、帖子信息展示等功能;

II. 业务逻辑层

1)具体的操作逻辑,对表现层提供接口调用,链接数据访问层,承上启下;

2)用户输入的数据通过业务逻辑层的处理发给中间层;数据层返回的数据通过业务逻辑层发送给界面展示;

3)接口单一职责、易于业务逻辑维护;

该层为核心逻辑层,设计成两部分:

A)主要逻辑管理类组和API接口,按IM主要功能设计管理类,处理表现层需要的逻辑处理;B)转换功能,主要职能是数据转换、加密、数据缓存等,数据转换的设计是为让表现层隔离IM SDK的数据类,将IM SDK有自己的消息bean类转换为我们自己的bean类,已到达上层与SDK的隔离,这样升级SDK或替换SDK,对上层无影响;

III.数据访问层

数据来源层,IM SDK为我司自研的IM 体系微聊SDK、路由库、网络库;


分层架构实施后的优点

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(18)

介绍一下业务逻辑层核心逻辑的设计

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(19)

将IM的核心逻辑抽象了一个统一的入口类IMClient,作为IM功能的代表,包含多个业务逻辑管理类成员变量,与上层交互统一使用此类交互,调用方便简单,可读性操作性高,缩短API的学习时间,先将场景罗列,再抽象,明确管理类的职责,使管理类易维护可扩展,有利于单元测试。

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(20)

音视频通话的设计是底层服务采用我们公司开发的音视频通话WRTC SDK库,封装管理类WRTCManager,用于管理和对接音视频功能,音视频通话界面包括4个View,音频通话邀请/接通,视频通话邀请/接通,以状态驱动界面的展示和逻辑,音视频通话界面可以切换音频通话界面,可通过管理类操作WRTC库服务API。

有关“面向并行研发的IM功能实现方案”“思考与总结”等内容可以 点击“阅读原文”找到《58同城APP中基于IM SDK的应用实践》详细阅读


王剑飞:58同城资深架构师


干货分享:《实时音视频的架构设计与调优实践》

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(21)

WRTC是58同城TEG架构平台线为58各业务线提供的实时音视频通话解决方案,帮助业务线快速实现音视频通话及IP电话能力。在如今的网络环境下,58很多业务场景都有音视频通信的需求,比如IM场景,除了文字交流还需要音视频通话进行实时交互。WRTC能帮助58、安居客等业务线更好的为用户提供服务,节约沟通成本,提升效率,实现App客户端与Web端、小程序客户端、移动电话之间互相通话的功能。


即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(22)

客户端SDK:

这一部分是WRTC面向iOS、Android所提供的接入SDK,在工程架构上分为3个模块:(1)WebRTC基础能力模块,由TEG在开源软件WebRTC基础上改造而来,是WRTC客户端实践的核心功能,主要实现了音视频的采集、视频特效处理、视频编解码、信息传输、传输质量控制等功能;(2)WRTC通话管理模块,这一部分是对通话流程的抽象,包括房间管理、信令管理和状态管理,方便从逻辑层控制通话流程;(3)WRTC客户端API模块,该模块是WRTC向客户端提供的调用入口,对(1)(2)模块的功能进行了业务化封装,调用方只需要关心业务逻辑的实现和调用,无需过多关注通话功能的代码细节。


WRTC服务:

WRTC服务端包括媒体转换单元SFU、协议转换服务(SIP)、房间服务、STUN服务、信令服务、Nginx-RTMP等模块。WRTC中主要处理两部分数据,即信令和媒体。信令的处理是为了服务媒体通信,在一对一音视频通话中,有房间ID的概念,即是每一个房间只有两方,主叫和被叫。所以信令的逻辑主要包括房间状态的管理,媒体的信息与主被叫的绑定关系。在整体架构中,这部分的处理由信令服务和房间服务共同完成;房间服务通过同时控制SFU进行媒体的中转;协议转换服务主要负责WebRTC的协议和SIP协议的转换,完成App/Web浏览器到电话的IP电话能力;Nginx-RTMP模块主要实现推拉流的地址的分配。通过自研的媒体转换进行RTMP和RTP的转换,完成App/Web浏览器和小程序之前的媒体通信。在整体实践中,WRTC分别从SDK包压缩、首帧时间、网络结构、弱网对抗、丢包处理上做了大量的优化工作,对通话质量有了一定的程度的提升。在新技术的结合实践中,音视频服务积极扩展了VR带看功能,持续为业务赋能,效果如下图。

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(23)

除了一对一音视频外,扩展了多人音视频的能力。最多支持9人同时在线。并在此基础上通过和直播服务的结合提供了互动直播的能力。统一提供了一套一对一音视频、IP电话、多人音视频、直播、互动直播在内的完整的58视频生态。


现场活动精美照我们也来分享一波:

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(24)

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(25)

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(26)


关注【58技术】微信公众号,掌握更多优质一手干货

即时通讯基础知识大全 沙龙即时通讯及底层网络技术揭秘(27)

保存相册——微信扫一扫即可关注

,