Jack Jiang

我的最新工程MobileIMSDK:http://git.oschina.net/jackjiang/MobileIMSDK
posts - 349, comments - 13, trackbacks - 0, articles - 0

2022年8月22日

本文内容由百度技术团队分享,原题“基于公共信箱的全量消息实现”,为了帮助理解,有较多修订、内容重组和重新排版。

1、引言

百度的IM消息中台为百度APP以及厂内百度系产品提供即时通讯的能力,提供包括私聊、群聊、聊天室、直播弹幕等用户沟通场景,并帮助业务通过消息推送触达用户。

如今,百度APP新增了一种需要以“低用户打扰”的形式触达全量用户的场景需求,而现有的IM消息中台主要是基于用户“私有信箱”通知拆分的机制(通俗了说也就是IM里的“扩散写”),所以如果不进行改造,是很难低成本、高时效的满足该场景诉求。

基于上述问题,本文介绍了百度现有IM消息中台系统的主要组成,并对比多种实现方案的优劣,以“公有信箱”通知读扩散的技术方案对现有IM消息中台系统进行改造,从而达成了低成本、高时效地实现全量用户通知推送需求。

技术交流:

本文已同步发布于:http://www.52im.net/thread-4235-1-1.html

2、全量用户消息推送需求背景

百度APP新增了需要通过IM实时通知触达全量用户的诉求,比如2022年12月7日解除疫情管控结束后,将经过筛选的官方政策解读、专题汇总、知识科普、实用工具类介绍等信息,通过官方号“x度小助手”下发触达到百度APP用户,从而来有效体现人文关怀,提高用户粘性。

在以IM消息服务进行全量用户消息触达时,需要满足以下诉求:

具体就是:

  • 1)在触达范围上:希望尽量扩大用户触达范围,包括百度APP月活用户、以及非月活用户但是近期新注册或登录的用户;
  • 2)在时效上:一次全量触达,希望短时间内完成(比如小时级、甚至分钟级),抢占时效性;
  • 3)在用户打扰方面:消息触达不能给用户带来较大的打扰,每次消息下发,只触达一次,不能重复打扰用户(但是需要保留回访入口,满足用户二次查看的诉求)。

3、现有IM消息中台的技术痛点

我们现有的IM(即时通讯)服务中,每个IM用户对应一个用户信箱。

基于现有的IM技术实现方案,如果想完成全量用户的消息触达,需要把消息推送到每个用户的信箱(也就是IM中的扩散写)。

这样的话,要完成6亿以上的消息写入(假定每条占用存储4KB,每秒写入2W条消息),在消息写入时效性以及存储资源消耗上,都是很难接受的。

且现有的基于用户私有信箱的方案,在同时支持多条全量用户通知消息的场景下,扩展性也较差。

基于上述需求背景和技术痛点,我们本次的改造目的,就是要找到一种技术方案,从而在特定业务场景下通过改造后的消息服务,低成本、高时效的给全量用户推送内容一致的消息通知。

4、现有IM消息中台的主要技术实现

在讨论改造方案前,我们有必要介绍一下目前IM消息系统的现状,包括消息系统的组成、通知拉取模式、用户信箱等。

4.1 消息系统组成

从普通用户的直观体验上看,一个IM系统可以包括如下元素:

  • 1)用户主体;
  • 2)用户账号;
  • 3)账号关系;
  • 4)聊天会话;
  • 5)聊天消息。

用自然语言串一下以上元素就是:

  • 1)“用户主体”具有“用户账号”;
  • 2)“用户主体”具有头像、昵称等用户属性;
  • 3)“用户主体”通过“用户账号”登录IM系统,进行聊天;
  • 4)“用户账号”之间的关注、屏蔽、免打扰等构成“用户关系”;
  • 5)通过用户之间的互动环节可以产生“聊天消息”;
  • 6)聊天记录构成了一个“聊天会话”。

下面这张图可能更直观一些:

从集成消息服务的业务方角度看:

  • 1)一个IM系统可以包括消息客户端(消息客户端UI组件、消息SDK)和消息服务端;
  • 2)IM消息可以作为一种服务,嵌入到各业务系统中,为业务系统提供“实时交互”能力;
  • 3)业务通过集成IM服务,提升其用户体验;
  • 4)业务APP集成IM SDK,通过IM SDK与IM Server交互,完成用户上行通讯能力;
  • 5)业务APP Server通过与IM Server交互,完成通知下行触达用户。

下图为一个集成了IM SDK的业务架构图:

从使用场景来看,消息包括:

  • 1)“私信消息”(包括用户上下行消息);
  • 2)“通知消息”(业务方给用户推送的下行消息);
  • 3)“群聊”、“聊天室”;
  • 4)“直播间弹幕”等。

4.2 消息的通知拉取模式

百度的IM消息系统,采用通知拉取(notify-pull)模式来感知新消息、拉取新消息。

IM SDK登录时,与IM 服务端建立长连接(LCS, Long Connect Service),用户有新的消息时,通过长连接下发notify,实时通知用户的IM SDK。

实时notify不写用户信箱,因为noitfy不是消息(可以理解为提醒在线用户有新消息的信号),IM SDK根据这个信号,来服务端拉取消息。

业务方server或者其他用户给该用户发送消息后,经过IM业务处理模块,把消息写入接收者信箱,IM Server会根据用户的登录和路由信息,给消息接收者(私信场景下也包括“消息发送者”,用于消息的多端同步)发送新消息notify,接收到notify的IM设备,通过IM SDK来IM Server端拉取(pull)消息。

4.3 用户信箱介绍

为了暂存尚未拉取到IM SDK本地的离线消息,需要对消息进行服务端存储,而消息的离线存储是通过消息信箱服务完成的。

目前百度的IM用户消息信箱主要包括:

  • 1)用户私有信箱;
  • 2)群公共信箱(非下文提到的用户公共信箱);
  • 3)直播间弹幕mcast等。

用户信箱通过“消息所属应用”+“IM标识用户的唯一ID”来标识。

就一条消息而言:消息参与者有“消息发送者”和“消息接收者”,消息收发双方的信箱都是相互独立的(假设发送方删除了自己信箱的某一条消息,不会影响消息接受者信箱的消息)。

对于有查看历史消息诉求的一方来说:消息需要入该方的信箱,比如用户之间的私信(也就是一对一单聊)消息需要入发送者和接收者的信箱。

而对于全量用户消息通知的场景:消息不需要存储发送者信箱,而只需要存接收者的信箱。而用户的信箱排序,是基于信箱Timeline(详见《现代IM系统中聊天消息的同步和存储方案探讨》)。即消息在信箱内部基于时间线存储,每条消息对应一个unix 微秒时间戳(如第一条消息1679757323320865),用户进行信箱拉取时,基于时间范围正序或者逆序拉取。

如下为信箱Timeline的示例:

用户信箱中的每一条消息记录都包含四个主要部分:

  • 1)“消息ID”;
  • 2)“消息用户标识”;
  • 3)“消息通用属性”;
  • 4)“消息业务属性”。

下面详细介绍以上四个部分:

  • 1)消息ID:为unix微秒时间戳,不需要全局唯一,只需要特定用户信箱范围内唯一即可;
  • 2)消息用户标识:包括from_uid、to_uid、contacter;
  • 3)消息通用属性:包括create_time、expire、is_read;
  • 4)消息业务属性:包括category、type、priority、business_type、APP_id、msgkey、content等。

如下为一条消息记录示例:

5、全量用户消息推送技术方案选型

5.1 需求分析

目前百度的IM消息推送机制中,主要支持:

  • 1)单播:消息推送方式,每次给一个用户推送一条消息;
  • 2)批量单播:每次给小范围用户推送消息,比如30个;
  • 3)广播:基于关注关系的推送,如给全量粉丝推送。

上述三种消息推送机制推送的消息,均需要存储服务端的用户私有信箱。为了完成百度APP 6亿以上全量月活用户的消息推送,目前有三种可选的方案,接下来我们逐一分析。

5.2 方案1:全流程从通知入口推送

该种方式下:需要获取全量的月活用户列表,经过IM Server推送入口,给每一个用户推送疫情相关通知。

该通知写入到用户信箱时:

  • 1)若用户在线,在实时拉取该通知;
  • 2)若用户离线,再下次登录IM服务时,拉取离线通知。

该种方案下:推送行为会覆盖IM的全流程,推送的通知会进入每个月活用户的私有信箱,服务压力大。其中增量用户不会收到通知推送(这里增量用户指的是不在月活用户列表的用户)。

5.3 方案2:跳过通知入口直接写信箱

该种方式跳过IM消息推送流程中的中间环节,直接把通知消息写入用户信箱。

由于跳过了中间流程直接写入信箱,通知写入速度主要取决于信箱底层存储的压力承受情况。

该种方案下,同方案1一样,无法给用户发送实时通知,依赖用户IM SDK的主动消息拉取(断链后重新登录/新消息提醒拉取),无法给增量用户发送通知。

该方案由于跳过中间环节直接写信箱,风险较大,无法直接提供给业务方使用,不建议如此操作。

5.4 方案3:公有信箱实现机制

该种公有信箱机制的逻辑是把通知消息写入“公共信箱”。在用户消息拉取时,合并“用户私信信箱”+“公共信箱”的消息。

5.5 三种方案比较

方案1和2都是写扩散方式,基于现有“用户私有信箱”的机制,把通知消息写入每个接收通知的用户私有信箱。

方案2与方案1的差别主要是跳过了消息中间流程,可以避免因为中间环节负载瓶颈导致整体消息写入速度过低。

方案3是读扩散方式,消息不用再写入接收通知的用户私有信箱,而只需要在公共信箱存储一份。在用户拉取消息时,实时拉取公共信箱的消息。方案③中可以采用内存缓存方案,解决对公共信箱的读压力。

本质上来说:方案3与方案前两种相比,是用读成本(CPU)换写成本(存储)。

6、基于公有信箱技术方案的全量用户消息推送实现

6.1 概述

基于上述方案3的思路,我们进行基于公有信箱的全量消息设计与实现。

该种方案中包含两个主要流程:

  • 1)全量消息的管理;
  • 2)用户私有+公有信箱的拉取。

6.2 全量消息的管理

全量消息管理主要分为:

  • 1)运营O端操作平台:复用运营消息平台;
  • 2)全量消息处理服务:复用IM服务的连接层、逻辑处理层、信箱代理、信箱处理。

运营O端平台为运营同学提供可视化界面,可以对全量消息进行编辑、预发布、发布、修改、停止、撤回等操作。

具体就是:

  • 1)接入层:对接运营O端,进行参数校验、转发IM后端逻辑处理模块;
  • 2)逻辑处理层:进行全量消息的创建、修改、停止、删除、撤回等逻辑操作;
  • 3)信箱代理层:复用IM服务的信箱CRUD操作;信箱存储层公共信箱的底层存储。

全量消息管理流程:

6.3 用户信箱拉取

用户通过IM SDK,以长连接的方式,在逻辑处理层进行消息拉拉取。

在用户拉取信箱消息时,需要对“用户个人信箱”和“公有信箱”进行合并。于是每次用户信箱拉取,都需要进行信箱的合并拉取。

6.3.1)公共信箱内存缓存机制:

百度APP的IM用户,在IM SDK登录时需要拉取信箱中的消息。每次消息拉取时,需要检查公共信箱中是否有消息。

因此,公共信箱需要能抗住日常和峰值流量(拉取峰值为4.7Wqps)。为了防止流量击穿,流量打到底层的持久化公共信箱MYSQL存储,我们设计了基于内存的公共信箱缓存机制。同时公共信箱内容变化时,也要实时(或者在能容忍的范围内做到准实时)变更内存缓存信箱中的消息,我们采用Bthread定期轮询持久化公共信箱,更新内存公共信箱,轮询间隔可配置(比如设置1秒)。

6.3.2)分级发布机制:

同时,在逻辑层实现白名单机制,支持全量消息在“预发布”状态下,仅对白名单用户可见,从而达到分级验证的效果。

白名单的用户列表通过逻辑处理成的配置加载,也支持通过CURL请求动态修改白名单的配置。

7、基于公有信箱技术方案的技术挑战

公有信箱的技术方案,需要解决如下问题:

8、基于公有信箱技术方案的优缺点总结

8.1 优点

以公共信箱的方式,实现全量用户消息分发,具有:“分发速度快”、“资源成本低”的特点。

8.2 缺点

但公共信箱的方式也存在一定的局限性。

8.2.1)不适用于个性化要求高的场景:

由于消息在公共信箱只存储一份,下发消息内容固定,无法很大程度下,下发个性化消息(当然也不是一定无法下发个性化的消息,可以通过在公共信箱存储消息模板,根据拉取消息的用户ID获取个性化信息,在消息拉取时,临时拼装消息,这样就增大了消息拉取时的代价)。

8.2.2)不适用于实时消息提醒场景:

1)从业务场景上看:全量消息优先级低,不需要在全量生效的瞬间让用户感知。

2)从实现上看:全量消息实时消息提醒成本高。因为实时消息提醒Notify,需要以类似单播的形式实时通知用户。和单播的区别是,Notify不用触达离线用户,也就是不用写用户信箱,只需实时触达在线用户。

3)从系统压力看:全量在线用户均收到实时新消息提醒,会带来信箱拉取请求的瞬时流量(手机百度IM SDK长连接峰值在线1550W,假定新消息提醒在瞬间下发,同时在线用户信箱拉取请求,会把db打挂的)。

9、基于公有信箱技术方案的落地实施效果

全量消息目前已经在百度APP得到应用,包括:重大通知的下发;百度APP功能更新介绍通知;消息的撤回,后续还将推广到其他的矩阵APP的全量通知推送场景。

举个具体的例子:22年Q4宣布疫情解封时,利用全量消息推送,低成本、高时效的完成3条“疫情解封专项”全量消息下发。

 

在这个例子中,三次全量消息下发,到达数据在2亿+(该值小于月活的6亿+),主要因为几个原因:

  • 1)本次全量消息有效期仅3天左右,全量消息有效期内登录IM SDK的用户才有机会拉到全量消息;
  • 2)本次下发使用了新的消息展示模板,所以限制了拉取全量消息的百度APP版本,只有高版本百度APP可以拉到;
  • 3)本次全量消息,限制了仅有百度APP登录用户拉取。

10、未来展望

本文介绍了现有IM消息中台系统,并通过公有信箱技术方案的改造,达成了低成本、高分发速度完成全量用户消息下发的设计、实现与应用。

在全量用户消息应用方面,除了业务上的使用,后续也可以用于广播消息、批量单播消息的撤回。比如由于误操作发送了广播消息,用户已经把广播消息拉到了端,并持久化到端,这是可以“以全量消息的方式,下发删除指令”,删除已经缓存到端的垃圾消息。

我们希望,通过消息系统持续不断优化,为更多的业务提供低成本、高稳定性的即时通讯能力。

11、相关资料

[1] 现代IM系统中聊天消息的同步和存储方案探讨

[2] 百度APP移动端网络深度优化实践分享(一):DNS优化篇

[3] 百度APP移动端网络深度优化实践分享(二):网络连接优化篇

[4] 百度APP移动端网络深度优化实践分享(三):移动端弱网优化篇

[5] 百度直播的海量用户实时消息系统架构演进实践

[6] 深入了解百度开源的分布式RPC框架brpc的方方面面

[7] 百度网盘千万节点的P2P架构设计(PPT)

[8] 零基础IM开发入门(一):什么是IM系统?

[9] 一套海量在线用户的移动端IM架构设计实践分享(含详细图文)

[10] 一套原创分布式即时通讯(IM)系统理论架构方案

[11] 一套亿级用户的IM架构技术干货(上篇):整体架构、服务拆分等

[12] 基于实践:一套百万消息量小规模IM系统技术要点总结

[13] 一套十万级TPS的IM综合消息系统的架构实践与思考

[14] 从新手到专家:如何设计一套亿级消息量的分布式IM系统

[15] 闲鱼亿级IM消息系统的架构演进之路

[16] 深度解密钉钉即时消息服务DTIM的技术设计

[17] 一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践

[18] 企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等

本文已同步发布于:http://www.52im.net/thread-4235-1-1.html

posted @ 2023-05-26 10:57 Jack Jiang 阅读(48) | 评论 (0)编辑 收藏

     摘要: ► 相关链接:① MobileIMSDK-Uniapp端的详细介绍② MobileIMSDK-Uniapp端的开发手册new(* 精编PDF版)一、理论知识准备您需要对Uniapp和Vue开发有所了解:1)Uniapp 官方入门教程2)可能是最好的 uniapp 入门教程3)Uniapp 官方 Vue 快速入门教程您需要对...  阅读全文

posted @ 2023-05-18 12:04 Jack Jiang 阅读(56) | 评论 (0)编辑 收藏

为了更好地分类阅读 52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第15 期。

[- -] IM跨平台技术学习(一):快速了解新一代跨平台桌面技术——Electron

[链接] http://www.52im.net/thread-2616-1-1.html

[摘要] 本文将从入门者的角度,为你快速讲解Electron到底是个什么技术,包括案例介绍、技术优势、技术体验、实现原理等。

[- 2 -] IM跨平台技术学习(二):Electron初体验(快速开始、跨进程通信、打包、踩坑等)

[链接] http://www.52im.net/thread-4039-1-1.html

[摘要] 本篇将带你简单上手Electron框架开发跨平台桌面端,内容包括一个快速开始例子、跨进程通信原理、打包和分发、以及一些典型的技术踩坑等。希望能带给你启发。

[- 3 -] IM跨平台技术学习(三):vivo的Electron技术栈选型、全方位实践总结

[链接] http://www.52im.net/thread-4044-1-1.html

[摘要] 本篇将基于vivo技术团队的技术实践,详细阐述了vivo在使用Electron进行跨端桌面开发时的技术栈选型考量,同时分享了在打包构建、版本更新、性能优化、质量保障、安全性等方面的实践方案和踩坑总结。

[- 4 -] IM跨平台技术学习(四):蘑菇街基于Electron开发IM客户端的技术实践

[链接] http://www.52im.net/thread-4051-1-1.html

[摘要] 本篇将回到IM即时通讯技术本身,根据蘑菇街的实际技术实践,总结和分享基于Electron开发跨平台IM客户端的过程中,需要考虑的典型技术问题以及我们的解决方案。

[- 5 -] IM跨平台技术学习(五):融云基于Electron的IM跨平台SDK改造实践总结

[链接] http://www.52im.net/thread-332-1-1.html

[摘要] 本文分享的是融云基于Electron的IM跨平台PC端SDK改造过程中所总结的一些实践经验,希望对你有用。

[- 6 -] IM跨平台技术学习(六):网易云信基于Electron的IM消息全文检索技术实践

[链接] http://www.52im.net/thread-4065-1-1.html

[摘要] 本文将要分享的是,网易云信基于Electron的PC端是如何实现IM客户端全文检索能力的。

[- 7 -] IM跨平台技术学习(七):得物基于Electron开发客服IM桌面端的技术实践

[链接] http://www.52im.net/thread-4159-1-1.html

[摘要] 本文要分享的是得物技术团队基于Electron开发客服IM桌面端的技术实践过程,内容包括桌面技术选型、Electron的基础概念、具体的实施技术方案、遇到的棘手问题等。

[- 8-]  社交软件红包技术解密(一):全面解密QQ红包技术方案——架构、技术实现等

[链接] http://www.52im.net/thread-2202-1-1.html

[摘要] 本文将从架构开始,到手机 QQ 移动端优化,再到个性化红包和 AR 新玩法,为大家全面解密 QQ 红包技术方案。

[- 9 -] 社交软件红包技术解密(二):解密微信摇一摇红包从0到1的技术演进

[链接] http://www.52im.net/thread-2519-1-1.html

[摘要] 本文要分享的是微信团队是如何从0到1实现“有把握”的微信春晚摇一摇红包系统的。

[- 10-] 社交软件红包技术解密(三):微信摇一摇红包雨背后的技术细节

[链接] http://www.52im.net/thread-2533-1-1.html

[摘要] 本文将由微信团队工程师张文瑞分享微信春节摇一摇红包技术背后的方方面面,希望能给同行们带来启发。

[- 11-] 社交软件红包技术解密(四):微信红包系统是如何应对高并发的

[链接] http://www.52im.net/thread-2548-1-1.html

[摘要] 本文将为读者介绍微信百亿级别红包背后的高并发设计实践,内容包括微信红包系统的技术难点、解决高并发问题通常使用的方案,以及微信红包系统的所采用高并发解决方案。

[- 12-] 社交软件红包技术解密(五):微信红包系统是如何实现高可用性的

[链接] http://www.52im.net/thread-2564-1-1.html

[摘要] 本次分享介绍了微信红包后台系统的高可用实践经验,主要包括后台的 set 化设计、异步化设计、订单异地存储设计、存储层容灾设计与平行扩缩容等。听众可以了解到微信红包后台架构的设计细节,共同探讨高可用设计实践上遇到的问题与解决方案。

[- 13-] 社交软件红包技术解密(六):微信红包系统的存储层架构演进实践

[链接] http://www.52im.net/thread-2568-1-1.html

[摘要] 微信红包本质是小额资金在用户帐户流转,有发、抢、拆三大步骤。在这个过程中对事务有高要求,所以订单最终要基于传统的RDBMS,这方面是它的强项,最终订单的存储使用互联网行业最通用的MySQL数据库。支持事务、成熟稳定,我们的团队在MySQL上有长期技术积累。但是传统数据库的扩展性有局限,需要通过架构解决。

[- 14-] 社交软件红包技术解密(七):支付宝红包的海量高并发技术实践

[链接] http://www.52im.net/thread-2573-1-1.html

[摘要] 经过多年的发展,口碑和社交业务的崛起让支付宝架构进一步在原有架构基础上拓展出支持线下市场和社交的生活互动型架构。2015 年钱包 9.0 的发布,这个里程碑式的项目初步奠定了支付 + 移动互联网金融 + 生活互动型混合架构。

[- 15-]社交软件红包技术解密(八):全面解密微博红包技术方案

[链接] http://www.52im.net/thread-2576-1-1.html

[摘要] 在服务器数量一定的情况下,如何构建高并发操作、瞬间峰值高的稳定服务?对于团队和架构师都是一个极大的挑战。这时候系统的架构尤为重要!本文将为你分享这些内容。

[- 16-]社交软件红包技术解密(九):谈谈手Q红包的功能逻辑、容灾、运维、架构等

[链接] http://www.52im.net/thread-2583-1-1.html

[摘要] 本文将会详细介绍手Q春节红包项目的功能设计/逻辑、容灾、运维、架构以及实践总结。

[- 17-]社交软件红包技术解密(十):手Q客户端针对2020年春节红包的技术实践

[链接] http://www.52im.net/thread-2966-1-1.html

[摘要] 对于这种大体量的IM社交应用运营活动,技术上除了前端、后台的大力支撑,对于手Q客户端来说,又是从哪些方面来保证整个红包活动的灵活性、稳定性和用户体验的呢?带着这个问题,我们一起来阅读余下的文字。

[- 18-]社交软件红包技术解密(十一):解密微信红包随机算法(含代码实现)

[链接] http://www.52im.net/thread-3125-1-1.html

[摘要] 本文根据有限的资料,分享了微信红包随机算法实现中的一些技术要点,并整理了两种比较靠谱的红包算法实现思路(含可运行的实现代码),希望能给你的红包算法开发带来启发。

[- 19-]社交软件红包技术解密(十二):解密抖音春节红包背后的技术设计与实践

[链接] http://www.52im.net/thread-3945-1-1.html

[摘要] 本文将要分享的是春节期间海量红包社交活动为抖音所带来的各种技术挑战,以及抖音技术团队是如何在实践中一一解决这些问题的。

👉52im社区本周新文:《即时通讯框架MobileIMSDK的Uniapp端开发者手册(精编PDF导出图片) http://www.52im.net/thread-4234-1-1.html》,欢迎阅读!👈

我是Jack Jiang,我为自已带盐!https://github.com/JackJiang2011/MobileIMSDK/

posted @ 2023-05-16 13:29 Jack Jiang 阅读(55) | 评论 (0)编辑 收藏

一、基本介绍

MobileIMSDK-Uniapp端是一套基于Uniapp跨端框架的即时通讯库:

  • 1)超轻量级、无任何第3方库依赖(开箱即用);
  • 2)纯JS编写、ES6语法、高度提炼,简单易用;
  • 3)基于Uniapp标准WebSocket API,简洁优雅;
  • 4)理论上可运行于任何支持Uniapp跨端框架的平台上;
  • 5)能与 MobileIMSDKGithub托管链接) 的各种客户端完美互通;
  • 6)可应用于基于Uniapp的跨平台App或Web的消息推送、客服聊天、企业OA、IM等场景。

详细开发资料:

二、与MobileIMSDK的关系

MobileIMSDK-Uniapp端 是基于Uniapp标准 WebSocket API的 MobileIMSDK配套客户端库。

以下是MobileIMSDK的最新通信架构图:

 

MobileIMSDK是一套专为移动端开发的原创开源IM通信层框架:

  • 1)历经8年、久经考验;
  • 2)超轻量级、高度提炼,lib包50KB以内;
  • 3)精心封装,一套API同时支持UDP、TCP、WebSocket三种协议(可能是全网唯一开源的);
  • 4)客户端支持iOS、Android、标准Java、H5(暂未开源)、微信小程序(暂未开源)、Uniapp:new:(暂未开源);
  • 5)服务端基于Netty,性能卓越、易于扩展;
  • 6)可与姊妹工程 MobileIMSDK-Web 无缝互通实现网页端聊天或推送等;
  • 7)可应用于跨设备、跨网络的聊天APP、企业OA、消息推送等各种场景。

PS: MobileIMSDK一直在持续开发和升级中,本Uniapp客户端是MobileIMSDK工程的最新成果。

三、设计目标

直接使用Uniapp的WebSocket API开撸,有以下问题和劣势:

  • 1)功能有限: 没有心跳保活、断线重连、消息送达保证(重传和去重)等即时通讯关键算法和逻辑;
  • 2)API简陋: 在如此有限的API接口下,能逻辑清晰且健壮地实现并组合心跳保活、断线重连、消息送达保证等算法,需要相当高的技术掌控力;
  • 3)逻辑耦合: 经验欠缺的开发人员,会将WebSocket通信与前端UI界面代码混在一起,使得UI界面的编写、维护、改版都非常困难。

针对以上问题: MobileIMSDK-Uniapp端库将让开发者专注于UI应用层的开发,网络通信层的专业代码交由SDK开发人员,从而解偶UI前端和通信层的逻辑耦合性,大大降低技术复杂度和应用门槛。

MobileIMSDK-Uniapp端库的设计目标是为您的开发带来以下便利:

  • 1)界面与通信解偶: UI界面与网络通信代码解耦,UI界面的重构、维护、改版都非常容易和优雅;
  • 2)轻量级和兼容性: 受益于坚持使用Uniapp的标准WebSocket API,简洁轻量,无需任何额外库依赖;
  • 3)核心内聚和收敛: 得益于长期的提炼和经验积累,SDK核心层高度封装,开发者无需理解复杂算法即可简单上手。
  • 4)纯JS轻量级实现: 纯JS编写、ES6语法,无重量级框架和库依赖(更无Native代码),可干净利落地对接各种既有系统;
  • 5)跨平台运行能力: 受益于Uniapp框架的跨端特性,理论上本SDK可运行于任何支持Uniapp的平台上。

四、技术亮点

  • 1)轻量易使用: 超轻量级——纯JS编写且无任何第3方库依赖,高度提炼——简单易用;
  • 2)代码现代感: 尽可能优先使用ES6语法,摒弃旧式JS语法的年代感;
  • 3)跨端支持好: 基于Uniapp的标准WebSocket API(无Native代码依赖),理论上可很好地运行于任何支持Uniapp的平台上;
  • 4)断网恢复能力: 拥有网络状况自动检测、断网自动治愈的能力;
  • 5)送达保证机制: 完善的QoS消息送达保证机制(自动重传、消息去重、状态反馈等),不漏过每一条消息;
  • 6)通信协议封装: 实现了一个对上层透明的即时通讯通信协议模型;
  • 7)身份认证机制: 实现了简单合理的身份认证机制;
  • 8)完善的log信息: 在开发调试阶段,确保每一个算法关键步骤都有日志输出,让您的运行调试更为便利;
  • 9)界面代码解耦: 实现了UI界面代码与SDK网络通信代码解偶,防止界面代码跟IM核心代码混在一起,不利于持续升级、重用和维护;
  • 10)多端协议兼容: 实现了与MobileIMSDK各种客户端完全兼容的协议模型。

五、文件组成

SDK代码文件概览:

SDK代码文件用途说明:

六、Demo运行效果和说明

七、跨平台运行效果演示

1)Demo在内置浏览器中的运行效果:

2)Demo在电脑浏览器中的运行效果(以Chrome为例):

3)Demo在Android真机上的运行效果:

4)Demo在iOS模拟器上的运行效果:

5)Demo在iOS真机上的运行效果:

6)Demo在微信小程序上的运行效果:

7)Demo在支付宝小程序上的运行效果:

其它更多平台的运行效果就不一一列举了,因为都要安装各自的开发工具,硬盘空间吃紧 。。。

八、详细资料

① MobileIMSDK-Uniapp端的详细介绍:点此查看 👈
② MobileIMSDK-Uniapp端的开发手册(网页版):点此查看 👈
 MobileIMSDK-Uniapp端的开发手册(精编PDF版):点此查看 👈 (* 推荐
④ MobileIMSDK-开源框架的详细介绍:https://gitee.com/jackjiang/MobileIMSDK (Github托管链接)👈

posted @ 2023-05-12 11:44 Jack Jiang 阅读(59) | 评论 (0)编辑 收藏

     摘要: 本文由阿里技术团队詹向阳(骁飏)分享,原题“一文读懂字符编码”,有修订和改动。一、引言说起计算机字符编码,让我想起了科幻巨作《三体-黑暗深林》人类遇到外星文明魔戒的画面(以下内容摘自大刘的原文)。人类第一次近距离看到四维物体魔戒,卓文用中频电波发送了一个问候语。这是一幅简单的点阵图,图中由六行不同数量的点组成了一个质数数列:1,3,5,7,11,13。他们没有指望得到应答,...  阅读全文

posted @ 2023-05-11 11:55 Jack Jiang 阅读(68) | 评论 (0)编辑 收藏

     摘要: 【来源申明】本文引用了微信公众号“鲜枣课堂”的《上网慢?经常掉线?这篇文章告诉你该怎么办!》文章内容。为了更好的内容呈现,即时通讯网在引用和收录时内容有改动,转载时请注明原文来源信息,尊重原作者的劳动。1、本文内容概述对于不太了解网络通信的人来说(包括开发者),可能会经常碰到下面这些问题:“手机(电脑)上网经常掉线,是为什么?”“手机(电...  阅读全文

posted @ 2023-05-06 11:21 Jack Jiang 阅读(55) | 评论 (0)编辑 收藏

为了更好地分类阅读52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第14 期。

[- 1 -] 新手快速入门:WebSocket简明教程

[链接] http://www.52im.net/thread-831-1-1.html

[摘要] 通俗的讲,WebSocket 是一种新的网络通信协议,现在浏览器端很多高级功能都需要用到它。本文将以通俗易懂的方式介绍 WebSocket 协议的使用方法,适合初学者快速入门之用。

[- 2 -] WebSocket从入门到精通,半小时就够!

[链接] http://www.52im.net/thread-3134-1-1.html

[摘要] 本文也是一篇关于WebSocket从入门到精通的文章,内容由浅入深,比较适合想要在短时间内较深入的了解WebSocket协议的开发者学习。

[- 3 -] WebSocket详解(一):初步认识WebSocket技术

[链接] http://www.52im.net/thread-331-1-1.html

[摘要] HTML5规范在传统的web交互基础上为我们带来了众多的新特性,随着web技术被广泛用于web APP的开发,这些新特性得以推广和使用,而websocket作为一种新的web通信技术具有巨大意义。本文将带您认识WebSocket。

[- 4 -] WebSocket详解(二):技术原理、代码演示和应用案例

[链接] http://www.52im.net/thread-326-1-1.html

[摘要] 本文将简要介绍 WebSocket 的由来、原理机制以及服务端/客户端实现,并以实际客户案例指导并讲解了如何使用 WebSocket 解决实时响应及服务端消息推送方面的问题。

[- 5 -] WebSocket详解(三):深入WebSocket通信协议细节

[链接] http://www.52im.net/thread-332-1-1.html

[摘要] ebSocket 是HTML5一种新的web通信技术,它真正实现了浏览器与服务器的全双工实时通信(full-duplex)。本文将详解介绍WebSocket的通信协议细节。

[- -] WebSocket详解(四):刨根问底HTTP与WebSocket的关系(上篇)

[链接] http://www.52im.net/thread-1258-1-1.html

[摘要] 因本文有点长,所以分成了上下两篇,本文将首先以通俗易懂的语言着重介绍HTTP协议,下篇中再展开WebSocket协议相关的文字。

[- 7 -] WebSocket详解(五):刨根问底HTTP与WebSocket的关系(下篇)

[链接] http://www.52im.net/thread-1266-1-1.html

[摘要] 本文的上篇《WebSocket详解(四):刨根问底HTTP与WebSocket的关系(上篇)》介绍了HTTP1.1协议的基本内容,这篇文章将继续分析WebSocket协议,然后对这两个进行简单的比较。

[- 8-]  WebSocket详解(六):刨根问底WebSocket与Socket的关系

[链接] http://www.52im.net/thread-1273-1-1.html

[摘要] 目前网上全面介绍这两种协议的中文文章并不多,或者说不够全面。我无法找到一篇文章能解决上面的所有问题。因此,我写了本文,把找到的 Socket 和 WebSocket 的相关资料做一个梳理,以方便理解。

[- 9 -] WebSocket硬核入门:200行代码,教你徒手撸一个WebSocket服务器

[链接] http://www.52im.net/thread-3175-1-1.html

[摘要] 本文分享了自已开发一个WebSocket服务端实现过程中需要的知识储备,以及具体的代码实现含义等,非常适合想在短时间内对WebSocket协议从入门到精通的Web端即时通讯开发者阅读。

[- 10 -] Web端即时通讯安全:跨站点WebSocket劫持漏洞详解(含示例代码)

[链接] http://www.52im.net/thread-793-1-1.html

[摘要] 本文将深入浅出为读者介绍跨站点 WebSocket 漏洞的原理、检测方法和修复方法,希望能帮助广大读者在实际工作中避免这个已知安全漏洞。

[- 11 -] 长连接网关技术专题(四):爱奇艺WebSocket实时推送网关技术实践

[链接] http://www.52im.net/thread-3539-1-1.html

[摘要] 本文分享了爱奇艺基于Netty实现WebSocket长连接实时推送网关时的实践经验总结。

[- 12 -] Web端即时通讯实践干货:如何让你的WebSocket断网重连更快速?

[链接] http://www.52im.net/thread-3098-1-1.html

[摘要] 本文将基于笔者的开发实践,分享WebSocket在不同状态下、不同的网络场景下,应该如何实现快速断网重连。

[- 13 -] 理论联系实际:从零理解WebSocket的通信原理、协议格式、安全性

[链接] http://www.52im.net/thread-1341-1-1.html

[摘要] 本文由浅入深,介绍了WebSocket如何建立连接、交换数据的细节,以及数据帧的格式。此外,还简要介绍了针对WebSocket的安全攻击,以及协议是如何抵御类似攻击的。

[- 14 -] 微信小程序中如何使用WebSocket实现长连接(含完整源码)

[链接] http://www.52im.net/thread-1703-1-1.html

[摘要] 这篇文章分享了一个基于WebSocket长连接的微信小程序——简单的剪刀石头布小游戏的制作过程,希望能对想要在微信小程序中使用 WebSocket 的开发者有所帮助。

[- 15 -] 八问WebSocket协议:为你快速解答WebSocket热门疑问

[链接] http://www.52im.net/thread-2488-1-1.html

[摘要] 本文将从8个常见的疑问入手,为还不了解WebSocket协议的开发者快速普及相关知识,从而节省您学习WebSocket的时间。

👉52im社区本周新文:《IM开发干货分享:IM客户端不同版本兼容运行的技术思路和实践总结 http://www.52im.net/thread-4202-1-1.html》,欢迎阅读!👈

我是Jack Jiang,我为自已带盐!https://github.com/JackJiang2011/MobileIMSDK/

posted @ 2023-05-04 13:45 Jack Jiang 阅读(54) | 评论 (0)编辑 收藏

本文由巩鹏军分享,原题“IM兼容性基建”,本文有修订。

1、引言

一个成熟的IM成品,在运营过程中随着时间的推移,会发布不同的版本,但为了用户体验并不能强制要求用户必须升级到最新版本,而服务端此时已经是最新版本了,所以为了让这些不同客户端版本的用户都能正常使用(尤其IM这种产品,不同版本可能通信协议都会有变动,这就更要命了),则必须要针对不同客户端版本的兼容处理。

本文将基于笔者的IM产品开发和运营实践,为你分享如何实现不同APP客户端版本与服务端通信的兼容性处理方案。

 

学习交流:

(本文已同步发布于:http://www.52im.net/thread-4202-1-1.html

2、关于作者

巩鹏军:专注移动开发十多年,热爱即时通讯技术。个人微信公众号:“巩鹏军”。

作者在即时通讯网分享的另一篇《知识科普:IM聊天应用是如何将消息发送给对方的?(非技术篇)》,感兴趣的读者也可以看看。

3、一个App时怎么办?

提示:“一个App”指的是同一个IM服务端,只服务于一个特定的IM产品。

首先想到的就是直接使用App版本号判断新老版本并进行兼容处理。

如下图所示:

一般来说,不同的IM客户端(如iOS、Android、Windows、Mac)都是同步迭代,多端发版时间一致,App版本号也一样。

所以用跨多端的App版本号可以很容易地让服务端只用写一遍判断和兼容逻辑。

示例:假设从V2.1.0开始应用红包消息,那么判断客户端是否支持红包的逻辑就很简单。

伪代码如下:

booleanisSupportRedEnvelop(String appVersion) {

 returngte(appVersion, "2.1.0");

}

附:版本号比对逻辑(未充分考虑异常情况):

List<Integer> toNums(String version) {

  Matcher matcher = Pattern

 

    .compile("/[0-9]+\\.[0-9]+\\.[0-9]+")

 

    .matcher(version);

 

  String versionString = matcher.find()

 

    ? matcher.group(0).substring(1)

 

    : "1.0.0";

 

  List<Integer> verNums = Arrays

 

    .stream(versionString.split("\\."))

 

    .map(Integer::valueOf)

     .collect(Collectors.toList());

  returnverNums;

}

 

booleangte(String version, String target) {

 

  List<Integer> appVerNums = toNums(version);

  Integer appMajor = appVerNums.get(0);

  Integer appMinor = appVerNums.get(1);

  Integer appPatch = appVerNums.get(2);

  List<Integer> targetNums = toNums(target);

  Integer targetMajor = targetNums.get(0);

  Integer targetMinor = targetNums.get(1);

  Integer targetPatch = targetNums.get(2);

  return(appMajor >= targetMajor) ||

         (appMinor >= targetMinor) ||

         (appPatch >= targetPatch);

}

4、多个App时怎么办?

4.1概述

提示:“多个App”指的是同一个IM服务端,可能作为通用服务,作为多个不同APP产品中的聊天模块使用的场景。

只有一个App时肯定是比较简单的。但现实情况是一套IM系统通常会用于多个业务场景,这是很普遍的现象。业界的知名IM产品,比如钉钉、飞书、企业微信、美团大象等都是这样。

底层逻辑大概是:IM系统比较复杂,功能繁多而且难以实现、更难以稳定,所以一个IM团队维护一套IM系统,然后应用在多个业务场景就是最具性价比的选择了。

4.2使用App版本

每个业务场景都会有自己的客户端App,每个App都有自己的版本号,那么根据App版本号判断新老版本的逻辑就不适用了(如下图所示)。

一个App时可以这样做兼容性判断:

booleanisSupportRedEnvelop(String appVersion) {

 returngte(appVersion, "2.1.0");

}

多个App时的兼容性判断:

booleanisSupportRedEnvelop(String version) {

    return

    (app.equals("App1")&>e(version,"2.1.0"))||

    (app.equals("App2")&>e(version,"2.2.3"))||

    (app.equals("App3")&>e(version,"6.1"));

}

4.3使用App版本号的麻烦

随着App的增多,需要的判断也越多,这会很麻烦,也很容易出错。

每个App推出新版本后,用户不可能瞬间就升级到最新版本,根据经验,每个App往往都会同时存在十个以上的不同版本。

这就会形成如下图所示的局面:

5、多个App时,可将IM能力提炼为一套公用代码

多个App时的问题总结起来就是:一套服务端代码如何适应集成了不同IM能力的不同App客户端?

我们来具体举例分析一下,假设一个IM团队维护的IM相关的客户端模块有IM Client SDK、联系人、长连接、朋友圈等四个模块(如下图所示)。

如上图所示:

  • 1)App 1:集成了全部四个模块;
  • 2)App 2:只集成了三个模块;
  • 3)App 3:只集成了三个模块。

因为三个App面向的客户群不同,发版节奏不同,所以各自集成的IM的能力也不同。

比如下面这样:

  • 1)App 1:面向内部员工办公沟通使用的App 1需要功能丰富,对于稳定性和Bug有一定的包容性,也容易沟通和修复再发版;
  • 2)App 2:面向客服场景,用于企业的客服专员和企业的C端用户沟通解决客诉问题,对于稳定性要求高,C端用户升级率不好控制,发版节奏慢,最快只能和主业务App一致;
  • 3)App 3:面向企业和B端供应商,比如美团和美团上的商户,京东和京东平台上的第三方商家,对于稳定性要求也比较高,B端商家的升级率好控制一点,发版节奏也可以快一些。

从上图可以看出,因为IM核心能力是同一个团队维护,所以Core包含的多个模块的代码必然是只有一套源代码。不同App只是Core集成打包出来的产物,或者说不同App只是Core外面套了不同的壳而已,只要Core一样,则App的IM能力就一样(这就是本节标题所述的“多个App时,可将IM能力提炼为一套公用的代码”这个意思)。

6、给每个App中使用的公用代码(Core)一个版本号

如上节所述,我们将IM能力提炼为一套公用代码(以下内容简称“Core”)。

那么,我们能不能给Core一个版本标识呢?

答案是肯定的:

站在App的角度,每个App相当于打上了Core版本标签:

7、如何正确地解读Core版呢?

7.1抛开App看Core版本

如果不看App版本,只看Core版本标签:

7.2从一套服务端代码看Core版本

同一个IM团队,其IM Servers必然也是同一套代码集,不考虑部署的区别。

那么上图逻辑上等价于下图:

7.3使用Core版本的兼容性判断

站在Core的视角,多个App就像单个App类似,只是使用的版本标识不同。

具体如下:

  • 1)单个App时,IM服务端要区分不同App版本;
  • 2)多个App时,IM服务端要区分不同Core版本。

还拿是否支持红包的判断举例。

一个App时:

booleanisSupportRedEnvelop(String appVersion){

 

returngte(appVersion, "2.1.0");

}

多个App时:

booleanisSupportRedEnvelop(Integer coreVersion){

 

 returncoreVersion >= 2;

}

通过Core版本号,我们可以把兼容逻辑判断简化到和单个App一样的简单。

8、关于Core版本的命名和取值

关于Core版本号的取值,有下列可能的选项:

  • 选项一:语义版本号 1.2.0;
  • 选项二:整数 自然数 1 2 3;
  • 选项三:整数 迭代日期 20220819 或 220819。

因为Core版本号不用给最终用户看的,无需遵循常见的语义版本号规范。而且Core版本号只用于版本对比,所以整数会是一个比较好的选择,方便比较,准确可靠。

用自然数 1、 2、 3作为Core版本号是可以的,每个迭代发布新的Core版本时递增一下就可以了。

但是考虑到有多个终端平台iOS、Android、Windows、Mac,如果某个平台的Core发布后发现小Bug需要HotFix,那么要递增版本号,就会挤占其它端的下一个自然数。究其原因,在于自然数是连续的,没办法在两个常规的版本间插入一个HotFix版本。

选项三就可以解决这个问题:因为Core的迭代发布日期是稀疏的,若干天后才会发布一个Core版本,那么当某个端需要一个HotFix版本时,选择HotFix当天的日期作为版本号即可。

总体上:多个端的主要版本号都是约定的统一的发布日期,多端一致,同时允许某个端临时HotFix插入一个新的版本号,保留弹性。

参考 Google 对Android SDK API版本的实践,我们可以把Core版本号命名为core_level,取值为Core的发布日期的整数表示。

9、多个App情况下的其它版本标识

1)platform:

一套Core,不同端在实际开发中,可能存在差异,为了针对具体端进行特定的兼容,需要知道当前是哪个端,可以约定platform字段表示端。取值可以是:ios、android、win、mac、linux等。

2)App版本号:

在IM相关逻辑的兼容性判断中,只需使用跨App的多端一致的core_level了。但是为了和最终用户、产品经理等沟通方便,保留App版本号app_version用于人和人之间沟通交流。core_level主要用于研发工程师之间,还有工程师和程序之间的沟通。两者各取所长。

10、版本标识的传输方式

每个API和每条长连接数据包都携带Core版本,这样服务端可以无状态得处理每一个请求。如果需要在服务端主动推送时区分目标端的版本,可以在App登录时将其携带的Core版本落库存储,然后推送时查询使用。

10.1短连接(HTTP)

HTTP短连接通过新增Header字段方式传输:

curl "https://{domain}/api/v1/xxx"\

  -H "platform: ios"\

  -H "app_version: 8.0.25"\

  -H "core_level: 220819"

10.2长连接(Socket)

长连接SDK通过类似HTTP Header的方式传输:

{

  "platform":"ios",

  "app_version":"8.0.25",

  "core_level":"220819"

 

}

10.3短转长

短转长时HTTP Header会转换为长连接数据body里的header通过长链传递。

这样就同时存在长连接header和长连接body.header两套字段,最终以长连接body.header为准即可。

10.4其它

IM系统里的浏览器和小程序,如果可以新增HTTP Header则新增Header传输,实在没有办法可以通过User-Agent传输该信息,服务端优先解析Header,没有找到时再解析User-Agent。

服务端解析UA的正则表达式:

/ platform\/(ios|android|mac|win|linux) app_version\/([0-9]\.[0-9]+\.[0-9]+) core_level\/([1-9][0-9]+)( |$)/

以上正则表达式在线运行效果:点此查看

11、本文小结

至此,我们找到了一个适用于多个App、多个子模块、多个功能点、临时BugFix的版本标识:Core版本号,这样就可以很好地解决多App的IM能力兼容性问题。

以下是版本兼容性判断伪码:

booleanisSupportRedEnvelop(Integer coreLevel) {

  returncoreLevel >= 220819;

}

12、参考资料

[1] Browser vs Engine Version

[2] Node.js ABI version number

[3] Android SDK API Level

[4] 零基础IM开发入门(一):什么是IM系统?

[5] 一套海量在线用户的移动端IM架构设计实践分享(含详细图文)

[6] 一套原创分布式即时通讯(IM)系统理论架构方案

[7] 从零到卓越:京东客服即时通讯系统的技术架构演进历程

[8] 一套亿级用户的IM架构技术干货(上篇):整体架构、服务拆分等

[9] 基于实践:一套百万消息量小规模IM系统技术要点总结

[10] 一套十万级TPS的IM综合消息系统的架构实践与思考

[11] 从新手到专家:如何设计一套亿级消息量的分布式IM系统

[12] 闲鱼亿级IM消息系统的架构演进之路

[13] 深度解密钉钉即时消息服务DTIM的技术设计

[14] 一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践

[15] 企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等

(本文已同步发布于:http://www.52im.net/thread-4202-1-1.html

posted @ 2023-04-28 10:41 Jack Jiang 阅读(50) | 评论 (0)编辑 收藏

为了更好地分类阅读52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第13 期。

[- 1 -] 新手入门贴:史上最全Web端即时通讯技术原理详解

[链接] http://www.52im.net/thread-338-1-1.html

[摘要] 本文的目的就是要详细探讨这些技术并分析其原理和过程。

[- 2 -] Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE

[链接] http://www.52im.net/thread-336-1-1.html

[摘要] 本文将简要介绍这4种技术的原理,并指出各自的异同点、优缺点等。

[- 3 -] SSE技术详解:一种全新的HTML5服务器推送事件技术

[链接] http://www.52im.net/thread-335-1-1.html

[摘要] 本文对服务器推送技术(SSE)进行了详细的介绍,包含浏览器端和服务器端的相应实现细节,为在实践中使用该技术提供了指南。

[- 4 -]Comet技术详解:基于HTTP长连接的Web端实时通信技术

[链接] http://www.52im.net/thread-334-1-1.html

[摘要] 一般来说,Web端即时通讯技术因受限于浏览器的设计限制,一直以来实现起来并不容易,主流的Web端即时通讯方案大致有4种:传统Ajax短轮询、Comet技术、WebSocket技术、SSE(Server-sent Events)。本文将专门讲解Comet技术。

[- 5 -] socket.io实现消息推送的一点实践及思路

[链接] http://www.52im.net/thread-188-1-1.html

[摘要] 对于普通站点来说, 请求-响应模式可以满足绝大多数的功能需求,但总有某些功能我们希望能够为用户提供实时消息的体验。

[- 6 - LinkedIn的Web端即时通讯实践:实现单机几十万条长连接

[链接] http://www.52im.net/thread-659-1-1.html

[摘要] 在这篇文章中会描述在我们收到了消息、分型指标和读回复之后,如何立刻把它们发往客户端。内容会包含我们是如何使用Play框架和Akka Actor Model来管理长连接、由服务器主动发送事件的。我们也会分享一些在生产环境中我们是如何在服务器上做负载测试,来管理数十万条并发长连接的,还有一些心得。最后,我们会分享在整个过程中我们用到的各种优化方法。

[- 7 -] Web端即时通讯技术的发展与WebSocket、Socket.io的技术实践

[链接] http://www.52im.net/thread-690-1-1.html

[摘要] 为什么说Web即时通讯技术这么重要?我们生活在一个实时(real-time)的世界中,因此Web的最终最自然的状态也应当是实时的。用户需要实时的沟通、数据和搜索。我们对互联网信息实时性的要求也越来越高,如果信息或消息延时几分钟后才更新,简直让人无法忍受。现在很多大公司(如Google、Facebook和Twitter)都在关注实时Web,并提供了实时性服务。实时Web是现在也将是未来最热门的话题之一。

[- -]  开源框架Pomelo实践:搭建Web端高性能分布式IM聊天服务器

[链接] http://www.52im.net/thread-849-1-1.html

[摘要] Pomelo是来自网易公司的基于 Node.js 的高性能、分布式游戏服务器框架。它包括基础的开发框架和相关的扩展组件(库和工具包),可以帮助你省去游戏开发枯燥中的重复劳动和底层逻辑的开发。

[- 9 -] 使用WebSocket和SSE技术实现Web端消息推送

[链接] http://www.52im.net/thread-907-1-1.html

[摘要] 请注意,本文要求熟悉 HTTP 服务器推送的语言和概念。两个应用程序都是在 Python 中使用 CherryPy 编写的。

[- 10 -] 详解Web端通信方式的演进:从Ajax、JSONP 到 SSE、Websocket

[链接] http://www.52im.net/thread-1038-1-1.html

[摘要] 这里我们将围绕上述的几种通信方式进行详细的介绍。

[- 11 -] MobileIMSDK-Web的网络层框架为何使用的是Socket.io而不是Netty?

[链接] http://www.52im.net/thread-1248-1-1.html

[摘要] 本文要讨论的是MobileIMSDK-Web的网络层框架为何使用的是Socket.io而不是Netty。

[- 12 -] 一文读懂前端技术演进:盘点Web前端20年的技术变迁史

[链接] http://www.52im.net/thread-2719-1-1.html

[摘要] 我们经历了前端的洪荒时代、Prototype时代、jQuery时代 、后jQuery时期、三大框架割据时代,这其中均是由国外开发者主导,直到如今的小程序时代,才是中国开发者独创的。这是漫长的技术储备下的成果,最终促成了良好的技术成长收获。期间的前端发展之路,崎岖艰难,本文将带你回顾这个过程。

[- 13 -] Web端即时通讯基础知识补课:一文搞懂跨域的所有问题!

[链接] http://www.52im.net/thread-2732-1-1.html

[摘要] 本文将为你讲解跨域问题原理,以及理论联系实际,用实践代码也为你演示解决跨域问题的几种方法。

[- 14 -网页端IM通信技术快速入门:短轮询、长轮询、SSE、WebSocket

[链接] http://www.52im.net/thread-3555-1-1.html

[摘要] 对于即时通讯网的im和消息推送这类即时通讯技术开发者来说,掌握WebSocket固然很重要,但了解短轮询、长轮询等这些所谓的Web端即时通讯“老技术”仍然大有裨益,这也正是整理分享本文的重要原因。

[- 15 -] 搞懂现代Web端即时通讯技术一文就够:WebSocket、socket.io、SSE

[链接] http://www.52im.net/thread-3695-1-1.html

[摘要] 本文将专门介绍WebSocket、socket.io、SSE这几种现代的Web端即时通讯技术,从适用场景到技术原理,通俗又不失深度的文字,特别适合对Web端即时通讯技术有一定了解,且想深入学习WebSocket等现代Web端“实时”通信技术,却又不想花时间去深读枯燥的IETF技术手册的读者。

👉52im社区本周新文:《网络编程懒人入门(十五):外行也能读懂的网络硬件设备功能原理速成 http://www.52im.net/thread-4188-1-1.html》,欢迎阅读!👈

posted @ 2023-04-21 13:49 Jack Jiang 阅读(53) | 评论 (0)编辑 收藏

一、基本介绍

MobileIMSDK - 微信小程序端是一套基于微信原生 WebSocket 的即时通讯库:

  • 1)超轻量级、无任何第 3 方库依赖(开箱即用);
  • 2)纯 JS 编写、ES6 语法、高度提炼,简单易用;
  • 3)基于微信原生 WebSocket API,简洁优雅;
  • 4)支持运行于任何支持微信小程序的手机端;
  • 5)能与 MobileIMSDK 的各种客户端完美互通;
  • 6)可应用于微信小程序中的消息推送、客服聊天、企业 OA、IM 等场景。

二、与 MobileIMSDK 的关系

MobileIMSDK - 微信小程序端是基于微信原生 WebSocket 协议的 MobileIMSDK 配套客户端库。

MobileIMSDK 是一套专为移动端开发的开源原创 IM 通信层框架:

  • 历经 8 年、久经考验;
  • 超轻量级、高度提炼,lib 包 50KB 以内;
  • 精心封装,一套 API 同时支持 UDPTCPWebSocket 三种协议(可能是全网唯一开源的);
  • 客户端支持 iOSAndroid标准 JavaH5、小程序、Uniapp(开发中..);
  • 服务端基于 Netty,性能卓越、易于扩展;👈
  • 可与姊妹工程 MobileIMSDK-Web 无缝互通实现网页端聊天或推送等;👈
  • 可应用于跨设备、跨网络的聊天 APP、企业 OA、消息推送等各种场景。

以下是 MobileIMSDK 的最新通信架构图:

PS:MobileIMSDK 的客户端库一直在持续开发和升级中,目前 基于 Uniapp 的 MobileIMSDK 客户端正在开发中 。

三、设计目标

直接使用原生的微信小程序 WebSocket 有以下问题和劣势:

  • 1)功能有限:没有心跳保活、断线重连、消息送达保证(重传和去重)等即时通讯关键算法和逻辑;
  • 2)API 简陋:在如此有限的原生 API 下,能逻辑清晰地实现并组合心跳保活、断线重连、消息送达保证等算法,需要相当高的技术掌控力;
  • 3)逻辑耦合:经验欠缺的开发人员,会将 WebSocket 通信与前端 UI 界面代码混在一起,使得 UI 界面的重构、维护、改版都非常困难。

针对以上问题,而 MobileIMSDK - 微信小程序端库将让开发者专注于 UI 应用层的开发,网络通信层的专业代码交由 SDK 开发人员,从而解偶 UI 前端和通信层的逻辑耦合性,大大降低技术复杂性。

MobileIMSDK - 微信小程序端库的设计目标是为您的开发带来以下便利:

  • 1)界面与通信解偶:UI 界面与网络通信代码解耦,UI 界面的重构、维护、改版都非常容易和优雅;
  • 2)轻量级和兼容性:受益于坚持原生微信小程序 WebSocket API,简洁轻量,无需任何额外依赖;
  • 3)核心内聚和收敛:得益于长期的提炼和经验积累,SDK 核心层高度封装,开发者无需理解复杂算法即可简单上手。
  • 4)纯 JS 轻量级实现:SDK 为纯 JS 编写、ES6 语法,无重量级框架和库依赖,可干净利落地对接各种既有系统。

四、技术亮点

  • 轻量易使用:超轻量级 —— 纯 JS 编写且无任何第 3 方库依赖,高度提炼 —— 简单易用;
  • 代码现代感:尽可能优先使用 ES6 语法,摒弃旧式 JS 语法的年代感;
  • 兼容性很好:基于微信原生 WebSocket API,可很好地运行于支持微信小程序的手机端;
  • 断网恢复能力:拥有网络状况自动检测、断网自动治愈的能力;
  • 送达保证机制:完善的 QoS 消息送达保证机制(多重保障),不漏过每一条消息;
  • 通信协议封装:实现了一个对上层透明的即时通讯通信协议模型;
  • 身份认证机制:实现了简单合理的身份认证机制;
  • 完善的 log 信息:在开发调试阶段,确保每一个算法关键步骤都有日志输出,让您的运行调试更为便利;
  • 界面代码解耦:实现了 UI 界面代码与 SDK 网络通信代码解偶,防止界面代码跟 IM 核心代码混在一起,不利于持续升级、重用和维护;
  • 聊天协议兼容:实现了与 MobileIMSDK 各种客户端完全兼容的协议模型。

五、文件组成

SDK代码文件概览:

SDK代码文件用途说明:

六、技术交流 

学习和资料:点击进入、bug和建议:点击进入

七、Demo运行截图

1)Demo的真机运行效果和功能说明图:

2)Demo在模拟器下的运行效果:

3)Demo真机运行实拍图:

八、详尽开发者手册

① 开发者手册(网页版):MobileIMSDK的微信小程序端开发快速入门 

② 开发者手册(PDF精编版):

 

九、引用资料

[1] 微信小程序开发者手册
[2] MobileIMSDK开源框架的API文档
[3] MobileIMSDK开源IM框架源码Github地址点此
[4] 开源轻量级 IM 框架 MobileIMSDK 的微信小程序端已发布
[5] 开源即时通讯框架MobileIMSDK的微信小程序端开发者手册

posted @ 2023-04-20 10:33 Jack Jiang 阅读(41) | 评论 (0)编辑 收藏

本文由黄工首先发表于strongerHuang公众号,原题“网络硬件的发展史”,本文有修订。

1、引言

本文是《网络编程懒人入门》系列文章的第15篇,本篇将继续以通俗易懂的文字,帮你无脑理解各种基础网络硬件设备的功能原理。

本文不罗列复杂、全面的计算机网络理论,目的是让阅读者脱离以往计算机理论专著的枯燥内容,在寓教于乐的语言文字中轻松快速的掌握这些知识,适合入门者,计网大佬和网络编程老油条们请略过。

学习交流:

(本文已同步发布于:http://www.52im.net/thread-4188-1-1.html

2、如何连接个人计算机(PC)?

在发明网络之前,个人计算机之间是独立工作的,没有网卡、网线或协议栈,主要使用磁盘、CD 和其他东西来传输数据。

后来,网线出现了。

最小的网络单元由网线、网卡和协议栈组成:

  • 1)网线起着物理介质的作用,以传输比特流 / 电信号;
  • 2)网卡将转换数据(例如:它将计算机存储的数据转换为网线的比特流 / 电信号);
  • 3)协议栈作为一种通信语言,可以在通信过程中实现数据分析、地址寻址和流控制。

3、网线不够长怎么办?

如果终端之间的距离太远,一旦超过网线物理传输距离的上限,数据就会开始丢失。

中继器是物理层的设备,可以中继和放大信息以实现设备的远距离传输。

 

4、中继器端口不足怎么办?

中继器通常只有两个接口,这意味着如果网络中有三个以上的终端主机,则无法实现多个主机之间的直接数据通信。

集线器是一种多接口中继器,也是一个物理层设备。它可以中继和放大信息,从任何接口接收的数据都将被发送到所有其他接口。

5、如何有选择性的发送数据?

有人把网桥比喻成一个 “聪明” 的中继器。因为中继器只是对所接收的信号进行放大,然后直接发送到另一个端口连接的电缆上,主要用于扩展网络的物理连接范围。

而网桥除了可以扩展网络的物理连接范围外,还可以对 MAC 地址进行分区,隔离不同物理网段之间的碰撞(也就是隔离 “冲突域”)。

6、速度不够快怎么办?

交换机可以记录该终端主机的 MAC 地址,并生成一个 MAC 表。MAC 表相当于一个 “map”,交换机根据 MAC 表在主机之间转发数据流。

交换机基于网桥进行扩展和升级。

与网桥相比,交换机具有以下优点:

  • 1)接口数量更密集(每个主机位于一个独立的冲突域中,带宽利用率大大提高);
  • 2)使用专用的 ASIC 硬件芯片进行高速转发;
  • 3)VLAN 隔离(不仅可以隔离冲突域,还可以通过 VLAN 隔离广播域)。

交换机是一种局域网设备,通常用于局域网,不能实现远程广域网通信。

7、距离还不够怎么办?

世界上第一台路由器是由斯坦福大学的 Leonard Bossack 和 Santi Lerner 这对教师夫妇为斯坦福大学校园网络 (SUNet) 和思科公司发明的。

▲ 思科公司创始人Leonard Bossack 和 Santi Lerner 夫妇

路由器是一种基于 IP 寻址的网络层设备,利用路由表来实现数据转发。路由器主要用于连接不同的局域网以实现广播域隔离,也可以用于远程通信,如广域网连接。

诸如 IP 协议之类的逻辑寻址机制是实现不同类型局域网连接的关键。不同局域网的主机只要具有逻辑地址(IP 地址)和合理的逻辑地址规划(网段规划),它们就可以通信。

路由器的诞生是互联网爆炸的主要原因,跨媒介、跨地域的网络集成已成为现实。

8、接线太麻烦怎么办?

无线 AP可以被视为具有无线功能的交换机 / 路由器。随着无线城市和移动办公的发展趋势,无线产品在网络中所占的比例正在增加。

根据部署方式的不同,可以分为胖 AP 和瘦 AP 解决方案。

1)在胖 AP 方案中,无线 AP 具有独立的操作系统,该操作系统可以独立调试无线热点的所有配置,类似于家用 Tp-link 产品。

2)在瘦 AP 方案中,无线 AP 仅具有无线信号传输功能,所有命令调试都集中在后台的 AC / 无线控制器上。

小型无线网络(家庭、小型企业)可以使用胖 AP 解决,而大型无线网络(无线城市、无线园区网络)则需要使用瘦 AP(AC + AP)解决。

9、不够安全怎么办?

防火墙是一种用于限制网络安全访问的网络安全产品,通常用于 Internet 的边缘,以防止外部黑客的攻击。

根据防火墙的技术特点,可以分为包过滤、应用代理和状态检测防火墙。根据产品形式,可以分为软件防火墙和硬件防火墙。

防火墙可视为具有安全功能的路由器。早期的防火墙在路由器的基础上增加了访问控制功能,因此在路由器上可以看到许多防火墙的功能,例如路由协议、访问控制列表、地址转换技术等。

防火墙和路由器可以同时存在于网络中。例如,防火墙可以放置在路由器之前或之后。在这种情况下,路由器侧重于地址转换和路由策略,而防火墙侧重于安全隔离等。

在防火墙的基础上,扩展出了 Web 防火墙、安全网关和入侵检测 / 入侵防御等安全产品。

10、网络拥塞怎么办?

网络中的流量控制设备主要分为:

  • 1)上网行为管理;
  • 2)负载均衡器 / 应用交付;
  • 3)链路优化;
  • ... ...

上网行为管理产品主要关注细粒度的区分和流量控制。

负载平衡 / 应用程序交付侧重于流量的负载平衡(根据流量特征、应用程序、地址等进行区分,然后分配到不同的链接和服务器)。

链接优化主要用于广域网等低速链路的边界,以使链路利用率最大化。

问题来了:组成一个网络需要多少种设备?

11、家庭 SOHO 网络

这是一个典型的家庭网络,它通过无线路由器提供 WiFi 热点访问,并提供路由器连接到外部网络。

12、小型企业网络

小型企业网络使用二层架构、单核拓扑,需要路由器、交换机和服务器。

13、园区网

最常见的园区网架构,如大中型企业网络 / 校园网络,采用接入汇聚核三层架构和双核组网。

根据网络需求,分为:

  • 1)用户区;
  • 2)内部服务区;
  • 3)外部服务区;
  • 4)管理区;
  • 5)Internet 区;
  • ... ...

它们通过核心交换机和防火墙连接并隔离。

互联网使用多出口连接,通过路由器实现拨号和 NAT,通过流量控制设备实现负载均衡 / 上网行为管理,通过防火墙实现安全隔离。

14、数据中心网络

上图是典型的大型第二层数据中心网络 / IDC 设计。

主要分为:

  • 1)租户区(服务集群);
  • 2)Internet 区;
  • 3)安全管理区域。

租户区:采用设备虚拟化和链路虚拟化技术,提高设备处理能力和链路承载能力,并将负载均衡器放置在服务器区域中,以合理有效的方式将流量分配给固定服务器。

Internet 出口区域:使用路由器执行 BGP 和地址反转,使用 IPS / anti-DDoS 设备进行大流量泛洪攻击,使用流量控制执行出口负载,并使用防火墙进行安全隔离。

安全管理区:通过防火墙安全访问,通过审计、日志、入侵检测、网络管理等产品对整个网络进行管理。

15、系列文章

本文是系列文章中的第15篇,本系列文章的大纲如下:

[1] 网络编程懒人入门(一):快速理解网络通信协议(上篇)

[2] 网络编程懒人入门(二):快速理解网络通信协议(下篇)

[3] 网络编程懒人入门(三):快速理解TCP协议一篇就够

[4] 网络编程懒人入门(四):快速理解TCP和UDP的差异

[5] 网络编程懒人入门(五):快速理解为什么说UDP有时比TCP更有优势

[6] 网络编程懒人入门(六):史上最通俗的集线器、交换机、路由器功能原理入门

[7] 网络编程懒人入门(七):深入浅出,全面理解HTTP协议

[8] 网络编程懒人入门(八):手把手教你写基于TCP的Socket长连接

[9] 网络编程懒人入门(九):通俗讲解,有了IP地址,为何还要用MAC地址?

[10] 网络编程懒人入门(十):一泡尿的时间,快速读懂QUIC协议

[11] 网络编程懒人入门(十一):一文读懂什么是IPv6

[12] 网络编程懒人入门(十二):快速读懂Http/3协议,一篇就够!

[13] 网络编程懒人入门(十三):一泡尿的时间,快速搞懂TCP和UDP的区别

[14] 网络编程懒人入门(十四):到底什么是Socket?一文即懂!

[15] 网络编程懒人入门(十五):外行也能读懂的网络硬件设备功能原理速成(* 本文)

16、参考资料

[1] 快速理解网络通信协议(上篇)

[2] 快速理解网络通信协议(下篇)

[3] 假如你来设计网络,会怎么做?

[4] 史上最通俗的集线器、交换机、路由器功能原理入门

[5] 面视必备,史上最通俗计算机网络分层详解

[6] 技术往事:改变世界的TCP/IP协议(珍贵多图、手机慎点)

[7] P2P技术详解(一):NAT详解——详细原理、P2P简介

[8] 通俗讲解,有了IP地址,为何还要用MAC地址?

(本文已同步发布于:http://www.52im.net/thread-4188-1-1.html

posted @ 2023-04-18 11:07 Jack Jiang 阅读(66) | 评论 (0)编辑 收藏

     摘要: 本文引用自Hussein Nasser的两个视频分享,原文内容由卢冰聪翻译整理,即时通讯网收录时有大量修订和重新排版。1、内容概述本文是专为学习开源实时音视频工程WebRTC的入门者编写的速成指南。本文主要分享了WebRTC的基本概念、关键技术术语(包括NAT、STUN、TURN、ICE、SDP 和信令),着重讲解了WebRTC是如何实现P2P通信以及WebRTC信令的作用,同时讨论了WebRTC...  阅读全文

posted @ 2023-04-13 17:11 Jack Jiang 阅读(84) | 评论 (0)编辑 收藏

为了更好地分类阅读52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第12 期。

[- 1 -] 应用保活终极总结(一):Android6.0以下的双进程守护保活实践

[链接] http://www.52im.net/thread-1135-1-1.html

[摘要] 因为Android机型太多太杂,以及各厂商定制ROOM的差异,Android应用保活没有一劳永逸和万能的方法,本文探讨的是Android应用在Android 6.0以下系统中的典型应用场景下的保活实践(Android 6.0及以上系统的防杀和复活方法,详见本系列文章的下两篇《应用保活终极总结(二):Android6.0及以上的保活实践(进程防杀篇)》、《Android应用保活终极总结(三):Android6.0及以上的保活实践(被杀复活篇)》),内容仅供参考,希望给您带来启发。

[- 2 -] 应用保活终极总结(二):Android6.0及以上的保活实践(进程防杀篇)

[链接] http://www.52im.net/thread-1138-1-1.html

[摘要] 本文便是对最近一周的Android进程防杀、进程被杀复活的探索、学习、测试的内容总结,以备将来不时之需。因保活防杀和被杀复活涉及内容较多,我将它分成了两篇:即进程防杀篇(本文)和进程被杀复活篇(下篇),本篇将讨论如何实现进程防杀。

[- 3 -] 应用保活终极总结(三):Android6.0及以上的保活实践(被杀复活篇)

[链接] http://www.52im.net/thread-1140-1-1.html

[摘要] 本文将重点讨论进程被杀后复活的可能性及实践。

[- 4 -] Android进程保活详解:一篇文章解决你的所有疑问

[链接] http://www.52im.net/thread-438-1-1.html

[摘要] 什么样的应用需要进程保活?通常情况下,即时通讯类的应用(包括IM聊天应用、消息推送服务等)为了保证消息的全时、实时送达能力,必须要实现进程或Service的保活。而就这一看似不起眼的问题,实际处理起来,因为众多Android手机和Android系统版本的差异,让问题的处理充满了不确定性。

[- 5 -] Android端消息推送总结:实现原理、心跳保活、遇到的问题等

[链接]http://www.52im.net/thread-341-1-1.html

[摘要] 最近研究Android推送的实现, 研究了两天一夜, 有了一点收获, 写下来既为了分享, 也为了吐槽. 需要说明的是有些东西偏底层硬件和通信行业, 我对这些一窍不通, 只能说说自己的理解.

[- 6-] 为何基于TCP协议的移动端IM仍然需要心跳保活机制?

[链接] http://www.52im.net/thread-281-1-1.html

[摘要] 很多人认为,TCP协议自身先天就有KeepAlive机制,为何基于它的通讯链接,仍然需要在应用层实现额外的心跳保活?本文将从移动端IM实践的角度告诉你,即使使用的是TCP协议,应用层的心跳保活仍旧必不可少。

[- 7 -] 一文读懂即时通讯应用中的网络心跳包机制:作用、原理、实现思路等

[链接] http://www.52im.net/thread-2697-1-1.html

[摘要] 要想真正理解即时通讯应用底层的开发,心跳机制必须掌握,而这也是本文写作的目的,希望能带给你启发。

[- 8-]  微信团队原创分享:Android版微信后台保活实战分享(进程保活篇)

[链接] http://www.52im.net/thread-210-1-1.html

[摘要] 尽量保证应用的进程不被Android系统回收。这是本文要讨论的内容。

[- 9 -] 微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)

[链接] http://www.52im.net/thread-209-1-1.html

[摘要] 如何保证消息接收实时性。这是本文要讨论的内容。

[- 10-] 移动端IM实践:实现Android版微信的智能心跳机制

[链接] http://www.52im.net/thread-120-1-1.html

[摘要] 设计此方案的主要目标是,在尽量不影响用户收消息及时性的前提下,根据网络类型自适应的找出保活信令TCP连接的尽可能大的心跳间隔,从而达到减少安卓微信因心跳引起的空中信道资源消耗,减少心跳Server的负载,以及减少部分因心跳引起的耗电。

[- 11-] 移动端IM实践:WhatsApp、Line、微信的心跳策略分析

[链接] http://www.52im.net/thread-121-1-1.html

[摘要] 本文着重分析WhatsApp、Line、微信的心跳。

[- 12-] Android P正式版即将到来:后台应用保活、消息推送的真正噩梦

[链接] http://www.52im.net/thread-1832-1-1.html

[摘要] Android P官方公开的开发者资料来看,此版加入或强化的多项设备电量管理新特性,使得需要后台消息推送、应用保活的APP变的越来越困难,黑科技恐将成为历史。

[- 13-] 全面盘点当前Android后台保活方案的真实运行效果(截止2019年前)

[链接] http://www.52im.net/thread-2176-1-1.html

[摘要] 正因为Android系统版本的差异,也导致了各种保活黑科技的运行效果大相径庭,所以本文正好借此机会,盘点一下当前主流(截止2019年前)的保活黑科技在市面上各版本Android手机上的运行效果,希望能给大家提供一些客观的参考

[- 14-] 融云技术分享:融云安卓端IM产品的网络链路保活技术实践

[链接] http://www.52im.net/thread-2744-1-1.html

[摘要] 众所周知,IM 即时通讯是一项对即时性要求非常高的技术,而保障消息即时到达的首要条件就是链路存活。那么在复杂的网络环境和国内安卓手机被深度定制化的条件下,如何保障链路存活呢?本文详解了融云安卓端IM产品在基于 TCP 协议实现链路保活方面的实践总结。

[- 15-一种Android端IM智能心跳算法的设计与实现探讨(含样例代码)

[链接] http://www.52im.net/thread-783-1-1.html

[摘要] 本文将与大家一起探讨一种更加简单易行和实用的心跳算法,不一定适合所有人,但希望能需要的同行带来一些启发。

[- 16-] 跟着源码学IM(一):手把手教你用Netty实现心跳机制、断线重连机制

[链接] http://www.52im.net/thread-2663-1-1.html

[摘要] 说到用Netty来开发IM或推送系统,以一个生产级产品的标准来说,最基本的心跳机制、断线重连机制肯定得有吧?好,如果你还不清楚这些,那就看看本文吧!

[- 17-] 跟着源码学IM(五):正确理解IM长连接、心跳及重连机制,并动手实现

[链接] http://www.52im.net/thread-2799-1-1.html

[摘要] 本文正好借着在CIM系统中有这样两个需求(CIM是本文作者从零开发的一个学习性质的IM系统,详见《拿起键盘就是干:跟我一起徒手开发一套分布式IM系统》),正好来聊一聊我是如何理解IM长连接的心跳及重连机制,以及又是怎么踩坑已及填坑的。

[- 18-] 2020年了,Android后台保活还有戏吗?看我如何优雅的实现

[链接] http://www.52im.net/thread-2881-1-1.html

[摘要] 总之,Android应用的后台保活在某些场景下,还是有持续的需求。除了之前那些耳熟能详的保活黑科技以外,在Android 9.0(甚至Android 10)时代,我们还有哪些保活方法可以用?那么,请跟着本文作者的思路,看看更优雅的后台保活实现方法吧。

[- 19-] 史上最强Android保活思路:深入剖析腾讯TIM的进程永生技术

[链接] http://www.52im.net/thread-2893-1-1.html

[摘要] 本文将从Andriod系统层面为你深入剖析腾讯TIM这款IM应用的超强保活能力,希望能给你带来更多Android方面的灵感。

[- 20-] Android进程永生技术终极揭密:进程被杀底层原理、APP应对被杀技巧

[链接] http://www.52im.net/thread-2921-1-1.html

[摘要] 本文的技术原理讲解透彻、系统源码分享到位、样例代码也很有参考意义,希望能对有同样兴趣爱好的Android开发者、IM开发者、推送系统开发者等,带来对于Android进程保活技术的深入理解。

[- 21-] Android保活从入门到放弃:乖乖引导用户加白名单吧(附7大机型加白示例

[链接] http://www.52im.net/thread-3033-1-1.html

[摘要] 本文将以某款线上的IM产品为例,介绍它是如何引导用户在多款主流机型上加白名单的,并分享了该款IM中已制作完成的多达7款主流Andriod机型的详细加白FAQ页面资源(含完整HTML+图片),方便您进行参考、学习和研究,希望能为你的应用开发带来帮助。

[- 22-] 阿里IM技术分享(五):闲鱼亿级IM消息系统的及时性优化实践

[链接] http://www.52im.net/thread-3726-1-1.html

[摘要] 本文将根据闲鱼IM消息系统在消息及时性方面的优化实践,详细分析了IM在线通道面临的各种技术问题,并通过相应的技术手段来优化从而保证用户消息的及时到达。

[- 23-] 万字长文:手把手教你实现一套高效的IM长连接自适应心跳保活机制

[链接] http://www.52im.net/thread-3908-1-1.html

[摘要] 我将通过本篇文章,手把手教大家实现一套可自适应的心跳保活机制,从而能高效稳定地维持诸如IM聊天这类需求的长连接。

👉52im社区本周新文:《即时通讯框架MobileIMSDK的微信小程序端开发者手册》,欢迎阅读!👈

我是Jack Jiang,我为自已带盐!https://github.com/JackJiang2011/MobileIMSDK/

posted @ 2023-04-11 14:49 Jack Jiang 阅读(65) | 评论 (0)编辑 收藏

     摘要: 一、理论知识准备您需要对微信小程序开发有所了解:1)真正零基础入门学习笔记系列2)从零开始的微信小程序入门教程3)最全教程:微信小程序开发入门详解您需要对WebSocket技术有所了解:1)新手快速入门:WebSocket简明教程2)WebSocket详解(一):初步认识WebSocket技术3)WebSocket从入门到精通,半小时就够!4)从零理解WebSocket的通信原理、协议格式、安全性...  阅读全文

posted @ 2023-04-07 12:21 Jack Jiang 阅读(88) | 评论 (0)编辑 收藏

一、基本介绍

MobileIMSDK - 微信小程序端是一套基于微信原生 WebSocket 的即时通讯库:

  • 1)超轻量级、无任何第 3 方库依赖(开箱即用);
  • 2)纯 JS 编写、ES6 语法、高度提炼,简单易用;
  • 3)基于微信原生 WebSocket API,简洁优雅;
  • 4)支持运行于任何支持微信小程序的手机端;
  • 5)能与 MobileIMSDK 的各种客户端完美互通;
  • 6)可应用于微信小程序中的消息推送、客服聊天、企业 OA、IM 等场景。

二、与 MobileIMSDK 的关系

MobileIMSDK - 微信小程序端是基于微信原生 WebSocket 协议的 MobileIMSDK 配套客户端库。

MobileIMSDK 是一套专为移动端开发的开源原创 IM 通信层框架:

  • 历经 8 年、久经考验;
  • 超轻量级、高度提炼,lib 包 50KB 以内;
  • 精心封装,一套 API 同时支持 UDPTCPWebSocket 三种协议(可能是全网唯一开源的);
  • 客户端支持 iOSAndroid标准 JavaH5、小程序、Uniapp(开发中..);
  • 服务端基于 Netty,性能卓越、易于扩展;👈
  • 可与姊妹工程 MobileIMSDK-Web 无缝互通实现网页端聊天或推送等;👈
  • 可应用于跨设备、跨网络的聊天 APP、企业 OA、消息推送等各种场景。

以下是 MobileIMSDK 的最新通信架构图:

MobileIMSDK 的客户端库一直在持续开发和升级中,目前 基于 Uniapp 的 MobileIMSDK 客户端正在开发中 。

三、设计目标

直接使用原生的微信小程序 WebSocket 有以下问题和劣势:

  • 1)功能有限:没有心跳保活、断线重连、消息送达保证(重传和去重)等即时通讯关键算法和逻辑;
  • 2)API 简陋:在如此有限的原生 API 下,能逻辑清晰地实现并组合心跳保活、断线重连、消息送达保证等算法,需要相当高的技术掌控力;
  • 3)逻辑耦合:经验欠缺的开发人员,会将 WebSocket 通信与前端 UI 界面代码混在一起,使得 UI 界面的重构、维护、改版都非常困难。

针对以上问题,而 MobileIMSDK - 微信小程序端库将让开发者专注于 UI 应用层的开发,网络通信层的专业代码交由 SDK 开发人员,从而解偶 UI 前端和通信层的逻辑耦合性,大大降低技术复杂性。

MobileIMSDK - 微信小程序端库的设计目标是为您的开发带来以下便利:

  • 1)界面与通信解偶:UI 界面与网络通信代码解耦,UI 界面的重构、维护、改版都非常容易和优雅;
  • 2)轻量级和兼容性:受益于坚持原生微信小程序 WebSocket API,简洁轻量,无需任何额外依赖;
  • 3)核心内聚和收敛:得益于长期的提炼和经验积累,SDK 核心层高度封装,开发者无需理解复杂算法即可简单上手。
  • 4)纯 JS 轻量级实现:SDK 为纯 JS 编写、ES6 语法,无重量级框架和库依赖,可干净利落地对接各种既有系统。

四、技术亮点

  • 轻量易使用:超轻量级 —— 纯 JS 编写且无任何第 3 方库依赖,高度提炼 —— 简单易用;
  • 代码现代感:尽可能优先使用 ES6 语法,摒弃旧式 JS 语法的年代感;
  • 兼容性很好:基于微信原生 WebSocket API,可很好地运行于支持微信小程序的手机端;
  • 断网恢复能力:拥有网络状况自动检测、断网自动治愈的能力;
  • 送达保证机制:完善的 QoS 消息送达保证机制(多重保障),不漏过每一条消息;
  • 通信协议封装:实现了一个对上层透明的即时通讯通信协议模型;
  • 身份认证机制:实现了简单合理的身份认证机制;
  • 完善的 log 信息:在开发调试阶段,确保每一个算法关键步骤都有日志输出,让您的运行调试更为便利;
  • 界面代码解耦:实现了 UI 界面代码与 SDK 网络通信代码解偶,防止界面代码跟 IM 核心代码混在一起,不利于持续升级、重用和维护;
  • 聊天协议兼容:实现了与 MobileIMSDK 各种客户端完全兼容的协议模型。

五、Demo 运行截图

六、详细介绍

① MobileIMSDK - 微信小程序端的详细介绍:点此查看 👈

② MobileIMSDK - 微信小程序端的开发手册:点此查看 👈

③ MobileIMSDK 开源框架的详细介绍:https://gitee.com/jackjiang/MobileIMSDK  👈

posted @ 2023-04-03 12:00 Jack Jiang 阅读(80) | 评论 (0)编辑 收藏

     摘要: 本文由得物技术团队Uni分享,即时通讯网收录时有内容修订和排版优化。一、引言本文要分享的是得物技术团队基于Electron开发客服IM桌面端的技术实践过程,内容包括桌面技术选型、Electron的基础概念、具体的实施技术方案、遇到的棘手问题等。Electron社区虽然很活跃,但是不一样的场景遇到的技术问题,几乎找不到对应的解决方案,我们很多都是在探索过程中不断的去完善,希望本文能带给你一些启发。学...  阅读全文

posted @ 2023-03-30 13:38 Jack Jiang 阅读(93) | 评论 (0)编辑 收藏

     摘要: 一、本文内容概述WiFi对于现在的家庭来说,属于司空见惯的上网方式,但很多情况下,家里房间多、空间大、杂物乱的情况下,WiFi的信号就受影响。为什么WiFi信号会受影响?什么情况下该使用何种方式组网?如何改善WiFi信号差的问题?等等,本文将通俗易懂地为你找到这些问题的答案。学习交流:- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM》- 开源IM框架源码:https://gith...  阅读全文

posted @ 2023-03-23 14:53 Jack Jiang 阅读(61) | 评论 (0)编辑 收藏

为了更好地分类阅读52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第10 期。

[-1-] 简述传输层协议TCP和UDP的区别

[链接http://www.52im.net/thread-580-1-1.html

[摘要] 本文将从应用层的角度,简要的对比TCP和UDP协议的区别,或许能给你些许启发。


[-2-] 为什么QQ用的是UDP协议而不是TCP协议?

[链接http://www.52im.net/thread-279-1-1.html

[摘要] QQ既有UDP也有TCP!不管UDP还是TCP,最终登陆成功之后,QQ都会有一个TCP连接来保持在线状态。这个TCP连接的远程端口一般是80,采用UDP方式登陆的时候,端口是8000。


[-3-]移动端即时通讯协议选择:UDP还是TCP?

[链接http://www.52im.net/thread-33-1-1.html

[摘要]对于有选择困难证的人来说,基于以上因素,加上UDP和TCP协议的本质差异,这样的选择确实很纠结。本文将从作者的实践总结,给出自已的观点,如有异议还请理性回复,不为找喷,仅供参考。


[-4-]快速理解TCP和UDP的差异

[链接http://www.52im.net/thread-1160-1-1.html

[摘要] 本文延续《网络编程懒人入门》系列文章的风格,通过快速对比分析 TCP 和 UDP 的区别,来帮助即时通讯初学者快速了解这些基础的知识点,从而在IM、消息推送等网络通信应用场景中能准确地选择合适的传输层协议。


[-5-] 快速理解为什么说UDP有时比TCP更有优势

[链接http://www.52im.net/thread-1277-1-1.html

[摘要] 随着网络技术飞速发展,网速已不再是传输的瓶颈,UDP协议以其简单、传输快的优势,在越来越多场景下取代了TCP,如网页浏览、流媒体、实时游戏、物联网。本文作为《网络编程懒人入门》系列文章的第5篇,将为您快速梳理UDP协议在某些场景下对比TCP协议所具有的优势。


[-6-] UDP的连接性和负载均衡

[链接http://www.52im.net/thread-1018-1-1.html

[摘要]本文将从实践出发,讨论UDP在实际应用中的连接性和负载均衡问题。


[-7-] 深入地理解UDP协议并用好它

[链接] http://www.52im.net/thread-1024-1-1.html

[摘要] 本文接系列文章的上篇《不为人知的网络编程(五):UDP的连接性和负载均衡》,将从实践出发,讨论如何深入地理解UDP协议并在实践中用好它。


[-8-] 如何让不可靠的UDP变的可靠?

[链接http://www.52im.net/thread-1293-1-1.html

[摘要] 涉及到实时传输我们都会先考虑 RUDP,RUDP 应用在我们APP核心传输体系的各个方面,但不同的系统场景我们设计了不同的 RUDP 方式,所以基于那些激烈的讨论和我们使用的经验,我决定扒一扒 RUDP,来给大家分享如何让UDP变的可靠的实践经验。


[-9-] 从底层入手,深度分析TCP连接耗时的秘密

[链接http://www.52im.net/thread-3265-1-1.html

[摘要] 经过日常工作的思考之后,我更想弄明白的是,TCP的开销到底有多大,能否进行量化。一条TCP连接的建立需要耗时延迟多少,是多少毫秒,还是多少微秒?能不能有一个哪怕是粗略的量化估计?当然影响TCP耗时的因素有很多,比如网络丢包等等。我今天只分享我在工作实践中遇到的比较高发的各种情况。


[-10-]彻底搞懂TCP协议层的KeepAlive保活机制

[链接http://www.52im.net/thread-3506-1-1.html

[摘要] 限于篇幅,该篇并没有深入探讨TCP协议本身的KeepAlive机制,所以这次借本文想把TCP协议的KeepAlive保活机制给详细的整理出来,以便大家能深入其中一窥究竟。


[-11-] 拔掉网线再插上,TCP连接还在吗?一文即懂

[链接http://www.52im.net/thread-3846-1-1.html

[摘要] 本篇文章,我们就从系统层面深入地探讨一个有趣的TCP技术问题:拔掉网线后,再插上,原本的这条TCP连接还在吗?或者说它还“好”吗?


[-12-] 单台服务器并发TCP连接数到底可以有多少

[链接http://www.52im.net/thread-561-1-1.html

[摘要] 到底一台服务器能够支持多少TCP并发连接呢?这就是本文要讨论的问题。


👉52im社区本周新文:《得物从0到1自研客服IM系统的技术实践之路》,欢迎阅读!👈

我是Jack Jiang,我为自已带盐!https://github.com/JackJiang2011/MobileIMSDK/

posted @ 2023-03-23 10:42 Jack Jiang 阅读(80) | 评论 (0)编辑 收藏

     摘要: 1、前言最近我负责的 LiveChat 客服聊天系统到了自研阶段,任务类似于做一个腾讯云IM这样的通信层SDK。在和后台进行技术选型讨论后,确定了数据传输层协议格式使用 Protobuf。本文基于我对Protobuf在Android端的实际使用心得,手把手教你如何在Android端IM产品中使用Protobuf,希望对你有帮助。学习交流:- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动...  阅读全文

posted @ 2023-03-09 14:30 Jack Jiang 阅读(59) | 评论 (0)编辑 收藏

1、项目简介

MobileIMSDK是一套专为移动端开发的原创IM通信层框架:

  • 1)历经8年、久经考验;
  • 2)超轻量级、高度提炼,lib包50KB以内;
  • 3)精心封装,一套API同时支持UDP、TCP、WebSocket三种协议(可能是全网唯一开源的);
  • 4)客户端支持iOS、Android、标准Java、H5(暂未开源)、小程序(开发中..)、Uniap(开发中..);
  • 5)服务端基于Netty,性能卓越、易于扩展 new;
  • 6)可与姊妹工程 MobileIMSDK-Web 无缝互通实现网页端聊天或推送等;
  • 7)可应用于跨设备、跨网络的聊天APP、企业OA、消息推送等各种场景。

2、代码托管同步更新

GitHub.com:

码云gitee:

3、设计目标

让开发者专注于应用逻辑的开发,底层复杂的即时通讯算法交由SDK开发人员,从而解偶即时通讯应用开发的复杂性。

4、框架组成

整套MobileIMSDK框架由以下6部分组成:

  • 1)Android客户端SDK:用于开发Android版即时通讯客户端,支持Android 2.3及以上版本,查看API文档
  • 2)iOS客户端SDK:用于开发iOS版即时通讯客户端,支持iOS 8.0及以上版本,查看API文档
  • 3)Java客户端SDK:用于开发跨平台的PC端即时通讯客户端,支持标准Java 1.6及以上版本,查看API文档
  • 4)H5客户端SDK:暂无开源版,查看精编注释版
  • 5)小程序端SDK:持续开发中,敬请关注;
  • 6)服务端SDK:用于开发即时通讯服务端,支持Java 1.7及以上版本,查看API文档

整套MobileIMSDK框架的架构组成:

5、技术特征

  • 久经考验:历经8年,从Andriod 2.3、iOS 5.0 时代持续升级至今(绝不烂尾);
  • 超轻量级:高度提炼,lib包50KB以内;
  • 多种协议:可能是全网唯一开源可同时支持UDP、TCP、WebSocket三种协议的同类框架;
  • 多种网络:精心优化的TCP、UDP、WebSocket协议实现,可应用于卫星网、移动网、嵌入式物联网等场景;
  • 高效费比:独有的UDP协议实现,无连接特性,同等条件下可实现更高的网络负载和吞吐能力;
  • 消息走向:支持即时通讯技术中消息的所有可能走向,共3种(即C2C、C2S、S2C);
  • 粘包半包:优雅解决各端的TCP经典粘包和半包问题,底层封装,应用层完全无感知;
  • QoS机制:完善的消息送达保证机制(多重保障),不漏过每一条消息;
  • 健壮可靠:实践表明,非常适于在高延迟、跨洲际、不同网络制式环境中稳定、可靠地运行;
  • 断网恢复:拥有网络状况自动检测、断网自动治愈的能力;
  • 原创算法:核心算法和实现均为原创,保证了持续改进和提升的空间;
  • 多种模式:预设多种实时灵敏度模式,可根据不同场景控制即时性、流量和客户端电量消耗;
  • 数据压缩:自有协议实现,未来可自主定制数据压缩,灵活控制客户端的流量、服务端网络吞吐;
  • 高度封装:高度封装的API接口,保证了调用的简易性,也使得可应用于更多的应用场景;
  • Web支持:可与姊妹工程 MobileIMSDK-Web 无缝互通实现网页端聊天或推送等;
  • 扩展性好:服务端基于Netty,继承了Netty的优秀高可扩展性;
  • 性能优异:服务端继承了Netty高性能、高吞吐特性,适用于高性能服务端场景。

MobileIMSDK 所支持的全部3种即时通讯消息走向分别是:

(1) Client to Client (C2C):即由某客户端主动发起,接收者是另一客端;

(2) Client to Server (C2S):即由某客户端主动发起,接收者是服务端;

(3) Server to Client (S2C):即由服务端主动发起,接收者是某客户端。

6、性能测试

压力测试表明,MobileIMSDK用于推送场景时,理论单机负载可接近千万级。用于聊天应用时,单机负载也可达数十万。

当然,每款应用都有各自的特点和差异,请视具体场景具体评估之,测试数据仅供参考。

性能测试报告:点此查看

7、演示程序

8、应用案例

RainbowChat是一款基于MobileIMSDK的产品级聊天APP,更多详情:点击下载体验 或 查看运行截图

① 基于MobileIMSDK的产品级聊天APP:

▶ 详细介绍下载体验 或 查看运行截图

② MobileIMSDK在高网络延迟下的案例:

▶ 某款基于MobileIMSDK的商业商品,曾运营于跨洲际的复杂网络环境下,端到端通信延迟在洲际网络繁忙时可高达600ms以上(与服务端的单向延迟约为300ms左右,而通常大家访问国内主流门户的延迟约为20~50ms),某段时期的非敏感运营数据 点此查看

9、打包下载(all in one)

说明:最新发布版打包内容中,已包含完整的demo源码、sdk源码、api文档、编译后的分发包等。

10、典型应用场景

场景1:聊天APP

  • 应用说明:可用于开发类似于微信、QQ等聊天工具。
  • 消息走向:需使用C2C、C2S、S2C全部类型。

特别说明:MobileIMSDK并未定义聊天应用的应用层逻辑和协议,开发者可自行定义并实现之。

场景2:消息推送

  • 应用说明:可用于需要向客户端实时推送信息的各种类型APP。
  • 消息走向:仅需使用S2C 1种消息走向,属MobileIMSDK的最简单应用场景。

场景3:企业OA

  • 应用说明:可用于实现企业OA的指令、公文、申请等各种消息实时推送,极大提升用户体验,并可延伸至移动设备。
  • 消息走向:仅需使用S2C 1种消息走向,属MobileIMSDK的最简单应用场景。

场景4:企业OA的增强型

  • 应用说明:可用于实现企业OA中各种系统级、用户级消息的实时互动,充分利用即时通讯技术提升传统OA的价值。
  • 消息走向:可使用C2C、C2S、S2C全部类型,这与聊天APP在很多方面已无差别,但企业OA有自已的用户关系管理模型和逻辑,较之全功能聊天APP要简单的多。

11、开发指南

12、关注作者

博客地址:点击入进、Github主页:点击进入

附录1:Demo截图

1)Android和iOS运行效果

>> 安装和使用:进入Android版Demo帮助页进入iOS版Demo帮助页

2)Windows 运行效果

>> 安装和使用:进入Java版Demo帮助页

3)Mac OS X 运行效果

>> 安装和使用:进入Java版Demo帮助页

附录2:基于MobileIMSDK的全功能IM【案例】

>> 关于RainbowChat的更多资料请见:RainbowChat前端APP功能截图网页 。

 

附录3:基于MobileIMSDK-Web的网页端IM系统【案例】

下图为RainbowChat-Web的主界面(更多截图点此进入更多演示视频点此进入):

posted @ 2023-03-06 12:21 Jack Jiang 阅读(50) | 评论 (0)编辑 收藏

     摘要: 1、引言我相信大家刚开始学网络编程中socket的时候,都跟我一样对书上所讲的socket概念云里雾里的、似懂非懂,很是困扰。这篇文章我打算从初学者的角度,用通俗易懂的文字,跟大家分享下我所理解的socket是什么,并由浅入深从操作系统内核实现来透视socket的原理。* 推荐阅读:跟本篇类似,《到底什么是Socket?一文即懂!》一文也非常适合初学者。另一篇《我们在读写Socket时,究竟在读写...  阅读全文

posted @ 2023-03-02 14:25 Jack Jiang 阅读(57) | 评论 (0)编辑 收藏

关于MobileIMSDK

MobileIMSDK 是一套专门为移动端开发的开源IM即时通讯框架,超轻量级、高度提炼,一套API优雅支持UDP 、TCP 、WebSocket 三种协议,支持iOSAndroidH5标准Java平台,服务端基于Netty编写。

工程开源地址是:

关于RainbowChat

► 详细产品介绍:http://www.52im.net/thread-19-1-1.html
► iOS端更新记录:http://www.52im.net/thread-2735-1-1.html
► 全部运行截图:iOS端全部运行截图 (另:Android端运行截图 点此查看
► 在线体验下载:App Store安装地址 (另:Android端下载体验 点此查看

 

RainbowChat是一套基于开源IM聊天框架 MobileIMSDK 的产品级移动端IM系统。RainbowChat源于真实运营的产品,解决了大量的屏幕适配、细节优化、机器兼容问题(可自行下载体验:专业版下载安装)。

RainbowChat可能是市面上提供im即时通讯聊天源码的,唯一一款同时支持TCP、UDP两种通信协议的IM产品(通信层基于开源IM聊天框架 MobileIMSDK 实现)。

v6.2 版更新内容

此版更新内容更多历史更新日志):

  • 1)[优化] 升级核心通信层库 MobileIMSDK 至 v6.3
  • 2)[优化] 提供了方便的配置用于开/关长连接的SSL/TLS加密传输。

此版主要功能运行截图更多截图点此查看):

posted @ 2023-03-01 12:05 Jack Jiang 阅读(37) | 评论 (0)编辑 收藏

     摘要: 1、引言对于IM聊天应用来说,为了提升安全性,对聊天消息加密是常规操作。众所周之,Netty是高性能的Java NIO网络通信框架,因而用Netty来写IM是再正常不过了。网上关于为Netty生成、以及使用SSL/TLS证书的文章有很多,但由于各种原因,生成的证书要么是Netty中无法读取和使用,要么是代码不全或不具体导致根本配不通SSL/TLS加密。正好这段时间专门为 MobileIM...  阅读全文

posted @ 2023-02-23 14:18 Jack Jiang 阅读(68) | 评论 (0)编辑 收藏

关于MobileIMSDK

MobileIMSDK 是一套专门为移动端开发的开源IM即时通讯框架,超轻量级、高度提炼,一套API优雅支持UDP 、TCP 、WebSocket 三种协议,支持iOS、Android、H5、标准Java平台,服务端基于Netty编写。

工程开源地址是:

关于RainbowChat

► 详细产品介绍:http://www.52im.net/thread-19-1-1.html
► 版本更新记录:http://www.52im.net/thread-1217-1-1.html
► 全部运行截图:Android端iOS端
► 在线体验下载:专业版(TCP协议)专业版(UDP协议)      (关于 iOS 端,请:点此查看

 

RainbowChat是一套基于开源IM聊天框架 MobileIMSDK 的产品级移动端IM系统。RainbowChat源于真实运营的产品,解决了大量的屏幕适配、细节优化、机器兼容问题(可自行下载体验:专业版下载安装)。

* RainbowChat可能是市面上提供im即时通讯聊天源码的,唯一一款同时支持TCP、UDP两种通信协议的IM产品(通信层基于开源IM聊天框架  MobileIMSDK 实现)。

v8.4 版更新内容

此版更新内容更多历史更新日志):

(1)Android端主要更新内容通信核心层优化!】:

  • 1)[优化] 可根据http接口的url自动判断并启用https加密;
  • 2)[优化] 升级核心长连接通信层库 MobileIMSDK 至 v6.3
  • 3)[优化] 提供了灵活的接口定制和开启长连接的SSL/TLS加密传输。

(2)服务端主要更新内容:

  • 1)[优化] 升级核心长连接通信层库MobileIMSDK 至 v6.3
  • 2)[优化] 开放了灵活的接口定制和开启长连接的SSL/TLS加密传输。

此版主要功能运行截图更多截图点此查看):

posted @ 2023-02-16 10:42 Jack Jiang 阅读(57) | 评论 (0)编辑 收藏

本文作者:丁同舟,来自金蝶随手记技术团队。

1、引言

接上篇《金蝶随手记团队的Protobuf应用实践(原理篇)》,本文将以iOS端的Objective-C代码为例,图文并茂地向您菔救绾卧趇OS工程中快速使用Protobuf,希望对你有帮助。

 

学习交流:

(本文已同步发布于:http://www.52im.net/thread-4133-1-1.html

2、系列文章

本文是系列文章中的第 9 篇,本系列总目录如下:

另外:如果您还打算系统地学习IM开发,建议阅读《新手入门一篇就够:从零开发移动端IM》。

3、基本介绍

 

Protobuf(全称 Protocol buffers) 是 Google 提出的一种跨平台、多语言支持且开源的序列化数据格式。相对于类似的 XML 和 JSON,Protobuf 更为小巧、快速和简单。相对于传统的 XML 和 JSON, Protobuf 的优势主要在于:更加小、更加快,其语法目前分为proto2和proto3两种格式。

如果你没不了解Protobuf是什么,建议先阅读本系列的前几篇《Protobuf从入门到精通,一篇就够!》、《快速理解Protobuf的背景、原理、使用、优缺点》、《金蝶随手记团队的Protobuf应用实践(原理篇)》,本篇就不再重复介绍了。

目前 Google 官方的 Protobuf最新 release 版本为3.21.12,但本文写作时用的是3.5.1,以下截图都是基于此版本的环境搭建,如果你使用最新版本,差异并不大,因为只是小版本更新。

关于 Protobuf的使用可以查阅官方文档:https://developers.google.com/protocol-buffers/docs/overview,建议养成阅读文档的习惯。

4、准备工作

4.1环境要求

最低开发环境要求:

  • 1)Objective-C 2.0 Runtime (32bit & 64bit iOS, 64bit OS X)
  • 2)Xcode 7.0 以上版本

注意:Protobuf 出于性能考虑没有使用 ARC,但在 ARC 下是可以使用的。

4.2下载安装

下载 Protobuf 代码包(https://github.com/protocolbuffers/protobuf/releases/tag/v21.12),因文章截图时用的是v3.5.1,所以我这里的为了保持一致选择的是 protobuf-objectivec-3.5.1.tar.gz,版本区别不大,建议依此类推。

4.3解压代码包

编译 Protobuf,这里可能需要安装部分工具:

$ brew install autoconf

$ brew install automake

$ brew install libtool

运行下面脚本进行编译:

$ ./autogen.sh

$ ./configure

$ make

$ makeinstall

检查protobuf是否安装成功:

$ protoc --version

如果成功打印版本号则安装成功:

libprotoc 3.5.1

5、在 iOS 中使用 Protobuf

5.1创建.proto文件

这里使用官方文档上的一份示例数据结构创建Person.proto:

syntax = "proto3";

 

message Person {

  string name = 1;

  int32 id = 2;

  string email = 3;

 

  enumPhoneType {

    MOBILE = 0;

    HOME = 1;

    WORK = 2;

  }

 

  message PhoneNumber {

    string number = 1;

    PhoneType type = 2;

  }

 

  repeated PhoneNumber phone = 4;

}

使用命令行编译Person.proto为objective-c的文件,编译出来的文件为Person.pbobjc.h和Person.pbobjc.m:

protoc Person.proto --objc_out=./

5.2引入 Protobuf 运行时资源

Google 官方的文档提供了两种引入方式,但使用第一种的时候编译不能通过,所以这里选择了第二种。

具体就是:复制protobuf目录下的:objectivec/*.h, objectivec/google/protobuf/*.pbobjc.h, objectivec/google/protobuf/*.pbobjc.m, 以及除去 objectivec/GPBProtocolBuffers.m 后的objectivec/*.m。

这里直接用命令行操作。

首先进入protobuf下objectivec的目录:

$ cdprotobuf-3.5.1/objectivec

然后复制符合规则的文件到指定的工程目录下:

$mkdir~/ProtobufDemo/ProtocolBuffers~/ProtobufDemo/ProtocolBuffers/google~/ProtobufDemo/ProtocolBuffers/google/protobuf

$ cp*.h *.m ~/ProtobufDemo/ProtocolBuffers

$ cpgoogle/protobuf/*.pbobjc.h google/protobuf/*.pbobjc.m ~/ProtobufDemo/ProtocolBuffers/google/protobuf

注意:上面的命令并没有排除 GPBProtocolBuffers.m 文件,引入时需要手动排除。

现在把ProtocolBuffers目录下所有文件以及上面编译出来的 Person.pbobjc.h 和 Person.pbobjc.m 都引入到工程中。

现在工程目录结构大概是长这样:

 

注意:由于protobuf没有使用 ARC,因此需要为所有.m文件加上-fno-objc-arc来关闭 ARC。

结果如下:

提示:需要留意工程中的 Header Search Paths 要增加 $(PROJECT_DIR)/ProtocolBuffers(具体的路径视情况而定)

5.3直接引入 ProtocolBuffers 工程

如果觉得手动引入文件的方式过于复杂,可以直接引入ProtocolBuffers工程作为依赖项。

1)进入解压后的protobuf目录下,复制objective目录下的所有文件到ProtobufDemo/ProtocolBuffers目录下。

2)在ProtobufDemo工程中引入ProtocolBuffers_iOS工程:

3)在Build Phases中加入依赖关系并链接库:

 

4)引入Person.pbobjc.hPerson.pbobjc.m文件并为.m加上-fno-objc-arc

5)修改工程配置中部分路径为 $(PROJECT_DIR)/ProtocolBuffers

5.4运行测试

首先引入头文件:

#import "Person.pbobjc.h"

生成Person对象并进行编码和解码:

Person *p = [[Person alloc] init];

p.id_p = 1;

p.name = @"person1";

p.email = @"123@qq.com";

 

//encode

NSData*data = [p data];

NSLog(@"Protocol Buffers:\n%@\nData: %@\nData Length: %lu", p, data, data.length);

 

//decode

Person *newP = [[Person alloc] initWithData:data error:nil];

NSLog(@"Decoded: %@", newP);

运行程序,打印日志如下:

Protocol Buffers:

<;Person 0x60c0000da2b0>: {

    name: "person1"

    id: 1

    email: "123@qq.com"

}

Data: <0a077065 72736f6e 3110011a 0a313233 4071712e 636f6d>

Data Length: 23

Decoded: <;Person 0x6040000d9c90>: {

    name: "person1"

    id: 1

    email: "123@qq.com"

}

6、参考资料

[1] Protobuf 官方开发者指南(中文译版)

[2] Protobuf官方手册

[3] Protobuf从入门到精通,一篇就够!

[4] 如何选择即时通讯应用的数据传输格式

[5] 强列建议将Protobuf作为你的即时通讯应用数据传输格式

[6] APP与后台通信数据格式的演进:从文本协议到二进制协议

[7] 面试必考,史上最通俗大小端字节序详解

[8] 移动端IM开发需要面对的技术问题(含通信协议选择)

[9] 简述移动端IM开发的那些坑:架构设计、通信协议和客户端

[10] 理论联系实际:一套典型的IM通信协议设计详解

[11] 58到家实时消息系统的协议设计等技术实践分享

[12] 金蝶随手记团队的Protobuf应用实践(原理篇)

[13] 新手入门一篇就够:从零开发移动端IM

Coffee time!

(本文已同步发布于:http://www.52im.net/thread-4133-1-1.html

posted @ 2023-02-14 12:52 Jack Jiang 阅读(33) | 评论 (0)编辑 收藏

本文由钉钉技术专家啸台、万泓分享,为了获得更好的阅读效果,本文已对内容进行少修订和重新排版。

1、引言

钉钉后端架构的单元化工作从2018年开始到今年,已经是第五个年头了。五年的时间,钉钉单元化迭代了三个版本,从最初的毛头小子,到达今年已经小有成就。

我们在进行单元化架构建设的过程中,除了网上能找到的屈指可数的文章外,可以直接使用的系统更是乏善可陈,使我们不得不从最基础的系统开始造轮子,极大的影响建设效率。幸运的是,近几年云原生技术的兴起,让我们能复用很多基础设施,进而快速提升我们的单元化建设能力,助力钉钉的发展。

今天想借此文和大家分享我们在钉钉单元化架构实施过程中的心路历程和一些最佳实践。因涉及的技术和业务面太广,本文的分享无法做到面面俱到,主要是想在同路人中形成共鸣,进而能复用一些架构或子系统的设计和实现思路。

学习交流:

(本文同步发布于:http://www.52im.net/thread-4122-1-1.html

2、系列文章

本文是系列文章的第 10 篇,总目录如下:

3、术语概念

本文内容中使用了一些专有的技术名词,为了方便大家理解,我把关键的几个术语概念的缩写及其含义专门列出来,供大家参考。

主要是以下几个

  • 1)Geo:钉钉专有化部署单位,解决数据合规需求,Geo间数据按需互通,并且互通数据在Geo内部做镜像拷贝,解决两化问题;
  • 2)Unit: Geo内部资源物理分区隔离的最小单位,解决Geo内的容灾和容量的问题;
  • 3)L0:客户端路由,决定了用户客户端接入钉钉服务器的所属单元,用户长连接所在的逻辑单元,起到连接加速作用。用户接入单元;
  • 4)L1:接入层路由,以用户为维度进行调度,即用户操作发生的单元。用户归属单元;
  • 5)L2:业务层路由,以业务资源为维度进行调度,大部分的业务资源所在单元应该和用户调度单元一致,但一些业务无法按照用户划分单元,如IM的会话,音视频的会议。 业务归属单元;
  • 6)DMB:负责钉钉应用跨单元RPC调用的转发,可以认为是钉钉单元化RPC路由中间件;
  • 7)DMR:负责钉钉应用跨单元MQ消息的转发,可以认为是钉钉单元化MQ路由中间件;
  • 8)DTIM:钉钉IM系统。

4、单元化架构1.0版:合规驱动下的部署架构

2018年,部分大客户出于法律政策、商业机密数据存储的要求,要求钉钉的数据存储、访问接入、服务部署需要在其信任的区域内。既需要满足其数据存储私有化要求,同时需要满足跨地区网络的rt性能要求。

于是我们结合阿里云机房部署位置、物理距离、用户数据安全等方面出发,钉钉在客户的阿里云机房内建设了一个单元,将通讯录、IM信息等企业数据单独存储在客户机房。

我们通过一条专线,将两个机房逻辑串联到一起,内部通过DMB/DMR系统,实现了请求互通,这就是钉钉单元化架构的1.0版。

1.0版比较简单,纯粹是业务驱动,和支付宝单元化建设的初衷——“容灾驱动”有较大区别。两个站点通过UID分段,将用户划分为中心用户和专有用户。

上图只是一个简化的逻辑结构,内部实现远比上图复杂,但是1.0建设主要是从0到1,和大多数异地多活的系统较相似,这里就只简单的和大家分享一下。

5、单元化架构2.0版:逼出来的容量架构

2020年是一个特殊的年份,由于疫情的原因,带给大家非常多的改变,其中也包括钉钉。

由于在线办公与教育流量的突增,开年第一天上班就给钉钉一个下马威,平峰的流量已经和除夕跨年的持平,但是和除夕不同的是这个流量是持续的,即使节前准备了三倍容量,也抵挡不住流量对系统的冲击。只能借助阿里云的能力,不断的扩容。

但是每天将近30%的流量增幅,单纯的扩容也能难保障服务的连续性,最终也遇到了扩无可扩的场景,张北机房没有机位了,有机器资源但是没有机位让我们有力无处使。我们不得不不断进行系统优化,同时借助限流、降级、双推等措施,勉强抗住了流量的最高峰。

疫情之前,我们一直在做高可用,但是这个高可用主要集中在容灾机制上,比如搭建容灾单元。如同支付宝一样,是因为当时光纤被挖断;又比如银行的两地三中心架构,是担心某一个地域由于天灾或者战争导致数据丢失。疫情的流量给我们上了一课,仅仅关注容灾是不够的,特别是钉钉的DAU从千万走向亿级别之后,更需要在容量上做出提前规划。

正因如此,我们认为“容量架构不是设计出来而是真真切切被逼出来的”,所以容量架构就成为我们单元化核心要素之一。

容量架构是将流量划分到不同单元,每个单元承载各自的流量。容灾架构是单元异常时,能保障核心的能力可用,也可以将流量动态调度到别的单元,实现服务的快速恢复。

因此钉钉单元化进入了2.0时代,专注于容量和容灾的建设。

6、2.0版是基于什么维度进行流量划分的?

要实现流量的划分,必然要基于一个维度进行划分,一部分到A单元,一部分到B单元。

钉钉单元化架构也是参考了淘系和支付宝的单元化架构,前两者都是基于UID划分,钉钉单元化的第一个版本其实也是一样的,基于UID做拆分。

但是当我们设计容量架构时,发现基于UID划分无法解决我们的容量问题。

以IM为例:一条消息其实属于聊天双方的,群聊亦是如此。用户能和任意一个人聊天,这样我们根本无法找到一个切入点来划分流量,强行按照UID拆分,必然导致一个用户的消息出现在N个单元,单元的自封闭就无法做了。

也有同学会说:为什么消息不按照每个人存储,这不就能按照UID划分了吗?结论是不行。首先这个消息变成了写扩散,持久化的时候会变成多单元写,其次是成本翻倍,在DTIM这种过亿规模的场景这条路走不通。这里可以多说一点,因为这个观点来之不易,大家都知道,人是有惯性的,既然淘宝、支付宝甚至是微信都是UID划分,为什么钉钉要特立独行?当时我们团队受到了绝大部分钉钉技术团队的挑战,持续长达将近一个月的技术选型的“争吵”,最终还是达成了一致意见。

DTIM主要有3个维度,分别是UID、会话(CID)、消息。其中会话和消息是绑定的,而系统中最大量的是消息,按照第一性原则来看,一定要将消息划分开来,才能做到将容量划分开来的效果。

我们再来看看音视频,是按照房间维度组织流量和数据的,和IM又完全不同。

同样,文档其实更适合按照企业维度来划分。

不同的业务拥有不同的维度,因此我们认为:单元化最重要的找到自身“最大”的业务维度,将这个维护拆分,才能实现单元的横向扩展,我们称之为“业务路由”。

回头来看:我们之前其实是进入了思考误区,以为淘系和支付宝都是UID维度,我们也要这个维度,其实UID正是前者的业务维度,比如订单,也是围绕用户,并不会有交集的情况,会话就是IM的划分维度,因此做单元化之前要先找到属于自己的业务维度。

7、2.0版是如何实现IM消息的全局路由能力的?

7.1概述

UID路由有个最大的好处,就是可以按照UID分段,能实现高效的静态路由,也不用担心多单元之间的一致性问题。但是这种分段路由局限性也比较明显,需要预先分配,单元之间动态调度流量和数据成本极高,而且只能支持这种数值+顺序的场景。

在钉钉的场景中,有会话维度、房间维度、企业维度等等,想简单采用这种预分段机制难以满足业务需求。因此我们需要构建一个业务路由系统(RoutingService),实现消息流量的精确路由。

 

 以IM为例:每次消息的发送,在单元化框架层面,会通过消息的会话(CID),查询路由信息,如果是本单元,流量下行并持久化;如果是非本单元,路由到对应的单元中。

下图是三个会话:分别是cid:1001、cid:1002、cid:1003,三个会话隶属不同单元,不管用户从哪个单元发送消息,都会路由到会话所在的单元。比如:用户在Unit B的cid:1001 中发送消息,当消息进入Receiver之后,会先查询此cid:1001所在的单元,发现是Unit A,路由框架将请求转到A单元,消息在A单元持久化并通过A单元的同步协议,将数据推送到客户端。

 

 

 从上图可知:每次消息发送,都要查询路由服务,DTIM百万的峰值,对路由必然会带来超大的压力,同时我们能发现,路由数据在多单元实现一致性是一个巨大的挑战。

7.2边缘计算:端到端路由

在DTIM的场景中,会话的路由信息几乎不会变更,只有当我们决定将某些超大的会话或者企业腾挪到新单元时,才会发起路由的变更,因此会话的路由信息几乎可以认为是恒定不变的。那么每次查询路由服务端,效费比太低,是极大的浪费。

既然路由信息几乎不可变,是否将路由信息缓存呢?最常见的是使用一个集中式的Cache系统,缓存Hot的会话,我们也是这么做的,但是这么做还是不够,一旦Cache系统失效,DTIM还是会出现大面积故障,而且这个百万级的请求对Cache也是一个极大的压力。

考虑到钉钉有强大的客户端,借用边缘计算的思路,我们将用户的会话数据缓存到客户端。对于客户端来说,也只用缓存用户自身最热的N会话路由数据,消息发送时,通过Header将路由数据携带到服务端,服务端路由SDK只要做合法性和续约即可,这样就将路由流量降低了95%以上。当路由服务出现异常时,还可以继续使用客户端路由,将路由的可用性提升到一个新的高度。

SDK本地会依据上行请求的返回中是否有新的路由信息,进而更新客户端路由。同时可以借助钉钉有主动下推的能力,通过同步协议将新的路由信息主动推送给客户端,使会话迁移做到更平顺。

7.3计算下沉:多单元一致性


对于新会话:比如小明要创建一个群聊,是应该创建在那个单元呢?

如果在A单元创建了,当会话消息来到B单元,系统怎么能第一时间知道会话已经在被绑定到A单元。

这里一般的方式有两种

  • 1)单元之间的存储系统采用类似DTS的机制进行异步同步,这种机制有秒级延迟;
  • 2)在应用层主动同步,比如接入消息队列。


这两种方式由于都是异步的原因,都会出现不一致的问题,如果会话同时被绑定在两个单元,逻辑上会导致用户的历史消息丢失,这个是不能接受的。

多地域(Region)数据同步其实是通用的技术挑战,我们认为存储系统提供是最好的方式,正如Google的Spanner一样,这样对我们上层才是最友好的方式。

因此我们找到了存储的OTS、Nuwa团队一起共建了GlobalTable。GlobalTable的核心原理还是借助Nuwa的一致性组,组分布在多个地域,采用多数派写入成功即返回的原理,做到20ms以内的一致性写。

8、2.0版的容灾能力

钉钉单元化的容灾能力是深度结合钉钉的业务层场景落地的,和淘系支付宝等有明确的区别。

以DTIM为例,最大的特点是当服务单元异常时,服务侧仍能提供最核心的服务,保障最基本的能力。本质上是由于DTIM是最终一致性系统,可以短暂允许部分环节失败。

可以看一下DTIM发送消息的容灾场景。当某个单元完全不可用的情况下,用户消息发送链路通过降级为local模式,在本地校验非本单元会话数据通过之后直接做消息发送,processor遇到非本单元的会话消息数据可以做单元间投递做数据回放,本地是否落库可选,同步协议推送不必区分是否为本单元会话消息数据直接通过本单元的topic推送给客户端,配合用户无状态快速迁移能力,单元间可以实现真正的分钟级别容灾切换能力。

9、2.0版的成果与突破

以上是钉钉单元化2.0提供给应用的核心能力,在满足容灾和容量设计需求之后,钉钉单元化给应用带来了更多的能力和想象空间。

比如:

  • 1)快速迁移:当某一地域资源不足时,钉钉单元化可以将业务快速的从A单元迁移到B单元;
  • 2)常态化切流:比如新建的教育会话,可以放到独立的单元;
  • 3)热点治理:当前某一个会话过热,特殊时期可以迁移到独立集群;
  • 4)SLA:满足不同的VIP客户需求,基于不同的SLA和售卖价格,将VIP客户放到对应地单元。

核心还是我们拥有单元化能力之后,实现了多单元流量的快速调度,为业务解决了后顾之忧。

10、2.0版在新时代面临的新挑战

10.1鱼和熊掌不可兼得

2022年对钉钉来说是成本之年,成本的压力不光落到了团队,还落到了每个人身上。

正如存储的CAP理论是一样的,我们同时只能满足两个维度,对于流量(性能P)、成本(C)、体验(E)也是一样,在流量不可预知和干预的情况下,选择成本必然导致体验受损,反之选择体验,必然导致成本升高。进入下半年,疫情反复带来流量的反复,为了实现可控的教育成本,只能在高峰期降级部分能力,这又导致体验受损,这段时间的工单量可以窥见一斑。

流量是用户侧触发的,我们无法干预,只能在成本和体验之间寻求平衡。和前面提及的一样,为了减小成本的消耗这就导致我们在扩容和缩容之间疲于奔命,反应不及时甚至有故障的危险,这种机制不可取也不可持续。到底是要流量与成本,还是要流量与体验,给我们技术团队带来了巨大的挑战和矛盾。

10.2商业化路在何方

当前钉钉为支持大客户提供了多种解决方案,专业钉钉、专属存储与打包、专有钉钉。

专属钉钉通过APP专属化以及部分专属功能,比如为一个企业定制一个拥有独立Logo的APP,能满足一般的中大型客户的业务诉求。

对于大型以及超大型客户,我们提供专有钉钉,提供专有化输出,完全隔离的方案,比如浙政钉。

伴随着钉钉的商业化进入深水区,客户对钉钉提出了新的诉求,特别是数据安全与归属、互联互通、完整的能力栈等诉求,当前钉钉输出产品形态都无法同时地满足以上需求。

前几年互联网上出现的几起数据安全事件,数据丢失与泄露,未经客户授权私自访问客户数据,让大多数客户不信任服务提供商,即使服务商的安全能力已经是业界一线能力。其实这个是可以理解的,数据即客户的生命线,数据无法在自身可控范围内,特别是对于很多特殊行业,这是无法接受的,自身性命岂能假手于人。专属钉钉在面临这种客户时,前线售卖同学是无能为力。

那么很多同学肯定会提“如果专属钉钉满足不了需求,我们专有钉钉不是能解决这些问题吗?”,其实单单从诉求来看,专有钉钉场景是切合客户的业务诉求,提供完全独立运行环境、可控的数据安全。但是专有钉钉由于其独特的架构带来高昂的售价以及后期的运维代价,对于超大型的客户来说也难以承担如此高的成本。对于钉钉自身来说,从研发到后续运维,维护一套独立体系也难以在客户侧大面积推广。

11、单元化架构3.0版:混合云架构

11.1概述

钉钉单元化经过四年的发展,在容灾和容量上做出一定的积淀,同时完成了一些核心技术的积累。

当整体架构成熟之后,我们也在思考,单元化能否从技术架构升级为业务架构,比如搭建独立的高可用单元,按照售卖的SLA提供给VIP客户,支持钉钉商业化的发展。

同时我们在云原生逐步发力,将部分核心应用放到云上,经过这一年多的运行,遇到了新的挑战,但更获得云下无法获得的计算弹性能力,云上的弹性对云下是一个降维打击,从一个新的方向解决计算问题。

如上文提到的两个核心挑战,钉钉单元化同样面临这个问题,在持续的发展中找到了一个合适的架构方向。

基本思路是:

  • 1)云下作为基本盘,保障核心流量的问题,毕竟云下经过集团多年的打磨,不管是稳定性还是流程的合理性都有保障;
  • 2)云上应对高涨异常的流量,比如和疫情正相关的教育流量,既保证了服务的稳定性,又能充分利用云上弹性能力,在提供完整能力的前提下做到一个相对较低的成本。

其次是升级Geo概念:

  • 1)将Geo作为一个独立的业务域,实现Geo级别完全独立部署,分布式云模式;
  • 2)同时Geo之间按需互通,从研发体系上能做到一套代码。

因此,钉钉单元化来到了3.0版本,我们称之为钉钉单元化混合云架构。

混合云主要是从两个维度来看:

  • 第一:是云上云下,我们认为云上云下并不是取代的关系,而是相互补充的关系,是一个长期的状态,正如很多大客户随着规模的持续扩张,最终依赖的部分核心能力必然走向自研道理一样,这能做成本的进一步降低,所以架构是一个混合云架构;
  • 第二:业务架构上也是混合云架构,通过不同的Geo,将不同的业务逻辑上聚合到一起,构建起一张钉钉的大网,不同Geo按需互通,实现了业务架构的混合。

3.0从系统架构上相对于2.0,最大的区别就是云原生技术的运用和互通网关的建立。

11.2云原生技术 :抵抗系统架构熵增的有效手段

近几年,互联网圈最火的技术莫过于以Docker为代表的云原生技术最为火热,各大云厂商也都在不遗余力的推广云原生技术以及对应的产品。同时钉钉服务过亿DAU的客户,面对各种可靠性、服务连续性、并发、容灾等技术挑战,也都走到了现有技术的边界。

所以我们也在不断吸收新的技术和架构,希望从体系与架构上降低我们的技术复杂度,以抵抗熵增。

我们在2021年底启动了云原生升级战略,升级云原生技术并不是为了技术而升级,而是切实面临巨大的技术挑战。

1)首先我们面临多语言的挑战:

我们以IM为例,IM的核心逻辑都是使用C++构建,但是我们常用的中间件三大件:存储、缓存、异步队列,其中缓存和异步队列在C++客户端上长期建设不足,导致IM长期在使用低版本。

低版本由于长时间缺乏维护,经常会出现异常,比如队列假死、消费不均等,导致我们自己不得不亲自上阵修改SDK的代码,以致最后难以使用到产品的新能力,阻碍IM服务能力的提升。

2)其次是多产品多云的挑战:

我们以阿里云为例,数据库类目下的产品,从类别上就有关系数据库、NoSQL数据库、数仓等等,还有存储也是一样。

对于我们上层业务,其实绝大部分服务都只依赖了底层的CURD,这么多产品,每次对接一个产品都要开发一轮。

配置系统也是一样,弹内有Diamond,云上有Nacos、Mse,K8s有自己的Configmap等,而且这些配置系统不像数据库有标准,而是百花齐放,但是这样却苦了我们使用者。

这些内容不是我们的核心路径,浪费大把时间在各种产品接口的适配上,明显拖累了钉钉的发展。

3)最后就是通用的流量治理挑战:

钉钉很多系统都是最终一致的系统,IM就是典型的最终一致系统,这类系统和强同步系统在架构设计有一个明显的区别,强一致系统如果遇到失败,必须要持续重试直到成功,所以一般编程上都是重试+退避。

但是最终一致系统不是,这类系统允许部分节点失败,不要阻碍其他流程,失败的流量通过一个异步回旋的队列,将数据逐步回放回来即可。这种回旋需要借助异步队列,而且要设计各种消费机制,比如限速、比如丢弃等等,这是一个通用的逻辑,但是每个业务方或多或少都在实现自己的回旋系统,重复的造轮子。又比如各种故障注入,单元化路由流量等等,要想拥有这个能力,团队不得不投入人力研发。

在对付架构复杂度上,我们主要从两个维度来屏蔽复杂度。

首先代码层面我们选择了DDD模式,我们使用DDD分层核心是把对外系统的依赖全部收拢到Infrastructure这一层,全部采用纯虚函数(Interface)对外提供接口。屏蔽底层中间件差异和细节。

在架构上采用Sidecar的模式,类似于Dapr的思想,通过标准的GRPC和PB实现应用与中间件解耦。Sidecar中集成了各种中间件、配置系统、灰度系统等,等价实现了应用和中间件的解耦。上文中提到的不管是多语言挑战、多云多产品的挑战、重复造轮子等问题,都能很好的解决。

11.3互通网关 :混合架构的基石

云上云下互通,或者说多个云账户VPC之间的互通,我们常见的有两种方案:

  • 1)其一是VPC直接打通,让多个VPC之间形成一个大的局域网,RealServer实现点对点互通;
  • 2)其一是中间搭建一个负载均衡器,通过暴露EIP实现互通。

两个方案都有自己的优缺点。

对于方案一:打通的VPC涉及到IP规划,如果前期没有合理规划,后续很难打通;还有这种方案有水桶短板安全问题,一旦一个VPC被攻破,这张网也被攻破;但是对于内部的应用来说架构就比较简单,可以仅仅借助K8s DNS service就能做到服务发现。

对于方案二:最大的缺点就是中间有一个集中式的负载均衡,需要申请独立的LB才可访问;但是这种方案隔离性好。

对于钉钉单元化来说,涉及N个业务方,N * M个应用,对应X个VPC,要想VPC之间打通,几乎没有可能性,而且VPC打通,还面临应用之间的安全性问题。要实现Geo之间互通,环境之间的隔离性是基本要求,与此同时,我们也要考虑到系统的可扩展性,所以我们必须要构建一套独立的流量网关,实现流量加密、寻址、转发等通用能力。

钉钉互通网关是构建在Envoy之上的系统,双向Ingress和Egress,支持GRPC和钉钉自研协议。具备流量管理、传输加密、单元寻址等能力。钉钉单元化借助互通网关的能力,再配合全局流控系统,我们可以在多单元之间实现精确的流量控制和调度。

12、写在最后

伴随着专属集群的持续输出,客户对专属的场景需求会越来越多,需要我们投入更多的人力持续的建设。

比如:

  • 1)在架构侧:首先是Sidecar持续强化,支持更多的中间件和环境,提供不同维度的安全能力,满足客户和应用的安全需求;
  • 2)在运维侧:我们需要构建多Geo管理能力,完善Geo和单元之间流量快速调度能力,提供自动化的自检系统等;
  • 3)在交付侧:如果实现快速交付,比如是否能做到新应用一周完成单元化改造,新Geo一天部署完成。这些挑战都是接下来我们要重点投入的方向。

对于标准钉钉来说,这个是我们的基本盘,一个稳定可靠且低成本的钉钉是我们持之以恒的目标,接下来我们会加大云上流量的占比,充分的借助云上弹性能力,实现可控的成本。

今天我们只是站在钉钉的角度上抛了一个“砖”,希望在异地多活这个领域激起一层浪花,欢迎大家一起讨论。

13、相关资料

[1] 现代IM系统中聊天消息的同步和存储方案探讨

[2] 企业级IM王者——钉钉在后端架构上的过人之处

[3] 深度解密钉钉即时消息服务DTIM的技术设计

[4] 钉钉——基于IM技术的新一代企业OA平台的技术挑战(视频+PPT)

[5] 企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等

[6] IM系统的MQ消息中间件选型:Kafka还是RabbitMQ?

[7] 深度揭密RocketMQ在钉钉IM系统中的应用实践

(本文同步发布于:http://www.52im.net/thread-4122-1-1.html

posted @ 2023-02-13 10:50 Jack Jiang 阅读(66) | 评论 (0)编辑 收藏

一、更新内容简介

本次更新为次要版本更新,进行了若干优化(更新历史详见:码云 Release Nodes)。可能是市面上唯一同时支持 UDP+TCP+WebSocket 三种协议的同类开源IM框架。

二、MobileIMSDK简介

MobileIMSDK 是一套专为移动端开发的原创IM通信层框架:

  • 历经8年、久经考验;
  • 超轻量级、高度提炼,lib包50KB以内;
  • 精心封装,一套API同时支持UDP、TCP、WebSocket三种协议(可能是全网唯一开源的);
  • 客户端支持 iOSAndroid标准JavaH5小程序(开发中..)、Uniapp(开发中..);
  • 服务端基于Netty,性能卓越、易于扩展;👈
  • 可与姊妹工程 MobileIMSDK-Web 无缝互通实现网页端聊天或推送等;👈
  • 可应用于跨设备、跨网络的聊天APP、企业OA、消息推送等各种场景。

MobileIMSDK工程始于2013年10月,起初用作某产品的即时通讯底层实现,完全从零开发,技术自主可控!

您可能需要:查看关于MobileIMSDK的详细介绍

三、代码托管同步更新

OsChina.net

GitHub.com

四、MobileIMSDK设计目标

让开发者专注于应用逻辑的开发,底层复杂的即时通讯算法交由SDK开发人员,从而解偶即时通讯应用开发的复杂性。

五、MobileIMSDK框架组成

整套MobileIMSDK框架由以下5部分组成:

  1. Android客户端SDK:用于Android版即时通讯客户端,支持Android 2.3及以上,查看API文档
  2. iOS客户端SDK:用于开发iOS版即时通讯客户端,支持iOS 8.0及以上,查看API文档
  3. Java客户端SDK:用于开发跨平台的PC端即时通讯客户端,支持Java 1.6及以上,查看API文档
  4. H5客户端SDK:暂无开源版,查看精编注释版
  5. 服务端SDK:用于开发即时通讯服务端,支持Java 1.7及以上版本,查看API文档

整套MobileIMSDK框架的架构组成:

 另外:MobileIMSDK可与姊妹工程 MobileIMSDK-Web 无缝互通,从而实现Web网页端聊天或推送等。

六、MobileIMSDK v6.3更新内容 

【重要说明】:

MobileIMSDK v6.3 为次要版本,进行了若干优化! 查看详情

【新增的特性】:

  • 1. [所有端] 提供了灵活的接口供开发者定制和开启SSL/TLS加密传输;

【其它优化和提升】:

  • 1. [iOS] 解决了iOS端Demo在iOS16下的适配问题;
  • 2. [iOS] 解决了iOS端Demo在黑暗模式下背景和标题栏是黑色的问题;
  • 3. [Android] 优化了Android端Demo在最新Android系统下的适配等;
  • 4. [Android/Java] 对全局单例增加线程安全处理,防止在高版本JDK中出现并发调用而导致单例被重复实例化。

【版本地址】:

https://gitee.com/jackjiang/MobileIMSDK/releases/tag/6.3

posted @ 2023-02-07 10:27 Jack Jiang 阅读(48) | 评论 (0)编辑 收藏

     摘要: 本文引用了“鲜枣课堂”的《史上最强5G科普》文章内容。为了更好的内容呈现,在引用和收录时内容有改动,转载时请注明原文来源。1、内容概述➊ 5G技术的关注度越来越高:在此之前,5G技术对于普通老百姓来说,似乎还很遥远,关注度并不高。但从去年开始,美帝赤裸裸打压中兴和华为的国际事件,让5G技术在国内有了很高的关注度。美帝打压中兴、华为固然是坏事,但因为这个事情,相当于反过来为5...  阅读全文

posted @ 2023-02-04 16:21 Jack Jiang 阅读(59) | 评论 (0)编辑 收藏

     摘要: 本文由金蝶随手记技术团队丁同舟分享。1、引言跟移动端IM中追求数据传输效率、网络流量消耗等需求一样,随手记客户端与服务端交互的过程中,对部分数据的传输大小和效率也有较高的要求,普通的数据格式如 JSON 或者 XML 已经不能满足,因此决定采用 Google 推出的 Protocol Buffers 以达到数据高效传输。本文将基于随手记团队的Protobuf应用实践,分享了Protobuf的技术原...  阅读全文

posted @ 2023-01-28 16:57 Jack Jiang 阅读(73) | 评论 (0)编辑 收藏

     摘要: 1、前言Protobuf是Google开源的一种混合语言数据标准,已被各种互联网项目大量使用。Protobuf最大的特点是数据格式拥有极高的压缩比,这在移动互联时代是极具价值的(因为移动网络流量到目前为止仍然昂贵的),如果你的APP能比竞品更省流量,无疑这也将成为您产品的亮点之一。现在,尤其IM、消息推送这类应用中,Protobuf的应用更是非常广泛,基于它的优秀表现,微信和手机QQ这样的主流IM...  阅读全文

posted @ 2023-01-05 16:14 Jack Jiang 阅读(122) | 评论 (0)编辑 收藏

本文由钉钉技术专家尹启绣分享,有修订和重新排版。

1、引言

短短的几年时间,钉钉便迅速成为一款国民级应用,发展速度堪称迅猛。

IM作为钉钉最核心的功能,每天需要支持海量企业用户的沟通,同时还通过 PaaS 形式为淘宝、高德等 App 提供基础的即时通讯能力,是日均千亿级消息量的 IM 平台。

在钉钉的IM中,我们通过 RocketMQ实现了系统解耦、异步削峰填谷,还通过定时消息实现分布式定时任务等高级特性。同时与 RocketMQ 深入共创,不断优化解决了很多RocketMQ本身的问题,并且孵化出 POP 消费模式等新特性,使 RocketMQ 能够完美支持对性能稳定性和时延要求非常高的 IM 系统。本文将为你分享这些内容。

学习交流:

本文已同步发布于:http://www.52im.net/thread-4106-1-1.html

2、系列文章

本文是系列文章的第9篇,总目录如下:

3、钉钉IM面临的巨大技术挑战

3.1 概述

钉钉作为企业级 IM 领先者,面临着巨大的技术挑战。市面上DAU过亿的App里,只有钉钉是2B产品,我们不仅需要和其他 2C 产品一样,支持海量用户的低时延、高并发、高性能、高可用,还需保证企业级用户在使用钉钉时能够提升沟通协同效率。

下图是概括的是钉钉的主要能力:

3.2 技术挑战1:ToB与ToC的差异

作为企业级应用,需要保证帮助用户提升沟通体验。

ToB 的工作沟通和 ToC 的场景生活沟通存在较大差异, ToC的IM产品比如微信,在有完整的关系链后,只需满足大部分用户需求即可。

然而微信的很多体验其实并不友好:比如聊天消息中的视频图片在固定时间内没有打开则会无法下载,卸载重装之后聊天记录全部丢失。

而 ToB 场景下:聊天记录是非常重要的内容,钉钉为保证用户消息不丢失,提供了多端同步和消息云端存储的能力,用户任意换端都能查看完整的聊天记录。

在工作过程中,大量会议是工作效率杀手,钉钉还提供了已读、Ding 等效率套件,为工作沟通提供新选项。

3.3 技术挑战2:安全要求高

在ToB 的工作场景下,用户对信息安全要求非常高,信息安全是企业的生命线。

钉钉提供了人和组织架构打通的工作群,用户离开组织后自动退出企业工作群,这样就很好地保障了企业信息的安全。

同时,在已经支持的全链路加密能力上提供了三方加密能力,可以最大程度保障企业用户的信息安全性。

3.4 技术挑战3:稳定性要求高

企业用户对稳定性的要求也非常高,如果钉钉出现故障,深度使用钉钉的企业都会受到巨大影响。

因此,钉钉 IM 系统在稳定性上也做了非常深入的建设,架构上对依赖和流量做了深入治理,核心能力所有依赖都为双倍。

比如虽然 RocketMQ 已经非常稳定,也没有发生过故障,但是对 RocketMQ 可能出现故障的产品依然做了很好的保护,使用 RocketMQ 定时消息和堆积能力做热点治理和流量防护,让系统面对大规模流量时能从容应对,并且建设了异地多活和可弹性扩缩容能力,疫情期间很好地保证了学生们的在线课堂。

在稳定性机制上,常态化容灾演练、突袭演练、自动化健康巡检等也能很好地保证线上稳定性。比如波浪式流量就是在做断网演练时发现。

3.5 技术挑战4:业务多样性

针对不同行业的业务多样性,还要尽可能地满足用户的通用性需求,比如万人群、全员群等,目前钉钉已经做到能够支持 10 万人级别的群。

更多的业务需求将依赖于我们抽象出的通用开放能力,将 IM 能力尽可能地开放给企业和三方 ISV,使得不同形态的业务都能在钉钉平台上得到满足 。

4、消息队列在钉钉IM系统中的重要作用

4.1 概述

在如此丰富的企业级能力下,钉钉IM要与微信等 ToC 产品一样,支持亿级用户低时延沟通,系统架构需要具备高并发、高性能、高可用的能力,挑战非常之大。

IM 本身是异步化沟通系统,与开会或者电话沟通相比,让沟通双方异步处理消息能够减少打断次数,提升沟通效率。这种异步的特性和消息队列的能力很契合,消息队列可以很好地帮助 IM 完成异步化解耦、失败重试、削峰填谷等能力。

这里,我们以钉钉IM系统最核心的发消息和已读链路简化流程(如下图所示),来详细说明消息队列在系统里的重要作用。

 

4.2 发消息链路

钉钉IM系统的发消息链路流程如下:

  • 1)处于登录状态的钉钉用户发送一条消息时,首先会将请求发送到 receiver 应用;
  • 2)为保证发消息体验和成功率,receiver 应用只做这条消息能否发送的校验,其他如消息入库、接收者推送等都交由下游应用完成;
  • 3)校验完成之后将消息投递给消息队列,成功后即可返回给用户;
  • 4)消息发送成功,processor 会从消息队列里订阅到这条消息,并对消息进行入库处理,再通过消息队列将消息交给同步服务 syncserver 做处理,将消息同步给在线接收者。

上述过程中,对于不在线的用户:可以通过消息队列将消息推给离线 push 系统。离线 push 系统可以对接接苹果、华为、小米等推送系统进行离线推送。

用户发消息过程中的每一步,失败后都可通过消息队列进行重试处理。如 processor 入库失败,可将消息打回消息队列,继续回旋处理,达到最终一致。同时,可以在订阅的过程中对消费限速,避免线上突发峰值给系统带来灾难性的后果。

4.3 消息已读链路

钉钉IM系统的消息已读链路流程如下:

  • 1)用户对一条消息做读操作后,会发送请求到已读服务;
  • 2)已读服务收到请求后,直接将请求放到消息队列进行异步处理,同时可以达到削峰填谷的目的;
  • 3)已读服务处理完之后,将已读事件推给同步服务,让同步服务将已读事件推送给消息发送者。

从上面两个链路可以看出,消息队列是 IM 系统里非常重要的组成部分。

5、钉钉IM选择RocketMQ的原因

阿里内部曾有 notify、RocketMQ 两套应用消息中间件,也有其他基于 MQTT 协议实现的消息队列,最终都被 RocketMQ 统一。

IM 系统对消息队列有如下几个基本要求:

  • 1)解耦和削峰填谷(这是消息队列的基础能力);
  • 2)高性能、低时延;
  • 3)高可用性。

对于第 3)点:要求消息队列的高可用性方面不仅包括系统可用性,也包括数据可用性,要求写入消息队列时消息不丢失(钉钉 IM 对消息的保证级别是一条都不丢)。

RocketMQ 经过多次双 11 考验,其堆积性能、低时延、高可用已成为业届标杆,完全符合对消息队列的要求。

同时它的其他特性也非常丰富,如定时消息、事务消息,能够以极低的成本实现分布式定时任务,消息可重放和死信队列提供了后悔药的能力,比如线上系统出现 bug ,很多消息没有正确处理,可以通过重置位点、重新消费的方式,订正之前的错误处理。

另外:消息队列的使用场景非常丰富,RocketMQ 的扩展能力可以在消息发送和消费上做切面处理,实现通用性的扩展封装,大大降低开发工作量。 Tag & SQL 过滤能让下游针对性地订阅定业务需要的消息,无需订阅整个 topic 里的所有消息,大幅降低下游系统的订阅压力。

RocketMQ 至今从未发生故障,集群峰值 TPS 可达 300w/s,从生产到消费时延能够保证在 10 ms 以内,支持 30 亿条消息堆积,核心指标数据表现抢眼,性能异常优秀。

6、RocketMQ的消息必达3重保险

如上图所示,发消息流程中,很重要的一步是 receiver 应用做完消息能否发送的校验之后,通过 RocketMQ 将消息投递给 processor做消息入库处理。

投递过程中,将提供三重保险,以保证消息发送万无一失。

第一重保险:receiver 将消息写进 RocketMQ 时, RocketMQ SDK 默认会重试五次(每次尝试不同的 broker ,保障了消息写失败的概率非常小)。

第二重保险:写入 RocketMQ 失败的情况下,会尝试以 RPC 形式将消息投递给 processor 。

第三重保险:如果 RPC 形式也失败,会尝试将本地 redoLog 通过 Crontab 任务定时将消息回放到 RocketMQ 里面。

此外,如何在系统异常的情况下做到消息最终一致?

Processor 收到上游投递的消息时,会尝试对消息做入库处理。即使入库失败,依然会将消息投给同步服务,将消息下发,保证实时消息收发正常。异常情况时会将消息重新投递到异常 topic 进行重试,投递过程中通过设置RocketMQ 定时消息做退避处理,对异常 topic 做限速消费。

重试写不同的 topic 是为了与正常流量隔离,优先处理正常流量,防止因为异常流量消费而导致真正的线上消息处理被延迟。

另外:Rocket MQ 的一个 broker 默认只有一个 Retry 消息队列,如果消费失败量特别大的情况下,会导致下游负载不均,某些机器打死。

此外:如果系统持续发生异常,则会不断地进行回旋重试,如果不做限速处理,线上容易出现流量叠加,导致整个系统雪崩。

7、RocketMQ的独门绝技——分布式定时任务

在几千人的群里发一条消息,假设有 1/4 的成员同时开着聊天窗口,如果不对服务端已读服务和客户端需要更新的已读数做合并处理,更新的 QPS 会高达到 1000/s。钉钉能够支持十几万人的超大群,超大群的活跃对服务端和客户端都会带来很大冲击,而实际上用户的需求只需实现秒级更新。

针对以上场景:可以利用 RocketMQ 的定时消息能力实现分布式定时任务。

以已读流程为例(如下图所示),用户发起请求时,会将请求放入集中式请求队列,再通过 RocketMQ 定时消息生成定时任务,比如 5 秒后批量处理。5秒之后,RocketMQ 订阅到任务触发消息,将队列里面所有请求都取出处理。

▲ 用 RocketMQ 实现分布式定时任务的流程原理

我们抽象了一个分布式定时任务的组件,提供了很多其他实时性可达秒级的功能,如万人群的群状态更新、消息扩展更新都接入了此组件。通过组件的定时合并处理,大幅降低系统压力。

如上图(右边部分),在一些大群活跃的时间点成功地让流量下降并保持平稳状态。

8、钉钉IM使用RocketMQ遇到的技术问题

8.1 概述

RocketMQ 的生产端策略如下:

  • 1)生产者获取到对应 topic 所有 broker 和 Queue 列表,然后轮询写入消息;
  • 2)消费者端也会获取到 topic 所有 broker 和Queue列表;
  • 3)还需要要从 broker 中获取所有消费者 IP 列表进行排序(按照配置负载均衡,如哈希、一次性哈希等策略计算出自己应该订阅哪些 Queue)。

上图中:ConsumerGroupA的Consumer1被分配到MessageQueue0和MessageQueue1,则它订阅MessageQueue0和MessageQueue1。

在RocketMQ的使用过程中,我们面临了诸多问题,下面我们来逐一分享。

8.2 问题1:波浪式流量

我们发现订阅消息集群滚动时,CPU 呈现波浪式飙升。

经过深入排查发现,断网演练后进行网络恢复时,大量 producer 同时恢复工作,同时从第一个 broker 的第一个 Queue 开始写入消息,生产消息波浪式写入 RocketMQ ,进而导致消费者端出现波浪式流量。

最终,我们联系 RocketMQ 开发人员,调整了生产策略,每次生产者发现 broker 数量或状态发生变化时,都会随机选取一个初始Queue写入消息,以此解决问题。

另一个导致波浪式流量的问题是配置问题。

排查线上问题时,从 broker 视角看,每个 broker 的消息量都是平均的,但 consumer 之间流量相差特别大。最终通过在 producer 侧尝试抓包得以定位到问题,是由于 producer 写入消息时超时率偏高。

梳理配置后发现,是由于 producer 写入消息时配置超时太短,Rocket MQ 在写消息时会尝试多次,比如第一个 broker 写入失败后,将直接跳到下一个 broker 的第一个 Queue ,导致每个 broker 的第一个 Queue 消息量特别大,而靠后的 partition 几乎没有消息。

8.3 问题2:负载均衡维度太粗

负载均衡只能到Queue维度,导致需要不时地关注 Queue 数量。

比如线上流量增长过快,需要进行扩容,而扩容后发现机器数大于 Queue 数量,导致无论怎么扩容都无法分担线上流量,最终只能联系 RocketMQ 运维人员调高 Queue 数量来解决。

虽然调高 Queue 数量能解决机器无法订阅的问题,但因为负载均衡策略只到 Queue 维度,负载始终无法均衡。从下图可以看到, consumer 1 订阅了两个 Queue 而 consumer 2 只订阅了一个 Queue。

8.4 问题3:单机夯死导致消息堆积

单机夯死导致消息堆积,这也是负载均衡只能到 Queue 维度带来的副作用。

比如 Broker A 的 Queue 由 consumer 1 订阅,出现宿主机磁盘 IO 夯死但与 broker 之间的心跳依然正常,导致 Queue 消息长时间无法订阅进而影响用户接收消息。最终只能通过手动介入将对应机器下线来解决。

8.5 问题4:rebalance

Rocket MQ 的负载均衡由 client 自己计算,导致有机器异常或发布时,整个集群状态不稳定,时常会出现某些 Queue 有多个 consumer 订阅,而某些 Queue 在几十秒内没有 consumer 订阅的情况。

因而导致线上发布的时候,出现消息乱序或对方已回消息但显示未读的情况。

8.6 问题5:C++ SDK 能力缺失

钉钉IM的核心处理模块Receiver、processor 等应用都是通过 C++ 实现,而RocketMQ 的 C++ SDK 相比于 Java 存在较大缺失。经常出现内存泄漏或 CPU 飙高的情况,严重影响线上服务的稳定。

9、钉钉IM与RocketMQ的相互促进

面对以上困扰,在经过过多次讨论和共创后,最终孵化出 RocketMQ 5.0 POP 消费模式。

这是 RocketMQ 在实时系统里程碑式的升级,解决了大量实时系统使用 RocketMQ 过程中遇到的问题(如下图所示)。

1)Pop消费模式下,每一个 consumer 都会与所有 broker 建立长连接并具备消费能力,以 broker 维护整个消息订阅的负载均衡和位点。重云轻端的模式下,负载均衡、订阅消息、位点维护都在客户端完成,而新客户端只需做长链接管理、消息接收,并且通用 gRPC 协议,使得多语言比如 C++、Go、 Python 等语言客户端都能轻松实现,无需持续投入力去升级维护 SDK 。

2)broker能力升级更简单。重云轻端很好地解决了客户端版本升级问题,客户端改动的可能性和频率大大降低。以往升级新特性或能力只能推动所有相关 SDK 应用进行升级发布,升级过程中还需考虑新老兼容等问题,工作量极大。而新模式只需升级 broker 即可完成工作。

3)单机夯死消息能继续被消费。新模式下 consumer 和 broker 进行网状连接和消息订阅,由 broker 通过负载均衡策略平均分配消息给 consumer 进行消费,以往宕机夯死导致的 Queue 消息堆积问题也迎刃而解。如果 broker 发现 consumer 长时间没有进行消息 ACK ,则将不再对其投递消息,彻底解决单机夯死问题。

4)无需关注partition数量。

5)彻底解决rebalance。

6)负载更均衡。通过新的订阅模式,不管上游流量如何偏移,只要不超过单个 broker 的容量上限,消费端都能实现真正意义上的负载均衡。

POP 模式消费模式已经在钉钉 IM 场景磨合得非常成熟,在对可用性、性能、时延方面要求非常高的钉钉 IM 系统证明了自己,也证明了不断升级的 RocketMQ 是即时通讯场景消息队列的不二选择。

10、相关资料

[1] 现代IM系统中聊天消息的同步和存储方案探讨

[2] 企业级IM王者——钉钉在后端架构上的过人之处

[3] 深度解密钉钉即时消息服务DTIM的技术设计

[4] 钉钉——基于IM技术的新一代企业OA平台的技术挑战(视频+PPT)

[5] 企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等

[6] IM系统的MQ消息中间件选型:Kafka还是RabbitMQ?

本文已同步发布于:http://www.52im.net/thread-4106-1-1.html

posted @ 2022-12-30 12:05 Jack Jiang 阅读(90) | 评论 (0)编辑 收藏

1、引言

在社区中,分享了很多篇基于Netty编写的IM聊天入门文章(比如《跟着源码学IM》系列、《基于Netty,从零开发IM》系列等),在这些文章中分享了各种IM通信算法原理和功能逻辑的实现。但是这样简单的IM聊天系统是比较容易被窃听的,如果想要在里面说点悄悄话是不太安全的。

怎么办呢?学过密码学的朋友可能就想到了一个解决办法,聊天的时候对消息加密,处理的时候再对消息进行解密。是的,道理就是这样。

但密码学本身的理论就很复杂,加上相关的知识和概念又太多太杂,对于IM入门者来说,想要快速理清这些概念并实现合适的加解密方案,是比较头疼的。

本文正好借此机会,以Netty编写的IM聊天加密为例,为入门者理清什么是PKI体系、什么是SSL、什么是OpenSSL、以及各类证书和它们间的关系等,并在文末附上简短的Netty代码实示例,希望能助你通俗易懂地快速理解这些知识和概念!

补充说明:本文为了让文章内容尽可能言简意赅、通俗易懂,尽量不深入探讨各个技术知识和概念,感兴趣的读者可以自行查阅相关资料进一步学习。

学习交流:

本文已同步发布于:http://www.52im.net/thread-4104-1-1.html

2、相关文章

  1. 即时通讯安全篇(一):正确地理解和使用Android端加密算法
  2. 即时通讯安全篇(二):探讨组合加密算法在IM中的应用
  3. 即时通讯安全篇(三):常用加解密算法与通讯安全讲解
  4. 即时通讯安全篇(四):实例分析Android中密钥硬编码的风险
  5. 即时通讯安全篇(五):对称加密技术在Android平台上的应用实践
  6. 即时通讯安全篇(六):非对称加密技术的原理与应用实践
  7. 即时通讯安全篇(十):IM聊天系统安全手段之通信连接层加密技术
  8. 即时通讯安全篇(十一):IM聊天系统安全手段之传输内容端到端加密技术

3、什么是PKI?

我们需要先了解一下公钥和私钥的加密标准体系PKI。

3.1 基本概念

PKI的全称是Public Key Infrastructure,是指支持公钥管理体制的基础设施,提供鉴别、加密、完整性和不可否认性服务。

通俗讲:PKI是集机构、系统(硬件和软件)、人员、程序、策略和协议为一体,利用公钥概念和技术来实现和提供安全服务的、普适性的安全基础设施。

在公钥密码中,发送者用公钥(加密密钥)加密,接收者用私钥(解密密钥)解密。公钥一般是公开的,不再担心窃听,这解决了对称密码中的密钥配送问题。但是接收者依然无法判断收到的公钥是否合法(有可能是中间人假冒的)。

事实上,仅靠公钥密码本身,无法防御中间人攻击。于是,需要(认证机构)对公钥进行签名,从而确认公钥没有被篡改。加了数字签名的公钥称为公钥证书,一般简称证书。

有了证书来认证,可以有效防御中间人攻击,随之带来了一系列非技术性工作。

例如:谁来发证书?如何发证书?不同机构的证书怎么互认?纸质证书作废容易,数字证书如何作废?解决这些问题,需要制定统一的规则,即PKI体系。

PKI体系是通过颁发、管理公钥证书的方式为终端用户提供服务的系统,最核心的元素是证书。

围绕证书构成了PKI体系的要素:

  • 1)使用PKI的用户;
  • 2)颁发证书的机构(Certificate Authority,CA);
  • 3)保存证书的仓库。

总之:PKI是一个总称,既包括定义PKI的基础标准,也包括PKI的应用标准。

3.2 PKI体系现状

事实上PKI已经有两代了。

第一代的PKI标准主要是由美国RSA公司的公钥加密标准PKCS、国际电信联盟的ITU-T X.509、IETF的X.509、WAP和WPKI等标准组成。但是因为第一代PKI标准是基于抽象语法符号ASN.1进行编码的,实现起来比较复杂和困难,所以产生了第二代PKI标准。

第二代PKI标准是由微软、VeriSign和webMethods三家公司在2001年发布的基于XML的密钥管理规范也叫做XKMS。

事实上现在CA中心使用的最普遍的规范还是X.509系列和PKCS系列。

X.509系列主要由X.209、X.500和X.509组成,其中X.509是由国际电信联盟(ITU-T)制定的数字证书标准。在X.500基础上进行了功能增强,X.509是在1988年发布的。

X.509证书由用户公共密钥和用户标识符组成。此外还包括版本号、证书序列号、CA标识符、签名算法标识、签发者名称、证书有效期等信息。

而PKCS是美国RSA公司的公钥加密标准,包括了证书申请、证书更新、证书作废表发布、扩展证书内容以及数字签名、数字信封的格式等方面的一系列相关协议。它定义了一系列从PKCS#1到PKCS#15的标准。

其中最常用的是PKCS#7、PKCS#12和PKCS#10。PKCS#7 是消息请求语法,常用于数字签名与加密,PKCS#12是个人消息交换与打包语法主要用来生成公钥和私钥(题外话:iOS程序员对PKCS#12不陌生,在实现APNs离线消推送时就需要导出.p12证明,正是这个)。PKCS#10是证书请求语法。

4、什么是SSL?

4.1 基本概念

SSL(全称 Secure Socket Layer)安全套接层是网景公司(Netscape)率先采用的网络安全协议。它是在传输通信协议(TCP/IP)上实现的一种安全协议,采用公开密钥技术。

通俗地说:SSL被设计成使用TCP来提供一种可靠的端到端的安全服务,它不是单个协议,而是二层协议。低层是SSL记录层,用于封装不同的上层协议,另一层是被封装的协议,即SSL握手协议,它可以让服务器和客户机在传输应用数据之前,协商加密算法和加密密钥,客户机提出自己能够支持的全部加密算法,服务器选择最适合它的算法。

SSL特点是:它与应用层协议独立无关。上层的应用层协议(例如:HTTP、FTP、Telnet等)能透明的建立于SSL协议之上。SSL协议在应用层协议通信之前就已经完成加密算法、通信密钥的协商以及服务器认证工作。在此之后应用层协议所传送的数据都会被加密,从而保证通信的私密性。

4.2 与TLS的关系

SSL是网景公司(Netscape)设计,但IETF将SSL作了标准化,即RFC2246,并将其称为TLS(Transport Layer Security),其最新版本是RFC5246、版本1.2。

实际上:TLS是IETF在SSL3.0基础上设计的,相当于SSL的后续版本。所以我们通常都是SSL/TLS放一起说。

5、什么是OpenSSL?

5.1 基本概念

 

OpenSSL是一个开放源代码的软件库,应用程序可以使用这个包来进行安全通信,它包括代码、脚本、配置和过程的集合。例如:如果您正在编写一个需要复杂安全加密的软件,那么只有添加一个安全加密库才有意义,这样您就不必自己编写一大堆复杂的加解密函数(而且密码学本身很复杂,要写好它们并不容易)。

其主要库是以 C 语言所写成,实现了基本的加密功能,实现了 SSL 与 TLS 协议。

OpenSSL整个软件包大概可以分成三个主要功能部分:

  • 1)SSL协议库;
  • 2)应用程序;
  • 3)密码算法库。

OpenSSL的目录结构自然也是围绕这三个功能部分进行规划的。

OpenSSL 可以运行在 OpenVMS、 Microsoft Windows 以及绝大多数类 Unix 操作系统上。

5.2 具体来说

密钥和证书管理是PKI的一个重要组成部分,OpenSSL为之提供了丰富的功能,支持多种标准。

OpenSSL实现了ASN.1的证书和密钥相关标准,提供了对证书、公钥、私钥、证书请求以及CRL等数据对象的DER、PEM和BASE64的编解码功能。

OpenSSL提供了产生各种公开密钥对和对称密钥的方法、函数和应用程序,同时提供了对公钥和私钥的DER编解码功能。并实现了私钥的PKCS#12和PKCS#8的编解码功能。

OpenSSL在标准中提供了对私钥的加密保护功能,使得密钥可以安全地进行存储和分发。

在此基础上,OpenSSL实现了对证书的X.509标准编解码、PKCS#12格式的编解码以及PKCS#7的编解码功能。并提供了一种文本数据库,支持证书的管理功能,包括证书密钥产生、请求产生、证书签发、吊销和验证等功能。

5.3 发展历程

OpenSSL 计划在 1998 年开始,其目标是发明一套自由的加密工具,在互联网上使用。

OpenSSL 以 Eric Young 以及 Tim Hudson 两人开发的 SSLeay 为基础,随着两人前往 RSA 公司任职,SSLeay 在 1998 年 12 月停止开发。因此在 1998 年 12 月,社群另外分支出 OpenSSL,继续开发下去。

▲ 上图为 Tim Hudson

OpenSSL 管理委员会当前由 7 人组成有 13 个开发人员具有提交权限(其中许多人也是 OpenSSL 管理委员会的一部分)。只有两名全职员工(研究员),其余的是志愿者。

该项目每年的预算不到 100 万美元,主要依靠捐款。 TLS 1.3 的开发由 Akamai 赞助。

5.4 下载方法

OpenSSL可以从其官网上下载,地址是:https://www.openssl.org/source/,感兴趣的读者可以自行下载安装研究。

6、各类证书

6.1 证书类型

操作过证书的朋友可能会对各种证书类型眼花缭乱,典型的体现就是各种不同的证书扩展名上,一般来说会有DER、CRT、CER、PEM这几种证书的扩展名。

以下是最常见的几种:

  • 1)DER文件:表示证书的内容是用二进制进行编码的;
  • 2)PEM文件:是一个文本文件,其内容是以“ - BEGIN -” 开头的,Base64编码的字符;
  • 3)CRT和CER文件:基本上是等价的,他们都是证书的扩展,也是文本文件,不同的是CRT通常用在liunx和unix系统中,而CER通常用在windows系统中。并且在windows系统中,CER文件会被MS cryptoAPI命令识别,可以直接显示导入和/或查看证书内容的对话框;
  • 4)KEY文件:主要用来保存PKCS#8标准的公钥和私钥。

6.2 常用OpenSSL命令

下面的命令可以用来查看文本证书内容:

openssl x509 -incert.pem -text -noout

openssl x509 -incert.cer -text -noout

openssl x509 -incert.crt -text -noout

下面的命令可以用来查看二进制证书内容:

openssl x509 -incert.der -inform der -text -noout

下面是常见的PEM和DER相互转换。

PEM到DER的转换:

openssl x509 -incert.crt -outform der-out cert.der

DER到PEM的转换:

openssl x509 -incert.crt -inform der -outform pem -out cert.pem

补充说明:上述命令中用到的openssl程序,就是本文中提到的OpenSSL开源库提供的程序。

7、Netty中的聊天加密代码示例

7.1 关于Netty

Netty是一个Java NIO技术的开源异步事件驱动的网络编程框架,用于快速开发可维护的高性能协议服务器和客户端,事实上用Java开发IM系统时,Netty是几乎是首选。

有关Netty的介绍我就不啰嗦了,如果不了解那就详读以下几篇:

史上最强Java NIO入门:担心从入门到放弃的,请读这篇!

Java的BIO和NIO很难懂?用代码实践给你看,再不懂我转行!

新手入门:目前为止最透彻的的Netty高性能原理和框架架构解析

史上最通俗Netty框架入门长文:基本介绍、环境搭建、动手实战

基它有关Netty的重要资料:

Netty-4.1.x 源码 (在线阅读版)

Netty-4.1.x API文档 (在线查阅版)

7.2 启动SSL Server代码示例

事实上这个标题是不对的,Netty中启动的server还是原来那个server,只是对发送的消息进行了加密解密处理。也就是说添加了一个专门进行SSL操作的Handler。

netty中代表ssl处理器的类叫做SslHandler,它是SslContext工程类的一个内部类,所以我们只需要创建好SslContext即可通过调用newHandler方法来返回SslHandler。

让服务器端支持SSL的代码:

ChannelPipeline p = channel.pipeline();

  SslContext sslCtx = SslContextBuilder.forServer(...).build();

  p.addLast("ssl", sslCtx.newHandler(channel.alloc()));

让客户端支持SSL的代码:

ChannelPipeline p = channel.pipeline();

   SslContext sslCtx = SslContextBuilder.forClient().build();

   p.addLast("ssl", sslCtx.newHandler(channel.alloc(), host, port));

netty中SSL的实现有两种方式,默认情况下使用的是OpenSSL,如果OpenSSL不可以,那么将会使用JDK的实现。

要创建SslContext,可以调用SslContextBuilder.forServer或者SslContextBuilder.forClient方法。

这里以server为例,看下创建流程。

SslContextBuilder有多种forServer的方法,这里取最简单的一个进行分析:

publicstaticSslContextBuilder forServer(File keyCertChainFile, File keyFile) {

    returnnewSslContextBuilder(true).keyManager(keyCertChainFile, keyFile);

}

该方法接收两个参数:

  • 1)keyCertChainFile是一个PEM格式的X.509证书文件;
  • 2)keyFile是一个PKCS#8的私钥文件。

熟悉OpenSSL的童鞋应该知道使用openssl命令可以生成私钥文件和对应的自签名证书文件。

具体openssl的操作可以查看我的其他文章,这里就不详细讲解了。

除了手动创建证书文件和私钥文件之外,如果是在开发环境中,大家可能希望有一个非常简单的方法来创建证书和私钥文件,netty为大家提供了SelfSignedCertificate类。

看这个类的名字就是知道它是一个自签名的证书类,并且会自动将证书文件和私钥文件生成在系统的temp文件夹中,所以这个类在生产环境中是不推荐使用的。默认情况下该类会使用OpenJDK's X.509来生成证书的私钥,如果不可以,则使用 Bouncy Castle作为替代。

7.3 启动SSL Client代码示例

同样的在client中支持SSL也需要创建一个handler。

客户端的SslContext创建代码如下:

// 配置 SSL.

finalSslContext sslCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();

上面的代码我们使用了一个InsecureTrustManagerFactory.INSTANCE作为trustManager。

什么是trustManager呢?

当客户端和服务器端进行SSL连接的时候,客户端需要验证服务器端发过来证书的正确性。

通常情况下,这个验证是到CA服务器中进行验证的,不过这样需要一个真实的CA证书环境,所以在测试中,我们使用InsecureTrustManagerFactory,这个类会默认接受所有的证书,忽略所有的证书异常。

当然:CA服务器也不是必须的,客户端校验的目的是查看证书中的公钥和发送方的公钥是不是一致的,那么对于不能联网的环境,或者自签名的环境中,我们只需要在客户端校验证书中的指纹是否一致即可。

netty中提供了一个FingerprintTrustManagerFactory类,可以对证书中的指纹进行校验。

该类中有个fingerprints数组,用来存储安全的授权过的指纹信息。通过对比传入的证书和指纹,如果一致则校验通过。

使用openssl从证书中提取指纹的步骤如下:

openssl x509 -fingerprint -sha256 -inmy_certificate.crt

8、小结一下

上面我们对Netty聊天用到的加密技术和相关概念进行了梳理,我来简单这些概念之间的关系。

这些概念之间的关系,简单来说就是:

  • 1)PKI:是一套加密体系和标准的合集,它是理论方案;
  • 2)SSL:是利用了PKI理论体系,针对Socket网络这个场景设计的一套安全通信标准,属于是PKI的一个具体应用场景;
  • 3)OpenSSL:是PKI体系及SSL标准的算法和代码实现,它包括了具体的开源代码、工具程序等;
  • 4)各种证书:是在SSL或其它基于PKI体系的安全协议标准中需要使用的到一些加密凭证文件等。

而具体到Netty中的聊天加密,那就是应用了上述的PKI体系,基于SSL协议,在OpenSSL等开源库的帮助下实现的安全程序。

9、参考资料

[1] 公钥基础设施(PKI)国际标准进展

[2] 一篇文章让你彻底弄懂SSL/TLS协议

[3] 什么是OpenSSL?它有什么用途

[4] OpenSSL是什么软件

[5] netty系列之对聊天进行加密

[6] 跟着源码学IM

[7] 基于Netty,从零开发IM

[8] TCP/IP详解(全网唯一在线阅读版)

[9] 快速理解TCP协议一篇就够

[10] Netty-4.1.x 源码(在线阅读版)

[11] Netty-4.1.x API文档(在线版)

本文已同步发布于http://www.52im.net/thread-4104-1-1.html

posted @ 2022-12-22 17:34 Jack Jiang 阅读(82) | 评论 (0)编辑 收藏

     摘要: 本文由陶文分享,InfoQ编辑发布,有修订和改动。1、前言本系列的前几篇主要是从各个角度讲解Protobuf的基本概念、技术原理这些内容,但回过头来看,对比JSON这种事实上的数据协议工业标准,Protobuf到底性能到底高多少?本篇将以Protobuf为基准,对比市面上的一些主流的JSON解析库,通过全方位测试来证明给你看看Protobuf到底比JSON快几倍。学习交流:- 移动端IM开发入门文...  阅读全文

posted @ 2022-12-16 12:43 Jack Jiang 阅读(99) | 评论 (0)编辑 收藏

关于MobileIMSDK

MobileIMSDK 是一套专门为移动端开发的开源IM即时通讯框架,超轻量级、高度提炼,一套API优雅支持UDP 、TCP 、WebSocket 三种协议,支持iOS、Android、H5、标准Java平台,服务端基于Netty编写。

工程开源地址是:

关于RainbowChat

► 详细产品介绍:http://www.52im.net/thread-19-1-1.html
► 版本更新记录:http://www.52im.net/thread-1217-1-1.html
► 全部运行截图:Android端iOS端
► 在线体验下载:专业版(TCP协议)专业版(UDP协议)      (关于 iOS 端,请:点此查看

 

RainbowChat是一套基于开源IM聊天框架 MobileIMSDK 的产品级移动端IM系统。RainbowChat源于真实运营的产品,解决了大量的屏幕适配、细节优化、机器兼容问题(可自行下载体验:专业版下载安装)。

* RainbowChat可能是市面上提供im即时通讯聊天源码的,唯一一款同时支持TCP、UDP两种通信协议的IM产品(通信层基于开源IM聊天框架  MobileIMSDK 实现)。

v8.3 版更新内容

此版更新内容更多历史更新日志):

(1)Android端主要更新内容bug修复及优化!】:

  • 1)[bug] 当首页“消息”列表所有的item都是置顶时,取消其中任一个置顶,都会错误地将其排在列表首位而不是列表末尾;
  • 2)[bug] 解决了从首页“消息”列表中遗留的陌生人聊天信息无法重置消息未读数的问题;
  • 3)[bug] 解决了聊天界面中底部面板和输入法软键盘切换时ui发生弹跳的问题;
  • 4)[优化] 重构了APP包名、应用名,防止被某些手机误报成恶意软件。
  • 5)[优化] 重构了搜索功能相关的代码,使之更易理解和维护;
  • 6)[优化] 优化了APP中各种文本输入框UI效果,以及其它UI细节;
  • 7)[优化] 解决了自定义长按菜单在某些机型上item文字会换行的问题;
  • 8)[优化] 大文件发送时,选择的图片、视频文件可以自动以图片消息和短视频消息的形式发送;
  • 9)[优化] 优化了APP处于后台时,收到实时语音/视频请求的通知形式(用高优先级的系统Notification方式提醒用户)。 

(2)服务端主要更新内容:

  • 1)[bug] 解决了uid登陆时的sql注入风险;
  • 2)[优化] 升级MobileIMSDK至v6.2正式版

此版主要功能运行截图更多截图点此查看): 

posted @ 2022-12-07 15:17 Jack Jiang 阅读(87) | 评论 (0)编辑 收藏

     摘要: 本文由腾讯PCG后台开发工程师的SG4YK分享,进行了修订和和少量改动。1、引言近日学习了 Protobuf 的编码实现技术原理,借此机会,正好总结一下并整理成文。接上篇《由浅入深,从根上理解Protobuf的编解码原理》,本篇将从Base64再到Base128编码,带你一起从底层来理解Protobuf的数据编码原理。本文结构总体与 Protobuf 官方文档相似,不少内容也来自官方文档,并在官方...  阅读全文

posted @ 2022-12-02 12:33 Jack Jiang 阅读(100) | 评论 (0)编辑 收藏

     摘要: 本文由码农的荒岛求生陆小风分享,为了提升阅读体验,进行了较多修订和排版。1、引言搞即时通讯IM方面开发的程序员,在谈到通讯层实现时,必然会提到网络编程。那么计算机网络编程中的一个非常基本的问题:到底该怎样组织Client与server之间交互的数据呢?本篇文章我们不讨论IM系统中的那些高端技术话题,我们回归到通讯的本质——也就是数据在网络中交互时的编解码原理,并由浅入深从底...  阅读全文

posted @ 2022-11-24 11:43 Jack Jiang 阅读(108) | 评论 (0)编辑 收藏

本文由vivo技术团队Li Guanyun分享,为了提升阅读体验,行了较多修订和重新排版。

1、引言

Protobuf 作为一种跨平台、语言无关、可扩展的序列化结构数据通讯协议,已广泛应用于网络数据交换的场景中(比如IM通信、分布式RPC调用等)。

随着互联网的发展,分布式系统的异构性会愈发突出,跨语言的需求会愈加明显,同时 gRPC 也大有取代Restful之势,而 Protobuf 作为gRPC 跨语言、高性能的法宝,我们技术人有必要深入理解 Protobuf 原理,为以后的技术更新和选型打下基础。

借此机会,我将个人的Protobuf学习过程以及实践经验,总结成文,与大家一起探讨学习。本篇主要从Protobuf的基础概念开始,包括技术背景、技术原理、使用方法和优缺点。

PS:本篇本跟上篇《Protobuf从入门到精通,一篇就够!》类似,都适合作为Protobuf的入门文章,但本篇力求简洁,尽量不涉及Protobuf的具体技术细节,目的是降低阅读的门槛、提升阅读效果,希望对你有用。

学习交流:

(本文已同步发布于:http://www.52im.net/thread-4081-1-1.html

2、系列文章

本文是系列文章中的第 2 篇,本系列总目录如下:

  • IM通讯协议专题学习(一):Protobuf从入门到精通,一篇就够!
  • IM通讯协议专题学习(二):快速理解Protobuf的背景、原理、使用、优缺点》(* 本文
  • 《IM通讯协议专题学习(三):由浅入深,从通信编解码原理上理解Protobuf》(稍后发布..)
  • 《IM通讯协议专题学习(四):从Base64到Protobuf,详解Protobuf的数据编码原理》(稍后发布..)
  • 《IM通讯协议专题学习(五):Protobuf到底比JSON快几倍?请看全方位实测!》(稍后发布..)
  • 《IM通讯协议专题学习(六):手把手教你如何在Android上从零使用Protobuf》(稍后发布..)
  • 《IM通讯协议专题学习(七):手把手教你如何在NodeJS中从零使用Protobuf》(稍后发布..)
  • 《IM通讯协议专题学习(八):金蝶随手记团队的Protobuf应用实践(原理篇)  》(稍后发布..)
  • 《IM通讯协议专题学习(九):金蝶随手记团队的Protobuf应用实践(实战篇) 》(稍后发布..)

3、什么是Protobuf?

Protobuf(全称是Protocol Buffers)是一种跨平台、语言无关、可扩展的序列化结构数据的方法,可用于网络通信数据交换及存储。

在序列化结构化数据的机制中,Protobuf是灵活、高效、自动化的,相对常见的XML、JSON,描述同样的信息,Protobuf序列化后数据量更小、序列化/反序列化速度更快、更简单。

一旦定义了要处理的数据的数据结构之后,就可以利用Protobuf的代码生成工具生成相关的代码。只需使用 Protobuf 对数据结构进行一次描述,即可利用各种不同语言(proto3支持C++, Java, Python, Go, Ruby, Objective-C, C#)或从各种不同流中对你的结构化数据轻松读写。

PS:类似的介绍,在上篇《Protobuf从入门到精通,一篇就够!》中也有涉及,有兴趣可以一并阅读之。

4、为什么是 Protobuf?

4.1 技术背景

大家可能会觉得 Google 发明 Protobuf 是为了解决序列化速度的,其实真实的原因并不是这样的。

Protobuf最先开始是 Google用来解决索引服务器 request/response 协议的。

在没有Protobuf之前,Google 已经存在了一种 request/response 格式,用于手动处理 request/response 的编解码。

这种sstk式也能支持多版本协议,不过代码不够优雅:

if(protocolVersion=1) {

    doSomething();

} elseif(protocolVersion=2) {

    doOtherThing();

} ...

如果是非常明确的格式化协议,会使新协议变得非常复杂。因为开发人员必须确保请求发起者与处理请求的实际服务器之间的所有服务器都能理解新协议,然后才能切换开关以开始使用新协议。

这也就是每个服务器开发人员都遇到过的低版本兼容、新旧协议兼容相关的问题。

为了解决这些问题,于是Protobuf就诞生了。

4.2 Protobuf 诞生了

Protobuf 最初被寄予以下 2 个期望:

  • 1)更容易引入新的字段,并且不需要检查数据的中间服务器可以简单地解析并传递数据(而无需了解所有字段);
  • 2)数据格式更加具有自我描述性,可以用各种语言来处理(比如C++, Java 等各种语言)。

但这个版本的 Protobuf 仍需要自己手写解析的代码。

随着Protobuf的发展、演进,它具有了更多的特性:

  • 1)自动生成的序列化和反序列化代码(避免了手动解析的需要。官方提供自动生成代码工具,各个语言平台的基本都有);
  • 2)除了用于数据交换之外,Protobuf也被用作某些持久化数据的便捷自描述格式。

Protocol Buffers 命名的由来:

Why the name "Protocol Buffers"?

The name originates from the early days of the format, before we had the protocol buffer compiler to generate classes for us. At the time, there was a class called ProtocolBuffer which actually acted as a buffer for an individual method. Users would add tag/value pairs to this buffer individually by calling methods like AddValue(tag, value). The raw bytes were stored in a buffer which could then be written out once the message had been constructed.

Since that time, the "buffers" part of the name has lost its meaning, but it is still the name we use. Today, people usually use the term "protocol message" to refer to a message in an abstract sense, "protocol buffer" to refer to a serialized copy of a message, and "protocol message object" to refer to an in-memory object representing the parsed message.

4.3 Protobuf 在谷歌业务中的地位

Protobuf 现在是 Google 用于数据交换和存储的通用语言。

谷歌代码树中定义了 48162 种不同的消息类型,包括 12183 个 .proto 文件。它们既用于 RPC 系统,也用于在各种存储系统中持久存储数据。

Protobuf 诞生之初是为了解决服务器端新旧协议(高低版本)兼容性问题,名字也很体贴——“协议缓冲区”,只不过后期慢慢发展成用于传输数据。

5、Protobuf 协议的工作原理

如下图所示:可以看到,对于序列化协议来说,使用方只需要关注业务对象本身,即 idl 定义,序列化和反序列化的代码只需要通过工具生成即可。

6、Protobuf 协议的消息定义

Protobuf 的消息是在idl文件(.proto)中描述的。

下面是本次样例中使用到的消息描述符 customer.proto

syntax = "proto3";

 

package domain;

 

option java_package = "com.Protobuf.generated.domain";

option java_outer_classname = "CustomerProtos";

 

message Customers {

    repeated Customer customer = 1;

}

 

message Customer {

    int32 id= 1;

    string firstName = 2;

    string lastName = 3;

 

    enum EmailType {

        PRIVATE = 0;

        PROFESSIONAL = 1;

    }

 

    message EmailAddress {

        string email = 1;

        EmailType type= 2;

    }

 

    repeated EmailAddress email = 5;

}

上面的消息比较简单,Customers包含多个Customer(Customer包含一个id字段、一个firstName字段、一个lastName字段以及一个email的集合)。

除了上述定义外,文件顶部还有三行可帮助代码生成器的申明:

  • 1)syntax = "proto3":用于idl语法版本,目前有两个版本proto2和proto3,两个版本语法不兼容,如果不指定,默认语法是proto2(由于proto3比proto2支持的语言更多,语法更简洁,本文使用的是proto3);
  • 2)package domain:此配置用于嵌套生成的类/对象;
  • 3)option java_package:生成器还使用此配置来嵌套生成的源(此处的区别在于这仅适用于Java,在使用Java创建代码和使用JavaScript创建代码时,使用了两种配置来使生成器的行为有所不同。也就是说,Java类是在包com.Protobuf.generated.domain下创建的,而JavaScript对象是在包domain下创建的)。

Protobuf 提供了更多选项和数据类型,本文不做详细介绍,感兴趣可以参考官方文档

7、Protobuf 的代码生成

首先安装 Protobuf 编译器 protoc(点这里有详细的安装教程)。

安装完成后,可以使用以下命令生成 Java 源代码:

1protoc --java_out=./src/main/java./src/main/idl/customer.proto

上述命令的意图是:从项目的根路径执行该命令,并添加了两个参数 java_out(即定义 ./src/main/java/ 为Java代码的输出目录;而 ./src/main/idl/customer.proto 是.proto文件所在目录)。

生成的代码非常复杂,但幸运的是它的用法却非常简单:

CustomerProtos.Customer.EmailAddress email = CustomerProtos.Customer.EmailAddress.newBuilder()

        .setType(CustomerProtos.Customer.EmailType.PROFESSIONAL)

        .setEmail("crichardson@email.com").build();

 

CustomerProtos.Customer customer = CustomerProtos.Customer.newBuilder()

        .setId(1)

        .setFirstName("Lee")

        .setLastName("Richardson")

        .addEmail(email)

        .build();

// 序列化

byte[] binaryInfo = customer.toByteArray();

System.out.println(bytes_String16(binaryInfo));

System.out.println(customer.toByteArray().length);

// 反序列化

CustomerProtos.Customer anotherCustomer = CustomerProtos.Customer.parseFrom(binaryInfo);

System.out.println(anotherCustomer.toString());

8、Protobuf 的性能数据

我们简单地以上述Customers为模型,分别构造、选取小对象、普通对象、大对象进行性能对比。

序列化耗时以及序列化后数据大小对比:

反序列化耗时:

更多性能数据可以参考官方的测试Benchmark

9、Protobuf 的优点

9.1效率高

从序列化后的数据体积角度,与XML、JSON这类文本协议相比,Protobuf通过 T-(L)-V(TAG-LENGTH-VALUE)方式编码,不需要", {, }, :等分隔符来结构化信息。同时在编码层面使用varint压缩。

所以描述同样的信息,Protobuf序列化后的体积要小很多,在网络中传输消耗的网络流量更少,进而对于网络资源紧张、性能要求非常高的场景。比如在移动网络下的IM即时通讯应用中,Protobuf协议就是非常不错的选择(PS:这也是我为什么着手分享Protobuf系列文章的原因啦)。

我们来简单做个对比。

要描述如下JSON数据:

1{"id":1,"firstName":"Chris","lastName":"Richardson","email":[{"type":"PROFESSIONAL","email":"crichardson@email.com"}]}

使用JSON序列化后的数据大小为118byte:

7b226964223a312c2266697273744e616d65223a224368726973222c226c6173744e616d65223a2252696368617264736f6e222c22656d61696c223a5b7b2274797065223a2250524f46455353494f4e414c222c22656d61696c223a226372696368617264736f6e40656d61696c2e636f6d227d5d7d

而使用Protobuf序列化后的数据大小为48byte:

0801120543687269731a0a52696368617264736f6e2a190a156372696368617264736f6e40656d61696c2e636f6d1001

从序列化/反序列化速度角度,与XML、JSON相比,Protobuf序列化/反序列化的速度更快,比XML要快20-100倍。

9.2支持跨平台、多语言

Protobuf是平台无关的,无论是Android、iOS、PC,还是C#与Java,都可以利用Protobuf进行无障碍通讯。

proto3支持C++、Java、Python、Go、Ruby、Objective-C、C#(详见《Protobuf从入门到精通,一篇就够》)。

9.3扩展性、兼容性好

Protobuf具有向后兼容的特性:更新数据结构以后,老版本依旧可以兼容,这也是Protobuf诞生之初被寄予解决的问题,因为编译器对不识别的新增字段会跳过不处理。

9.4使用简单

Protobuf 提供了一套编译工具,可以自动生成序列化、反序列化的样板代码,这样开发者只要关注业务数据idl,简化了编码解码工作以及多语言交互的复杂度。

10、Protobuf 的缺点

Protobuf的优点很突出,但缺点也很明显。

Protobuf的缺点主要是:

  • 1)不具备自描述能力:跟XML、JSON相比,这两者是自描述的,而ProtoBuf则不是;
  • 2)数据可读性非常差:ProtoBuf是二进制协议,如果没有idl文件,就无法理解二进制数据流,对调试非常不友好。

不过:Charles已经支持Protobuf协议,导入数据的描述文件即可,详情可参考 Charles Protocol Buffers

然而:由于没有idl文件无法解析二进制数据流,ProtoBuf在一定程度上可以保护数据,提升核心数据被破解的门槛,降低核心数据被盗爬的风险(也算是缺点变优点的典型范例)。

11、参考资料

[1] Protobuf官方网站

[2] Protobuf从入门到精通,一篇就够!

[3] 如何选择即时通讯应用的数据传输格式

[4] 强列建议将Protobuf作为你的即时通讯应用数据传输格式

[5] APP与后台通信数据格式的演进:从文本协议到二进制协议

[6] 面试必考,史上最通俗大小端字节序详解

[7] 移动端IM开发需要面对的技术问题(含通信协议选择)

[8] 简述移动端IM开发的那些坑:架构设计、通信协议和客户端

[9] 理论联系实际:一套典型的IM通信协议设计详解

[10] 58到家实时消息系统的协议设计等技术实践分享

(本文已同步发布于:http://www.52im.net/thread-4081-1-1.html

posted @ 2022-11-17 10:52 Jack Jiang 阅读(79) | 评论 (0)编辑 收藏

为了更好地分类阅读52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第5 期。

* 评语:本系列文章尽量使用最浅显易懂的文字、图片来组织内容,力求通信技术零基础的人群也能看懂。但个人建议,至少稍微了解过网络通信方面的知识后再看,会更有收获。特别推荐即时通讯开发者来阅读,因为针对移动弱网的问题,确实可以找到很多有价值的答案。


[- 1 -] IM开发者的零基础通信技术入门(一):通信交换技术的百年发展史(上)

[链接]http://www.52im.net/thread-2354-1-1.html

[摘要] 本文(上下两篇)将带你了解当今通信交换技术最初的模样以及发展过程。学习技术更要了解技术的前世今生,技术本无聊,故事很有趣。


[- 2 -]IM开发者的零基础通信技术入门(二):通信交换技术的百年发展史(下)

[链接]http://www.52im.net/thread-2356-1-1.html

[摘要] 接上篇,本篇里我们需要暂停一下,回过头来看看我们国家的交换机发展情况。


[- 3 -] IM开发者的零基础通信技术入门(三):国人通信方式的百年变迁

[链接] http://www.52im.net/thread-2360-1-1.html

[摘要] 本文通过大量珍贵历史图片,从中国第一条电报线路,到如今触手可及的5G网络,回顾过去、展望未来,一起来看国人通信方式的百年历史变迁。


[- 4 -]IM开发者的零基础通信技术入门(四):手机的演进,史上最全移动终端发展史

[链接] http://www.52im.net/thread-2369-1-1.html

[摘要] 本文将通过大量历史图片,讲述手机这种移动终端的演化过程,为您呈现如今已深度融入人类生活的智能手机本来的样子。了解过去,才能更好地展望未来。


[- 5 -] IM开发者的零基础通信技术入门(五):1G到5G,30年移动通信技术演进史

[链接] http://www.52im.net/thread-2373-1-1.html

[摘要] 今天的5G,3.5GHz+大规模MIMO+波束赋形,还有固定无线应用,不禁让人看到了当年3G时代WiMax的影子,但WiMax为何输给了LTE,难道命运也喜欢对技术开玩笑吗?一部跨越三十年惊心动魄的移动通信史,为你揭晓答案。


[- 6 -] IM开发者的零基础通信技术入门(六):移动终端的接头人——“基站”技术

[链接] http://www.52im.net/thread-2375-1-1.html

[摘要]自上个世纪70年代末移动通信网络诞生以来,移动通信基站已经陪伴人类40年了,为人类社会带来了空前的变革,但你知道它的故事吗?


[- 7 -] IM开发者的零基础通信技术入门(七):移动终端的千里马——“电磁波”

[链接] http://www.52im.net/thread-2382-1-1.html

[摘要] 本文将回归到无线通信的技术之魂——“电磁波”,尽量用通俗易懂的文字讲述这个稍显枯燥的通信技术基础知识。


[- 8 -] IM开发者的零基础通信技术入门(八):零基础,史上最强“天线”原理扫盲

[链接] http://www.52im.net/thread-2385-1-1.html

[摘要] 实际生活中,无线通信中的天线都长什么样?有哪些用途?更重要的是,天线的技术原理是怎样的?本文将通过大量的图片,为你讲述这些内容。本文力求通俗易懂,面向零基础读者,希望继续给即时通讯网的开发者带来更多通信技术方面的收获。


[- 9 -] IM开发者的零基础通信技术入门(九):无线通信网络的中枢——“核心网”

[链接]http://www.52im.net/thread-2391-1-1.html

[摘要] 对于通信专业的人来说,几乎每个人都认为核心网难(不只是难,而且是非常难),很难有人能通俗易懂地讲明白它是什么东西。所以本文想借此机会,为零基础的IM开发者或其他移动端应用层程序员们,讲清楚这个话题。


[- 10 -] IM开发者的零基础通信技术入门(十):零基础,史上最强5G技术扫盲

[链接] http://www.52im.net/thread-2394-1-1.html

[摘要] 作为IM开发者,或者移动端开发者来说,提前了解5G技术显然是很有必要的。那么什么是5G技术?技术原理是怎么样的?5G技术将带来哪些技术革新?本文将以零基础的应用程序开发者为阅读对象,帮你找到这些问题的答案。


[- 11 -] IM开发者的零基础通信技术入门(十一):为什么WiFi信号差?一文即懂!

[链接] http://www.52im.net/thread-2402-1-1.html

[摘要] 为什么WiFi信号会受影响?什么情况下该使用何种方式组网?如何改善WiFi信号差的问题?等等,本文将通俗易懂地为你找到这些问题的答案。


[- 12 -] IM开发者的零基础通信技术入门(十二):上网卡顿?网络掉线?一文即懂!

[链接]http://www.52im.net/thread-2406-1-1.html

[摘要] 本文将详细介绍生活中遇到的常见网络问题,及可能的解决方法,虽说是一篇技术文章,但内容将一如既往地通俗易懂,简单实用。


[- 13 -] IM开发者的零基础通信技术入门(十三):为什么手机信号差?一文即懂!

[链接] http://www.52im.net/thread-2415-1-1.html

[摘要] 关于手机信号的问题真的不是大家想象得那么简单。本文正好收集整理了这一块的通信技术知识,一如既往的力求通俗易懂,希望对你有用。


[- 14 -] IM开发者的零基础通信技术入门(十四):高铁上无线上网有多难?一文即懂!

[链接] http://www.52im.net/thread-2419-1-1.html

[摘要] 为什么在高铁上手机信号会这么差?这个无线通信难题真的无法解决吗?今天,作为通信老司机的笔者,就详细和大家聊聊这个问题。


[- 15 -] IM开发者的零基础通信技术入门(十五):理解定位技术,一篇就够

[链接]http://www.52im.net/thread-2428-1-1.html

[摘要] 定位技术到底是怎么实现的?技术原理怎样?有哪些局限性?貌似我们平时也没有做更多了解,既然这样,那就跟着本文来一窥究竟吧。


👉52im社区本周新文:《IM通讯协议专题学习(一):Protobuf从入门到精通,一篇就够! http://www.52im.net/thread-4080-1-1.html》,欢迎阅读!👈

我是Jack Jiang,我为自已带盐!https://github.com/JackJiang2011/MobileIMSDK/

posted @ 2022-11-11 11:33 Jack Jiang 阅读(193) | 评论 (0)编辑 收藏

     摘要: 本文由IBM开发者社区分享,有较多修订和改动。1、引言在当今移动网络时代,手机流量和电量是宝贵的资源,对于移动端最常见的即时通讯IM应用,由于实时通信基于Socket长连接,它对于流量和电量的需求较一般应用来说更高(详见《移动端IM实践:WhatsApp、Line、微信的心跳策略分析》)。在IM应用中,优化数据流量消耗过多的基本方法就是使用高度压缩的通讯协议,而数据压缩后流量减小带来的自然结果也就...  阅读全文

posted @ 2022-11-10 11:49 Jack Jiang 阅读(101) | 评论 (0)编辑 收藏

关于MobileIMSDK

MobileIMSDK 是一套专门为移动端开发的开源IM即时通讯框架,超轻量级、高度提炼,一套API优雅支持UDP 、TCP 、WebSocket 三种协议,支持iOS、Android、H5、标准Java平台,服务端基于Netty编写。

工程开源地址是:

关于RainbowChat

► 详细产品介绍:http://www.52im.net/thread-19-1-1.html
► iOS端更新记录:http://www.52im.net/thread-2735-1-1.html
► 全部运行截图:iOS端全部运行截图 (另:Android端运行截图 点此查看
► 在线体验下载:App Store安装地址 (另:Android端下载体验 点此查看

 

RainbowChat是一套基于开源IM聊天框架 MobileIMSDK 的产品级移动端IM系统。RainbowChat源于真实运营的产品,解决了大量的屏幕适配、细节优化、机器兼容问题(可自行下载体验:专业版下载安装)。

RainbowChat可能是市面上提供im即时通讯聊天源码的,唯一一款同时支持TCP、UDP两种通信协议的IM产品(通信层基于开源IM聊天框架 MobileIMSDK 实现)。

v6.1 版更新内容

此版更新内容更多历史更新日志):

  • 1)[bug] 在聊天信息界面中查找消息时,点击查看指定消息,在聊天界面中不能自动滚动到这条消息;
  • 2)[bug] 点击首页“消息”列表中遗留的陌生人聊天信息时,无法重置消息未读数的问题;
  • 3)[bug] 在聊天界面中进入别的界面再回来时,底部面板没有自动关闭/收起;
  • 4)[优化] 优化了标题栏弹出菜单的圆角效果(使之更符合最新iOS美感设计);
  • 5)[优化] 优化了APP中各种文本输入框UI效果,以及其它UI细节;
  • 6)[优化] 优化了短视频录制界面在iOS16“灵动岛”手机上的ui适配。

此版主要功能运行截图更多截图点此查看):

 

posted @ 2022-11-05 17:42 Jack Jiang 阅读(70) | 评论 (0)编辑 收藏

1、引言

在《IM消息ID技术专题》系列文章的前几篇中,我们已经深切体会到消息ID在分布式IM聊天系统中的重要性以及技术实现难度,各种消息ID生成算法及实现虽然各有优势,但受制于具体的应用场景,也并不能一招吃遍天下,所以真正在IM系统中该如何落地消息ID算法和实现逻辑,还是要因地致宜,根据自已系统的设计逻辑和产品定义取其精华,综合应用之。

本文将基于网易严选的订单ID使用现状,分享我们是如何结合业内常用的分布式ID解决方案,从而在此基础之上进行ID特性丰富,并不断提升系统可用性和稳定性保障。同时,也对ID生成算法的落地实践过程中遇到坑进行了深入剖析。

本篇中的订单ID虽然不同于IM系统中的消息ID,但其技术实践仍然相通,希望能给你的IM系统消息ID技术选型也来更多的启发。

学习交流:

本文已同步发布于:http://www.52im.net/thread-4069-1-1.html

2、关于作者

西狂:服务端研发工程师, 早期参与严选采购、严选财务、严选合伙人以及报警平台等系统后端建设,目前主要致力于严选交易域技术演进以及业务研发工作。

3、系列文章

本文是系列文章中的第7篇,本系列总目录如下:

4、为什么需要分布式ID?

4.1 业务背景

如上图所示,对于网易严选的主站、分销和tob都会生成各自的订单ID,在同步订单数据到订单中心的时候,订单中心会生成一个订单中心内部的一个订单号,只是推送给到下游仓配时使用的订单ID略有不同。

4.2 带来的问题

 因为订单ID使用的混乱,导致了一系列问题的产生,例如: 沟通壁垒 、管控困难以及代码腐化等等。

4.3 技术目标

 我们希望通过分布式ID来帮助生成订单ID,在业务规则上必须全局唯一、安全性高,在性能上要高可用、低延迟。

5、我们的分布式ID架构原理

5.1 技术选型

下表是业内常见的分布式ID解决方案:

综合考虑是否支持水平扩展以及能够显示指定ID长度,最终选择的是Leaf的Segment模式(详见《深度解密美团的分布式ID生成算法》)。

5.2 架构简介

Leaf采用了预分发的方式来生成ID(如下图所示),在DB之上搭载若干个Server,每个Server在启动的时候,都会去DB中拿固定长度的ID列表,存放于内存中,因为ID是基于内存分发的,所以可以做到很高效。

在数据持久化方面,每次去DB拿固定长度的ID列表,只是把最大的ID持久化。

整体架构实现比较简单,主要是为了尽快解决业务层DB压力的问题,但是在生产环境中也暴露出一些问题。

比如:

  • 1)TP999数据波动大,当号段使用完之后还是会hang在更新数据库的I/O上,tp999数据会出现偶尔的尖刺;
  • 2)当更新DB号段的时候,如果DB宕机或者发生主从切换,会导致一段时间的服务不可用。

5.3 可用性优化

为了解决上面提到这个两个问题,引入双Buffer机制和异步更新策略,当一个Buffer消耗到某个临界点时,就会异步的触发任务,把下一个号段加载到内存中。

保证无论何时DB出现问题,都能有一个Buffer的号段可以正常对外提供服务,只要DB在一个Buffer的下发的周期内恢复,就不会影响整个Leaf的可用性。

5.4 步长动态调整

号段长度在固定不变的前提下,流量的突增和锐减都会使得正常流量下维持原有号段正常工作的时间缩短和提升。

可以尝试使用以下关系表达式来描述:

Q * T = L

(Q:服务qps  L:号段长度  T:号段更新周期)

但是Leaf的本质是希望T固定,如果Q和L可以正相关,T就可以趋于一个定值。

所以在Leaf每次更新号段的时候,会根据上一次号段更新的周期T和号段长度step,来决定下一次号段长度nextStep。

如下所示:

T < 15min,nextStep = step * 2

15min < T < 30min,nextStep = step

T > 30min,nextStep = step / 2

(初始指定step <= nextStep <= 最大值(自定义:100W))

6、我们做了什么改进?

6.1 特性丰富

 

通过结合严选的实际业务场景,进行了特性化支持,例如支持批量ID获取、大促提前扩容以及提前跳段处理。

6.2 可用性保障

1)针对DB:

 DB(MySql)采用主从模式(读写分离、降低主库压力),一主两从的配置方式,Master和Slave之间采用的是半同步复制(数据一致性要求,后期可考虑使用MySql Group Replication)。同时还添加了双1配置,保证不丢数据。

2)引入SDK:

通过引入SDK可以降低各个业务方的接入成本、降低Leaf服务端压力以及在Leaf服务不可用时,客户端起到短暂降级的效果。

SDK的实现原理和Leaf类似,在项目启动之初会加载业务关心参数配置信息,在应用构建本地缓存,同样采用了双Buffer存储模式。

6.3 稳定性保障

1)运维方面:

主要分为3个方面:

  • 1)日志监控:可以帮助发现预期之外的异常情况;
  • 2)流量监控:流有助于号段长度的评估范围,预防号段被快速消费的极端场景;
  • 3)线上巡检:可以时刻对服务进行存活校验。

2)SLA高可用方面:

除了运维之外还做了SLA的接入,通常用SLA来衡量系统的稳定性,除此之外我们还按照接口维度设定了SLO目标规则,目前的指标项比较单一只有请求延迟和错误率这两项。

 


 

7、我们遇到的坑

7.1 问题发现

如下图所示,我们发现每次服务启动上线接口的rt(响应时间)都要比平时高的多,但是过了一段时间之后却又恢复成正常水平。

7.2 问题探究

在分析之前,我们可以先简单的回顾下java虚拟机是如何运行Java字节码的。

虚拟机视角下Java字节码如何被虚拟机运行:

Java虚拟机将class文件加载到虚拟机中,然后将字节码翻译成机器码给底层硬件执行,而这里的翻译有两种形式,解释执行和编译执行。前者的优势在于无需等待编译,后者的优势在于实际运行速度更快。HotSpot默认采用混合模式,它会先解释执行字节码,然后将其中反复执行的热点代码,以方法为单位进行即时编译,JVM是依据方法的调用次数以及循环回边的执行次数来触发JIT编译的。

在Java7之前我们可以根据程序的特性选择对应的即时编译器。Java7开始引入分层编译机制(-XX:+TieredCompilation):综合了C1的启动性能优势和C2的峰值性能优势。

分层编译将JVM的执行状态分为了5个层次:

  • L0:解释执行(也会profiling);
  • L1:执行不带profiling的C1代码;
  • L2:执行仅带方法调用次数和循环回边执行次数profiling的C1代码;
  • L3:执行带所有profiling的C1代码;
  • L4:执行C2代码。

对于C1编译的三个层次,按执行效率从高至低:L1 > L2 > L3, 这是因为profiling越多,额外的性能开销越大。通常情况下,C2代码的执行效率比C1代码高出30%以上。(这里需要注意的是Java8默认开启了分层编译)

这张图列出了常见的分层编译的编译路径:

  • 1)通常情况下,热点方法会被第三层的C1编译器编译,再被C2编译器编译(0-> 3-> 4);
  • 2)如果方法的字节数目比较少并且第三层的profilling没有可收集的数据,jvm会判定该方法对于C1和C2的执行效率相同,在经过3层的C1编译过后,直接回到1层的C1(0-> 3-> 1);
  • 3)在C1忙碌的情况下,JVM在解释执行过程中对程序进行profiling,而后直接由4层的C2编译(0-> 4);
  • 4)在C2忙碌的情况下,方法会被2层的C1编译,然后再被3层的C1编译,以减少方法在3层的执行时间(0-> 2-> 3-> 4)。

上图是项目启动时的分层编译日志以及整个过程接口响应RT。

从图中可以看到先是执行了C1编译,再执行C2编译(日志文件中的3和4分别打标L3和L4),满足 0->3->4 编译顺序。

发现从C1编译到C2编译耗时过程比较长,这符合我们一开始提出的疑问,为什么项目启动需要经过一段时间接口RT才能趋于稳定。

7.3 解决方案

为了能在项目启动之初,快速达到接口RT峰值,因此只要尽最大程度缩短解释执行这个中间过程即可。

相应的解决方案:

  • 方案 1:关闭分层编译,降低编译阈值;
  • 方案 2:Mock接口数据, 快速触发JIT编译以及C2编译;
  • 方案 3:Java9 AOT提前编译。

针对方案3:Java9中支持新特性AOT提前编译,相比较于JIT即时编译而言,AOT在运行前就已经编译好了,避免 JIT 编译器的运行时性能消耗,同时避免解释程序的早期性能开销,可以极大提高java代码性能。

8、落地使用概况

Leaf已经在线上环境投入使用,各个业务方(包括主站、渠道、tob)也相应接入进行统一整改,自此严选订单ID生成得到统一收拢。

在整个严选的落地情况,按照业务维度,目前累计接入3个业务,分别是订单ID、订单快照ID、订单商品快照ID,都经受住了双十一和双十二考验。

9、参考资料

[1] 微信的海量IM聊天消息序列号生成实践(算法原理篇)

[2] 解密融云IM产品的聊天消息ID生成策略

[3] 深度解密美团的分布式ID生成算法

[4] 深度解密滴滴的高性能ID生成器(Tinyid)

本文已同步发布于:http://www.52im.net/thread-4069-1-1.html

posted @ 2022-11-03 11:45 Jack Jiang 阅读(95) | 评论 (0)编辑 收藏

为了更好地分类阅读52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第4 期。

[- 1 -] 不为人知的网络编程(一):浅析TCP协议中的疑难杂症(上篇)

[链接] http://www.52im.net/thread-1003-1-1.html

[摘要] 可能大家都知道TCP是三次交互完成连接的建立,四次交互来断开一个连接,那为什么是三次握手和四次挥手呢?反过来不行吗?


[- 2 -] 不为人知的网络编程(二):浅析TCP协议中的疑难杂症(下篇)

[链接] http://www.52im.net/thread-1004-1-1.html

[摘要] 接上篇《不为人知的网络编程(一):浅析TCP协议中的疑难杂症(上篇)》,我们提到第6个疑问:TCP的头号疼症TIME_WAIT状态,下面我们继续这个问题的解答。


[-3 -] 不为人知的网络编程(三):关闭TCP连接时为什么会TIME_WAIT、CLOSE_WAIT

[链接] http://www.52im.net/thread-1007-1-1.html

[摘要] 这次就和大家分享一下我们的netframework服务总会抛出一个“connet reset by peer”的原因吧。


[-4 -] 不为人知的网络编程(四):深入研究分析TCP的异常关闭

[链接] http://www.52im.net/thread-1014-1-1.html

[摘要] 大家都明白是“网络被对端重置了”,但究竟什么情况下会导致这种情况呢?本文就对TCP的各种关闭情况做了进一步的测试研究。


[- 5 -] 不为人知的网络编程(五):UDP的连接性和负载均衡

[链接] http://www.52im.net/thread-1018-1-1.html

[摘要] 本文将从实践出发,讨论UDP在实际应用中的连接性和负载均衡问题。


[- 6 -] 不为人知的网络编程(六):深入地理解UDP协议并用好它

[链接] http://www.52im.net/thread-1024-1-1.html

[摘要]本文接上篇《不为人知的网络编程(五):UDP的连接性和负载均衡》,将从实践出发,讨论如何深入地理解UDP协议并在实践中用好它。


[- 7 -] 不为人知的网络编程(七):如何让不可靠的UDP变的可靠?

[链接] http://www.52im.net/thread-1293-1-1.html

[摘要] 在 UDP 之上做一层可靠,很多朋友认为这是很不靠谱的事情,也有朋友认为这是一个大杀器,可以解决实时领域里大部分问题。涉及到实时传输我们都会先考虑 RUDP,RUDP 应用在我们APP核心传输体系的各个方面,但不同的系统场景我们设计了不同的 RUDP 方式,所以基于那些激烈的讨论和我们使用的经验,我决定扒一扒 RUDP,来给大家分享如何让UDP变的可靠的实践经验。


[- 8 -] 不为人知的网络编程(八):从数据传输层深度解密HTTP

[链接] http://www.52im.net/thread-2456-1-1.html

[摘要] 市面上讲HTTP协议的文章很多,但深入到传输层从2进制的角度来解析,则相当少见。保证全篇读完之后,你对HTTP的理解会上升一个台阶!


[- 9 -] 不为人知的网络编程(九):理论联系实际,全方位深入理解DNS

[链接] http://www.52im.net/thread-2740-1-1.html

[摘要] 当我们发现可以上QQ但不能浏览网页时,我们会想到可能是域名服务器挂掉了;当我们用别人提供的hosts文件浏览到一个“不存在”的网页时,我们会了解到域名解析系统的脆弱。然而关于DNS还有一大堆故事值得我们去倾听,去思考。


[- 10 -] 不为人知的网络编程(十):深入操作系统,从内核理解网络包的接收过程(Linux篇)

[链接] http://www.52im.net/thread-3247-1-1.html

[摘要] 这篇文章将用图解的方式,从操作系统这一层来深度理解一下网络包的接收过程。


[- 11 -] 不为人知的网络编程(十一):从底层入手,深度分析TCP连接耗时的秘密

[链接] http://www.52im.net/thread-3265-1-1.html

[摘要] TCP的开销到底有多大,能否进行量化。一条TCP连接的建立需要耗时延迟多少,是多少毫秒,还是多少微秒?能不能有一个哪怕是粗略的量化估计?我今天只分享我在工作实践中遇到的比较高发的各种情况。


[- 12 -] 不为人知的网络编程(十二):彻底搞懂TCP协议层的KeepAlive保活机制

[链接] http://www.52im.net/thread-3506-1-1.html

[摘要] 次借本文想把TCP协议的KeepAlive保活机制给详细的整理出来,以便大家能深入其中一窥究竟。


[- 13 -] 不为人知的网络编程(十三):深入操作系统,彻底搞懂127.0.0.1本机网络通信

[链接] http://www.52im.net/thread-3590-1-1.html

[摘要] 今天咱们就把 127.0.0.1 本机网络通信相关问题搞搞清楚!


[- 14 -] 不为人知的网络编程(十四):拔掉网线再插上,TCP连接还在吗?一文即懂!

[链接] http://www.52im.net/thread-3846-1-1.html

[摘要] 本篇文章,我们就从系统层面深入地探讨一个有趣的TCP技术问题:拔掉网线后,再插上,原本的这条TCP连接还在吗?或者说它还“好”吗?

我是Jack Jiang,我为自已带盐!

https://github.com/JackJiang2011/MobileIMSDK/

posted @ 2022-11-01 12:14 Jack Jiang 阅读(90) | 评论 (0)编辑 收藏

本文作者网易云信高级前端开发工程师李宁,本文有修订。

1、引言

在IM客户端的使用场景中,基于本地数据的全文检索功能扮演着重要的角色,最常用的比如:查找聊天记录、联系人等。

类似于IM中的聊天记录查找、联系人搜索这类功能,有了全文检索能力后,确实能大大提高内容查找的效率,不然,让用户手动翻找,确实降低了用户体验。

本文将要分享的是,网易云信基于Electron的PC端是如何实现IM客户端全文检索能力的。

学习交流:

(本文已同步发布于:http://www.52im.net/thread-4065-1-1.html

2、关于作者

李宁:网易云信高级前端开发工程师,负责音视频 IM SDK 的应用开发、组件化开发及解决方案开发,对 React、PaaS 组件化设计、多平台的开发与编译有丰富的实战经验。

3、系列文章

本文是系列文章中的第6篇,本系列总目录如下:

4、什么是全文检索

所谓全文检索,就是要在大量内容中找到包含某个单词出现位置的技术。

在传统的关系型数据库中,只能通过LIKE条件查询来实现,这样有几个弊端:

  • 1)无法使用数据库索引,需要遍历全表,性能较差;
  • 2)搜索效果差,只能首尾位模糊匹配,无法实现复杂的搜索需求;
  • 3)无法得到内容与搜索条件的相关性。

我们在 IM 的 iOS、安卓以及桌面端中都实现了基于 SQLite 等库的本地数据全文检索功能,但是在 Web 端和 基于Electron的PC端上缺少了这部分功能。

因为在 Web 端,由于浏览器环境限制,能使用的本地存储数据库只有 IndexDB,暂不在讨论的范围内。但在基于Electron的PC端上,虽然也是内置了 Chromium 的内核,但是因为可以使用 Node.js 的能力,于是乎选择的范围就多了一些。本文内容我们具体以基于Electron的IM客户端为例,来讨论全文检索技术实现。

PS:如果你不了解什么是Electron技术,读一下这篇《快速了解Electron:新一代基于Web的跨平台桌面技术》。

我们先来具体看下该如何实现全文检索。

要实现全文检索,离不开以下两个知识点:

  • 1)倒排索引;
  • 2)分词。

这两个技术是实现全文检索的技术以及难点,其实现的过程相对比较复杂,在聊全文索引的实现前,我们具体学习一下这两个技术的原理。

5、什么是倒排索引

先简单介绍下倒排索引,倒排索引的概念区别于正排索引:

  • 1)正排索引:是以文档对象的唯一 ID 作为索引,以文档内容作为记录的结构;
  • 2)倒排索引:是以文档内容中的单词作为索引,将包含该词的文档 ID 作为记录的结构。

以倒排索引库 search-index 举个实际的例子:

在我们的 IM 中,每条消息对象都有 idClient 作为唯一 ID,接下来我们输入「今天天气真好」,将其每个中文单独分词(分词的概念我们在下文会详细分享),于是输入变成了「今」、「天」、「天」、「气」、「真」、「好」。再通过 search-index 的 PUT 方法将其写入库中。

最后看下上述例子存储内容的结构:

如是图所示:可以看到倒排索引的结构,key 是分词后的单个中文、value 是包含该中文消息对象的 idClient 组成的数组。

当然:search-index 除了以上这些内容,还有一些其他内容,例如 Weight、Count 以及正排的数据等,这些是为了排序、分页、按字段搜索等功能而存在的,本文就不再细细展开了。

6、什么是分词

6.1基本概念

分词就是将原先一条消息的内容,根据语义切分成多个单字或词句,考虑到中文分词的效果以及需要在 Node 上运行,我们选择了Nodejieba作为基础分词库。

以下是 jieba 分词的流程图:

以“去北京大学玩”为例,我们选择其中最为重要的几个模块分析一下。

6.2加载词典

jieba 分词会在初始化时先加载词典,大致内容如下:

6.3构建前缀词典

接下来会根据该词典构建前缀词典,结构如下:

其中:“北京大”作为“北京大学”的前缀,它的词频是0,这是为了便于后续构建 DAG 图。

6.4构建 DAG 图

DAG 图是 Directed Acyclic Graph 的缩写,即有向无环图。

基于前缀词典,对输入的内容进行切分。

其中:

  • 1)“去”没有前缀,因此只有一种切分方式;
  • 2)对于“北”,则有“北”、“北京”、“北京大学”三种切分方式;
  • 3)对于“京”,也只有一种切分方式;
  • 4)对于“大”,有“大”、“大学”两种切分方式;
  • 5)对于“学”和“玩”,依然只有一种切分方式。

如此,可以得到每个字作为前缀词的切分方式。

其 DAG 图如下图所示:

6.5最大概率路径计算

以上 DAG 图的所有路径如下:

  • 去/北/京/大/学/玩
  • 去/北京/大/学/玩
  • 去/北京/大学/玩
  • 去/北京大学/玩

因为每个节点都是有权重(Weight)的,对于在前缀词典里的词语,它的权重就是它的词频。因此我们的问题就是想要求得一条最大路径,使得整个句子的权重最高。

这是一个典型的动态规划问题,首先我们确认下动态规划的两个条件。

1)重复子问题:

对于节点 i 和其可能存在的多个后继节点 j 和 k:

  • 1)任意通过i到达j的路径的权重 = 该路径通过i的路径权重 + j的权重,即 R(i -> j) = R(i) + W(j);
  • 2)任意通过i到达k的路径的权重 = 该路径通过i的路径权重 + k的权重,即 R(i -> k) = R(i) + W(k)。

即对于拥有公共前驱节点 i 的 j 和 k,需要重复计算到达 i 路径的权重。

2)最优子结构:

设整个句子的最优路径为 Rmax,末端节点为 x,多个可能存在的前驱节点为 i、j、k。

得到公式如下:

Rmax = max(Rmaxi, Rmaxj, Rmaxk) + W(x)

于是问题变成了求解 Rmaxi、Rmaxj 以及 Rmaxk,子结构里的最优解即是全局最优解的一部分。

如上,最后计算得出最优路径为“去/北京大学/玩”。

6.6HMM 隐式马尔科夫模型

对于未登陆词,jieba 分词采用 HMM(Hidden Markov Model 的缩写)模型进行分词。

它将分词问题视为一个序列标注问题,句子为观测序列,分词结果为状态序列。

jieba 分词作者在 issue 中提到,HMM 模型的参数基于网上能下载到的 1998 人民日报的切分语料,一个 MSR 语料以及自己收集的 TXT 小说、用 ICTCLAS 切分,最后用 Python 脚本统计词频而成。

该模型由一个五元组组成,并有两个基本假设。

五元组:

  • 1)状态值集合;
  • 2)观察值集合;
  • 3)状态初始概率;
  • 4)状态转移概率;
  • 5)状态发射概率。

基本假设:

  • 1)齐次性假设:即假设隐藏的马尔科夫链在任意时刻 t 的状态只依赖于其前一时刻 t-1 的状态,与其它时刻的状态及观测无关,也与时刻 t 无关;
  • 2)观察值独立性假设:即假设任意时刻的观察值只与该时刻的马尔科夫链的状态有关,与其它观测和状态无关。

状态值集合即{ B: begin, E: end, M: middle, S: single },表示每个字所处在句子中的位置,B 为开始位置,E 为结束位置,M 为中间位置,S 是单字成词。

观察值集合就是我们输入句子中每个字组成的集合。

状态初始概率表明句子中的第一个字属于 B、M、E、S 四种状态的概率,其中 E 和 M 的概率都是0,因为第一个字只可能 B 或者 S,这与实际相符。

状态转移概率表明从状态 1 转移到状态 2 的概率,满足齐次性假设,结构可以用一个嵌套的对象表示:

P = {

    B: {E: -0.510825623765990, M: -0.916290731874155},

    E: {B: -0.5897149736854513, S: -0.8085250474669937},

    M: {E: -0.33344856811948514, M: -1.2603623820268226},

    S: {B: -0.7211965654669841, S: -0.6658631448798212},

}

P['B']['E'] 表示从状态 B 转移到状态 E 的概率(结构中为概率的对数,方便计算)为 0.6,同理,P['B']['M'] 表示下一个状态是 M 的概率为 0.4,说明当一个字处于开头时,下一个字处于结尾的概率高于下一个字处于中间的概率,符合直觉,因为二个字的词比多个字的词要更常见。

状态发射概率表明当前状态,满足观察值独立性假设,结构同上,也可以用一个嵌套的对象表示:

P = {

    B: {'突': -2.70366861046, '肃': -10.2782270947, '适': -5.57547658034},

    M: {'要': -4.26625051239, '合': -2.1517176509, '成': -5.11354837278},

    S: {……},

    E: {……},

}

P['B']['突'] 的含义就是状态处于 B,观测的字是“突”的概率的对数值等于 -2.70366861046。

最后,通过Viterbi算法,输入观察值集合,将状态初始概率、状态转移概率、状态发射概率作为参数,输出状态值集合(即最大概率的分词结果)。关于Viterbi算法,本文不再详细展开,有兴趣的读者可以自行查阅。

7、技术实现

上节中介绍的全文检索这两块技术,是我们架构的技术核心。基于此,我们对IM 的 Electron 端技术架构做了改进。以下将详细介绍之。

7.1架构图详解

考虑到全文检索只是 IM 中的一个功能,为了不影响其他 IM 的功能,并且能更快的迭代需求,所以采用了如下的架构方案。

架构图如下:

如上图所示,右边是之前的技术架构,底层存储库使用了 indexDB,上层有读写两个模块。

读写模块的具体作用是:

  • 1)当用户主动发送消息、主动同步消息、主动删除消息以及收到消息的时候,会将消息对象同步到 indexDB;
  • 2)当用户需要查询关键字的时候,会去 indexDB 中遍历所有的消息对象,再使用 indexOf 判断每一条消息对象是否包含所查询的关键字(类似 LIKE)。

那么,当数据量大的时候,查询的速度是非常缓慢的。

左边是加入了分词以及倒排索引数据库的新的架构方案,这个方案不会对之前的方案有任何影响,只是在之前的方案之前加了一层。

现在,读写模块的工作逻辑:

  • 1)当用户主动发送消息、主动同步消息、主动删除消息以及收到消息的时候,会将每一条消息对象中的消息经过分词后同步到倒排索引数据库;
  • 2)当用户需要查询关键字的时候,会先去倒排索引数据库中找出对应消息的 idClient,再根据 idClient 去 indexDB 中找出对应的消息对象返回给用户。

7.2架构优点

该方案有以下4个优点:

  • 1)速度快:通过 search-index 实现倒排索引,从而提升了搜索速度;
  • 2)跨平台:因为 search-index 与 indexDB 都是基于 levelDB,因此 search-index 也支持浏览器环境,这样就为 Web 端实现全文检索提供了可能性;
  • 3)独立性:倒排索引库与 IM 主业务库 indexDB 分离;
  • 4)灵活性:全文检索以插件的形式接入。

针对上述第“3)”点:当 indexDB 写入数据时,会自动通知到倒排索引库的写模块,将消息内容分词后,插入到存储队列当中,最后依次插入到倒排索引数据库中。当需要全文检索时,通过倒排索引库的读模块,能快速找到对应关键字的消息对象的 idClient,根据 idClient 再去 indexDB 中找到消息对象并返回。

针对上述第“4)”点:它暴露出一个高阶函数,包裹 IM 并返回新的经过继承扩展的 IM,因为 JS 面向原型的机制,在新的 IM 中不存在的方法,会自动去原型链(即老的 IM)当中查找,因此,使得插件可以聚焦于自身方法的实现上,并且不需要关心 IM 的具体版本,并且插件支持自定义分词函数,满足不同用户不同分词需求的场景

7.3使用效果

使用了如上架构后,经过我们的测试,在数据量 20W 的级别上,搜索时间从最开始的十几秒降到一秒内,搜索速度快了 20 倍左右。

8、本文小结

本文中,我们便基于Nodejiebasearch-index在 Electron 上实现了IM聊天消息的全文检索,加快了聊天记录的搜索速度。

当然,后续我们还会针对以下方面做更多的优化,比如以下两点:

1)写入性能 :在实际的使用中,发现当数据量大了以后,search-index 依赖的底层数据库 levelDB 会存在写入性能瓶颈,并且 CPU 和内存的消耗较大。经过调研,SQLite 的写入性能相对要好很多,从观测来看,写入速度只与数据量成正比,CPU 和内存也相对稳定,因此,后续可能会考虑用将 SQLite 编译成 Node 原生模块来替换 search-index。

2)可扩展性 :目前对于业务逻辑的解耦还不够彻底。倒排索引库当中存储了某些业务字段。后续可以考虑倒排索引库只根据关键字查找消息对象的 idClient,将带业务属性的搜索放到 indexDB 中,将倒排索引库与主业务库彻底解耦。

以上,就是本文的全部分享,希望我的分享能对大家有所帮助。

9、参考资料

[1]微信移动端的全文检索优化之路

[2]微信移动端的全文检索多音字问题解决方案

[3]微信iOS端的最新全文检索技术优化实践

[4]蘑菇街基于Electron开发IM客户端的技术实践

[5]融云基于Electron的IM跨平台SDK改造实践总结

[6]闲鱼IM基于Flutter的移动端跨端改造实践

(本文已同步发布于:http://www.52im.net/thread-4065-1-1.html

posted @ 2022-10-27 11:18 Jack Jiang 阅读(75) | 评论 (0)编辑 收藏

为了更好地分类阅读52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第3 期。

第 

[标题] 高性能网络编程(一):单台服务器并发TCP连接数到底可以有多少

[链接] http://www.52im.net/thread-561-1-1.html

[摘要] 到底一台服务器能够支持多少TCP并发连接呢?这就是本文要讨论的问题。


第 

[标题] 高性能网络编程(二):上一个10年,著名的C10K并发连接问题

[链接] http://www.52im.net/thread-566-1-1.html

[摘要] 了解C10K问题及其解决思路,通过举一反三,或许可以为你以后面对类似问题提供更多可借鉴的思想和解决问题的实践思路。


第 

[标题] 高性能网络编程(三):下一个10年,是时候考虑C10M并发问题了

[链接] http://www.52im.net/thread-568-1-1.html

[摘要] 本文将讨论单机服务器实现C10M(即单机千万并发连接)的可能性及其思路。


第 

[标题] 高性能网络编程(四):从C10K到C10M高性能网络应用的理论探索

[链接] http://www.52im.net/thread-578-1-1.html

[摘要] 本文内容由京东的资深架构师闫国旗分享,以分享者多年的实践和总结,进一步探讨解决C10M问题的理论可行性。


第 

[标题] 高性能网络编程(五):一文读懂高性能网络编程中的I/O模型

[链接] http://www.52im.net/thread-1935-1-1.html

[摘要] 本文旨在为大家提供有用的高性能网络编程的I/O模型概览以及网络服务进程模型的比较,以揭开设计和实现高性能网络架构的神秘面纱。


第 

[标题] 高性能网络编程(六):一文读懂高性能网络编程中的线程模型

[链接] http://www.52im.net/thread-1939-1-1.html

[摘要] 限于篇幅原因,请将本文与《高性能网络编程(五):一文读懂高性能网络编程中的I/O模型》连起来读,这样会让知识更连贯。


第 

[标题] 高性能网络编程(七):到底什么是高并发?一文即懂!

[链接]http://www.52im.net/thread-3120-1-1.html

[摘要] 在面视即时通讯相关工作的时候,高并发也是必谈问题,那到底什么是高并发?嗯,真要说出个所以然来,还真有点懵...本文就与大家一起探讨学习一下。


第 

[标题] 从根上理解高性能、高并发(一):深入计算机底层,理解线程与线程池

[链接] http://www.52im.net/thread-3272-1-1.html

[摘要] 返璞归真、回归本质,这些技术特征背后的底层原理到底是什么?如何能通俗易懂、毫不费力真正透彻理解这些技术背后的原理,正是《从根上理解高性能、高并发》系列文章所要分享的。


第 

[标题] 从根上理解高性能、高并发(二):深入操作系统,理解I/O与零拷贝技术

[链接] http://www.52im.net/thread-3280-1-1.html

[摘要] 对于即时通讯IM这种系统的开发来说,网络通信知识确实非常重要,但回归到技术本质,实现网络通信本身的这些技术特征:包括上篇提到的线程池、零拷贝、多路复用、事件驱动等等,它们的本质是什么?底层原理又是怎样?这就是整理本系列文章的目的,希望对你有用。


第 10 

[标题] 从根上理解高性能、高并发(三):深入操作系统,彻底理解I/O多路复用

[链接] http://www.52im.net/thread-3287-1-1.html

[摘要] 本篇将以更具象的文件这个话题入手,带你一步步理解高性能、高并发服务端编程时无法回避的I/O多路复用及相关技术。


第 11 

[标题] 从根上理解高性能、高并发(四):深入操作系统,彻底理解同步与异步

[链接] http://www.52im.net/thread-3296-1-1.html

[摘要] 本篇将从基础着眼,为你讲解什么是同步和异步,以及这两个极为重要的概念在高并发、高性能技术中编程中到底意味着什么。


第 12 

[标题] 从根上理解高性能、高并发(五):深入操作系统,理解高并发中的协程

[链接] http://www.52im.net/thread-3306-1-1.html

[摘要] 了解和掌握协程技术对于很多程序员(尤其海量网络通信应用的后端程序员)来说是相当有必要的,本文正是为你解惑协程技术原理而写。


第 13 

[标题] 从根上理解高性能、高并发(六):通俗易懂,高性能服务器到底是如何实现的

[链接] http://www.52im.net/thread-3315-1-1.html

[摘要] 本篇是本系列文章的完结篇,你将能了解到,一个典型的服务器端是如何利用前5篇中讲解的各单项技术从而实现高性能高并发的。


第 14 

[标题] 从根上理解高性能、高并发(七):深入操作系统,一文读懂进程、线程、协程

[链接]http://www.52im.net/thread-3357-1-1.html

[摘要] 本篇是本系列文章的临时续篇,本篇将由浅入深,总结进程、线程、协程这3个技术概念,将3者的技术原理、用途、关系进行了系统梳理和总结,希望有助于解决你这方面的技术困惑。

我是Jack Jiang,我为自已带盐!

https://github.com/JackJiang2011/MobileIMSDK/

posted @ 2022-10-24 12:04 Jack Jiang 阅读(91) | 评论 (0)编辑 收藏

本文由融云技术团队分享,有修订和改动。

1、引言

Electron 凭借其相对更低的研发成本投入、强大的跨平台支持、拥有基数庞大的 Javascript 开发者受众等优势,在 PC 端跨平台桌面开发领域异军突起,大受欢迎。

本文分享的是融云基于Electron的IM跨平台PC端SDK改造过程中所总结的一些实践经验,希望对你有用。

* 友情提示:如果您对Electron的基础概念还不太了解,建议您先从本系列文章的首篇《快速了解新一代跨平台桌面技术——Electron》和第2篇《Electron初体验(快速开始、跨进程通信、打包、踩坑等)》开始阅读,否则可能难以理解本文的有关内容。

学习交流:

(本文已同步发布于:http://www.52im.net/thread-4060-1-1.html

2、系列文章

本文是系列文章中的第5篇,本系列总目录如下:

3、本次改造的技术目标

针对本次改造,我们需要达到以下4个技术目标:

  • 1)需提供与传统桌面通讯软件相匹配的能力支持;
  • 2)需实现浏览器与Electron不同运行时代码的高度复用;
  • 3)便于开发者构建多窗口、多进程的复杂桌面端应用;
  • 4)需同步适配同一IM端SDK的多个版本。

以下,我们将逐条讨论这4个目标所有实现的具体技术内容。

4、技术目标1:需提供与传统桌面通讯软件相匹配的能力支持

相较于 B/S 架构的 Web 网页应用,我们期望能够在 Electron 环境下向开发者提供更为丰富的本地化能力,以及比 Websocket(或Comet)更高效的Socket实时双工通信通道。

借助这些原本在浏览器环境下不便实现的技术能力,来整体提高用户对于桌面端产品的使用体验,将 Electron 作为一个 C/S 架构软件运行平台的潜力发挥到最大。(白话就是,我们希望借助Electron这个框架,将原本Web端的一些鸡肋能力,做到像原生富客户端一样)

5、技术目标2:浏览器与Electron不同运行时代码的高度复用

由于 Electron 与标准 Web 应用拥有几乎相同的技术生态,因此多数产品会要求前端代码工程兼顾浏览器与 Electron。

也就是说,一套代码既要打包为传统桌面端应用(利用Electron),又可发布为浏览器中运行的 Web 网页应用。

基于此,我们提供的 IM SDK 需要在两种不同的运行时环境下做到差异最小化,避免开发者编写冗余的平台兼容代码。(白话就是,尽可能在基于Electron的桌面端和纯Web网页端之间重用更多的代码,不然又得多撸一个全新的Electron端,这得多费劲)

6、技术目标3:便于开发者构建多窗口、多进程的复杂桌面端应用

Electron 通过对 IPC 能力的封装为桌面端应用开发提供了较完善的跨进程通讯方案,借助此能力,开发者构建的桌面端应用也逐渐趋于复杂。

比较典型的如桌面端IM产品:通常用一个独立窗口做基础的 IM 聊天业务,一个窗口做历史聊天记录查询业务。

当有音视频会议业务场景时,还需要再开一个窗口做会议业务。

甚至有开发者提出了与每个聊天对象都保持一个独立聊天窗口的需求(产品形态如 QQ)。

在这类需求下,长连接状态维持、消息同步变得异常复杂,原因在于以下3个方面。

  • 1)若每个进程窗口都维持独立长连接,难免会出现某一进程连接与其他进程连接状态不同步。且开发者需在各进程同时维护连接状态,复杂度较高。同时还会造成服务的并发能力下降。
  • 2)若仅有单一主窗口进行连接维持,其他窗口通过 IPC 能力将主窗口作为连接代理,则需要在主进程、各渲染进程中维护复杂的跨进程通讯业务代码,从而推高项目整体的复杂度。
  • 3)目前的 Electron 开发者绝大多数来自于 Web 开发者,既有编程思维是建立在浏览器页面内单进程单线程的应用模型下构建起来的,对于处理此类多进程模型的产品开发缺乏相关的经验积累。

为降低类似需求场景的业务实现复杂度,我们需要在 PaaS 能力层面上解决多进程连接共享、多进程消息同步问题,让开发者在既有编程思维模式下将每个业务实现的更为顺畅。

7、技术目标4:需同步适配同一IM端SDK的多个版本

我们的既有Web端 IM SDK 存在一个端多个不同版本的情况(主要是为了兼容老用户,旧版本很难一刀切直接扔掉,只能新老版末同时并存)。

各版本都有不同数量的客户积累,且各版本 API 接口设计迥异,跨版本升级成本较高。

考虑到使用不同版本的客户未来将业务向 Electron 迁移的可能性,我们期望通过架构设计的改进来避免既有客户做过多的集成代码修改,在确保既有客户不因版本升级而流失的前提下降低 Web 研发团队自身的多版本 SDK 维护成本。

8、本次改造的落地实践

针对上面章节中确定的技术目标,我们将从以下3个方向着手落地实践:

  • 1)剥离各版本的共同业务与对外差异性 API 定义;
  • 2)Electron 与浏览器平台下 IM SDK 的区分;
  • 3)解决多进程消息同步、多进程连接共享问题。
    以下,我们将逐条分享这3个方面的具体实践内容。

9、落地实践1:剥离各版本的共同业务与对外差异性API定义

我们的 IM SDK 各版本分别为不同的代码仓库独立维护,互无干系。(白话就是,所有端的IM SDK都是独立开发,从头造轮子)

这导致所有的功能(包括即将开发的 Electron 桌面解决方案)都可能要在各个版本仓库上单独实现,不仅开发成本高,还会导致实现质量无法保证、或代码实现不统一,同时也推高了产研后续流程的测试、上线等环节的成本。

▲ IM SDK 不同版本独立维护

基于前述技术目标4的要求,在既有现状下继续开发,就意味着需要在两个版本的基础上做不同实现,既不符合程序员的代码审美,也影响团队整体的研发效率。(白话就是,如果又要从头造轮子实在太难受)

为更好地达成技术目标4,团队决定优先通过重构将既有业务分层,即各个版本所必须的业务代码抽象下沉为 IM Engine 包,并为各个版本 IM SDK 分别实现不同的API Layer以便与既有线上版本接口对齐,这样既可以降低团队的研发成本,也可以满足既有线上客户后续的升级需求。

▲ 重构代码实现业务分层

完成业务分层后,对于 IM SDK 有依赖的其他产品如 RTC SDK,也都可以摆脱对 IM SDK 接口的依赖而直接调用 Engine 层接口,业务层在拓展 RTC 业务时,也就无需再考虑 IM SDK 的版本问题。

▲ 业务分层后的结构将保证拓展性

做分层的另一个考虑还为了达成技术目标2,将与业务层的交互限制在 API 层,在 Engine 中处理 Electron 与浏览器两种运行时下的代码差异,业务层只需关心 IM SDK 的接口调用而无需关心底层差异,确保业务层在两种运行时下只需要维护极少甚至无需维护兼容代码,便于业务层更专注于业务开发。

10、落地实践2:Electron 与浏览器平台下 IM SDK 的区分

在将 Engine 与业务层隔离后(见上一节),需要考虑 Engine 在不同的运行时下的关键能力差异,并依据能力差异落实 Engine 的底层设计。

Electron 环境下的连接、消息存储等能力由 c++ 模块编写提供(即后面提到的 CppProto.node):

在浏览器与 Electron 平台下,从连接管理、到消息收发等实现方式迥异,团队需要对 Engine 包继续分层,通过 AEngine 抽象类来定义 IM Engine 的能力接口,并抽象 APIContext 类用来管理 AEngine 的能力调用。

考虑到纯 Web 应用构建尺寸问题,Electron 的能力实现代码不应被打包到标准 Web 页面内,因此还需要将 Electron 平台下的实现代码单独抽离出来作为一个独立包(即ElectronSolution),作为可选模块由开发者选择安装使用。

▲ Electron相关的代码抽离为可选模块

如上图所示,CppEngine 在 ElectronSolution 包中定义,其需要由开发者在 Electron 应用创建 BrowserWindow 实例时通过 webPreferences.preload 配置属性向渲染进程窗口预挂载。

APIContext 在初始化 AEngine 实例时,优先检测 CppEngine 是否已定义。当发现有 CppEngine 定义时,则初始化 CppEngine 提供更丰富的本地化能力,否则初始化 JSEngine。

就像下面的代码的展现的逻辑:

const engine: AEngine = typeofCppEngine !== 'undefined'

  ? newCppEngine()

  : newJSEngine()

11、落地实践3:解决多进程消息同步、多进程连接共享问题

ElectronSolution 包截止目前的设计中,所有代码都运行在渲染进程内。

这意味着每个进程彼此独立,都在维护独立的进程状态,无法满足目标 3 中多进程状态同步、连接共享的需求。

为了解决该问题,需要将 CppProto.node 模块放到主进程,在主进程中实现连接管理、消息收发等能力,多个渲染进程通过 IPC 通信共享主进程状态。

▲ 多个渲染进程通过 IPC 通信共享主进程状态

为了达成技术目标3的要求,ElectronSolution 需要拆分为两个子包,即Main 与 Renderer。

具体就是:

  • 1)Main 包运行在主进程内,负责维持 CppProto.node 模块的调用,实现底层连接管理、消息管理等功能,同时通过 Electron 提供的 ipcMain 与各渲染进程维持通信;
  • 2)Renderer 包中定义 CppEngine 类,继承自 Engine 包内的 AEngine 抽象类,依然通过 webPreferences.preload 用来作为主进程的代理,通过 ipcRenderer 与主进程维持通信。

▲ 拆分为Main与Renderer两个子包

修改完成后,ElectronSolution 包的整体结构基本确定。

以下列出 ElectronSolution 包关键目录结构供参考:

node_modules/@rongcloud/electron-solution

├── index.js

├── main

│   ├── addon

│   │   ├── binding

│   │   │   └── electron-v{electron-version}-{platform}-{arch}.node

│   │   └── index.js

│   ├── dist

│   │   └── index.js

│   ├── index.js

│   └── package.json

└── renderer

│   ├── dist

│   │   └── index.js

│   ├── index.js

│   └── package.json

└── package.json

基于上述架构变动,当业务层需要在多个渲染进程中实现 IM 能力时,仅需要关注在各个进程中的 IM SDK 接口调用,由 ElectronSolution 处理多进程之间的状态同步问题。

当开发者期望由既有 Web 业务向 Electron 平台迁移时,开发者也无需修改既有的 Web 业务代码,仅需要增量编写主进程代码相关功能实现,将 ElectronSolution 安装并集成到 Electron 桌面端应用中即可。

最终,我们形成了以下这样的IM SDK整体结构:

12、未来的规划

除了上述IM相关业务,后续我们还打算在Electron平台下提升RTC的场景能力。

目前,Electron 平台下由 Chromium 原始提供的 WebRTC 能力对于开发桌面级音视频应用软件来说相对薄弱,我们有计划探索借助 node.js 的拓展能力,提供更为底层的 WebRTC 能力拓展如音效、音质、视频特效等。

13、参考资料

[1] 快速了解新一代跨平台桌面技术——Electron

[2] Electron初体验(快速开始、跨进程通信、打包、踩坑等)

[3] WebSocket从入门到精通,半小时就够!

[4] Comet技术详解:基于HTTP长连接的Web端实时通信技术

[5] 一套海量在线用户的移动端IM架构设计实践分享(含详细图文)

[6] Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE

[7] 搞懂现代Web端即时通讯技术一文就够:WebSocket、socket.io、SSE

(本文已同步发布于:http://www.52im.net/thread-4060-1-1.html

posted @ 2022-10-20 11:53 Jack Jiang 阅读(63) | 评论 (0)编辑 收藏

为了更好地分类阅读52im.net 总计1000多篇精编文章,我将在每周三推送新的一期技术周刊,本次是第期。

第 

[标题] 脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手

[链接] http://www.52im.net/thread-1729-1-1.html

[摘要]网络编程中TCP协议的三次握手和四次挥手的问题,在面试中是最为常见的知识点之一。本篇文章尝试使用动画图片的方式,来对这个知识点进行“脑残式”讲解(哈哈),期望读者们可以更加简单、直观地理解TCP网络通信交互的本质。


第 

[标题] 脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

[链接] http://www.52im.net/thread-1732-1-1.html

[摘要] 套接字socket是大多数程序员都非常熟悉的概念,它是计算机网络编程的基础,TCP/UDP收发消息都靠它。本篇文章依然尝试使用动画图片的方式,来对这个知识点进行“脑残式”讲解(哈哈),期望读者们可以更加简单、直观地理解Socket通信的数据读写本质。


第 

[标题] 脑残式网络编程入门(三):HTTP协议必知必会的一些知识

[链接] http://www.52im.net/thread-1751-1-1.html

[摘要]无论是即时通讯应用还是传统的信息系统,Http协议都是我们最常打交道的网络应用层协议之一,它的重要性可能不需要再强调。但是实际上很多人(包括我自己),虽然每天都会跟http的代码打交道,但对http了解的并不够深入。本文就我自己的学习心得,分享一下我认为需要知道的http常见的相关知识点。


第 

[标题] 脑残式网络编程入门(四):快速理解HTTP/2的服务器推送(Server Push)

[链接] http://www.52im.net/thread-1795-1-1.html

[摘要] 服务器推送(server push)是 HTTP/2 协议里面唯一一个需要开发者自己配置的功能。其他功能都是服务器和浏览器自动实现,不需要开发者关心。本文详细介绍新一代HTTP/2服务器推送技术(server push)的原理和配置方法等。


第 

[标题] 脑残式网络编程入门(五):每天都在用的Ping命令,它到底是什么?

[链接] http://www.52im.net/thread-1973-1-1.html

[摘要] Ping命令很简单,但作为为数不多的网络检测工具,却非常有用,是开发网络应用时最常用到的命令。虽然“Ping”这个动作这么简单,但你知道Ping命令背后后的逻辑吗?这就是本文要告诉你!


第 

[标题] 脑残式网络编程入门(六):什么是公网IP和内网IP?NAT转换又是什么鬼?

[链接] http://www.52im.net/thread-2082-1-1.html

[摘要] 搞网络通信应用开发的程序员,可能会经常听到外网IP(即互联网IP地址)和内网IP(即局域网IP地址),但他们的区别是什么?又有什么关系呢?另外,内行都知道,提到外网IP和内网IP就不得不提NAT路由转换这种东西,那这又是什么鬼?本文就来简单讲讲这些到底都是怎么回事。


第 

[标题] 脑残式网络编程入门(七):面视必备,史上最通俗计算机网络分层详解

[链接] http://www.52im.net/thread-2851-1-1.html

[摘要] 输入URL,到页面呈现出来,其中经历了什么?这道面试题的背后,涉及到了很多网络原理的知识,我们这篇文章不会全部分享到,而是先把由来和网络层次划分弄清楚,就完成了这篇文章的目的。


第 

[标题] 脑残式网络编程入门(八):你真的了解127.0.0.1和0.0.0.0的区别?

[链接] http://www.52im.net/thread-2928-1-1.html

[摘要] 对于后端程序员来说,127.0.0.1和0.0.0.0这两个IP地址再熟悉不过了,看起来好像就那么回事,但真正较起真来,这两个IP地址到底有什么作用以及到底有什么不同?貌似谁可以轻松回答,但张嘴却又不知从何说起。本文将系统地总结127.0.0.1和0.0.0.0这两个IP地址的作用,以及它们之间的区别,希望能为你解惑。


第 

[标题] 脑残式网络编程入门(九):面试必考,史上最通俗大小端字节序详解

[链接] http://www.52im.net/thread-3101-1-1.html

[摘要] 程序员在写应用层程序时,一般不需要考虑字节序问题,因为字节序跟操作系统和硬件环境有关,而我们编写的程序要么不需要跨平台(比如只运行在windows),要么需要跨平台时会由Java这种跨平台语言在虚拟机层屏蔽掉了。但典型情况,当你编写网络通信程序,比如IM聊天应用时,就必须要考虑字节序问题,因为你的数据在这样的场景下要跨机器、跨网络通信,必须解决不同系统、不同平台的字节序问题。


第 10 

[标题] 网络编程入门从未如此简单(一):假如你来设计网络,会怎么做?

[链接] http://www.52im.net/thread-3330-1-1.html

[摘要] 本篇主要以通俗易懂的文风,引导你理解计算机网络是如何演化成今日的样子,文中穿插了集线器、交换杨、路由器等设备的使用背景以及技术原理,由浅入深,非常适合入门者阅读。


第 11 

[标题] 网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?

[链接] http://www.52im.net/thread-3339-1-1.html

[摘要] 本篇将运用通俗易懂的语言,配上细致精确的图片动画,循序渐进地引导你理解TCP协议的主要特性和技术原理,让TCP协议的学习不再如此枯燥和生涩,非常适合入门者阅读。


第 12 

[标题] 网络编程入门从未如此简单(三):什么是IPv6?漫画式图文,一篇即懂!

[链接] http://www.52im.net/thread-3868-1-1.html

[摘要] 本篇文章将利用简洁生动的文字,配上轻松幽默的漫画,助你从零开始快速建立起对IPv6技术的直观理解,非常适合入门者阅读。

我是Jack Jiang,我为自已带盐!

https://github.com/JackJiang2011/MobileIMSDK/

posted @ 2022-10-18 13:06 Jack Jiang 阅读(82) | 评论 (0)编辑 收藏

关于MobileIMSDK

MobileIMSDK 是一套专门为移动端开发的开源IM即时通讯框架,超轻量级、高度提炼,一套API优雅支持UDP 、TCP 、WebSocket 三种协议,支持iOS、Android、H5、标准Java平台,服务端基于Netty编写。

工程开源地址是:

关于RainbowChat

► 详细产品介绍:http://www.52im.net/thread-19-1-1.html
► iOS端更新记录:http://www.52im.net/thread-2735-1-1.html
► 全部运行截图:iOS端全部运行截图 (另:Android端运行截图 点此查看
► 在线体验下载:App Store安装地址 (另:Android端下载体验 点此查看

 

RainbowChat是一套基于开源IM聊天框架 MobileIMSDK 的产品级移动端IM系统。RainbowChat源于真实运营的产品,解决了大量的屏幕适配、细节优化、机器兼容问题(可自行下载体验:专业版下载安装)。

RainbowChat可能是市面上提供im即时通讯聊天源码的,唯一一款同时支持TCP、UDP两种通信协议的IM产品(通信层基于开源IM聊天框架  MobileIMSDK 实现)。

v6.0 版更新内容

此版更新内容新增“一键已读、搜索”等功能!】(更多历史更新日志):

  • 1)[新增] 搜索功能(支持好友、群聊、聊天记录搜索(与微信逻辑一样));
  • 2)[新增] “聊天信息”界面中新增“查找聊天记录”功能;
  • 3)[新增] “群聊信息”界面中新增“查找聊天记录”功能;
  • 4)[新增] 首页消息界面中,增加了“一键已读”功能;
  • 5)[bug] 解决了iOS16+“灵动岛”手机下,聊天界面功能面板和输入法显示的冲突;
  • 6)[优化] 优化了聊天界面中查看位置、名片消息回来时会自动滚动到最后一行的问题。

此版主要新增功能运行截图更多截图点此查看):

posted @ 2022-10-12 15:01 Jack Jiang 阅读(80) | 评论 (0)编辑 收藏

     摘要: 本文由vivo技术团队Yang Kun分享,原题“electron 应用开发优秀实践”,即时通讯网有修订。1、引言在上篇《Electron初体验(快速开始、跨进程通信、打包、踩坑等)》的分享中,我们已经对Electron跨端框架的开发有了大概的了解。本篇将基于vivo技术团队的技术实践,详细阐述了vivo在使用Electron进行跨端桌面开发时的技术栈选型考量,同时分享了在...  阅读全文

posted @ 2022-10-08 10:16 Jack Jiang 阅读(109) | 评论 (0)编辑 收藏

为了更好地分类阅读总计1000多篇精编文章,我将在每周三推送新的一期技术文集,本次是第1 期。

[标题] 网络编程懒人入门(一):快速理解网络通信协议(上篇)

[链接] http://www.52im.net/thread-1095-1-1.html

[摘要] 互联网的核心是一系列协议,总称为"互联网协议"(Internet Protocol Suite)。它们对电脑如何连接和组网,做出了详尽的规定。理解了这些协议,就理解了互联网的原理。本篇将带你从理论上快速理解这些协议。


[标题] 网络编程懒人入门(二):快速理解网络通信协议(下篇)

[链接] http://www.52im.net/thread-1103-1-1.html

[摘要] 接上篇,本篇将以普通人实际上网为例子,通俗易懂地讲解网络通信协议到底是什么。本篇带了有些基础的计网理论知识,但力求通俗不枯燥。


[标题]网络编程懒人入门(三):快速理解TCP协议一篇就够

[链接]http://www.52im.net/thread-1107-1-1.html

[摘要] TCP 是互联网的核心协议之一,鉴于它的重要性,本文将单独介绍它的基础知识,希望能加深您对TCP协议的理解。


[标题]网络编程懒人入门(四):快速理解TCP和UDP的差异

[链接]http://www.52im.net/thread-1160-1-1.html

[摘要] 对于即时通讯开者新手来说,在开始着手编写IM或消息推送系统的代码前,最头疼的问题莫过于到底该选TCP还是UDP作为传输层协议。本文延续《网络编程懒人入门》系列文章的风格,通过快速对比分析 TCP 和 UDP 的区别,来帮助即时通讯初学者快速了解这些基础的知识点,从而在IM、消息推送等网络通信应用场景中能准确地选择合适的传输层协议。


[标题]网络编程懒人入门(五):快速理解为什么说UDP有时比TCP更有优势

[链接]http://www.52im.net/thread-1277-1-1.html

[摘要] 随着网络技术飞速发展,网速已不再是传输的瓶颈,UDP协议以其简单、传输快的优势,在越来越多场景下取代了TCP,如网页浏览、流媒体、实时游戏、物联网。本文作为《网络编程懒人入门》系列文章的第5篇,将为您快速梳理UDP协议在某些场景下对比TCP协议所具有的优势。


[标题]网络编程懒人入门(六):史上最通俗的集线器、交换机、路由器功能原理入门

[链接]http://www.52im.net/thread-1629-1-1.html

[摘要] 本文旨在简单地说明集线器、交换机与路由器的区别,因而忽略了很多细节,三者实际的发展过程和工作原理并非文中所写的这么简单。如果你看完本文能大概了解到三者的异同,本文的目的就达到了。


[标题] 网络编程懒人入门(七):深入浅出,全面理解HTTP协议

[链接] http://www.52im.net/thread-1677-1-1.html

[摘要] 对于移动端即时通讯(尤其IM应用)来说,现今主流的数据通信总结下来无外乎就是长连接+短连接的方式,而短连接在应用上讲就是本文将要介绍的HTTP协议的应用,而正确地理解HTTP协议对于写好IM来说,是相当有益的(关于移动端的HTTP具体应用情况,可以阅读《现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障http://www.52im.net/thread-1413-1-1.html》)。


[标题] 网络编程懒人入门(八):手把手教你写基于TCP的Socket长连接

[链接] http://www.52im.net/thread-1722-1-1.html

[摘要] TCP 是互联网的核心协议之一,鉴于它的重要性,希望通过阅读上面介绍的几篇理论文章,再针对本文的动手实践,能真正加深您对TCP协议的理解。


[标题] 网络编程懒人入门(九):通俗讲解,有了IP地址,为何还要用MAC地址?

[链接] http://www.52im.net/thread-2067-1-1.html

[摘要] 标题虽然是为了解释有了 IP 地址,为什么还要用 MAC 地址,但是本文的重点在于理解为什么要有 IP 这样的东西。本文对读者的定位是知道 MAC 地址是什么,IP 地址是什么。


10 

[标题] 网络编程懒人入门(十):一泡尿的时间,快速读懂QUIC协议

[链接]http://www.52im.net/thread-2816-1-1.html

[摘要] 一般的稳定网络传输都是通过TCP,但是在网络基建本身就已经越来越完善的情况下,TCP设计本身的问题便暴露了出来,特别是在弱网环境下,让我们不得不考虑一些新的可能性。


11 

[标题] 网络编程懒人入门(十一):一文读懂什么是IPv6

[链接]http://www.52im.net/thread-2979-1-1.html

[摘要] 本文将用浅显易懂的文字,带你了解到底什么是IPv6。


12 

[标题]网络编程懒人入门(十二):快速读懂Http/3协议,一篇就够!

[链接]http://www.52im.net/thread-3020-1-1.html

[摘要] 多年来,为了跟上互联网的发展,以及WWW上交换的内容种类增加,HTTP进行了几次重大升级,而HTTP/3就是目前的最新版本。本文将从HTTP/3的基本概念、技术原理、应用场景和如何使用它等方面进行介绍,确保在有限的篇幅内,能让你通俗地理解它。


13 

[标题]网络编程懒人入门(十三):一泡尿的时间,快速搞懂TCP和UDP的区别

[链接]http://www.52im.net/thread-3793-1-1.html

[摘要] 不同于其它长篇大论,本文尽量以简洁精炼的文字,帮你总结归纳TCP和UDP协议的主要区别,方便那些想掌握这方面知识又不愿意耗费太多时间去系统地学习网络理论基础的同学快速理解!


14 

[标题]网络编程懒人入门(十四):到底什么是Socket?一文即懂!

[链接] http://www.52im.net/thread-3821-1-1.html

[摘要] 本系列文章前面那些主要讲解的是计算机网络的理论基础,但对于即时通讯IM这方面的应用层开发者来说,跟计算机网络打道的其实是各种API接口。本篇文章就来聊一下网络应用程序员最熟悉的Socket这个东西,抛开生涩的计算机网络理论,从应用层的角度来理解到底什么是Socket。

我是Jack Jiang,我为自已带盐!

https://github.com/JackJiang2011/MobileIMSDK/

posted @ 2022-10-08 10:16 Jack Jiang 阅读(92) | 评论 (0)编辑 收藏

     摘要: 本文由蘑菇街前端技术团队分享,原题“Electron 从零到一”,有修订和改动。1、引言在上篇《快速了解新一代跨平台桌面技术——Electron》,我们已经对Electron跨端框架有了基本的认识。本篇将带你简单上手Electron框架开发跨平台桌面端,内容包括一个快速开始例子、跨进程通信原理、打包和分发、以及一些典型的技术踩坑等。希望能带给你启发。...  阅读全文

posted @ 2022-09-22 11:10 Jack Jiang 阅读(127) | 评论 (0)编辑 收藏

关于MobileIMSDK

MobileIMSDK 是一套专门为移动端开发的开源IM即时通讯框架,超轻量级、高度提炼,一套API优雅支持UDP 、TCP 、WebSocket 三种协议,支持iOS、Android、H5、标准Java平台,服务端基于Netty编写。

工程开源地址是:

关于RainbowChat

► 详细产品介绍:http://www.52im.net/thread-19-1-1.html
► iOS端更新记录:http://www.52im.net/thread-2735-1-1.html
► 全部运行截图:iOS端全部运行截图 (另:Android端运行截图 点此查看
► 在线体验下载:App Store安装地址 (另:Android端下载体验 点此查看

 

RainbowChat是一套基于开源IM聊天框架 MobileIMSDK 的产品级移动端IM系统。RainbowChat源于真实运营的产品,解决了大量的屏幕适配、细节优化、机器兼容问题(可自行下载体验:专业版下载安装)。

RainbowChat可能是市面上提供im即时通讯聊天源码的,唯一一款同时支持TCP、UDP两种通信协议的IM产品(通信层基于开源IM聊天框架  MobileIMSDK 实现)。

v5.0 版更新内容

此版更新内容【新增“扫一扫”等功能更多历史更新日志):

  • 1)[新增] “扫一扫”界面及功能逻辑;
  • 2)[新增] “我的二维码”界面及功能逻辑;
  • 3)[新增] “群聊二维码”界面及功能逻辑;
  • 4)[优化] 相关界面中的弹出菜单UI细节优化。

此版主要新增功能运行截图更多截图点此查看):

posted @ 2022-09-14 22:59 Jack Jiang 阅读(83) | 评论 (0)编辑 收藏

     摘要: 本文由微信客户端技术团队工程师“Jon”分享,原题“Windows微信:消息数据库架构演进”,有较多修订。1、引言本文分享的是,微信客户端团队基于对微信用户日常使用场景和数据分析,通过分离重要和非重要数据、采用可靠的分库策略等,对微信Windows端IM本地数据库的架构进行的优化和改造,并最终得到一个具备良好实践效果的技术改造方案。 以下是...  阅读全文

posted @ 2022-09-05 11:50 Jack Jiang 阅读(104) | 评论 (0)编辑 收藏

本文由融云技术团队分享,原题“互联网通信安全之端到端加密技术”,内容有较多修订和改动。

1、引言

在上篇《IM聊天系统安全手段之通信连接层加密技术》中,分享了关于通信连接层加密的相关技术和实践,包括在传输即时通信消息时启用 TLS 链路加密(保证消息在到达服务器前无法被窃听和篡改)、使用 CA 认证机制(杜绝中间人攻击)等。

本篇将围绕IM传输内容的安全问题,以实践为基础,为你分享即时通讯应用中的“端到端”加密技术。

学习交流:

本文已同步发布于:http://www.52im.net/thread-4026-1-1.html

2、系列文章

本文是IM通讯安全知识系列文章中的第11篇,此系列总目录如下:

3、为什么需要端到端加密?

上篇中提到的连接层加密技术,这是提升IM客户端到服务器之间数据传输的安全性手段,但是这并不能解决用户间的通信隐私性以及安全性风险。

因为在将数据传输到服务器之后,所有有权访问此服务器的人,包括员工、供应商及其他有关人员(甚至黑客),都有可能读取到用户的数据。

有鉴于此,端到端加密技术在即时通讯IM领域被广泛应用,包括WhatsApp、Signal、Telegram 等国外即时通信软件中都有使用。

PS:有关端到端加密的基础知识,可以从这两篇里得到,建议详读:

4、端到端加密的技术设计思路

4.1 简化版思路

说到端到端加密,我们首先想到的解决方案是:在发送端发送消息前对整个消息进行加密,接收端接收到消息后进行解密。

如上这样:消息中转服务器就无法获取我们的消息内容了。

事实上:这确实是端到端加密中消息收发的简化版解决方案,只是我们在实际应用中要更加复杂,效果也更加安全。

4.2 如何安全地传递用于消息加解密的密钥

对于端到端加密,我们需要先解决的前置安全问题是:如何安全地传递用于消息加解密的密钥。

答案是:用非对称加密的方式传输密钥(与 SSL / TLS 中安全交换密钥的方式类似)。

非对称加密传输对称加密密钥的算法,一般归结两种方式:

  • 1)一种是以 RSA、ECC 等为主(公钥加密私钥解密的方式,本质是加解密的算法);
  • 2)另一种是以 DH、ECDH 为主的生成共享密钥的方式(本质是通过计算协商一个共同的密钥而不是加解密算法)。

实际上:大部分即时通信软件中的端到端加密都采用生成共享密钥的方式来传输会话密钥。这是为什么呢?

这就涉及到 DH 算法(即 Diffie-Hellman 密钥交换算法),关于DH算法的资料,有兴趣可以详读《Diffie-Hellman密钥协商算法》,限于篇幅,这里不专门讨论。

Diffie-Hellman 密钥交换算法的安全性依赖于这样一个事实:虽然计算以一个素数为模的指数相对容易,但计算离散对数却很困难。对于大的素数,计算出离散对数几乎是不可能的。

这里简要描述一下 DH 共享密钥的过程如下:

其中“密钥 S”即为最终的共享密钥

4.3 采用共享密钥的原因

端到端加密采用共享密钥的方式来传输会话密钥有如下几个原因:

1)如果采用 RSA、ECC 等公钥加密私钥解密的方式传输密钥,需要在创建会话时生成临时密钥,并通过对方公钥加密后传输到接收端。

这就需要完全保证消息的可靠性,如果该消息在任何一个环节中丢失或损坏,则后续通信都无法进行。或者,需要采用更为可靠的传输方案,通常做法为需要接收端在线,通过各种确认来保证这个可靠性。

而采用共享密钥的方式则只需要知道对方的公钥,就可以完成生成共享密钥,并不一定需要对方在线。

2)如果已经生成的临时对称密钥丢失,则需要重新协商密钥。而采用共享密钥的方式则只需要知道对方的公钥,就可以完成生成共享密钥,不需要重新协商。

3)采用公钥加密私钥解密的方式至少会比生成共享密钥方式多一次交换对称密钥的通信过程。

4)密钥协商方式,不仅仅可以完成两个点之间的密钥协商,还可以延展到多人之间的共同协商出相同的密钥,这样能满足多人群体沟通的需求。

5、端到端加密的初步实践方案

我们结合对于 DH 算法(即 Diffie-Hellman 密钥交换算法)这种共享密钥方式的认知(即公钥可随意公开),先设计一个简单的端到端消息加密的过程。

这个过程的逻辑流程如下:

  • 1)在客户端 APP 首次安装时,基于服务器公开的两个全局的参数,生成自己的 DH 公钥和私钥;
  • 2)将自己的公钥上传证书服务器,证书服务器上保存用户标识与其公钥的关系。私钥则保存在客户端上;
  • 3)首次给对方发送消息或首次接收到对方消息时,便到证书服务器查询对方的公钥;
  • 4)根据对方公钥和自己的私钥计算出共享密钥;
  • 5)后续与对方所有的消息都基于这个密钥和相同的对称加解密算法进行加密解密操作。

端到端消息加密过程示意:

至此:我们完成了一个简单的端到端消息加密方案,在这个方案中我们引入了一个第三方的用于存储用户公钥的角色,这个角色的存在可以让任何一方都不用关心对方的在线状态,随时给对方发送加密过消息,而消息转发服务器无法解密消息。

接下来,我们针对这个简单方案存在的各种安全隐患问题,进行逐步分析和优化。

6、端到端加密实践方案的进一步优化和演进

6.1 使用HMAC作为消息完整性认证算法

在消息传输过程中,双方需要确认彼此消息的完整性,简单的做法就是将消息进行 Hash,得到的 Hash 值附加到消息后,随消息一起发送;对端接收后,同样进行 Hash,来验证消息是否被篡改。

关键点在于不同数据得到的 Hash 值一定不同,其中带密钥的 Hash 值就是 MAC算法。

另外,为了避免使用同样的 Hash 函数对相同数据进行操作总是得出同样的值,额外加入一个密钥,这样使用不同密钥就可以得出不同的 MAC。当然,这个密钥是两个对端都知道的。

这样,我们就得到了基于加密 Hash 的消息完整性认证的算法——Hash-based MAC(简称HMAC)。

基础知识1:什么是MAC算法?

全称Message Authentication Code,即消息认证码(带密钥的Hash函数)。在密码学中,MAC是通信实体双方使用的一种验证机制,是保证消息数据完整性的一种工具。

MAC算法的安全性依赖于Hash函数,故也称带密钥的Hash函数。消息认证码是基于密钥和消息摘要“hash”所获得的一个值,可用于数据源发认证和完整性校验。

使用 MAC 验证消息完整性的具体过程是:

  • 1)假设通信双方 A 和 B 共享密钥 K,A用消息认证码算法将 K 和消息 M 计算出消息验证码 Mac,然后将 Mac 和 M 一起发送给 B;
  • 2)B 接收到 Mac 和 M 后,利用 M 和 K 计算出新的验证码 Mac*,若 Mac*和Mac 相等则验证成功,证明消息未被篡改。

由于攻击者没有密钥 K,攻击者修改了消息内容后无法计算出相应的消息验证码,因此 B 就能够发现消息完整性遭到破坏。

简而言之就是:

  • 1)发送者通过MAC算法计算出消息的MAC值,并和消息一起发给收信者;
  • 2)收信者用同样的MAC算法计算收到的消息的MAC值,并对比两者。

下图是原理示意:

基础知识2:什么是HMAC算法?

HMAC是MAC算法中的一种,其基于加密HASH算法实现。任何加密HASH, 比如MD5、SHA256等,都可以用来实现HMAC算法,其相应的算法称为HMAC-MD5、HMAC-SHA256等。

6.2 使用ECDH算法替换DH算法

DH 算法是以离散对数的数学难题为基础的,随着计算机计算能力逐步增强,我们要不停地使用更大的数以增加破解难度,目前业界普遍认为至少需要使用 2048 位 DH 算法才具备更好的安全性。

在此我们引入 ECDH 算法替换 DH 算法。ECDH 密钥协商算法是 ECC 算法和 DH 密钥交换原理结合使用。ECC 是建立在基于椭圆曲线的离散对数问题上的密码体制。在相同破解难度下,ECC 具有更小长度的密钥和更快的正向计算速度优势。

我们系统上的 ECDH 可以直接采用目前公开的 sepc256kl 和 Curve25519 曲线,而无需服务再提供公开大数参数。

6.3 提升前向安全性

在消息传输过程中,如果协商好的密钥泄露了,就意味着所有信息都将暴露于风险之下。

为了防止这种情况发生,我们需要每次加密使用的密钥都与上一次不同,且不可以反向推导得出之前的密钥。

此处引入一个 Hash 算法:这个 Hash 算法可以通过输入一个密钥导出另外一个离散性更大的密钥,每次发送消息时都是用上次的消息密钥进行 Hash 运算得出本次密钥,由于 Hash 算法具有单向不可逆的特性,因此就无法通过本次的密钥推导之前的密钥。

从感观上,这就像一个棘轮,棘轮就是一种特殊的齿轮,他只能往一个方向转下去,而不能往回转。

我们先来感性认识一下棘轮:

在技术上,做到"只能往一个方向转下去,而不能往回转",是达到前向安全的关键。这就保证了,如果某一轮的密钥被破解出来,但前面的密钥是无法计算出来的,也就是前面的消息无法被解密。

6.4 同时保证前向安全和后向安全性

出于极致的安全性要求,我们会同时考虑前向安全和后向安全。如何保证在某次通信中,被破解出来的密钥,不能破解出之前的消息,而且在一定周期内,这个破解出来的密钥将不会再起作用。

介于此我们再引入另外一个棘轮来保证其向后的安全性。这就是大名鼎鼎的 Signal protocol 中的双棘轮算法。

Signal protocol 是真正的端到端的通讯加密协议,号称是世界上最安全的通讯协议,任何第三方包括服务器都无法查看通讯内容。

双棘轮算法包含一个 KDF 棘轮和一个 DH 棘轮。

KDF 全称(Key derivation function) 密钥导出函数,用于从一个原始的密钥导出一个或多个密钥。本质上就是 Hash 函数,通常用来将短密码变成长密码。另外 KDF 需要加“盐”(salt),用于防彩虹表,出于 Hash 的特性,这个“盐”的长度至少要大于 Hash 结果长度。

KDF (原密钥,盐) = 导出密钥

KDF 棘轮就是运用 KDF 算法,设计出一种密钥不断变化的效果,流程如下:

首先:将初始密钥使用 KDF 算法导出新的密钥,新密钥被切成两部分,前半部分作为下一次 KDF 计算的输入,后半部分作为消息密钥。

每迭代一次(也可以说棘轮步进一次),就会生成新的消息密钥。

由于 KDF 算法的单向性,通过这条消息的密钥无法倒推出上一条消息密钥,这就保证了密钥的前向安全。但是如果 KDF 中的盐被掌握,那么它就可以按照这种算法计算出以后所有的消息密钥。

为了保证后向安全,就要设计一种方法,使每次迭代时引入的盐是随机的,从而保证每次的消息密钥是不可以向后推算的。

由前面介绍的 DH 算法得知:两对密钥对可以通过 DH 协议生成一个安全的协商密钥,如果更换其中一个密钥对,新的协商密钥也会变化。

根据这个方法:我们可以设计出一个安全更新盐的方法。我们在证书服务器增加一个临时公钥证书,这个临时证书是按照接收双方标识构建的临时公钥对,即每个人的每个单人会话都具备一个临时公钥。每进行一个消息轮回,就更新一次己方的临时公钥,同时根据另外一方的临时公钥和己方的私钥进行协商,并将协商出的密钥作为盐,使得 KDF 棘轮算法生成的消息密钥具有后向安全性。

在初始时我们无法预测出每个人所有的新二人会话:那么我们就可以规定创建新的二人会话时,发起方首先生成一个新的临时 DH 公私钥对,并向服务器上传自己的临时 DH 公钥;其次发送方用接收方公布的长期公钥与自己的临时私钥协商出密钥作为消息加密的密钥,对消息进行加密;最后接收方首次接收到消息后用自己的长期公钥和发送方的临时私钥计算得出消息密钥,并在首次回复消息时生成临时公私钥,同时上传临时公钥。

问题是:如果接收端不在线,而发送端每条消息都去更新己方的临时公钥证书,就会导致发出去的这些消息,在接收端上线并收取后无法被正常解密。

为了解决这个问题,我们需要规定:只有在发出消息并得到对方回复后才更新临时证书,若对方不回复消息则不去更新临时证书。接收端能回复消息就表示其已经上线并接收完消息,这样就可以保证离线消息或者消息乱序也可以被对方正常解析。这种方法就是双棘轮算法中的另外一个 DH 棘轮。

6.5 更安全的密钥交换协议—— X3DH

对比最初的方案,为了满足消息的前向安全和后向安全,我们增加了双棘轮算法,在原基础方案上为每个人增加了一组会话级别临时 DH 密钥,每个人都拥有一个长期密钥和一组临时密钥。

但是:由于长期密钥无法被更换,所以方案依然存在着安全隐患。

因此:Signal protocol 设计了一种更为复杂和安全的 DH 密钥交换过程,称之为 X3DH(即 DH 协议的 3 倍扩展版)。

在 X3DH 协议里,每个人都要创建 3 种密钥对,分别如下:

  • 1)身份密钥对(Identity Key Pair):一个长期的符合 DH 协议的密钥对,用户注册时创建,与用户身份绑定;
  • 2)已签名的预共享密钥(Signed Pre Key):一个中期的符合 DH 协议的密钥对,用户注册时创建,由身份密钥签名,并定期进行轮换,此密钥可能是为了保护身份密钥不被泄露;
  • 3)一次性预共享密钥(One-Time Pre Keys):一次性使用的 Curve25519 密钥对队列,安装时生成,不足时补充。

所有人都要将这 3 种密钥对的公钥上传到服务器上,以便其他人发起会话时使用。

假如 Alice 要给 Bob 发送消息,首先要和 Bob 确定消息密钥,流程大致如下:

  • 1)Alice 要创建一个临时密钥对(ephemeral key),我们设成 EPK-A,此密钥对是为了后面棘轮算法准备,在此处作用不大;
  • 2)Alice 从服务器获取 Bob 的三种密钥对的公钥:身份密钥对IPK-B、已签名的预共享密钥 SPK-B、一次性预共享密钥 OPK-B;
  • 3)Alice 开始使用 DH 协议计算协商密钥,要引入参数包括:自己创建的两个密钥对的私钥,以及 Bob 的三个公钥。然后用类似排列组合的方式,将自己的私钥与对方的公钥分别带入 DH 算法计算。

DH1 = DH(IPK-A, SPK-B)

DH2 = DH(EPK-A, IPK-B)

DH3 = DH(EPK-A, SPK-B)

DH4 = DH(IPK-A, OPK-B)

如图所示:

然后将计算得到的四个值,前后连接起来,就得到了初始密钥,如下:

DH = DH1 || DH2 || DH3 || DH4

注:“||”代表连接符,比如 456 || 123 = 456123

但是 DH 这个密钥太长,不适合作为消息密钥,所以对这个初始密钥进行一次 KDF 计算,以衍生出固定长度的消息密钥 S:

S = KDF(DH1 || DH2 || DH3 || DH4)

这一步,Alice 终于计算出了消息密钥 S。

于是:

  • 1)Alice 使用消息密钥 S 对消息进行加密,连同自己的身份公钥 IPK-A 和临时公钥 EPK-A 一同发给 Bob;
  • 2)Bob 收到 Alice 的信息后,取出 Alice 的 2 个公钥,连同自己的密钥,使用与 Alice 相同的算法计算消息密钥 S;
  • 3)Bob 和 Alice 使用消息密钥进行加密通讯。

由上可知:X3DH 实际是复杂版的 DH 协议。

至此:我们简单介绍了 Signal Protocol 中最为核心的 X3DH 协议与双棘轮算法,基本上可以满足前向安全和后向安全。当然,真实的处理过程会更为复杂和安全。

7、IM群聊的端到端加密方案

在即时通讯场景中,除了二人之间的聊天以外,还有一个重要的场景就是群聊,那么群聊时的多人消息如何做端到端加密呢?

我们再次回到 DH 密钥协商算法上的推导过程:显然,多方情况下依然可以继续使用 DH 密钥协商算法,这就是群聊中端到端加密的基础。

而 Signal Protocol 在群组聊天中的设计与二人聊天又有所不同,由于群聊的保密性要求相对低一些,只采用了 KDF 链棘轮+公钥签名来进行加密通讯以保障加密的前向安全。

群组聊天的加解密通讯流程如下:

  • 1)每个群组成员都要首先生成随机 32 字节的 KDF 链密钥(Chain Key),用于生成消息密钥,以保障消息密钥的前向安全性,同时还要生成一个随机 Curve25519 签名密钥对,用于消息签名;
  • 2)每个群组成员用向其它成员单独加密发送链密钥(Chain Key)和签名公钥。此时每一个成员都拥有群内所有成员的链密钥和签名公钥;
  • 3)当一名成员发送消息时,首先用 KDF 链棘轮算法生成的消息密钥加密消息,然后使用私钥签名,再将消息发给服务器,由服务器发送给其它成员;
  • 4)其它成员收到加密消息后,首先使用发送人的签名公钥验证,验证成功后,使用相应的链密钥生成消息密钥,并用消息密钥解密;
  • 5)当群组成员离开时,所有的群组成员都清除自己链密钥和签名公钥并重新生成,再次单独发给每一位成员。这样操作,离开的成员就无法查看群组内的消息了。

由上可知:一个人在不同的群组里,会生成不同的链密钥和签名密钥对,以保障群组之间的隔离。在每个群组中,每个成员还要存储其它成员的 KDF 链和签名公钥,如果群组成员过多,加解密运算量非常大,会影响发送和接收速度,同时密钥管理数据库也会非常大,读取效率也会降低。

所以:群组聊天使用 Signal Protocol 协议,群人数不宜太多。

8、端到端加密方案的补充说明

上面我们介绍了即时通信中二人聊天和群组聊天的端到端加密全部过程。但是正常情况下端到端消息加密只是加密消息的实际负载部分(即只加密消息“体”部分),而消息的控制层则不会被加密,因为消息转发服务器需要根据控制信息进行消息转发或路由(否则肯定大大影响IM底层的路由和通信效率,因为需要反复加密解密)。

为了防止消息被定向分析(分析用户什么时间向谁发送了消息,或接收了谁的消息),我们依然需要对整体即时通信的长连接链路进行加密保护(这说的就是上篇文章里的通信连接层加密技术了),防止信息被中间网络设备截获并分析。而且为了防止密钥服务器被中间人攻击,也需要开启链路加密保护。

9、参考资料

[1] 移动端安全通信的利器——端到端加密(E2EE)技术详解

[2] 简述实时音视频聊天中端到端加密(E2EE)的工作原理

[3] HASH、MAC、HMAC学习

[4] 一文了解加解密、哈希函数、MAC、数字签名、证书、CA等

[5] 双棘轮算法:端对端加密安全协议,原理以及流程详解

[6] Signal protocol 开源协议理解

[7] X25519(Curve25519)椭圆曲线参考资料

本文已同步发布于:http://www.52im.net/thread-4026-1-1.html

posted @ 2022-08-29 16:13 Jack Jiang 阅读(80) | 评论 (0)编辑 收藏

本文由融云技术团队分享,原题“互联网通信安全之端到端加密技术”,内容有修订和改动。

1、引言

随着移动互联网的普及,IM即时通讯类应用几乎替代了传统运营商的电话、短信等功能。得益于即时通讯技术的实时性优势,使得人与人之间的沟通和交流突破了空间、时间等等限制,让信息的传递变的无处不在。

但互联网为我们的生活带来极大便利的同时,用户的隐私和通信安全问题也随之而来。

对于IM应用开发者来说,信息沟通的开放性也意味着风险性,用户与网络和移动设备的高度依赖,也为不法之徒提供了可乘之机。因此,提升即时通讯应用的安全性尤其重要。

本篇文章将围绕IM通信连接层的安全问题及实现方案,聚焦IM网络“链路安全”,希望能带给你启发。

学习交流:

本文已同步发布于:http://www.52im.net/thread-4015-1-1.html

2、系列文章

本文是IM通讯安全知识系列文章中的第10篇,此系列总目录如下:

3、即时通讯面临的安全问题

1)窃取内容:如果在整个即时通讯的通信过程中,其数据内容是未加密或弱加密的,那么其信息被截获后就可以直接被读取出来。

那么,这就会导致用户数据(包括个人隐私数据)的泄露,甚至可能危害用户的财产安全(比如微信这类IM中,红包、钱包都会涉及财产安全)。如果在办公场景下,被窃取的还可能是公司商业机密,那势必将会造成更大的经济损失。

2)篡改内容:如果通信内容被截获后,对其进行修改再发送,会破坏信息的正确性和完整性(此消息已非彼消息)。

3)伪造内容:如果用户通信凭证(比如token)被窃取或在通信过程中穿插其他信息,就可能为冒用用户身份骗取与之通信者的信任创造可能,埋下更大的安全隐患。

4)传播不法内容:基于即时通讯系统的消息推送能力,不法分子除了可能传播涉黄、涉赌、暴恐或危害国家安全的信息外,还可能传播计算机木马病毒等,可能带来的危害范围将进一步扩大。

4、常用的互联网攻击手段

网络通信过程中常见的攻击手段:

1)移植木马:过在终端移植木马,截获或篡改信息。

2)伪造应用:通过伪造 APP 或在 APP 中添加后门等方式,使终端用户误以为是正常应用进行使用,从而达到其不法目的。

3)网络抓包:通过在网络设备上进行抓包,获取用户通信内容。

4)中间人攻击:通过劫持 DNS 等手段,使用户通信连接经过攻击者的设备,从而达到窃取、篡改等目的。

5)漏洞挖掘:服务端或终端除了自有的程序以外还包含了各种三方组件或中间件,通过挖掘其上的漏洞,达到不法目的。

从上图和手段可知,聊天信息从应用经过网络到达服务端,这期间的任何一个环节都有可能被人利用。所以,在“危机四伏”的互联网络通信中,“安全”必须重视。

5、密码学在即时通讯系统中的应用

5.1 基本常识

针对前述的安全问题和攻击手段,将密码学应用在即时通讯系统连接上,对通信数据进行加密就变得尤为重要。

密码学解决信息安全的三要素(CIA)即:

  • 1)机密性(Confidentiality):保证信息不泄露给未经授权的用户;
  • 2)完整性(Integrity):保证信息从真实的发信者传送到真实的收信者手中,传送过程中没有被非法用户添加、删除、替换等;
  • 3)可用性(Availability):保证授权用户能对数据进行及时可靠的访问。

以上表述,好像有点绕口,我们换个通俗一点的表述。。。

密码学在网络通信中的三大作用就是:

  • 1)加密:防止坏人获取你的数据;
  • 2)认证:防止坏人修改了你的数据而你却并没有发现;
  • 3)鉴权:防止坏人假冒你的身份。

除 CIA 外,还有一些属性也是要求达到的,如可控性(Controllability)和不可否认性(Non-Repudiation)。

5.2 在即时通讯中的应用

作为即时通讯中的关键组成,IM即时通讯系统为了实现消息的快速、实时送达,一般需要客户端与服务器端建立一条socket长连接,用以快速地将消息送达到客户端。

通常即时通讯客户端会以 TCP 或 UDP 的方式与服务器建立连接,同时某些场景下也会使用 HTTP 的方式从服务器获取或提交一些信息。

整个过程中所有的数据都需进行加密处理,简单的数据加密和解密过程可以归纳为:发送方输入明文 -> 加密 -> 生成密文 -> 传输密文 -> 接收方解密 -> 得到明文。

这其中,会涉及:

这其中,我国也有一套自有的密码算法(国密算法):国密算法,即国家商用密码算法,是由国家密码管理局认定和公布的密码算法标准及其应用规范,其中部分密码算法已经成为国际标准。如 SM 商用系列密码:对称加密算法 SM4、非对称加密算法 SM2、信息摘要算法 SM3。

6、通信连接层的会话加密

对于连接层面(链路层面)面的加密,应最先考虑的是基于 SSL/TLS 协议进行链路加密(比如微信的作法:《微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解》),这是现代网络通信安全的基石。

很多人认为 SSL/TLS 协议是附加在 HTTP 协议上的,是 HTTPS 的一部分(详见《为什么要用HTTPS?深入浅出,探密短连接的安全性》)。

其实这种理解不完全正确,SSL/TLS 是独立于应用层协议的,高层协议可以透明地分布在 SSL/TLS 协议上面。因此基于socket长连接的IM即时消息通讯协议也可以构建在 SSL/TLS 协议上面。

SSL/TLS 是独立于应用层协议:

SSL/TLS 可以被简单地归纳为:利用基于公私钥体系的非对称加密算法,传输对称加解密算法的密钥,并将后续通讯的数据包基于双方相同的对称加解密算法和密钥进行加密并传输,从而达到保证数据安全通讯的目的。

非对称加密算法里面的公钥和私钥在数学上是相关的,这样才能用一个加密、用另一个解密。不过,尽管是相关的,但以现有的数学算法,是没有办法从一个密钥算出另一个密钥。

另外需要着重强调的是:在系统中不要使用自签证书,而要使用具备 CA 认证的证书,这样可以有效的防止中间人攻击。

7、基于SSL/TLS的通信连接层如何实现会话的快速恢复

7.1 概述

客户端和服务器端建立 SSL/TLS 握手时,需要完成很多步骤:密钥协商出会话密钥、数字签名身份验证、消息验证码 MAC 等。

整个握手阶段比较耗时的是密钥协商,需要密集的 CPU 处理。当客户端和服务器断开了本次会话连接,那么它们之前连接时协商好的会话密钥就消失了。在下一次客户端连接服务器时,便要进行一次新的完整的握手阶段。

这似乎没什么问题,但是当系统中某一时间段里有大量的连接请求提交时,就会占用大量服务器资源,导致网络延迟增加。

为了解决上面的问题,TLS/SSL 协议中提供了会话恢复的方式,允许客户端和服务器端在某次关闭连接后,下一次客户端访问时恢复上一次的会话连接。

会话恢复有两种:

  • 1)一种是基于 Session ID 的恢复;
  • 2)一种是使用 Session Ticket TLS 扩展。

下面来看看两种方式的优劣。

7.2 基于Session ID的SSL/TLS长连接会话恢复