Jack Jiang

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

2019年4月13日

     摘要: 本文由得物技术WWQ分享,原题“基于IM场景下的Wasm初探:提升Web应用性能”,下文进行了排版和内容优化。1、什么是WasmWasm,全称 WebAssembly,官网描述是一种用于基于堆栈的虚拟机的二进制指令格式。Wasm被设计为一个可移植的目标,用于编译C/C++/Rust等高级语言,支持在Web上部署客户端和服务器应用程序。简单的来说,Wasm就是使用C...  阅读全文

posted @ 2024-11-21 12:56 Jack Jiang 阅读(25) | 评论 (0)编辑 收藏

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

[-1-] 直播系统聊天技术(一):百万在线的美拍直播弹幕系统的实时推送技术实践之路

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

[摘要] 直播弹幕指直播间的用户,礼物,评论,点赞等消息,是直播间交互的重要手段。美拍直播弹幕系统从 2015 年 11 月到现在,经过了三个阶段的演进,目前能支撑百万用户同时在线。比较好地诠释了根据项目的发展阶段进行平衡演进的过程。这三个阶段分别是快速上线、高可用保障体系建设、长连接演进。具体我将在正文中展开,请继续往下阅读。


[-2-] 直播系统聊天技术(二)阿里电商IM消息平台,在群聊、直播场景下的技术实践

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

[摘要] 本文来自淘宝消息业务团队的技术实践分享,分析了电商IM消息平台在非传统IM应用场景下的高发并、强互动群聊和直播业务中的技术特点,总结并分享了在这些场景下实现大量多对多实时消息分发投递的一些架构方面的设计实践。


[-3-] 直播系统聊天技术(三):微信直播聊天室单房间1500万在线的消息架构演进之路

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

[摘要] 本文将回顾微信直播聊天室单房间海量用户同时在线的消息组件技术设计和架构演进,希望能为你的直播聊天互动中的实时聊天消息架构设计带来启发。


[-4-] 直播系统聊天技术(四):百度直播的海量用户实时消息系统架构演进实践

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

[摘要] 本文主要分享的是百度直播的消息系统的架构设计实践和演进过程。


[-5-] 直播系统聊天技术(五):微信小游戏直播在Android端的跨进程渲染推流实践

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

[摘要] 微信小游戏出于性能和安全等一系列考虑,运行在一个独立的进程中,在该环境中不会初始化视频号直播相关的模块。这就意味着小游戏的音视频数据必须跨进程传输到主进程进行推流,给我们实现小游戏直播带来了一系列挑战。


[-6-] 直播系统聊天技术(六):百万人在线的直播间实时聊天消息分发技术实践

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

[摘要] 本文将基于融云在直播技术实践的背景,分享了单直播间百万用户在线量的实时消息分发的技术经验总结,希望带给你启发。


[-7-] 直播系统聊天技术(七):直播间海量聊天消息的架构设计难点实践

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

[摘要] 本文将主要从高可用、弹性扩缩容、用户管理、消息分发、客户端优化等角度,分享直播间海量聊天消息的架构设计技术难点的实践经验。


[-8-] 视频直播技术干货(十一):超低延时视频直播技术的演进之路

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

[摘要] 本文将带您了解超低延时视频直播技术的优化和演进历程。


[-9 -]  视频直播技术干货(十二):从入门到放弃,快速学习Android端直播技术

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

[摘要] 本文详细介绍了Android端直播技术的全貌,涵盖了从实时音视频采集、编码、传输到解码与播放的各个环节。文章还探讨了直播中音视频同步、编解码器选择、传输协议以及直播延迟优化等关键问题。希望本文能为你提供有关Andriod端直播技术的深入理解和实践指导。


[-10-] 海量实时消息的视频直播系统架构演进之路(视频+PPT)[附件下载]

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

[摘要] 本次主要分享的是融云视频直播互动平台的实时消息可靠性的设计方案,支撑无上限消息并发的架构演进,单机吞吐性能的优化历程。


[-11 -] YY直播在移动弱网环境下的深度优化实践分享(视频+PPT)[附件下载]

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

[摘要] 本次分享介绍了 YY 直播针对质量较差网络(简称弱网)的环境,基于数据分析,在客户端和云端所采取的一系列技术手段。 同时,就如何改善上下行网络环境,也给出自己的一些解决方案。


[-12 -] 从0到1:万人在线的实时音视频直播技术实践分享(视频+PPT) [附件下载]

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

[摘要] 本次分享由“跟谁学”CTO带来,介绍跟谁学的团队是怎样在很短的时间内,构建了一个支持万人实时音视频直播的在线教室。


[-13 -] 在线音视频直播室服务端架构最佳实践(视频+PPT) [附件下载]

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

[摘要] 本期演讲嘉宾将为大家带来金山视频云在社交直播场景的支撑技术架构和优化方案。


👉52im社区本周新文:《Wasm在即时通讯IM场景下的Web端应用性能提升初探》,欢迎阅读!👈

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

posted @ 2024-11-20 11:34 Jack Jiang 阅读(31) | 评论 (0)编辑 收藏

     摘要: 本文由携程技术团队Aaron分享,原题“干货 | 携程弱网识别技术探索”,下文进行了排版和内容优化。1、引言网络优化一直是移动互联网时代的热议话题,弱网识别作为移动端弱网优化的第一步,受到的关注和讨论也是最多的。本文从方案设计、代码开发到技术落地,详尽的分享了携程在移动端弱网识别方面的实践经验,如果你也有类似需求,这篇文章会是一个不错的实操指南。技术交流:- 移动端IM开发...  阅读全文

posted @ 2024-11-14 11:14 Jack Jiang 阅读(47) | 评论 (0)编辑 收藏

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

[-1-] 实时音频的混音在视频直播中的技术原理和实践总结

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

[摘要] 今天,我们就来聊一聊混音技术在视频直播应用中的实现原理、方案等,及其在创新玩法中的实践应用。


[-2-] 七牛云技术分享:使用QUIC协议实现实时视频直播0卡顿!

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

[摘要] 不做任何开发,就能实现弱网环境下实现实时视频直播零卡顿,听上去是不是天方夜谭?看完这篇文章你就知道,我们是如何做到的。


[-3-] 近期大热的实时直播答题系统的实现思路与技术难点分享

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

[摘要] 我们首先分析一下直播答题和传统直播在技术上的不同,然后深度解释一下直播答题解决方案的海量并发派题和收题。


[-4-] P2P技术如何将实时视频直播带宽降低75%?

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

[摘要] 那整个系统是怎么设计的?使用了哪些技术来达成目标?接下来我来重点分享一下架构设计和技术细节。


[-5-] 网易云信实时视频直播在TCP数据传输层的一些优化思路

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

[摘要] 网易云信的实时视频直播目前使用了TCP进行传输,且基于此,从编码动态适配、发送队列调整、协议优化、socket等做了全流程的优化,确保在限带宽、丢包、时延、抖动,无论单项还是复杂网络,都有非常不错的实际体验。


[--] 首次披露:快手是如何做到百万观众同场看直播仍能秒开且不卡顿的?

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

[摘要] 快手拥有5亿注册用户,单个直播间人数峰值已经超过180万,他们针对海量用户,基于大数据技术,在首屏和流畅度优化上做了大量的探索与实践。快手直播是如何设计全链路质量监控方案、如何搭建大数据处理Pipeline 、如何解决开播跳帧、首屏卡顿优化等问题的?本文干货满满,全面解密快手直播大数据技术架构与优化实践。


[-7-] 浅谈实时音视频直播中直接影响用户体验的几项关键技术指标

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

[摘要] 这两年互联网领域的一个热门关键词就是实时音视频直播,从刚开始的游戏直播和秀场娱乐开始,实时音视频直播带来了远超传统互动的用户体验,现在实时音视频直播已逐渐深入当今主流的互联网应用形态里。我们将逐一分析和总结实时音视频直播中的这几个重要技术指标。


[-8-] 技术揭秘:支持百万级粉丝互动的Facebook实时视频直播

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

[摘要] 在这篇文章中,我们将粗略地看一下我们在每次发布时解决的问题,我还将向你解释我们为负载均衡和 RTMP 实现问题所选择的解决方案。


[--]  移动端实时视频直播技术实践:如何做到实时秒开、流畅不卡

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

[摘要] 本次分享将为大家揭开移动端实时音视频直播核心技术的神秘面纱。


[-10-] 实现延迟低于500毫秒的1080P实时音视频直播的实践分享

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

[摘要] 实时视频直播是很多技术团队及架构师关注的问题,在实时性方面,大部分直播是准实时的——存在 1-3 秒延迟。本文由袁荣喜分享其将1080P高清实时视屏直播延迟控制在 500ms 的背后的技术挑战以及实践结论等,期待与各同行共同讨论、学习和进步。


[-11 -] 浅谈开发实时视频直播平台的技术要点

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

[摘要] 现在大大小小的公司,甚至个人开发者,都想开发自己的直播网站或App,本文会帮你理清,开发视频直播平台,你需要注意哪些技术要点。


[-12 -] 海量用户IM聊天室的架构设计与实践

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

[摘要] 本文将分享网易云信针对海量用户IM聊天室的架构设计与应用实践,希望能带给你启发。


[-13 -] 微信团队分享:详解iOS版微信视频号直播中因帧率异常导致的功耗问题

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

[摘要] 功耗优化一直是 app 性能优化中让人头疼的问题,尤其是在直播这种用户观看时长特别久的场景。怎样能在不影响主体验的前提下,进一步优化微信iOS端视频号直播的功耗占用,本文给出了一个不太一样的答案。


👉52im社区本周新文:《移动端弱网优化专题(十四):携程APP移动网络优化实践(弱网识别篇)》,欢迎阅读!👈

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

posted @ 2024-11-13 11:58 Jack Jiang 阅读(45) | 评论 (0)编辑 收藏

     摘要: 本文由微信后台Astra项目团队分享,原题“Ray在微信AI计算中的大规模实践”,下文进行了排版和内容优化。1、引言微信存在大量AI计算的应用场景,主要分为三种:流量分发、产品运营和内容创作。流量分发场景中的 AI 计算主要用于搜索、广告、推荐场景的核心特征生产,产品运营相关的 AI 计算主要用于产品功能相关和内容运营相关(低质、优质、生态建设),由于大模型的兴起,AIGC...  阅读全文

posted @ 2024-11-07 11:07 Jack Jiang 阅读(62) | 评论 (0)编辑 收藏

     摘要: 本文来自微信团队工程师张文瑞的技术分享,由InfoQ编辑发布,下文有修订和改动。原文地址:infoq.cn/article/1-billion-bonus-from-the-clouds,感谢原作者的分享。一、引言与传统意义上的红包相比,手机端的红包似乎更符合现在年轻一代的习惯。这其中,以春节发红包最为流行。以微信为例,除夕全天微信用户红包总发送量可以达到百亿个,红包峰值收发量为比百万个/秒。本文...  阅读全文

posted @ 2024-11-06 11:52 Jack Jiang 阅读(52) | 评论 (0)编辑 收藏

     摘要: 本文由LearnLHC分享,原始出处:blog.csdn.net/LearnLHC/article/details/115268028,本文进行了排版和内容优化。1、引言熟悉网络编程的(尤其搞实时音视频聊天技术的)同学们都有个约定俗成的主观论调,一提起UDP和TCP,马上想到的是UDP没有TCP可靠,但UDP肯定比TCP高效。说到UDP比TCP高效,理由是什么呢?事实真是这样吗?跟着本文咱们一探究...  阅读全文

posted @ 2024-10-30 11:31 Jack Jiang 阅读(61) | 评论 (0)编辑 收藏

关于MobileIMSDK

MobileIMSDK 是一套专门为移动端开发的开源IM即时通讯框架,超轻量级、高度提炼,一套API优雅支持 UDP 、TCP 、WebSocket 三种协议,支持 iOS、Android、H5、标准Java、小程序、Uniapp,服务端基于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 实现)。

v9.1 版更新内容

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

  • 1)[bug] 解决了与Web产品互通时,收到撤回被引用消息的指令时会崩溃的问题;
  • 2)[bug] 解决了“查换用户”界面中精确查找时,输入内容时会导致底部按钮等控件显示高度被错误改变的问题;
  • 3)[bug] 解决了聊天输入框中自定义表情和数字、英文混输时,表情图标会消失的问题;
  • 4)[优化] 更换了位置消息中的高德地图AppKey,解决每日调用量限制问题;
  • 5)[优化] 优化了首页“消息”列表中单聊类型未正确同步时的收发消息和点击后的处理逻辑;
  • 6)[优化] 聊天消息自动识别电话、网址、邮箱等内容,点击自动跳转到系统功能;
  • 7)[优化] 优化了首页“消息”列表中同一好友和陌生人会话不能自动合并的问题。

部分功能运行截图(更多截图点此查看):

posted @ 2024-10-29 12:23 Jack Jiang 阅读(61) | 评论 (0)编辑 收藏

     摘要: 1、引言当你在浏览器输入 qq.com 按下回车键,到页面呈现在你面前,整个过程发生了什么?我以前思考过这个问题,从最前面的浏览器到最后的 db 都梳理的一遍,触发了一次技术顿悟,将很多散落的知识点贯通起来了。本文将抛弃千篇一律的计网知识理论,从现实的互联网技术实践角度,一步步为你分享一次网络请求背后的技术秘密。 技术交流:- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端I...  阅读全文

posted @ 2024-10-24 11:34 Jack Jiang 阅读(77) | 评论 (0)编辑 收藏

一、关于RainbowChat-Web

RainbowChat-Web是一套Web网页端IM系统,是RainbowChat的姊妹系统(RainbowChat是一套基于开源IM聊天框架 MobileIMSDK (Github地址)  的产品级移动端IM系统)。

二、v7.2 版更新内容

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

  • 1)[bug] [前端]      - 解决了加载首页聊天记录时,存在极小概率出现消息重复的问题;
  • 2)[bug] [前端]      - 解决了Firefox浏览器中右键无法复制文本消息的问题;
  • 3)[bug] [服务端]   - 升级了MobileIMSDK-Web库,解决了服务端QoS机制C2S消息路径时去重逻辑未起效的问题;
  • 4)[优化] [前端]     - 解决了引用的名片消息不会显示默认头像的问题;
  • 5)[优化] [前端]     - 重构了相关的类名、文件名等;
  • 6)[优化] [服务端]  - 优化了离线消息处理效率(异步化、无锁队列、批量处理、事务合并);
  • 7)[优化] [服务端]  - 优化了聊天记录处理效率(异步化、无锁队列、批量处理、事务合并);
  • 8)[优化] [服务端]  - 优化了“接口1008-26-8”,使按时间戳加载的消息在客户端不发生重复;
  • 9)[优化] [服务端]  - 修改了离线消息、聊天记录异步定时器实现,使之运行更健壮;
  • 10)[重构] [服务端] - 重构了通用http服务端工程、MQ工程目录名等;

三、主要功能特性截图

主要功能特性截图(更多运行截图运行视频

posted @ 2024-10-21 14:20 Jack Jiang 阅读(44) | 评论 (0)编辑 收藏

     摘要: 本文由陆业聪分享,原题“一文掌握直播技术:实时音视频采集、编码、传输与播放”,本文进行了排版和内容优化。1、引言从游戏、教育、电商到娱乐,直播技术的应用场景无处不在。随着移动端的网速越来越快,直播技术的普及和发展将更加迅速。本文详细介绍了Android端直播技术的全貌,涵盖了从实时音视频采集、编码、传输到解码与播放的各个环节。文章还探讨了直播中音视频同步、编解码器选择、传输...  阅读全文

posted @ 2024-10-17 11:10 Jack Jiang 阅读(57) | 评论 (0)编辑 收藏

关于RainbowChat

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

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

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

关于MobileIMSDK

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

工程开源地址:

v11.7 版更新内容

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

(1)Android端主要更新内容:

  • 1)[优化] 优化了首页“消息”列表中单聊类型未正确同步时的收发消息和点击后的处理逻辑;
  • 2)[优化] 优化了首页“消息”列表中同一好友和陌生人会话不能自动合并的问题;

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

  • 1)[优化] 大幅提升群聊性能(改进离线消息存储方式等:异步提交、批量处理);
  • 2)[优化] 升级了mysql驱动至最新版8.4.0;
  • 3)[优化] 优化了离线消息处理性能(异步化、无锁队列、批量处理、事务合并);
  • 4)[优化] 优化了聊天记录处理性能(异步化、无锁队列、批量处理、事务合并);
  • 5)[优化] 优化了“接口1008-26-8”,使得与Web产品联合部署明web前端按时间戳加载的消息不与客户端发生重复;
  • 6)[优化] 修改了离线消息、聊天记录异步定时器实现,使之运行更健壮;
  • 7)[优化] 加好友成功后将成功通知保存至离线消息和消息记录。

部分功能运行截图更多截图点此查看):

posted @ 2024-10-16 10:16 Jack Jiang 阅读(53) | 评论 (0)编辑 收藏

     摘要: 本文由百度技术团队分享,引用自百度Geek说,原题“百度Android IM SDK组件能力建设及应用”,本文进行了排版和内容优化。1、引言移动互联网时代,随着社交媒体、移动支付、线上购物等行业的快速发展,对即时通讯功能的需求不断增加。对于各APP而言,接入IM SDK(即时通讯软件开发工具包)能够大大降低开发成本、提高开发效率,快速构建自己的IM系统。本文主要介绍了百度公...  阅读全文

posted @ 2024-10-10 12:35 Jack Jiang 阅读(69) | 评论 (0)编辑 收藏

     摘要: 本文来自微信团队工程师张文瑞的技术分享,由“极客邦科技Geekbang”编辑发布,下文有修订和改动。一、开场白谢谢大家!我是来自腾讯WXG技术架构部的张文瑞,今天下午跟大家分享的主题是:微信团队是如何从0到1实现“有把握”的微信春晚摇一摇红包系统的。回忆一下春晚的活动,有什么样的活动形式呢?当时我们是直接复用客户端摇一摇入口,专门给春晚摇一摇定制了一...  阅读全文

posted @ 2024-10-10 10:18 Jack Jiang 阅读(89) | 评论 (0)编辑 收藏

     摘要: 1、前言在猴年新春的时候,腾讯当时推出了新春广告片(点击观看视频),作为《弹指间 心无间》的延续。片中通过春节期间发送QQ红包让家人打车回家团聚,让我们感受到了“最温暖的红包,给最爱的人”那种弹指间的感动。而就在这弹指一挥间,此次腾讯新春广告片距离2011年腾讯发布《弹指间 心无间》“亲情篇”已经好几年过去了。在这几年的时间里,腾讯QQ从音频、视频、...  阅读全文

posted @ 2024-09-29 12:18 Jack Jiang 阅读(87) | 评论 (0)编辑 收藏

本文由萤火架构分享,原题“localhost和127.0.0.1的区别是什么?”,原文链接“juejin.cn/post/7321049446443417638”,下文进行了排版和内容优化。

1、引言

继《你真的了解127.0.0.1和0.0.0.0的区别?》、《深入操作系统,彻底搞懂127.0.0.1本机网络通信》之后,这是整理收录的第3篇有关本机网络的网络编程基础文章。以下是正文内容。

今天在网上逛的时候看到一个问题,没想到大家讨论的很热烈,就是标题中这个:

前端同学本地调试的时候,应该没少和localhost打交道吧,只需要执行 npm run 就能在浏览器中打开你的页面窗口,地址栏显示的就是这个 http://localhost:xxx/index.html。

可能大家只是用,也没有去想过这个问题。联想到我之前合作过的一些开发同学对它们俩的区别也没什么概念,所以我觉得有必要普及下。

 
 

2、系列文章

本文是该系列文章中的第 4 篇:

网络编程入门如此简单(一):假如你来设计网络,会怎么做?

网络编程入门如此简单(二):假如你来设计TCP协议,会怎么做?

网络编程入门如此简单(三):什么是IPv6?漫画式图文,一篇即懂!

网络编程入门如此简单(四):一文搞懂localhost和127.0.0.1》(* 本文)

3、localhost是什么呢?

localhost是一个域名,和大家上网使用的域名没有什么本质区别,就是方便记忆。

只是这个localhost的有效范围只有本机,看名字也能知道:local就是本地的意思。

张三和李四都可以在各自的机器上使用localhost,但获取到的也是各自的页面内容,不会相互打架。

4、从域名到程序

要想真正的认清楚localhost,我们还得从用户是如何通过域名访问到程序说起。

以访问百度为例。

1)当我们在浏览器输入 baidu.com 之后,浏览器首先去DNS中查询 baidu.com 的IP地址。

为什么需要IP地址呢?打个比方,有个人要寄快递到你的公司,快递单上会填写:公司的通讯地址、公司名称、收件人等信息,实际运输时快递会根据通信地址进行层层转发,最终送到收件人的手中。网络通讯也是类似的,其中域名就像公司名称,IP地址就像通信地址,在网络的世界中只有通过IP地址才能找到对应的程序。(请详读《什么是公网IP和内网IP?NAT转换又是什么鬼?》)

DNS就像一个公司黄页,其中记录着每个域名对应的IP地址,当然也有一些域名可能没做登记,就找不到对应的IP地址,还有一些域名可能会对应多个IP地址,DNS会按照规则自动返回一个。我们购买了域名之后,一般域名服务商会提供一个域名解析的功能,就是把域名和对应的IP地址登记到DNS中。(请详读《理论联系实际,全方位深入理解DNS》)

这里的IP地址从哪里获取呢?每台上网的电脑都会有1个IP地址,但是个人电脑的IP地址一般是不行的,个人电脑的IP地址只适合内网定位,就像你公司内部的第几栋第几层,公司内部人明白,但是直接发给别人,别人是找不到你的。

如果你要对外部提供服务,比如百度这种,你就得有公网的IP地址,这个IP地址一般由网络服务运营商提供,比如你们公司使用联通上网,那就可以让联通给你分配一个公网IP地址,绑定到你们公司的网关服务器上,网关服务器就像电话总机,公司内部的所有网络通信都要通过它,然后再在网关上设置转发规则,将网络请求转发到提供网络服务的机器上。

2)有了IP地址之后,浏览器就会向这个IP地址发起请求,通过操作系统打包成IP请求包,然后发送到网络上。

网络传输有一套完整的路由协议,它会根据你提供的IP地址,经过路由器的层层转发,最终抵达绑定该IP的计算机。

3)计算机上可能部署了多个网络应用程序,这个请求应该发给哪个程序呢?

这里有一个端口的概念,每个网络应用程序启动的时候可以绑定一个或多个端口,不同的网络应用程序绑定的端口不能重复,再次绑定时会提示端口被占用。

通过在请求中指定端口,就可以将消息发送到正确的网络处理程序。但是我们访问百度的时候没有输入端口啊?这是因为默认不输入就使用80和443端口,http使用80,https使用443。我们在启动网络程序的时候一定要绑定一个端口的,当然有些框架会自动选择一个计算机上未使用的端口。

5、localhost和127.0.0.1的区别是什么?

有了前面的知识储备,我们就可以很轻松的搞懂这个问题了。

localhost是域名,上文已经说过了。

127.0.0.1 呢?是IP地址,当前机器的本地IP地址,且只能在本机使用,你的计算机不联网也可以用这个IP地址,就是为了方便开发测试网络程序的。

我们调试时启动的程序就是绑定到这个IP地址的。

这里简单说下,我们经常看到的IP地址一般都是类似 X.X.X.X 的格式,用"."分成四段。其实它是一个32位的二进制数,分成四段后,每一段是8位,然后每一段再转换为10进制的数进行显示。

那localhost是怎么解析到127.0.0.1的呢?经过DNS了吗?没有。每台计算机都可以使用localhost和127.0.0.1,这没办法让DNS来做解析。

那就让每台计算机自己解决了。每台计算机上都有一个host文件,其中写死了一些DNS解析规则,就包括 localhost 到 127.0.0.1 的解析规则,这是一个约定俗成的规则。

如果你不想用localhost,那也可以,随便起个名字,比如 wodehost,也解析到 127.0.0.1 就行了。

甚至你想使用 baidu.com 也完全可以,只是只能自己自嗨,对别人完全没有影响。

PS:以下两篇可以深入进行阅读:

  1. 你真的了解127.0.0.1和0.0.0.0的区别?
  2. 深入操作系统,彻底搞懂127.0.0.1本机网络通信

6、域名的等级划分

localhost不太像我们平常使用的域名,比如 www.juejin.cn 、baidu.com、csdn.net, 这里边的 www、cn、com、net都是什么意思?localhost为什么不需要?

域名其实是分等级的,按照等级可以划分为顶级域名、二级域名和三级域名...

1)顶级域名(TLD):

顶级域名是域名系统中最高级别的域名。它位于域名的最右边,通常由几个字母组成。顶级域名分为两种类型:通用顶级域名和国家顶级域名。常见的通用顶级域名包括表示工商企业的.com、表示网络提供商的.net、表示非盈利组织的.org等,而国家顶级域名则代表特定的国家或地区,如.cn代表中国、.uk代表英国等。

2)二级域名(SLD):

二级域名是在顶级域名之下的一级域名。它是由注册人自行选择和注册的,可以是个性化的、易于记忆的名称。例如,juejin.cn 就是二级域名。我们平常能够申请到的也是这种。目前来说申请 xxx.com、xxx.net、xxx.cn等等域名,其实大家不太关心其顶级域名com\net\cn代表的含义,看着简短好记是主要诉求。

3)三级域名(3LD):

三级域名是在二级域名之下的一级域名。它通常用于指向特定的服务器或子网。例如,在blog.example.com中,blog就是三级域名。www是最常见的三级域名,用于代表网站的主页或主站点,不过这只是某种流行习惯,目前很多网站都推荐直接使用二级域名访问了。

域名级别还可以进一步细分,大家可以看看企业微信开放平台这个域名:developer.work.weixin.qq.com,com代表商业,qq代表腾讯,weixin代表微信,work代表企业微信,developer代表开发者。这种逐层递进的方式有利于域名的分配管理。

按照上边的等级定义,我们可以说localhost是一个顶级域名,只不过它是保留的顶级域,其唯一目的是用于访问当前计算机。

7、多网站共用一个IP和端口

上边我们说不同的网络程序不能使用相同的端口,其实是有办法突破的。

以前个人博客比较火的时候,大家都喜欢买个虚拟主机,然后部署个开源的博客程序,抒发一下自己的感情。为了挣钱,虚拟主机的服务商会在一台计算机上分配N多个虚拟主机,大家使用各自的域名和默认的80端口进行访问,也都相安无事。这是怎么做到的呢?

如果你有使用Nginx、Apache或者IIS等Web服务器的相关经验,你可能会接触到主机头这个概念。主机头其实就是一个域名,通过设置主机头,我们的程序就可以共用1个网络端口。

首先在Nginx等Web程序中部署网站时,我们会进行一些配置,此时在主机头中写入网站要使用的域名。

然后Nginx等Web服务器启动的时候,会把80端口占为己有。

然后当某个网站的请求到达Nginx的80端口时,它会根据请求中携带的域名找到配置了对应主机头的网络程序。

然后再转发到这个网络程序,如果网络程序还没有启动,Nginx会把它拉起来。

8、私有IP地址

除了127.0.0.1,其实还有很多私有IP地址,比如常见的 192.168.x.x。

这些私有IP地址大部分都是为了在局域网内使用而预留的,因为给每台计算机都分配一个独立的IP不太够用,所以只要局域网内不冲突,大家就可劲的用吧。你公司可以用 192.168.1.1,我公司也可以用192.168.1.1。

但是如果你要访问我,就得通过公网IP进行转发。

大家常用的IPv4私有IP地址段分为三类:

  • 1)A类:从10.0.0.0至10.255.255.255;
  • 2)B类:从172.16.0.0至172.31.255.255;
  • 3)C类:从192.168.0.0至192.168.255.255。

这些私有IP地址仅供局域网内部使用,不能在公网上使用。

除了上述三个私有的IPv4地址段外,还有一些保留的IPv4地址段:

1)用于本地回环测试的127.0.0.0至127.255.255.255地址段,其中就包括题目中的127.0.0.1,如果你喜欢也可以给自己分配一个127.0.0.2的IP地址,效果和127.0.0.1一样。

2)用于局域网内部的169.254.0.0至169.254.255.255地址段,这个很少接触到,如果你的电脑连局域网都上不去,可能会看到这个IP地址,它是临时分配的一个局域网地址。

这些地址段也都不能在公网上使用。

近年来,还有一个现象,就是你家里或者公司里上网时,光猫或者路由器对外的IPv4地址也不是公网IP了,这时候获得的可能是一个类似 100.64.x.x 的地址,这是因为随着宽带的普及,运营商手里的公网IP也不够了,所以运营商又加了一层局域网,而100.64.0.0 这个网段是专门分给运营商做局域网用的。

如果你使用阿里云等公有云,一些云产品的IP地址也可能是这个,这是为了将客户的私有网段和公有云厂商的私有网段进行有效的区分。

其实还有一些不常见的专用IPv4地址段,完整的IP地址段定义可以看这里:www.iana.org/assignments

9、IPv6  

你可能也听说过IPv6,因为IPv4可分配的地址太少了,不够用,使用IPv6甚至可以为地球上的每一粒沙子分配一个IP。只是喊了很多年,大家还是喜欢用IPv4,这里边原因很多,这里就不多谈了。

IPv6地址类似于:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX。

它是128位的,用":"分成8段,每个X是一个16进制数(取值范围:0-F),IPv6地址空间相对于IPv4地址有了极大的扩充。比如:2001:0db8:3c4d:0015:0000:0000:1a2f:1a2b 就是一个有效的IPv6地址。(请详读《什么是IPv6?漫画式图文,一篇即懂!》)

10、参考资料  

[1] 你真的了解127.0.0.1和0.0.0.0的区别?

[2] 深入操作系统,彻底搞懂127.0.0.1本机网络通信

[3] 什么是IPv6?漫画式图文,一篇即懂!

[4] 一文读懂什么是IPv6

[5] IPv6技术详解:基本概念、应用现状、技术实践(上篇)

[6] 什么是公网IP和内网IP?NAT转换又是什么鬼?

[7] 深入操作系统,一文搞懂Socket到底是什么

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

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

[10] 理论联系实际,全方位深入理解DNS


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

posted @ 2024-09-26 10:23 Jack Jiang 阅读(79) | 评论 (0)编辑 收藏

     摘要: 1、前言微信——腾讯战略级产品,创造移动互联网增速记录,10个月5000万手机用户,433天之内完成用户数从零到一亿的增长过程,千万级用户同时在线,摇一摇每天次数过亿...在技术架构上,微信是如何做到的?日前,在腾讯大讲堂在中山大学校园宣讲活动上,腾讯广研助理总经理、微信技术总监周颢在两小时的演讲中揭开了微信背后的秘密。周颢把微信的成功归结于腾讯式的“三位一体&...  阅读全文

posted @ 2024-09-25 11:17 Jack Jiang 阅读(117) | 评论 (0)编辑 收藏

► 相关链接:

一、技术准备

您是否已对Web端即时通讯技术有所了解?

您需要对WebSocket技术有所了解:

WebSocket标准文档、API手册:

二、开发工具准备

1)WebStorm:

(JackJiang 使用的版本号如上图所示,建议你也使用此版或较新版本)

2)一站式下载地址:WebStorm官方下载地址点此进入

三、工程文件用途说明

3.1文件概览

纯原生JS实现,无任何重框架依赖:

MobileIMSDK-H5端SDK本身只是JS文件源码的集合,本工程中自带的前端Demo的目的只是为了方便随时测试MobileIMSDK-H5端的SDK代码而已,在此工程中的使用也仅仅只涉及了一个主Demo页面而已。

工程目录说明:

3.2详细说明

SDK 各模块/文件作用说明:

四、主要 API 接口

4.1主要 API 接口概览

如下图所示:所有 SDK 接口均由/mobileimsdk/mobileimsdk-client-sdk.js 提供。,接口设计跟MobileIMSDK 的APP版一样,均为高内聚和低侵入的回调方式传入SDK处理逻辑,无需(也不建议)开发者直接修改sdk级代码。

▲ 图上为浏览器端SDK的对外接口文件位置

▲ 图上为浏览器SDK为开发者提供的回调接口

▲ 图上浏览器端SDK的对外接口文件全图

4.2主要 API 接口用途说明

1)IMSDK.isLogined():

  • 用途:是否已经完成过首次登陆。
  • 说明 :用户一旦从自已的应用中完成登陆IM服务器后,本方法就会一直返回true(直到退出登陆IM)。
  • 返回值:{boolean},true表示已完成首次成功登陆(即已经成功登陆过IM服务端了,后面掉线时不影响此标识),否则表示尚未连接IM服务器。

2)IMSDK.isOnline():

  • 用途:是否在线。
  • 说明 :表示网络连接是否正常。
  • 返回值:{boolean},true表示网络连接正常,否则表示已掉线,本字段只在this._logined=true时有意义(如果都没有登陆到IM服务器,怎么存在在线或掉线的概念呢)。

3)IMSDK.getLoginInfo():

  • 用途:返回登陆时提交的登陆信息(用户名、密码/token等)。
  • 说明 :格式形如:{loginUserId:'',loginToken:''},此返回值的内容由调用登陆函数 loginImpl()时传入的内容决定。字段定义详见:PLoginInfo
  • 返回值:{boolean},true表示网络连接正常,否则表示已掉线,本字段只在this._logined=true时有意义(如果都没有登陆到IM服务器,怎么存在在线或掉线的概念呢)。

4)IMSDK.sendData(p, fnSucess, fnFail, fnComplete):

  • 用途:向某人发送一条消息。
  • 参数p:{Protocal} 要发送的消息协议包对象,Protocal详情请见“/module/mb_constants.js”下的createCommonData函数说明。
  • 返回值:{int} 0表示成功,否则表示错误码,错码详见“/module/mb_constants.js”下的MBErrorCode对象属性说明。

5)IMSDK.disconnectSocket():

  • 用途:客户端主动断开客户端socket连接。
  • 说明 :当开发者登陆IM后,需要退出登陆时,调用本函数就对了,本函数相当于登陆函数 loginImpl()的逆操作。

6)IMSDK.setDebugCoreEnable(enable):

  • 用途:是否开启MobileIMSDK-H5端核心算法层的log输入,方便开发者调试。
  • 参数enable :{boolean} true表示开启log输出,否则不输出,开发者不调用本函数的话系统默认是false(即不输出log)。

7)IMSDK.setDebugSDKEnable(enable):

  • 用途:是否开启MobileIMSDK-H5端框架层的log输入,方便开发者调试。
  • 参数enable :{boolean} true表示开启log输出,否则不输出,开发者不调用本函数的话系统默认是false(即不输出log)。

8)IMSDK.setDebugPingPongEnable(enable):

  • 用途:是否开启MobileIMSDK-H5端框架层的底层网络WebSocket心跳包的log输出,方便开发者调试。
  • 参数enable :{boolean} true表示开启log输出,否则不输出,开发者不调用本函数的话系统默认是false(即不输出log)。
  • 注意:必须 setDebugEnable(true) 且 setDebugPingPongEnable(true) 时,心跳log才会真正输出,方便控制。
  • 返回值:true表示开启log输出,否则不输出,开发者不调用本函数的话系统默认是false(即不输出log)。

9)IMSDK.loginImpl(varloginInfo, wsUrl):

  • 用途:登陆/连接MobileIMSDK服务器时调用的方法。
  • 说明 :登陆/连接MobileIMSDK服务器由本函数发起
  • 参数varloginInfo:{PLoginInfo} 必填项,登陆要提交给Websocket服务器的认证信息,不可为空,对象字段定义见:PLoginInfo
  • 参数wsUrl:{string} 必填项:要连接的Websocket服务器地址,不可为空,形如:wss://yousite.net:3000/websocket。

10)IMSDK.callback_onIMLog(message, toConsole):

  • 用途:由开发者设置的回调方法:用于debug的log输出。
  • 推荐用法 :开发者可在此回调中按照自已的意图打印MobileIMSDK微信小程序端框架中的log,方便调试时使用。
  • 参数1: {String}:必填项,字符串类型,表示log内容。
  • 参数2: {boolean}:选填项,true表示输出到console,否则默认方式(由开发者设置的回调决定)。

11)IMSDK.callback_onIMData(p, options):

  • 用途:由开发者设置的回调方法:用于收到聊天消息时在UI上展现出来(事件通知于收到IM消息时)。
  • 推荐用法:开发者可在此回调中处理收到的各种IM消息。
  • 参数1: {Protocal}:详情请见“/module/mb_constants.js”下的Protocal类定义)。

12)IMSDK.callback_onIMAfterLoginSucess():

  • 用途:由开发者设置的回调方法:客户端的登陆请求被服务端成功认证完成后的回调(事件通知于 登陆/认证 成功后)。
  • 推荐用法 :开发者可在此回调中进行登陆IM服务器成功后的处理。

13)IMSDK.callback_onIMAfterLoginFailed(isReconnect):

  • 用途:由开发者设置的回调方法:客户端的登陆请求被服务端认证失败后的回调(事件通知于 登陆/认证 失败后)。
  • 说明 :登陆/认证失败的原因可能是用户名、密码等不正确等,但具体逻辑由服务端的 callBack_checkAuthToken回调函数去处理。
  • 推荐用法:开发者可在此回调中提示用户登陆IM服务器失败。。
  • 参数1: {boolean}:true表示是掉线重连后的认证失败(在登陆其间可能用户的密码信息等发生了变更),否则表示首次登陆时的认证失败。

14)IMSDK.callback_onIMReconnectSucess():

  • 用途:由开发者设置的回调方法:掉线重连成功后的回调(事件通知于掉线重连成功后)。
  • 推荐用法 :开发者可在此回调中处理掉线重连成功后的界面状态更新等,比如设置将界面上的“离线”文字更新成“在线”。

15)IMSDK.callback_onIMDisconnected():

  • 用途:由开发者设置的回调方法:网络连接已断开时的回调(事件通知于与服务器的网络断开后)。
  • 推荐用法 :开发者可在此回调中处理掉线时的界面状态更新等,比如设置将界面上的“在线”文字更新成“离线”。

16)IMSDK.callback_onIMPing():

  • 用途:由开发者设置的回调方法:本地发出心跳包后的回调通知(本回调并非MobileIMSDK-H5端核心逻辑,开发者可以不需要实现!)。
  • 推荐用法 :开发者可在此回调中处理底层网络的活动情况。

17)IMSDK.callback_onIMPong():

  • 用途:由开发者设置的回调方法:收到服务端的心跳包反馈的回调通知(本回调并非MobileIMSDK-H5端核心逻辑,开发者可以不需要实现!)。
  • 推荐用法 :开发者可在此回调中处理底层网络的活动情况。

18)IMSDK.callback_onIMShowAlert(alertContent):

  • 用途:由开发者设置的回调方法:框架层的一些提示信息显示回调(本回调并非MobileIMSDK-H5端核心逻辑,开发者可以不需要实现!)。
  • 说明 :开发者不设置的情况下,框架默认将调用wx.showModal()显示提示信息,否则将使用开发者设置的回调——目的主要是给开发者自定义这种信息的UI显示,提升UI体验,别无它用】。
  • 参数1:{String}:必填项,文本类型,表示提示内容。

19)IMSDK.callback_onIMKickout(kickoutInfo):

  • 用途:由开发者设置的回调方法:收到服务端的“踢出”指令(本回调并非MobileIMSDK-H5端核心逻辑,开发者可以不需要实现!)。
  • 参数1 :{PKickoutInfo}:非空,详见:PKickoutInfo

20)IMSDK.callback_onMessagesLost(lostMessages):

  • 用途:由开发者设置的回调方法:消息未送达的回调事件通知。
  • 发生场景 :比如用户刚发完消息但网络已经断掉了的情况下,表现形式如:就像手机qq或微信一样消息气泡边上会出现红色图标以示没有发送成功)。
  • 建议用途:应用层可通过回调中的指纹特征码找到原消息并可以UI上将其标记为“发送失败”以便即时告之用户。
  • 参数1:{Array}:由框架的QoS算法判定出来的未送达消息列表。

21)IMSDK.callback_onMessagesBeReceived(theFingerPrint):

  • 用途:由开发者设置的回调方法:消息已被对方收到的回调事件通知。
  • 说明 :目前,判定消息被对方收到是有两种可能:1) 对方确实是在线并且实时收到了;2) 对方不在线或者服务端转发过程中出错了,由服务端进行离线存储成功后的反馈(此种情况严格来讲不能算是“已被收到”,但对于应用层来说,离线存储了的消息原则上就是已送达了的消息:因为用户下次登陆时肯定能通过HTTP协议取到)。
  • 建议用途:应用层可通过回调中的指纹特征码找到原消息并可以UI上将其标记为“发送成功”以便即时告之用户。
  • 参数1:{String}:已被收到的消息的指纹特征码(唯一ID),应用层可据此ID找到原先已发的消息并可在UI是将其标记为”已送达“或”已读“以便提升用户体验。

五、前端开发指南

5.1如何引入SDK文件到您的前端工程中?

很简单:只需要将第2节中提到的SDK所有JS文件复制到您的Uniapp工程下即可。

SDK内容见下图:

5.2如何在代码中调用SDK?

第一步:在你的网页中引用SDK的js文件(具体例子详见Demo中的index.html文件)

第二步:直接在你的JS文件中编写回调配置代码(具体例子详见Demo中的index.js文件)

第三步:在你的JS文件中调用IM的登陆方法即可(具体例子详见Demo中的index.js文件)

注意:上图中登录连接的IP地址请设置为您的MobileIMSDK服务器地址哦。

六、Demo运行方法(在WebStorm中直接预览)

6.1重要说明

特别说明:MobileIMSDK的H5端(包括Demo在内),全部是静态的HTML+JS资源,可以通过WebStorm自带的HTML页面预览功能,直接自动加载到电脑的浏览器中运行和预览。

6.2预览方法

1)在Demo中的index.html文件中,移动鼠标,会在右上角出现如下图所示的浮出菜单:

2)点击右上角浮出菜单上相应的浏览器就可以自动预览了这里以我电脑上已安装的Edge浏览器为例):

七、Demo运行方法(在Web服务器中部署并访问)

7.1重要说明

特别说明:MobileIMSDK的H5端(包括Demo在内),全部是静态的HTML+JS资源,对于服务端是没有任何依赖的,只需要保证浏览器端能加载到即可,可以把它们放置在Tomcat、Apache、IIS、Nginx等等传统Web服务器中即可,无需任何动态运行环境。

7.2安装Tomcat

提示:以下Demo的部署,以Java程序员最常用和Tomcat为例(Apache、IIS、Nginx等依此类推)。

Tomcat的安装就没什么好说的,直接官网下载对应的版本即可:https://tomcat.apache.org/download-90.cgi

7.3配置要连接的MobileIMSDK服务器IP

注意:下图中登陆连接的IP地址请设置为您的MobileIMSDK服务器地址哦。

友情提示: MobileIMSDK的服务端该怎么部署就不是本手册要讨论的内容了,你可以参见《即时通讯框架MobileIMSDK的Demo使用帮助:Server端》。

▲ 配置要连接的服务器IP(以上代码详见demo/index.js 文件)

7.4部署Demo

说“部署”有点扯蛋,因为Demo(包括SDK)在内,全是HTML静态内容,只需要直接复制到任何一种Web服务器即可。

以下是复制到Tomcat服务器网页目录后的截图:

7.5启动Tomcat

提示:本手册中仅以启Tomcat为例,Apache、IIS、Nginx等Web服务器的启动请自动百度。

运行startup.bat启动Tomcat:

7.6Demo的运行效果预览

八、Demo功能预览和说明

九、Demo运行效果实拍图

1)Demo在手机端浏览器中的真机实拍图:

2)Demo在电脑端浏览器中的真机实拍图:

十、更多Demo运行效果截图

1)Demo在PC端浏览器运行效果:

2)Demo在手机端浏览器运行效果:

3)Demo在PC端各主流浏览器的运行效果:

十一、常见问题(FAQ)

11.1为什么浏览控制台下有些log不显示?

原因是浏览器控制台下的日志级别默认进行了过滤,勾选所有日志级别,就能看到SDK的详细日志输出了。

勾选所有的日志输出级别:

然后就能看到SDK中详细的日志输出了(就像下图这样),方便调试和研究:

十二、引用资料

[1] WebSocket 标准API手册

[2] MobileIMSDK开源框架的API文档

[3] MobileIMSDK开源IM框架源码Github地址点此

[4] MobileIMSDK-H5端基本介绍

[5] MobileIMSDK-H5端的开发手册(* 精编PDF版)

[6] MobileIMSDK的Demo使用帮助:Server端

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

posted @ 2024-09-19 13:14 Jack Jiang 阅读(66) | 评论 (0)编辑 收藏

一、基本介绍

MobileIMSDK的H5端是一套纯JS编写的基于标准WebSocket的即时通讯库:
  • 1)超轻量级、极少依赖;
  • 2)纯JS编写、高度提炼,简单易用;
  • 3)基于标准WebSocket协议,客户端兼容性好;
  • 4)支持运行于iOS、Android等移动端浏览器和各种PC端浏览器;
  • 5)能与 MobileIMSDKGithub托管链接)的各种APP原生代码客户端完美互通;
  • 6)可应用于手机端/PC端的网页聊天应用、企业OA、Web端等即时通讯场景。

二、与MobileIMSDK的关系

MobileIMSDK-H5端 是基于标准HTML5的WebSocket协议的 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工程的最新成果。

三、与MobileIMSDK-Web的关系

MobileIMSDK-Web也是一套纯JS编写的Web端即时通讯框架(含服务端)。

MobileIMSDK-Web框架与MobileIMSDK-H5端的相同点:
  • 1)都是Web端即时通讯框架;
  • 2)都是纯JS编写;
  • 3)都可以运行在手机、pc端的浏览器或web容器内。
MobileIMSDK-Web框架与MobileIMSDK-H5端的不同点:
  • 1)MobileIMSDK-Web可以兼容不支持HTML5的旧版浏览器或容器,而MobileIMSDK-H5端必须运行在当前主流的HTML5浏览器或容器;
  • 2)MobileIMSDK-Web需依赖于socket.io这种第3方通信层库,而MobileIMSDK-H5端无任何额外依赖。
我该如何选型?
  • 选择一:如果您的应用必须兼容旧版浏览器(包括旧版IE等)
    那唯一的选择就是MobileIMSDK-Web,因为它存在的主要价值就是为了兼容旧版浏览器;
  • 选择二:如果您的应用只需运行在现今主流的HTML5浏览器或容器
    那么建议您优先使用MobileIMSDK的H5端,必竟直接调用标准HTML5的WebSocket API,要简洁、轻量多了,也没有第3方依赖。

四、设计目标

直接使用原生的WebSocket有以下问题和劣势:
  • 1)功能有限:没有提供心跳保活、断线重连、送达保证(重传和去重)等即时通讯关键算法和逻辑;
  • 2)API 简陋:在如此有限的标准API下,能逻辑清晰和健壮地实现并组合心跳保活、断线重连、送达保证等算法,需要相当高的技术掌控力
  • 3)逻辑耦合:经验欠缺的开发人员,会将WebSocket通信代码与前端UI界面代码混在一起,使得UI界面的编写、维护、改版都非常困难。
针对以上问题,而MobileIMSDK-H5端库将让开发者专注于UI应用层的开发,网络通信层的专业代码交由SDK开发人员,从而解偶UI前端和通信层的逻辑耦合性,大大降低技术复杂性。

总结一下,MobileIMSDK-H5端库的设计目标是为您的Web端IM带来以下便利:
  • 1)前端与通信解偶:前端UI与网络通信代码解耦,UI界面的重构、维护、改版都非常容易和优雅;
  • 2)轻量级和兼容性:受益于标准WebSocket,可很好地运行于现今主流的H5浏览器上,且无需额外依赖;
  • 3)核心内聚和收敛:得益于长期的提炼和经验积累,SDK核心层高度封装,开发者无需理解复杂算法即可简单上手。
  • 4)纯JS轻量级实现:纯JS编写,无Angular、EmberJS、VUE等各种重量级前端框架依赖,方便对接各种既有系统;

五、技术亮点

  • 1)轻量易使用:超轻量级——纯JS编写且极少依赖,高度提炼——简单易用;
  • 2)兼容性很好:基于标准WebSocket,可很好地运行于现今主流的H5浏览器上,且无需额外依赖;
  • 3)断网恢复能力:拥有网络状况自动检测、断网自动治愈的能力;
  • 4)送达保证机制:完善的QoS消息送达保证机制(自动重传、消息去重、状态反馈等),不漏过每一条消息;
  • 5)支持多种设备:支持运行于iOS、Android等移动端浏览器和各种PC端浏览器;
  • 6)通信协议封装:实现了一个对上层透明的即时通讯通信协议模型;
  • 7)身份认证机制:实现了简单合理的身份认证机制;
  • 8)完善的log信息:在开发调试阶段,确保每一个算法关键步骤都有日志输出,让您的运行调试更为便利;
  • 9)前端代码解耦:实现了UI前端代码与sdk网络通信代码解偶,防止前端代码跟IM核心代码混在一起,不利于持续升级、重用和维护;
  • 10)多端协议兼容:实现了与MobileIMSDK各APP端完全兼容的协议模型;

六、文件组成

SDK代码文件概览:

SDK代码文件用途说明:

七、Demo功能预览和说明

八、Demo运行效果实拍图

1)Demo在手机端浏览器中的真机实拍图:

2)Demo在电脑端浏览器中的真机实拍图:

八、更多Demo运行效果截图

1)Demo在PC端浏览器运行效果:

 

2)Demo在手机端浏览器运行效果(点击可看大图 ▼):

3)Demo在PC端主流浏览器的运行效果(点击可看大图 ▼):

十、详尽开发者手册

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

十一、相关资料

[1] HTML5 WebSocket API 文档
[2] MobileIMSDK开源框架的API文档
[3] MobileIMSDK开源IM框架源码Github地址点此
[4] MobileIMSDK-Web框架基础介绍

posted @ 2024-09-18 10:36 Jack Jiang 阅读(62) | 评论 (0)编辑 收藏

     摘要: 本文由得物技术厉飞雨、GavinX分享,原题“得物App白屏优化系列|网络篇”,下文进行了排版和内容优化。1、引言图片加载作为重中之重的App体验指标,端侧的白屏问题则是其中最为严重、也是最为常见的问题之一。想象一下如果你在浏览交易商品、社区帖子等核心场景下,图片无法完成加载是多么糟糕的体验。如上图所示,通过线上白屏问题归因,我们看到网络问题导致比例最高,占比达81.97%...  阅读全文

posted @ 2024-09-12 11:02 Jack Jiang 阅读(76) | 评论 (0)编辑 收藏

     摘要: 【来源申明】本文引用了微信公众号“鲜枣课堂”的《老司机揭秘手机定位技术,这下彻底明白啦!》文章内容。为了更好的内容呈现,下文在引用和收录时内容有改动,转载时请注明原文来源信息,尊重原作者的劳动。1、系列文章引言1.1适合谁来阅读?本系列文章尽量使用最浅显易懂的文字、图片来组织内容,力求通信技术零基础的人群也能看懂。但个人建议,至少稍微了解过网络通信方面的知识后再看,会更有收...  阅读全文

posted @ 2024-09-11 12:07 Jack Jiang 阅读(82) | 评论 (0)编辑 收藏

     摘要: 【来源申明】本文引用了微信公众号“鲜枣课堂”的《坐高铁手机没信号?原因远比你想的要复杂!》文章内容。为了更好的内容呈现,本文在引用和收录时内容有改动,转载时请注明原文来源信息,尊重原作者的劳动。1、系列文章引言1.1适合谁来阅读?本系列文章尽量使用最浅显易懂的文字、图片来组织内容,力求通信技术零基础的人群也能看懂。但个人建议,至少稍微了解过网络通信方面的知识后再看,会更有收...  阅读全文

posted @ 2024-09-06 12:02 Jack Jiang 阅读(82) | 评论 (0)编辑 收藏

本文由携程技术Jim分享,原题“日访问过亿,办公IM及开放式平台在携程的实践”,下文进行了排版和内容优化。

1、引言

携程内部的办公IM项目最早在2016年立项,经历了初期简单办公场景下的纯IM服务,到支持简单办公组件的IM应用,又演变为一体化办公集成平台,进而演变为目前集成IM功能的开放式企业效率平台。

本文总结了携程办公IM这些年的发展历程及未来的演进方向,并着重从高可用、高性能和可扩展的角度,探讨开放式平台的技术实现及发展方向。

 
 

2、关于作者

Jim:携程高级研发经理,关注Java & Go技术栈后端研发。目前致力于TripPal开放平台的高可用、开放化进程及核心衍生服务。

3、什么是IM

IM(Instant Message)即时消息,是一种通过网络提供实时消息传输的在线沟通技术。

在移动互联网时代,IM的使用变得越来越广泛,通过各种技术手段使得用户之间的交流成本变的极低,沟通效率和用户体验有极大的提升。而且IM的出现极大地改变了目前互联网应用的形态,多数互联网应用只要做到了一定规模,一定会有自身IM的需求,而不是单纯地仅仅依托第三方(例如微信、云信等)。

PS:关于什么是IM,您也可详读专题文章《零基础IM开发入门(一):什么是IM系统?》。

4、 携程办公IM的发展历程

早期携程使用微软的IM软件lync和自研的纯IM软件CtripTeam来支持企业内的沟通需求,这些软件在维护性、拓展性和可用性上都或多或少存在一些缺陷。同时随着互联网的发展,也逐渐不适合日益增长的办公需求和用户体验。

2017年左右,使用基于ejabberd+erlang的自研IM服务的Cchat项目应运而生,该项目的主要目标是在采用自研IM的基础上,实现IM与办公的结合。在完善IM服务的基础上,支持了一些常规的办公场景,如电话、假单、考勤、OA等,通常采用嵌入外部页面、跳转外部地址等方式提供服务。这个改造项目奠定了携程办公IM继续发展的基础。

随着项目的深入,最初的系统交互模式及服务管理模式逐渐不适用越来越复杂的办公场景及服务治理需求。于是在2019年上马了TripPal的改造项目,在结合公司国际化战略的基础上,倾力打造小程序平台,服务号等基础服务。在梳理、优化原有服务的同时,打造了诸多衍生服务。

2020年中开始,在继续推进企业内办公一站式平台的基础上,我们需要支持更多的外部场景,实际需求促使我们向开放式平台转型,这在服务整体架构、安全性、扩展性等方面都提出了新的要求及挑战。

5、携程TripPal开放平台总体架构

5.1Gateway网关层

这一层是所有请求调用流量的入口,主要功能如下:

  • 1)服务路由;
  • 2)集中式限流、风控、日志监控等功能;
  • 3)调用IDS (Identity Service) 验证请求的合法性。

第 3)步中验证通过后,可以将用户ID、Token等基本信息,通过 HttpHeader 的方式向后端服务透传,后端服务可以直接使用UserID,也可以再次对Token进行认证

5.2IDS (Identity Service) 服务

IDS同时支持多种不同类型的访问令牌的鉴权,同时还负责令牌的颁发,以及RBAC+模块级别的接口控权。

另外,针对开放小程序,TripPal提供两种认证方式:

1)常规的Oauth第三方模式接入:

2)另一种是基于Oauth+开放平台签名的第三方认证,对于接入方相对简单:

5.3微服务层

这一层是整个系统的业务层,具体包含三种类型的微服务:

  • 1)TripPal开放平台内部系统微服务:只有在特定用户认证和权限验证通过之后,外部才能访问;
  • 2)开放平台对外提供的OpenAPI:采用Oauth+RBAC的方式控制权限;
  • 3)自研小程序后端服务:根据安全需要,所有使用Oauth+模块权限的第一方小程序服务端。

目前TripPal自身的核心微服务应用达到28个,提供全集团的多端(C端、B端)基础服务能力,服务全公司超过500个业务应用,在线C端用户均值超过2万,日访问量超过亿。

6、 TripPal的IM服务

目前TripPal使用完全自研的基于Java实现的类ejabberd架构,底层采用的XMPP协议进行通讯。

Tips:

XMPP全称是ExtensibleMessageing and Presence Protocol,可扩展消息与存在协议。是目前网络上开源,最灵活,应用最广泛的一种即时消息通信协议。

1999年Jeremie Miller,首先提出了Jabber,一种为实现即时消息和存在的开放技术,后续基于这个协议,开发了一个开源的服务实现jabberd。后续,IETF国际标准组织介入,成立Extensible Messageing and Presence Protocol(XMPP)工作组,并开始标准化工作。

2000年,jabberd服务器1.0版本发布,那时Jabber协议的基本特点(基于XML的流,消息,存在,联系人列表等)都被固定下来。

2004年,IETF出版了RFC 3902和RFC3921,定义了XMPP的核心功能,成为推荐标准。

后续在2011年,IETF出版了RFC6120和RFC 6121,更新了XMPP的核心定义,替代了之前的RFC 3920和3921。

目前XMPP协议被XMPP Standards Foundation负责管理运作,集中于在IETF定义的基础XMPP规范之上,如何开发开放的协议扩展。

IM服务端做了大量的系统性的优化,从底层的数据库调优、底层通讯服务升级,到上层消息、群、群成员等核心功能的大幅改造。

底层通讯服务由之前的erlang完整迁移至java技术栈,服务可靠性、弹性伸缩、安全性和性能获得了提升。同时对上层偏业务的服务进行了改造,极大地提升了接口响应,服务稳定性也得到了提升,为整个产品的研发提供了重要支撑。

目前这套自研的IM 3.0服务在生产环境稳定运行,整体资源消耗比2.0时期有较大下降。

7、 TripPal办公衍生服务

7.1概述

在实际的企业办公场景下,尤其是大型企业复杂组织架构和管理模式的场景下,TripPal逐渐摸索出了自己的一套行之有效且契合携程场景的办公智能应用,如搜索中台,消息卡片,智能审批中台,角色服务,工作流引擎等。

本文简单介绍其中3个服务。

7.2智能审批中台

智能审批中台在集成携程自有的审批系统的同时也集成了自研的智能审批配置服务,该服务支持用户自定义整个审批单及审批流的全部细节。

 

7.3角色服务

角色服务在灵活定义角色范围及基础角色的基础上,支持用户灵活调整,动态管理,且自动接入审批中台,同时打通应用对接渠道。

整个角色服务在产品定义上分为如下表4个主要概念:

7.4在线文档

在线文档服务主要提供文档的在线协作能力,支持用户同时/实时的查看、编辑、保存和分享的能力。同时结合IM实现通知和反馈等功能。

技术实现上,在线文档是采用CRDT算法实现的无冲突merge(LastWrite Wins)、多端最终一致的分布式方案,同时兼具高可用、可容错的特性,在服务器发生故障时,允许Shift至另一台机器上继续执行,即使服务端完全宕机,客户端依然能够离线工作。

8、 TripPal高可用的实践

目前TripPal部署在3个机房,分为公有云1个机房及私有云2个机房。

总体架构在应用多机房部署、数据层跨机房DRC的基础上,采用就近访问的原则进行服务访问,其中一旦发生任意2个机房全挂的情况,都能保证系统内的核心应用仍能提供服务。

其中公有云机房的一期部署方案已经完成,二期部署方案和测试计划预计于7月完成,届时可以和大家分享一下混合云方案的一些细节和历程。

9、 开放平台的未来架构及演进方向

9.1概述

开放平台主要面向两类群体,开发者和用户。

所以主要有两个方向:

1)一是便捷开发,主要围绕降低开发者门槛、较低研发成本,打通不同开发者、应用之间的壁垒,实现生态共享。

2)另一方面,针对实际用户,在提高用户体验、数据安全的同时,实现用户服务能力整合和主动发现。

9.2开发者

在这方面,目前主流开放平台已经对开发者提供了强大的支持。

主要形式分为以下3种。

1)前端信任:

前端信任的目的是通过减少或杜绝开发者后端跟开放平台OpenAPI交互的方式,来降低开发者接入门槛,减少工作量。主要的做法是通过权限控制、签名、加密等手段使得小程序能够在前端拿到可信数据。

2)低代码(Low-Code):

由于大量的互联网业务属于简单交互或模型化交互,以此为出发点,基于构建合理模型、简单业务函数等形式,可以允许开发者通过拖拽组件、简单伪业务代码等形式提供编程入口,可以大幅度降低开发者的研发门槛和成本,打破用户和开发者界线,提高开放平台整体生态的活力。

3)ServerLess:

基于云原生的ServerLess结合低代码,开放开发者的云端编程入口,同时提供云端基础组件,允许开发者无需部署实际的后端应用服务,极大降低的开发者的运营维护门槛。

9.3用户层面

目前业界主流开放平台在对用户本身的服务能力整合和挖掘上,投入的都比较少,也没有比较成熟的实践,我们认为在这方面可以围绕两个点展开。

一方面:第三方应用治理模式向商城化的转型。常规开放平台的应用治理和推广,基本是应用方独立管理和推广,但是随着应用数量的大幅度增加,以及应用方单方面推广难度较大等原因,亟需开放平台从生态整体角度进行支持和治理。这样可以在安全性、可维护性、便捷性等维度上对应用进行正向反馈,实现开放平台应用生态的可持续性和能力共享。同时,在特定场景下,结合用户分析、大数据及AI,提高用户主动或被动的应用发现能力。

另一方面:构建符合应用间开放协议的软件联盟,打破应用壁垒,围绕服务集成、开放应用的核心原则,使得不同的互联网业务或行为在一定程度上实现数据/能力共享。一般情况下,一个复杂互联网业务通常由多个异构子业务/子应用构成,这样,通过应用拆分、开放共享等形式,在一定程度上使复杂的互联网业务更加精细化、轻量化、可扩展。

9.4开放平台标准化、互通

目前国内外各大互联网公司、机构和组织都搭建了多种开放平台,用于提供各种各样的信息服务,在可以预见的未来,各个平台之间会有一个整合、标准化、互通的可能性。

那么构建标准开放协议,使得开放平台向底层沉淀的过程则至关重要。

10、 本文小结

通过实现基本IM开放平台架构,以及各种衍生服务,我们总结出了IM开放平台的一些核心能力。

主要是:

  • 1)服务集成:根据不同的业务场景集成并提供相应场景下的基础服务能力;
  • 2)开放应用:提供第三方接入能力;
  • 3)高性能、高可用。

11、参考资料

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

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

[3] 瓜子IM智能客服系统的数据架构设计(整理自现场演讲,有配套PPT)

[4] 从游击队到正规军(一):马蜂窝旅游网的IM系统架构演进之路

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

[6] 浅谈IM系统的架构设计

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

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

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

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

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

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

[13] 阿里IM技术分享(三):闲鱼亿级IM消息系统的架构演进之路

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

[15] 跟着源码学IM(十):基于Netty,搭建高性能IM集群(含技术思路+源码)

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

[17] 直播系统聊天技术(八):vivo直播系统中IM消息模块的架构实践

[18] 融云技术分享:全面揭秘亿级IM消息的可靠投递机制

[19] 得物从0到1自研客服IM系统的技术实践之路

[20] 一套分布式IM即时通讯系统的技术选型和架构设计

[21] 微信团队分享:来看看微信十年前的IM消息收发架构,你做到了吗


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

posted @ 2024-08-29 15:45 Jack Jiang 阅读(77) | 评论 (0)编辑 收藏

     摘要: 【来源申明】本文引用了微信公众号“网优雇佣军”的《是谁偷走了我家的手机信号?》文章内容。为了更好的内容呈现,下文在引用和收录时内容有改动,转载时请注明原文来源信息,尊重原作者的劳动。1、系列文章引言1.1适合谁来阅读?本系列文章尽量使用最浅显易懂的文字、图片来组织内容,力求通信技术零基础的人群也能看懂。但个人建议,至少稍微了解过网络通信方面的知识后再看,会更有收获。如果您大...  阅读全文

posted @ 2024-08-21 17:53 Jack Jiang 阅读(82) | 评论 (0)编辑 收藏

     摘要: 本文由得物技术厉飞雨分享,原题“得物App弱网诊断探索之路”,下文进行了排版和内容优化。1、引言随着得物用户规模和业务复杂度不断提升,端上网络体验优化已逐步进入深水区。为了更好地保障处于弱网状态下得物App用户的使用体验,我们在已有的网络体验大盘、网络诊断工具的基础上研发了弱网诊断能力。该工具能够高效实时诊断用户真实网络环境,同时给出精确网络质量分级,为后续App各业务场景...  阅读全文

posted @ 2024-08-15 11:08 Jack Jiang 阅读(97) | 评论 (0)编辑 收藏

     摘要: 本文来自腾讯手Q基础架构团队杨萧玉、邱少雄、张自蹊、王褚重天、姚伟斌的分享,原题“QQ 客户端性能稳定性防劣化系统 Hodor 技术方案”,下文进行了排版和内容优化。1、引言接上篇《首次公开,最新手机QQ客户端架构的技术演进实践》。防劣化是比较经典的技术话题,手 Q 的防劣化系统从 2021 年 10 月开始投入研发,从 0 到 1 迭代了将近三年的时间,已经达到了业界先进...  阅读全文

posted @ 2024-08-02 10:38 Jack Jiang 阅读(50) | 评论 (0)编辑 收藏

关于RainbowChat

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

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

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

关于MobileIMSDK

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

工程开源地址是:

v11.6 版更新内容

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

(1)Android端主要更新内容:

  • 1)[bug] 解决了APP从后台恢复时,有一定几率因后台多线程操作好友数据导致的线程安全崩溃问题;
  • 2)[优化] 加固了一处好友列表中根据昵称取拼音首字母的非空检查逻辑;

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

  • 1)[bug] 升级了MobileIMSDK至v6.5,尝试解决极小几率下Android端会误把“自已”踢掉的问题
  • 2)[bug] 解决了因Netty库版本升级导致iOS消息推送失败报错的问题:
  • 3)[bug] 解决了消息撤回时,被引用消息的历史记录没有正确处理撤回逻辑;
  • 4)[优化] 为“接口1008-26-7”增加了“at_me”字段的返回;
  • 5)[优化] 优化了“接口1008-26-8”,使得在跟Web互通时支持按时间戳的聊天记录分页加载方案;
  • 6)[优化] 为“接口1008-26-8”增加了“消息发送者昵称”内容的返回;

部分功能运行截图更多截图点此查看):

posted @ 2024-07-26 12:57 Jack Jiang 阅读(91) | 评论 (0)编辑 收藏

一、关于RainbowChat-Web

RainbowChat-Web是一套Web网页端IM系统,是RainbowChat的姊妹系统(RainbowChat是一套基于开源IM聊天框架 MobileIMSDK (Github地址)  的产品级移动端IM系统)。

二、v7.1 版更新内容

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

  • 1)[bug] [前端]   - 解决了转发语音消息后,语音消息ui气泡css样式问题;
  • 2)[bug] [前端]   - 解决了登陆后首次打开对应聊天界面前收到的新消息和历史消息显示顺序问题;
  • 3)[bug] [前端]   - 解决了删除聊天后,没有自动清除聊天界面上的“加载更多”功能按钮;
  • 4)[bug] [前端]   - 解决了引用陌生人消息时,显示的是uid而不是对方昵称的问题;
  • 5)[bug] [前端]   - 解决了群主撤回群员消息时,系统通知中显示的是uid而不是对方昵称的问题;
  • 6)[优化] [前端]   - 优化了引用的消息内容中表情图标导致引用的文字不能垂直居中显示的ui问题;
  • 7)[优化] [前端]   - 优化了群聊中消息发送者昵称的显示;
  • 8)[优化] [服务端] - 为“接口1008-26-8”增加了“消息发送者昵称”内容的返回;

三、主要功能特性截图

主要功能特性截图(更多运行截图运行视频

posted @ 2024-07-26 11:42 Jack Jiang 阅读(74) | 评论 (0)编辑 收藏

     摘要:      本文由京东技术王泽知分享,原题“基于Web的跨平台桌面应用开发”,下文进行了排版和内容优化。1、引言近些年来,跨平台跨端一直是比较热门的话题,Write once, run anywhere一直是开发者所期望的,跨平台方案的优势十分明显。对于开发者而言,可以做到一次开发、多端复用,一套代码就能够运行在不同设备上,这在很大程度上能够降低...  阅读全文

posted @ 2024-07-25 11:08 Jack Jiang 阅读(103) | 评论 (0)编辑 收藏

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

[- 1 -] 移动端实时音视频直播技术详解(一):开篇

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

[摘要] 本文是《移动端实时音视频直播技术详解》系列文章之第一篇,我们将从整体介绍直播中的各个环节。


[- 2 -] 移动端实时音视频直播技术详解(二):采集

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

[摘要] 本文是《移动端实时音视频直播技术详解》系列文章之第二篇:我们将从整体介绍直播中的采集环节。


[- 3 -] 移动端实时音视频直播技术详解(三):处理

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

[摘要] 本篇是《移动端实时音视频直播技术详解》系列文章之第三篇:我们将从整体讲解常见视频处理功能:如美颜、视频水印、滤镜、连麦等。


[- 4 -] 移动端实时音视频直播技术详解(四):编码和封装

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

[摘要] 本篇是是《移动端实时音视频直播技术详解》系列文章之第四篇:我们将从整体讲解编码和封装。


[- 5 -] 移动端实时音视频直播技术详解(五):推流和传输

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

[摘要] 本篇是《移动端实时音视频直播技术详解》系列文章之第五篇:我们将从整体讲解推流和传输。


[- 6 -] 移动端实时音视频直播技术详解(六):延迟优化

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

[摘要] 本篇是《移动端实时音视频直播技术详解》系列文章之第六篇:我们将从整体讲解延迟优化技术。


[- 7 -] 理论联系实际:实现一个简单地基于HTML5的实时视频直播

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

[摘要] 本次分享就向大家介绍一下分享一下直播的整个流程和一些技术点,并动手实现一个简单的Demo。


[- 8 -] 实时视频直播客户端技术盘点:Native、HTML5、WebRTC、微信小程序

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

[摘要] 连麦视频直播的客户端主要包括:原生 APP、浏览器 H5、浏览器 WebRTC、微信小程序。浏览器上的应用包括 H5 和 WebRTC,前者可以拉流观看,后者可以实现推流和拉流。


[- 9 -]  Android直播入门实践:动手搭建一套简单的直播系统

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

[摘要] 实时视频直播是这两年非常火的技术形态,已经渗透到教育、在线互娱等各种业务场景中。但要搭建一套实时视频直播系统,并非易事,当然相关的直播技术理论在论坛的其它文章里已经写的非常详细,本文不再展开。


[- 10 -] 淘宝直播技术干货:高清、低延时的实时视频直播技术解密

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

[摘要] 本文由淘宝直播音视频算法团队分享,对实现高清、低延时实时视频直播技术进行了较深入的总结,希望分享给大家。


[- 11 -] 技术干货:实时视频直播首屏耗时400ms内的优化实践

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

[摘要] 直播行业的竞争越来越激烈,进过2018年这波洗牌后,已经度过了蛮荒暴力期,剩下的都是在不断追求体验。最近正好在做直播首开优化工作,实践中通过多种方案并行,已经能把首开降到500ms以下,借此机会分享出来,希望能对大家有所启发。


[- 12 -] 新浪微博技术分享:微博实时直播答题的百万高并发架构实践

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

[摘要] 本文将分享新浪微博系统开发工程师陈浩在 RTC 2018 实时互联网大会上的演讲。他分享了新浪微博直播互动答题架构设计的实战经验。其背后的百万高并发实时架构,值得借鉴并用于未来更多场景中


👉52im社区本周新文:《IM跨平台技术学习(十二):万字长文详解QQ Linux端实时音视频背后的跨平台实践》,欢迎阅读!👈

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

posted @ 2024-07-11 12:38 Jack Jiang 阅读(102) | 评论 (0)编辑 收藏

     摘要: 本文由QQ音视频团队贺坤分享原题“Linux QQ能打语音视频了!一文详解背后技术实现!”,下文进行了排版和内容优化等。1、引言2024年6月6日,QQ For Linux 3.2.9 正式支持了音视频通话功能,这是 QQ Linux 版本的又一个里程碑事件。 2024 年,QQ 音视频正式推出 NTRTC,全平台(iOS/Android/MacOS/Windows/Lin...  阅读全文

posted @ 2024-07-04 11:31 Jack Jiang 阅读(89) | 评论 (0)编辑 收藏

本文由爱奇艺技术团队分享,作者isno,原题“爱奇艺海外App的网络优化实践”,下文进行了排版和内容优化等。

1、引言

做海外市场,特别目标是面向全球的用户,网络的重要性不言而喻。试想一个移动端应用,比如即时通讯IM,聊天消息的本质就是人跟人在说话,一条消息从发送到接受需要10秒的时间,这恐怕会让用户崩溃,随之就是被无情地卸载,开拓海外市场那就是做梦了。

本次分享的文章内容,基于爱奇艺面向全球用户推出的国际版,在海外跨国网络环境复杂的前提下,针对性地做了一系列弱网优化实践,取得了不错的效果,在此总结分享我们的一些做法和优化思路,希望对你有所帮助。

总结下来,跨国弱网优化实践的几个核心就是:

  • 1)能不请求网络就不请求;
  • 2)请求的链接目标 0-RTT;
  • 3)请求的内容越小越好。

正文内容我们将逐个技术点展开了分享。

 
 

2、系列文章

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

  1. 移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”
  2. 移动端IM开发者必读(二):史上最全移动弱网络优化方法总结
  3. 移动端IM开发者必读(三):爱奇艺移动端跨国弱网通信的优化实践》(* 本文)

如果您是IM开发初学者,强烈建议首先阅读《新手入门一篇就够:从零开发移动端IM》。

3、 跨国弱网样本摸底

在 App 初期版本内增加请求链路的采样。样本数足够的情况下,可以清楚你要推广的市场是怎样的环境。样本数据让我们清楚发现了各个国家、地区网络的问题,在大规模宣传和投入前,做好 App 的基础工作非常重要。

海外用户至海外数据中心的网络延迟(这是监测节点数据,用户端延迟更高):

海外主要国家、地区移动网络情况:

在调研阶段,我们发现了以下问题比较明显,切实影响我们的运营及 App 体验。

这些问题主要是:

  • 1)运营商劫持严重,DNS 劫持、HTTP 劫持;
  • 2)移动端网络复杂 ,东南亚的网络基础建设还待改善;
  • 3)低端 Android 机有一定的占比,数量级别影响决策;
  • 4)国际网络用户端到服务器的延迟高。

在初期阶段,技术工作的核心是解决以上问题,为后续的运营做好基础建设。因为业务接口大部分为 HTTP 形式,就开始围绕 HTTPS 进行针对性改进。

一个HTTPS请求阶段分析:

一个 HTTPS 在第一请求会有 5 个 RTT:

1RTT(DNS)+ 1RTT(TCP 握手)+ 2RTT(TLS1.2)+ 1RTT(HTTP 链接)

如果以端到服务 50ms 延迟为例:

一个 HTTPS 的接口延迟 =  350ms =  50*5+ 100ms(服务端)

如果目标是一个非国内用户,打开首页需要 1.1s, 这个时间显然有点长。

下面开始进行技术改进的正文,以下是概括技术性优化的关键点:

4、基础链路的改进优化

4.1DNS 优化调整

DNS 的解析改为 HTTPDNS,DNS 的改进上线后观察初始连接请求提升 17% 的效率。

目的主要是:

  • 1)解决域名劫持问题 (东南亚地区回传的数据显示有不少劫持);
  • 2)解决 LocalDNS 非就近分配问题;
  • 3)结合业务可以做解析预热。

4.2传输层的优化调整

MTU 的问题 :

  • 1)Client 端和 Server 端不同的 MTU 值会导致丢包率过高。AWS 某些场景实例默认巨型帧:MTU 是 9001,但接收端默认 1500,这时候就会出现一些丢包的现象;
  • 2)如果你用了多个云商服务,用 VPN 组网,IP隧道封装的数据临界 1500,又会造成丢包、包重传问题;
  • 3)最严重的情况:部分网络封杀 ICMP 协议,导致 MTU 无法自动协商。

TCP 拥塞控制优化:

拥塞窗口 CongWin 是未接收到接收端确认情况下连续发送的字节数; 。CongWin 是动态调整,取决于带宽和延迟的积,比如 100MB 的带宽 100ms 的延迟环境。

时延带宽积 = 100Mbps*100ms = (100/8)*(100/1000) = 1.25MB

理论上 CongWin 窗口可以最大化到 1.25MB。CentOS 默认CongWin = 20*MSS,在 29KB 左右,离上限 1.26MB 差太多了,默认值上调TCP的启动会更快。

TCP 快速打开 (TCP Fast Open:TFO):

TCP 的 keepalive 下依然会有链接断掉重建的情况,TFO 是针对这种情况的优化。

TFO 的原理机制:

在我们观察中开启 TFO 机制,海外业务一个 RTT 通常时间在 100ms 以上,HTTP 请求效率提升了 12% 左右。

5、应用层的改进优化

5.1HTTP 的优化

HTTP1.1 有个 keep-alive 作用是复用 TCP 链接,减少新建的消耗,对于浏览器的业务比较适用,但对于移动端这种时间分散的请求,大部分请求还是新建连接。

HTTP1.1 的串行机制有头部阻塞的问题。

5.2SSL 层优化

尽量升级到 TLS1.3(微信的TLS1.3实践:《微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解》),利用 Pre-shared Key 机制,开启 ssl_early_data 可以进一步优化 “0-RTT ”,如果无法升级 TLS 版本,优化密钥算法为 ECDHE,运算速度快,握手的消息往返由 2-RTT 减少到 1-RTT,能达到与 TLS1.3 类似的效果。

TLS 版本的区别:

TLS1.3 经过优化后,一个 HTTP 请求由之前的 4 个 RTT 减少为 3 个 RTT。

5.3升级 HTTP2.0

几个重要的改进点:

  • 1)分帧传输;
  • 2)多路复用;
  • 3)头部压缩。

多路复用:

在 HTTP/2 中,两个非常重要的概念:帧(frame)和流(stream)。帧代表着最小的数据单位,每个帧会标识出该帧属于哪个流,流也就是多个帧组成的数据流。多路复用,就是在一个 TCP 连接中可以存在多条流。这些改进可以避免 HTTP 队头阻塞问题,提高传输性能。

头部压缩:

开发人员如果不注意对 header 内容的控制,会造成 header 内容失控的现象,客户端极容易存储一个非常大的 Cookie。

HTTP2 的分帧传输机制:

5.4边缘节点动态加速

这个是非常有效的方式。

尽可能离用户最近,利用边缘节点对路由、链路进行优化,提高动态服务的效率。相较于直连模式,使用动态加速后,P90 的接口延迟效率提升了 60%。

爱奇艺海外动态加速的效果提升(请求时间为秒):

5.5启用兜底机制

对于失败的请求,启用兜底的协议 QUIC 或者 kcp。

客户端的失败率在 3% 左右,对这部分请求使用 UDP 协议兜底尝试,在我们的观察成功率提升了 45%。

6、传输内容的优化

6.1应用 Brotli

因为预置了字典,在同等级别的压缩率下,对比 gzip 至少提升了 17% 的压缩比,接口平均的 Content-Size 由 30KB,降至 18KB。

6.2接口由 JSON 改为 Google Protobuf

应用 Protobuf 的重要原因是解析效率比 JSON 至少高四五倍,在节点深度和数据量大的情况下更明显。

但注意 Protobuf 内部的 varint 压缩,只对小于 128 的数字进行可变长压缩。实际效果不大,生产环境如果数据量大,外层的压缩如 gzip 不可少。

PS:关于Protobuf的资料,可以进一步阅读《IM通讯协议专题学习》。

6.3图片格式升级为 WebP

在应用 WebP 的同时,降低海报图片的质量,实践看海报的 quality 设置为 85% 肉眼难以分辨,相对同质量的 JPEG 或者 PNG ,可以最大减小 45% 的体积。

应用效果明显。App 打开首页图片的加载提升肉眼可见。

7、业务层面的优化改进

7.1减少不必要请求:

一些通用内容,如导航、频道,通常由运营人员主动更新。

如下图:增加一个启动阶段请求的接口,里面放入内容更新的时间戳,与本地 cache 的时间戳有差异,则异步请求更新。

 

7.2区别用户网络,适应不同的策略

具体作法是:

  • 1)对于视频,非 WiFi 默认启播码率为 360P;
  • 2)对于海报,后端接口提供两种质量的 Url,WiFi 高质,4G 低质。

7.3更多的业务优化

增加请求重试、调整 HTTP 的超时时间,请求缓存等等  这些可以根据业务的需求进行调整。

8、本文小结

爱奇艺海外版APP经过一系列细节优化,用户体验持续上升。用户接口延迟、客户端失败率、视频播放成功率一系列的关键指标得到很大的改善。这也助力爱奇艺在东南亚多个国家的应用市场排名升至 TOP 1。

另外 App 优化、Server 延迟优化、产品体验的改进,这一系列只有相辅相成才可以最大化提升用户体验。

9、参考资料

[1] TCP/IP详解 - 第17章·TCP:传输控制协议

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

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

[4] 现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障

[5] 全面了解移动端DNS域名劫持等杂症:技术原理、问题根源、解决方案等

[6] 美图App的移动端DNS优化实践:HTTPS请求耗时减小近半

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

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

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

[10] 爱奇艺移动端网络优化实践分享:网络请求成功率优化篇

[11] 美团点评的移动端网络优化实践:大幅提升连接成功率、速度等

[12] 淘宝移动端统一网络库的架构演进和弱网优化技术实践

[13] 谈谈移动端 IM 开发中登录请求的优化

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

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

[16] 微信对网络影响的技术试验及分析(论文全文)

[17] 腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(上篇)

[18] IM开发者的零基础通信技术入门(十二):上网卡顿?网络掉线?一文即懂!

[19] 微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解

[20] IM通讯协议专题学习(一):Protobuf从入门到精通,一篇就够!


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

posted @ 2024-06-27 11:51 Jack Jiang 阅读(84) | 评论 (0)编辑 收藏

一、关于RainbowChat-Web

RainbowChat-Web是一套Web网页端IM系统,是RainbowChat的姊妹系统(RainbowChat是一套基于开源IM聊天框架 MobileIMSDK (Github地址)  的产品级移动端IM系统)。

二、v7.0 版更新内容

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

  • 1)[bug] [前端]    - 解决了断网重连后,首页“消息”列表中的item选中状态会消失的问题;
  • 2)[bug] [前端]    - 解决了“清屏”功能不能清除群聊缓存的问题;
  • 3)[bug]  [服务端] - 解决了消息撤回时,被引用消息的历史记录没有被正确处理;
  • 4)[新增] [前端]    - 新增“@”功能;
  • 5)[新增] [前端]    - 新增消息引用功能(支持引用全部消息类型);
  • 6)[新增] [前端]    - 启用了新的“加载更多”功能,支持动态分页加载,提升大量历史聊天记录下的用户体验;
  • 7)[优化] [前端]    - 首页消息列表中的语音消息将显示时长(跟新版微信一样);
  • 8)[优化] [前端]    - 优化了聊天消息中的网址链接显示(自动解析超链接);
  • 9)[优化] [前端]    - 大幅提升聊天界面中加载大量消息时的ui渲染性能;
  • 10)[优化] [前端]   - 其它ui和体验的小细节优化;
  • 11)[优化] [服务端] - 为“接口1008-26-7”增加了“at_me”字段的返回;
  • 12)[优化] [服务端] - 优化了“接口1008-26-8”,使聊天记录支持按时间戳的分页加载方案;
  • 13)[优化] [服务端] - 升级了包括log4j2等在内的一些基础库版本。

三、v7.0 版新增主要特性截图

“@”功能功能运行截图查看演示视频更多运行截图):

“消息引用”功能(查看演示视频更多运行截图):

 

posted @ 2024-06-24 13:25 Jack Jiang 阅读(48) | 评论 (0)编辑 收藏

     摘要: 本文由腾讯技术kernel分享,原题“TCP经典异常问题探讨与解决”,下文进行了排版和内容优化等。1、引言TCP的经典异常问题无非就是丢包和连接中断,在这里我打算与各位聊一聊TCP的RST到底是什么?现网中的RST问题有哪些模样?我们如何去应对和解决?本文将从TCP的RST技术原理、排查手段、现网痛难点案例三个方面,自上而下、循序渐进地给读者带来一套完整的分析方法和解决思路...  阅读全文

posted @ 2024-06-20 12:49 Jack Jiang 阅读(88) | 评论 (0)编辑 收藏

     摘要: 本文由环信技术黄飞鹏分享,原题“实战|如何利用 Electron 快速开发一个桌面端应用”,本文进行了排版和内容优化等。1、引言早就听说利用Electron可以非常便捷的将网页端快速打包成桌面应用,并且利用 Electron 提供的 API 调用可以使用原生桌面 API 一些高级功能。于是这次借着论证 Web IM端 SDK 是否可以在 Electron 生成的桌面端正常稳...  阅读全文

posted @ 2024-06-13 11:53 Jack Jiang 阅读(65) | 评论 (0)编辑 收藏

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

[- 1 -] 一个基于长连接的安全可扩展的订阅/推送服务实现思路

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

[摘要] 本文将从如何保证连接的业务安全(禁止非业务认证的连接订阅消息)和如何扩展能够支持更多的消息和连接两点展开分析。


[- 2 -] 实践分享:如何构建一套高可用的移动端消息推送系统?

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

[摘要] 本文追溯了推送技术的发展历史,剖析了其核心原理,并对推送服务的关键技术进行深入剖析,围绕消息推送时产生的服务不稳定性,消息丢失、延迟,接入复杂性,统计缺失等问题,提供了一整套平台级的高可用消息推送解决方案。实践中,借助于该平台,不仅能提能显著提高消息到达率,还能提高研发效率,并道出了移动开发基础设施的平台化架构思路。


[- 3 -] Go语言构建千万级在线的高并发消息推送系统实践(来自360公司)

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

[摘要] 本文内容整理自奇虎360公司的周洋在 Gopher China 2015 大会上的分享(演讲PPT下载:《Go语言构建高并发消息推送系统实践PPT(来自奇虎360)[附件下载] 》),该次分享以360海量在线的消息推送系统为例,来探讨使用Go语言构建高并发消息推送系统时所遇到的问题以及总结出的各种实践技巧。


[- 4 -]腾讯信鸽技术分享:百亿级实时消息推送的实战经验

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

[摘要] 本文整理了此次甘恒演讲的内容并以文字的方式分享给大家,希望能给技术同行带来一些技术上的启发。



[- 5 -] 百万在线的美拍直播弹幕系统的实时推送技术实践之路

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

[摘要] 本文作者是美拍的架构师,经历了直播弹幕从无到有,从小到大的过程,借此文为大家分享构建弹幕系统的经验,希望能为正在开发或正打算开发弹幕、消息推送、IM聊天等系统的技术同行带来一些启发。


[- -] 京东京麦商家开放平台的消息推送架构演进之路

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

[摘要] 我会详细的介绍下京麦实时消息推送是如何在演变中不断完善的。


[- 7 -] 了解iOS消息推送一文就够:史上最全iOS Push技术详解

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

[摘要] 本文将对iOS Push的在线push、本地push及离线(远程)push进行了详细梳理,介绍相关逻辑、测试时要注意的要点以及相关工具的使用。


[- 8 -] 基于APNs最新HTTP/2接口实现iOS的高性能消息推送(服务端篇)

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

[摘要] 本文要分享的消息推送指的是当iOS端APP被关闭或者处于后台时,还能收到消息/信息/指令的能力。


[- 9 -]  解密“达达-京东到家”的订单即时派发技术原理和实践

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

[摘要] 本文将描述“达达-京东到家”的订单即时派发系统从无到有的系统演进过程,以及方案设计的关键要点,希望能为大家在解决相关业务场景上提供一个案例参考。


[- 10 -] 技术干货:从零开始,教你设计一个百万级的消息推送系统

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

[摘要] 本文主要分享的是如何从零设计开发一个中大型推送系统,因限于篇幅,文中有些键技术只能一笔带过,建议有这方面兴趣的读者可以深入研究相关知识点,从而形成横向知识体系。


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

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

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


[- 12 -] 喜马拉雅亿级用户量的离线消息推送系统架构设计实践

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

[摘要] 本文分享的离线消息推送系统设计并非专门针对IM产品,但无论业务层的差别有多少,大致的技术思路上都是相通的,希望借喜马拉雅的这篇分享能给正在设计大用户量的离线消息推送的你带来些许启发。


[- 13 -] 直播系统聊天技术(三):微信直播聊天室单房间1500万在线的消息架构演进之路

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

[摘要] 本文将回顾微信直播聊天室单房间海量用户同时在线的消息组件技术设计和架构演进,希望能为你的直播聊天互动中的实时聊天消息架构设计带来启发。


[- 14 -] 直播系统聊天技术(四):百度直播的海量用户实时消息系统架构演进实践

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

[摘要] 本文主要分享的是百度直播的消息系统的架构设计实践和演进过程。


[- 15 -] 消息推送技术干货:美团实时消息推送服务的技术演进之路

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

[摘要] 本文将首先从Pike的系统架构升级、工作模式升级、长稳保活机制升级等方面介绍2.0版本的技术演进,随后介绍其在直播、游戏等新业务场景下的技术特性支持,并对整个系统升级过程中的技术实践进行了总结。


[- 16 -] 揭秘vivo百亿级厂商消息推送平台的高可用技术实践

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

[摘要] 本文将要分享的是vivo技术团队针对消息推送系统的高并发、高时效、突发流量等特点,从长连接层容灾、逻辑层容灾、流量容灾、存储容灾等方面入手,如何保证百亿级厂商消息推送平台的高可用性的。


[- 17 -] 得物从零构建亿级消息推送系统的送达稳定性监控体系技术实践

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

[摘要] 本文分享的是得物针对现有的消息推送系统的消息送达耗时、实时性、稳定性等方面问题,从零到一构建完整的消息推送质量监控体系和机制的技术实践。


[- 18 -] B站千万级长连接实时消息系统的架构设计与实践

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

[摘要] 本文将介绍B站基于golang实现的千万级长连接实时消息系统的架构设计与实践,包括长连接服务的框架设计,以及针对稳定性与高吞吐做的相关优化。


👉52im社区本周新文:《IM跨平台技术学习(十一):环信基于Electron打包Web IM桌面端的技术实践》,欢迎阅读!👈

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

posted @ 2024-06-12 14:54 Jack Jiang 阅读(52) | 评论 (0)编辑 收藏

     摘要: 本文由腾讯梁中原分享,原题“红包算法揭秘!哪段代码让你只抢了0.01元?”,下文进行了排版和内容优化等。1、引言在上一篇《来看看微信十年前的IM消息收发架构,你做到了吗》的文章中,有用户提到想了解自己每次微信红包只能抽中 0.01 元的反向手气最佳是怎么在技术上实现的,于是就有了本篇文章的诞生。其实,微信红包最初在产品设计上有过很多思路,最初曾以多档次、按比例分配的方式,但...  阅读全文

posted @ 2024-06-06 12:45 Jack Jiang 阅读(55) | 评论 (0)编辑 收藏

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

[- 1 -] iOS的推送服务APNs详解:设计思路、技术原理及缺陷等

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

[摘要] 本文重点介绍APNs的设计思路、技术原理以及各种缺陷槽点,也希望能给自已设计推送系统的同行带来启发。

[- 2 -] 信鸽团队原创:一起走过 iOS10 上消息推送(APNS)的坑

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

[摘要] 集成推送需要注意些什么?集成之后,怎样确认自己是否正确集成了远程消息推送呢?

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

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

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

[- 4 -] 扫盲贴:认识MQTT通信协议

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

[摘要] MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分。

[- 5 -] 一个基于MQTT通信协议的完整Android推送Demo

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

[摘要] 本文主要介绍的是基于MQTT实现一个简单的Android消息推送系统。更多推送技术资料请见:http://www.52im.net/forum.php?mod=collection&action=view&ctid=11

[- 6 -] 求教android消息推送:GCM、XMPP、MQTT三种方案的优劣

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

[摘要] 对各个方案的优缺点的研究和对比,推荐使用MQTT协议的方案进行实现,主要原因是在文中。

[- 7 -] IBM技术经理访谈:MQTT协议的制定历程、发展现状等

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

[摘要] MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分。

[- 8 -] 移动端实时消息推送技术浅析

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

[摘要] 本文将从移动端无线网络的特点来谈谈实时消息推送的技术原理及相关问题,希望能给你带来些许启发。

[- 9 -]  扫盲贴:浅谈iOS和Android后台实时消息推送的原理和区别

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

[摘要] 本文将从原理上谈谈两个平台上实时消息推送的区别。

[- 10 -] 绝对干货:基于Netty实现海量接入的推送服务技术要点

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

[摘要] 通过本文的案例分析和对推送服务设计要点的总结,帮助大家在实际工作中少走弯路。

[- 11 -] 移动端IM实践:谷歌消息推送服务(GCM)研究(来自微信)

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

[摘要] 本文主要内容由微信开发团队人员编写,来自 WeMobileDev

[- 12 -] 为何微信、QQ这样的IM工具不使用GCM服务推送消息?

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

[摘要] 同样是IM软件,为什么微信不使用GCM的机制而要自己开启一个Service常驻后台轮询,并且还要使用多种方式触发该Service导致无法关闭,这种机制既耗电又浪费网络资源,微信放弃成熟的GCM推送机制而使用自身后台服务的软件是否有其他自身目的性?还是说微信某些功能必须自身常驻呢?

[- 13 -] 极光推送系统大规模高并发架构的技术实践分享

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

[摘要] 2016年的双十一大促改改过去,作为国内第三方推送服务的领导者,极光(JIGUANG)采取了哪些措施来应对高并发推送服务?同时,极光基于 ICE 打造高可用云推送平台,其背后有哪些技术细节值得探索?

[- 14 -] 从HTTP到MQTT:一个基于位置服务的APP数据通信实践概述

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

[摘要] 基于以上业务场景,如此频繁的数据交互,要达到数据的实时推送级别,该选用哪种技术?HTTP短轮询还是基于TCP的实时长连接?本文给出的答案是使用MQTT协议,请继续往下阅读。

[- 15 -] 魅族2500万长连接的实时消息推送架构的技术实践分享

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

[摘要] 此文内容整理自魅族架构师于小波在“魅族技术开放日”的演讲分享,本次演讲中于小波分享了魅族在实现2500万长连接的实时消息推送系统中所遇到的坑和一些心得体会,希望对实时消息推送技术相关的技术同行有所启发和帮助。

[- 16 -] 专访魅族架构师:海量长连接的实时消息推送系统的心得体会

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

[摘要] 本文内容来自ChinaUnix的IT名人堂对魅族系统架构师于小波的专访,于小波分享了在构建魅族海量长连接的实时消息推送系统过程中所总结出的各种心得和体会,希望对正在或即将开发消息推送系统的开发者同行带来一些启发。请往下看正文。

[- 17 -]  深入的聊聊Android消息推送这件小事

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

[摘要] 微信由于有国际版,将 GCM 作为辅助公共通道,但仅用于激活微信自己的 Push 通道,并没有通过 GCM 来传递数据,这点也是为了复用心跳的优化策略和数据处理逻辑。

[- 18 -] 基于WebSocket实现Hybrid移动应用的消息推送实践(含代码示例)

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

[摘要] 本文将围绕 Hybrid App(以Cordova为例)的 WebSocket 消息推送进行一系列的实践性探索。

👉52im社区本周新文:《社交软件红包技术解密(十三):微信团队首次揭秘微信红包算法,为何你抢到的是0.01元》,欢迎阅读!👈

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

posted @ 2024-06-05 11:56 Jack Jiang 阅读(14) | 评论 (0)编辑 收藏

本文由腾讯技术何金源分享,原题“不畏移山,手机QQ技术架构升级变迁史”,本文进行了排版和内容优化等。

1、引言

接上篇《总是被低估,从未被超越,揭秘QQ极致丝滑背后的硬核IM技术优化》,本文则将重点介绍手机 QQ 客户端技术架构升级背后的故事。

手机 QQ 经过20多年发展,功能不断增加,代码不断累积,架构已经变得越来越臃肿,影响到协作团队开发效率,对用户体验、质量稳定都有较大风险,因此手机 QQ 亟需技术架构的升级。但是对如此庞大的项目进行架构升级,在行业内也是少有的,手机 QQ 架构升级面临的困难和挑战都十分巨大,本文将围绕最新手机 QQ 客户端项目背景、项目历程、项目挑战、项目成果等方面进行深入介绍。

 
 

2、手机QQ的历史包袱

在过去20多年里,手机 QQ 从原来纯粹的即时通讯IM工具,成长为承载了空间、频道、短视频、超秀、增值服务等众多业务的平台。

随着业务越来越复杂,最初设计的技术架构变得越来越不适配,业务相互之间耦合越来越严重,时常会遇到改一个问题,牵扯出 N 个问题,问题改不动,代码债越积越多的情况,历史的包袱如同一座大山横在每一位手机 QQ 项目成员面前。

2020年,我们开始着手做架构升级。

鉴于手机 QQ 的业务复杂度、代码量级都非常大,评估下来架构升级的工作量大得惊人,于是我们采用分阶段、逐步演进的策略去进行架构升级。

整体回顾,手机 QQ 的架构升级时间线是这样的:

3、“解耦重构”架构设计

虽然历史包袱如同一座大山,但是手机 QQ 项目成员也有移山的意志和决心。

在2020年,手机 QQ 启动了名为“工业化实践”的技术架构升级项目,这标志着手机 QQ 工程首次系统性地进行业务边界划分、解耦和重构升级。

从上图可看出,旧架构虽然有模块化和插件化,但存在以下不足:

  • 1)边界不清晰:主工程承载基础和大部分业务代码,导致基础和业务代码边界不清晰;
  • 2)代码耦合紧:基础核心类持续膨胀、业务之间代码依赖不合理;
  • 3)开发效率低:代码修改扩散造成 CR、解冲突、定位问题成本高,同时拖慢编译速度。

针对以上不足,对手机 QQ 工程重新设计了架构:

1)新架构按业务划分模块,业务模块之间是相互解耦的,业务模块之间通过接口和路由进行通信;

2)同时按层级设计划分,层级自上而下依赖,上层模块可依赖下层模块,但下层模块不能逆向依赖上层模块。

手 Q 客户端新架构:

新架构的主要收益:

  • 1)模块更加内聚:新特性开发影响范围逐步收敛到模块内部,提升研发效率;
  • 2)接口更加清晰:依赖数减少,可测性提升,更易于通过单元测试、接口测试保障代码逻辑正确性,提升产品质量。

4、“解耦重构”的实践历程

4.1概述

手机 QQ 工程各个业务之间的依赖非常严重,对它进行解耦重构不是一蹴而就的事情,需要按阶段制定目标,一步一步地优化。

通过整理,手机 QQ 工程解耦重构划分为以下三个阶段。

4.2阶段一(2020.11 - 2021.2)

基本完成约300万行核心代码的解耦,一共约30个基础模块和40个基础组件完成解耦,核心业务模块基本完成解耦。

开发新功能时,因为接口与服务实现是隔离的,通过接口依赖的代码不会再耦合严重。

4.3阶段二(2021.3 - 2021.6)

目标:业务模块继续解耦,建设防劣化机制。

成果:

  • 1)API 代码占比与依赖数不增加;
  • 2)完成防劣化机制搭建,在合入阶段拦住不合理修改;
  • 3)完善动态化能力,优化插件与宿主间通信机制和发布效率。

4.4阶段三(2021.7 以后)

目标:进一步完善基础模块和组件化,实现子工程化。

成果:

  • 1)完善基础模块和公共组件重构,建立基础模块发布组件流程;
  • 2)对频道、小世界业务实现子工程化,独立编译运行。

5、“解耦重构”的技术收益

在重构基础上,梳理依赖关系,通过三个阶段改善模块化水平,提高编译速度和研发效率,流水线的编译耗时提升50%。

代码冲突方面也得到明显改善,对比重构前后数据,冲突文件数减少60%,冲突次数减少30%,大大提升开发效率。

6、手机QQ下一代架构:NT架构

在成功迈出改革的第一步之后,我们将注意力转向了手机 QQ 面临的版本碎片化问题。

不同端各自发展,形成了所谓的“烟囱式”结构,其中代码的复用率极低。这种结构带来了多端体验不一致、端内业务体验参差不齐以及每次版本更新时高昂的开发和维护成本等问题。

为了解决这些问题,并在提升用户体验、优化性能和提高研发效率方面实现突破,我们不得不深入思考。

正是这些迫切的需求和挑战促使我们启动了改革的第二步——推进手机 QQ NT 架构升级项目。

在 NT 架构设计之初,我们坚定认为不应该继续缝缝补补,而是应该采用最新且合理的技术理念,摒弃了简单的修补式方法。这次升级不仅是技术上的一次大刀阔斧的改造,更是一场深思熟虑的技术转型。

我们重视在不造成架构大规模动荡的前提下,制定了一条清晰、可行的实施路径。目标是以更少的人力投入实现更高的工作效率和成果,确保了升级过程中的高效和稳健。这种方法不仅保证了项目的顺利进行,也为未来的技术发展和迭代奠定了坚实的基础。

7、NT架构落地之难

由于手机 QQ 的历史悠久且拥有庞大的用户群,该项目在业务和用户层面都展现了巨大的复杂性。

具体来看,项目层面的挑战包括:

  • 1)代码总量庞大:手机端代码近千万行,形成了一个技术上的庞然大物;
  • 2)测试复杂性高:测试用例众多,功能繁杂,且存在部分文档缺失的情况;
  • 3)依赖组件过时:项目中依赖了一些陈旧且缺乏维护的组件,以及大量无人维护的二进制库;
  • 4)研发流程保障:在进行架构升级的同时,必须确保研发工作流程能够平稳过渡,以免影响到研发效率。

用户层面上的挑战则包括:

  • 1)在长达一年以上的升级过程中,日常版本需要正常迭代;
  • 2)用户本地数据量巨大,如超过 10G 的本地消息数据库;
  • 3)项目需在技术优化的同时提升用户体验与活跃度,确保技术优化在用户端实现价值。

面对这些复杂度,项目的核心难点主要集中在以下三个方面。

1)海量功能项目的架构升级和统一:针对全终端、全功能和全项目团队的整体升级,确保架构升级过程中不能有任何缺失。手机 QQ 是在发展了20多年进行彻底重构,难度空前,没有资料可参考。

2)IM 全链路架构重写升级:解决陈年技术债,优化消息架构,平稳迁移用户历史数据,并提升消息性能。QQ 消息架构有陈年技术债,很多 QQ 历史版本里,没有统一的消息 ID 生成规则,没有统一的存储和索引方案,消息类型也是无序扩张。所以,既需要对IM全链路重写优化,同时在过程中,还需要平稳迁移用户历史数据,最终完成升级,保护用户数据、用户体验不受影响。

3)用户体验提升与活跃数据提升:逐步优化核心功能体验,不影响用户习惯,通过提升体验推动产品数据增长。代码的重写不能全盘一次性推倒重来。核心功能体验要保持,逐步优化,不能影响用户使用习惯。

这些挑战不仅说明了手机 QQ NT 架构升级项目的复杂性,也证明了我们在面对前所未有的技术难题时的决心。

8、NT架构设计

为了实现架构升级和统一,项目团队先用 C++ 开发了具备 QQ IM 核心功能的跨平台内核层:把 IM 核心业务逻辑(好友、群、频道等消息逻辑、资料与关系链逻辑、图片语音视频等富媒体收发逻辑、实时音视频逻辑等),QQ 通用组件(数据库、协议编解码、网络传输等),以及线程/网络/IO 等通用资源管理模块和操作系统封装部分,由原来的各平台原生语言实现,统一下沉到 C++ 跨平台层。

为了控制项目质量风险,NT 跨平台内核先接入用户量相对较少,对功能补齐紧迫度高的桌面端,完全用新架构重写桌面端。

在桌面端成功完成功能验证和质量测试之后,我们开始了向移动端的迁移工作,并顺利完成了 iOS 和安卓平台的集成。

当然,移动端的接入远远不像图中描述的这般容易,接下来将介绍其中的解决方案和主要过程。

9、 IM客户端全链路重写升级

在新的 NT 架构基础上,对 QQ 来说,最核心的技术升级,是 IM 全链路的升级。

IM 消息数据源复杂,历史包袱很重,升级过程的遇到的第一个难点就是数据转换及存量数据迁移到新版本问题。

比如:

  • 1)老版本的 QQ,好友消息没有唯一标识字段,导入和去重影响大;
  • 2)2012年以前的版本,群消息没有支持漫游,消息无唯一字段;
  • 3)各平台消息数据格式不同,复杂度高,iOS 和 Android 分别有约200种消息类型;
  • 4)富媒体(图片、视频、语音、文件)资源,存储的目录结构、命名都不同;
  • 5)特殊消息,如结构化消息、Ark 消息、小灰条消息,需要做转换,完成业务的梳理和下架工作;
  • 6)还有因为各种功能的变迁带来的遗留数据问题,如已经退出或者解散的群和讨论组等。

所以,首先需要做 IM 的精简。项目团队基于用户价值考虑,零基思维,完成消息格式统一,对消息和会话类型进行彻底精简,为 QQ 消息长治久安打下基础。

有了全端格式统一和类型精简的基础,开始用大小、性能、安全性综合最优方案设计跨平台统一的全新客户端 DB,然后再考虑旧 DB 的数据,如何平稳升级到新 DB。

移动端和桌面端不同,活跃用户全年在线,有些手机本地纯文本消息的 DB 文件超过10G,加上富媒体、文件等,总数据量超过100G,而且移动端又有存储空间小、功耗敏感、后台杀进程等多方面限制,需要设计出一套周密的升级策略,保护用户核心数据资产不丢失。

方案核心要点:

  • 1)断点续导:移动端场景,进程随时可能被杀或退出。确保消息不丢失、不重复;
  • 2)用户分级:跟进消息数据大小,用户分为三类,做不同的体验优化,减少对用户的影响;
  • 3)优化发烫和耗电:限制导入速度,防止手机发烫。手机切后台后停止导入。对消息数据多的用户,引导用户设置在后台导入;
  • 4)监控:做好各种导入异常上报监控,随时跟进用户反馈。

通过设计周密的升级策略,内部多轮推演,外部从百级开始放量,全方位监控,并用兜底策略保障不丢消息。最终结合监控数据和用户反馈数据,完成了全量用户的全量数据平稳迁移新 DB。

10、客户端核心功能优化提升

不仅是消息,在 NT 架构重写升级过程中,对 QQ 核心功能也一起做了更彻底的重构,手机 QQ 原生功能进行了大规模解耦,通用的部分进行优化并下沉为统一的 NT-Runtime 原生组件(NT 组件服务及框架层)。基于重构后的架构,也对性能进行全面优化。

首先是消息相关核心模块的优化。

消息逻辑下沉到 C++ 跨平台,也推动上层进行架构刷新。

以聊天窗口(AIO)为例:基于全新数据流架构 + 数据预加载 + UI 逻辑并行化的设计思路,完成单向数据流驱动与异步加载渲染,系统资源全力供给 AIO 消息列表,最终性能指标提升明显,AIO 内查看、跳转、滑动消息,顺畅丝滑。

核心技术优化方案:

  • 1)采用基于单向数据流的 MVI 架构,实现业务解耦;
  • 2)预加载和异步渲染,实现消息无缝滑动;
  • 3)消息加载并行化,减少首屏和滑动时的加载时间;
  • 4)消息动态加载、释放,优化内存占用。
  • 5)200+业务组件懒加载,实现数据分层和按需加载。

其它 QQ 主场景,如消息列表页、消息与富媒体收发、图片视频查看等,也采用相同的路径进行优化,最终性能全面提升。

11、本文小结

在手机 QQ 超过20年的发展历程中,应用功能的不断扩展和代码量的持续增长积累了巨大的技术债务,给原有的客户端架构带来了沉重的负担。最新版手机QQ通过一系列的架构演变和技术升级,成功地实现了从臃肿不堪到模块化、高效、稳定的转变。

客户端架构由各端烟囱式架构逐步升级为多端跨平台复用的 NT 架构,降低多端维护人力成本,提升 QQ 全端开发效率,为 QQ 的持续发展和技术迭代打下了坚实的基础。

展望未来,QQ 将基于 NT 架构,在技术创新的道路上继续前行,不断进行架构优化和技术升级,为用户提供更加流畅稳定的产品体验。

12、相关资料

[1] 总是被低估,从未被超越,揭秘QQ极致丝滑背后的硬核IM技术优化

[2] 大型IM工程重构实践:企业微信Android端的重构之路

[3] 企业微信针对百万级组织架构的客户端性能优化实践

[4] 微信团队分享:详解iOS版微信视频号直播中因帧率异常导致的功耗问题

[5] 腾讯技术分享:Android版手机QQ的缓存监控与优化实践

[6] 腾讯技术分享:Android手Q的线程死锁监控系统技术实践

[7] 全面解密新QQ桌面版的Electron内存优化实践

[8] 移动端IM实践:iOS版微信界面卡顿监测方案

[9] 微信团队原创分享:Android版微信的臃肿之困与模块化实践之路

[10] 微信Windows端IM消息数据库的优化实践:查询慢、体积大、文件损坏等

[11] 微信团队分享:微信支付代码重构带来的移动端软件架构上的思考

[12] 微信客户端团队负责人技术访谈:如何着手客户端性能监控和优化

[13] 抖音技术分享:飞鸽IM桌面端基于Rust语言进行重构的技术选型和实践总结

[14] 阿里技术分享:闲鱼IM基于Flutter的移动端跨端改造实践

[15] QQ设计团队分享:新版 QQ 8.0 语音消息改版背后的功能设计思路

13、更多鹅厂技术文章汇总

  1. 微信朋友圈千亿访问量背后的技术挑战和实践总结
  2. 腾讯技术分享:腾讯是如何大幅降低带宽和网络流量的(图片压缩篇)
  3. IM全文检索技术专题(二):微信移动端的全文检索多音字问题解决方案
  4. 微信团队分享:iOS版微信的高性能通用key-value组件技术实践
  5. 微信团队分享:iOS版微信是如何防止特殊字符导致的炸群、APP崩溃的?
  6. 微信团队分享:微信Android版小视频编码填过的那些坑
  7. IM全文检索技术专题(一):微信移动端的全文检索优化之路
  8. 企业微信客户端中组织架构数据的同步更新方案优化实战
  9. 微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解
  10. 微信“红包照片”背后的技术难题
  11. 移动端IM实践:iOS版微信的多设备字体适配方案探讨
  12. 腾讯信鸽技术分享:百亿级实时消息推送的实战经验
  13. IPv6技术详解:基本概念、应用现状、技术实践(上篇)
  14. 腾讯技术分享:GIF动图技术详解及手机QQ动态表情压缩技术实践
  15. 微信团队分享:Kotlin渐被认可,Android版微信的技术尝鲜之旅
  16. 社交软件红包技术解密(一):全面解密QQ红包技术方案——架构、技术实现等
  17. 社交软件红包技术解密(四):微信红包系统是如何应对高并发的
  18. 社交软件红包技术解密(十):手Q客户端针对2020年春节红包的技术实践
  19. 微信团队分享:极致优化,iOS版微信编译速度3倍提升的实践总结
  20. IM“扫一扫”功能很好做?看看微信“扫一扫识物”的完整技术实现
  21. 微信团队分享:微信支付代码重构带来的移动端软件架构上的思考
  22. IM开发宝典:史上最全,微信各种功能参数和逻辑规则资料汇总
  23. 微信团队分享:微信直播聊天室单房间1500万在线的消息架构演进之路
  24. 企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等
  25. IM全文检索技术专题(四):微信iOS端的最新全文检索技术优化实践
  26. 微信团队分享:微信后台在海量并发请求下是如何做到不崩溃的
  27. 微信Windows端IM消息数据库的优化实践:查询慢、体积大、文件损坏等
  28. 微信技术分享:揭秘微信后台安全特征数据仓库的架构设计
  29. IM跨平台技术学习(九):全面解密新QQ桌面版的Electron内存优化实践
  30. 企业微信针对百万级组织架构的客户端性能优化实践
  31. 揭秘企业微信是如何支持超大规模IM组织架构的——技术解读四维关系链
  32. 微信团队分享:详解iOS版微信视频号直播中因帧率异常导致的功耗问题
  33. 微信团队分享:微信后端海量数据查询从1000ms降到100ms的技术实践
  34. 大型IM工程重构实践:企业微信Android端的重构之路
  35. IM技术干货:假如你来设计微信的群聊,你该怎么设计?
  36. 微信团队分享:来看看微信十年前的IM消息收发架构,你做到了吗
  37. 长连接网关技术专题(十一):揭秘腾讯公网TGW网关系统的技术架构演进


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

posted @ 2024-05-30 10:24 Jack Jiang 阅读(67) | 评论 (0)编辑 收藏

     摘要: 本文由腾讯云开发者张曌、毕磊分享,原题“QQ 9“傻快傻快”的?!带你看看背后的技术秘密”,本文进行了排版和内容优化等。1、引言最新发布的 QQ 9 自上线以来,流畅度方面收获了众多用户好评,不少用户戏称 QQ 9 “傻快傻快”的,快到“有点不习惯了都”。作为庞大量级的IM应用,QQ 9 从哪些方面做了...  阅读全文

posted @ 2024-05-23 14:20 Jack Jiang 阅读(95) | 评论 (0)编辑 收藏

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

[- 1 -] 高仿Android版手机QQ首页侧滑菜单源码 [附件下载]

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

[摘要] 本文分享的源码高仿了手机QQ的这个效果,希望可以为有相同需求的IM开发者同行节省点撸码时间。


[- 2 -] 开源libco库:单机千万连接、支撑微信8亿用户的后台框架基石 [源码下载]

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

[摘要] libco在2013年的时候作为腾讯六大开源项目首次开源,ibco支持后台敏捷的同步风格编程模式,同时提供系统的高并发能力。


[- 3 -] 分享java AMR音频文件合并源码,全网最全

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

[摘要] 分享java AMR音频文件合并源码,全网最全。


[- 4 -]微信团队原创Android资源混淆工具:AndResGuard [有源码]

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

[摘要] 本文主要是讲述资源混淆组件的用法以及性能,资源混淆组件不涉及编译过程,只需输入一个apk,可得到一个实现资源混淆后的apk


[- 5 -] 一个基于MQTT通信协议的完整Android推送Demo [附件下载]

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

[摘要] 本文主要介绍的是基于MQTT实现一个简单的Android消息推送系统。更多推送技术资料请见:http://www.52im.net/forum.php?mod=collection&action=view&ctid=11


[- 6 -] Android版高仿微信聊天界面源码 [附件下载]

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

[摘要] 微信的聊天界面是挺漂亮的,每条消息都带一个气泡,给人一种很清新的感觉,其实实现起来也不是那么的难,下面我们就来实现一下。


[- 7 -] 高仿手机QQ的Android版锁屏聊天消息提醒功能 [附件下载]

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

[摘要] 今天为大家带来的是,可以在锁屏下弹窗显示消息来提醒用户,可用于移动端IM或消息推送应用中。


[- 8 -] 高仿iOS版手机QQ录音及振幅动画完整实现 [源码下载]

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

[摘要] 高仿iOS版手机QQ聊天界面中录音及振幅动画。


[- -]  Android端社交应用中的评论和回复功能实战分享[图文+源码]

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

[摘要] 页面整体采用了CoordinatorLayout来实现详情页的顶部视差效。同时,这里我采用ExpandableListView来实现多级列表,然后再解决它们的嵌套滑动问题。


[- 10 -] Android端IM应用中的@人功能实现:仿微博、QQ、微信,零入侵、高可扩展[图文+源码]

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

[摘要] 网上已经有一些文章分享了类似功能实现逻辑,但是几乎都是扩展EditText类,这种实现方式肯定不能进入我的首发阵容。你以为是因为它不符合面向对象六大原则?错,只因为它不够优雅!不够优雅!不够优雅!


[- 11 -] 仿微信的IM聊天时间显示格式(含iOS/Android/Web实现)[图文+源码]

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

[摘要] 作为移动端IM的王者,微信无疑处处是标杆,所以本次的消息时间显示格式,直接参照微信的实现逻辑准没错(随大流虽然没个性,但不至于非主流)。


[- 12 -] Android版仿微信朋友圈图片拖拽返回效果 [源码下载]

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

[摘要] 目前的app的动画效果是越来越炫了,很多主流app的图片预览返回都有类似功能,比较常见的是ios自带相册,微信朋友圈等等。自己项目中也有类似功能,最近整理了一下这个功能的代码,做个笔记记录,有兴趣的朋友可以在文末附件下载源码。


[- 13 -] 手把手教你实现网页端社交应用中的@人功能:技术原理、代码示例等

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

[摘要] 本文分享的@人功能是针对Web网页前端的,跟移动端原生代码的实现,从技术原理和实际实现上,还是有很大差异,所以如果想了解移动端IM这种社交应用中的@人实现功能,可以读一下《Android端IM应用中的@人功能实现:仿微博、QQ、微信,零入侵、高可扩展[图文+源码]》这篇文章。


[- 14 -] SpringBoot集成开源IM框架MobileIMSDK,实现即时通讯IM聊天功能

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

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


[- 15 -] 基于Netty,徒手撸IM(一):IM系统设计篇

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

[摘要] 本篇主要是徒手撸IM系列的开篇,主要讲解的是的IM设计思路,不涉及实践编码,希望给你带来帮助。


👉52im社区本周新文:《总是被低估,从未被超越,揭秘QQ极致丝滑背后的硬核IM技术优化》,欢迎阅读!👈

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

posted @ 2024-05-22 13:53 Jack Jiang 阅读(72) | 评论 (0)编辑 收藏

本文由哔哩哔哩资深开发工程师黄山成分享,原题“千万长连消息系统”,本文进行了排版和内容优化等。

1、引言

在当今数字娱乐时代,弹幕已经成为直播平台上不可或缺的互动元素之一。

用户通过发送弹幕、送礼等,可以实时在直播画面上展现自己的想法、评论和互动内容,从而丰富了用户观看体验。在这个过程中,实时向终端推送互动信息,就需要用到长连接。

长连接,顾名思义,是应用存活期间和服务端一直保持的网络数据通道,能够支持全双工上下行数据传输。其和请求响应模式的短连接服务最大的差异,在于它可以提供服务端主动给用户实时推送数据的能力。

本文将介绍B站基于golang实现的千万级长连接实时消息系统的架构设计与实践,包括长连接服务的框架设计,以及针对稳定性与高吞吐做的相关优化。

 
 
 技术交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK备用地址点此

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

2、关联文章

3、架构设计

3.1概述

长连接服务是多业务方共同使用一条长连接。

因为在设计时,需要考虑到不同业务方、不同业务场景对长连接服务的诉求,同时也要考虑长连接服务的边界,避免介入业务逻辑,影响后续长连接服务的迭代和发展。

长连接服务主要分为三个方面:

  • 1)长连接建立、维护、管理;
  • 2)下行数据推送;
  • 3)上行数据转发(目前只有心跳,还没实际业务场景需求)。

3.2整体架构

长连接服务整体构架如上图所示,整体服务包含以下几个部分。

1)控制层:建连的前置调用,主要做接入合法性校验、身份校验和路由管控。

主要职责:

  • 1)用户身份鉴权;
  • 2)加密组装数据,生成合法token;
  • 3)动态调度分配接入节点。

2)接入层:长连接核心服务,主要做卸载证书、协议对接和长连接维护。

主要职责:

  • 1)卸载证书和协议;
  • 2)负责和客户端建立并维护连接,管理连接id和roomid的映射关系;
  • 3)处理上下行消息。

3)逻辑层:简化接入层,主要做长连的业务功能。

主要职责:

  • 1)在线人数上报记录;
  • 2)记录连接ID各属性和各节点的映射关系。
  • 4)消息分发层:消息推送到接入层。

主要职责:

  • 1)消息封装、压缩和聚合推送给相应的边缘节点;

5)服务层:业务服务对接层,提供下行消息推送入口。

主要职责:

  • 1)管控业务推送权限;
  • 2)消息检测和重组装;
  • 3)消息按一定策略限流,保护自身系统。

3.3核心流程

长连接主要是3个核心流程:

  • 1)建立连接:由客户端发起,先通过控制层,获取该设备合法的token和接入点配置;
  • 2)维持连接:主要是客户端定时发起心跳,来保证长连接活跃;
  • 3)下行推送:下行推送由业务Server发起,经由服务层根据相关标识确定连接标识和接入节点,经过消息分发层,把推送到对应的接入层,写入到指定连接上,然后下发到客户端。

3.4功能列表

结合B站业务场景,下行数据推送,提供如下通用功能:

  • 1)用户级消息:指定推送给某些用户(比如给某个主播发送邀请pk消息);
  • 2)设备级消息:制定推送给某些设备(比如针对未登陆的设备,推送客户端日志上报指令);
  • 3)房间级消息:给某房间内的连接推送消息(比如给直播间的所有在线用户推送弹幕消息);
  • 4)分区消息:给某分区的房间推送消息(比如给某个分区下,所有开播的房间,推送某个营收活动);
  • 5)全区消息:给全平台用户推送消息(比如给全部在线用户推送活动通知)。

4、高吞吐技术设计

随着业务发展壮大,在线用户越来越多,长连系统的压力越来越大,尤其是热门赛事直播,比如s赛期间,全平台在线人数快达到千万,消息吞吐量有上亿,长连系统消息分发平均延迟耗时在1s左右,消息到达率达到99%,下面具体分析下长连做了哪些措施。

4.1网络协议

选择合适的网络协议对于长连接系统的性能至关重要:

  • 1)TCP协议:可以提供可靠的连接和数据传输,适用于对数据可靠性要求较高的场景;
  • 2)UDP协议:是一个不可靠的协议,但是传输效率高,适用于对数据可靠性要求不高的场景;
  • 3)WebSocket协议:也是实现双向通信而不增加太多的开销,更多的用于web端。

接入层拆分成协议模块和连接模块:

  • 1)协议模块:和具体的通讯层协议交互,封装不同通讯协议的接口和逻辑差异。
  • 2)连接模块:维护长连接业务连接状态,支持请求上行、下行等业务逻辑,维护连接各属性,以及和房间id的绑定关系。

针对以上第 1)点,协议模块同时给连接模块提供统一的数据接口,包括连接建立、数据读取、写入等。后续增加新协议,只要在协议模块做适配,不影响其他模块的长连业务逻辑。

优势在于:

  • 1)业务逻辑和通讯协议做了隔离,方便迭代增加通讯协议,简化兼容多通讯协议的实现难度;
  • 2)控制层可以根据客户端的实际情况,下发更优的通讯协议。

4.2负载均衡

采用负载均衡技术可以将请求分发到不同的服务器节点上处理,避免了单一节点的负载过高,提高了系统的扩展性和稳定性。

长连增加控制层,做负载均衡。控制层提供http短连接口,基于客户端和各边缘节点实际情况,根据就近原则,动态选择合适的接入节点。

接入层支持水平扩展,控制层可以实时增加、减少分配节点。在S赛期间,在线人数快到达千万时,平衡调度各接入节点,保障了各节点的CPU和内存都在稳定的范围内。

4.3消息队列

消息推送链路是:业务发送推送,经过服务层推到边缘节点,然后下发给客户端。

服务层实时分发到各边缘节点,如果是房间类型消息,需要推到多个边缘节点,服务层同时还要处理业务逻辑,很影响消息的吞吐量。

所以增加消息队列和消息分发层,消息分发层维护各边缘节点信息和推送消息,提高了系统的并发处理能力和稳定性,避免了因消息推送阻塞而导致的性能问题。

4.4消息聚合

当有热门赛事时,同时在线可能达到千万级别,一条弹幕消息就要扩散到千万个终端,假如在线的每个人每秒发一条,需要发送消息量就是1kw*1kw,消息量非常大,此时消息分发层和接入层,压力都会很大。

分析发现:这些消息都是同一个房间的,属于热点房间,比如s赛房间,观众数量是无法减少的,那只能在消息数上做文章。业务消息推送不能减少,又要减少扩散的消息数,就想到了消息聚合。

针对房间消息,按照一定的规则进行消息聚合,批量推送:

消息聚合上线后,消息分发层对接入层调用QPS下降60%左右,极大的降低了接入层和消息分发层的压力。

4.5压缩算法

消息聚合后,降低了消息的数量,但是增加了消息体的大小,影响了写入IO,需要减少消息体大小,就想到了消息压缩。

压缩算法,选了市面上比较常用的两个:zlib和brotli,进行比较。

抓取了线上业务推送的数据,选择最高等级的压缩等级,进过压缩验证:

由此可见,brotli相比zlib有很大的优势,最后选择了brotli压缩算法。

选择在消息分发层进行消息压缩,避免在各接入节点多次重复压缩,浪费性能。上线后提升吞吐量的同时,也降低的宽带使用成本。

5、服务保障技术设计

现在有些业务是强依赖长连推送消息,消息丢失,轻则影响用户体验,重则阻塞业务后续流程,进而影响业务流水。针对长连服务消息保障,做了如下工作。

5.1多活部署

多活部署,通过在不同地理位置部署相同的系统架构和服务,实现了系统在单一地域故障时的快速故障转移,从而提高了系统的稳定性和可用性。

长连服务部署,主要做了以下几点:

  • 1)长连接在国内华东、华南、华北地域均部署了接入点,支持三大运营商;华南和华中自建机房也部署了接入点;为支持海外用户,增加了新加坡机房独立接入点;
  • 2)针对业务场景不同,在云上节点和自建节点之间,实时切换,因为云上节点和自建机房的成本是不一样的,在保证服务质量的前提下,尽可能的控制成本。

目前线上运行过程中,偶尔会遇到单节点或机房的网络抖动,通过控制层,对有问题的节点,进行秒级摘流,大大减少了对业务的影响。

5.2高低消息通道

多业务消息接入长连接,但不同消息之间的重要性是不一样的,比如弹幕消息和邀请pk消息,丢失几条弹幕对用户体验不会影响很大,但如果邀请pk消息丢失,则会导致pk业务无法进行后续的流程。

针对不同等级的消息,采用了高低优消息通道。重要消息走高优通道,普通消息走低优通道。这样重要和普通消息进行了物理隔离,消息分发优先保证重要消息。

针对高优通道,做了双投递的保障,在接入层做幂等去重。首先重要消息是针对用户级别的,量不会很大,所以对接入层的压力不会增加很大。另外双投递的job是部署在多机房的,这也就降低单机房网络抖动造成的影响。

高低优通道上线后,遇到过内网出网抖动,当时内网部属的job节点推送消息异常,而云上高优job节点可正常推送,很好的保障了高优消息的到达,进而保障了高优业务不受影响。

5.3高达功能

高低优通道解决的是job到接入层的这一个环节,但消息推送联路涉及到多个环节,比如服务层到job、接入层到客户端。

针对整个链路,通过实现必达机制来确保终端的到达率,简称高达功能。

功能实现:

  • 1)每条消息引入msgID,客户端收到消息后进行幂等去重和ack回执;
  • 2)服务端针对msgid进行ack检测,针对未ack的,有效期内再次重试下发。

最终到达率 = (1-(1-r)^(n+1)),其中:r为广播单次到达率,n为最大重试次数。

例如:r = 97%、n=2,那么最终到达率可以达到(1-(1-0.97)^(2+1)) = 99.9973%

6、进出”房“消息的送达保证设计

有些业务场景,需要用到用户进出房消息,比如用户A进入直播间,页面会显示欢迎用户A进入房间,或者是加入在线榜单。

1)进房消息会存在丢失,需要有补偿机制。想到可以通过连接心跳来补偿进房消息,但心跳是持续不断的,连接在线期间,业务希望只收到一次进房消息,所以进房消息需要有幂等机制。

2)出房消息也会存在丢失,如果丢失了,业务无法从在线榜单剔除用户,此时也需要有补偿机制。此时就需要增加连接的状态机,通过心跳维护状态机,当心跳丢失时,认为连接断开,用户退房。

7、未来规划

统一长连接服务经历数次迭代后,目前基本功能已经趋于稳定,后续对长连接服务进行改善和优化。

主要集中在以下几个方向:

  • 1)数据化:进一步完善长连接全链路网络质量数据统计和高价值消息全链路追踪的能力;
  • 2)智能化:端上建联、接入点选择等能够根据实际环境进行自动化调整;
  • 3)性能优化:接入层的连接模块中,处理上下行消息的携程进行共享,减少接入层的携程数,进一步提升单机性能和连接数;
  • 4)功能扩展:新增离线消息功能等。

8、参考资料

[1] 手把手教你写基于TCP的Socket长连接

[2] 正确理解IM长连接、心跳及重连机制,并动手实现

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

[4] 用JWT技术解决IM系统Socket长连接的身份认证痛点

[5] TCP/IP详解 - 第11章·UDP:用户数据报协议

[6] TCP/IP详解 - 第17章·TCP:传输控制协议

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

[8] 快速理解TCP协议一篇就够

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

[10] 一泡尿的时间,快速搞懂TCP和UDP的区别

[11] 到底什么是Socket?一文即懂!

[12] 我们在读写Socket时,究竟在读写什么?

[13] 假如你来设计TCP协议,会怎么做?

[14] 深入操作系统,一文搞懂Socket到底是什么

[15] 通俗易懂,高性能服务器到底是如何实现的

[16] 12306抢票带来的启示:看我如何用Go实现百万QPS的秒杀系统(含源码)


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

posted @ 2024-05-16 11:44 Jack Jiang 阅读(89) | 评论 (0)编辑 收藏

一、更新内容简介

本次更新为次要版本更新,进行了bug修复和优化升级(更新历史详见:码云 Release NotesGithub Release Notes)。

MobileIMSDK 可能是市面上唯一同时支持 UDP+TCP+WebSocket 三种协议的同类开源IM框架。轻量级、高度提炼,历经10年、久经考验。客户端支持iOSAndroidJavaH5微信小程序Uniapp,服务端基于Netty

二、MobileIMSDK简介

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

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

MobileIMSDK工程始于2013年10月,历经10年,起初用作某产品的即时通讯底层实现,完全从零开发,技术自主可控!

您可能需要:查看关于MobileIMSDK的详细介绍

三、源码托管同步更新

OsChina.net

GitHub.com

四、MobileIMSDK设计目标

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

五、MobileIMSDK框架组成

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

  1. Android客户端SDK:用于Android版即时通讯客户端,支持Android 4.0及以上,查看API文档
  2. iOS客户端SDK:用于开发iOS版即时通讯客户端,支持iOS 12.0及以上,查看API文档
  3. Java客户端SDK:用于开发跨平台的PC端即时通讯客户端,支持Java 16及以上,查看API文档
  4. H5客户端SDK查看精编注释版
  5. 微信小程序端SDK查看精编注释版
  6. Uniapp端SDK查看精编注释版
  7. 服务端SDK:用于开发即时通讯服务端,支持Java 1.7及以上版本,查看API文档

整套MobileIMSDK框架的架构组成:

 另外:MobileIMSDK可与姊妹工程 MobileIMSDK-Web 无缝互通,从而实现Web网页端聊天或推送等。

六、MobileIMSDK v6.5更新内容 

【重要说明】:

MobileIMSDK v6.5 为次要版本,进行了若干优化! 查看详情 (github

【新增重要特性】:

  • 1. [Android端] 新增了Demo中当APP处于后台时,收到消息时显示系统通知的功能。

【解决的Bug】:

  • 1. [服务端] 尝试解决极小几率下Android端会误把“自已”踢掉的问题。

【其它优化和提升】:

  • 1. [服务端] 升级了log4j2等基础库,解决基础库低版中带来的安全漏洞风险;
  • 2. [服务端] 服务端SDK和Demo工程已迁移至IDEA;
  • 3. [Java端] Java桌面端的TCP和UDP两种协议的SDK和Demo工程已迁移至IDEA;
  • 4. [Android端] 提升targetSdkVersion至34(即Android 14);
  • 5. [Android端] 解决了Demo中绑定前台服务在Android 14中崩溃等问题。
  • 6. [iOS端] 提升最低系统支持版本为iOS 12;
  • 7. [iOS端] 优化了JSON解析库中的一处过时API调用。

【最新版本源码地址】:

七、Demo运行演示

八、技术应用示例

8.1 示例1:基于MobileIMSDK的移动端IM RainbowChat更多运行截图):

 

8.2 示例2:基于MobileIMSDK-Web的Web端IM RainbowChat-Web更多运行截图):

 

posted @ 2024-05-09 11:34 Jack Jiang 阅读(82) | 评论 (0)编辑 收藏

即时通讯技术文集(第37期):IM代码入门实践(Part1) [共16篇]

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

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

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

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


[- 2 -] 详解Netty的安全性:原理介绍、代码演示(上篇)

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

[摘要] 作为一个高性能的NIO通信框架,基于Netty的行业应用非常广泛,不同的行业、不同的应用场景,面临的安全挑战也不同,下面我们根据Netty的典型应用场景,分析下Netty面临的安全挑战。


[- 3 -] 详解Netty的安全性:原理介绍、代码演示(下篇)

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

[摘要] 接上篇《详解Netty的安全性:原理介绍、代码演示(上篇)》。


[- 4 -] Java NIO基础视频教程、MINA视频教程、Netty快速入门视频 [有源码]

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

[摘要] 本次分享的是自己收藏的Java nio、mima、netty的视频教程,现分享给各位,希望对大家有帮助。


[- -] 轻量级即时通讯框架MobileIMSDK的源码

[链接]http://git.oschina.net/jackjiang/MobileIMSDK

https://github.com/JackJiang2011/MobileIMSDK

[摘要] 如Github下载慢,请往:https://gitee.com/jackjiang/MobileIMSDK,代码完全同步,请放心下载 


[- 6 -] 开源IM工程“蘑菇街TeamTalk”2015年5月前未删减版完整代码 [附件下载]

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

[摘要] 本次分享的源码来自即时通讯群群友的个人分享,因可能涉及网易泡泡源码版权纠纷,请开发者保证仅用于个人学习和研究之用,切勿用于商业用途。


[- 7 -]  NIO框架入门(四):Android与MINA2、Netty4的跨平台UDP双向通信实战 [附件下载]

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

[摘要] 本文中,服务端将分别用MINA2和Netty4进行实现,但在你实际的项目中服务端实现只需选其一就行了。


[- 8 -] NIO框架入门(三):iOS与MINA2、Netty4的跨平台UDP双向通信实战 [附件下载]

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

[摘要] 本文将演示一个iOS客户端程序,通过UDP协议与两个典型的NIO框架服务端,实现跨平台双向通信的完整Demo。


[- 9 -] NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示 [附件下载]

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

[摘要] 本文将演示的是一个基于MINA2的UDP服务端和一个标准UDP客户端(Java实现)双向通信的完整例子。


[- 10 -] NIO框架入门(一):服务端基于Netty4的UDP双向通信Demo演示 [附件下载]

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

[摘要] 本文将演示的是一个基于Netty4的UDP服务端和一个标准UDP客户端(Java实现)双向通信的完整例子。


[- 11 -] 用于IM中图片压缩的Android工具类源码,效果可媲美微信 [附件下载]

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

[摘要] 本文要分享的工具类源码来自IM产品 RainbowChat,压缩效果可媲美微信,详情请参见源码。


[- 12 -] 高仿Android版手机QQ可拖拽未读数小气泡源码 [附件下载]

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

[摘要] 本文分享的源码高仿了手机QQ的这个效果,希望可以为有相同需求的IM开发者同行节省点撸码时间。


[- 13 -] 一个WebSocket实时聊天室Demo:基于node.js+socket.io [附件下载]

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

[摘要] 本文将基于HTML5规范中的WebSocket技术,使用Node.js和Socket.io(关于Socket.io介绍,请参见《Socket.IO介绍:支持WebSocket、用于WEB端的即时通讯的框架》)来实现一个可用于Web端的简易实时聊天室,源码可从文末附件中下载到。


[- 14 -] Android聊天界面源码:实现了聊天气泡、表情图标(可翻页) [附件下载]

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

[摘要] Android聊天界面源码:实现了聊天气泡、表情图标。


👉52im社区本周新文:《即时通讯安全篇(十四):网络端口的安全防护技术实践》,欢迎阅读!👈

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

posted @ 2024-05-08 12:24 Jack Jiang 阅读(77) | 评论 (0)编辑 收藏

     摘要: 本文由vivo互联网技术Peng Qiankun分享,原题“vivo 网络端口安全建设技术实践”,本文进行了排版和内容优化等。1、引言随着互联网业务的快速发展,网络攻击的频率和威胁性也在不断增加,端口是互联网络通信中的门户,它是数据进出的必经之路,因此端口安全也逐渐成为了企业内网的重要防线之一。然而网络端口因其数量庞大、端口开放和关闭的影响评估难度大,业务影响程度高、以及异...  阅读全文

posted @ 2024-05-06 12:35 Jack Jiang 阅读(77) | 评论 (0)编辑 收藏

本文由腾讯技术团队peter分享,原题“腾讯网关TGW架构演进之路”,下文进行了排版和内容优化等。

1、引言

TGW全称Tencent Gateway,是一套实现多网统一接入,支持自动负载均衡的系统, 是公司有10+年历史的网关,因此TGW也被称为公司公网的桥头堡。

本文从腾讯公网TGW网关系统的应用场景、背景需求讲起,重点解析了从山海1.0架构到山海2.0架构需要解决的问题和架构规划与设计实现,以及对于未来TGW山海网关的发展和演进方向。

 

技术交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK备用地址点此

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

2、专题目录

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

  1. 长连接网关技术专题(一):京东京麦的生产级TCP网关技术实践总结
  2. 长连接网关技术专题(二):知乎千万级并发的高性能长连接网关技术实践
  3. 长连接网关技术专题(三):手淘亿级移动端接入层网关的技术演进之路
  4. 长连接网关技术专题(四):爱奇艺WebSocket实时推送网关技术实践
  5. 长连接网关技术专题(五):喜马拉雅自研亿级API网关技术实践
  6. 长连接网关技术专题(六):石墨文档单机50万WebSocket长连接架构实践
  7. 长连接网关技术专题(七):小米小爱单机120万长连接接入层的架构演进
  8. 长连接网关技术专题(八):B站基于微服务的API网关从0到1的演进之路
  9. 长连接网关技术专题(九):去哪儿网酒店高性能业务网关技术实践
  10. 长连接网关技术专题(十):百度基于Go的千万级统一长连接服务架构实践
  11. 长连接网关技术专题(十一):揭秘腾讯公网TGW网关系统的技术架构演进》(* 本文

3、TGW网关系统的重要性

TGW全称Tencent Gateway,是一套实现多网统一接入、支持自动负载均衡的系统, 是公司有10+年历史的网关,因此TGW也被称为公司公网的桥头堡。它对外连接了各大运营商并支撑公有云上EIP、CLB等产品功能,对内提供了公网网络的接入功能,如为游戏、微信等业务提供公网接入服务。

TGW主要有两大产品:

  • 1)弹性EIP(比如购买一台虚拟机CVM或是一个NAT实例后,通过EIP连通外网);
  • 2)四层CLB。

四层CLB一般分为内网CLB和外网CLB:

  • 1)内网CLB是在vpc内创建一个CLB实例,把多个CVM服务挂在了内网CLB上,为后端RS提供负载均衡的能力;
  • 2)外网CLB面对的是公网侧负载均衡的需求。

当在内部部署CLB集群时,可分为IPV4或者IPV6两大类,根据物理网络类型又细分为BGP和三网两类。三网指这些IP地址是静态的,不像BGP一样能够在多个运营商之间同时进行广播。

以上就是四层TGW产品及功能,山海网关在原有产品基础上做了网络架构方面的演进。

4、Region EIP的引入

具体介绍下EIP和CLB两个产品。

过去CLB和EIP使用不同的IP地址池,导致资源池上的隔离问题。使得我们无法把EIP地址绑定到公有云CLB实例上。

例如:一个创业公司最初只购买一台虚拟机并挂载一个公网EIP来提供服务。随着用户量的增长,如果想将这个EIP地址迁移到一个公网CLB实例上,在原有架构下是无法实现这种迁移的。

此外:EIP和CLB部署在每个机房,因此在每个机房都需要建立EIP出口。但是各个机房的公网出口之间缺无法相互容灾。

所以这种情形下,我们确定了产品的目标:

  • 1)希望将所有公网出口整合到一到两个机房之内,以避免重复建设,节省成本;
  • 2)通过将出口集中,我们可以将对应的网关服务器也进行集中,进而提高设备的利用率;
  • 3)通过这样的布局可实现跨机房的容灾方案。

因此:最早的Region EIP(REIP)计划应运而生。

以北京这类大型region为例的:我们将EIP专区建设到位于两个城市的超核机房。这两个机房通常会放置物理网络的交换设备,并为各自设立了一个REIP专区。在REIP专区内部署Region EIP集群。为了实现跨AZ容灾,两个机房的集群之间借助大小网段实现互相备份容灾的能力。一旦其中一个机房的集群发生故障或出现网络问题,另一个机房的集群可以立即承担起容灾任务。

同时:因为新的Region EIP的网络架构跟原来的网络架构不一样,通过网络架构升级以及机型升级,我们能够把单台Region EIP的性能做到原有单台EIP性能的5倍。这样我们通过容量的提升进一步提升了设备利用率,在完成全量Region EIP后,设备数量会从3000+台缩减至700+台。同时原有的CLB集群还保留在各个机房不变,这些CLB集群的外网接入能力由Region EIP承担。

5、公网CLB的演进

5.1概述

公网CLB最早是有公网接入能力的。引入到Region EIP之后,当初设想是公网CLB不再演进,尽量让存量用户迁移到另外一种形式,上层是Region EIP,下层是内网CLB。用户先买一个内网CLB,如果需要对公网提供服务就再买一个弹性EIP,把EIP跟内网CLB绑定在一起,提供CLB公网的能力,替代原有的公网CLB,这是最早公网CLB的替代方案。

两个方案的区别是:原有公网CLB,用户仅看到一个CLB实例。新的模式下,用户看到的是两个实例:一个EIP+一个内网CLB,两个实例都可以独立运营管理。这就是我们最早的两层架构设想,想把公网CLB跟外网解耦。

但是,真正去跟用户或产品交流时,这个想法遇到了比较大的挑战:

1)用户体验的改变:以前公网CLB用户看到是一个实例,但是现在用户看到两个实例,必然会给用户带来一些适配工作。比如用户进行创建、管理实例时,API不一样了。以前使用通过自动化脚本创建公网CLB实例的,现在脚本还要改变去适配新的API。

2)用户习惯改变:以前用户习惯在一个实例下,点击页面,就能够查看流量、链接数等监控信息。现在EIP流量需要到REIP查看,而链接数还需在CLB产品上看。

3)存量客户无法迁移:原来客户买的公网CLB实例,是无法直接无感知迁移到内网CLB+REIP这种新形式的。

在这些挑战下,这个替代方案没能真正落地。结合用户的要求,我们最终跟产品定下的策略是:公网CLB保持不变。原有的公网CLB继续保留,同时如果用户新增的公网CLB需求,也要继续支持。

5.2公网CLB模型

那么,公网CLB到底怎么演变?

我们的初衷并不是把公网CLB这个产品摒弃掉,而是要收敛公网入口。所以我们针对这个初始需求,提出了上面这个两级架构模型。

首先:用REIP将公网流量先引进来,再将这个流量通过隧道报文的形式转发给原有的公网CLB集群,这样公网CLB不需要原有外网接入的能力,不需要再跟外网打交道,可以演变成只在机房内部的集群;同时因为公网CLB的流量都会经过REIP,REIP自然也就是公网CLB的流量入口。从而达到我们最初收敛公网入口的目的。这样的架构升级,可实现用户无感知。架构升级切换过程中,用户在访问公网CLB,不会出现卡顿或者重连的现象。

这个架构模型也有一定的局限性的。公网CLB实例只能承载公网的流量,无法像上文提到的两层RERP+CLB那样,内外网随时进行转化。REIP+CLB实例中的CLB既承载内网侧CLB的流量,又承载公网侧CLB的流量。

6、山海架构 1.0

借助这个两级架构模型,我们能够把公网CLB保留下来,并且通过REIP把公网入口收敛。

进一步思考并完善,我们提出了下面的想法:跟产品进行解耦。

以前我们一个地区上线公网CLB产品,底层就要搭建有一个公网CLB的集群去支持。用户需要内网CLB服务,就要对应搭建个内网CLB的集群。底层集群类型跟产品是强耦合,有IPv4/IPv6, 公网/内网、BGP/三网组合出的多个产品形态。

这种模式在小地域部署,因为产品业务的流量小,集群利用率低,就会造成很大的成本压力。

为了应对这种小带宽低成本的诉求,我们将CLB+REIP的模型进一步抽象,引入山海架构:我们只建设CLB和REIP两类集群。通过这两类集群上的不同实例组合,满足多个产品形态的要求。从而实现产品形态和底层物理网络集群类型解耦。

解耦合的方式是:CLB和REIP通过不同的实例类型,组合出不同的产品形态。

山海架构在TGW内部做闭环,不涉及到产品侧和用户侧的改动。整个过程升级,对产品侧不做任何接口上的更新。因为产品侧的API接口保持不变,对用户侧就可以做到完全无感知。在产品侧保持不变,就需要我们在内部管控,识别接入用户实例是哪种形态的产品,拆分成不同形式的CLB和REIP的实例。其他的相关功能的比如流量统计、限速等模块也都要适配不同的产品形态,通过模块的适配,做到山海架构对上层产品侧应用的透明。

山海架构1.0归纳起来有两个重点:收敛公网入口和集群类型归一。

1)REIP:部署在城核机房,同时承载的是CLB和REIP两类产品的公网流量。之前EIP,在物理网络上有BGP+三网、v4/v6等多种集群类型。REIP借助vlan的隔离支持,把所有的网络类型都集中到一种REIP集群上来,我们称之为全通集群。在物理网络层面实现网络类型的归一, 然后再通过软件层的适配,实现REIP支持多通类型的网络接入能力。

2)CLB:在山海两级架构下,REIP集群处理公网侧的各种场景组合,CLB集群通过隧道与REIP处理公网流量。之前一个机房如果要把所有的产品能力支持起来,大概有7种集群类型。现在CLB集群可以用一种集群类型来支持所有的产品的公网CLB产品,以及内网CLB产品的能力。我们把三网+BGP以及内外网还有V4V6等集群类型都用一种类型来支持,山海架构完全落地后,开区的最小服务器数量可以降低到8台服务器,来承载所有的EIP和CLB产品需求。

归纳起来一句话:对于用户来说,产品形态没有改变,用户使用习惯也没有改变。而在底层,我们把集群类型收敛到一个CLB集群和一个REIP集群上。

7、山海架构1.0限速技术

在山海架构演进中,有许多技术点,本文选取限速技术进行分享。

首先Region EIP支持三网。以前BGP跟三网分开独立支持,山海网关统一用Region EIP支持。Region EIP本身的网络架构分成两个机房,每个机房放4台TGW设备,每个EIP只会走左边或者右边。一个EIP进来的流量经过上面这层交换机时,经过了ECMP分流,然后分到了4台设备上。这样对每个EIP其实是采用了分布式限速。

限速有两个要求:

  • 1)精确性,限速上下浮动要小,要限得准;
  • 2)要有容灾能力。

限速最极端的精准就是把它放到单点上去做限速,但是单点限速就会面临单点故障和容灾的问题。在X86服务器上,使用的是分布式限速,一个EIP均分到4台服务器上,每五秒钟做一次流量的的汇总统计,通过流量比例计算将这个EIP的带宽配额,重新分配并分发到4台设备上,以此来实现集群上的限速。在单台设备上,也是没隔一段时间,就重新计算配额并分配到每个CPU核上,我们目前用的是300毫秒周期。

需要说明的是:在限速的实现上,业务有多重实现方式,我们了解到有的实现的是静态分配,比如120兆的带宽,4台设备,我们每台设备分40M(三分之一)的带宽。1/3而不是1/4的带宽,目的是防止某一台设备断了之后,用户总带宽不达标,影响用户体验。在单台设备上限速,也有另外一种实现方式,大小桶。比如限速1M的带宽,那么每个核第一次取回100K或者200K配额。后续报文处理时候,先消耗上次取回的配额,如果带宽配额消耗光了,再重新取。周期调整跟大小桶这两种实现方式各有优缺点。从资源消耗来说,300毫秒周期的资源消耗相对会更少一些,两者大概有10%左右的性能偏差。

限速上另一诉求:小带宽的限速的精准限速。

大带宽比如100兆,分到每个核上相对富裕。小带宽如一M带宽,一秒钟100k字节等,分到四台机器再分到几十个核上,每个核都可能不到一个大报,这时候再去做精准限速就会非常困难,因为既然要提前分配资源,资源那么少,分配到单核上,可能一个包都过不去,但凡有一个报文过去了,又可能超了。所以在小带宽限速时,我们把它退化成类似于单点限速的模式。由于入方向带宽最小也是100兆,因此保持原有的分布式限速不变。只对出方向小带宽,使用单点限速。方案是这样的:

每台REIP有自己一个独享的内网地址,只有这台服务器故障时候,这个地址的流量才被分发到其他三台服务器。

入方向流量被分到四台REIP服务器后,REIP处理完通过tunnel转发给母机。隧道的外层源地址,只使用其中一台REIP服务器的独享的IP地址。每个外网IP地址在挂载到集群下管理时候,就确定下来了。

母机在接受到网关发过去的流量,解析外层报文地址,并记录在本地会话表里,我们称之为母机的自学习能力。当母机侧转发出方向报文时,就只会使用本地学习并记录的外层地址去封装隧道。这样出方向的流量,就回到单台TGW设备上,实现了单点限速。

独享的内网地址本身是有容灾能力:

  • 1)当其服务器故障了,流量就被分散到集群其他服务器,放弃单点限速;
  • 2)当服务器被修复上线后,又可以重新变成精准的单点限速。

这样保证小带宽精准限速的同时,又避免了单点故障。

在限速过程中,还有一个问题,因为CLB集群原来的限速是在CLB集群上自己做的,引入山海之后,REIP上有限速能力,那么公网CLB的限速要不要挪到REIP上?

我们经过多次讨论, 最终还是维持**这个限速在公网CLB上不变。

这里有几种场景考量:

1)内外网攻击:如果我们把它放到REIP上,这里可以扛住外网的攻击,但同时内网的攻击我们是防不住的,因为公网CLB上没有限速后,流量内网的攻击就会先把CLB上压过载,导致丢包,影响业务的稳定性。

2)有效流量的准确统计:原有架构下,从公网流量首先到达CLB,我们需要检查公网CLB上与port对应的服务是否已配置规则并启用。如果没有启用,则将报文直接丢弃且不记录为公网CLB的带宽使用量。山海架构下,如果先经过Region EIP限速,这类无服务访问流量(如恶意攻击和垃圾流量)也将占用限速资源。尽管这部分限速流量会送达至CLB集群,但由于缺乏相应服务支持,它们最终还是将被丢弃。结果导致用户带宽不及预期。比如用户购买10M带宽,实际有效运行的仅有8M流量,而其余2M被无服务流量占用了。

3)多重限速的影响:还有一个这个场景中,当Region EIP实施带宽限速后,这些流量最终可能进入公网CLB。然而,由于CLB的规格限制,例如新建连接数或并发连接数已达到上限,部分数据包可能会被丢弃。这些丢失的数据包已经消耗了购买的公网带宽,从而导致用户观察到的公网CLB流量带宽未达到预期。因此,我们保留公网CLB限速功能不变,仅进行引流调整。

8、山海架构1.0的优势

CLB产品及REIP产品,在使用山海1.0之后的几点优势。

1)CLB产品本身支持热迁移,扩容到山海热迁移,不会引起用户的断流,有助于运维做用户产品升级迭代。这方面有个典型案例,比如某台设备坏了或者发现某台设备上有问题,需要把流量迁走的时候,我们可以不用中断用户的流量的。我们了解到,以前有的竞品,因为热迁移做的不是特别完善,在设备出现问题或者是需要升级版本的时候,常选择低峰期做升级。

2)EIP在做限速的时候,在出方向时是小带宽,可以做到比较精准的限速。好处是用户做压测或测试的时,带宽不会抖动影响自己的业务的稳定性。

3)高低优先级限速。用户买一些比较小的比如10M带宽或者5M带宽,用来服务本身业务,同时也会ssh或者远程桌面登录EIP;因为一起我们是做无差别的限速丢包的话,这样会造成它本身的控制流量,如远程桌面的流量也会被丢包,造成登录的卡顿。用户需要在不超限速的前提下,优先保证远程桌面不卡,然后再提供其他的下载服务。我们把流量根据端口进行区分,比如22端口或者是远程桌面的3389端口的流量,标记为高优先级。在做限速时,只要高优先流量不超限速,就全部放行。当高优先级流量再叠加上低优先级的流量超限速时,把低优先级的流量丢掉,这样ssh访问服务器的时候能够非常顺畅。

4)山海架构上线后,基于vip粒度的调度,可以让调度更加灵活。比如原来一个集群为了节省路由条目,我们按照一个网段发路由,不是每个VIP都发路由的。山海两级架构之后,没有了这个限制,就可以按照VIP,把CLB实例调度到不同CLB集群。这样如果用户需要一个特别大规格的VIP的时候,我们可用一个集群的能力去扛用户一个VIP,从而满足超大规格实例的诉求。当然真实使用产品时,很少有客户把上百G的流量用一个VIP来承载。用户出于容灾考虑,通常不会把所有的鸡蛋放到一个篮子里。

9、山海架构 2.0

9.1概述

如前所述:山海 1.0 主要目标是整合公共网络并将所有公网出口集中在城市核心机房内。至于剩余的 CLB 群集,我们会继续将其保存在原有各机房的专区里。这是因为网关设备有其与服务器不同的网络诉求,例如普通服务器不能提供发布动态路由,并通过动态路由引流处理业务流量。

再比如:网关专区的收敛比1:1,而服务器虽然带宽也是100G, 但其收敛比率往往小于1:1。

在这种情况下,我们不能简单地将 CLB 网关群集群平移放置到服务器区。因此,CLB 网关群集通常在构建每个机房时,预先规划并预留相应的网关专区。机房建设起来后,如业务量小,又会因预留资源空置造成浪费。目前专区闲置机位也是一笔较大的费用。

同时,还有一种临时扩容的需求场景,例如VIP大客户,临时会有大流量的转发需求,这时常态运营水位没法满足需要,需要调配设备做集群扩容。如果本机房的设备不够还需要跨机房搬迁,搬迁周期比较长,对我们运营压力会很大。

所以,我们希望通过山海2.0能把专区建设的空置率降下来,同时提升弹性,能够低成本的快速扩缩容。

9.2引流交换机

在山海 2.0里,我们采用了“引流交换机”。在每个机房的建设时,我们可以放置两组共四台引流交换机。

考虑到单个交换机的容量可以达到 1 T 以上,有四台交换机工作,一个机房能够承受大约 4T~ 6T 的流量峰值。这意味着后续无需再额外扩容,一次性的建设和布局就可以满足长期的需求。相比于 CLB 群集占用的机位空间,四台交换机所需的机位显著减少。

我们把原来CLB集群对外声明路由的能力放到了引流交换机上,把CLB服务器用用通用服务器区的设备来代替。考虑收敛比和容灾,不会把一个集群放到一两个机架上,会相对分散些,更不会把整个机架全部再用成CLB集群。这样CLB集群不再单独建设网关专区,引流交换机把路由声明发出去,通过隧道跟CLB设备转发流量。

9.3山海2.0的变化

我们以内网CLB为例,原来一台虚拟机访问CLB集群,CLB集群把它的流量转到对应的RS。

引入交换机之后,其进出两个方向都会有变化:入方向(访问LB方向),虚拟机的流量先被引流到了引流交换机,交换机把报文做一次封装,然后发送给对应的服务器,进行负载均衡转换。最后处理后的结果,被转发给真正的RS。原来的两跳访问变成了现在的三跳。同样反方向流量返回时,RS的流量先回到引流交换机,然后被分发到对应的LD设备上。LD处理完之后,再把报文直接转到client虚拟机上。借助引流交换机的中转,我们就能够让负载均衡的专区设备的放到普通的服务器区里。

另外:这里的CLB服务器,可以跟其他的网关包括母机复用一些相同机型的服务器,当需要扩容时,就可以使用通用服务器。而不像以前CLB既有自己独立的机型,又对服务器的物理位置有要求。有了引流交换机跟LD之间是做隧道传输,LD具体的物理位置就没有像原来一样有硬性的要求。这样CLB可以通过通用服务器区域,调配服务器。

最后一项是:原有跟REIP类似的,CLB设备做路由通告时,也是按照网段通告,有引流交换机之后,我们可以在引流交换机上去做细粒度的调度,一个VIP或是几个vip放到一个集群。还可以在引流交换机上做更细粒度的调度,如IP+port这样的五元组的粒度的调度。

10、未来展望

目前网关设备最重要也是最大的一个方向就是做高性能、硬件卸载。依赖硬件来实现高性能的转发。

网关设备分为有状态和无状态两种:

  • 1)无状态设备就像IP转换一样,只要依据规则,任何时刻来了报文,转换出来的形式都是固定的;
  • 2)有状态设备是需要记录TCP、 UDP状态,记录转发到后端设备,当不同的时间转发即使相同的类型的流量,它转发的目的地也不一样,转换的格式也可能不一样。

硬件卸载在有状态和无状态时,基本上用到的设备都是DPU和交换机,用到的介质几乎都是FPGA。

FPGA和ASIC本质上是一个东西,无论友商还是我们自己内部研发,更多的是FPGA上做功能,并小规模的灰度上线验证,一旦稳定下来,就转化成批量的ASIC,以此来降低成本。

DPU和交换机在无状态设备上,交换机相对更有优势,因为无状态设备对容量的要求相对小些,像EIP网关以及内部无状态的网关大多用交换机形态实现。DPU目前更多的用在母机侧,做有状态类的网络处理。当然, 采用DPU不仅仅局限网络诉求,还有存储安全等其他需求。去年英特尔宣布已不再进行交换机tf芯片的演进迭代,大家对交换机的质疑会增大。

所以,也衍化了另一种方案:在一台额外的服务器中插入 DPU 网卡以实现卸载功能。

但不同方案有不同的优缺点:

1)使用交换机的最大优势在于其强大的交换性能(可达 1T或几个T及更高),可支持很大的接入容量。但是,交换机仅能是一个底座,若要扩展容量仍需依赖 FPGA 技术。

2) DPU 的优点则包括成熟的产业链、庞大的产量以及稳定的供应保障;此外,由于 DPU 在母机侧已被广泛验证和采用,许多功能的实现都相对固定。

这是两种方案各自的优缺点。

在两个产品运用负载均衡状态的交换上,业内不同的厂家也有不同的玩法,有的是交换机,有的是DPU。当前,无论是交换机还是 DPU,都依赖FPGA(ASIC)来做大容量的会话管理,同时越来越多的设备或多或少的支持P4。在 X86 上进行编程时,通常选择 DPDK。

相较之下:使用 P4 进行编程的门槛较低。P4 编写一般功能需求的代码非常简单快捷,只需一两周时间即可完成,甚至对于熟练者来说,可以在几个小时就开发出一个小功能。虽然充分发挥硬件的性能,P4类芯片还需要进行很深入细节的研究,但P4还是大大降低了数据面编程的门槛,特别是在高性能转发的需求方面。

另一个特点是:小型化。大家过去比较关注数据中心和海量数据的优化问题,随着业务发展,逐步转向降低运营成本和提高效率的场景,开设小型站点。这类小型站点,是典型的“麻雀虽小,五脏俱全”,希望用尽量少的设备成本来满足各种功能需求。所以我们将设备设计为具有较小规格的产品系列,并在易用性上进行改进,通过集群合并、虚拟机等承担更多的任务负载。这样在业务规模和流量不大,也能以较少的资源应对较高的功能性需求。一旦业务规模扩大,我们可将这些小型站点升级为传统的数据中心级物理设备。

以上未来网关两个主要的方向。

11、相关资料

[1] IPv6技术详解:基本概念、应用现状、技术实践(上篇)

[2] 网络编程入门从未如此简单(三):什么是IPv6?漫画式图文,一篇即懂!

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

[4] 脑残式网络编程入门(六):什么是公网IP和内网IP?NAT转换又是什么鬼?

[5] 脑残式网络编程入门(七):面视必备,史上最通俗计算机网络分层详解

[6] 以网游服务端的网络接入层设计为例,理解实时通信的技术挑战

[7] 百度统一socket长连接组件从0到1的技术实践

[8] 淘宝移动端统一网络库的架构演进和弱网优化技术实践

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

[10] 新手入门:零基础理解大型分布式架构的演进历史、技术原理、最佳实践

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

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

posted @ 2024-04-18 11:06 Jack Jiang 阅读(87) | 评论 (0)编辑 收藏

关于MobileIMSDK

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

工程开源地址是:

关于RainbowChat

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

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

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

v11.5 版更新内容

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

(1)Android端主要更新内容:

  • 1)[bug] 解决了“@”提醒在客户端新消息时未持久化的问题;
  • 2)[bug] 解决了首页“一键已读”功能不清除“@”提醒标记的问题;
  • 3)[bug] 解决了消息转发时,“最近消息”列表中的表情内容没有被转义成表情图标的问题;
  • 4)[bug] 解决了查看iOS端发的引用的文件消息时,无法跳转到文件下载界面的问题;
  • 5)[bug] 解决了查看iOS端发的引用的短视频消息时,无法跳转到短视频下载界面的问题;
  • 6)[升级] 提升targetSdkVersion至34,全面兼容Android 14;
  • 7)[升级] 解决了绑定前台服务在Android 14中崩溃的问题;
  • 8)[升级] 升级权限管理框架XXPermissions至18.62,全面兼容Android 14;
  • 9)[升级] 其它基础库升级等。

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

  • 1)[bug] 修复一处跟RainbowChat-Web产品联合部署时,Web端无法成功加载历史记录的问题;
  • 2)[升级] 升级了包括log4j2等在内的一些基础库版本;
  • 3)[升级] 优化了iOS离线推送时苹果手机端的桌面未读数角标显示;

部分功能运行截图更多截图点此查看):

 

posted @ 2024-04-17 11:51 Jack Jiang 阅读(88) | 评论 (0)编辑 收藏

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

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

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

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


[-2-] 跟着源码学IM(二):自已开发IM很难?手把手教你撸一个Andriod版IM

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

[摘要] 本文适合没有任何即时通讯(IM)开发经验的小白开发者阅读,文章将教你从零开始,围绕一个典型即时通讯(IM)系统的方方面面,手把手为你展示如何基于Netty+TCP+Protobuf来开发出这样的系统。非常适合从零入门的Android开发者。


[-3-] 跟着源码学IM(三):基于Netty,从零开发一个IM服务端

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

[摘要] “文适合IM新手阅读,但最好有一定的网络编程经验,必竟实践性的代码上手就是网络编程。如果你对网络编程,以及IM的一些理论知识知之甚少,请务必首先阅读:《新手入门一篇就够:从零开发移动端IM》,该文为IM小白分类整理了详尽的理论资料,请按需补充相关知识。


[-4-] 跟着源码学IM(四):拿起键盘就是干,教你徒手开发一套分布式IM系统

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

[摘要] 本文记录了我开发的一款面向IM学习者的 IM系统——CIM(全称:CROSS-IM),同时提供了一些组件帮助开发者构建一款属于自己可水平扩展的 IM。


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

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

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


[--] 跟着源码学IM(六):手把手教你用Go快速搭建高性能、可扩展的IM系统

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

[摘要] 本文适合有一定网络通信技术基础的IM新手阅读。如果你对网络编程,以及IM的一些理论知识知之甚少,请务必首先阅读:《新手入门一篇就够:从零开发移动端IM》,按需补充相关知识。


[-7-] 跟着源码学IM(七):手把手教你用WebSocket打造Web端IM聊天

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

[摘要] 本文将基于Tomcat和Spring框架实现一个逻辑简单的入门级IM应用,对于即时通讯初学者来说,能找到一个简单直接且能顺利跑通的实例代码,显然意义更大,本文正是如此。希望能给你的IM开发和学习带来启发。


[-8-] 跟着源码学IM(八):万字长文,手把手教你用Netty打造IM聊天

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

[摘要] 上篇《跟着源码学IM(七):手把手教你用WebSocket打造Web端IM聊天》中,我们使用 WebSocket 实现了一个简单的 IM 功能,支持身份认证、私聊消息、群聊消息。然后就有人发私信,希望使用纯 Netty 实现一个类似的功能,因此就有了本文。


[--]  跟着源码学IM(九):基于Netty实现一套分布式IM系统

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

[摘要] 接下来的内容,我会为你介绍如何开发一个IM的方方面面,包括系统架构、通信协议、单聊群聊、表情发送、UI事件驱动等,以及全套的实践源码让你可以上手学习。


[-10-] 跟着源码学IM(十):基于Netty,搭建高性能IM集群(含技术思路+源码)

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

[摘要] 本文将根据笔者这次的业余技术实践,为你讲述如何基于Netty+Zk+Redis来搭建一套高性能IM集群,包括本次实现IM集群的技术原理和实例代码,希望能带给你启发。


[-11 -] 跟着源码学IM(十一):一套基于Netty的分布式高可用IM详细设计与实现(有源码)

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

[摘要] 本文将要分享的是如何从零实现一套基于Netty框架的分布式高可用IM系统,它将支持长连接网关管理、单聊、群聊、聊天记录查询、离线消息存储、消息推送、心跳、分布式唯一ID、红包、消息同步等功能,并且还支持集群部署。


[-12 -] 跟着源码学IM(十二):基于Netty打造一款高性能的IM即时通讯程序

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

[摘要] 原本打算做个多人斗地主练习程序,但那需要织入过多的业务逻辑,因此一方面会带来不必要的理解难度,让案例更为复杂化,另一方面代码量也会偏多,所以最终依旧选择实现基本的IM聊天程序,既简单,又能加深对Netty的理解。


👉52im社区本周新文:《微信团队分享:来看看微信十年前的IM消息收发架构,你做到了吗》《移动端IM产品RainbowChat[专业版] iOS端 v9.0版已发布!》,欢迎阅读!👈

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

posted @ 2024-04-12 12:06 Jack Jiang 阅读(70) | 评论 (0)编辑 收藏

本文由微信技术团队分享,原题“十年前的微信消息收发架构长啥样?”,下文进行了排版和内容优化等。

1、引言

2023 年,微信及 WeChat 的 DAU(月活用户)达到 13.4 亿,微信已经是很多人工作、生活中不可或缺的一个环节。从 2011 年 1 月 21 日上线至今,微信已经走过了 13 个年头,其背后的技术基座与架构也发生了巨大的变化。这些变化背后,所折射的也正是中国互联网高速发展的黄金年代。

好的架构是迭代出来的,却也少不了良好的设计,本文将带大家回顾微信背后最初的也是最核心的IM消息收发技术架构,愿各位读者能从中获得启发。

 
 

技术交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK备用地址点此

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

2、微信技术起步

微信诞生于 QQMail 团队,初始的整个微信后台架构都带着浓重的邮箱气息,消息收发架构作为微信最为核心的部分,同样是基于邮箱的存储转发机制演变而来

微信定位为即时通讯IM软件,对消息的收发有2个基本的要求:

  • 1)消息尽可能的实时送达;
  • 2)不丢消息。

在邮箱的存储转发机制上做了改良后,微信的消息收发实现了以上2个基本要求。

3、消息发送架构

首先通过手机 A 给手机 B 发送一条微信消息来看消息发送的整体架构是怎样的(如下图所示)。

微信消息发送在整体架构上可以分为2个部分。

第一部分:手机A发送消息到服务器(上图中1、2、3部分):

  • 1)- 手机A发送发消息请求到接入层 ConnnectSvr;
  • 2)2 - 接入层收到请求后,将请求转到逻辑层 SendSvr 进行处理;
  • 3)3 - 逻辑层处理完各种逻辑(如反垃圾,黑名单等等)之后,将消息存入存储层 MsgStore。

第二部分:服务器发送通知到手机B(上图中4、5.1、5.2、6、7部分):

1)4 - 逻辑层 SendSvr 将给手机 B 的新消息到达通知发送到通知处理服务器 PushSvr。

2)5.1 - PushSvr 查询手机 B 在接入层所在长连接的 ConnectSvr,并将通知发给该 ConnectSvr。

3)5.2 - PushSvr 发送一个 Push tips 给手机操作系统自建的第三方 Push 系统(如苹果的 APNsPush,微软的 WPPush,黑莓的 BBPush 等)。像苹果的 IOS 系统,在 APP 退出到后台10分钟后就会释放掉该 APP 所持有的所有资源(如 CPU,网络,内存等),导致之前建立的长连接通道也会一并断掉,此时通过5.1的方式进行通知是不可达的,所以还需要依赖与苹果自身的 apns 通道来达到实时通知的目的。

4)6 - 接入层 ConnnectSvr 通过手机 B 建立的长连接通道将新消息达到通知发送给手机 B。

5)7 - 第三方 Push 服务器通过自建的 Push 通过发送 Push tips 到手机 B。

4、消息接收架构

手机 B 在收到新消息到达通知后进行消息收取的整体架构如下图所示:

 

消息收取的流程主要分为3个步骤:

  • 1)手机 B 发起收取消息的请求到接入层服务器 ConnnectSvr;
  • 2)接入层服务器 ConnnectSvr 接到请求后转给逻辑层服务器 ReceiveSvr 进行处理;
  • 3)ReceiveSvr 从存储层 MsgStore 中获取到需要下发的消息。

5、消息收发架构小结

在上述第4、5两节中分享的消息收发架构保障之下,微信可以保证手机 A 在发出消息 100ms 级别内让手机 B 收取到该条消息。

当然,对于退出后台的苹果 iOS 的微信用户,在苹果的 APNs 服务器正常的情况下,也可以保证在秒级别内通知到手机 B 点开 APP 进入前台来收取消息。

6、消息防丢失机制

虽然消息收发架构保证了消息收发双方能够及时收发消息,但该架构不能保证消息在传输过程中不发生丢弃。

当然为了达到任意一条消息都不丢的状态,最简单的方案是手机端对收到的每条消息都给服务器进行一次 ack 确认,但该方案在手机端和服务器之间的交互过多,并且也会遇到在弱网络情况下 ack 丢失等问题。

为了完美的做到消息不丢,微信消息系统对消息收发引入了 sequence 机制。

PS:感兴趣的话,以下是更多与IM消息送达保证有关的文章,可以一并阅读:

  1. 理解IM消息“可靠性”和“一致性”问题,以及解决方案探讨
  2. 融云技术分享:全面揭秘亿级IM消息的可靠投递机制
  3. 从客户端的角度来谈谈移动端IM的消息可靠性和送达机制
  4. IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

7、消息防丢失机制技术实现

7.1sequence 机制

  • 1)每个用户都有42亿的 sequence 空间(从1到 UINT_MAX),从小到大连续分配;
  • 2)每个用户的每条消息都需要分配一个 sequence;
  • 3)服务器存储有每个用户已经分配到的最大 sequence;
  • 4)手机端存储有已收取消息的最大 sequence。

PS:微信sequence序列号生成的具体算法和实现详见《微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)》。

7.2消息收取sequnece确认机制

当服务器和手机端都拥有了一个 sequence 之后,服务器和手机端之间就可以根据两者 sequence 的差异来收取消息,同时保证手机端未收取下去的消息最终能够收取下去。

具体流程如下图表示:

1)根据服务器和手机端之间 sequence 的差异,可以很轻松的实现增量下发手机端未收取下去的消息。

2)对于在弱网络环境差的情况,丢包情况发生概率是比较高的,此时经常会出现服务器的回包不能到达手机端的现象。由于手机端只会在确切的收取到消息后才会更新本地的 sequence,所以即使服务器的回包丢了,手机端等待超时后重新拿旧的 sequence 上服务器收取消息,同样是可以正确的收取未下发的消息。

3)由于手机端存储的 sequence 是确认收到消息的最大 sequence,所以对于手机端每次到服务器来收取消息也可以认为是对上一次收取消息的确认。一个帐号在多个手机端轮流登录的情况下,只要服务器存储手机端已确认的 sequence,那就可以简单的实现已确认下发的消息不会重复下发,不同手机端之间轮流登录不会收到其他手机端已经收取到的消息。

如上图4所示:假如手机 A 拿 Seq_cli = 100 上服务器收取消息,此时服务器的 Seq_svr =  150,那手机 A 可以将 sequence 为[101 - 150]的消息收取下去,同时手机 A 会将本地的 Seq_cli 置为150。

 

如上图5所示:手机 A 在下一次再次上来服务器收取消息,此时 Seq_cli = 150,服务器的 Seq_svr = 200,那手机 A 可以将 sequence为[151 - 200]的消息收取下去。

如上图6所示:假如原手机 A 用户换到手机 B 登录,并使用 Seq_cli = 120 上服务器收取消息,由于服务器已经确认 sequence <= 150 的消息已经被手机收取下去了,故不会再返回 sequence 为[121 - 150]的消息给手机 B,而是将 sequence 为[151 - 200]的消息下发给手机 B。

这里虽然 sequence 为[151 - 200]的消息有可能是被手机 A 和手机 B 都收取到,但由于手机 A 在收到 sequence 为[151 - 200]的消息时并没有给服务器进行确认或者这些消息手机 A 压根就没有收取到,所以为了防止消息丢失,sequence 为[的消息也是需要下发给手机 B 的。

8、本文小结

以上简单文字描述的就是微信最初的IM消息收发的架构。

该架构实现了即时通讯软件对消息收发所需的两个基本要求:

  • 1)消息尽可能的实时送达 ;
  • 2)不丢消息。

以上:是 2014 年微信古早时期的消息收发架构的基本介绍,时过境迁,微信的消息收发架构已经发生了巨大的变化,但我们还是可以从中看到技术演变的价值与力量。

程序员最大的成就与幸福,或许就是自己的代码跑在千万人的设备上,默默支撑着海量的需求。

9、参考资料

[1] iOS的推送服务APNs详解:设计思路、技术原理及缺陷等

[2] 了解iOS消息推送一文就够:史上最全iOS Push技术详解

[3] 消息推送技术干货:美团实时消息推送服务的技术演进之路

[4] 微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

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

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

[7] 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

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

[9] 一套分布式IM即时通讯系统的技术选型和架构设计

[10] 从客户端的角度来谈谈移动端IM的消息可靠性和送达机制

[11] IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

[12] IM开发宝典:史上最全,微信各种功能参数和逻辑规则资料汇总

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

[14] 理解IM消息“可靠性”和“一致性”问题,以及解决方案探讨

[15] 融云技术分享:全面揭秘亿级IM消息的可靠投递机制

10、微信团队的其它文章

微信七年回顾:历经多少质疑和差评,才配拥有今天的强大

前创始团队成员分享:盘点微信的前世今生——微信成功的必然和偶然

即时通讯创业必读:解密微信的产品定位、创新思维、设计法则等

[技术脑洞] 如果把14亿中国人拉到一个微信群里技术上能实现吗?

那些年微信开发过的鸡肋功能,及其带给我们的思考

读懂微信:从1.0到7.0版本,一个主流IM社交工具的进化史

同为IM社交产品中的王者,QQ与微信到底有什么区别

还原真实的腾讯:从最不被看好,到即时通讯巨头的草根创业史

社交应用教父级人物的张小龙和马化腾的同与不同

专访马化腾:首次开谈个人经历、管理心得、技术创新、微信的诞生等

一文读懂微信之父张小龙:失败天才、颠覆者、独裁者、人性操控师

微信团队分享:极致优化,iOS版微信编译速度3倍提升的实践总结

IM“扫一扫”功能很好做?看看微信“扫一扫识物”的完整技术实现

微信团队分享:微信支付代码重构带来的移动端软件架构上的思考

IM开发宝典:史上最全,微信各种功能参数和逻辑规则资料汇总

微信团队分享:微信直播聊天室单房间1500万在线的消息架构演进之路

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

IM全文检索技术专题(四):微信iOS端的最新全文检索技术优化实践

微信团队分享:微信后台在海量并发请求下是如何做到不崩溃的

微信Windows端IM消息数据库的优化实践:查询慢、体积大、文件损坏等

微信技术分享:揭秘微信后台安全特征数据仓库的架构设计

IM跨平台技术学习(九):全面解密新QQ桌面版的Electron内存优化实践

企业微信针对百万级组织架构的客户端性能优化实践

揭秘企业微信是如何支持超大规模IM组织架构的——技术解读四维关系链

微信团队分享:详解iOS版微信视频号直播中因帧率异常导致的功耗问题

微信团队分享:微信后端海量数据查询从1000ms降到100ms的技术实践

大型IM工程重构实践:企业微信Android端的重构之路

IM技术干货:假如你来设计微信的群聊,你该怎么设计?


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

posted @ 2024-04-11 11:05 Jack Jiang 阅读(80) | 评论 (0)编辑 收藏

关于MobileIMSDK

MobileIMSDK 是一套专门为移动端开发的开源IM即时通讯框架,超轻量级、高度提炼,一套API优雅支持 UDP 、TCP 、WebSocket 三种协议,支持 iOS、Android、H5、标准Java、小程序、Uniapp,服务端基于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 实现)。

v9.0 版更新内容

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

  • 1)[新增] 新增“@”功能;
  • 2)[新增] 新增消息引用功能(支持引用全部消息类型);
  • 3)[bug] 解决显示Android端发起的的音视频呼叫记录时,显示的是JSON文本的问题;
  • 4)[bug] 解决了消息转发时,“最近消息”列表中的表情内容没有被转义成表情图标的问题;
  • 5)[bug] 聊天界面中对新发的图片消息等长按时不显示弹出菜单的问题(直到表格被刷新后才会正常);
  • 6)[优化] 首页消息列表中的语音消息将显示语音时长(跟新版微信一样);
  • 7)[优化] 其它优化及bug修复。

新增功能运行截图(更多截图点此查看):

posted @ 2024-04-07 12:18 Jack Jiang 阅读(519) | 评论 (0)编辑 收藏

     摘要: 本文由苏三说技术分享,原题“微信群聊功能,原来是这样设计的!”,下文进行了排版和内容优化等。1、引言当我那天拿着手机,正在和朋友们的微信群里畅聊着八卦新闻和即将到来的周末计划时,忽然一条带着喜意的消息扑面而来,消息正中间写着八个大字:恭喜发财,大吉大利。抢红包!!相信大部分人对此都不陌生,微信的这个群聊系统可以方便地聊天、分享图片和表情,还有那个神奇的红包功能。微信作为 1...  阅读全文

posted @ 2024-04-03 10:25 Jack Jiang 阅读(96) | 评论 (0)编辑 收藏

     摘要: 本文由腾讯技术yeconglu分享,原题“企业微信大型Android系统重构之路”,下文进行了排版和内容优化等。1、引言企业微信本地部署版(下文简称为本地版)是从2017年起,脱胎于企业微信的一款产品。本地版的后台服务能独立部署在政府或者大型企业的本地服务器上。在一个已经迭代了7年的大型Android端工程中,企业微信本地版不可避免地会暴露出一些遗留系统的特点。本文将探讨我...  阅读全文

posted @ 2024-03-28 11:21 Jack Jiang 阅读(114) | 评论 (0)编辑 收藏

本文由微信技术团队仇弈彬分享,原题“微信海量数据查询如何从1000ms降到100ms?”,本文进行了内容修订和排版优化。

1、引言

微信的多维指标监控平台,具备自定义维度、指标的监控能力,主要服务于用户自定义监控。作为框架级监控的补充,它承载着聚合前 45亿/min、4万亿/天的数据量。

当前,针对数据层的查询请求也达到了峰值 40万/min,3亿/天。较大的查询请求使得数据查询遇到了性能瓶颈:查询平均耗时 > 1000ms,失败率居高不下。

针对大数据量带来的查询性能问题,微信团队对数据层查询接口进行了针对性的优化,将平均查询速度从1000ms+优化到了100ms级别。本文为各位分享优化过程,希望对你有用!

 
 

技术交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK备用地址点此

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

2、技术背景

微信多维指标监控平台(以下简称多维监控),是具备灵活的数据上报方式、提供维度交叉分析的实时监控平台。

在这里,最核心的概念是“协议”、“维度”与“指标”。

例如:如果想要对某个【省份】、【城市】、【运营商】的接口【错误码】进行监控,监控目标是统计接口的【平均耗时】和【上报量】。在这里,省份、城市、运营商、错误码,这些描述监控目标属性的可枚举字段称之为“维度”,而【上报量】、【平均耗时】等依赖“聚合计算”结果的数据值,称之为“指标”。而承载这些指标和维度的数据表,叫做“协议”。

多维监控对外提供 2 种 API:

1)维度枚举查询:用于查询某一段时间内,一个或多个维度的排列组合以及其对应的指标值。它反映的是各维度分布“总量”的概念,可以“聚合”,也可以“展开”,或者固定维度对其它维度进行“下钻”。数据可以直接生成柱状图、饼图等。

2)时间序列查询:用于查询某些维度条件在某个时间范围的指标值序列。可以展示为一个时序曲线图,横坐标为时间,纵坐标为指标值。

然而,不管是用户还是团队自己使用多维监控平台的时候,都能感受到明显的卡顿。主要表现在看监控图像或者是查看监控曲线,都会经过长时间的数据加载。

团队意识到:这是数据量上升必然带来的瓶颈。

目前:多维监控平台已经接入了数千张协议表,每张表的特点都不同。维度组合、指标量、上报量也不同。针对大量数据的实时聚合以及 OLAP 分析,数据层的性能瓶颈越发明显,严重影响了用户体验。

于是这让团队人员不由得开始思考:难道要一直放任它慢下去吗?答案当然是否定的。因此,微信团队针对数据层的查询进行了优化。

3、优化分析1:用户查询行为分析

要优化,首先需要了解用户的查询习惯,这里的用户包含了页面用户和异常检测服务。

于是微信团队尽可能多地上报用户使用多维监控平台的习惯,包括但不限于:常用的查询类型、每个协议表的查询维度和查询指标、查询量、失败量、耗时数据等。

在分析了用户的查询习惯后,有了以下发现:

1)时间序列查询占比 99% 以上:

出现如此悬殊的比例可能是因为:调用一次维度枚举,即可获取所关心的各个维度。

但是针对每个维度组合值,无论是页面还是异常检测都会在查询维度对应的多条时间序列曲线中,从而出现「时间序列查询」比例远远高于「维度枚举查询」。

2)针对1天前的查询占比约 90%:

出现这个现象可能是因为每个页面数据都会带上几天前的数据对比来展示。异常检测模块每次会对比大约 7 天数据的曲线,造成了对大量的非实时数据进行查询。

4、优化分析2:数据层架构

分析完用户习惯,再看下目前的数据层架构。

多维监控底层的数据存储/查询引擎选择了 Apache-Druid 作为数据聚合、存储的引擎,Druid 是一个非常优秀的分布式 OLAP 数据存储引擎,它的特点主要在于出色的预聚合能力和高效的并发查询能力。

它的大致架构如图:

具体解释就是:

5、优化分析3:为什么查询会慢

查询慢的核心原因,经微信团队分析如下:

1)协议数据分片存储的数据片段为 2-4h 的数据,每个 Peon 节点消费回来的数据会存储在一个独立分片。

2)假设异常检测获取 7 * 24h 的数据,协议一共有 3 个 Peon 节点负责消费,数据分片量级为 12*3*7 = 252,意味着将会产生 252次 数据分片 I/O。

3)在时间跨度较大时、MiddleManager、Historical 处理查询容易超时,Broker 内存消耗较高。

4)部分协议维度字段非常复杂,维度排列组合极大(>100w),在处理此类协议的查询时,性能就会很差。

6、优化实践1:拆分子查询请求

根据上面的分析,团队确定了初步的优化方向:

  • 1)减少单 Broker 的大跨度时间查询;
  • 2)减少 Druid 的 Segments I/O 次数;
  • 3)减少 Segments 的大小。

在这个方案中,每个查询都会被拆解为更细粒度的“子查询”请求。例如连续查询 7 天的时间序列,会被自动拆解为 7 个 1天的时间序列查询,分发到多个 Broker,此时可以利用多个 Broker 来进行并发查询,减少单个 Broker 的查询负载,提升整体性能。

但是这个方案并没有解决 Segments I/O 过多的问题,所以需要在这里引入一层缓存。

7、优化实践2:拆分子查询请求+Redis Cache

7.1概述

这个方案相较于 v1,增加了为每个子查询请求维护了一个结果缓存,存储在 Redis 中(如下图所示)。

假设获取 7*24h 的数据,Peon 节点个数为 3,如果命中缓存,只会产生 3 次 Druid 的 Segments I/O (最近的 30min)数据,相较几百次 Segments I/O 会大幅减少。

接下来看下具体方法。

7.2时间序列子查询设计

针对时间序列的子查询,子查询按照「天」来分解,整个子查询的缓存也是按照天来聚合的。

以一个查询为例:

{

    "biz_id": 1, // 查询协议表ID:1

    "formula": "avg_cost_time", // 查询公式:求平均

    "keys": [

        // 查询条件:维度xxx_id=3

        {"field": "xxx_id", "relation": "eq", "value": "3"}

    ],

    "start_time": "2020-04-15 13:23", // 查询起始时间

    "end_time": "2020-04-17 12:00"// 查询结束时间

}

其中 biz_id、 formula,、keys 了每个查询的基本条件。但每个查询各不相同,不是这次讨论的重点。

本次优化的重点是基于查询时间范围的子查询分解,而对于时间序列子查询分解的方案则是按照「天」来分解,每个查询都会得到当天的全部数据,由业务逻辑层来进行合并。

举个例子:04-15 13:23 ~ 04-17 08:20 的查询,会被分解为 04-15、04-16、04-17 三个子查询,每个查询都会得到当天的全部数据,在业务逻辑层找到基于用户查询时间的偏移量,处理结果并返回给用户。

每个子查询都会先尝试获取缓存中的数据,此时有两种结果:

经过上述分析不难看出:对于距离现在超过一天的查询,只需要查询一次,之后就无需访问 DruidBroker 了,可以直接从缓存中获取。

而对于一些实时热数据,其实只是查询了cache_update_time-threshold_time 到 end_time 这一小段的时间。在实际应用里,这段查询时间的跨度基本上在 20min 内,而 15min 内的数据由 Druid 实时节点提供。

7.3维度组合子查询设计

维度枚举查询和时间序列查询不一样的是:每一分钟,每个维度的量都不一样。

而维度枚举拿到的是各个维度组合在任意时间的总量,因此基于上述时间序列的缓存方法无法使用。在这里,核心思路依然是打散查询和缓存。

对此,微信团队使用了如下方案。

缓存的设计采用了多级冗余模式,即每天的数据会根据不同时间粒度:天级、4小时级、1 小时级存多份,从而适应各种粒度的查询,也同时尽量减少和 Redis 的 IO 次数。

每个查询都会被分解为 N 个子查询,跨度不同时间,这个过程的粗略示意图如下:

举个例子:例如 04-15 13:23 ~ 04-17 08:20 的查询,会被分解为以下 10 个子查询:

04-15 13:23 ~ 04-15 14:00

04-15 14:00 ~ 04-15 15:00

04-15 15:00 ~ 04-15 16:00

04-15 16:00 ~ 04-15 20:00

04-15 20:00 ~ 04-16 00:00

04-16 00:00 ~ 04-17 00:00

04-17 00:00 ~ 04-17 04:00

04-17 00:00 ~ 04-17 04:00

04-17 04:00 ~ 04-17 08:00

04-17 08:00 ~ 04-17 08:20

这里可以发现:查询 1 和查询 10,绝对不可能出现在缓存中。因此这两个查询一定会被转发到 Druid 去进行。2~9 查询,则是先尝试访问缓存。如果缓存中不存在,才会访问 DruidBroker,在完成一次访问后将数据异步回写到 Redis 中。

维度枚举查询和时间序列一样,同时也用了 update_time 作为数据可信度的保障。因为最细粒度为小时,在理想状况下一个时间跨越很长的请求,实际上访问 Druid 的最多只有跨越 2h 内的两个首尾部查询而已。

8、优化实践3:更进一步(子维度表)

通过子查询缓存方案,我们已经限制了 I/O 次数,并且保障 90% 的请求都来自于缓存。但是维度组合复杂的协议,即 Segments 过大的协议,仍然会消耗大量时间用于检索数据。

所以核心问题在于:能否进一步降低 Segments 大小?

维度爆炸问题在业界都没有很好的解决方案,大家要做的也只能是尽可能规避它,因此这里,团队在查询层实现了子维度表的拆分以尽可能解决这个问题,用空间换时间。

具体做法为:

  • 1) 对于维度复杂的协议,抽离命中率高的低基数维度,建立子维度表,实时消费并入库数据;
  • 2) 查询层支持按照用户请求中的查询维度,匹配最小的子维度表。

9、优化成果

9.1缓存命中率>85%

在做完所有改造后,最重要的一点便是缓存命中率。因为大部分的请求来自于1天前的历史数据,这为缓存命中率提供了保障。

具体是:

  • 1)子查询缓存完全命中率(无需查询Druid):86%;
  • 2)子查询缓存部分命中率(秩序查询增量数据):98.8%。

9.2查询耗时优化至 100ms

在整体优化过后,查询性能指标有了很大的提升:

平均耗时 1000+ms -> 140ms;P95:5000+ms -> 220ms。

 

10、相关文章

[1] 微信后台基于时间序的海量数据冷热分级架构设计实践

[2] IM开发基础知识补课(三):快速理解服务端数据库读写分离原理及实践建议

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

[4] 微信后台基于时间序的新一代海量数据存储架构的设计实践

[5] 陌陌技术分享:陌陌IM在后端KV缓存架构上的技术实践

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

[7] 微信海量用户背后的后台系统存储架构(视频+PPT) [附件下载]

[8] 腾讯TEG团队原创:基于MySQL的分布式数据库TDSQL十年锻造经验分享

[9] IM全文检索技术专题(四):微信iOS端的最新全文检索技术优化实践

[10] 微信Windows端IM消息数据库的优化实践:查询慢、体积大、文件损坏等

[11] 微信技术分享:揭秘微信后台安全特征数据仓库的架构设计

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

11、微信团队的其它文章

Android版微信安装包“减肥”实战记录

iOS版微信安装包“减肥”实战记录

移动端IM实践:iOS版微信界面卡顿监测方案

微信“红包照片”背后的技术难题

IPv6技术详解:基本概念、应用现状、技术实践(上篇)

微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

微信团队分享:Kotlin渐被认可,Android版微信的技术尝鲜之旅

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

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

QQ设计团队分享:新版 QQ 8.0 语音消息改版背后的功能设计思路

微信团队分享:极致优化,iOS版微信编译速度3倍提升的实践总结

IM“扫一扫”功能很好做?看看微信“扫一扫识物”的完整技术实现

微信团队分享:微信支付代码重构带来的移动端软件架构上的思考

IM开发宝典:史上最全,微信各种功能参数和逻辑规则资料汇总

微信团队分享:微信直播聊天室单房间1500万在线的消息架构演进之路

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

微信团队分享:微信后台在海量并发请求下是如何做到不崩溃的

IM跨平台技术学习(九):全面解密新QQ桌面版的Electron内存优化实践

企业微信针对百万级组织架构的客户端性能优化实践

揭秘企业微信是如何支持超大规模IM组织架构的——技术解读四维关系链

微信团队分享:详解iOS版微信视频号直播中因帧率异常导致的功耗问题


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

posted @ 2024-03-21 13:25 Jack Jiang 阅读(84) | 评论 (0)编辑 收藏

本文由冀浩东分享,原题“单核QPS近6000S,陌陌基于OceanBase的持久化缓存探索与实践”,为了阅读便利,本文进行了排版和内容优化等。

1、引言

挚文集团于 2011 年 8 月推出了陌陌,这款立足地理位置服务的开放式移动视频IM应用在中国社交平台领域内独树一帜。陌陌和探探作为陌生人社交领域的主流IM应用,涵盖了多种核心业务模块,包括直播服务、附近动态功能、即时通讯(IM)业务以及增值服务等,每个业务场景都具有其独特性和挑战。

在本文中,陌陌数据库负责人冀浩东将聚焦探讨陌陌的 KV 系统架构选型思路,深入解析如何进行此类系统的甄选决策,同时进一步分享陌陌团队在采用 OceanBase(OBKV)过程中所经历的探索与实践经验。

技术交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK备用地址点此

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

2、关于作者

冀浩东:陌陌(现挚文集团)数据库负责人。目前负责陌陌和探探两个数据库团队建设以及集团数据库存储运营工作。在大规模数据源稳定性建设 、团队建设、成本优化、机房迁移等方面等领域积累了深厚的专业经验与实战心得。

3、陌陌的主要IM业务场景特点

1)直播业务:在陌陌众多业务场景中,直播业务占据了显著位置,其特点就在于随时可能出现的流量突发场景。由于低延时和高并发的需求,直播场景对数据库系统的实时处理能力提出了较高要求。平台需要确保在大量用户同时在线观看和互动时,数据能够被及时、准确地处理和分发。

2)附近动态:此功能则涉及到用户的地理位置信息、活动轨迹以及社交关系等复杂数据。这类数据会迅速积累,并随着时间的推移形成大规模的数据集。数据具有明显的冷热分层特性,即某些数据在某一时刻可能会成为热点,如当某用户发布的帖子引发热议并成为热门话题时。这要求系统能够有效管理并快速响应热点数据的访问需求。

3)IM 业务:此场景的核心特点是低延迟和高并发通信。信息的送达时间必须精确,对实时性有极高的要求。为了保证用户体验,应用程序需要确保消息能够即时、可靠地在用户之间传递。

4)增值服务:则主要侧重于数据的一致性和实时性。在处理用户购买、赠送虚拟物品或享受会员特权等操作时,系统需要确保数据的准确性并及时更新用户账户状态。同时,为了提供优质的增值服务,实时性也是不可或缺的因素,例如实时计算用户的积分、等级或者权益等。

陌陌和探探在运营这些业务场景时,都需要强大的数据处理和管理系统来应对各种特性和挑战,以确保为用户提供高效、稳定且满足个性化需求的社交体验。

针对以上的业务场景,我们应该如何选择 KV 系统呢?

4、陌陌后端KV缓存架构的演进阶段

在公司的成长过程中,存储选型通常会经历四个阶段。

4.1初始阶段

公司的主要目标是能够运行起来。

在创业初期,基于新开发的 App 进行运营工作时,由于业务能力可能还未成熟,为了应对快速迭代的业务需求,对系统的期望不会过高。只需要确保技术层面能够满足基本的业务需求并逐步演进即可。在这个阶段,常见的架构选择包括 Redis 主从架构和 Redis Cluster 等原生架构。

Redis 主从集群架构的优势在于可以迅速构建主从集群或分片集群,并且许多设计可以直接在客户端操作。然而,这种简单的操作方式可能导致设计与客户端业务代码的高度耦合,不利于后期的弹性扩容。

相比之下,Redis Cluster 集群架构支持动态扩容和高可用性。

然而,使用 Redis Cluster 时,业务依赖客户端感知节点变更。如果客户端未能正确处理节点变更,可能会导致服务中断或业务性能下降,因此对于对错误敏感的业务,Redis Cluster 可能会引入额外的复杂性。尽管 Redis Cluster 具有去中心化、组件少、提供 Smart Client 以及支持水平扩展等优点,但也存在批处理功能不友好和缺乏有效流控机制等问题。

4.2第二阶段

进入第二阶段,随着公司的发展和用户数量的增长,需要架构具备快速扩展的能力。

这一阶段的代表性架构例如 Codis、Twemproxy 等基础性 Redis分片架构。

其中,Codis提供了服务端分片方案、中心化管理、故障自动转移、节点水平扩展(1024 槽位)、动态扩缩容,以及支持 pipeline 和批处理等功能。

然而,Codis的当前版本较为陈旧,官方仅提供 3.2.9 版本,更新版本需要自行修复和适配,且由于组件多、资源消耗大。

4.3第三阶段

随着业务的进一步发展和公司进入相对稳定期,可能会发现先前急于扩张时遗留了一些问题。

例如:是否过度使用内存,数据是否可以冷热分层等。这些问题需要重新检验和优化。这个优化过程是第三阶段的重点。

在这个阶段,常见的持久化架构选择包括 oneStore-Pika、Tendis 和 Pika 等。

4.4第四阶段

最后,在第四阶段,公司业务和技术可能已经进入了深度复杂的领域,简单的优化调整可能无法带来显著的收益,甚至可能出现无法进一步优化的情况。

这时,可以通过引入更稳定的架构或者采用新的解决思路来应对挑战。

我们个人推荐考虑多模态架构,它能够适应多种数据类型和工作负载,提供更大的灵活性和优化空间。

总的来说,公司在不同发展阶段的存储选型应根据业务需求、技术成熟度、成本效益以及未来的扩展性和优化空间等因素进行综合考虑和决策。随着公司的发展和业务复杂性的增加,存储架构也需要不断进化和优化,以确保系统的稳定、高效和可持续发展。

5、陌陌自研的KV缓存“oneStore”

针对当前公司的业务状况,陌陌面临的最显著挑战在于集群规模的不断增长。

当单集群分片数量超过 1000 个,数据量超过 10TB,以及 QPS 超过 100 万时,现有的 Codis 架构和 Redis Cluster 架构已然无法满足需求,达到了其承载能力的极限。

为了解决这一瓶颈问题,公司自主研发了一款名为 oneStore 的存储产品(如下图所示)。

这一架构经过了分阶段的优化和改进过程,旨在突破原有的限制,以适应更高的分片数量、更大的数据量以及更密集的查询请求。通过 oneStore 架构,陌陌力求实现业务扩展的无缝对接和性能的大幅提升。

1)第一阶段:提供服务端 Proxy 方案,并通过自主研发的 oneStore Watcher 哨兵组件进行架构精简。这样一来,只需要部署一套哨兵集群,就能有效地管理一个业务区域。

2)第二阶段:提供客户端 SDK 方案。虽然服务端 Proxy 方案表现优秀,但随着业务的稳定,公司着眼于降本增效。直接使用客户端 SDK 方案,感知集群拓扑变化,并且通过 SDK 直连后端 Redis 地址,这样可以去除服务端 Proxy 组件,节省技术资源开销。然而,我们并没有完全摒弃服务端 Proxy 方案。因为目前陌陌的客户端 SDK 方案仅支持 Java 和 C++,对于 PHP、Python 等其他语言的用户,仍需要通过服务端 Proxy 访问数据源。这两种方案的成功运用,帮助我们统一了公司层面 Redis 的接入方式,并显著提升了机房迁移的效率。

随着业务的进一步稳定,陌陌开始从成本角度进行优化,选择 Pika 替代部分请求量不高的 Redis 集群,再提升架构的持久化能力(如下图所示)的同时降低存储成本。

然而现阶段 Pika 主要用来存储一些相对较冷数据,对于热数据的处理性能仍有待提高,后续团队也会持续关注并努力提升这一方面的性能。

总的来说,目前陌陌还面临一些需要解决和优化的场景:

1)单机多实例之间互相影响的问题:陌陌迫切需要解决单机多实例之间相互影响的问题,以确保各个实例的稳定运行和高效协作。这涉及到系统的整体稳定性和协同性,需要有针对性的优化和调整。

2)数据持久化支持:陌陌计划增强数据持久化的支持能力,以实现完整的数据持久化解决方案,以保障数据的完整性和可靠性。不仅仅局限于冷数据,而是要覆盖更广泛的数据类型,以确保数据的完整性和可靠性。这将是系统长期稳定性的一个重要保障。

所以,陌陌需要通过一个简单可靠可扩展的 KV 系统来解决以上问题。

6、陌陌的分布式KV缓存选型

6.1OceanBase

OBKV 是 OceanBase 数据库提供的通过 API 接口访问 Table 模型 Hbase 模型的能力。

有关OceanBase 数据库的来历,详见:阿里技术分享:阿里自研金融级数据库OceanBase的艰辛成长之路 。

之所以选择 OceanBase(OBKV),主要看中其两大优势:

  • 1)性能更好;
  • 2)稳定性高。

6.2关于性能

OceanBase(OBKV)基于 Table 模型构建,与 Redis 数据结构持久化方案这个典型的表模型匹配,且性能比传统持久化存储更强 ,能构建更丰富的数据结构。

下图是OceanBase(OBKV)在大量写数据的场景(TPS 17000),由于不同阶段都有任务在写数据,可以看出 TPS 非常陡峭,并且响应延时在 2 毫秒以下,事务的响应时间明细与预期是相对应的。

下图为 CPU 监控图:可以看到 CPU 使用率在 10% 以下,相对稳定。MemStore 的使用比例也是正常的,在 24% 以内,波动范围非常小,符合预期。

整体来看:OceanBase(OBKV) 生产环境波动小,资源占用稳定。

6.3关于稳定性

OceanBase(OBKV)基于 OceanBase ,存储引擎经过丰富的大规模 TP 场景验证,能提供高并发、低延时的能力。

从下图OceanBase(OBKV) 的多租户功能可见其稳定性。黑色线代表OceanBase(OBKV)租户,蓝色线的租户是 MySQL 租户。在 11:30 左右发起压测以后,OceanBase(OBKV) 租户的响应正常, MySQL 租户也没有受到影响。从服务器层面来看,CPU 负载是因为压测而上升的,而 MySQL 租户并不受影响。

因此可以得出:多租户功能能够有效解决单机多实例的相互影响问题。下图展示了是线上 MySQL 生产租户的表现,TPS 为 5000时,整体表现非常稳定。CPU 和内存使用波动较小,符合预期。

此外:能够便捷地通过 KV 接口将数据存入数据库,并运用 SQL 进行数据查询。OceanBase(OBKV)进一步增强了这一便捷性,支持二级索引以及服务端TTL功能,这有助于显著简化上层服务架构的设计。

尽管如此,OceanBase(OBKV)也存在一定的局限性,如仅提供单机事务处理能力;若要开启分布式事务支持,则可能会影响到系统在高并发环境下的性能表现和低延时响应能力。但鉴于当前陌陌业务的需求,我们认为OceanBase(OBKV)的单机事务能力完全符合要求,并因此共同构建了结合OceanBase(OBKV)- Redis 储存方案。

7、陌陌的分布式KV集群架构改进

陌陌与 OceanBase 开源团队共同打造了一个内部代号为 modis 的项目。

该项目整体架构涵盖了接入层、数据结构层、缓冲层、存储层以及管理平面等多个层次(具体可参考下图)。

值得注意的是:缓冲层在未来的规划中将用于有效解决热点读取及大 KEY 问题的挑战。而在存储层方面,陌陌将对其进行标准化抽象设计,构建出标准的 Storage 结构,以便能够灵活接入包括但不限于OceanBase(OBKV)在内的多种存储解决方案。

在测试评估过程中,将 Pika 数据(总计 158GB)成功迁移到 OceanBase(OBKV)-Redis 集群后,存储占用空间显著减少至 95GB,这一举措带来了存储成本的显著优化,总体上节约了大约 40% 的存储成本。

为了评估性能表现,特意构建了一个专门的测试环境(具体规格参见下图),并在该环境中模拟了不同并发线程场景以观测其峰值性能情况。

基于多租户管理的思路,不会对单一租户分配过多资源,而是优先观察各个租户在使用过程中哪个率先达到性能瓶颈,并据此计算单核的 QPS。当前,陌陌提供的标准规格为 12C40G 内存。未来,为了更好地适应业务需求的变化,可能会推出更小规格的配置方案,例如 4C8G 或 8C16G 等规格,这些决策将完全取决于实际业务的具体需要。

下图展示了 128 个线程数  QPS 70000 情况下 OceanBase(OBKV)-Redis 的性能表现。

具体是:

  • 1)P90 响应延迟为 1.9 ms;
  • 2)P95 响应延迟为 2.2 ms;
  • 3)P99响应延迟为6.3 ms;

平均计算下来,单核读写比例是 4:1,此时单核能力接近 6000 QPS。

此外:在运维管理方面,深入对比了 OceanBase(OBKV)、Pika 以及 TiKV 在日常运维操作中的特性差异。目前,只有 OceanBase(OBKV)提供了原生的多租户支持功能,这一优势有效地解决了在单机部署多实例时所面临的相互干扰的问题。值得一提的是,OceanBase(OBKV)凭借完备的图形化界面管理工具和参数变更即刻生效的特点,对于数据库运维工作来说,无疑是极其贴心且高效的解决方案。

总的来说,OceanBase(OBKV)-Redis 实现了性能的显著提升、更少的磁盘使用以及运维管理的极大简化。

这主要得益于 OceanBase(OBKV)-Redis 的几个优势:

  • 1)多租户隔离,解决单机多实例互相影响的困境;
  • 2)存储成本更低。通过 Encoding 框架 + 通用压缩 ,进行表模型存储;
  • 3)性能更高。将请求过滤直接下压存储,不用序列化以及反序列化,支持服务端 TTL。

8、相关文章

[1] 知乎技术分享:从单机到2000万QPS并发的Redis高性能缓存实践之路

[2] 微信后台基于时间序的新一代海量数据存储架构的设计实践

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

[4] 腾讯TEG团队原创:基于MySQL的分布式数据库TDSQL十年锻造经验分享

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

[6] 微信技术分享:揭秘微信后台安全特征数据仓库的架构设计

[7] 阿里技术分享:深度揭秘阿里数据库技术方案的10年变迁史

[8] 阿里技术分享:阿里自研金融级数据库OceanBase的艰辛成长之路

[9] 阿里IM技术分享(九):深度揭密RocketMQ在钉钉IM系统中的应用实践

[10] 阿里IM技术分享(七):闲鱼IM的在线、离线聊天数据同步机制优化实践

[11] 阿里IM技术分享(八):深度解密钉钉即时消息服务DTIM的技术设计

[12] IM开发基础知识补课(六):数据库用NoSQL还是SQL?读这篇就够了!

[13] 小红书万亿级社交网络关系下的图存储系统的架构设计与实践

[14] IM开发基础知识补课(三):快速理解服务端数据库读写分离原理及实践建议

[15] 微信后台基于时间序的海量数据冷热分级架构设计实践

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

posted @ 2024-03-14 12:09 Jack Jiang 阅读(20) | 评论 (0)编辑 收藏

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

​[- 1 -] 直播系统聊天技术(一):百万在线的美拍直播弹幕系统的实时推送技术实践之路

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

[摘要] 本文作者是美拍的架构师,经历了直播弹幕从无到有,从小到大的过程,借此文为大家分享构建弹幕系统的经验,希望能为正在开发或正打算开发弹幕、消息推送、IM聊天等系统的技术同行带来一些启发。

[- 2 -] 直播系统聊天技术(二)阿里电商IM消息平台,在群聊、直播场景下的技术实践

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

[摘要] 本文来自淘宝消息业务团队的技术实践分享,分析了电商IM消息平台在非传统IM应用场景下的高发并、强互动群聊和直播业务中的技术特点,总结并分享了在这些场景下实现大量多对多实时消息分发投递的一些架构方面的设计实践。

[- 3 -] 直播系统聊天技术(三):微信直播聊天室单房间1500万在线的消息架构演进之路

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

[摘要] 本文将回顾微信直播聊天室单房间海量用户同时在线的消息组件技术设计和架构演进,希望能为你的直播聊天互动中的实时聊天消息架构设计带来启发。

[- 4 -] 直播系统聊天技术(四):百度直播的海量用户实时消息系统架构演进实践

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

[摘要] 本文主要分享的是百度直播的消息系统的架构设计实践和演进过程。

[- 5 -] 直播系统聊天技术(七):直播间海量聊天消息的架构设计难点实践

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

[摘要] 本文将主要从高可用、弹性扩缩容、用户管理、消息分发、客户端优化等角度,分享直播间海量聊天消息的架构设计技术难点的实践经验。

[- -] 直播系统聊天技术(八):vivo直播系统中IM消息模块的架构实践

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

[摘要] 本文针对秀场直播,结合我们一年以来通过处理不同的业务线上问题,进行了技术演进式的IM消息模块架构的升级与调整,并据此进行了技术总结、整理成文,希望借此机会分享给大家。

[- 7 -] 直播系统聊天技术(九):千万级实时直播弹幕的技术实践

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

[摘要] 本文基于网易云信针对TFBOYS某场线上演唱会的技术支持,为你分享千万级在线用户量的直播系统中实时弹幕功能的技术实践,希望能带给你启发。

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

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

[摘要] 本文总结了企业微信的IM消息系统架构设计,阐述了企业业务给IM架构设计带来的技术难点和挑战,以及技术方案的对比与分析。同时总结了IM后台开发的一些常用手段,适用于IM消息系统。

[- -]  融云IM技术分享:万人群聊消息投递方案的思考和实践

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

[摘要] 本文根据融云技术团队的实践经验,总结了万人群聊消息投递方案的一些思考和实践,希望能给你带来启发。

[- 10 -] 实时社群技术专题(一):支持百万人超级群聊,一文读懂社群产品Discord

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

[摘要] 本文为系列文章的首篇,文章内容不讨论Discord具体的技术实现,仅从其产品定义的角度上对Discord软件进行详尽和具体的介绍,希望能帮助你对Discord从产品形态上有较为完整的认知,也方便你阅读本系列文章的后续篇章。

[- 11 -] 实时社群技术专题(二):百万级成员实时社群技术实现(消息系统篇)

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

[摘要] 本文是序列文章的第2篇,将要分享的是云信的实时社群产品“圈组”(“圈组”是云信的类Discord产品实现方案)的消息系统技术设计实践。

[- 12 -] 海量用户IM聊天室的架构设计与实践

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

[摘要] 本文将分享网易云信针对海量用户IM聊天室的架构设计与应用实践,希望能带给你启发。

👉52im社区本周新文:《陌陌技术分享:陌陌IM在后端KV缓存架构上的技术实践》,欢迎阅读!👈

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

posted @ 2024-03-13 14:00 Jack Jiang 阅读(58) | 评论 (0)编辑 收藏

     摘要: 本文由百度技术团队分享,引用自百度Geek说,原题“千万级高性能长连接Go服务架构实践”,为了阅读便利,本文进行了排版优化等。1、引言移动互联网时代,长连接服务成为了提升应用实时性和互动性的基础服务。本文将介绍百度基于golang实现的统一长连接服务,从统一长连接功能实现和性能优化等角度,描述了其在设计、开发和维护过程中面临的问题和挑战,并重点介绍了解决相关问题和挑战的方案...  阅读全文

posted @ 2024-03-07 10:59 Jack Jiang 阅读(98) | 评论 (0)编辑 收藏

本文由ELab团队公众号授权发布,原题《Rust语言在IM客户端的实践》,来自抖音电商前端团队的分享,本文有修订和改动。

1、引言

本文将介绍飞鸽IM前端团队如何结合Rust对飞鸽客户端接待能力进行的技术提升,一步步从概念验证、路径分解到分工开发,再到最后上线收益论证,并分享了其中遇到的技术挑战与经验总结等。

本项目是一个长周期的复杂项目,相信本项目落地的经验对其他同学及团队能有所借鉴。

 
 

技术交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK备用地址点此

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

2、技术背景

飞鸽是在抖音电商业务上面向商家和用户的聊天工具,其拉通售前、售中、售后渠道,为商家履约提供重要支撑。

对于飞鸽桌面端IM而言,我们会面临很多基础挑战,比如做好会话稳定性、操作流畅性、冷启动速度等,而在满足98%以上的用户需求且业务趋于稳定后,一些在冲刺后遗留的性能天花板问题暴露在我们面前,其中 高并发接待 & 多开是两个重要的挑战,是旧账与难啃的硬骨头。

为何持续会有这些挑战存在?

1)历史技术选型,包含者成本、人力、效率等考量,飞鸽客户端使用的技术栈是react + electron:

* im sdk与业务渲染代码都由 js 编写,im sdk同时是cpu密集型 & io 密集型的组件,在高并发场景下,渲染频率也比较高,业务与sdk相互抢占cpu资源与io资源,导致收发消息慢、操作卡顿(高并发限制)。

* 由于im sdk运行在webview中,所以收发消息依赖webview存活,故多开账号 = 多个webview,内存成本线性增长。

2)im页面在web层面多次优化后已接近架构上限,无法基于现有架构做更多天花板的突破。

对于以上这些挑战,我们给出的解法是:对现有架构进行调整,使用Rust语言对im sdk进行重写,彻底解除这一块的性能瓶颈!

3、为什么选Rust语言?

飞鸽im sdk是一个对运行稳定性要求高的组件,其工程量大、逻辑复杂,对于异步特性使用非常频繁,其对于内存安全、 线程安全有着比较严格的要求。

假如使用C++,作为新手并没有把握能够将复杂的IM SDK少bug的编写下来(团队限制)。

Rust学习曲线虽然陡峭,但是其为安全设计的各类语言特性、强大的编译器,能够将新人编写代码的问题数降到最低(逻辑问题除外)。

并且飞书团队提供了客户端的rust生态库,帮助我们解决很多的基建问题,所以这里使用Rust是相当合适的。

Rust学习成长曲线:

4、飞鸽IM客户端历史架构的问题

如背景中所描述,历史架构存在这两个问题:

  • 1)IM SDK 与 业务JS代码共用Weview资源,接待密集的时候,sdk与业务,互相抢占cpu与io资源,导致容易卡顿、消息延迟;
  • 2)多开的账号必须依赖IM Webview存活(否则无法收到消息),内存线性增长。

5、飞鸽IM客户端新架构与预期目标

具体是:

  • 1)Rust独立进程承担所有的im sdk的计算压力,可以大幅减轻js线程压力,可提升压力场景接待体验;
  • 2)Rust im SDK 解除浏览器中的IO限制(如同域名并发数限制);
  • 3)解除Webview存活依赖,依靠rust进程也可收消息,为更多账号的多开能力提供了铺垫。

6、先用Rust进行技术可行性验证

为了验证推测切实可行,我们提前做了完备的POC验证。

在POC中,我们针对“单进程单线程模型”、“多进程模型”、“多线程模型”,这三种模型搭建了mvp demo,即简易的客服聊天模型,并进行压力测试,并监测其内存、cpu等指标。

通过POC,我们得出的结论是:

具体就是:

  • 1)rust 整体优于 js,计算占比越重,优势越明显(高压时cpu差别能到达3倍以上);
  • 2)架构选型上,rust进程独立是最好的方案,稳定性更优、性能损耗相差较小。

7、新架构开始实施

路要一步步走,整个项目粗估下来会有上百的工作日,作为业务团队,我们无法在短期内投入大量的资源去做这个项目,所以需要一步一步拆解、验证、拿收益。

团队内native开发资源有限,这件事情的进行也需要团队进行学习、成长。下面我们将详细分享这个过程 。

8、新架构实施阶段1:Rust SDK工程基建

造房子先得有一个地基 —— Rust工程的基础建设,是Native业务的前置条件!

桌面端同学牵头搭建了整个RustSDK地基,地基解决的问题如下图所示:

需要做的工作:

  • 1)业务容器:有规律的组织代码结构,进行业务隔离、资源隔离;
  • 2)跨进程调用封装:降低业务调用难度;
  • 3)建设日志系统、日志回捞:降低排查问题的难度;
  • 4)构建跨平台异步执行环境:简化异步代码编写,底层封装,便于跨平台代码迁移;
  • 5)跨平台编译,跨平台集成;
  • 6)... ...

9、新架构实施阶段2:IM基础能力夯实

在拥有一部分地基后,我们开始针对IM SDK的基础能力进行实现和验证。

因为只有完成基础能力验证之后,我们才会有信心在新的架构上叠加更多的功能。

这阶段我们关注以下指标( 希望其存在优化,至少不劣化):

  • 1)长链在线率;
  • 2)消息发送成功率;
  • 3)卡顿率;
  • 4)Rust进程崩溃率、无响应率。

仅实现长链能力下沉,验证&提升其稳定:

本阶段论证结果如下:

  • 1)Rust Crash率, 达成预期;
  • 2)Rust无响应率 - 未达预期,可优化;
  • 3)长链在线率 - 达成预期,但是存在优化空间;
  • 4)卡顿率 - 不劣化 达成预期;
  • 5)消息发送成功率 - 不劣化,达成预期。

这阶段的工作是考验耐心的,因为这个阶段并不能带来实质性的用户体验提升、也无法拿到明显的提升数据,只是作为中间阶段,它有存在的必要性。

这阶段后,在稳定性治理、基础能力验证、 Rust 语言经验、指标制定合理性这几方面,我们踩上了一个更结实的台阶,更有信心去进行更复杂的下一阶段。

10、 新架构实施阶段3:使用Rust实现IM SDK全部能力

夯实基础后,我们开始发力冲刺,大刀阔斧的对IM SDK进行重新设计、实现、联调以及上线。

此阶段要实现im sdk的全部能力、 并对线上运行的js im sdk进行替换。

由于飞鸽im对于通信模块的稳定程度要求是很高的,替换过程就像是在高速行驶的车辆上替换轮胎,如果出现问题也容易导致大量的客服负面反馈。

因此,新rust sdk的稳定性、异常问题时的兜底方案、灰度时的监控观察、对新增反馈的留意都很重要,放量过程会存在一定精神压力。

工作内容大致如下。

1)多实例的Rust IM SDK设计(商家单聊、群聊、平台客服)、Js -> Rust IMSDK跨端调用协议设计:

  • a)分析、拆解所有Js Im SDK至今具有的能力,并以贴合Rust的方式重新设计;
  • b)需要在协议设计中,尽可能的合并 & 简化 Js -> Rust的调用,以减少IPC通信成本。

2)开发:

  • a)Rust IM SDK核心实现;
  • b)Rust\Js适配同学紧密合作,根据协议进行业务实现、业务适配;
  • c)密切沟通,发现问题及时纠偏;
  • d)编写单测;

3)测试:

  • a)各类IM场景回归测试;
  • b)性能进行验证。

4)异常兜底方案实现:

设计数据冗余,当Rust进程出现崩溃、无响应、不可恢复的网络错误时,识别并fallback到 web版本,使用冗余数据快速恢复im sdk正常运行状态,确保用户体验。

5)稳妥的上线方案 & 稳定性治理。

6)调用&适配优化,结合Native能力进一步性能优化。

7)结果回收。

8)其中各个步骤都会存在一些挑战,在后后面的内容会提到。

调用简化模型:

IM Core简化模型:

11、新架构实施阶段4:基于稳定的RustIM SDK实现形态升级

最后的阶段,我们基于完善的Rust IM SDK的能力进行形态的升级。

本阶段正在进行中,完成后会做更多的分享。

1)多窗口改造:销毁后台的多开账号,让多开账号数量突破到25个。

 

2)消息提醒、通知流程改造。

3)消息本地化能力:加快消息上屏。

12、技术挑战与实践总结

12.1编程语言 & IM领域知识突破

一个有战斗力的团队,一定是持续学习、进步的。

比如:

  • 1)获取学习的纯粹快乐:当沉浸在学习中,并感受到自己在进步的时候,会是一个快乐的状态;
  • 2)逐步克服小挑战,及时获得正反馈;
  • 3)在同事中找到伙伴和老师,询问与探讨:建立团队中的学习氛围。

 

12.2长周期技术项目,如何持续保持信心 ?

比如 :

  • 1)Leader与同事认可与支持 — 团队基础、价值观鼓励;
  • 2)关注长期收益,训练自己延迟满足感;
  • 3)做好阶段性分解与验证,缩短单个周期(如本文的一二阶段拆解,可逐步累积信心);
  • 4)增强自身实力,做好问题把控,及时发现&解决问题。

 

12.3高效合作

团队Native开发同学少,且各自并行业务需求,需合理的安排开发路线,减少总开发时长。

 
  • 1)合理的设计开发并行路线,减少串行依赖
  • 2)协议与接口先行;
  • 3)各同学负责其相近&擅长的部分;
  • 4)联调时缩短彼此距离,高效沟通。

 

12.4保障用户体验的灰度上线

1)编写模块的健康自检,检测到异常时用最小的代价切换备用老方案。

2)完善业务监控&技术指标监控:crash率、无响应率、长链在线率、发消息成功率、请求成功率、卡顿率等。

3)对真实用户使用体验进行跟踪:

  • a)书反馈群组维护,及时获得用户反馈;
  • b)与商家客服保持线下联系,获取一手体验情况。

4)放量节奏的把控:

  • a)大型改动可以先给白名单用户试用,收集反馈;
  • b)放出能够识别问题的量,解决问题后再继续放量;
  • c)放量期间主动查询用户实时反馈数据,有问题及时解决。

 

12.5如何减少IPC通信成本带来的开销

频率过高的IPC通信可能使得CPU优化适得其反,因为老版本都运行在Js中,所以调用频率是没有节制的(循环读取数据也经常出现),必须要在设计上降低下来——降低业务JS线程的压力。

以下措施可以将本场景通信成本降低90%以上。

1)更高效的数据协议 protobuf:相较于json,数据更小、解析和序列化性能更高、跨语言生成代码工具。

2)Rust push to js:使用数据收集去重 + debounce批量更新的策略,合并多个数据回调接口,减少通信频率。

3)Js call rust(单次基础耗时4ms):

  • a)适当缓存数据,不用每次都回源查询;
  • b)需要频繁调用的逻辑下沉Rust,Rust逻辑自完善。

12.6结果回收:极端场景下的优化大盘数据体现不明显

 

针对某种场景做的优化工作不容易在大盘数据中得到体现(尤其在灰度阶段),我们应该针对特殊场景建立新指标。

即编写策略,识别并收集极端场景下的数据:为了衡量极端场景的的卡顿优化,建立了忙碌与卡顿指标,可以衡量出用户接待忙碌程度与卡顿率的关系,并且通过此指标将优化清晰的衡量出来。

12.7Rust SDK的问题治理

具体是:

  • 1)前期的问题不稳定,需更多信息辅助排查,日志尽量完整;
  • 2)与真实用户群体保持联系,可加快问题验证、问题发现的过程;
  • 3)需要建设便捷的日志回捞 & 日志分析工具(帮助快速找到日志还原现场)。

13、新架构带来的收益

压力评测:

数据表现:

解读一下:

  • 1)客服发送消息,大盘端到端耗时降低 40%;
  • 2)消息发送成功率三个9 -> 四个9;
  • 3)im页面大盘卡顿率降低 15%;
  • 4)密集接待场景,卡顿率降低 50%。

全量至今,再无大量进线导致卡顿的反馈。回访历史反馈用户,皆无因大量接待导致的卡顿现象

14、相关文章

[1] 阿里技术分享:闲鱼IM基于Flutter的移动端跨端改造实践

[2] IM开发干货分享:有赞移动端IM的组件化SDK架构设计实践

[3] IM开发干货分享:我是如何解决大量离线消息导致客户端卡顿的

[4] 如约而至:微信自用的移动端IM网络层跨平台组件库Mars已正式开源

[5] 从客户端的角度来谈谈移动端IM的消息可靠性和送达机制

[6] IM开发干货分享:IM客户端不同版本兼容运行的技术思路和实践总结

[7] IM全文检索技术专题(四):微信iOS端的最新全文检索技术优化实践

[8] 从游击队到正规军(二):马蜂窝旅游网的IM客户端架构演进和实践总结

[9] IM跨平台技术学习(九):全面解密新QQ桌面版的Electron内存优化实践

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

[11] 抖音技术分享:抖音Android端手机功耗问题的全面分析和详细优化实践

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


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

posted @ 2024-02-29 10:26 Jack Jiang 阅读(75) | 评论 (0)编辑 收藏

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

[- 1 -] 快速裂变:见证微信强大后台架构从0到1的演进历程(一)

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

[摘要] 2个月的开发时间,微信后台系统经历了从0到1的过程。从小步慢跑到快速成长,经历了平台化到走出国门,微信交出的这份优异答卷,解题思路是怎样的?


[- 2 -] 如何保证IM实时消息的“时序性”与“一致性”?

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

[摘要] 实时消息时序和一致性是分布式系统架构设计中非常难的问题(尤其IM应用这种以消息为中心的应用形态),困难在哪?有什么常见优化实践?这就是本文要讨论的内容。


[- 3 -] IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?

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

[摘要] “用户在线状态的一致性”(单聊好友在线状态、群聊用户在线状态)是IM应用领域比较难解决的一个技术问题,如何精准实时的获得好友、群友的在线状态,是今天将要探讨的话题。


[- 4 -]IM群聊消息如此复杂,如何保证不丢不重?

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

[摘要] 由于“消息风暴扩散系数”的存在(概念详见《IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?》),群消息的复杂度要远高于一对一的单聊消息。群消息的实时性、可达性、离线消息是今天将要讨论的核心话题。


[- 5 -] 微信后台团队:微信后台异步消息队列的优化升级实践分享

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

[摘要] 本文分享了该组件2.0版本的功能特点及优化实践,希望能为类似业务(比如移动端IM系统等)的消息队列设计提供一定的参考。


[- -] 移动端IM中大规模群消息的推送如何保证效率、实时性?

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

[摘要] 当然,实际在生产环境下,群消息的发送都会想尽办法进行压缩,并开展各种改善性能的处理办法,而不是像上述举例里的直接扩散写(即2000人群里,一条消息被简单地复制为2000条一对一的消息投递)。具体有哪些优先策略?本文或许可以带给你一些启发。


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

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

[摘要] 本文内容主要涉及IM系统中的消息系统架构,探讨一种适用于大用户量的消息同步以及存储系统的架构实现,能够支持消息系统中的高级特性『多端同步』以及『消息漫游』。在性能和规模上,能够做到全量消息云端存储,百万TPS以及毫秒级延迟的消息同步能力。


[- 8 -] 关于IM即时通讯群聊消息的乱序问题讨论

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

[摘要] 问题描述:客户端A、B、C,服务端S,例如:A发三条群消息,B、C收到的消息都是乱序,目前问题:A发第一条消息失败之后排到队列,这时服务端还在持续发消息,那么第二条消息送达到B、C,然后客户端最先显示的就不是第一条消息,导致乱序出现。


[- 9 -]  IM群聊消息的已读回执功能该怎么实现?

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

[摘要] 那么群聊消息的收发流程、消息的送达保证、已读回执机制,到底该怎么实现呢?这就是今天要讨论的话题。


[- 10 -] IM群聊消息究竟是存1份(即扩散读)还是存多份(即扩散写)?

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

[摘要] 任何技术方案,都不是天才般灵感乍现想到的,一定是一个演进迭代,逐步优化的过程。今天就聊一聊,IM群聊消息,为啥只需要存一份。


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

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

[摘要] 本文将分享的是一套生产环境下的IM群聊消息系统的高可用、易伸缩、高并发架构设计实践,属于原创第一手资料,内容较专业,适合有一定IM架构经验的后端程序员阅读。


[- 12 -] [技术脑洞] 如果把14亿中国人拉到一个微信群里技术上能实现吗?

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

[摘要] 听到这个问题,全厂的人都炸了。要知道一个微信群最多只能有500人啊,QQ群也只有2000而已。当你有机会加入一个2000人QQ群的时候,你就已经感受到“信息爆炸”的可怕……


[- 13 -] IM群聊机制,除了循环去发消息还有什么方式?如何优化?

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

[摘要] 目前我是用循环来获取群成员,然后获取群成员ID去循环调用senddata()方法,想不用循环或者用其他什么方式来优化群聊循环发送这个机制,各位大佬有什么办法没?


[- 14 -] 网易云信技术分享:IM中的万人群聊技术方案实践总结

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

[摘要] 本文内容是网易云信团队为了响应万人群聊功能需求,在设计实现万人群聊技术方案中总结的技术实践,借此机会分享给各IM开发者同行。


[- 15 -] 阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处

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

[摘要] 本文适合有一定IM后端架构设计经验的开发者阅读,或许出于商业产品技术秘密的考虑,分享者在本次所分享的内容上有所保留,鉴于阿里对于钉钉在技术上的内容分享做的非常少,所以本文虽然内容不够全面,但仍然值得一读。


👉52im社区本周新文:《抖音技术分享:飞鸽IM桌面端基于Rust语言进行重构的技术选型和实践总结》,欢迎阅读!👈

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

posted @ 2024-02-28 13:19 Jack Jiang 阅读(106) | 评论 (0)编辑 收藏

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

[- 1 -] IM开发技术学习:揭秘微信朋友圈这种信息推流背后的系统设计

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

[摘要] 本文将重点讨论的是“关注”功能对应的技术实现:先总结常用的基于时间线Feed流的后台技术实现方案,再结合具体的业务场景,根据实际需求在基本设计思路上做一些灵活的运用。


[- 2 -] 阿里IM技术分享(六):闲鱼亿级IM消息系统的离线推送到达率优化

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

[摘要] 本文将要分享的是闲鱼IM消息在解决离线推送的到达率方面的技术实践,内容包括问题分析和技术优化思路等,希望能带给你启发。


[- 3 -] 阿里IM技术分享(七):闲鱼IM的在线、离线聊天数据同步机制优化实践

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

[摘要] 本篇将要分享的是闲鱼IM系统中在线和离线聊天消息数据的同步机制上所遇到的一些问题,以及实践性的解决方案。


[- 4 -] 探探的IM长连接技术实践:技术选型、架构设计、性能优化

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

[摘要] 本文将要分享的是陌生人社交应用探探的IM长连接模块从技术选型到架构设计,再到性能优化的整个技术实践过程和经验总结。


[- 5 -] IM开发干货分享:浅谈IM系统中离线消息、历史消息的最佳实践

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

[摘要] 本文将基于IM消息系统的技术实践,分享关于离线消息和历史消息的正确理解,以及具体的技术配合和实践,希望能为你的离线消息和历史消息技术设计带来最佳实践灵感。


[- 6 -] IM开发干货分享:IM客户端不同版本兼容运行的技术思路和实践总结

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

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


[- 7 -] 字符编码那点事:快速理解ASCII、Unicode、GBK和UTF-8

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

[摘要] 字符编码是计算机技术的基石,对于程序员来说尤其重要,字符编码的知识是必须要懂的。


[- 8 -] IM开发基础知识补课(八):史上最通俗,彻底搞懂字符乱码问题的本质

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

[摘要] 对于乱码这个看似不起眼,但并不是一两话能讲清楚的问题,是很有必要从根源了解字符集和编码原理,知其然知其所以然显然是一个优秀码农的基本素养,所以,便有了本文,希望能帮助到你。


[- -]  史诗级计算机字符编码知识分享,万字长文,一文即懂!

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

[摘要] 前一阵跟同事碰到了字符乱码的问题,了解后发现这个问题存在两年了,我们程序员每天都在跟编码打交道,但大家对字符编码都是一知半解:“天天吃猪肉却很少见过猪跑”,今天我就把它彻底讲透!


[- 10 -] 百度统一socket长连接组件从0到1的技术实践

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

[摘要] 本文旨在探讨socket长连接技术在移动端的实践,并以iOS端为例,重点分享了百度在实现统一socket长连接组件过程中的技术选型和整体架构设计逻辑。并结合IM即时通讯聊天应用案例,展示长连接组件是如何在移动应用领域为类似业务场景提供解决方案的。


[- 11 -] 淘宝移动端统一网络库的架构演进和弱网优化技术实践

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

[摘要] 本文将介绍淘宝 APP 统一网络库演进的过程,讲述如何围绕体验持续构建南北向从监测到加速一体化的终端网络架构,通过构建 NPM 弱网诊断感知能力,落地原生多通道技术/多协议择优调度手段,贴合厂商附能网络请求加速,实现去 SPDY 及规模化 IPv6/H3 协议簇的平滑过渡,为用户提供弱网更好、好网更优的 APP 加载浏览体验,支撑业务创造更多的可能性。


[- 12 -] 揭秘企业微信是如何支持超大规模IM组织架构的——技术解读四维关系链

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

[摘要] 本文将摘取企业微信的其中一个技术分支——IM体系之下的“关系链”内核要素,为你揭秘企业微信是如何支持超大规模IM组织架构的。


👉52im社区本周新文:《长连接网关技术专题(九):去哪儿网酒店高性能业务网关技术实践》,欢迎阅读!👈

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

posted @ 2024-02-22 12:13 Jack Jiang 阅读(106) | 评论 (0)编辑 收藏

本文由去哪儿网技术团队田文琦分享,本文有修订和改动。

1、引言

本文针对去哪儿网酒店业务网关的吞吐率下降、响应时间上升等问题,进行全流程异步化、服务编排方案等措施,进行了高性能网关的技术优化实践。

技术交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK备用地址点此

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

2、作者介绍

田文琦:2021年9月加入去哪儿网机票目的地事业群,担任软件研发工程师,现负责国内酒店主站技术团队。主要关注高并发、高性能、高可用相关技术和系统架构。主导的酒店业务网关优化项目,荣获22年去哪儿网技术中心TC项目三等奖。

3、专题目录

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

  1. 长连接网关技术专题(一):京东京麦的生产级TCP网关技术实践总结
  2. 长连接网关技术专题(二):知乎千万级并发的高性能长连接网关技术实践
  3. 长连接网关技术专题(三):手淘亿级移动端接入层网关的技术演进之路
  4. 长连接网关技术专题(四):爱奇艺WebSocket实时推送网关技术实践
  5. 长连接网关技术专题(五):喜马拉雅自研亿级API网关技术实践
  6. 长连接网关技术专题(六):石墨文档单机50万WebSocket长连接架构实践
  7. 长连接网关技术专题(七):小米小爱单机120万长连接接入层的架构演进
  8. 长连接网关技术专题(八):B站基于微服务的API网关从0到1的演进之路
  9. 长连接网关技术专题(九):去哪儿网酒店高性能业务网关技术实践》(* 本文

4、技术背景

近来,Qunar 酒店的整体技术架构在基于 DDD 指导思想下,一直在进行调整。其中最主要的一个调整就是包含核心领域的团队交出各自的“应用层”,统一交给下游网关团队,组成统一的应用层。

这种由多个网关合并成大前台(酒店业务网关)的融合,带来的好处是核心系统边界清晰了,但是对酒店业务网关来说,也带来了不小的困扰。

系统面临的压力主要来自两方面:

  • 1)首先,一次性新增了几十万行大量硬编码、临时兼容、聚合业务规则的复杂代码且代码风格迥异,有些甚至是跨语言的代码迁移;
  • 2)其次,后续的复杂多变的应用层业务需求,之前分散在各个子网关中,现在在源源不断地汇总叠加到酒店业务网关。

这就导致了一系列的问题:

  • 1)业务网关吞吐性能变差:应对流量尖峰时期的单机最大吞吐量与合并之前相比,下降了20%
  • 2)内部业务逻辑处理速度变差:主流程业务逻辑的处理时间与合并之前相比,上涨了10%。
  • 3)代码难以维护、开发效率低:主站内部各个模块之间严重耦合,边界不清,修改扩散问题非常明显,给后续的迭代增加了维护成本,开发新需求的效率也不高。

酒店业务网关作为直接面对用户的系统,出现任何问题都会被放大百倍,上述这些问题亟待解决。

5、吞吐量下降问题分析

现有系统虽然业务处理部分是异步化的,但是并不是全链路异步化(如下图所示)。

同步 servlet 容器,servlet 线程与业务逻辑线程是同一个,高峰期流量上涨或者尤其是遇到流量尖峰的时候,servlet 容器线程被阻塞的时候,我们服务的吞吐量就会明显下降。

业务处理虽然使用了线程池确实能实现异步调用的效果,也能压缩同步等待的时间,但是也有一些缺陷。

比如:

  • 1)CPU 资源大量浪费在阻塞等待上,导致 CPU 资源利用率低;
  • 2)为了增加并发度,会引入更多额外的线程池,随着 CPU 调度线程数的增加,会导致更严重的资源争用,上下文切换占用 CPU 资源;
  • 3)线程池中的线程都是阻塞的,硬件资源无法充分利用,系统吞吐量容易达到瓶颈。

6、响应时间上涨问题分析

前期为了快速落地酒店 DDD 架构,合并大前台的重构中,并没有做到一步到位的设计。

为了保证项目质量,将整个过程切分为了迁移+重构两个步骤。迁移之后,整个酒店业务网关的内部代码结构是割裂、混乱的。

总结如下:

我们最核心的一个接口会调用70多个上游接口,上述问题:边界不清、不内聚、各种重复调用、依赖阻塞等问题导致了核心接口的响应时间有明显上涨。

7、 解决方案Part1:全流程异步化提升吞吐量

全流程异步化方案,我们主要采用的是 Spring WebFlux。

7.1选择的理由

1)响应式编程模型:Spring WebFlux 基于响应式编程模型,使用异步非阻塞式 I/O,可以更高效地处理并发请求,提高应用程序的吞吐量和响应速度。同时,响应式编程模型能够更好地处理高负载情况下的请求,降低系统的资源消耗。

2)高性能:Spring WebFlux 使用 Reactor 库实现响应式编程模型,可以处理大量的并发请求,具有出色的性能表现。与传统的 Spring MVC 框架相比,Spring WebFlux 可以更好地利用多核 CPU 和内存资源,以实现更高的性能和吞吐量。

3)可扩展性:Spring WebFlux 不仅可以使用 Tomcat、Jetty 等常规 Web 服务器,还可以使用 Netty 或 Undertow 等基于 NIO 的 Web 服务器实现,与其它非阻塞式 I/O 的框架结合使用,可以更容易地构建可扩展的应用程序。

4)支持函数式编程:Spring WebFlux 支持函数式编程,使用函数式编程可以更好地处理复杂的业务逻辑,并提高代码的可读性和可维护性。

5)50与 Spring 生态系统无缝集成:Spring WebFlux 可以与 Spring Boot、Spring Security、Spring Data 等 Spring 生态系统的组件无缝集成,提供了完整的 Web 应用程序开发体验。

7.2实现原理和异步化过程

上图中从下到上每个组件的作用:

  • 1)Web Server:适配各种 Web 服务, 监听客户端请求,并将其转发到 HttpHandler 处理;
  • 2)HttpHandler:以非阻塞的方式处理响应式 http 请求的最底层处理器,不同的处理器处理的请求都会归一到 httpHandler 来处理,并返回响应;
  • 3)DispatcherHandler:调度程序处理程序用于异步处理 HTTP 请求和响应,封装了HandlerMapping、HandlerAdapter、HandlerResultHandler 的调用,实际实现了HttpHandler的处理逻辑;
  • 4)HandlerMapping:根据路由处理函数 (RouterFunction) 将 http 请求路由到相应的handler。WebFlux 中可以有多个 handler,每个 handler 都有自己的路由;
  • 5)HandlerAdapter:使用给定的 handler 处理 http 请求,必要时还包括使用异常处理handler 处理异常;
  • 6)HandlerResultHandler:处理返回结果,将 response 写到输出流中;
  • 7)Reactive Streams:Reactive Streams 是一个规范,用于处理异步数据流。Spring WebFlux 实现了 Reactor 库,该库基于响应式流规范,处理异步数据流。

在整个过程中 Spring WebFlux 实现了响应式编程模型,构建了高吞吐量、高并发的 Web 应用程序,同时也具有响应快速、可扩展性好、资源利用率高等优点。

下面我们来看下 webFlux 是如何将 Servlet 请求异步化的:

1)ServletHttpHandlerAdapter 展示了使用 Servlet 异步支持和 Servlet 3.1非阻塞I/O,将 HttpHandler 适配为 HttpServlet。

2)第10行:request.startAsync()开启异步模式,然后将原始 request 和 response 封装成 ServletServerHttpRequest 和 ServletServerHttpResponse。

3)第36行:httpHandler.handle(httpRequest, httpResponse) 返回一个 Mono 对象(即Publisher),对 Request 和 Response 的所有具体处理都在 Mono 对象中定义。

所有的操作只有在 subscribe 订阅的那一刻才开始进行,HandlerResultSubscriber 是 Reactive Streams 规范中标准的 subscriber,在它的 onComplete 事件触发时,会结束 servlet 的异步模式。

对 Servlet 返回结果的异步写入,以 DispatcherHandler 为例说明:

1)第2行:exchange 是对 ServletServerHttpRequest 和 ServletServerHttpResponse 的封装。

2)第10-15行:在系统预加载的 handlerMappings 中根据 exchange 找到对应的 handler,然后利用 handler 处理 exchange 执行相关业务逻辑,最终结果由 result 将 ServletServerHttpResponse 写入到输出流中。

最后:除了 Servlet 的异步化,作为业务网关,要实现全链路异步化还需要在远程调用方面要支持异步化。在 RPC 调用方式下,我们采用的异步 Dubbo,在 HTTP 调用方式下,我们采用的是 WebClient。

WebClient 默认使用的是 Netty 的 IO 线程进行发送请求,调用线程通过订阅一些事件例如:doOnRequest、doOnResponse 等进行回调处理。异步化的客户端,避免了业务线程池的阻塞,提高了系统的吞吐量。

在使用 WebClient 这种异步 http 客户端的时候,我们也遇到了一些问题:

1)首先:为了避免默认的 NettyIO 线程池可能会执行比较耗时的 IO 操作导致 Channel 阻塞,建议替换成其他线程池,替换方法是 Mono.publishOn(reactor.core.scheduler.Schedulers.newParallel("biz_scheduler", 300))。

2)其次:因为线程发生了切换,无法兼容 Qtracer (Qunar内部的分布式全链路跟踪系统),所以在初始化 WebClient 客户端的时候,需要在 filter 里插入对 Request 的修改,记录前一个线程保存的 Qtracer 的上下文。WebClient.Builder wcb = WebClient.builder().filter(new QTraceRequestFilter())。

8、解决方案Part2:服务编排降低响应时间

Spring WebFlux 并不是银弹,它并不能保证一定能降低接口响应时间,除了全流程异步化,我们还利用 Spring WebFlux 提供的响应式编程模型,对业务流程进行服务编排,降低依赖之间的阻塞。

8.1服务编排解决方案

在介绍服务编排之前,我们先来了解一下 Spring WebFlux 提供的响应式编程模型 Reactor。

它有最重要的两个响应式类 Flux 和 Mono:

  • 1)一个 Flux 对象表明一个包含0..N 个元素的响应式序列;
  • 2)一个 Mono 对象表明一个包含零或者一个(0..1)元素的结果。

不管是 Flux 还是 Mono,它的处理过程分三步:

  • 1)首先声明整个执行过程(operator);
  • 2)然后连通主过程,触发执行;
  • 3)最后执行主过程,触发并执行子过程、生成结果。

每个执行过程连通输入流和输出流,子过程之间可以是并行的,也可以是串行的这个取决于实际的业务逻辑。我们的服务编排就是完成输入和输出流的编排,即在第一步声明执行过程(包括子过程),第二步和第三步完全交给 Reactor。

下面是我们服务编排的总体设计:

如上图所示:

1)service:是最小的业务编排单元,对 invoker 和 handler 进行了封装,并将结果写回到上下文中。主流程中,一般是由多个 service 进行并行/串行地编排。

2)Invoker:是对第三方的异步非阻塞调用,对返回结果作 format,不包含业务逻辑。相当于子过程,一个 service 内部根据实际业务场景可以编排0个或多个 Invoker。

3)handler:纯内存计算,封装共用和内聚的业务逻辑。在实际的业务开发过程中,对上下文中的任一变量,只有一个 handler 有写权限,避免了修改扩散问题。也相当于子过程,根据实际需要编排进 service 中。

4)上下文:为每个接口都设计了独立的请求/处理/响应上下文,方便监控定位每个模块的处理正确性。

上下文设计举例:

在复杂的 service 中我们会根据实际业务需求组装 invoker 和 handler,例如:日历房售卖信息展示 service 组装了酒店报价、辅营权益等第三方调用 invoker,优惠明细计算、过滤报价规则等共用的逻辑处理 handler。

在实际优化过程中我们抽象了100多个 service,180多个 invoker,120多个 handler。他们都是小而独立的类,一般都不会超过200行,减轻了开发同学尤其是新同学对代码的认知负担。边界清晰,逻辑内聚,代码的不可知问题也得到了解决。

每个 service 都是由一个或多个 Invoker、handler 组装编排的业务单元,内部处理都是全异步并行处理的。

如下图所示:ListPreAsyncReqService 中编排了多个 invoker,在基类 MonoGroupInvokeService 中,会通过 Mono.zip(list, s -> this.getClass() + " succ")将多个流合并成为一个流输出。

在 controller 层就负责处理一件事,即对 service 进行编排(如下图所示)。

我们利用 flatMap 方法可以方便地将多个 service 按照业务逻辑要求,进行多次地并行/串行编排。

1)并行编排示例:第12、14行是两个并行处理的输入流 afterAdapterValidMono、preRankSecMono ,二者并行执行各自 service 的处理。

2)并行处理后的流合并:第16行,搜索结果流 rankMono 和不依赖搜索的其他结果流preRankAsyncMono,使用 Mono.zip 操作将两者合并为一个输出流 afterRankMergeMono。

3)串行编排举例:第16、20、22行,afterRankMergeMono 结果流作为输入流执行 service14 后转换成 resultAdaptMono,又串行执行 service15 后,输出流 cacheResolveMono。

以上是酒店业务网关的整体服务编排设计。

8.2编排示例

下面来介绍一下,我们是如何进行流程编排,发挥网关优势,在系统内和系统间达到响应时间全局最优的。

8.2.1)系统内:

上图示例中的左侧方案总耗时是300ms。

这300ms 来自最长路径 Service1的200ms 加上 Service3 的100ms:

  • 1)Service1 包含2个并行 invoker 分别耗时100ms、200ms,最长路径200ms;
  • 2)Service3 包含2个并行invoker 分别耗时50ms、100ms,最长路径100ms。

而右图是将 Service1 的200ms 的 invoker 迁移至与 Service1 并行的 Service0 里。

此时,整个处理的最长路径就变成了200ms:

  • 1)Service0 的最长路径是200ms;
  • 2)Service1+service3 的最长路径是100ms+100ms=200ms。

通过系统内 invoker 的最优编排,整体接口的响应时间就会从300ms 降低到200ms。

8.2.2)系统间:

举例来说:优化前业务网关会并行调用 UGC 点评(接口耗时100ms)和 HCS 住客秀(接口耗时50ms)两个接口,在 UGC 点评系统内部还会串行重复调用 HCS 住客秀接口(接口耗时50ms)。

发挥业务网关优势,UGC 无需再串行调用 HCS 接口,所需业务聚合处理(这里的业务聚合处理是纯内存操作,耗时可以忽略)移至业务网关中操作,这样 UGC 接口的耗时就会降下来。对全局来说,整体接口的耗时就会从原来的100ms 降为50ms。

还有一种情况:假设业务网关是串行调用 UGC 点评接口和 HCS 住客秀接口的话,那么也可以在业务网关调用 HCS 住客秀接口后,将结果通过入参在调用 UGC 点评接口的时候传递过去,也可以省去 UGC 点评调用 HCS 住客秀接口的耗时。

基于对整个酒店主流程业务调用链路充分且清晰的了解基础之上,我们才能找到系统间的最优解决方案。

9、优化后的效果

9.1页面打开速度明显加快

优化后最直接的效果就是在用户体感上,页面的打开速度明显加快了。

以详情页为例:

 

9.2接口响应时间下降50%

列表、详情、订单等主流程各个核心接口的P50响应时间都有明显的降幅,平均下降了50%。

以详情页的 A、B 两个接口为例,A接口在优化前的 P50 为366ms:

A 接口优化后的 P50 为36ms:

B 接口的 P50 响应时间,从660ms 降到了410ms:

9.3单机吞吐量性能上限提升100%,资源成本下降一半

单机可支持 QPS 上限从100提升至200,吞吐量性能上限提升100%,平稳应对七节两月等常规流量高峰。

在考试、演出、临时政策变化、竞对故障等异常突发事件情况下,会产生瞬时的流量尖峰。在某次实战的情况下,瞬时流量高峰达到过二十万 QPS 以上,酒店业务网关系统经受住了考验,能够轻松应对。

单机性能的提升,我们的机器资源成本也下降了一半。

9.4圈复杂度降低38%,研发效率提升30%

具体就是:

  • 1)优化后酒店业务网关的有效代码行数减少了6万行;
  • 2)代码圈复杂度从19518减少至12084,降低了38%;
  • 3)网关优化后,业务模块更加内聚、边界清晰,日常需求的开发、联调时间均有明显减少,研发效率也提升了30%。

10、本文小结与下一步规划

1)通过采用 Spring WebFlux 架构和系统内/系统间的服务编排,本次酒店业务网关的优化取得了不错的效果,单机吞吐量提升了100%,整体接口的响应时间下降了50%,为同类型业务网关提供一套行之有效的优化方案。

2)在此基础上,为了保持优化后的效果,我们除了建立监控日常做好预警外,还开发了接口响应时长变化的归因工具,自动分析变化的原因,可以高效排查问题作好持续优化。

3)当前我们在服务编排的时候,只能根据上游接口在稳定期的响应时间,来做到最优编排。当某些上游接口响应时间存在波动较大的情况时,目前的编排功能还无法做到动态自动最优,这部分是我们未来需要优化的方向。

11、相关文章

[1] 从C10K到C10M高性能网络应用的理论探索

[2] 一文读懂高性能网络编程中的I/O模型

[3] 一文读懂高性能网络编程中的线程模型

[4] 以网游服务端的网络接入层设计为例,理解实时通信的技术挑战

[5] 手淘亿级移动端接入层网关的技术演进之路

[6] 喜马拉雅自研亿级API网关技术实践

[7] B站基于微服务的API网关从0到1的演进之路

[8] 深入操作系统,彻底理解I/O多路复用

[9] 深入操作系统,彻底理解同步与异步

[10] 通俗易懂,高性能服务器到底是如何实现的

[11] 百度统一socket长连接组件从0到1的技术实践

[12] 淘宝移动端统一网络库的架构演进和弱网优化技术实践

[13] 百度基于金融场景构建高实时、高可用的分布式数据传输系统的技术实践


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

posted @ 2024-02-21 10:20 Jack Jiang 阅读(89) | 评论 (0)编辑 收藏

本文由得物技术暖树分享,有修订和改动。

1、引言

本文分享的是得物针对现有的消息推送系统的消息送达耗时、实时性、稳定性等方面问题,从零到一构建完整的消息推送质量监控体系和机制的技术实践。

 
 
技术交流:

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

2、消息推送的作用

2.1 什么是消息推送

消息推送每天都在我们的手机上发生,如下图所示,除非你的手机没有安装App或关闭了通知栏权限。

2.2 消息推送的价值

从用户的生命周期来看,消息推送对于提高App活跃度、提升用户粘性和用户留存率都起到了重要作用。

比如:

  • 1)提升新用户次日留存,低成本促活,对平台的短期留存率影响显著;
  • 2)提升老用户活跃度,push可以通过外部提醒起到拉活的作用;
  • 3)流失用户召回,当用户流失后,若push权限未关闭,通过消息推送的方式,有可能重新唤醒用户。

对于第 2)点,很多内容平台类App的用户push首次启动占比可达 10%以上,因此push对DAU的增量贡献不容小觑。

3、业务背景和技术痛点

消息中心为得物App提供了强大,高效的用户触达渠道。其中push对于得物DAU的贡献有可观的占比,这也就意味着每一条推送消息都是一次与用户沟通的宝贵机会。所以推送的稳定性成为我们关注的首要问题。

那么我们遇到的以下痛点就亟待解决:

1)消息中心没有明确消息推送的耗时标准,业务和技术之间存在gap,业务方对于推送的消息什么时候到达没有明确的心理预期。

2)从技术上来讲消息推送各个节点的耗时不明确,无法对各个节点的耗时做针对性的优化,这也就需要我们针对消息推送的节点耗时进行监控。

3)消息推送的稳定性依赖于第三方的推送通道,而三方通道对于我们来讲就是个黑盒子,如何做到三方通道异常及时发现并止损也是需要考虑的问题。

4)在我们正常的迭代过程中有时候不可避免的会出现些异常或者有坏味道的代码,这些问题能不能及时发现、及时止损,能不能及时告警出来。

4、稳定性监控体系

SLA(Service-Level Agreement),也就是服务等级协议,指的是系统服务提供者(Provider)对客户(Customer)的一个服务承诺。这是衡量一个大型分布式系统是否“健康”的常见方法。

在开发设计系统服务的时候,无论面对的客户是公司外部的个人、商业用户,还是公司内的不同业务部门,我们都应该对自己所设计的系统服务有一个定义好的SLA。因为SLA是一种服务承诺,所以指标可以多种多样。

最常见的四个SLA指标:

  • 1)可用性;
  • 2)准确性;
  • 3)系统容量;
  • 4)延迟。

 

对于消息推送而言,我们主要关注的是消息能否及时可靠的送达给用户,也就是SLA中关注的时效性和稳定性的问题。

目前消息中心针对实效性和稳定性的开发已经完成并初显成效。

系统架构图:

下面主要针对时效性和稳定性的监控做一些介绍。

5、时效性监控的技术实现

5.1 节点的拆分

如何做到时效性的无死角监控,那么我们就要对消息推送的整个流程进行拆分,把整个流程拆分成若干个独立且无依赖的可监控节点。

从消息系统流转图中可以看到:整个推送流程是清晰明了的,消息的的推送主要会经历推送鉴权、用户查询、防疲劳过滤、防重复过滤等的逻辑处理,考虑到每个业务逻辑的处理是相互独立且无依赖的,那我们就可以根据具体的业务处理逻辑进行节点的拆分,这样就可以做到拆分无遗漏,监控无死角。

拆分后的具体节点如下:

5.2 节点耗时的计算

具体的节点拆分逻辑和耗时逻辑的计算如下图:

 

节点耗时的计算:记录节点消息推送到达的时间,并计算节点推送耗时,例如:防疲劳耗时 = T7(antiFatigueConsumeTime) - T6(checkrepeatConsumeTime)。

节点阻塞量的计算:记录节点消息推送的瞬时阻塞量, 例如:防疲劳节点阻塞量 = 防疲劳的总量 - 防疲劳已经处理的量。

5.3 节点指标的制定

既然需要监控的节点已经拆分明确了,那针对这些节点我们监控哪些指标才是有意义的呢。

1)目前消息推送高峰耗时较长,各业务域对于消息的到达时间也没有明确的心理一个预期,另外消息中心也无法感知推送在整个链路各个节点的耗时情况,无法针对节点耗时做到有针对性的优化,所以节点的推送量和推送耗时就是我们需要重点关注的指标。

2)节点的阻塞量可以让我们及时感知到推送中存在的积压问题,在大促期间,消息的推送量也会达到一个高峰,消息目前是否有堆积,处理的速度是否跟的上,是否需要临时扩容,那么节点的阻塞量就成了一个比较有意义的参考指标。

考虑到消息推送是有优先级的并且区分单推和批量推,所以我们要针对不同的优先级和推送方式设置不同的标准。

消息推送耗时的具体标准如下:

5.4 技术方案的实现

为了能感知到消息推送中发生的异常和耗时情况,这就需要我们标准化监控指标和监控的节点。

其中耗时指标可以感知节点的耗时和代码的坏味道,阻塞量可以监控到节点的堆积情况,推送成功率可以感知节点的推送异常等。

另外节点拆分后我们可以很快定位到异常发生的具体位置,经过拆分监控的主要节点包括鉴权、风控、用户查询、防疲劳、防重复、厂商调用等。

另外消息中心每天推送大量消息给得物用户,SLA监控任何一个操作嵌入主流程中都可能导致消息推送的延迟。这也就要求监控和主流程进行隔离,主流程的归主流程,SLA 的归 SLA,SLA 监控代码从主流程逻辑中剥离出来,彻底避免SLA代码对主流程代码的污染,这也就要求SLA逻辑计算需要独立于推送业务的主流程进行异步计算,防止SLA监控拖垮整个主流程,那么Spring AOP+Spring Event就是最好的实现方式 。

5.5 成果

消息推送实效性监控做完之后,对服务节点耗时异常可以及时感知,同时也完成了关键节点耗时的指标化。

可以明确的看到所有节点在各个时间的耗时情况,同时也对消息推送针对各个节点的的优化起到了指导作用。

时效性节点监控:

时效性节点告警:

6、厂商推送监控的技术实现

6.1 监控指标制定

消息推送接入的有多个推送通道,如何做到对这些通道做到无死角的监控,及时感知呢。

1)在做厂商监控之前,我们就已经遇到了厂商通道推送跌零的情况,这种情况下整个推送通道都挂掉了,我们要及时通知厂商进行修复,所以厂商推送跌零告警和厂商余量监控是必须的。

2)从现有数据来看,厂商的推送成功率、回执成功率、点击率都稳定在一定的的区间。如果厂商推送的指标数据偏离这个区间则说明推送有异常,所以推送成功率、回执成功率、点击率的监控是必须的。

3)另外从业务请求发送的用户数来看,每天的消息推送基本是稳定的,相对应的厂商的回执数量和点击数量也是稳定的,那么对厂商推送成功的数量,回执的数量和点击的数量监控也有一定的参考意义。

业务侧请求发送的用户数:

厂商监控告警:

6.2 技术方案实现

厂商每天有数亿的消息推送,这也就意味着厂商的监控不能嵌在主流程中处理。厂商的监控代码要从主流程逻辑中剥离出来,避免监控拖垮主流程,同样避免监控异常影响到推送的主流程。

针对厂商推送的监控,目前使用的是有界内存队列实现:

6.3 成果

消息推送厂商监控上线之后,可以及时感知到厂商推送的异常信息,对于厂商推送的异常和厂商规则的更改等可以做到及时的感知。

 

7、 稳定性监控体系带来的收益

7.1 异常的及时发现

监控上线后及时发现了发现了厂商推送线程关闭失败,厂商推送跌零、厂商营销消息规则更改、厂商通道偶发不可用等问题,并做到了及时的止损。

1)在时效性监控上线之后,发现了因厂商推送线程创建关闭失败导致线程数逐渐上升问题,避免了线上故障的发生。

2)厂商异常导致推送跌零,监控发现后及时通知到厂商并止损。

3)发现厂商营销消息规则更改的异常,并及时经梳理各大厂商文档后发现除了多个厂商通道在未来一个月内也会有规则的更改,消息平台及时适应了厂商规则,接入厂商系统通道,做到了及时止损。

7.2 服务性能的提升

时效性监控上线后发现了多个服务可以优化的点,其中多个厂商和推送节点在高峰推送时耗时较高,很明显节点耗时和厂商推送 SDK 连接池和连接时间参数需要优化。优化后消息推送整体的吞吐量实现了翻倍的提升。

8、 展望未来

由于时间问题,目前消息监控只做了时效性和厂商推送稳定性相关的监控,但是监控上线后带来的收益还是比较可观的,可以预见的是监控的构建在未来必将带给我们更大的收益,后续我们可以从以下点丰富现有监控。

1)考虑到业务预的推送量和推送时间是稳定的,那么我们可以针对业务维度添加推送数据的监控,及时感知上游推送数据的变化。

2)其次我们可以针对各个节点的推送异常、漏斗转化率、服务性能等做监控,进一步丰富消息平台的监控体系。

3)对于消息推送来讲也要考虑推送的转化率问题,那么卸载、屏蔽等指标也是我们需要监控的点,通过这些业务指标及时感知推送的效果,做到精细化的管控。

9、本文小结

消息平台监控上线后带来的收益还是比较可观的,包括多次异常的及时发现和止损,还有发现多个个可以优化的性能点,实现了服务高峰吞吐量的翻倍。

同时也解决了我们现在遇到的以下痛点:

1)时效性明确的给到了不同优先级的耗时标准,避免了业务和技术之间的gap,业务方对于推送的耗时也有了明确的心理预期。

2)时效性使得节点耗时的性能问题可以一目了然,通过对现有节点耗时问题的优化,消息服务的吞吐量实现了翻倍的提升。

3)厂商稳定性监控使得厂商异常可以及时感知,其中厂商稳定性监控上线后发现多起厂商推送的异常,并做到了及时的解决和止损。

4)SLA时效性和厂商稳定性上线后,消息中心可以及时感觉到推送链路的异常和代码的坏味道,特别是对于新上线的代码,如果存在异常可以及时感知。

10、相关文章

[1] 极光推送系统大规模高并发架构的技术实践分享

[2] 魅族2500万长连接的实时消息推送架构的技术实践分享

[3] 专访魅族架构师:海量长连接的实时消息推送系统的心得体会

[4] 实践分享:如何构建一套高可用的移动端消息推送系统?

[5] Go语言构建千万级在线的高并发消息推送系统实践(来自360公司)

[6] 腾讯信鸽技术分享:百亿级实时消息推送的实战经验

[7] 百万在线的美拍直播弹幕系统的实时推送技术实践之路

[8] 京东京麦商家开放平台的消息推送架构演进之路

[9] 技术干货:从零开始,教你设计一个百万级的消息推送系统

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

[11] 喜马拉雅亿级用户量的离线消息推送系统架构设计实践

[12] 直播系统聊天技术(三):微信直播聊天室单房间1500万在线的消息架构演进之路

[13] 消息推送技术干货:美团实时消息推送服务的技术演进之路

[14] 揭秘vivo百亿级厂商消息推送平台的高可用技术实践

11、 得物分享的其它文章

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

得物从0到1自研客服IM系统的技术实践之路

得物自研客服IM中收发聊天消息背后的技术逻辑和思考实现

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

posted @ 2024-01-25 11:27 Jack Jiang 阅读(278) | 评论 (0)编辑 收藏

关于MobileIMSDK

MobileIMSDK 是一套专门为移动端开发的开源IM即时通讯框架,超轻量级、高度提炼,一套API优雅支持UDP 、TCP 、WebSocket 三种协议,支持iOS、Android、H5、小程序、Uniapp、标准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 实现)。

v11.0 版更新内容

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

(1)Android端主要更新内容新增“@”功能、消息引用功能等】:

  • 1)[新增] 新增“@”功能;
  • 2)[新增] 新增消息引用功能(支持引用全部消息类型);
  • 3)[bug] 解决了转发的是收到的短视频消息时,发送者这边不从网络加载预览图的问题;
  • 4)[bug] 解决了离线好友消息在首页“消息”列表上显示的时间不是最后一条消息的发送时间问题;
  • 5)[优化] 首页消息列表中的语音消息将显示语音时长(跟新版微信一样);
  • 6)[优化] 其它优化及bug修复。

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

  • 1)[新增] 增加了“@”功能相关数据字段和代码逻辑的实现;
  • 2)[新增] 增加了消息引用功能相关数据字段和代码逻辑的实现;
  • 3)[优化] 更新了消息推送特权接口,支持陌生人、好友、群聊3种消息的推送,且增加了主机ip检查(提高安全性);

此版新增功能运行截图更多截图点此查看):

posted @ 2024-01-24 12:44 Jack Jiang 阅读(56) | 评论 (0)编辑 收藏

本文由百度搜索技术平台研发部分享,本文有修订和改动。

1、引言

分布式数据传输系统是一种用于在多个计算节点之间高效传输大量数据的系统,诣在高效的解决大规模数据迁移、备份、跨地域复制等问题。其广泛应用在实时数据流传输、跨数据中心数据迁移、多媒体传输等场景,在大多数企业中的日志管理、业务数据建库等场景中也都会使用到。

众所周知,数据的高效传输往往直接影响着企业对市场先机的把握,对企业发展有重要意义,特别是在金融领域,如证券行业,它对分布式数据传输系统的设计提出了更高的要求,证券领域数据变化飞快,一个高时效、稳定的数据流传输系统不仅能有效的提升用户体验,更能提供用户一手的投资信息,有助于用户的投资决策,进而拉进企业与用户的距离。

本文将通过一个百度搜索旗下的金融场景案例来分享构建高实时、高可用的分布式数据传输系统的技术实践。

 
 
技术交流:

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

2、业务背景

作为百度搜索场景下时效性要求较高的业务,金融承载着每天数千万次的用户搜索请求。

而在2021年以前,金融业务的数据一直都是采用传统的互联网引入方式,该方式的特点是接入成本较低,但受公网等不可控因素影响,数据时效性较差,且数据断流、错误等问题频出,随即而来的就是业务维护成本较高,十分不利于产品迭代。

我们基于此发起了一个证券数据直连项目,诣在通过接驳全球各大证券交易所数据中心来构建一个高时效、高可用的分布式传输系统,从而有效的解决传统数据引入方式(公网抓取、推送)所带来的时效性、稳定性、正确性等问题,进而满足全国乃至全球用户的金融需求。

3、设计目标

3.1业务目标

接驳全球各大证券交易所Level-1行情数据,来覆盖全量上市公司股票、外汇、期货、ETF、涡轮牛熊等证券业务来满足用户需求,时效性追平金融行业竞品,为打造强大的金融生态做数据基建储备。

Level-1行情简称LV1行情:是交易所根据交易规则发布的即时行情信息,数据格式包括基于FIX/FAST协议的接口和TXT文件、二进制数据流等,行情通过交易所信息技术公司的高速地面网和宽带广播卫星系统发布或上证所信息网络有限公司的互联网和专线传输。

3.2技术目标

1)基础设施建设:协同交易所、运营商完成物理专线的链路部署,通过物理专线接入的方式在百度云机房接入上海、深圳、香港、纳斯达克证券交易所数据中心,适配交易所单、组播协议将二进制流/文本数据引入到百度内部,再分别完成华南、华北、华东、香港(支持海外访问)地域的数据存储与转发,同时支持负载和流量调度来支撑各地域的用户请求。(注:这里的物理专线特指光缆)

2)时效性和稳定性提升:行情数据检索99分位耗时不超过200ms,数据稳定性从99%提升至99.99%以上,数据灾备能力从1主0备升级至1主2备。

3)数据安全:基于百度安全能力,构建类似的防火墙策略来严格控制每一个机房、每一个集群的出入权限,并且配置好相应的安全组策略。

4、关键思路

从功能和网络拓扑上来看,一个高时效、高可用的金融数据传输系统至少需要包含以下几个部分,我们逐个来进行解读。

4.1接入层

适配全球各大交易所单、组播传输协议,确保数据能在专线物理网络正常传输。

接入主要有2种方式:

  • 1)一种是走互联网;
  • 2)一种是走物理专线。

前者相对比较灵活:各类数据协议基本都可以支持,有直接走HTTP(GET/POST),或者是走消息队列的发布订阅等等,接入成本较低,属立即接入那种,但受公网的不可控因素影响,在传输效率和安全性上相对后者会有比较大的差距,我们一般会把互联网的方式当做一个灾备能力存在。

专线方式的特点:是仅点对点传输,由于用的是独立的光缆,在有限带宽内理论可以做到无争用状态,不受公网影响,属可靠传输,传输协议私有化,增加了更多的认证机制。因此也更安全,区分不同应用场景,像证券类数据传输,一般交易所采用的是单播、组播方式,当下用的多的是组播。另外专线中也有主备的概念,一般会预留1-2条线路做灾备,整体下来,专线的费用要更昂贵一些,接入的周期也更长,往往长达几个月。

4.2网络层

完成华南、华北、华东百度云机房虚拟网络架构建设,包括子网、路由、网关等。

虚拟网络的核心组成部分主要是子网、路由、网关、虚拟机,其中每个子网关联着一个虚拟机集群,我们把整个组成部分(域)统称为一个VPC(Virtual private Cloud),路由又区分为TGW路由和对等连接。

这里主要关注对等连接,它是为用户提供了VPC级别的网络互联服务,使用户实现在不同虚拟网络之间的流量互通,实现同区域/跨区域,同用户/不同用户之间稳定高速的虚拟网络互联,其核心是基于对路由表的操作,对等连接也支持配置地域级的DNS同步。

网关又分为NAT网关和专线网关:

1)一个对外:比如设置SNAT和DNAT规则用于统一网段的外网出口;

2)一个对内:对内其实就是确保能够走专线和内部网络打通。

4.3传输层

完成各机房内的数据解析、存储、同步、转发等。

对于接入层获取到的数据我们分为三个级别:

1)像交易所主要是二进制流、文本为一级数据,我们需要保留近一段时间的原始数据落在本地(一级数据管理集群),以便用作应急回放。

2)而解码后的数据为二级数据,落在二级数据管理集群上,主要用于跨地域同步。

3)最后,对解码后的数据进行计算&加工,作为三级数据,落在三级数据管理集群用于承接应用服务。同时,按协议解码后的数据按照使用场景区分为实时流(如分时)、延时流(如K线),延时流经过实时流计算得来,实时流同步进内存用于提升IO效率,延迟流通过实时流的计算后异步进DB,DB维护在三级数据管理集群上。

4.4应用层

负载/流量调度、监控能力等建设。

应用层的设计,主要有两个方面的考虑:

1)一方面是对于接入层的负载和流量调度,如通过部署websocket/http服务来支撑百度用户流量,使用BLB(Baidu Load Balance)将同一区域的多台百度智能云服务器虚拟成一个组,设置一个内网或外网的服务地址,将前端并发访问转发给后台多台云服务器(BCC),实现应用程序的流量均衡,性能上实现业务水平扩展。

负载均衡还通过故障自动切换及时地消除服务的单点故障,提升服务的可用性,支持服务器调度权重策略配置,并支持TCP、HTTP等协议。

2)一方面是对监控的应用,如请求/数据传输日志落盘、统计、分析以及流量和sla监控等。

4.5小结

将以上四层能力建设后,此时单机房内的网络拓扑应该如下图所示。

注:DCC/BBC/BCC都是百度云范畴的机器类型,更多细节可以参考百度智能云私有网络:https://cloud.baidu.com/doc/VPC/s/Vjwvytu2v

5、核心难点1

公网和私有网络方式下如何在云上完成多协议适配,尤其是在私有网络中适配单播、组播协议以及如何做组播转单播。

5.1公网&私有网络接入介绍

对于一个数据传输系统来说,最重要的一点其实就是能支持多协议的数据适配来提升系统的灵活性,证券交易所一般提供的接入方式有公网接入和私有网络接入,公网接入的成本较低,一般周粒度就可完成,没有复杂协议约束。

而私有网络往往会有更高的要求,协议上大部分都要求具备单播介入能力,少部分像纳斯达克和深圳交易所会要求下游支持组播接入。绝大多数的云厂商是无法直接在虚拟机上适配的,传统券商基本都是完全使用昂贵的物理机资源来承载,虽然物理机插拔更方便也更稳定,但运维管理成本也更高。

两种方式在效果和成本上也有本质的区别:

1)公网接入:公网比较常见的数据接入方式主要是HTTP/HTTPS方式,当然也会有RPC/FTP,只是用的相对少一些。

为了提升数据传输安全,双方可以在调用前协商好数据加密算法和密钥。优点是接入成本较低,能快速应用,尤其在跨洋传输上会有体现。缺点是走的公共线路,网络不可靠,且数据易被截获,当攻击者捕获两端的数据包后,哪怕不能完全解析,也可以实施一些流量攻击手段以影响服务稳定性。总的来说,一般不会对于安全性、时效性要求较高的数据采用该方式接入,更多是只是一种备用方式(特殊场景除外,如跨洋传输)。

2)私有网络接入:公司内网其实就属于一个私有网络,但是对于跨公司传输数据的场景,要想构建私有网络,一般会走物理专线接入的方式。

这种点对点传输方式的显著优点是专网专用且安全性较高,基本不受公共网络影响(自然灾害等不可抗力除外),在带宽范围内基本可以做到无网络争用状态(数据即发即达),由于是私有网络(双端内网传输),基本不用担心数据安全问题,而且往往还会增加额外的数据校验手段,尤其在金融场景,会有严格的token(硬/软)认证,该方式的缺点是成本相比公网传输接入成本更高,一般要持续数月,费用更昂贵,一般在上百万元,依赖选取的传输介质(一般选择光纤)和带宽。

5.2私有网络中单播、组播协议接入方案

私有网络有单播、广播、组播之分。

1)单播:相对比较好适配一些,走静态路由的方式在同一个VLANID下分别配置云端和IDC端的IP段作为IPV4专线互联地址即可。

2)广播:一般是对于服务端而言,比如证券交易所下游对接着全球范围的所有券商,数据源是相同的,一般会采用广播的机制把数据推送给所有下游。

3)组播:一般是要求下游需要适配,现如今大部分业务都已经上公有云,在云上常用虚拟化技术来完成服务器集群的部署。

对于虚拟机来说,更多的支持单播传输,不支持组播传输,往往需要在专门的物理设备(组播路由器、或特定的组播软件)上配置转发组播报文的路由,路由表关联着具体的路由协议(如PIM),再用IGMPV3协议来完成组播成员和报文的管理,通过动态BGP维护邻居关系(现在的云厂商上对BGP的可能是固定分配AS号,如果有AS的要求还是需要在物理机上单独做),我们可以圈出一部分物理资源专门承载组播数据传输,通过配置IGMP Snooping(可以将组播报文转发到二层数据链路层,实现组转单,注意版本需要是3,否则无法转发IGMPV3报文)+ AP完成组播转单播配置,再通过双网卡(WAN口+LAN口)形式实现专线网络数据接入&同步到百度内网,物理机通过三层交换机来关联,构造出类似下面的网络拓扑(如下图所示)。

6、核心难点2

6.1概述

数据管理&跨地域同步,数据灾备能力、时效性提升。

数据的分层管理主要是应对单机房内的场景,而对于跨机房或者说跨地域的主要难点是数据同步,后者需要更多的考虑跨机房数据传输效率和灾备管理,核心是网络设计。

6.2数据管理

按使用场景的不同,将数据分交易所二进制流数据(原始数据流)、文本数据、业务数据/日志等。

1)原始数据流:主要应对单机房、跨机房传输场景,当出现下游业务服务异常导致的数据展现错误时,存储的原始数据流可以很好的对数据进行回放,以便快速恢复业务,尤其是应对金融证券数据传输场景,证券交易所一般不会推送重复数据,如果下游业务服务异常导致存储的业务数据全部失效或为脏数据,那可能只能通过refresh主动请求上游来重新获取。

但这样做可能会出现核心数据丢失,由于这种方式的效率较低,还会扩大业务受损的影响面,因此一般会先存储交易所下发的原始数据流,业务可以自定义存储方式和周期,当出现问题时,可以通过『重播』原始数据流来止损。

另外原始数据流还能用于在对等网络中的跨机房恢复业务数据。

2)业务数据流:主要应对单机房传输的场景,根据模块分工的不同,分证券的实时行情、历史行情等等,对于单机房数据集群的管理我们有很多方式,对于自研的DB,在调度上可以用一些标准的分布式管理手段(如zk),数据同步的手段一般需要自定义,对于传统的DB如Mysql、Redis、Mongo等,一般有标准化的数据同步方式和调度模式。

6.3跨地域同步

跨机房地域同步的前提是多个机房之间需要有直接或间接关联关系的专用物理网络,即确保网络是可达的,然后再结合虚拟网络完成子网及路由配置。

对于具有直接网络关联关系的2个机房来说,我们的对等网络(Peer Connection)设计稍微简单一些。

现在各个云厂商也基本都支持直接配置了,其原理是首先在同一个VPC下划分好子网并规划好集群规模,其次通过配置路由表的方式完成本端和对端的下一跳关联,这样就完成了2个直接对端的对等网络建设。

接着再配置和内网专线的路由,就能做到云机房->内网机房的网络互通。

但如果2个机房没有直接关联关系,而又需要完成本端和对端数据同步怎么办呢,比如有A B C三个机房,只有A-B B-C有直接关联关系,而我们想要让A-C关联,这时候不可能说再建立一条物理链路,我们可以采用类似桥接的方式(或者叫隧道),同时关联A-B-C三个机房,其中B作为一个"网桥",再通过NAT技术完成IP地址转换,确保C可以识别从A过来的路由,而A-B B-C 正常采用对等网络的方式完成基础网络配置,这样就可以胯多个机房进行通信,由于是物理网络传输,机房间的耗时不会有很大差别(30ms内)。

由于网络细节的篇幅较多,我们不做详细的赘述,这里我们看看跨地域同步的网络架构(如下图所示)。

 

注:图中网段可以根据不同场景做划分,这里只做简单介绍。

6.4数据灾备能力、时效性提升

数据灾备:我们一般选择离各个证券交易所就近的一个接入点,比如上证选择在上海机房接入,深证选择在广州接入,纳斯达克在香港接入,每个接入点配置2条专线用做物理链路的主备,同时扩展一条互联网通路(注意这里的互联网也是直接和交易所对接,已经不是传统数据引入渠道)做次备,链路默认都是活跃状态,有专们的物理设备会根据专线的健康状况(自定义逻辑)自动切换。

最后,再根据上面提到的跨地域同步的原理,在云机房关联各条物理链路,在每条物理链路上抽象出独立的VPC,通过构建网络拓扑实现跨机房数据复制及灾备。

时效性:物理专线(光缆)接入方式天然的优势就是数据"即发即达",因为在固定带宽内基本不存在网络争用,而且现在大部分线路都会配置中继,其损耗带来的影响相对可控,因此接入方式就决定了数据传输的时效性。

相比传统互联网接入方式,单从数据上来看,专线接入SLA超过5个9(互联网接入2个9),当然也会配置上重传机制来进一步提升数据到达的可靠性。

交易所下发数据的数据频率按市场划分,A股一般3s/笔,港美股没有特殊限制,即有成交即下发,除去光损耗带来的影响,最快可以到3ms/笔,由于频率越高,对机器要求也越高,为此我们特殊做了一些限频操作,整体的数据时效性基本会在60ms(99.99+分位)内。

7、核心难点3

7.1概述

集群管理&单地域、跨地域流量调度。

流量调度生效在应用层,主要是找到一种高效的调度/负载方式来对内/外的业务提供数据支撑,从协议上/应用场景划分主要有TCP/HTTP,策略上因业务而异,主要还是基于对流量分配中权重的定义。

比如有基于RS健康检查的分配,每隔一段时间探测一下下游集群的健康状况来动态调整流量配比,也可以根据下游机器的连接数来分配,还可以基于对资源访问的热度来分配,区分单地域和跨地域场景如下面所述。

7.2单地域场景

现在各个云厂商都有相应的流量调度产品支撑,比如百度云上有BLB(Baidu Load Balance),可以很轻松构建一个调度规则出来,在BLB下可以设置调度集群的协议(TCP/HTTP),然后关联对应的服务器集群,最后给不同的服务器集群配置权重策略。

当流量进来时,BLB会帮我们完成自动分配,在某一个集群出现问题时,可以手动调整集群权重来干预流量配比,即所谓的切流。

7.3多地域场景

多个机房间的流量调度策略是在云上一般是隔离开的,当然我们可以在多个机房的最上层再抽象出一个专门的调度集群,对外暴露一个VIP。

在这个VIP上配置多个地域之间的调度关系,互联网公司基本上也都是这么做的,更多的是针对超大集群规模的场景,而且VIP的选取也是有条件/成本的。

但如果想低成本快速在云上创建一个能支持多地域同时访问且具备自动化流量调度的应用,且云上又不支持多地域共享VIP的功能时,我们可以尽可能多的基于云上已有的功能自己完成,在每个机房内部单独抽出一个类似nginx的集群,每个集群上维护着不同于本地域的调度关系,它们的下游就是不同于本机房的BLB,同时互相检查对方的健康状况并上报监控系统,这样当出现异常时,除了能针对性的在本机房内完成BLB级的流量调度,还能做到多机房间的流量切换,以提升机房间的灾备能力。当然,也需要有足够的容量。

 

8、总体设计

上图各个模块的作用如下(各模块均采用多路复用):

1)源数据接入集群:适配2种方式(互联网/物理专线)+各类协议(互联网、单播、组播)的数据源接入;

2)源数据转发集群:确保各机房源数据的一致性,降低由于业务服务本身带来的数据不一致问题;

3)数据解析集群:公共模块,主要是针对源数据进行统一的处理,以便转发给下游各业务;

4)业务数据集群(实时/延时流):负责将数据解析集群下发的内容转换成业务详细数据,也就是B端或C端用户看到的数据;

5)网关集群:负责承载用户访问流量;

6)监控集群:负责收集各个集群上报的日志情况,并作为稳定性管理手段之一。

可以看到:机房B相比其他机房,少了接入层配置,这主是基于成本和性能上考虑,把机房B当做数据传输枢纽,不仅能保证本机房数据传输,也能支持跨机房的数据同步&复制。该分布式传输系统从数据接入到监控集群,整体机器规模不大(100左右),但可支撑超过10亿的流量。

9、本文小结

一个良好的产品体验及产品矩阵,其背后一定离不开一个高可用、高时效的数据支撑,尤其是在金融领域,用户只可能会为一手的信息、完善的产品功能买单。

自21年完成数据通路建设以来,金融的稳定性和业务规模都有了质的飞跃,证券数据时效性问题从季度数十个降低到年度1个以内,99分位耗时更是从过去的分钟级降低到60ms以内,数据SLA从2个9左右提升至5个9以上,产品覆盖股票、外汇、基金、期货等诸多领域,也是第一个在搜索领域支持行情长连接的业务,基于搜索生态也孵化出来了像百度股市通PC站、app等多个独立端产品,目前正在结合AI能力进行持续优化,期望从完善用户体验->帮助用户决策进阶,也让金融投资变得更智能,更简单。

本文主要结合一个金融数据接入案例对分布式数据传输系统做了一个简单的介绍,包括传输系统中的一些核心节点的设计,如数据接入层的多协议适配、数据的分层管理以及跨地域的数据同步对应的网络拓扑等,通过实验得出结论,该方案能很好的应用在各种规模的分布式数据传输系统设计中。当然,由于篇幅问题,也省略了很多实现上的细节,读者有任何问题可以留言,可以一起探讨,也会尽量答复。

10、相关文章

[1] 技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解

[2] 以网游服务端的网络接入层设计为例,理解实时通信的技术挑战

[3] 知乎千万级并发的高性能长连接网关技术实践

[4] 手淘亿级移动端接入层网关的技术演进之路

[5] 喜马拉雅自研亿级API网关技术实践

[6] 石墨文档单机50万WebSocket长连接架构实践

[7] 小米小爱单机120万长连接接入层的架构演进

[8] B站基于微服务的API网关从0到1的演进之路

[9] 百度统一socket长连接组件从0到1的技术实践

[10] 淘宝移动端统一网络库的架构演进和弱网优化技术实践

11、其它百度技术分享

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

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

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

全面了解移动端DNS域名劫持等杂症:原理、根源、HttpDNS解决方案等

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

直播系统聊天技术(四):百度直播的海量用户实时消息系统架构演进实践

IM消息ID技术专题(五):开源分布式ID生成器UidGenerator的技术实现

百度统一socket长连接组件从0到1的技术实践

百度网盘千万节点的P2P架构设计(PPT) [附件下载]

即时通讯音视频开发(二十):一文读懂视频的颜色模型转换和色域转换

揭秘百度IM消息中台的全量用户消息推送技术改造实践

百度基于金融场景构建高实时、高可用的分布式数据传输系统的技术实践


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

posted @ 2024-01-18 11:22 Jack Jiang 阅读(58) | 评论 (0)编辑 收藏

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

[- 1 -] IM开发干货分享:如何优雅的实现大量离线消息的可靠投递

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

[摘要] 本文作者将以自已IM开发过程中的真实总结,分享针对大量离线聊天消息,在确保用户端体验不降级的前提下,保证离线消息的可靠投递。


[- 2 -] IM开发干货分享:有赞移动端IM的组件化SDK架构设计实践

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

[摘要] 本文主要以Android客户端为例,记录了有赞旗下 App 中使用自研 IM,并将IM提炼成组件化SDK的设计思路。


[- 3 -] 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

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

[摘要] 本文主要聚焦这套亿级用户的IM架构的一些比较细节但很重要的热门问题上,比如:消息可靠性、消息有序性、数据安全性、移动端弱网问题等。


[- 4 -] IM扫码登录技术专题(一):微信的扫码登录功能技术原理调试分析

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

[摘要] 本文将以轻松活泼的语言形式,为你分析和讲解微信手机扫码登录的技术原理,希望在你的IM中开发此功能时有所启发。


[- 5 -] IM扫码登录技术专题(二):市面主流的扫码登录技术原理调试分析

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

[摘要] 本文将简要的介绍扫码登录功能的技术实现逻辑,并实际结合淘宝、微信的扫码登录功能,学习和研究大厂主流应用的技术实现思路。


[- 6 -] IM扫码登录技术专题(三):通俗易懂,IM扫码登录功能详细原理一篇就够

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

[摘要] 最近刚好看到一个二维码的技术原理讲解视频,正好借此机会将扫码登录的详细技术原理梳理并总结一下,方便自已回顾,也希望能帮助到想在IM里开发类似功能的同行们。


[- 7 -] IM扫码登录技术专题(四):你真的了解二维码吗?刨根问底、一文掌握!

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

[摘要] 二维码技术使用起来很简单,本系列的前三篇文章也专门针对IM扫码登录这个功能做了详细的分享,但本着学习技术不留死角的习惯,我认为有必要单独学习一下到底什么是二维码。


[- 8 -] 理解IM消息“可靠性”和“一致性”问题,以及解决方案探讨

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

[摘要] 本文内容仅供参考,具体的解决方案请务结合自已的系统构架和实现情况,多阅读几篇即时通讯网上有关这个技术话题的文章,取其精华,找到适合自已的技术方案和思路才是最明智的。


[- 9 -]  阿里技术分享:闲鱼IM基于Flutter的移动端跨端改造实践

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

[摘要] 本文总结了阿里闲鱼技术团队使用Flutter在对闲鱼IM进行移动端跨端改造过程中的技术实践等,文中对比了传统Native与现在大热的Flutter跨端方案在一些主要技术实现上的差异,以及针对Flutter技术特点的具体技术实现,值得同样准备使用Flutter开发IM的技术同行们借鉴和参考。


[- 10 -] 融云技术分享:全面揭秘亿级IM消息的可靠投递机制

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

[摘要] 本文根据融云亿级IM消息系统的技术实践,总结了分布式IM消息的可靠投递机制,希望能为你的IM开发和知识学习起到抛砖引玉的作用。


[- 11 -] IM全文检索技术专题(三):网易云信Web端IM的聊天消息全文检索技术实践

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

[摘要] 本文将具体来聊聊网易云信是如何实现IM客户端全文检索能力的,希望能带给你启发。


[- 12 -]  IM开发干货分享:万字长文,详解IM“消息“列表卡顿优化实践

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

[摘要] 本文将要分享是融云IM技术团队基于对自有产品“消息”列表卡顿问题的分析和实践(本文以Andriod端为例),为你展示一款IM在解决类似问题时的分析思路和解决方案,希望能带给你启发。


👉52im社区本周新文:《百度基于金融场景构建高实时、高可用的分布式数据传输系统的技术实践》,欢迎阅读!👈

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

posted @ 2024-01-17 12:01 Jack Jiang 阅读(47) | 评论 (0)编辑 收藏

本文由21CTO万能的大雄分享,本文有修订和改动。

1、引言

在当今快速发展的技术环境中,对跨平台桌面应用程序的需求正在不断激增。

开发人员面临着选择正确框架之挑战,以便可以高效构建可在 Windows、macOS 和 Linux 上无缝运行的应用程序。

在本文中,我们将比较五种流行的桌面应用程序开发框架:ElectronFlutterTauriReact Native  Qt,希望可以帮助你根据项目需求做出明智的技术选型决策。

 
技术交流:

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

2、系列文章

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

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

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

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

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

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

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

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

IM跨平台技术学习(八):新QQ桌面版为何选择Electron作为跨端框架

IM跨平台技术学习(九):全面解密新QQ桌面版的Electron内存占用优化

IM跨平台技术学习(十):快速选型跨平台框架Electron、Flutter、Tauri、React Native等》(* 本文)

3、初识框架

1)Electron:

* 技术背景:Electron 由 GitHub 开发,因其使用 HTML、CSS 和 JavaScript 等 Web 技术构建跨平台桌面应用程序的能力而广受欢迎。

* 主要功能:Electron 通过其 Node.js 集成提供对本机 API 的轻松访问,使开发人员能够创建功能丰富的应用程序。它还支持用 C++ 编写的本机插件,尽管构建这些插件可能更复杂且容易出错。

2)Flutter:

* 技术背景:Flutter 由 Google 创建,以其在移动应用程序开发中的使用而闻名,但也可用于桌面应用程序。

* 主要特点:Flutter 提供了一组丰富的可定制 UI 小部件,其 Dart 代码被编译为本机机器代码,从而实现快速执行并减少开销。它采用独特的“基于小部件”架构,提供丰富的可定制 UI 小部件。

3)Tauri:

* 技术背景:Tauri 是一个较新的框架,旨在创建安全且轻量级的桌面应用程序。它旨在弥合 Rust 和 Web 技术之间的差距。

* 主要功能:Tauri 支持使用 Rust 或 C 构建本机插件,从而可以访问 Web 平台中不可用的本机 API 和功能。

4)React Native:

* 技术背景:React Native,同样来自 Facebook,主要以移动应用程序开发而闻名,但也有桌面应用程序开发的扩展。

* 主要功能:React Native 提供了一种访问本机 API 和功能的方法,但与其他框架相比,它可能需要更多的努力。它支持无缝集成第三方库。

5)Qt:

* 技术背景:Qt 是一个 C++ 框架,绑定了多种语言,包括 Python 和 JavaScript。这是一个历史悠久、历史悠久的框架。

* 主要功能:Qt 提供出色的本机集成功能,允许开发人员访问本机 API 和功能。它提供了一套用于构建跨平台桌面应用程序的全面工具,并强调本机外观和感觉。

4、跨平台能力

在跨平台功能方面,Electron、Flutter、Tauri 和 Qt 足以在多个操作系统上运行应用程序。它们为 Windows、macOS 和 Linux 提供广泛的支持,使其成为需要广泛兼容性的项目的合适选择。

React Native 虽然主要是为移动设备设计的,但可以扩展以创建桌面应用程序。然而,它的跨平台支持可能不像其他框架那样无缝,并且可能需要额外的努力才能在所有平台上实现一致的性能和 UI。

5、性能表现

性能是桌面应用程序开发的关键因素。

以下是这些框架的性能特征:

  • 1)Electron:以其较高的资源使用率而闻名,Electron 应用程序可能会占用更多内存和 CPU,从而影响较旧或功能较弱的计算机的性能;
  • 2)Flutter:Flutter 的性能值得称赞,这要归功于它的编译代码和 GPU 加速。它提供快速的启动时间和流畅的动画;
  • 3)Tauri:Tauri 因其轻量级特性和低资源消耗而脱颖而出。它是构建快速且响应灵敏的桌面应用程序的绝佳选择;
  • 4)React Native:React Native 桌面应用程序可以节省资源,但跨平台优化性能可能需要额外的工作;
  • 5)Qt:Qt 的性能非常出色,提供类似本机的速度和响应能力。它是资源密集型应用程序的首选。

6、用户界面

创建丰富且响应迅速的用户界面是桌面应用程序开发的一个重要指标。

以下是这些框架在 UI 功能方面的比较:

  • 1)Electron:Electron 提供了大量预构建的 UI 组件和广泛的主题选项。开发人员可以轻松创建具有视觉吸引力的应用程序;
  • 2)Flutter:Flutter 基于小部件的方法允许高度可定制且具有视觉吸引力的用户界面。它提供了广泛的开箱即用的小部件;
  • 3)Tauri:Tauri 不像其他框架那样提供那么多的 UI 组件,但允许对用户界面进行严格控制,这有利于创建独特的设计;
  • 4)React Native:通过React Native,开发人员可以使用第三方库和组件进行UI设计。可能需要额外的工作才能实现完全定制的外观;
  • 5)Qt:Qt 擅长提供与目标平台无缝集成的类似本机的 UI 元素。它是需要精美原生外观的应用程序的首选。

7、开发经验

流畅的开发工作流程对于生产力至关重要。

以下是这些框架在开发经验方面的比较:

  • 1)Electron:Electron 提供了一套广泛的开发工具和一个活跃的社区。调试和热重载得到良好支持;
  • 2)Flutter:由于其基于 widget 的架构和强大的文档,Flutter 的开发体验得到了简化。热重载是一个突出的功能;
  • 3)Tauri:Tauri 仍然相对较新,但使用 Rust 和 JavaScript 提供了简化的开发过程。它强调快速发展;
  • 4)React Native:React Native 为 Web 和移动开发人员提供了熟悉的开发体验。然而,过渡到桌面可能需要一个学习曲线;
  • 5)Qt:Qt 提供了一个成熟的开发环境,具有广泛的 IDE 和工具。它以其稳定性和全面的文档而闻名。

8、原生集成

访问本机平台功能和 API 对于许多桌面应用程序至关重要。

让我们看看这些框架如何处理本机集成:

  • 1)Electron:Electron 通过 Node.js 集成提供对本机 API 的轻松访问。它还支持用 C++ 编写的本机插件,尽管构建这些插件可能更复杂且容易出错;
  • 2)Flutter:Flutter 的 Dart 代码被编译为本机机器代码,从而实现快速执行并减少开销。它采用了一种称为“基于小部件”架构的独特方法,提供了一组丰富的可定制 UI 小部件;
  • 3)Tauri:Tauri 支持使用 Rust 或 C 构建原生插件,可用于访问 Web 平台中不可用的原生 API 和功能;
  • 4)React Native:React Native 提供了一种访问本机 API 和功能的方法,但与其他框架相比可能需要更多的努力。它支持无缝集成第三方库;
  • 5)Qt:Qt 提供出色的本机集成功能。它是一个 C++ 框架,绑定了多种语言,包括 Python 和 JavaScript,可用于访问本机 API 和功能。

9、社区与生态系统

开发人员社区的规模和活跃度,可以显着影响框架的成功和第三方库的可用性。

这些框架的表现如下:

  • 1)Electron:Electron 拥有一个庞大而活跃的社区,提供大量可用的插件和扩展;
  • 2)Flutter:Flutter 拥有不断增长的社区和越来越多的软件包,主要专注于移动开发,但也有桌面扩展;
  • 3)Tauri:Tauri 仍在成长,但其社区充满热情并致力于其发展。其生态系统正在稳步扩展;
  • 4)React Native:React Native 拥有完善的社区,主要专注于移动开发。桌面扩展社区规模较小,但正在不断增长;
  • 5)Qt:Qt 拥有悠久的历史和强大的生态系统,拥有庞大的工具、小部件和扩展库。

10、 框架们的成功案例

让我们探索一些现实世界的用例和使用这些框架构建的应用程序示例,以更好地了解它们在不同场景中的优点和缺点。

以下是具体的场景举例:

  • 1)Electron:广泛用于构建跨平台桌面应用程序,包括代码编辑器(VSCode)、通信工具(Slack)和娱乐应用程序(Spotify);
  • 2)Flutter:Flutter 逐渐成为富媒体应用程序的选择,已用于 Google Ads、阿里巴巴和 Reflectly 等应用程序;
  • 3)Tauri:Tauri 正在获得轻量级、安全应用程序的青睐,包括密码管理器 (LosePass) 和通信工具 (Mailspring);
  • 4)React Native:虽然主要是一个移动框架,但 React Native 已扩展到 Discord 和 Microsoft Teams 等应用程序中的桌面使用;
  • 5)Qt:Qt 是一种多功能选择,可用于从工业软件到游戏和汽车信息娱乐系统的广泛应用。

11、开发时的挑战

虽然每个框架都有其优点,但必须意识到潜在的挑战和限制。

比如这些:

  • 1)Electron:Electron 应用程序可能会占用大量资源,可能会导致旧硬件上出现性能问题;
  • 2)Flutter:如果您主要是移动开发人员,那么使用 Flutter 进行桌面开发可能会涉及一个学习曲线;
  • 3)Tauri:作为一个相对较新的框架,与更成熟的选项相比,Tauri 可能拥有较小的社区和较少的第三方库;
  • 4)React Native:将 React Native 转换到桌面可能需要额外的努力,并且某些特定于平台的功能可能更难访问;
  • 5)Qt:Qt 的学习曲线,特别是对于刚接触 C++ 的开发人员来说,可能是一个挑战。

12、本文小结

为桌面应用程序开发选择正确的框架很大程度上取决于项目的具体要求,例如目标平台、性能预期、UI 需求和所需的开发体验。

如果正在寻找一个允许你利用 Web 技术的框架,Electron和React Native是不错的选择。Electron 拥有庞大的社区和广泛的预构建组件,而 React Native 提供强大的组件系统,并允许在移动和桌面平台之间重用代码。

如果性能和小包大小是优先考虑的,请考虑Flutter或Tauri。Flutter 提供快速的启动时间和流畅的动画,而 Tauri 则以其轻量级和低资源消耗而闻名。

如果你需要一个具有出色本机集成和本机外观的框架,Qt是一个可靠的选择。

如果你正在开发需要丰富的、可定制的用户界面的复杂应用程序,Flutter可能是最佳选择,因为它基于 widget 的开发方法。

还请各位开发者要记住,请考虑与每个框架相关的学习曲线,特别是如果你或团队尚不熟悉所涉及的技术。比如,Tauri 需要 Rust 或 C 的前置知识,而 Flutter 使用 Dart 做为预备知识。

13、相关资料

[1] Electron官方开发者手册

[2] Flutter官方手册

[3] Tauri官方手册

[4] React Native开发指南

[5] QT官方文档和手册

[6] 快速了解新一代跨平台桌面技术——Electron

[7] Electron初体验(快速开始、跨进程通信、打包、踩坑等)

[8] vivo的Electron技术栈选型、全方位实践总结

[9] 融云基于Electron的IM跨平台SDK改造实践总结

[10] 闲鱼IM基于Flutter的移动端跨端改造实践

[11] 网易云信基于Electron的IM消息全文检索技术实践


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

posted @ 2024-01-11 10:58 Jack Jiang 阅读(390) | 评论 (0)编辑 收藏

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

​[- 1 -] IM消息ID技术专题(一):微信的海量IM聊天消息序列号生成实践(算法原理篇)

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

[摘要] 如何优雅地解决“消息序列号只要保证顺序性而不需要兼顾唯一性”的问题呢?这就是本文所要分享的内容,强烈建议深入理解和阅读。


[- 2 -] IM消息ID技术专题(二):微信的海量IM聊天消息序列号生成实践(容灾方案篇)

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

[摘要] 本篇将会介绍 seqsvr 分布式容灾架构的演变。


[- 3 -] IM消息ID技术专题(三):解密融云IM产品的聊天消息ID生成策略

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

[摘要] 本文要分享的是融云即时通讯云产品中的聊天消息ID生成算法和策略,一个19字节的ID就能包含:时间戳、消息类型、会话ID、序列号,小ID、大用途,值得借鉴!


[- 4 -]IM消息ID技术专题(四):深度解密美团的分布式ID生成算法

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

[摘要] 对于美团的Leaf-segment这个ID生成方案,因为生成的ID全局唯一、全局有序,所以非常适合IM这种应用场景,这也是即时通讯网整理并分享给社区的原因。


[- 5 -] IM消息ID技术专题(五):开源分布式ID生成器UidGenerator的技术实现

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

[摘要] 本文是专题系列文章的第5篇,专门介绍百度开源的分布式消息ID生成器UidGenerator的算法逻辑、实现思路、重点源码解读等,或许能带给你更多的启发。


[- -] IM消息ID技术专题(六):深度解密滴滴的高性能ID生成器(Tinyid)

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

[摘要] 本文将要分享的是滴滴开源的分布式ID生成器Tinyid的技术原理、使用方法等等,希望能进一步为你打开这方面的技术视野。


[- 7 -] IM消息ID技术专题(七):深度解密vivo的自研分布式ID服务(鲁班)

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

[摘要] 本文通过对分布式ID的3种应用场景、实现难点以及9种分布式ID的实现方式进行介绍,并对结合vivo业务场景特性下自研的鲁班分布式ID服务从系统架构、ID生成规则与部分实现源码进行分享,希望为本文的阅读者在分布式ID的方案选型或技术自研提供参考。


[- 8 -] IM开发宝典:史上最全,微信各种功能参数和逻辑规则资料汇总

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

[摘要] 本文将根据微信官方目前已公开的资料,将它的一些常用功能参数和逻辑规则资料进行了汇总整理,希望能助力你的IM开发!


[- -]  IM开发干货分享:我是如何解决大量离线消息导致客户端卡顿的

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

[摘要] 今天这篇不是原理性文章,而是为大家分享一下由笔者主导开发实施的IM即时通讯聊天系统,针对大量离线消息(包括消息漫游)导致的用户体验问题的升级改造全过程。


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

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

[摘要] 本系列文章将尽量从理论概念入手,通俗易懂的梳理IM中的基础技术概念和热门技术点,希望能帮你理清看似一团乱麻的IM知识体系,助你找到清晰的IM技术学习方向。


[- 11 -] 零基础IM开发入门(二):什么是IM系统的实时性?

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

[摘要] 对于技术门外汉来说,到底什么是IM的“实时性”?该如何理解它?这就是本文想要讨论的主题。


[- 12 -] 零基础IM开发入门(三):什么是IM系统的可靠性?

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

[摘要] 本篇主要讲解IM系统中的“可靠性”这个话题,内容尽量做到只讲原理不深入展开,避开深层次的技术性探讨,确保通俗易懂。


[- 13 -] 零基础IM开发入门(四):什么是IM系统的消息时序一致性?

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

[摘要] 本文尽量以通俗简显的文字为你讲解IM消息时序一致性问题的产品意义、发生原因、解决思路等。


👉52im社区本周新文:《IM跨平台技术学习(十):快速对比跨平台框架Electron、Flutter、Tauri、React Native等》,欢迎阅读!👈

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

posted @ 2024-01-10 13:24 Jack Jiang 阅读(59) | 评论 (0)编辑 收藏

本文由字节跳动技术团队李晨光、匡建鑫、陈鉴平分享,本文有修订和改动。

1、引言

新媒体互动直播已成为了广大网民最重要的休闲娱乐方式之一。丰富的传统文化、新闻、竞技体育、法律、知识共享等内容,通过移动端互动直播的形式得以更加高效的展现传播,既让优质的直播内容可以实现爆发式传播扩散,又可以让用户有更多的机会感受,学习甚至主动参与直播互动。超低延时视频直播技术正在走上一条全新的发展之路。

本文将带您了解超低延时视频直播技术的优化和演进历程。

 
技术交流:

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

2、系列文章

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

3、低延时直播技术的作用

网络基础设施升级、音视频传输技术迭代、WebRTC 开源等因素,驱动音视频服务时延逐渐降低, 使超低延时直播技术成为炙手可热的研究方向。实时音视频业务在消费互联网领域蓬勃发展, 并逐渐向产业互联网领域加速渗透。经历了行业第一轮的红利爆发期,我国实时音视频行业的场景效能逐渐深化,步入到理性增长阶段。

延时的指标选择很大程度上取决于用户与内容制作方的交互耦合程度,场景丰富多样。

在这些极端场景下,延时在用户侧希望越小越好,接近于实时通信的低延迟模式可以最大化地激发用户的参与感,无缝地与内容生产方产生互动效应,调动用户所见即所得的积极性。比如在主播秀场的PK、送礼、工会冲榜、打赏的活动关键环节,竞争双方的储值大户都希望实时地观察到自身主播在礼物刷榜后的反应,为后台运营决策团队或者后续活动策略提供第一时间的信息反馈。

下图体现了从技术/产品/运营的三方角度来综合思考低延时直播技术的作用;从外部-内部综合因素考虑技术的变迁对整个生态正向循环的影响。

4、传统直播技术中RTMP协议的延迟问题

RTMP 协议是最传统的直播协议,主播端采用 RTMP 协议推送 H.264/5 和 AAC 编码的视音频数据到云厂商 CDN 服务器进行转封装分发,端到端延迟一般控制在 3 到 7 秒。

问题是 RTMP 的可扩展性存在缺陷,同时对于延迟的进一步下探存在一定的技术困难。

RTMP 协议情况下:为了满足延时降低必然压缩播放器的下载缓冲区,这样会引发显著的卡顿问题,使得播放的观感产生不舒适的感受(延时下探至 2 秒以下)。

5、传统直播技术在实时互动场景中的不足

1)视频延时和弹幕交互的延时存在显著差异,问题聊天内容互动与视频传输图像节奏不匹配:

2)观众与主播互动形式单一,是单向内容传导无法做到双向(在 RTC 技术引入之前无法显著解决)。

3)单向传导的局限第一个方面表现在:观众端拉流传输无法做到根据网络情况自适应调节。用户只能以固定的码率进行流媒体传输无法做到动态感知,在网络情况实时变化的场景(比如弱网,移动基站切换等)固定单向码率传输有较大概率造成丢帧卡顿等因素影响观播体验。另一方面在网络条件更好时,固定码率传输无法动态提升视频传输码率(更高的画质带来更加舒适的体验)

4)在直播和连麦场景共存的互动直播场景下,主播采用传统RTMP推流在遇到连麦PK场景时,会产生推流/本地连麦合流/服务器连麦合流的切换问题,这种场景变换的切换会使得观众端产生瞬间的卡顿问题。如果采用基于webRTC直播技术的超低延时直播方案,这种推流--连麦逻辑的合流切换问题可以得到比较友好的解决(只需要改变服务器转发-订阅流通道的分发逻辑,不涉及推流媒体数据流的旁路调度切换)。

6、 超低延时直播与标准直播的区别

6.1超低延时直播

超低延时直播是近年来新兴起的一类应用。

如电商直播、赛事直播等场景,兼具高并发与低延时的特性,传统直播 3-20s 的时延难以满足其需求,但对实时互动的要求又不及视频会议等典型的实时音视频应用,无需将时延降低至 400ms 以下。

为此,超低延时直播融合了传统直播与实时音视频的技术架构,通过取长补短的方式实现了介于二者之间的端到端时延。

尽管针对超低延时直播厂商尚无一套标准的技术路径,但大体可以归纳为拉流协议、网络架构和推流协议三个方面的改造, 在实际应用过程中,厂商会平衡成本及性能指标等因素,在不同的协议和网络架构之间进行选择。

6.2传输层协议的差异

基于 UDP 协议的可靠性优化,为弱网对抗策略提供依据。

传统直播 FLV/RTMP 等采用的是 TCP 协议(或者 QUIC 协议)TCP 是牺牲传输实时性来换取数据完整性的可靠传输协议。

弱网环境下,其在数据传输前的“三次 握手”连接会带来较大延时。

而 UDP 作为不可靠的传输协议,其最大的优点为高实时性,但不保证数据的到达和排序。

实时音视频 产品(如 RTM 超低延时直播)往往采用 UDP 协议,并在此之上进行协议层与算法层的优化,来提高传输的可靠性与逻辑性。

相关文章可阅读:

  1. 网络编程懒人入门(五):快速理解为什么说UDP有时比TCP更有优势
  2. 技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解
  3. 不为人知的网络编程(六):深入地理解UDP协议并用好它
  4. 不为人知的网络编程(七):如何让不可靠的UDP变的可靠?

6.3UDP 协议的优化

UDP 协议往往和 RTP/RTCP 协议一起在实际应用中出现。

RTP 负责数据传输,其协议头中的序列号、 端口类型、时间戳等字段,可为数据包的分组、组装、排序提供逻辑依据。

RTCP 作为 RTP 的控制协议,负责对 RTP 的传输质量进行统计反馈,并为弱网对抗策略提供控制参数。

7、RTM 协议本身的演进历程

a=extmap:18 "http://www.webrtc.org/experiments/rtp-hdrext/decoding-timestamp"

a=extmap:19 "uri:webrtc:rtc:rtp-hdrext:video:CompositionTime"

a=extmap:21 uri:webrtc:rtc:rtp-hdrext:video:frame-seq-range

a=extmap:22 uri:webrtc:rtc:rtp-hdrext:video:frame-type

a=extmap:23 uri:webrtc:rtc:rtp-hdrext:video:reference-frame-timestamp

a=extmap:27 uri:webrtc:rtc:rtp-hdrext:audio:aac-config

RTP 使用 RTP 私有扩展头携带 DTS/CTS 值,每一帧 RTP 数据包通过 RFC5285-Header-Extension 扩展头携带该帧的 DTS 值,每一帧首个 RTP 包和 VPS/SPS/PPS 包通过 RFC5285-Header-Extension 扩展头携带该帧的 CTS 值,通过 PTS = DTS + CTS 计算当前帧的时间戳。用于启播快速音画同步和播放器播控逻辑精准音画同步。

扩展头携带帧的起始/结束序号:如果首帧的前几个包丢失,那么可根据起始序号快速发起重传加快首帧;如果当前帧的后几个包丢失,那么可根据该帧的结束序号快速发起重传,降低延时,减少卡顿。

扩展头携带帧的类型:如果携带并解析了正确的帧类型,客户端可以不用解析 metadata ;同时在弱网情形,客户端可以跳过 B 帧直接解码 P 帧,加速出帧并减少潜在卡顿。

扩展头携带 P 帧的参考帧信息:如果发生弱网情形,那么客户端可以依照扩展头指定的参考帧关系及其对应时间戳,跳过 B 帧解码 ,减少卡顿发生。

为了加速信令交互的速度,CDN 可以在某些条件下不去查询媒体信息,直接向客户端返回支持的音视频能力;此时 SDP 的媒体描述中将不包含有具体的音视频配置详细信息。在音频层面,此时AnswerSDP 中不包含 aac 解码所需的头信息;此时我们需要采取 RTP 扩展头模式携带 AAC-Config 供客户端在 RTP 收包时刻自行解析处理完成解码动作,作用是减少信令交互时间,提升拉流成功率。

miniSDP 信令标准实现部分(抖音)。

CDN 信令异步回源。

RTP 携带扩展头组成部分。

8、WebRTC 协议在直播播放器的移植

RTM 低延时直播基于 WebRTC 技术衍生,基于 WebRTC 标准构建点到点传输一般有如下几个步骤:

  • 1)通信双方要进行媒体协商,会话详细规范即 SDP(Session Description Protocol) 交互;
  • 2)随后进行交互式网络地址协商(查询对端真实 IP 地址)准备构建媒体传输通道;
  • 3)当上述条件准备完毕即进入最终的 Peer to Peer 点对点媒体数据传输。

信令部分客户端-服务器单独开发,利用了 SDP 标准报文模式。媒体传输部分采用开源的 WebRTC 框架和字节自研的实时音视频媒体引擎进行媒体传输。

9、RTC 信令协议的改造升级

MiniSDP压缩协议:https://github.com/zhzane/mini_sdp

标准 SDP 比较冗长(5-10KB 左右),不利于快速高效传输。在直播场景下,会尤其影响首帧时间。

MiniSDP 对标准 SDP 文本协议进行高效能压缩,将原生 SDP 转换成更小的二进制格式,使其能够通过一个 UDP 包来传输。

降低信令交互时间,提高网络传输效能,降低直播拉流首帧渲染时间,提高拉流秒开率/成功率等 QoS 统计指标。

10、CDN对RTM 信令的异步回源优化

降低 RTM 信令交互时间,降低 RTM 拉流首帧渲染时间。

原来的流程在服务端缓存不命中时需要等待回源拿到数据,才能返回带有 AacConfig 信息的 AnswerSDP。客户端收到 AnswerSDP 后发送 STUN,而服务端只能在收到 STUN 才能开始下发数据。

如下图左:当异步回源情况下,服务端不再等待回源结果直接返回 AnswerSDP,之后回源和WebRTC 建连流程同步进行。

如上图右:等到 WebRTC 建连成功且回源拿到数据立即下发 RTP 数据。

11、视频渲染卡顿的优化(百秒卡顿平均降低4秒)

改善人均看播时长,改变 RTC 引擎的组帧/解码策略;禁止 RTC 在低延时模式下的丢帧,改善直播的视频渲染卡顿。

传统的 RTC 场景优先保时延,全链路会触发各种丢帧(包括但不限于解码模块,网络模块),FLV 直播场景会优先保证观播体验(不丢帧,良好的音画同步效果)。

RTM 要想减少卡顿,取得 qoe 的收益,播控策略需进行定制化,定制逻辑修改点:

1)确保不会由于软解的解码耗时或者硬解的 dequeuinputbuffer 等其它 api 操作阻塞 jitterbuffer ,内核层有一层强制的音画同步逻辑,可以确保音视频的播放体验;

2)同时上层在监控网络模块和解码模块的缓存长度,有相应的兜底逻辑:

  • a. 判断硬解确实解不过来,dec_cache_frames 过多,上报错误,会降级到软解;
  • b. jitterbuffer 异常,缓存的 frame_list 过多,触发播放器异常逻辑,上报错误,重新拉流。

12、RTM播控逻辑的优化

改善移动端看播渗透,RTC 统一内核方案天生存在缺陷( MediaCodec 硬件解码器初始化耗时久)。将 RTM 视频解码模块从 RTC 内核中迁移至 TTMP 播放内核,复用了 FLV 的视频解码模块( MediaCodec 避免重新初始化)。显著的降低了安卓平台的首帧渲染时间,提升了拉流的成功率。

RTC 内核通用逻辑:

改进的 RTM 内核播控逻辑:

13、相关文章

[1] TCP/IP详解 - 第11章·UDP:用户数据报协议

[2] TCP/IP详解 - 第17章·TCP:传输控制协议

[3] 零基础入门:基于开源WebRTC,从0到1实现实时音视频聊天功能

[4] 实时音视频入门学习:开源工程WebRTC的技术原理和使用浅析

[5] 零基础快速入门WebRTC:基本概念、关键技术、与WebSocket的区别等

[6] 学习RFC3550:RTP/RTCP实时传输协议基础知识

[7] 基于RTMP数据传输协议的实时流媒体技术研究(论文全文)

[8] 技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解

[9] 让互联网更快:新一代QUIC协议在腾讯的技术实践分享

[10] 实时音视频面视必备:快速掌握11个视频技术相关的基础概念

[11] 实时音视频开发理论必备:如何省流量?视频高度压缩背后的预测技术

[12] 移动端实时音视频直播技术详解(一):开篇

[13] 直播系统聊天技术(九):千万级实时直播弹幕的技术实践

[14] 在线音视频直播室服务端架构最佳实践(视频+PPT) [附件下载]

[15] 视频直播技术干货:一文读懂主流视频直播系统的推拉流架构、传输协议等

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

posted @ 2024-01-04 11:45 Jack Jiang 阅读(120) | 评论 (0)编辑 收藏

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

​[- 1 -] 全面掌握移动端主流图片格式的特点、性能、调优等

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

[摘要] 本文我们一起全面分析学习目前主流和新兴的几种图片格式的特点、性能、调优等,以及相关开源库的选择,希望能为您的移动端应用(包括本社区主要讨论的即时通讯应用)中的图片优化带来一些启发。


[- 2 -] 最火移动端跨平台方案盘点:React Native、weex、Flutter

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

[摘要] 本篇主要以react-native、weex、flutter,深入聊聊当前最火的这3种跨平台移动开发方案的实现原理、现状与未来。至于为什么只讲它们,因为对比ionic、phoneGap,它们更于 “naive” (˶ ⁻̫ ˵)。看完本篇,相信你会对于当下跨平台移动开发的现状、实现原理、框架的选择等有更深入的理解。


[- 3 -] 子弹短信光鲜的背后:网易云信首席架构师分享亿级IM平台的技术实践

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

[摘要] 本文内容来自对网易云信首席架构师周梁伟的采访,采访内容主要围绕网易云信这种海量用户IM云平台的关键技术难点以及对应的技术实践。


[- 4 -] IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列

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

[摘要] 消息是互联网信息的一种表现形式,是人利用计算机进行信息传递的有效载体,比如即时通讯网坛友最熟悉的即时通讯消息就是其具体的表现形式之一。


[- 5 -] 微信技术分享:微信的海量IM聊天消息序列号生成实践(容灾方案篇)

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

[摘要] 本篇将会介绍 seqsvr 分布式容灾架构的演变。


[- 6 -] 阿里技术分享:深度揭秘阿里数据库技术方案的10年变迁史

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

[摘要] 阿里数据库事业部研究员张瑞,将为你讲述双11数据库技术不为人知的故事。


[- 7 -] 自已开发IM有那么难吗?手把手教你自撸一个Andriod版简易IM (有源码)

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

[摘要] 本文不是一篇即时通讯理论文章,文章内容全部由实战代码组织而成。


[- 8 -] 融云技术分享:解密融云IM产品的聊天消息ID生成策略

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

[摘要] 本文要分享的是融云即时通讯云产品中的聊天消息ID生成算法和策略,一个19字节的ID就能包含:时间戳、消息类型、会话ID、序列号,小ID、大用途,值得借鉴!


[- -]  IM开发基础知识补课(六):数据库用NoSQL还是SQL?读这篇就够了!

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

[摘要] 本文将分析传统数据库(即SQL数据库)存在的一些问题,以及盘点目前市面上几大类 NoSQL 特性、优缺点等,希望给大家提供一些在不同业务场景下存储技术选型方面的参考。


[- 10 -] 适合新手:从零开发一个IM服务端(基于Netty,有完整源码)

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

[摘要] 本文写的比较浅显但不太易懂,建议结合代码一起来读,文章配套的完整源码请从本文文末 “11、完整源码下载” 处下载!


[- 11 -] 拿起键盘就是干:跟我一起徒手开发一套分布式IM系统

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

[摘要] 本文记录了我开发的一款面向IM学习者的 IM系统——CIM(全称:CROSS-IM),同时提供了一些组件帮助开发者构建一款属于自己可水平扩展的 IM。


[- 12 -] 适合新手:手把手教你用Go快速搭建高性能、可扩展的IM系统(有源码)

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

[摘要] 本文适合有一定网络通信技术基础的IM新手阅读。如果你对网络编程,以及IM的一些理论知识知之甚少,请务必首先阅读:《新手入门一篇就够:从零开发移动端IM》,按需补充相关知识。


[- 13 -] IM里“附近的人”功能实现原理是什么?如何高效率地实现它?

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

[摘要] 本文将简要的为你讲解“附近的人”的基本理论原理,并以Redis的GEO系列地理位置操作指令为例,理论联系实际地为你讲解它们是如何被高效实现的。


[- 14 -] IM开发基础知识补课(七):主流移动端账号登录方式的原理及设计思路

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

[摘要] 本文将分享几种典型的移动端账号登陆方式的技术原理,以及设计思路,理解后,完全可以快速实施于你的各种应用系统(并不限于IM系统)中。


[- 15 -] IM“扫一扫”功能很好做?看看微信“扫一扫识物”的完整技术实现

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

[摘要] 本文将详细为你解密微信“扫一扫识物”功能背后的技术秘密。


[- 16 -] IM要做手机扫码登录?先看看微信的扫码登录功能技术原理

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

[摘要] 本文将以轻松活泼的语言形式,为你分析和讲解微信手机扫码登录的技术原理,希望在你的IM中开发此功能时有所启发。


👉52im社区本周新文:《视频直播技术干货(十一):超低延时视频直播技术的演进之路》,欢迎阅读!👈

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

posted @ 2024-01-03 11:57 Jack Jiang 阅读(18) | 评论 (0)编辑 收藏

     摘要: 本文由字节跳动技术团队杨晨曦分享,本文有修订和改动。1、引言本文将带你一起初步认识Thrift的序列化协议,包括Binary协议、Compact协议(类似于Protobuf)、JSON协议,希望能为你的通信协议格式选型带来参考。  技术交流:- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM》- 开源IM框架源码:https://github.com/JackJ...  阅读全文

posted @ 2023-12-28 10:52 Jack Jiang 阅读(59) | 评论 (0)编辑 收藏

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

[- 1 -] 谈谈移动端 IM 开发中登录请求的优化

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

[摘要] 到底是“登陆”还是“登录”?这是很多处女坐开发者纠结的问题,不过它不是本文本讨伦的内容。本文将针对移动端IM的登陆功能给出相应的优化建议。


[- 2 -] 移动端IM登录时拉取数据如何作到省流量?

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

[摘要] 移动网络时代,手机的流量是个很昂贵的资源(至少暂时是这样)。一个典型的移动端IM在登录后,往往要向服务器同步非常多的数据,如果处理的不好是很费流量的,那么从技术上来讲,有没有节省流量的方法呢?这就是本文要讨论的话题。


[- 3 -] 浅谈移动端IM的多点登录和消息漫游原理

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

[摘要] 本文将展开聊聊移动端IM“多点登陆”与“消息漫游”的原理。


[- 4 -] 完全自已开发的IM该如何设计“失败重试”机制?

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

[摘要] 如何设计好这个失败重试的机制,使得客户端能做好失败重试,服务器有能够排除这种重复消息,但是排重处理不太复杂?


[- 5 -] 通俗易懂:基于集群的移动端IM接入层负载均衡方案分享

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

[摘要] 本文将以基于TCP数据传输协议的移动端IM为例,通过循序渐进地方式,分享如何构建一个基于分布式集群的移动端IM接入层的设计和实现。


[- -] 微信对网络影响的技术试验及分析(论文全文)

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

[摘要] 本文来自论文《微信对网络影响的技术试验及分析》,文中研究了微信对现今移动网络的影响,对于即时通讯开发人员来说,文中的某些数据和研究结果,对于实现类似的技术,有一定的参考和借鉴意义。即时通讯网(52im.net)现全文收录之。


[- 7 -] 即时通讯系统的原理、技术和应用(技术论文)

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

[摘要] 首先,介绍即时通信的概念、特点和技术原理,较为全面地剖析了实现即时通信系统涉及的关键技术,包括即时通信传输协议、相关安全技术和音/视频编解码技术等;其次,简要概述了即时通信系统在我校的应用情况;最后,说明当前即时通信工具存在的问题及其发展趋势。


[- 8 -] 开源IM工程“蘑菇街TeamTalk”的现状:一场有始无终的开源秀

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

[摘要] 本文将简要介绍TeamTalk开源的过去和现在,为打算研究和采用TeamTalk的同行提供一定程度的参考。文中所涉及内容如有不妥,还请各位看官见谅。


[- -]  QQ音乐团队分享:Android中的图片压缩技术详解(上篇)

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

[摘要] 实际在生产环境下,群消息的发送都会想尽办法进行压缩,并开展各种改善性能的处理办法,而不是像上述举例里的直接扩散写(即2000人群里,一条消息被简单地复制为2000条一对一的消息投递)。具体有哪些优先策略?本文或许可以带给你一些启发。


[- 10 -] QQ音乐团队分享:Android中的图片压缩技术详解(下篇)

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

[摘要] 关于压缩图片在诸如即时通讯应用场景下的好处,我们就不再赘述,不言自明。本篇将承接上篇《QQ音乐团队分享:Android中的图片压缩技术详解(上篇)》,继续讨论图片的尺寸压缩和常用的几种尺寸压缩算法。


[- 11 -] 腾讯原创分享(一):如何大幅提升移动网络下手机QQ的图片传输速度和成功率

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

[摘要] 本文内容是由腾讯TMQ专项测试团队针对手机QQ图片上传速度和成功率问题,在各种复杂移动网络环境下的优化实践总结和整理而成。文章虽是针对手机QQ图片上传这一特定业务功能,但内容中大量涉及复杂移动网络环境下无线网络的特性、特点以及相关第一手测试数据,都是非常珍贵的,尤其值得移动端IM开发、消息推送这种深度依赖移动网络的应用开发者借鉴和参考。


[- 12 -] 腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(上篇)

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

[摘要] 本文将给读者们一个一年多以前为公司的某产品成功优化网络流量的案例。速度、成功率与流量正好是 Apps 网络优化的几大重点,希望本文我们分享的思路能够给诸位正在开展或将来会开展此类工作的读者们一些启发。


[- 13 -] 腾讯原创分享(三):如何大幅压缩移动网络下APP的流量消耗(下篇)

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

[摘要] 本篇中将详细介绍我们的具体分析方法和实践优化思路,以及在优化过程中总结出来的法则等。


[- 14 -] 如约而至:微信自用的移动端IM网络层跨平台组件库Mars已正式开源

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

[摘要] 本文正文内容引用了微信开发团队的资料。


[- 15 -] 基于社交网络的Yelp是如何实现海量用户图片的无损压缩的?

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

[摘要] 研究Yelp的极致图片压缩技术,或许能给即时通讯开发者同行带来一定的借鉴意义,而这也是此文的意义所在。


[- 16 -] 腾讯技术分享:腾讯是如何大幅降低带宽和网络流量的(图片压缩篇)

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

[摘要] 本次文章跟大家分享如何在保障质量(指的是图片质量、音视频质量)前提下所做的带宽和网络流量压缩,进而达到运营成本的优化。


[- 17 -] 腾讯技术分享:腾讯是如何大幅降低带宽和网络流量的(音视频技术篇)

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

[摘要] 本文接上篇《腾讯技术分享:腾讯是如何大幅降低带宽和网络流量的(图片压缩篇)》,继续腾讯公司分享如何在保障质量(指的是图片质量、音视频质量)前提下所做的带宽和网络流量压缩,进而达到运营成本的优化。


[- 18 -] 为什么说即时通讯社交APP创业就是一个坑?

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

[摘要] 所以今天,我将尽量试着以用户的眼光,去描述这样一种现实:什么拳打QQ、脚踩微信,自嗨式的创业就像浮云一样......


👉52im社区本周新文:《IM通讯协议专题学习(十):初识 Thrift 序列化协议》,欢迎阅读!👈

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

posted @ 2023-12-27 15:23 Jack Jiang 阅读(54) | 评论 (0)编辑 收藏

本文由冰河分享,作者博客 binghe.gitcode.host,原题“这套分布式IM即时通讯系统如何写到简历上?我给你整理好了!”,本文有修订和改动。

1、引言

分布式IM即时通讯系统本质上就是对线上聊天和用户的管理。

针对聊天本身来说,最核心的需求就是:发送文字、图片、文件、语音、视频、消息缓存、消息存储、消息未读、已读、撤回,离线消息、历史消息、单聊、群聊,多端同步,以及其他一些需求。

对用户管理来说,存在的需求包含:添加好友、查看好友列表、删除好友、查看好友信息、创建群聊、加入群聊、查看群成员信息、退出群聊、修改群昵称、拉人进群、踢人出群、解散群聊、填写群公告、修改群备注以及其他用户相关的需求等。

为了更好的理解分布式IM即时通讯系统的设计,我站在架构师的角度,在充分了解系统需求、业务流程和技术流程后,从全局视角为系统设定方案目标,对技术方案进行选型,对系统进行总体架构设计和分层架构设计,并梳理清楚发送消息的交互链路、单聊和群聊的交互链路。希望对你有帮助。

 
技术交流:

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

2、方案目标

在进行技术选型与总体架构设计之前,需要明确一个事项,就是系统无论采用哪种方案,采用哪种架构设计都需要明确这种方案的业务目标、技术目标和架构目标,并在研发过程中不断评估系统的总体性能表现,发现系统瓶颈并不断进行优化。

总体上,我们搭建和开发的分布式IM即时通讯系统,需要满足如下方案目标。

具体是:

  • 1)业务目标:满足需求设计篇章中的各类需求场景;
  • 2)技术目标:支持无限扩容,百万用户同时在线聊天;
  • 3)架构目标:高并发、高性能、高可用、可监控、可预警、可伸缩,支持无限扩展。

3、技术选型

在技术选型上,除了采用SpringBoot等基础框架外,也会采用容器化方案。

同时,考虑到为了尽量降低技术门槛,在整个分布式IM即时通讯系统的技术选型中,主要采用市面上比较流行的技术框架和方案。

具体选型如下所示:

  • 1)开发框架:SpringBoot、SpringCloud、SpringCloud Alibaba、Dubbo;
  • 2)缓存:Redis分布式缓存+Guava本地缓存;
  • 3)数据库:MySQL、TiDB、HBase;
  • 4)流量网关:OpenResty+Lua;
  • 5)业务网关:SpringCloud Gateway + Sentinel;
  • 6)持久层框架:MyBatis、Mybatis-Plus;
  • 7)服务配置、服务注册与发现:Nacos;
  • 8)消息中间件:RocketMQ;
  • 9)网络通信Netty
  • 10)文件存储:Minio;
  • 11)日志可视化治理:ELK;
  • 12)容器化管理:Swarm、Portainer;
  • 13)监控:Prometheus、Grafana;
  • 14)前端:Vue;
  • 15)单元测试:Junit;
  • 16)基准测试:JMH;
  • 17)压力测试:JMeter。

4、初步架构设计

对于IM即时通讯系统来说,涵盖了即时通讯后端服务、大后端平台、SDK接入服务、OpenAI接入服务、大前端UI,我相信不少小伙伴多多少少能够画出IM即时通讯系统的架构图,大致如下图所示。

 

其实,这种这种架构设计也比较常见,在这种架构设计中,Kong/Openresty/Nginx只做负载均衡和反向代理,研发人员更多的是关注业务层和基础层的开发,流量比较小时,这种架构设计一般不会有什么问题。但是一旦流量比较大,用户调用后端平台的接口发送消息时,即时通讯SDK同步调用即时通讯服务的接口就会出现性能问题。

因为每个终端同时只能与一个IM即时通讯服务实例建立连接,如果大量的用户终端恰好都与一个IM即时通讯服务建立连接,那即时通讯SDK频繁同步调用同一个IM即时通讯服务的接口就会出现性能瓶颈。此时,出现性能瓶颈时,不仅仅会影响到IM即时通讯服务,也会对后端平台接收请求的业务造成一定的影响。

5、架构设计优化

既然上节图中所示的架构设计存在性能瓶颈,那我们如何进行优化呢?

为此我们在前图基础上进行了优化,优化后的架构如下图所示。

对比两图可以看出,在屏蔽掉技术实现细节的前提下,我们将对业务的校验和流量管控进行前置化,放大Kong/OpenResty/Nginx的职责,使得这些软件不仅具备反向代理和负载均衡的功能,还能实现限流、黑白名单、流量管控、业务校验等功能。

也就是说,在这种架构模式下,我们充分发挥了整个分布式IM即时通讯系统的入口职责,充分利用Kong/OpenResty/Nginx的高并发、高吞吐量的能力,尽量将大部分无效请求挡在整个系统之外。例如,用户在没登录系统的前提下,就尝试调用发送消息、添加好友、添加群组等等接口。这样会大大减轻后台平台的业务压力。

除了在Kong/OpenResty/Nginx中实现限流、黑白名单、流量管控、业务校验等功能外,我们还引入了业务网关集群,实现限流、降级、熔断、流控、校验、鉴权等功能,进一步保证下游系统的稳定性和安全。

为了解决大量用户终端恰好连接到同一个IM即时通讯服务实例,IM即时通讯SDK频繁调用同一个IM即时通讯服务实例的接口造成的性能问题。我们在IM即时通讯服务SDK与IM即时通讯服务之间引入了RocketMQ集群。

IM即时通讯服务集群中的每一个IM即时通讯服务实例在集群中都有一个唯一的ID,并且每个IM即时通讯服务实例在启动后,只会监听RocketMQ中与自身ID相关的Topic。这样每个IM即时通讯服务只会收到与自身ID相关的Topic中的消息,不会接收所有的消息。

当用户登录系统后,就会与IM即时通讯服务建立长连接,并且会以用户ID和终端为Key,以IM即时通讯服务的ID为value,将其存储到分布式缓存中。同时,会以用户ID和终端为Key,以用户终端与IM即时通讯服务建立的长连接为value,将其存储到IM即时通讯服务本地内存中。

当用户调用后端平台的接口发消息时,会带上目标用户的ID,并且在IM即时通讯SDK中会指定用户登录的终端设备,最终会通过IM即时通讯SDK向RocketMQ发送消息。

此时IM即时通讯SDK会根据目标用户ID和终端从分布式缓存中获取目标用户连接的IM即时通讯服务的ID,并向此ID相关的Topic发送消息。此时与目标用户建立长连接的IM即时通讯服务就会接收到RocketMQ中的消息,随后根据用户ID和终端从本地缓存中获取到与用户终端建立的长连接,并基于此长连接向用户推送消息。

另外,在实际实现中,为了避免大量用户同时只连接IM即时通讯服务集群中的某一个服务实例,会对用户连接的IP、浏览器指纹、手机设备等做Hash和取模运算,使其尽量均匀分布到集群中的每一个服务实例上。

那么问题来了,这种架构设计还有进一步优化的空间吗?

6、容器化架构设计

为进一步增强分布式IM即时通讯系统的性能、可用性和弹性伸缩能力,我们可以对分布式IM即时通讯系统进行容器化架构设计,如下图所示。

可以看到,我们对分布式IM即时通讯系统的架构设计进行了进一步优化,采用了容器化架构设计。在原有架构的基础上,我们进行了如下改进和优化。

1)基础支撑服务:基础支撑服务会由各种基础中间件、数据存储服务、以及监控服务实现,包含:MySQL数据库、TiDB数据库、HBase、Redis缓存、RocketMQ消息队列、Prometheus监控和Portainer容器管理等基础中间件实现,基础支撑服务会对整个分布式IM即时通讯系统提供最基础的数据、传输、监控和容器管理等服务。

2)容器化:在容器化层面,会通过Docker、Swarm和Portainer实现,其中,会基于Swarm和Portainer对容器化进行管理。

3)其他基础性功能实现:除了上述分层架构外,对于建设分布式IM即时通讯系统来说,还要考虑异常监控、服务注册与发现、可视化、服务降级与兜底数据、服务限流、服务容灾、容量规划与扩缩容和全链路压测等。

7、DDD分层业务架构设计

在分布式IM即时通讯系统中,不管是大后端平台,还是IM即时通讯服务,我们都会对业务层的代码采用分层业务架构。

这里,可以借鉴DDD的分层架构思想,将代码总体上分成展示层、应用层、领域层和基础设施层四个层次。

但是,考虑到分布式IM即时通讯系统的特殊性,又不会严格按照DDD的原则来设计代码分层,具体按照如下图所示。

可以看到,分布式IM即时通讯系统会借鉴DDD的设计思想,但是不会完全按照DDD的方式进行设计。

1)展示层:展示层,也叫做用户UI层,是DDD设计的最上层,对外提供API接口,接收客户端请求,解析参数,返回结果数据,并对异常进行处理。

2)应用层:应用层,也叫做Application层,应用层主要处理容易变化的业务场景,可对相关的事件、调度和其他聚合操作进行相关的处理。

3)领域层:领域层,也叫做Domain层,领域层可以说是DDD设计的精髓所在,它是将业务系统中相对不变的部分抽象出来封装成领域模型。在分布式IM即时通讯系统的设计中,领域层基本不会依赖其他层,也不会依赖基础设施层,这里是与DDD设计存在区别的地方。

4)基础设施层:基础设施层,也叫做Infrastructure层,基础设施层会对其他各层提供通用的基础能力,在分布式IM即时通讯系统中,就包括了缓存、通用工具类、消息、系统的持久化机制等。

8、总体IM消息交互链路

在分布式IM即时通讯系统中,我们忽略掉其他一些细节信息,重点关注下发送消息的交互链路逻辑。不管是单聊还是群聊,最终都需要通过IM即时通讯服务将消息推送给用户的终端。此时发送消息的流程如下图所示。

可以看到:用户在分布式IM即时通讯系统发送消息时,不管是单聊还是群聊,最终的消息都会推送到用户登录的终端设备上。假设此时用户A给用户B发送消息,或者用户A和用户B在同一个群组,用户A向群组发送消息,用户B接收消息的主要流程如下。

具体是:

  • 1)用户A调用后端平台的接口向用户B发送消息,并且发送的消息中会带有用户B的ID以及终端信息;
  • 2)后端平台将消息缓存起来,并且会将消息异步写入消息库;
  • 3)后端平台从Redis中获取用户B连接的IM即时通讯服务的ID;
  • 4)后端平台获取到用户B连接的IM即时通讯服务的ID后,会向RocketMQ中用户B连接的IM即时通讯服务ID对应的Topic发送消息;
  • 5)IM即时通讯服务会监听自身服务ID对应的RocketMQ中Topic的消息,此时,用户B连接的IM即时通讯服务会接收到消息;
  • 6)IM即时通讯服务接收到消息后,会根据用户B的ID以及终端信息从缓存中获取用户B与IM即时通讯服务建立的连接,并且通过这个连接向用户B推送消息。

要实现如上发送消息的流程,前提是要满足如下条件:

  • 1)后端平台满足分布式条件,可随时横向扩展;
  • 2)IM即时通讯服务满足分布式条件,可随时横向扩展;
  • 3)每个启动的IM即时通讯服务实例在集群中都有一个唯一的ID;
  • 4)每个IM即时通讯服务,都只监听自身ID对应的RocketMQ中Topic的消息;
  • 5)用户登录分布式IM即时通讯系统后,会与IM即时通讯服务建立长连接,并且会根据用户ID和所在的终端缓存长连接,同时会根据用户ID和所在的终端将连接的IM即时通讯服务的ID缓存到Redis;
  • 6)用户发送消息时,会根据目标用户的ID和终端从Redis中获取IM即时通讯服务的ID,进而向当前IM即时通讯服务的ID对应的RocketMQ的Topic发送消息;
  • 7)对应的IM即时通讯服务监听并接收到RocketMQ消息后,会根据目标用户的ID和终端从缓存中获取到用户的连接信息,向目标用户推送消息。

9、IM单聊交互链路

单聊就是在分布式IM即时通讯系统中,一个用户直接与另外一个用户聊天,也就是一对一的聊天。在这种场景下,很有可能单聊的两个用户中,出现用户不在线的情况。

例如:用户A给用户B发送消息时,用户B可能不在线。

此时,我们就需要将用户A向用户B发送的消息存储起来。

其实,在我们实现的分布式IM即时通讯系统中,无论把用户B是否在线,都会存储消息记录。当用户B登录系统后,将消息同步给用户B,如下图所示。

可以看到,用户A向用户B发送消息时:

  • 1)如果用户B在线,就可以按照发送消息的交互链路向用户B发送消息了;
  • 2)如果用户B不在线,此时就无法向用户B正常推送消息。当用户B登录分布式IM即时通讯系统后,就会调用后端平台的接口拉取所有未读消息,并通过用户B在线流程向用户B推送消息。

10、IM群聊交互链路

群聊就是在分布式IM即时通讯系统中,多个用户在同一个群组中进行聊天。

此时在发送消息时,我们可以通过群组ID找出群内所有在线的用户,将消息即时发送给在线的用户。

那些未在线的用户就按照单聊未在线的用户进行处理,如下图所示。

可以看到,群聊的交互链路流程如下所示:

  • 1)用户调用后端平台的接口向群组发送消息;
  • 2)后端平台将消息缓存并异步写入消息库;
  • 3)由于是向群组发送消息,群里有多个用户,此时就会从Redis中获取所有用户连接的IM即时通讯服务ID列表;
  • 4)对用户按照服务ID分组,将相同服务ID下的用户分在同一个逻辑分组里,方便后续推送消息,并且会记录未在线的用户列表;
  • 5)循环向每个服务ID对应的RocketMQ中的Topic发送消息;
  • 6)广播处理未在线用户的未读消息ID;
  • 7)IM即时通讯服务会监听自身服务ID对应的Topic,会随时接收推送到自身服务的消息;
  • 8)当IM即时通讯服务接收到消息后,此时用户掉线,或者用户不在线,向用户推送消息就会失败,或者未查询到用户与IM即时通讯服务建立的连接,就不会向用户推送消息;
  • 9)当用户登录分布式IM即时通讯系统后,会从后端平台拉取历史(离线)消息,并通过用户在线的流程,向用户推送消息;

好了,看到这里,你明白如何设计一个高度可扩展的分布式IM即时通讯系统了吗?

11、相关资料

[1] 浅谈IM系统的架构设计

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

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

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

[5] 移动端IM中大规模群消息的推送如何保证效率、实时性?

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

[7] 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

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

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

[10] 融云技术分享:全面揭秘亿级IM消息的可靠投递机制

[11] 阿里IM技术分享(三):闲鱼亿级IM消息系统的架构演进之路

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

[13] 跟着源码学IM(十):基于Netty,搭建高性能IM集群(含技术思路+源码)

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

[15] 得物从0到1自研客服IM系统的技术实践之路

[16] 海量用户IM聊天室的架构设计与实践

[17] 史上最通俗Netty入门长文:基本介绍、环境搭建、动手实战

[18] 新手入门:目前为止最透彻的的Netty高性能原理和框架架构解析

[19] 写给初学者:Java高性能NIO框架Netty的学习方法和进阶策略

[20] 手把手教你用Netty实现网络通信程序的心跳机制、断线重连机制

[21] 史上最强Java NIO入门:担心从入门到放弃的,请读这篇!

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

posted @ 2023-12-21 11:29 Jack Jiang 阅读(111) | 评论 (0)编辑 收藏

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

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

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

[摘要] 本文将以新手的视角引导你阅读相关文章,便于你从零开发一个移动端IM做好方方面面的知识准备:包括但不限于网络编程基础、通信协议的选型、IM的架构设计等等。文笔有限,如有不妥之处还请批评指正,希望对你有用。

[- 2 -] 移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”

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

[摘要] 本文的目的,就是希望以通俗易懂的语言,帮助移动端IM开发者更好地理解移动网络的各种特性,使得开发出的功能能更好地适应移动网络,给用户带来更好的使用体验。

[- 3 -] 移动端IM开发者必读(二):史上最全移动弱网络优化方法总结

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

[摘要] 本文将针对上篇中提到的特性,结合我们的实践经验,总结了四个方法来追求极致的“爽快”:快链路、轻往复、强监控、多异步,从理论讲到实践、从技术讲到产品,理论联系实际,举一反三,希望给您带来启发。

[- 4 -] 从客户端的角度来谈谈移动端IM的消息可靠性和送达机制

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

[摘要] 这篇文章和大家聊下从移动端客户端的角度所关注的IM消息可靠性和送达机制

[- 5 -] 现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障

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

[摘要] 本文整理的有关内容,对于移动端即时通讯IM应用来说,同样具有启发意义

[- 6 -] 腾讯技术分享:社交网络图片的带宽压缩技术演进之路

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

[摘要] 为了进一步降低运营带宽成本,减小用户访问流量及提升页面加载速度,社交网络 CDN运维紧跟行业图片优化趋势,创新引入WebP、SharpP、自适应分辨率、Guetzli等图像压缩技术到现网,经过三年多的多部门联合攻关,已逐渐形成一套覆盖全图片类型(JPEG、JPG、PNG、WebP、GIF)多场景的图片压缩运营体系,适用于各类型终端,每年节约外网带宽几百G。

[- 7 -] 小白必读:闲话HTTP短连接中的Session和Token

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

[摘要] 本文的写作目的是以最白话地方式,通俗易懂的为你讲清HTTP协议中的Session和Token等概念,希望读完全文,您仍能满怀信心,继续义无反顾地跳入程序员这个职业深坑 ^_^。更深入的技术细节,请阅读《IM开发基础知识补课(四):正确理解HTTP短连接中的Cookie、Session和Token》。

[- 8 -] IM开发基础知识补课:正确理解前置HTTP SSO单点登录接口的原理

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

[摘要] 针对上述主流移动IM系统中“长”、“短”连接的分工方式,其中最为重要也是用户最先接触到的——就是基于Http的SSO单点登陆接口(有的系统里可能并不叫SSO接口,本文讨论的是其广义:即实现身份认证功能的http接口),那么这个SSO接口工作原理是什么?可以怎么来实现?有无最佳实践建议?

[- -]  移动端IM中大规模群消息的推送如何保证效率、实时性?

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

[摘要] 实际在生产环境下,群消息的发送都会想尽办法进行压缩,并开展各种改善性能的处理办法,而不是像上述举例里的直接扩散写(即2000人群里,一条消息被简单地复制为2000条一对一的消息投递)。具体有哪些优先策略?本文或许可以带给你一些启发。

[- 10 -] 移动端IM开发需要面对的技术问题

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

[摘要] 这两年多一直从事网易云信 iOS 端 IM SDK的开发,期间不断有兄弟部门的同事和合作伙伴过来问各种技术细节,干脆统一介绍下一个IM APP的方方面面,包括技术选型(包括通讯方式,网络连接方式,协议选择)和常见问题。

[- 11 -] 开发IM是自己设计协议用字节流好还是字符流好?

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

[摘要] 自己设计协议的话,协议用字节流好还是字符流好? 各有什么优缺点?

[- 12 -] 请问有人知道语音留言聊天的主流实现方式吗?

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

[摘要] 请问有人知道语音聊天的主流实现方式吗?就是类似微信那种,按住说话,录一段,发送那种。这语音文件录好之后是直接转成二进制发送。还是说当成一个文件上传到服务器,然后发送一个消息给对方,对方收到后下载?

[- 13 -] IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

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

[摘要] 本文将要讨论的是即时IM应用中极其重要但也不被用户感知的消息送达保证机制(即QoS机制),文中将给出目前主流的参考实现思路。

[- 14 -] IM消息送达保证机制实现(二):保证离线消息的可靠投递

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

[摘要] 实时在线投递针对的是消息收发双方都在线的情况(如当发送方用户A发送消息给接收方用户B时,用户B是在线的),那如果消息的接收方用户B不在线,系统是如何保证消息的可达性的呢?这就是本文要讨论的问题。

[- 15 -] 如何保证IM实时消息的“时序性”与“一致性”?

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

[摘要] 实时消息时序和一致性是分布式系统架构设计中非常难的问题(尤其IM应用这种以消息为中心的应用形态),困难在哪?有什么常见优化实践?这就是本文要讨论的内容。

[- 16 -] 一个低成本确保IM消息时序的方法探讨

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

[摘要] IM类系统中,都需要考虑消息时序问题,如果后发送的消息先显示,可能严重扰乱聊天消息所要表达的意义。

[- 17 -] IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?

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

[摘要] “用户在线状态的一致性”(单聊好友在线状态、群聊用户在线状态)是IM应用领域比较难解决的一个技术问题,如何精准实时的获得好友、群友的在线状态,是今天将要探讨的话题。

[- 18 -] IM群聊消息如此复杂,如何保证不丢不重?

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

[摘要] 由于“消息风暴扩散系数”的存在(概念详见《IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?》),群消息的复杂度要远高于一对一的单聊消息。群消息的实时性、可达性、离线消息是今天将要讨论的核心话题。

👉52im社区本周新文:《一套分布式IM即时通讯系统的技术选型和架构设计》,欢迎阅读!👈

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

posted @ 2023-12-21 10:30 Jack Jiang 阅读(55) | 评论 (0)编辑 收藏

本文由NetworkFox分享,来源于华三通信,原题“什么是国密算法?”,本文有修订和改动。

1、引言

最近几年经常能听到IM应用的开发者讨论国产信创方面的技术问题,在某些场景下,国密算法是硬性要求,所以学习一下国密算法还是很有必要的。

国密算法是指由中国国家密码管理局发布的密码算法标准,旨在保障国家信息安全。目前,国家密码管理局已发布了一系列国产商用密码标准算法,包括SM1(SCB2)、SM2、SM3、SM4、SM7、SM9以及祖冲之密码算法(ZUC)等。通过在金融、电子政务及安防等领域广泛应用国密算法,在对敏感数据进行机密性、完整性和可用性保护的同时,减少对外部密码产品的依赖,提升国家信息安全水平。

本文将尽量以通俗易懂的文字,为你分享国密算法的种类、技术原理和应用场景等。

 
 
技术交流:

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

2、系列文章

本文是IM通讯安全知识系列文章中的第12篇,此系列总目录如下:

即时通讯安全篇(一):正确地理解和使用Android端加密算法

即时通讯安全篇(二):探讨组合加密算法在IM中的应用

即时通讯安全篇(三):常用加解密算法与通讯安全讲解

即时通讯安全篇(四):实例分析Android中密钥硬编码的风险

即时通讯安全篇(五):对称加密技术在Android平台上的应用实践

即时通讯安全篇(六):非对称加密技术的原理与应用实践

即时通讯安全篇(七):用JWT技术解决IM系统Socket长连接的身份认证痛点

即时通讯安全篇(八):如果这样来理解HTTPS原理,一篇就够了

即时通讯安全篇(九):你知道,HTTPS用的是对称加密还是非对称加密?

即时通讯安全篇(十):为什么要用HTTPS?深入浅出,探密短连接的安全性

即时通讯安全篇(十一):IM聊天系统安全手段之通信连接层加密技术

即时通讯安全篇(十二):IM聊天系统安全手段之传输内容端到端加密技术

即时通讯安全篇(十三):信创必学,一文读懂什么是国密算法》(* 本文)

3、为什么需要国密算法?

3.1国密算法的产生背景

在网络信息传输和存储过程中,数据的保密性和安全性是一项重要的需求。

传统的国际标准加密算法虽然安全可靠,但由于无法保证源代码的安全性,因此存在着源代码被外部恶意攻击者渗透或篡改的风险。为了构建安全的行业网络环境并增强国家行业信息系统的“安全可控”能力,中国积极开展了针对信息安全需求的研究和探索。

自2007年开始,中国制定了国密算法标准,并于2010年正式发布。

经过多年的发展、改进和完善,国密算法已成为中国自主研发的密码算法标准,并在各行业得到广泛应用。它的诞生不仅显著提升了中国在密码技术领域的核心竞争力,还为国家信息安全建设作出了重要贡献。

3.2国密算法的特点

国密算法具备如下特点:

1)安全性高:国密算法采用了严密的密码学原理和复杂的运算方式,具有较高的安全性。它在加密、数字签名和哈希等功能上都能提供可靠的保护,抵抗了各种传统和现代密码攻击手段。

2)高效性与灵活性:国密算法在保证安全性的同时,注重算法的效率。它的加密速度和运行效率相对较高,同时也能适应不同的密码长度和密钥长度,以满足不同场景的需求。

3)标准化广泛:国密算法已被国家标准化机构认可和采用。它符合国际密码学标准的基本要求,具备与国际算法相媲美的能力。同时,国密算法也在国内推广和应用广泛,成为中国信息安全领域的基础核心算法之一。

4)自主创新:国密算法是中国自主研发的密码算法,所以对于算法的实现和推广都具有独立的掌控能力。这意味着中国可以更好地保护自己的国家信息安全,减少对外依赖,提高自主抵抗能力。

5)面向多领域应用:国密算法不仅局限于某个特定领域的应用,它适用于金融业、电子商务、通信、物联网、区块链等不同领域的信息安全保护。它的广泛应用范围使得国密算法可以满足不同行业的安全需求。

4、国密算法应用概述

国密算法包括SM1(SCB2)、SM2、SM3、SM4、SM7、SM9以及祖冲之密码算法(ZUC)等。

其中:

  • 1)SM1、SM4、SM7、祖冲之密码(ZUC)属于对称算法;
  • 2)SM2、SM9属于非对称算法;
  • 3)SM3属于杂凑算法。

下文将主要介绍国密算法中的常用算法SM1、SM2、SM3和SM4的实现和应用。

5、SM1算法的原理和应用场景

SM1算法是国密算法中的一种对称加密算法,其特点是加解密使用相同密钥。利用SM1对称加密算法加解密数据的过程。

SM1算法未公开,仅以IP核(Intellectual Property Core,一种预先做好的集成电路功能模块)的形式存在于芯片中。

SM1算法主要用于小数据量的加密保护,因此被广泛用于研制智能IC卡、智能密码钥匙、门禁卡、加密卡等安全产品。

6、SM2算法的实现和应用场景

6.1概述

SM2算法是基于ECC(Elliptic Curve Cryptography)椭圆曲线的非对称加密算法,包括了SM2-1椭圆曲线数字签名算法、SM2-2椭圆曲线密钥交换协议和SM2-3椭圆曲线公钥加密算法,分别用于实现数字签名、密钥协商和数据加密等功能。

SM2算法在许多领域都有广泛的应用。

在电子商务领域:SM2算法被用于保护用户个人信息的安全传输,确保用户在网上交易过程中的隐私和财产的安全。

在互联网金融领域:SM2算法被用于数字支付、电子银行等场景,实现用户身份认证和交易的安全性。

此外,SM2算法还适用于物联网领域,保护物联网设备之间的通信安全,确保数据的可靠传输。

6.2数据加密

在非对称加密算法中,可对外公布的密钥称为“公钥”,只有持有者所知的密钥称为“私钥”。发送者使用接收者的公钥来加密消息,接收者用自己的私钥解密和读取该消息。

利用SM2非对称加密算法加解密数据的过程:

6.3密钥协商

由于椭圆曲线的计算复杂性高,破解难度大,因此SM2算法在密钥协商技术领域也起着关键作用。

利用SM2算法进行密钥协商的过程:

  • 1)会话双方生成自己的私钥(随机数);
  • 2)会话双方由私钥、ECC椭圆曲线参数G各自计算出公钥;
  • 3)会话双方将自己的公钥传递给对方,传递过程公开。由于椭圆曲线的计算复杂性高,破解难度大,因此攻击者难以通过公钥和椭圆曲线参数G反推出私钥;
  • 4) 双方将自己的私钥与对方的公钥进行运算,最终得到相同的会话密钥,该会话密钥可作为共享密钥用于对称加密(例如SM4算法)通信。

6.4数字签名

数字签名是一种用于验证信息完整性、真实性和来源的技术手段。它通常用于确保数据在传输或存储过程中没有被篡改,并且可以追溯到特定的发送方。

发送方使用自己的私钥对消息进行加密,生成数字签名。接收方使用发送方的公钥对签名进行解密和验证,以验证消息的完整性和真实性。

在数字签名应用中,SM2算法通常与SM3摘要算法一起使用。

7、SM3算法的实现和应用场景

SM3杂凑(Hashing)算法是国密算法中的一种摘要算法。

SM3算法通过哈希函数将任意长度的消息压缩成固定长度的摘要。摘要具有唯一性,即不同信息生成的摘要不同,且无法由摘要恢复出原始信息,更无法伪造信息获得相同摘要,因此SM3算法被广泛用于实现数字签名、数据完整性检测及消息验证等功能。

基于SM3算法的特点,在信息安全领域,SM3算法被用于保护密码学协议、数字证书和电子签名等数据的完整性。在区块链领域,SM3算法被用于加密货币的区块生成和链上交易的校验,确保区块链的安全性。

此外,SM3算法还可以应用于密码学随机数的生成和伪随机序列的校验等领域,增加了数据的安全性和可靠性。

利用SM2算法和SM3算法对用户数据进行数字签名认证及完整性校验的过程:

  • 1) 用户A发送的数据A经过SM3哈希算法运算生成摘要A。
  • 2) 摘要A经过用户A的私钥加密生成数字签名。
  • 3) 用户A的明文数据和数字签名经加密算法(SM1/SM2/SM4)加密成密文后发送给用户B。加密算法以非对称加密算法SM2为例,即加解密使用不同密钥。
  • 4)密文到达用户B处,经加密算法(SM1/SM2/SM4)解密后,还原成明文数据和数字签名。
  • 5)用户B使用用户A的公钥解密数据包中的数字签名:
  •      解密成功,数据来源合法,得到摘要A;
  •      解密失败,数据来源非用户A,丢弃本次数据。
  • 6)收到的数据包中的明文数据经过SM3哈希运算生成摘要A’。对比摘要A和摘要A’:
  •      摘要A’=摘要A,数据完整;
  •      摘要A’≠摘要A,数据被篡改,丢弃本次数据。

8、SM4算法的实现和应用

8.1概述

与SM1算法分类相同,SM4算法同样为分组对称加密算法,但SM4算法实现公开。

分组加密算法是将明文数据按固定长度进行分组,用同一密钥逐组加密,密文解密时同样使用相同密钥逐组解密。

SM4算法实现简单,因此加解密速度较快,消耗资源少,主要用于大数据量的加密和解密,例如静态储存或数据信号传输通道中数据的加解密。

在网络安全领域,SM4算法被用于保护网络传输和存储的敏感数据,如银行卡信息、密码等。在物联网领域,SM4算法被用于物联网设备之间的通信和数据加密,确保物联网数据的隐私安全。

此外,SM4算法还可以应用于区块链领域,保护加密货币的交易安全等领域,为相关系统和数据的安全提供了保障。

SM4算法支持ECB、CBC、CFB等多种分组模式,下文将介绍ECB和CBC两种基础模式。

8.2加解密模式:ECB模式

SM4算法基于ECB模式对数据加解密的过程:

  • 1)发送端将明文按固定长度分组,对每个明文分组分别使用相同的密钥进行加密生成密文分组。完整的密文由所有密文分组按序排列组合而成;
  • 2)接收端将密文按固定长度分组,对每个密文分组分别使用相同的密钥进行解密生成明文分组。所有明文分组按序排列组合而成完整的明文数据。

ECB模式实现简单,各段数据间互不影响,有利于并行运算,但相同的明文块会被加密成相同的密文块,不能提供严格的数据保密性。

8.3加解密模式:CBC模式

SM4算法基于CBC模式对明文加密的过程:

  • 1)将明文按固定长度分组;
  • 2)明文分组1与初始向量IV进行异或运算,异或运算的结果经密钥加密后得到密文分组1;
  • 3)剩余的明文分组依次与前一个密文分组进行异或运算后再加密,得到对应的密文分组;
  • 4)完整的密文由所有密文分组按序排列组合而成。

SM4算法基于CBC模式对密文解密的过程:

  • 1)将密文按固定长度分组后,对密文分组进行倒序处理;
  • 2)对密文分组n先使用密钥进行解密,密文分组n解密后的数据与密文分组n-1进行逻辑逆运算,得到明文分组n;
  • 3) 同理,剩余的密文分组解密后再与前一个密文分组进行逻辑逆运算,得到对应的明文分组;
  • 4)最后,密文分组1用密钥解密后的数据是与初始向量进行逻辑逆运算,然后得到明文分组1;
  • 5)完整的明文由所有明文分组按序排列组合而成。

CBC模式安全性高于ECB,但明文块不能并行计算,且误差会传递下去。

9、国密算法与国际标准算法的对比

国密算法和国际标准算法都是现代密码学中常用的加密算法,但在技术和优劣方面存在一些区别。

常见国密算法与国际标准算法各参数性能的对比如下:

 

10、国密算法的典型应用场景有哪些?

10.1AD-WAN纵向IP/MPLS组网

国密算法可以与AD-WAN技术结合,应用于IP/MPLS纵向网场景。

通过AD-WAN智能运维平台,实现国密配置一键下发,在网络中构建国密数据加密通道,实现基于国密的端到端的IPsec隧道保护。

国密算法在端到端的IPsec隧道中的工作原理如下:

1)在IKE密钥协商阶段,使用IKE协议进行密钥协商过程中,采用SM2算法生成会话密钥。

2)在身份认证阶段,本端使用SM2和SM3算法生成身份信息的数字签名,并使用SM1或SM4算法和会话密钥对身份信息和数字签名进行加密;对端收到加密的身份信息后,使用相同的会话密钥解密,然后通过SM2和SM3算法进行身份认证。

3)在数据传输阶段,本端使用SM2和SM3算法生成用户数据的数字签名,并使用SM1或SM4算法以及会话密钥对用户数据和数字签名进行加密;对端收到加密的用户数据后,使用相同的会话密钥解密,然后通过SM2和SM3算法进行数据完整性检查。

10.24G/5G VPDN业务组网

4G/5G VPDN(Virtual Private Dialup Network,虚拟专有拨号网络)业务是在4G/5G无线网络中采用拨号方式实现的一种虚拟专有网络业务。它利用L2TP技术为客户构建与互联网隔离的隧道,以满足客户分支和总部内网通信的需求。VPDN组网同时支持将L2TP和IPsec技术结合,通过L2TP完成用户认证确保接入安全,并利用IPsec保障通信数据安全。

1)4G/5G VPDN组网中分支网关由4G/5G路由设备担任,通过拨号接入运营商网络。

2)运营商对4G/5G路由设备的APN(Access Point Name,接入点名称)、账户、SIM/USIM卡信息进行认证。

3)4G/5G路由设备认证通过后被运营商判断是VPDN用户,同时由运营商AAA服务器向LAC(L2TP Access Concentrator,L2TP访问集中器)设备下发L2TP隧道属性,LAC设备将基于下发的L2TP隧道属性信息向该VPDN用户所属总部的LNS(L2TP Network Server,L2TP网络服务器)设备发起隧道建立请求。

4)L2TP隧道建立后,LAC设备会通过此隧道向LNS设备透传用户的认证信息。LNS设备向总部内网的AAA服务器发起对VPDN用户的二次认证,认证通过后为VPDN用户分配一个企业内网IP地址。分支终端用户和总部可以开始通信。

5)分支网关与总部网关设备上均安装有国密板卡,通过IPsec协商建立起端到端的IPsec隧道,使用国密算法对传输的数据报文进行加密保护和数据完整性检查。

6)经IPsec加密后的数据报文在LAC设备处进行L2TP封装后,通过L2TP隧道传输到LNS。

7)LNS收到数据报文后首先对L2TP报文进行解封装,然后经过IPsec解密还原出数据报文,根据报文目的IP地址转发报文。

11、相关文章

[1] 常用加解密算法与通讯安全讲解

[2] 非对称加密技术的原理与应用实践

[3] IM聊天系统安全手段之通信连接层加密技术

[4] IM聊天系统安全手段之传输内容端到端加密技术

[5] 通俗易懂:一篇掌握即时通讯的消息传输安全原理

[6] 基于Netty的IM聊天加密技术学习:一文理清常见的加密概念、术语等

[7] 理论联系实际:一套典型的IM通信协议设计详解(含安全层设计)

[8] 微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解

[9] 手把手教你为基于Netty的IM生成自签名SSL/TLS证书


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

posted @ 2023-12-14 11:06 Jack Jiang 阅读(66) | 评论 (0)编辑 收藏

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

[- 1 -] 专访微信视频技术负责人:微信实时视频聊天技术的演进

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

[摘要] 本次专访是对谷沉沉老师在即将到来的 2017ArchSummit 全球架构师峰会上,以《数亿微信视频通话背后的视频技术二三事》为题发表演讲的一次预热。


[- 2 -] 腾讯音视频实验室:使用AI黑科技实现超低码率的高清实时视频聊天

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

[摘要] 腾讯音视频实验室和优图实验室X-lab的戴宇榮老师的团队联合开发的基于神经网络的实时视频超分辨率技术,在极小的神经网络模型大小的条件下,在手机实时视频通话上实现了基于机器学习的超分辨率技术,起到了主观上提升一档分辨率的效果。此技术即将应用在手机QQ 7.3.5的iOS版本上的实时视频聊天。


[- 3 -] 微信团队分享:微信每日亿次实时音视频聊天背后的技术解密

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

[摘要] 本文将为大家介绍微信实时音视频聊天在不同发展阶段的各个关键视频技术环节采用的方案,同时分享在实时音视频聊天中的视频编码器研发的方法和经验。


[- 4 -]福利贴:最全实时音视频开发要用到的开源工程汇总

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

[摘要] 本文汇总了一些能帮助到正在学习或进行实时音视频开发的同行们的开源工程,这些工程分为几类:音视频编解码类、视频前后处理、服务端类等,希望能加速您的学习或研究过程。


[- 5 -] 实时音视频聊天中超低延迟架构的思考与技术实践

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

[摘要] 从直播在线上抓娃娃,不断变化的是玩法的创新,始终不变的是对超低延迟的苛求。实时架构是超低延迟的基石,如何在信源编码、信道编码和实时传输整个链条来构建实时架构?在实时架构的基础之上,如果通过优化采集、编码、传输、解码和渲染中的关键环节来降低延迟?本文将会介绍即构在这方面的思考与实践。


[- 6 -] 理解实时音视频聊天中的延时问题一篇就够

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

[摘要] 音视频实时通讯的应用场景已经随处可见,从“吃鸡”的语音对讲、直播连麦、直播答题组队开黑,再到银行视频开户等。对于开发者来讲,除了关注如何能快速实现不同应用场景重点额音视频通讯,另一个更需要关注的可能就是“低延时”。但是,到底实时音视频传输延时应该如何“低”,才能满足你的应用场景呢?


[- 7 -] 写给小白的实时音视频技术入门提纲

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

[摘要] 本文是由一篇演讲稿整理出来的文章,目标读者是对实时音视频开发感兴趣但是又不知道如何下手的初学者们,对大家有所帮助。


[- 8 -] 微信多媒体团队访谈:音视频开发的学习、微信的音视频技术和挑战等

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

[摘要] 腾讯多媒体内核中心高级研究员时永方接受了LiveVideoStack的邮件采访,谈及了个人成长中的关键时刻,学习多媒体开发的三点核心,以及在5G和高清时代下,微信多媒体团队面临的挑战。


[- 9 -]  腾讯技术分享:微信小程序音视频技术背后的故事

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

[摘要] 本文来自腾讯视频云终端技术总监rexchang(常青)的技术分享,讲述的是微信小程序中音视频技术构思、设计和实现等方方面的内容,希望能为你的音视频技术实践带来启发。


[- 10 -] 微信多媒体团队梁俊斌访谈:聊一聊我所了解的音视频技术

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

[摘要] 从华为2012实验室到腾讯,过去十余年梁俊斌一直专注在音频技术。他告诉LiveVideoStack:音频技术还有许多难点需要解决,而作为技术人也延展到应用场景,关注用户需求。本文整理了本次访谈的主要内容,仅供参阅。


[- 11 -] 新浪微博技术分享:微博短视频服务的优化实践之路

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

[摘要] 本文的短视频技术跟IM的单聊、群聊、朋友圈里的小视频是类似的东西,文中针对短视频的相关优化实践可以为您的IM小视频开发提供一定的参考和借鉴意义,希望对您有用。


[- 12 -] 以网游服务端的网络接入层设计为例,理解实时通信的技术挑战

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

[摘要] 本文将尝试从开发者角度:梳理开发网游服务端的网络接入层的过程中面临的各种技术挑战,并针对性地提供相应的实时通信网络接入层解决思路,希望对于即时通讯应用的开发者来说,可以从中得到些许启发。


[- 13 -] 腾讯技术分享:微信小程序音视频与WebRTC互通的技术思路和实践

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

[摘要] 本文来自腾讯视频云终端技术总监rexchang(常青)技术分享,内容分别介绍了微信小程序视音视频和WebRTC的技术特征、差异等,并针对两者的技术差异分享和总结了微信小程序视音视频和WebRTC互通的实现思路以及技术方案。希望能带给你启发。


[- 14 -] 爱奇艺技术分享:轻松诙谐,讲解视频编解码技术的过去、现在和将来

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

[摘要] 本文以轻松幽默的语气,讲解了视频编解码的一些基本常识,并以爱奇艺为例,讲述了视频编解码技术在国内的发展以及未来的一些展望。


[- 15 -] 零基础入门:实时音视频技术基础知识全面盘点

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

[摘要] 本文是作者自已根据入门实时音视频的亲身经历,对于基础知识点的认知总结。虽然很浅显,但相对小白来说,能稍微系统的了解这些概念就已经是很好的起点了。


[- 16 -] 实时音视频面视必备:快速掌握11个视频技术相关的基础概念

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

[摘要] 本文将通过通俗的文字,言简意赅地为你讲解实时音视频技术中跟视频技术在关的11个非常重要的基础知识概念,希望能为你日后从事这方面的工作起到抛砖引玉的作用。


[- 17 -] 实时音视频开发理论必备:如何省流量?视频高度压缩背后的预测技术

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

[摘要] 本文将从视频编解码技术的基础知识入手,引出视频编解码技术中非常基础且重要的预测技术,学习帧内预测和帧间预测的技术原理。


👉52im社区本周新文:《即时通讯安全篇(十三):信创必学,一文读懂什么是国密算法》,欢迎阅读!👈

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

posted @ 2023-12-13 11:57 Jack Jiang 阅读(69) | 评论 (0)编辑 收藏

一、关于RainbowChat-Web

RainbowChat-Web是一套Web网页端IM系统,是RainbowChat的姊妹系统(RainbowChat是一套基于开源IM聊天框架 MobileIMSDK (Github地址)  的产品级移动端IM系统)。

二、v6.0 版更新内容

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

  • 1)[bug][服务端] - 解决了群成员从首页“消息”列表中删除已解散群的item时没有反应的问题;
  • 2)[新增][服务端] - 安全提升,实现了一套新的token生成、校验机制(支持对称加密和非对称加密两种模式);
  • 3)[新增][服务端] - 安全提升,启用了AppKey校验机制;
  • 4)[新增][前端]    - 优化了http接口、文件上传接口校验逻辑,提升安全性;
  • 5)[新增][前端]    - 安全提升,启用了AppKey校验机制;
  • 6)[新增][前端]    - 新增发送“群名片”消息功能;
  • 7)[新增][前端]    - 新增了消息转发功能;
  • 8)[优化][前端]    - 其它细节优化等。

三、v6.0 版新增特性截图

“群名片”功能运行截图查看演示视频更多运行截图):

“消息转发”功能(查看演示视频更多运行截图):

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

     摘要: 本文由字节跳动技术团队高原、汤中峰分享,原题“抖音功耗优化实践”,本文有修订和改动。一、引言功耗优化是应用体验优化的一个重要课题,高功耗会引发用户的电量焦虑,也会导致糟糕的发热体验,从而降低了用户的使用意愿。而功耗又是涉及整机的长时间多场景的综合性复杂指标,影响因素很多。不论是功耗的量化拆解,还是异常问题的监控,以及主动的功耗优化对于开发人员来说都是很有挑战性的。本文结合抖...  阅读全文

posted @ 2023-12-07 11:37 Jack Jiang 阅读(239) | 评论 (0)编辑 收藏

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

[- 1 -] 实时语音聊天中的音频处理与编码压缩技术简述

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

[摘要] 在视频或者音频通话过程中,一方面为了减小原始声音数据的传输码率,需要进行音频压缩,另一方面为了得到更高质量的音质,需要进行音频处理。如何处理好这两方面,保证声音传播的高真性,是个技术活儿!

[- 2 -] 网易视频云技术分享:音频处理与压缩技术快速入门

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

[摘要] 随着音频处理和压缩技术的不断发展,效果更好、适用范围更广、性能更高的算法和新的技术必将不断涌现,不断改善我们的生活。

[- 3 -] 学习RFC3550:RTP/RTCP实时传输协议基础知识

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

[摘要] 本文对这些协议进行初步归纳总结,在分析RFC3550的基础上,重点分析RTP系列协议,并以报文类型为主线分析RTCP系列协议。

[- 4 -]基于RTMP数据传输协议的实时流媒体技术研究(论文全文)

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

[摘要] 本文来自论文《基于 RTMP 协议的流媒体技术的原理与应用》,文中研究了基于 Flash 平台的流媒体系统中使用的 RTMP 协议的原理和应用,并对网络上实时流媒体的各种传输方式的优缺点进行了分析。

[- 5 -] 声网架构师谈实时音视频云的实现难点(视频采访)

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

[摘要] 孙雨润,声网 Agora.io 首席音视频架构师,负责全球音视频传输技术架构。毕业于中国科学技术大学,原 YY 后台架构师,主导 Web YY 整体后台系统架构搭建。曾任职腾讯 QQ 研究员 ,主导 QQ 空间面孔墙等项目;任职微软 Microsoft 期间,参与高性能计算产品项目。

[- 6 -] 还在靠“喂喂喂”测试实时语音通话质量?本文教你科学的评测方法!

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

[摘要] 实时语音聊天开发,对于一般的开发者来说比较神秘,很多朋友不太清楚如何全面的评估一个音频引擎。

[- 7 -] 如何用最简单的方法测试你的实时音视频方案

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

[摘要] 本文总结了一些有关实时音视频方案比较值得自测的要点,旨在没有生产环境反馈和丰富的测试资源情况下,用较低的成本来测试覆盖尽可能多的真实场景中可能遇到的网络和设备问题。

[- 8 -] 简述实时音视频聊天中端到端加密(E2EE)的工作原理

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

[摘要] 本文着重阐述端到端加密(E2EE),端到端加密是确保数据传输安全的可行方法之一。读完这篇文章,你可以了解这种加密方式的基本原理.

[- -]  理论联系实际:实现一个简单地基于HTML5的实时视频直播

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

[摘要] 本次分享就向大家介绍一下分享一下直播的整个流程和一些技术点,并动手实现一个简单的Demo。

[- 10 -] IM实时音视频聊天时的回声消除技术详解

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

[摘要] 为了不让文章读起来枯燥,本文将尽量通俗易懂地为您讲解实时音视频聊天场景下的回声消除技术原因希望能带给你些许启发。

[- 11 -] 如何优化传输机制来实现实时音视频的超低延迟?

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

[摘要] 要在语音视频 SDK 中实现超低延迟,实时的语音视频传输机制是必不可少的,而 FEC 和 ARQ 的智能结合是实时语音视频传输机制的基石。

[- 12 -] 实时通信RTC技术栈之:视频编解码

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

[摘要] 本文是系列文章的第一篇:讲述视频编解码的一些基本知识。

[- 13 -] Android直播入门实践:动手搭建一套简单的直播系统

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

[摘要] 实时视频直播是这两年非常火的技术形态,已经渗透到教育、在线互娱等各种业务场景中。但要搭建一套实时视频直播系统,并非易事,当然相关的直播技术理论在论坛的其它文章里已经写的非常详细,本文不再展开。

[- 14 -] 网易云信实时视频直播在TCP数据传输层的一些优化思路

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

[摘要] 网易云信的实时视频直播目前使用了TCP进行传输,且基于此,从编码动态适配、发送队列调整、协议优化、socket等做了全流程的优化,确保在限带宽、丢包、时延、抖动,无论单项还是复杂网络,都有非常不错的实际体验。

[- 15 -] 实时音视频聊天技术分享:面向不可靠网络的抗丢包编解码器

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

[摘要] 编解码器面向直播和网络通信是不一样的,我今天想说的是面向不可靠传输网络的抗丢包编解码器。

[- 16 -] P2P技术如何将实时视频直播带宽降低75%?

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

[摘要] 那整个系统是怎么设计的?使用了哪些技术来达成目标?接下来我来重点分享一下架构设计和技术细节。

👉52im社区本周新文:《抖音技术分享:抖音Android端手机功耗问题的全面分析和详细优化实践》,欢迎阅读!👈

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

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

     摘要: 本文由竹子爱熊猫分享,原题“(十一)Netty实战篇:基于Netty框架打造一款高性能的IM即时通讯程序”,本文有修订和改动。1、引言关于Netty网络框架的内容,前面已经讲了两个章节,但总归来说难以真正掌握,毕竟只是对其中一个个组件进行讲解,很难让诸位将其串起来形成一条线,所以本章中则会结合实战案例,对Netty进行更深层次的学习与掌握,实战案例也并不难,一个非常朴素的I...  阅读全文

posted @ 2023-11-30 12:28 Jack Jiang 阅读(88) | 评论 (0)编辑 收藏

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

[- 1 -] 即时通讯音视频开发(一):视频编解码之理论概述

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

[摘要] 本文主要讲解实时音视频技术中视频技术的编解码基础理论。

[- 2 -] 即时通讯音视频开发(二):视频编解码之数字视频介绍

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

[摘要] 本文主要讲解实时音视频技术中视频技术的数字视频知识。

[- 3 -] 即时通讯音视频开发(三):视频编解码之编码基础

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

[摘要] 本文主要讲解实时音视频技术中视频技术的编码理论知识。

[- 4 -] 即时通讯音视频开发(四):视频编解码之预测技术介绍

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

[摘要] 本文主要讲解实时音视频技术中视频技术的预测技术理论知识。

[- 5 -] 即时通讯音视频开发(五):认识主流视频编码技术H.264

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

[摘要] 本文主要讲解实时音视频技术中目前主流的视频编码技术H.264相关知识。

[- 6 -] 即时通讯音视频开发(六):如何开始音频编解码技术的学习

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

[摘要] 本文是一篇讲述新手如何学习音频编解码知识的文章。

[- 7 -] 即时通讯音视频开发(七):音频基础及编码原理入门

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

[摘要] 本文是一篇讲述基础音频知识和编码原理的文章。

[- 8 -]  即时通讯音视频开发(八):常见的实时语音通讯编码标准

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

[摘要] 本文是一篇讲述常用的实用音频通讯编码标准的文章。

[- 9 -] 即时通讯音视频开发(九):实时语音通讯的回音及回音消除概述

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

[摘要] 本文是一篇介绍实时音频通讯过程中的回音问题,以及回音消除技术的介绍文章。

[- 10 -] 即时通讯音视频开发(十):实时语音通讯的回音消除技术详解

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

[摘要] 本文是一篇详细介绍实时音频通讯过程中的回音消除技术的文章,主要描述的是回音消除技术理论和算法原理等。

[- 11 -] 即时通讯音视频开发(十一):实时语音通讯丢包补偿技术详解

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

[摘要] 本文是一篇详细介绍实时语音通讯过程中的丢包补偿技术的文章。

[- 12 -] 即时通讯音视频开发(十二):多人实时音视频聊天架构探讨

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

[摘要] 虽然都是视频通讯,大部分情况下的单人视频通话可能根本不需要用到流媒体服务,而多人视频,如在线教育这些则必须用到,所以下面主要介绍多人视频中服务端架构模式,以及各自特点。

[- 13 -] 即时通讯音视频开发(十三):实时视频编码H.264的特点与优势

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

[摘要] 本文主要讲解实时音视频技术中最流行的视频编码技术H.264的特点和优势,希望能为您的技术选型提供一定的参考。

[- 14 -] 即时通讯音视频开发(十四):实时音视频数据传输协议介绍

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

[摘要] 本文将简要介绍这些主流的实时音视频数据传输协议。

[- 15 -] 即时通讯音视频开发(十五):聊聊P2P与实时音视频的应用情况

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

[摘要] p2p就是点对点,两个客户端直接进行数据交互,不需要经过服务器转发(relay),这种方式能大大减轻服务端的负载,所以特别视适合大数据的传输,比如实时音视频聊天、在线视频直播、大文件传输等应用场景。

[- 16 -] 即时通讯音视频开发(十六):移动端实时音视频开发的几个建议

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

[摘要] 本文将就几个典型问题给出简要的参考建议。

[- 17 -] 即时通讯音视频开发(十七):视频编码H.264、VP8的前世今生

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

[摘要] 本文重在为读者从技术角度讲解H.264和VP8的发展渊源以及现时所面临的问题,相信读完此文后,对于即时通讯(IM聊天应用)的实时音视频开发中视频编码的选择会有个直观的了解。

[- 18 -] 即时通讯音视频开发(十八):详解音频编解码的原理、演进和应用选型

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

[摘要] 以下就是本次为大家分享的主要内容,希望通过此次分享可以使大家对音频编解码有一个整体的认识,并在实际应用中有参考的依据。

[- 19 -] 即时通讯音视频开发(十九):零基础,史上最通俗视频编码技术入门

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

[摘要] 视频编码技术涉及的内容太过专业和庞杂,市面上的书籍或博客多数都只是枯燥的技术概念罗列,对于新手来说读完依旧蒙逼是常态,本文将借此机会,专门给大家做一个关于视频编码的零基础科普。

[- 20 -] 即时通讯音视频开发(二十):一文读懂视频的颜色模型转换和色域转换

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

[摘要] 本文将以通俗易懂的文字,引导你理解视频是如何从采集开始,历经各种步骤,最终通过颜色模型转换和不同的色域转换,让你看到赏心悦目的视频结果的。

👉52im社区本周新文:《跟着源码学IM(十二):基于Netty打造一款高性能的IM即时通讯程序》,欢迎阅读!👈

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

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

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

[- 1 -] 开源实时音视频技术WebRTC的现状

[链接] http://www.52im.net/article-126-1.html

[摘要] 作为Google开源的技术,WebRTC并不是一个可以拿来就用并且性能很好的产品,而且正如众多的其它开源技术一样,WebRTC的发展并没有期待中的快。


[- 2 -] 简述开源实时音视频技术WebRTC的优缺点

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

[摘要] 作为Google开源的技术,WebRTC并不是一个可以拿来就用并且性能很好的产品,需要工程师们对其进行较多的改善。本文主要来谈一谈WebRTC的优缺点。


[- 3 -] 访谈WebRTC标准之父:WebRTC的过去、现在和未来

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

[摘要] 首届(WebRTC)网络实时通信大会期间,InfoQ 对 WebRTC 之父 Daniel C. Burnett 进行了专访,以下是专访实录。(注:Daniel 在访谈中的观点仅代表他本人及其在 W3C 所做的工作。)


[- 4 -] 良心分享:WebRTC 零基础开发者教程(中文)[附件下载]

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

[摘要] WebRTC,名称源自网页实时通信(Web Real-Time Communication)的缩写,是一个支持网页浏览器进行实时语音通话或视频聊天的技术,是谷歌2010年以6820万美元收购Global IP Solutions公司而获得的一项技术。


[- 5 -] WebRTC实时音视频技术的整体架构介绍

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

[摘要] 虽然WebRTC的目标是实现跨平台的Web端实时音视频通讯,但因为核心层代码的Native、高品质和内聚性,开发者很容易进行除Web平台外的移殖和应用。很长一段时间内WebRTC是业界能免费得到的唯一高品质实时音视频通讯技术。


[- 6 -] 新手入门:到底什么是WebRTC服务器,以及它是如何联接通话的?

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

[摘要] 通过WebRTC的端到端通信通常被人们所误解。WebRTC并不是真正意味着你不需要服务器来协商和联接通话。它只意味着,在多数情况中,你可以直接地在浏览器之间进行通信。


[- 7 -] WebRTC实时音视频技术基础:基本架构和协议栈

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

[摘要] 本文主要介绍WebRTC的架构和协议栈。


[- 8 -]  浅谈开发实时视频直播平台的技术要点

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

[摘要] 现在大大小小的公司,甚至个人开发者,都想开发自己的直播网站或App,本文会帮你理清,开发视频直播平台,你需要注意哪些技术要点。


[- 9 -] [观点] WebRTC应该选择H.264视频编码的四大理由

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

[摘要] 对实时音视频开发者来说,当开发一个基于WebRTC的产品时,我们应该选择什么样的视频编解码器?去年的时候,答案可能是“VP8”。几个月前,答案可能是“看情况”。现在答案是“除非必须用VP8,否则就用H.264”。


[- 10 -] 基于开源WebRTC开发实时音视频靠谱吗?第3方SDK有哪些?

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

[摘要] 利用Google开源的WebRTC来开发自已的实时音视频系统,靠不靠谱这个问题一直被问到,其实很难一两句话说清楚,因为答案不是一个靠谱或不靠谱可以回答好的,既然被反复问到,今天就系统地整理参考答案。


[- 11 -] 开源实时音视频技术WebRTC中RTP/RTCP数据传输协议的应用

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

[摘要] 本文在深入研究WebRTC源代码的基础上,以Video数据的发送和接收为例,力求用简洁语言描述RTP/RTCP模块的实现细节,为进一步深入掌握WebRTC打下良好基础。


[- 12 -] 简述实时音视频聊天中端到端加密(E2EE)的工作原理

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

[摘要] 本文着重阐述端到端加密(E2EE),端到端加密是确保数据传输安全的可行方法之一。读完这篇文章,你可以了解这种加密方式的基本原理.


[- 13 -] 实时通信RTC技术栈之:视频编解码

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

[摘要] 那么 RTC 技术栈究竟包含哪些技术,我们会提供一系列文章,来解读 RTC 技术栈。本文是系列文章的第一篇:讲述视频编解码的一些基本知识。


[- 14 -] 开源实时音视频技术WebRTC在Windows下的简明编译教程

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

[摘要] WebRTC是提供了一整套处理实时音视频的开源库。它包括了音视频处理(采集,编解码,前处理,后处理,渲染),数据传输(实时传输,流控)和业务逻辑控制。可以说 WebRTC 的出现大大减少了做音视频开发的难度,所以熟练掌握好这个库对于做音视频相关的同学就显的特别重要了。


[- 15 -] 网页端实时音视频技术WebRTC:看起来很美,但离生产应用还有多少坑要填?

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

[摘要] 直到2011年,WebRTC技术的出现,并且由谷歌做推广。WebRTC带来的体验是因为免安装才受到了关注。


[- 16 -] 了不起的WebRTC:生态日趋完善,或将实时音视频技术白菜化

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

[摘要] 有人说 2017 年是 WebRTC 的转折之年,2018 年将是 WebRTC 的爆发之年,这并非没有根据。就在去年(2017年),WebRTC 1.0 标准草案出炉(实际上WebRTC标准草案的早期版本早在2011年就已经发布,WebRTC并非一夜之间就出现的技术),并将于今年正式发布。与此同时,越来越多的浏览器和厂商都开始对它进行广泛的支持,WebRTC 即将成为互联网的基础设施了,或许门槛如此之高的实时音视频技术终有白菜化的那一天。


[- 17 -] 腾讯技术分享:微信小程序音视频与WebRTC互通的技术思路和实践

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

[摘要] 本文来自腾讯视频云终端技术总监rexchang(常青)技术分享,内容分别介绍了微信小程序视音视频和WebRTC的技术特征、差异等,并针对两者的技术差异分享和总结了微信小程序视音视频和WebRTC互通的实现思路以及技术方案。希望能带给你启发。


[- 18 -] 融云技术分享:基于WebRTC的实时音视频首帧显示时间优化实践

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

[摘要] 本文主要通过对WebRTC接收端的音视频处理过程分析,来了解和优化视频首帧的显示时间,并进行了总结和分享。


[- 19 -] 零基础入门:基于开源WebRTC,从0到1实现实时音视频聊天功能

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

[摘要] 本文将基于笔者公司开发的在线问诊产品中WebRTC技术的实践经验,讲述的如何基于WebRTC从零开发一个实时音视频聊天功能。文章会从WebRTC的基本知识、技术原理开始,基于开源技术为你演示如何搭建一个WebRTC实时音视频聊天功能。


[- 20 -] 实时音视频入门学习:开源工程WebRTC的技术原理和使用浅析

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

[摘要] WebRTC(全称 Web Real-Time Communication),即网页即时通信。是一个支持网页浏览器进行实时语音对话或视频对话的技术方案。从前端技术开发的视角来看,是一组可调用的API标准。


👉52im社区本周新文:《哔哩哔哩从0到1自研智能客服IM系统的技术实践之路 http://www.52im.net/thread-4517-1-1.html》,欢迎阅读!👈

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

posted @ 2023-11-24 11:39 Jack Jiang 阅读(72) | 评论 (0)编辑 收藏

     摘要: 本文由B端技术中心分享,原题“从0到1:哔哩哔哩智能客服系统的设计与实现”,本文有修订和改动。1、引言本文将要分享的是哔哩哔哩从0到1自研智能客服IM系统的技术实践过程,包括整体架构设计和主要核心功能的技术实现思路等,希望带给你启发。* 推荐阅读:《得物从0到1自研客服IM系统的技术实践之路》。  技术交流:- 移动端IM开发入门文章:《新手入门一篇就够...  阅读全文

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

     摘要: 本文由微信客户端团队rhythm分享,原题“视频号直播:如何进一步降低功耗占用?”,本文有修订和改动。1、引言功耗优化一直是 app 性能优化中让人头疼的问题,尤其是在直播这种用户观看时长特别久的场景。怎样能在不影响主体验的前提下,进一步优化微信iOS端视频号直播的功耗占用,本文给出了一个不太一样的答案。  技术交流:- 移动端IM开发入门文章:《新手入...  阅读全文

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

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

[- 1 -] 理论联系实际:一套典型的IM通信协议设计详解(含安全层设计)

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

[摘要] 本文将以理论联系实际的方式,详细讲解一套典型IM的通信协议设计的方方面面。


[- 2 -] 微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解

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

[摘要] 通信安全是互联网应用首要考虑的问题,有别于传统PC应用,随着移动互联网时代的到来,移动端的通信安全性要同时权衡:安全、性能、体验、数据流量等等方面,要实现一个完整而实用的通信安全解决方案并非易事。本文将详细介绍基于TLS 1.3的微信新一代通信安全协议mmtls。


[- 3 -] 来自阿里OpenIM:打造安全可靠即时通讯服务的技术实践分享

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

[摘要] OpenIM是阿里巴巴推出的,集成于阿里百川项目中的移动端IM开放服务。阿里百川是阿里巴巴集团无线开放平台,为移动开发者(涵盖移动创业者)提供快速搭建APP、加速APP商业化、提升用户体验的解决方案。


[- 4 -]简述实时音视频聊天中端到端加密

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

[摘要] 本文着重阐述端到端加密(E2EE),端到端加密是确保数据传输安全的可行方法之一。读完这篇文章,你可以了解这种加密方式的基本原理.


[- 5 -] 移动端安全通信的利器——端到端加密(E2EE)技术详解

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

[摘要] 端到端加密允许数据在从源点到终点的传输过程中始终以密文形式存在。采用端到端加密(又称脱线加密或包加密)时消息在被传输时到达终点之前不进行解密,因为消息在整个传输过程中均受到保护,所以即使有节点被损坏也不会使消息泄露。


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

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

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


[- 7 -] 通俗易懂:一篇掌握即时通讯的消息传输安全原理

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

[摘要] 本文将通过通俗易懂的文字,引导你一步步理解为何一个即时通讯应用需要加密技术,以及需要何种方式的加密技术等,希望能为您的IM或消息推送服务的设计提供一些参考。


[- 8 -]  IM开发基础知识补课(四):正确理解HTTP短连接中的Cookie、Session和Token

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

[摘要] 本文讨论的使用Http短连接的话题可能并不适用于微信这样的IM,因为微信的短连接并非使用Http标准协议实现,而是基于自研的Mars网络层框架再造了一套短连接机制,从而更适用于IM这种场景(更低延迟、更省流量、更好的弱网适应算法等)


[- 9 -] 快速读懂量子通信、量子加密技术

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

[摘要] 量子通信技术是个很高端的话题,对于搞IM、推送、网络通信的程序员来说,这到底是个什么鬼?所以我们一起来了解一下!


[- 10 -] 即时通讯安全篇(七):如果这样来理解HTTPS原理,一篇就够了

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

[摘要] 本文将尝试用通俗易懂的语言,一步步还原HTTPS的设计过程,以便您能轻松理解为什么HTTPS最终会是这副模样。


[- 11 -] 一分钟理解 HTTPS 到底解决了什么问题

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

[摘要] 本文只做简单的描述,力求简单明了的阐明主要内容,因为HTTPS 体系非常复杂,这么短的文字是无法做到很详细和精准的分析。想要详细了解HTTPS的方方面面,可以阅读此前即时通讯网整理的《即时通讯安全篇(七):如果这样来理解HTTPS,一篇就够了》一文。


[- 12 -] 一篇读懂HTTPS:加密原理、安全逻辑、数字证书等

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

[摘要] HTTPS(全称:Hypertext Transfer Protocol Secure,超文本传输安全协议),是以安全为目标的HTTP通道,简单讲是HTTP的安全版。本文,就来深入介绍下其原理。


[- 13 -] 基于Netty的IM聊天加密技术学习:一文理清常见的加密概念、术语等

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

[摘要] 本文正好借此机会,以Netty编写的IM聊天加密为例,为入门者理清什么是PKI体系、什么是SSL、什么是OpenSSL、以及各类证书和它们间的关系等,并在文末附上简短的Netty代码实示例,希望能助你通俗易懂地快速理解这些知识和概念!


[- 14 -] 手把手教你为基于Netty的IM生成自签名SSL/TLS证书

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

[摘要] 本文要分享的是如何使用OpenSSL生成在基于Netty的IM中真正可用的SSL/TLS证书,内容包括:证书的创建、创建过程中的注意点,以及在Server端、Android端、iOS端、Java桌面端、H5端使用证书的代码范例。


[- 15 -] 微信技术分享:揭秘微信后台安全特征数据仓库的架构设计

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

[摘要] 本文将介绍微信的安全数据特征仓库的背景起源、技术演进、当前的架构设计和实践,以及数据质量保证系统的实现。希望给中大型IM系统的安全数据特征仓库的设计带来启发。


👉52im社区本周新文:《微信团队分享:详解iOS版微信视频号直播中因帧率异常导致的功耗问题》,欢迎阅读!👈

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

posted @ 2023-11-15 10:51 Jack Jiang 阅读(61) | 评论 (0)编辑 收藏

本文由小红书基础架构存储组空洞和刘备分享,原题“小红书如何应对万亿级社交网络关系挑战?图存储系统 REDtao 来了!”,本文有修订和改动。

1、引言

小红书是一个社区属性为主的产品,它涵盖了各个领域的生活社区,并存储海量的社交网络关系。

为了解决社交场景下超大规模数据的更新与关联读取问题,并减少数据库压力和成本,我们自研了面向超大规模社交网络的图存储系统 REDtao,大大提高了系统稳定性。该系统借鉴了 Facebook 的图存储系统设计,将缓存和底层数据库封装起来,并对外提供统一的图查询 API,实现了访问收敛,同时在缓存中实现了高效的边聚合。

本文将为你分享小红书面向超大规模社交网络的图存储系统REDtao的架构设计与技术实践过程,希望能带给你启发。

 
 
技术交流:

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

2、关于作者

空洞:小红书基础架构存储组,负责图存储系统 REDtao 和分布式缓存的研发。

刘备:小红书基础架构存储组负责人,负责REDkv / REDtao / REDtable / REDgraph 的整体架构和技术演进。

基础架构存储组是给小红书的业务部门提供稳定可靠的存储和数据库服务,满足业务对存储产品的功能、性能、成本和稳定性要求。目前负责自研分布式 KV、分布式缓存、图存储系统、图数据库和表格存储。

已上线的存储产品包括:

  • 1)REDkv : 分布式高性能 KV;
  • 2)REDtao :满足一跳查询的高性能图存储数据库;
  • 3) REDtable :提供 Schema 语义和二级索引的表格存储;
  • 4) REDgraph :提供两跳及以上的图语义查询数据库。

3、技术背景

小红书是以年轻人为主的生活记录、分享平台,用户可以通过短视频、图文等形式记录生活点滴,分享生活方式。

在小红书的社交领域里,我们有用户、笔记、商品等实体,这些实体之间有各种各样的关系。

例如:用户与笔记之间可能存在“拥有”(发布)、“点赞”、“收藏”等三种关系,同时还存在对应的反向关系“被点赞”,“被收藏”等。

小红书的社交图谱数据已经达到了万亿条边的规模,且增长速度非常快。当用户登陆小红书时,每个用户都会看到关注的好友、粉丝、点赞、收藏以及其他为其量身定做的内容。

这些信息高度个性化,需要实时从这些海量社交关系数据中读取用户相关信息。这是一个读为主的过程,读取压力非常大。

过去,我们将这些社交图谱数据都存储在运维成熟的 MySQL 数据库中。

然而,即使我们只有百万请求每秒的规模,MySQL 的 CPU 使用率仍然到达了 55% 。随着用户和 DAU 爆发式的增长,需要不断扩容 MySQL 数据库,这带来了巨大的成本和稳定性压力。

为了解决这些问题且考虑到没有合适的开源方案,2021 年初我们开启了从 0 到 1 自研 REDtao 的历程。

4、方案调研和API设计

4.1方案调研

我们充分调研了业内其他厂商的实现,发现有着强社交属性的公司基本上都有一个自研的图存储系统(如下图所示)。

比如:

  • 1)Facebook 实现了一个叫做 “TAO” 专门的分布式社交图谱数据库,并将其作为最核心的存储系统;
  • 2)Pinterest 和 Facebook 类似,也实现了类似的图存储系统;
  • 3)字节跳动自研了 ByteGraph 并将其用于存储核心的社交图谱数据;
  • 4)Linkedln 在 KV 之上构建了社交图谱服务。

考虑到当时我们的社交图谱数据已经存放在 MySQL 数据库上且规模巨大,而社交图谱数据服务是非常重要的服务,对稳定性的要求非常高。回溯 Facebook 当年遇到的问题和我们类似,数据存储在 Memcache 和 MySQL 中。因此,参考 Facebook 的 Tao 图存储系统更贴合我们的实际情况和已有的技术架构,风险更小。

4.2API设计

社交图谱的访问主要是边的关系查询。

我们的图模型将关系表示为一个 <key, value> 对,其中 key 是 ( FromId,  AssocType,  ToId ) 的三元组,value 是属性的  JSON 格式。

比如“用户 A ”关注“用户 B ”,映射到 REDtao 的数据存储结构为:

1<FromId:用户A的ID, AssocType:关注, ToId:用户B的ID>  ->  Value (属性的json字段)

我们对业务方的需求进行分析,封装了 25 个图语义的 API 给业务方使用,满足了其增删改查的需求,并收敛业务方的使用方式。

相比于 Facebook 的 Tao,我们还补充了社交图谱所需要的图语义,为反作弊场景提供了额外的过滤参数。

同时,在缓存层面,我们支持对不同的字段在缓存中配置局部二级索引。

下面给一些典型的使用场景。

1)场景一:获取关注了 A 的所有正常用户(并且剔除作弊用户):

1getAssocs(“被关注类型”, 用户A的ID, 分页偏移量, 最大返回值, 只返回正常用户,是否按照时间从新到旧)

2)场景二:获取 A 的粉丝个数(并且剔除作弊用户):

1getAssocCount(“被关注类型”, 用户A的ID, 只返回正常用户)

5、整体架构设计

REDtao 的架构设计考虑了下面这几个关键的要素:

整体架构分为三层:

  • 1)接入层;
  • 2)缓存层;
  • 3)持久层。

业务方通过 REDtao SDK 接入服务。

如下图:

在这个架构中:和 Facebook Tao 不一样的是,我们的缓存层是一个独立的分布式集群,和下面的持久层是解耦的。缓存层和下面的持久层可以独立的扩容缩容,缓存分片和 MySQL 分片不需要一一对应,这样带来了更好的灵活性,MySQL 集群也变成了一个可以插拔替换的持久存储。

1)读流程:客户端将读请求发送给 router,router 接收到 RPC 请求后,根据边类型选择对应的 REDtao 集群,根据三元组 ( FromId,  AssocType,  ToId ) 通过一致性 Hash 计算出分片所在的 Follower 节点,将请求转发到该节点上。Follower 节点接收到该请求,首先查询本地的图缓存,如果命中则直接返回结果。如果没有命中,则将请求转发给 Leader 节点。同样的,Leader 节点如果命中则返回,如果不命中则查询底层 MySQL 数据库。

2)写流程:客户端将写请求发送给 router,和读流程一样,会转发到对应的 Follower 节点上。Follower 节点会转发写请求给 Leader 节点,Leader 节点转发给 MySQL,当 MySQL 返回写入成功后,Leader 会清除本地图缓存对应的 Key,并同步给其他所有 Follower 清除掉该 Key,保证数据的最终一致性。

6、高可用设计

REDtao 分为独立的两层:缓存层和持久层。每一层都保证高可用性。

1)自研的分布式缓存:

我们自研了实现图语义的分布式 cache 集群,支持故障自动检测和恢复、水平扩缩容。

它是一个双层 cache,每个分片都有一个 Leader 和若干个 Follower。所有的请求都先发给外层的 Follower,再由 Follower 转发给 Leader。这样的好处是读压力大的时候只需要水平扩展 Follower,单点 Leader 写入的方式也降低了复杂度,更容易实现数据的一致性。

如果一个副本故障,系统会在秒级别内进行切换。当持久层发生故障时,分布式缓存层仍然可以对外提供读取服务。

2)高可用的MySQL集群:

MySQL 集群通过自研的中间件实现了分库分表方案,并支持 MySQL 的水平扩容。每个 MySQL 数据库有若干从库,并且与公司内部其他的 MySQL 运维方案一致,保证高可用性。

3)限流保护功能:

为防止缓存击穿导致 MySQL 突发大量请求,从而导致 MySQL 宕机,我们通过限制每个主节点最大 MySQL 并发请求数来实现限流保护 MySQL。达到最大并发请求限制之后的请求会被挂起等待,直到已有请求被处理返回,或者达到等待超时请求被拒绝不会被继续请求到 MySQL 。限流阈值在线可调,根据 MySQL 集群规模调整对应限制。

为防止爬虫或者作弊用户频繁刷同一条数据,我们利用 REDtaoQueue 顺序执行对写入或者点查同一条边的请求,队列长度会被限制,控制同一时间大量相同的请求执行。相比于单个全局的队列控制所有请求的方式,基于每个请求的队列可以很好地限制单个同一请求,而不影响其他正常请求。

7、高性能设计

数据结构的设计是 REDtao 高性能的重要保证。

我们采用了三层嵌套 HashTable 的设计, 通过根据某个起点 from_id 从第一级 HashTable 中查找到 REDtaoGraph,记录了所有 type 下对应的所有的出边信息。

接着,在第二级 HashTable 中,根据某个 type_id 查找到 AssocType 对应某个 type 下边所有出边的计数、索引以及其他元数据。

最终在最后一级 HashTable ,通过 AssocType 的某个 to_id 查找到最终边信息。

我们记录了创建时间、更新时间、版本、数据以及 REDtaoQueue,time_index 则对应根据创建时间排序列表。

最后一级 HashTable 以及索引限制存储最新的 1000 个边信息,以限制超级点占据过多内存,同时集中提高最新热数据的查询命中率以及效率。REDtaoQueue 用于排队当前某个关系的读写,只记录了当前最后一个请求的元数据。

每次查询或写入时,首先查询 REDtaoAssoc:

  • 1)若缓存不存在,则会首先创建只包含 REDtaoQueue 的对象;
  • 2)若缓存已存在,则会更新队列元数据,将自己设置为队列的最后一个请求,并挂起等待被执行。

通过这种多层 hash+ 跳表的设计,我们能高效地组织点、边、索引、时间序链表之间的关系。内存的申请、释放在同一个线程上完成。

在线上环境中,我们的系统可以在一台 16 核的云厂商虚拟机上跑到 150w 查询请求/s,同时 CPU 利用率仅有 22.5% 。下方是线上集群的一个监控图,单机的 QPS 到达 3w ,每个 RPC 请求聚合了 50 个查询。

 

8、易用性设计

1)丰富的图语义 API :

我们在 REDtao 中封装了 25 个图语义的 API 给业务方使用,满足了业务方的增删改查的需求。业务方无需自行编写 SQL 语句即可实现相应操作,使用方式更加简单和收敛。

2)统一的访问 URL :

由于社区后端数据太大,我们按照不同的服务和优先级拆分成了几个 REDtao 集群。

为了让业务方不感知后端的集群拆分逻辑,我们实现了统一的接入层。

不同的业务方只需使用同一个服务 URL ,通过 SDK 将请求发送到接入层。接入层会接收到不同业务方的图语义的请求,并根据边的类型路由到不同的 REDtao 集群。它通过订阅配置中心,能够实时感知到边的路由关系,从而实现统一的访问 URL,方便业务方使用。

9、数据一致性设计

作为社交图谱数据,数据的一致性至关重要。我们需要严格保证数据的最终一致性以及一定场景下的强一致性。为此,我们采取了以下措施:

1)缓存更新冲突的解决:

REDtao 为每个写入请求生成一个全局递增的唯一版本号。在使用 MySQL 数据更新本地缓存时,需要比较版本号,如果版本号比缓存的数据版本低,则会拒绝此更新请求,以避免冲突。

2)写后读的一致性:

Proxy 会将同一个 fromId 的点或边请求路由到同一个读 cache 节点上,以保证读取数据一致性。

3)主节点异常场景:

Leader 节点收到更新请求后,会将更新请求变为 invalidate cache 请求异步的发送给其他 follower,以保证 follower 上的数据最终一致。在异常情况下,如果 Leader 发送的队列已满导致 invalidate cache 请求丢失,那么会将其他的 follower cache 全部清除掉。

如果 Leader 故障,新选举的 Leader 也会通知其他 follower 将 cache 清除。

此外,Leader 会对访问 MySQL 的请求进行限流,从而保证即使个别分片的cache被清除掉也不会将 MySQL 打崩。

4)少量强一致的请求:

由于 MySQL 的从库也提供读服务,对于少量要求强一致的读请求,客户端可以将请求染上特殊标志,REDtao 会透传该标志,数据库 Proxy 层会根据该标志将读请求转发到 MySQL 主库上,从而保证数据的强一致。

10、 跨云多活设计

跨云多活是公司的重要战略,也是 REDtao 支持的一个重要特性。

REDtao 的跨云多活架构整体如下:

这里不同于 Facebook Tao 的跨云多活实现,Facebook Tao 的跨云多活实现如下图所示。

Facebook 的方案依赖于底层的 MySQL 的主从复制都通过 DTS Replication 来做。而 MySQL 原生的主从复制是自身功能,DTS 服务并不包含 MySQL 的主从复制。该方案需要对 MySQL 和 DTS 做一定的改造。前面说到,我们的缓存和持久层是解藕的,在架构上不一样。

因此,REDtao 的跨云多活架构是我们结合自身场景下的设计,它在不改动现有 MySQL 功能的前提下实现了跨云多活功能。

1)持久层我们通过 MySQL 原生的主从 binlog 同步将数据复制到其他云的从库上。其他云上的写请求和少量要求强一致读将被转发到主库上。正常的读请求将读取本区的 MySQL 数据库,满足读请求对时延的要求。

2)缓存层的数据一致性是通过 MySQL DTS 订阅服务实现的,将 binlog 转换为 invalidate cache 请求,以清理掉本区 REDtao cache 层的 stale 数据。由于读请求会随机读取本区的任何一个 MySQL 数据库,因此 DTS 订阅使用了一个延迟订阅的功能,保证从 binlog 同步最慢的节点中读取日志,避免 DTS 的 invalidate cache 请求和本区 read cache miss 的请求发生冲突从而导致数据不一致。

11、云原生实现

REDtao 的云原生特性重点体现在弹性伸缩、支持多 AZ 和 Region 数据分布、产品可以实现在不同的云厂商间迁移等几个方面。REDtao 在设计之初就考虑到支持弹性扩缩容、故障自动检测及恢复。

随着 Kubernetes 云原生技术越来越成熟,我们也在思考如何利用 k8s 的能力将部署和虚拟机解绑,进一步云原生化,方便在不同的云厂商之间部署和迁移。

REDtao 实现了一个运行在 Kubernetes 集群上的 Operator,以实现更快的部署、扩容和坏机替换。

为了让 k8s 能感知集群分片的分配并且控制同一分片下的 Pods 调度在不同宿主机上,集群分组分片分配由 k8s Operator 渲染并控制创建 DuplicateSet (小红书自研 k8s 资源对象)。

REDtao 则会创建主从并根据 Operator 渲染出来的分片信息创建集群,单个 Pod 故障重启会重新加入集群,无需重新创建整个集群。集群升级时,Operator 通过感知主从分配控制先从后主的顺序,按照分片分配的顺序滚动升级以减少升级期间线上影响。

12、老服务的平滑升级实践

但凡变革,皆属不易。实现全新的 REDtao 只是完成了相对容易的那部分工作。

小红书的社交图谱数据服务已经在 MySQL 上运行多年,有很多不同的业务跑在上面,任何小的问题都会影响到小红书的在线用户。因此,如何保证不停服的情况下让现有业务无感知地迁移到 REDtao 上成为一个非常大的挑战。

我们的迁移工作关键有两点:

1)将老的大 MySQL 集群按优先级拆分成了四个 REDtao 集群。这样,我们可以先将优先级最低的服务迁移到一个 REDtao 集群,充分灰度后再迁移高优先级的集群;

2)专门开发了一个 Tao Proxy SDK,支持对原来的 MySQL 集群和 REDtao 集群进行双写双读,数据校验比对。

迁移时:我们首先将低优先级的数据从 MySQL 通过 DTS 服务迁移到了一个 REDtao 集群,并升级好业务方的 SDK 。DTS 服务一直对增量数据进行同步。业务方 SDK 会订阅配置中心的配置变更,我们修改配置让 Tao Proxy SDK 同时读写 MySQL 集群和 REDtao 集群,并关闭 DTS 服务。此时会使用 MySQL 集群的结果返回给用户。

在停止 DTS 服务时:有可能会有新的 MySQL 数据通过 DTS 同步过来,造成了 REDtao 集群新写的数据被同步过来的老数据覆盖。因此,在关闭 DTS 服务后,我们会通过工具读取开双写之后到关闭 DTS 服务这个时间段的 binlog 对数据进行校验和修复。

修复完成之后:Tao Proxy SDK 的双读会展示两边不一致的数据量,并过滤掉因为双写时延不一致导致数据不一致的请求。灰度一段时间后观察到 diff 的数目基本为 0,将 Tao Proxy SDK 的配置改为只读写新的 REDtao 集群。

最终:我们在 22 年初完成小红书所有核心社交图谱万亿边级别数据的迁移和正确性校验,并做到了整个迁移服务无感知,迁移过程没有发生一起故障。

13、新图存储系统带来的结果和收益

我们的社交图谱数据访问中,90% 以上的请求都是读请求,并且社交图谱的数据有非常强的时间局部性(即最近更新的数据最容易被访问)。REDtao 上线后,获得 90% 以上的 cache 命中率, 对MySQL 的 QPS 降低了 70%+ ,大大降低了 MySQL 的 CPU 使用率。在缩容 MySQL 的副本数目后,整体成本降低了21.3%。‍

业务的访问方式都全部收敛到 REDtao 提供的 API 接口上,在迁移过程中,我们还治理了一些老的不合理访问 MySQL 数据库的方式,以及自定义某些字段赋予特殊含义的不合理做法,通过 REDtao 规范了数据访问。

对比 2022 年初和 2023 年初,随着 DAU 的增长,社交图谱的请求增长了 250% 以上,如果是之前 MySQL 的老架构,扩容资源基本上和请求增长速度成正比,至少需要扩容 1 倍的资源成本(数万核)。

而得益于 REDtao 系统的存在,因其 90% 的缓存命中率,实际上整体成本只增加了 14.7%(数千核)就能扛下 2.5 倍的请求增长。在成本和稳定性上有了较大的提升。

14、未来展望

在较短的时间,我们自研了图存储系统 REDtao ,解决了社交图谱关系数据快速增长的问题。

REDtao 借鉴了 FaceBook Tao 的论文,并对整体架构、跨云多活做了较多的改进,全新实现了一个高性能的分布式图缓存,更加贴合我们自身的业务特点和提供了更好的弹性。同时,利用 k8s 能力进一步实现了云原生化。

随着 DAU 的持续增长,万亿的数据规模也在继续增长,我们也面临着更多的技术挑战。

目前公司内部的 OLTP 图场景主要分为三块:

1)社交图谱数据服务:通过自研图存储系统 REDtao 满足了社交场景超大规模数据的更新与关联读取问题。目前已经存储了万亿规模的关系;

2)风控场景:通过自研图数据库 REDgraph,满足多跳的实时在线查询。目前存储了千亿点和边的关系,满足 2 跳以及 2 跳以上的查询;

3)社交推荐:这块主要是两跳的查询。每天通过 Hive 批量地导入全量的数据,通过 DTS 服务近实时的写入更新数据。因为是在线场景,对时延的要求非常高,当前的 REDgraph 还无法满足这么高的要求,因此业务方主要是用 REDkv 来存储。

针对以上场景:为了快速满足业务需求,我们使用了三套不同的自研存储系统:REDtao 、REDgraph 和 REDkv 。

显然相对于 3 套存储系统,用一个统一的架构和系统去解决这几个图相关的场景是更加合适的。

未来:我们会将 REDgraph 和 REDtao 融合成一个统一的数据库产品,打造业内顶尖的图技术,对公司内部更多的场景进行赋能。

15、相关资料

[1] 以微博类应用场景为例,总结海量社交系统的架构设计步骤

[2] 腾讯技术分享:社交网络图片的带宽压缩技术演进之路

[3] 基于社交网络的Yelp是如何实现海量用户图片的无损压缩的?

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

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

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

[7] 渐行渐远的人人网:十年亲历者的互联网社交产品复盘和反思

[8] 中国互联网社交二十年:全民见证的互联网创业演义

[9] 盘点移动互联网时代的社交产品进化史(上篇):谁主沉浮

[10] 盘点移动互联网时代的社交产品进化史(下篇):大浪淘沙


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

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

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

[- 1 -] 即时通讯安全篇(一):正确地理解和使用Android端加密算法

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

[摘要] 本文主要讨论针对Android这样的移动端应用开发时,如何正确的理解目前常用的加密算法,为诸如即时通讯应用的实战开发,如何在合适的场景下选择适合的算法,提供一些参考。


[- 2 -] 即时通讯安全篇(二):探讨组合加密算法在IM中的应用

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

[摘要] 本文深入分析了即时通信(IM)系统中所面临的各种安全问题,综合利用对称加密算法(DES算法)、公开密钥算法(RSA算法)和Hash算法(MD5)的优点,探讨组合加密算法在即时通信中的应用。


[- 3 -] 即时通讯安全篇(三):常用加解密算法与通讯安全讲解

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

[摘要] 本次着重整理了常见的通讯安全问题和加解密算法知识与即时通讯(IM)开发同行们一起分享和学习。


[- 4 -] 即时通讯安全篇(四):实例分析Android中密钥硬编码的风险

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

[摘要] 本文主要借用乌云上已公布的几个APP漏洞来讲讲这其中的潜在风险和危害。


[- 5 -] 即时通讯安全篇(五):对称加密技术在Android平台上的应用实践

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

[摘要] 本文将重点分享对称加解密技术在Android平台上的实践应用。对于即时通讯社区里的IM、推送技术的开发者同行而言,是不可多得的第一手实践资料,希望对你有用。


[- 6 -] 即时通讯安全篇(六):非对称加密技术的原理与应用实践

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

[摘要] 本文将要分享的是非对称加密技术在当前互联网场景下的应用情况。


[- 7 -] 即时通讯安全篇(七):用JWT技术解决IM系统Socket长连接的身份认证痛点

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

[摘要] 本次分享正是基于此次解决Socket长连接身份安全认证的实践总结而来,方案可能并不完美,但愿能起到抛砖引玉的作用,希望能给您的IM系统开发带来启发。


[- 8 -]  即时通讯安全篇(八):你知道,HTTPS用的是对称加密还是非对称加密?

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

[摘要] 本文将带你了解HTTPS到底用的是对称加密还是非对称加密,以及具体又是怎么使用的。


[- 9 -] 即时通讯安全篇(九):为什么要用HTTPS?深入浅出,探密短连接的安全性

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

[摘要] 今天就借此机会,跟大家一起深入学习一下HTTPS的相关知识,包括HTTP的发展历程、HTTP遇到的问题、对称与非对称加密算法、数字签名、第三方证书颁发机构等概念。


[- 10 -] 即时通讯安全篇(十):IM聊天系统安全手段之通信连接层加密技术

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

[摘要] 本篇文章将围绕IM通信连接层的安全问题及实现方案,聚焦IM网络“链路安全”,希望能带给你启发 。


[- 11 -] 即时通讯安全篇(十一):IM聊天系统安全手段之传输内容端到端加密技术

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

[摘要] 本篇将围绕IM传输内容的安全问题,以实践为基础,为你分享即时通讯应用中的“端到端”加密技术。


[- 12 -] 传输层安全协议SSL/TLS的Java平台实现简介和Demo演示

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

[摘要] 本文将简要介绍Java平台的SSL/TLS实现并以Demo示例的方式予以讲解。


[- 13 -] 理论联系实际:一套典型的IM通信协议设计详解(含安全层设计)

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

[摘要] 本文将以理论联系实际的方式,详细讲解一套典型IM的通信协议设计的方方面面。


👉52im社区本周新文:《小红书万亿级社交网络关系下的图存储系统的架构设计与实践http://www.52im.net/thread-4495-1-1.html》,欢迎阅读!👈

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

posted @ 2023-11-06 13:45 Jack Jiang 阅读(49) | 评论 (0)编辑 收藏

     摘要: 本文由得物技术WWQ分享,原题“客服发送一条消息背后的技术和思”,本文有修订和改动。1、引言在企业IM客服场景中,客服发送一条消息的背后,需要考虑网络通信、前端展示、后端存储以及安全性等多个方面的技术支持。单从前端层面来说,就需要考虑到消息的显示、状态更新、稳定传输以及极限操作消息不卡顿等场景。随着IM系统的不断更新迭代,已经实现了从外采到自研再到一站式全场景工作台的搭建,...  阅读全文

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

关于MobileIMSDK

MobileIMSDK 是一套专门为移动端开发的开源IM即时通讯框架,超轻量级、高度提炼,一套API优雅支持 UDP 、TCP 、WebSocket 三种协议,支持 iOS、Android、H5、标准Java、小程序、Uniapp,服务端基于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 实现)。


v8.0 版更新内容

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

  • 1)[新增] 新增了“群名片”功能;
  • 2)[新增] 新增了消息转发功能;
  • 3)[新增] 安全提升,启用了AppKey校验机制;
  • 4)[优化] 安全提升,优化了http接口、文件上传接口、socket长连接的token校验逻辑;
  • 5)[优化] 更换了新的高德地图websevice key;
  • 6)[优化] 其它ui细节和bug优化等。

此版新增功能运行截图(更多截图点此查看):

posted @ 2023-11-01 11:46 Jack Jiang 阅读(56) | 评论 (0)编辑 收藏

     摘要: 本文由序员先生分享,原题“技术解读企业微信之四维关系链”,本文有修订和改动。1、引言3年疫情后的中国社会,最大的永久性变化之一,就是大多数的企业、教育机构或者政务机构,都用上了综合性的SaaS在线办公系统。而这其中,企业微信的覆盖率非常高,而且其占比还在不断增长。越来越多的人因此好奇,开始想要更深度的了解企业微信,自然也就有越来越多的人开始解读企业微信。而解读的角度,五花八...  阅读全文

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

     摘要: 本文由大淘宝终端平台技术团队沈良炜(沛轩)分享,本文有修订和改动。1、引言自 2013 年 ALLIN 无线到今天,已经走过 10 个年头,淘宝终端统一网络库 AWCN (Ali Wireless Connection Network) 从淘内孵化,一路过来伴随着淘宝业务的发展,经历集团 IPv6 战役、协议升级演进等,逐步沉淀为阿里集团终端网络通用解决方案,是兼具高性能、多协议、可容灾、可观测的...  阅读全文

posted @ 2023-10-19 14:10 Jack Jiang 阅读(126) | 评论 (0)编辑 收藏

本文由百度技术王伟分享,原题“视频中为什么需要这么多的颜色空间?”,本文收录时有修订和改动。

1、引言

在视频处理中,我们经常会用到不同的色彩空间:非线性RGB,线性 RGB,YUV,XYZ……为什么需要这么多的色彩空间呢?为什么在 FFMpeg 中会有 color_space,color_transfer,color_primaries 等一系列的颜色属性呢?这些术语之间究竟隐藏着什么秘密?

本文将以通俗易懂的文字,引导你理解视频是如何从采集开始,历经各种步骤,最终通过颜色模型转换和不同的色域转换,让你看到赏心悦目的视频结果的。

 
 
技术交流:

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

2、系列文章

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

即时通讯音视频开发(一):视频编解码之理论概述

即时通讯音视频开发(二):视频编解码之数字视频介绍

即时通讯音视频开发(三):视频编解码之编码基础

即时通讯音视频开发(四):视频编解码之预测技术介绍

即时通讯音视频开发(五):认识主流视频编码技术H.264

即时通讯音视频开发(六):如何开始音频编解码技术的学习

即时通讯音视频开发(七):音频基础及编码原理入门

即时通讯音视频开发(八):常见的实时语音通讯编码标准

即时通讯音视频开发(九):实时语音通讯的回音及回音消除概述

即时通讯音视频开发(十):实时语音通讯的回音消除技术详解

即时通讯音视频开发(十一):实时语音通讯丢包补偿技术详解

即时通讯音视频开发(十二):多人实时音视频聊天架构探讨

即时通讯音视频开发(十三):实时视频编码H.264的特点与优势

即时通讯音视频开发(十四):实时音视频数据传输协议介绍

即时通讯音视频开发(十五):聊聊P2P与实时音视频的应用情况

即时通讯音视频开发(十六):移动端实时音视频开发的几个建议

即时通讯音视频开发(十七):视频编码H.264、V8的前世今生

即时通讯音视频开发(十八):详解音频编解码的原理、演进和应用选型

即时通讯音视频开发(十九):零基础,史上最通俗视频编码技术入门

即时通讯音视频开发(二十):一文读懂视频的颜色模型转换和色域转换》(* 本文

3、视频采集

如上图所示,在相机系统中,外部世界的光信息(光子,photons)通过透镜或其他光学器件聚焦之后达到相机的图像传感器(CCD 或者 CMOS)。

过程是这样的:

  • 1)图像传感器可以将一个入射光子(photon)转换为对应的一个电子(electron);
  • 2)在曝光时间内,图像传感器对转换的电子进行电荷积累;
  • 3)然后,图像传感器会将积累的电荷信号转换成对应的电压信号;
  • 4)最后,利用 ADC 把电信号转换成数字信号,而转换后的数字信号则为某个范围内的整数值。

ADC 数字信号的取值范围 :

[pquote]ADC 转换之后的数字信号的取值范围受限于 ADC 设备。对于 8-bits 的 ADC 而言,数字信号的取值范围为 [0, 2^8-1],因此,对于每一个像素而言,会用 [0, 255] 之间的整数来进行编码。[/pquote]

ADC 转换的数字信号的数值是一个线性编码的过程,这意味着如果将图像传感器上的光量增加 1 倍,则 ADC 转换之后对应的数值也会增加 1 倍。

这是一个非常有用的特性:无论是增加物理世界的光量,还是增加 ADC 转换之后的数值,对图片而言,都会带来相同的效果。线性编码意味着我们所处理的数据和光发射的强度成正比关系。

由数码相机中的 CMOS 传感器产生并写入原始文件(Raw File)的数据是线性的。与普通照片相比,线性数据通常看起来非常暗且对比度较低。

在 iPhone 手机中,可以通过设置相机来拍摄 Apple ProRAW 格式的照片。

4、探索视频伽马校正

研究表明:人类视觉系统是以对数函数的方式来感知光亮度。这意味着:人眼会提高暗部的敏感度,降低高光部分的敏感度。

从数学角度看,感知光强度和测量光强度之间存在一个*似的*方关系,具体如下式所示。

由于人类视觉感知系统不是以线性方式工作的,因此必须使用非线性曲线来对 ADC 生成的的线性数据进行变换,从而使得拍摄的图像色调与我们的视觉系统的工作方式相匹配。这个过程也就是我们所说的 伽马校正。

因此:在从线性 RGB 空间转换到非线性 RGB 空间时,需要 γ 作为转换参数。相机中的 ISP 模块负责对图像传感器的线性 RGB 进行伽马校正进而产生对应的符合人眼感知的非线性 RGB 数据。

RGB 的设备依赖性 :

不同显示设备支持的色域空间不同,因此对于不同的显示设备而言,伽马校正之后的 RGB 数值也不同。从这个角度讲,RGB 是设备依赖型的色彩空间。

5、视频压缩

根据如上的信息,我们知道:相机系统经过 ISP 处理之后,最终会得到非线性的 RGB 信息。对于视频而言,如果以 RGB 存储每帧的信息,则需要消耗大量的存储空间。

人类视觉系统对颜色信息的敏感度要弱于亮度信息。利用这一特点,通常相机会将捕获的 RGB 信息转换为 YUV 格式,然后对 YUV 格式进行色度信息采样(例如,YUV420)以便压缩图像空间。

RGB->YUV,不同标准有不同要求,一般常用的标准有:

  • 1)BT. 601(SD: Standard-Definition);
  • 2)BT. 709(HD: High-Definition);
  • 3)BT. 2020(UHD: Ultra-High-Definition)。

注意 :

标准中,不但会规定 RGB->YUV 的转换系数,同时还会规定从线性 RGB 到非线性 RGB 转换的 gamma 系数。

将 RGB颜色模型,转换成 YUV 模型后,接下来会采用某种视频编解码算法(例如,H265, VP9)对获取的数据进行视频编码,最终得到视频文件(此处忽略了音频的采集编码以及合流的操作)。

6、视频转码

出于各种原因,例如:

  • 1)终端用户的带宽受限;
  • 2)终端用户支持的视频编解码算法和相机压缩视频的编解码算法不一致;
  • 3)……

一般不会直接把相机产出的视频文件分发给用户去消费。媒体服务商会对相机生成的视频文件进行转码,然后选择合适的转码后的视频分发给终端消费用户。

在视频转码阶段,如果我们希望对原视频进行色域的变换,例如从 BT. 601 转码为 BT. 709,则需要在不同色域的 RGB 数值之间进行转换。

在不同的色域空间进行 RGB 数据的转换,这也就是我们所说的 色彩管理。色彩管理会对图像进行色彩管理以适配当前环境下的颜色效果,从而保证同一张图片在不同输入、输出上都呈现出最好的颜色。

色彩转换需要在某个线性空间下进行操作,并且操作过程需要保持设备的独立性。因此,不同的 RGB 色域空间是不能直接进行转换的,需要一个设备无关、线性的颜色模型作为中转才能实现其转换。

而 XYZ(CIE 1931 XYZ color space)具备设备无关、线性操作的特性。

在 FFMpeg 中,主要使用 colorspace 滤镜 来完成不同色域空间的转换。

根据 colorspace 的实现可知,在 FFMpeg 中,BT. 601->BT. 709 的转换过程如下所示:

在如上的变换中,涉及到 3 个颜色空间的转换,分别是:

  • 1)YUV 和 RGB 之间的转换;
  • 2)线性 RGB 和非线性 RGB 之间的转换;
  • 3)线性 RGB 和 XYZ 之间的转换。

在 FFMpeg 中,所有的这些转换参数都保存在 AVFrame 结构中:

  • 1)AVFrame->colorspace 中保存了 YUV/RGB 的转换矩阵;
  • 2)AVFrame->color_trc 中保存了线性 RGB 和非线性 RGB 之间的转换函数(transformation characteristics);
  • 3)AVFrame->color_primaries 中保存了 RGB/XYZ 的转换矩阵;

如果用 ffprobe 命令解析视频文件,则:

  • 1)color_space 字段对应 YUV/RGB 的转换矩阵;
  • 2)color_transfer 字段对应线性 RGB 和非线性 RGB 之间的转换函数;
  • 3)color_primaries 字段对应 RGB/XYZ 的转换矩阵。

$ ffprobe -select_streams v:0 -show_entries stream=color_space,color_transfer,color_primaries test.mp4

 

[STREAM]

color_space=bt2020nc

color_transfer=arib-std-b67

color_primaries=bt2020

[/STREAM]

在如上的例子中,arib-std-b67 也就是我们所熟悉的 HLG。

在 MediaInfo 中:

  • 1)Matrix coefficients 字段对应 YUV/RGB 的转换矩阵;
  • 2)Transfer characteristic 字段对应线性 RGB 和非线性 RGB 之间的转换函数;
  • 3)Color primaries 字段对应 RGB/XYZ 的转换矩阵。

除了如上的参数外,AVFrame->range 还用来存储视频中对应像素的每个分量的取值范围。

在 vf_setparams.c 中也作了相关的定义说明:

{"limited", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG},  0, 0, FLAGS, "range"},

{"tv",      NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG},  0, 0, FLAGS, "range"},

{"mpeg",    NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG},  0, 0, FLAGS, "range"},

{"full",    NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG},  0, 0, FLAGS, "range"},

{"pc",      NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG},  0, 0, FLAGS, "range"},

{"jpeg",    NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG},  0, 0, FLAGS, "range"},

7、视频解码&播放

7.1基本

转码之后的视频,可以通过各种渠道分发到终端用户进行消费。

对于大部分显示设备,例如CRT显示器、LCD、OLED,屏幕上的每个像素都是通过驱动三个非常靠*但仍然分开的小型 RGB 光源而构建的。

因此:显示屏(监视器、电视机、屏幕等等)仅使用 RGB 模型,并以不同的方式来组织,并显示最终的图像。

如前所述:不同的显示设备采用的 RGB 的色域并不一定相同,因此,RGB 是一种设备依赖型的颜色模型。在 Mac 电脑上,可以通过显示器配置来选择显示器支持不同的 RGB 色域。

7.2显示设备和相机的色域一致

如果编码视频和播放视频的显示器采用的 RGB 色域是一致的,比如都是 sRGB,此时的播放过程相对比较简单。

视频解码之后:得到 YUV 数据,然后根据标准将 YUV 数据转换成非线性的 sRGB 数据,然后显示器根据 sRGB 数据显示图像即可。

7.3显示设备和相机的色域不一致

当显示设备支持的色域从 sRGB 变为 Rec. 2020 时,如果直接显示 sRGB 色域下的数据,则会导致比较严重的颜色失真。

和转码阶段的色域转换类似,此时,也需要在不同的色域空间进行 RGB 数据的转换(色彩管理)以保证相同的视频在不同输入、输出、显示设备上都呈现出最好的颜色。

对于显示设备而言,sRGB->RGB(Rec. 2020)的转换过程如下所示:

因此:对于拍摄设备和显示设备的色域不同时,视频的播放增加了颜色管理的过程。

8、视频观看

虽然视频信息的采集和最终终端播放采用的都是 RGB 的颜色模型,但是对人眼而言,RGB 其实并不直观,比如我们很难马上反应出天青色的 RGB 色值?

为了能够更直观的表示颜色,又引入了 HSL 色彩模型。

HSL 比 RGB 更加直观,比如:想从黄色过度到红色,只需要调整色相即可,饱和度和亮度保持不变。因此,HSL 一般更适合人的色彩感知,而 RGB 更适合显示领域。

为了让作品可以呈现出期望的效果,提升用户的视觉体验,在摄影后期,使用 HSL 对作品进行调整是最方便的一种方式。利用 HSL 对作品进行调整,简单几步就可以让灰暗的「马路随拍」秒变「街头大片」。

FFMpeg 的 signalstats 滤镜可以分析获取视频的色调、饱和度、亮度信息。但是该滤镜获取的色调、饱和度和 HSL 中的计算 是不一致的。

signalstats 计算色调、饱和度的算法如下所示:

如果需要得到视频的标准 HSL 信息,可以使用作者开发的 vf_hsl 滤镜。

9、本文小结

虽然颜色还是那个颜色,但是不同的颜色空间的适用范围并不相同。

具体是:

  • 1)RGB:面向采集和显示设备;
  • 2)YUV:面向存储;
  • 3)HSL:面向人类视觉感知;
  • 4)XYZ:RGB之间的转换桥梁。

从视频采集到视频消费的整个过程,涉及到不同的设备和标准,而不同的设备和标准所支持的色域空间又不相同。

正是通过不同的颜色模型转换和不同的色域转换,才得以让我们实现:在不同输入、输出、显示设备上都呈现出最好的颜色,并以*似相同的观看体验来消费视频。

10、参考文献

[1] CMOS Image Sensor原理简述

[2] 数字视频导论

[3] 用HSL调色=简单、快速、超出片

[4] 零基础入门:实时音视频技术基础知识全面盘点

[5] 实时音视频面视必备:快速掌握11个视频技术相关的基础概念

[6] 轻松诙谐,讲解视频编解码技术的过去、现在和将来

[7] 写给小白的实时音视频技术入门提纲

[8] 福利贴:最全实时音视频开发要用到的开源工程汇总

[9] 详解音频编解码的原理、演进和应用选型

[10] 零基础,史上最通俗视频编码技术入门


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

posted @ 2023-10-12 11:20 Jack Jiang 阅读(56) | 评论 (0)编辑 收藏

一、更新内容简介

本次更新为次要版本更新,进行了若干优化(更新历史详见:码云 Release NotesGithub Release Notes)。MobileIMSDK 可能是市面上唯一同时支持 UDP+TCP+WebSocket 三种协议的同类开源IM框架。

二、MobileIMSDK简介

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

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

MobileIMSDK工程始于2013年10月,历经10年,起初用作某产品的即时通讯底层实现,完全从零开发,技术自主可控!

您可能需要:查看关于MobileIMSDK的详细介绍

三、源码托管同步更新

OsChina.net

GitHub.com

四、MobileIMSDK设计目标

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

五、MobileIMSDK框架组成

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

  1. Android客户端SDK:用于Android版即时通讯客户端,支持Android 2.3及以上,查看API文档
  2. iOS客户端SDK:用于开发iOS版即时通讯客户端,支持iOS 9.0及以上,查看API文档
  3. Java客户端SDK:用于开发跨平台的PC端即时通讯客户端,支持Java 1.6及以上,查看API文档
  4. H5客户端SDK查看精编注释版
  5. 微信小程序端SDK查看精编注释版
  6. Uniapp端SDK查看精编注释版
  7. 服务端SDK:用于开发即时通讯服务端,支持Java 1.7及以上版本,查看API文档

整套MobileIMSDK框架的架构组成:

 另外:MobileIMSDK可与姊妹工程 MobileIMSDK-Web 无缝互通,从而实现Web网页端聊天或推送等。

六、MobileIMSDK v6.4更新内容 

【重要说明】:

MobileIMSDK v6.4 为次要版本,进行了若干优化! 查看详情 (github

【新增重要特性】:

【解决的Bug】:

  • 1. [Uniapp端] 解决了Demo界面右上角的连接状态title无法更新的问题;
  • 2. [服务端] 解决桥接模式下与最新rabbitmq库不兼容从而断线重连不成功,导致MQ中消息堆积的问题。

【其它优化和提升】:

  • 1. [服务端] 解决登陆连接指令中的一处潜在空指针风险;
  • 2. [微信小程序端] 优化自带Demo中聊天主界面flex布局下的中部聊天列表高度自适应能力;
  • 3. [微信小程序端/H5端] 优化了Demo中的CSS代码;
  • 4. [微信小程序端/H5端] 优化了WebSocket的关闭逻辑,确保标准API中的close方法因异步调用带来socket实例被错误重置的问题;
  • 5. [H5端] 为Demo增加了消息送达状态图标的显示(包括发送中、发送成功、发送失败3种状态);
  • 6. [H5端] 重新设计了Demo的登录界面;
  • 7. [服务端] 升级amqp-client库至5.x版;
  • 8. [服务端] 解决桥接模式下MQ断线自动恢复时消费者Chennal未主动清理,导致channel越来越多的问题(无消费者与其关联的空channel):
  • 9. [Android] 提升targetSdkVersion至33(即Android 13);
  • 10. [Android] 升级开发工程使之支持最新Android Studio Giraffe和Gradle 8.1.1;

【最新版本源码地址】:

posted @ 2023-10-07 12:27 Jack Jiang 阅读(108) | 评论 (0)编辑 收藏

     摘要: 本文由字节教育-成人与创新前端团队分享,本文有修订和改动。1、引言作为开发人员,工作中我们可能会遇到以下问题:1)可能你知道 JavaScript 中 '😁'.length = 2,但 '👨👩👧👦'.length 呢?2)困惑于 Unicode 和 UTF-8 的关系?3)学计算机时会遇到这样的提问:一个汉字是几个字节?4)读取二进制数据时,为何有大端序小端序的分别?5)为何 UTF-8...  阅读全文

posted @ 2023-09-28 11:20 Jack Jiang 阅读(81) | 评论 (0)编辑 收藏

本文由阮一峰(ruanyifeng.com)分享,本文收录时有内容修订和排版优化。

1、引言

今天中午,我突然想搞清楚 Unicode 和 UTF-8 之间的关系,就开始查资料。

这个问题比我想象的复杂,午饭后一直看到晚上9点,才算初步搞清楚。

下面就是我的总结,主要用来整理自己的思路。我尽量写得通俗易懂,希望能对其他朋友有用。毕竟,字符编码是计算机技术的基石,对于程序员来说尤其重要,字符编码的知识是必须要懂的。

 
技术交流:

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

2、专题目录

本文是“字符编码技术专题”系列文章的第 1 篇,总目录如下:

3、基础知识

计算机中储存的信息都是用二进制数表示的;而我们在屏幕上看到的英文、汉字等字符是二进制数转换之后的结果。通俗的说,按照何种规则将字符存储在计算机中,如'a'用什么表示,称为"编码";反之,将存储在计算机中的二进制数解析显示出来,称为"解码",如同密码学中的加密和解密。在解码过程中,如果使用了错误的解码规则,则导致'a'解析成'b'或者乱码。

字符集(Charset):是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。

字符编码(Character Encoding):是一套法则,使用该法则能够对自然语言的字符的一个集合(如字母表或音节表),与其他东西的一个集合(如号码或电脉冲)进行配对。即在符号集合与数字系统之间建立对应关系,它是信息处理的一项*本技术。通常人们用符号集合(一般情况下就是文字)来表达信息。而以计算机为*础的信息处理系统则是利用元件(硬件)不同状态的组合来存储和处理信息的。元件不同状态的组合能代表数字系统的数字,因此字符编码就是将符号转换为计算机可以接受的数字系统的数,称为数字代码。

常见字符集名称:ASCII字符集、GB2312字符集、BIG5字符集、GB18030字符集、Unicode字符集等。计算机要准确的处理各种字符集文字,需要进行字符编码,以便计算机能够识别和存储各种文字。

4、ASCII 码

我们知道,计算机内部,所有信息最终都是一个二进制值。每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(byte)。也就是说,一个字节一共可以用来表示256种不同的状态,每一个状态对应一个符号,就是256个符号,从00000000到11111111。

上个世纪60年代,美国制定了一套字符编码,对英语字符与二进制位之间的关系,做了统一规定。这被称为 ASCII 码,一直沿用至今。

ASCII 码一共规定了128个字符的编码,比如空格SPACE是32(二进制00100000),大写的字母A是65(二进制01000001)。这128个符号(包括32个不能打印出来的控制符号),只占用了一个字节的后面7位,最前面的一位统一规定为0。

▲ ASCII编码表

5、非 ASCII 编码

英语用128个符号编码就够了,但是用来表示其他语言,128个符号是不够的。比如,在法语中,字母上方有注音符号,它就无法用 ASCII 码表示。于是,一些欧洲国家就决定,利用字节中闲置的最高位编入新的符号。比如,法语中的é的编码为130(二进制10000010)。这样一来,这些欧洲国家使用的编码体系,可以表示最多256个符号。

▲ 扩展ASCII编码表

但是,这里又出现了新的问题。不同的国家有不同的字母,因此,哪怕它们都使用256个符号的编码方式,代表的字母却不一样。比如,130在法语编码中代表了é,在希伯来语编码中却代表了字母Gimel (ג),在俄语编码中又会代表另一个符号。但是不管怎样,所有这些编码方式中,0--127表示的符号是一样的,不一样的只是128--255的这一段。

至于亚洲国家的文字,使用的符号就更多了,汉字就多达10万左右。一个字节只能表示256种符号,肯定是不够的,就必须使用多个字节表达一个符号。比如,简体中文常见的编码方式是 GB2312,使用两个字节表示一个汉字,所以理论上最多可以表示 256 x 256 = 65536 个符号。

中文编码的问题比较复杂,将在文末讨论。这里先了解下,虽然都是用多个字节表示一个符号,但是GB类的汉字编码与后文的 Unicode 和 UTF-8 是毫无关系的。

6、Unicode

正如上一节所说,世界上存在着多种编码方式,同一个二进制数字可以被解释成不同的符号。因此,要想打开一个文本文件,就必须知道它的编码方式,否则用错误的编码方式解读,就会出现乱码。为什么电子邮件常常出现乱码?就是因为发信人和收信人使用的编码方式不一样。

可以想象,如果有一种编码,将世界上所有的符号都纳入其中。每一个符号都给予一个独一无二的编码,那么乱码问题就会消失。这就是 Unicode,就像它的名字都表示的,这是一种所有符号的编码。

Unicode 当然是一个很大的集合,现在的规模可以容纳100多万个符号。每个符号的编码都不一样,比如,U+0639表示阿拉伯字母Ain,U+0041表示英语的大写字母A,U+4E25表示汉字严。具体的符号对应表,可以查询unicode.org,或者专门的汉字对应表

7、Unicode 的问题

需要注意的是,Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。

比如,汉字严的 Unicode 是十六进制数4E25,转换成二进制数足足有15位(100111000100101),也就是说,这个符号的表示至少需要2个字节。表示其他更大的符号,可能需要3个字节或者4个字节,甚至更多。

这里就有两个严重的问题,第一个问题是,如何才能区别 Unicode 和 ASCII ?计算机怎么知道三个字节表示一个符号,而不是分别表示三个符号呢?第二个问题是,我们已经知道,英文字母只用一个字节表示就够了,如果 Unicode 统一规定,每个符号用三个或四个字节表示,那么每个英文字母前都必然有二到三个字节是0,这对于存储来说是极大的浪费,文本文件的大小会因此大出二三倍,这是无法接受的。

它们造成的结果是:1)出现了 Unicode 的多种存储方式,也就是说有许多种不同的二进制格式,可以用来表示 Unicode。2)Unicode 在很长一段时间内无法推广,直到互联网的出现。

8、UTF-8

互联网的普及,强烈要求出现一种统一的编码方式。UTF-8 就是在互联网上使用最广的一种 Unicode 的实现方式。其他实现方式还包括 UTF-16(字符用两个字节或四个字节表示)和 UTF-32(字符用四个字节表示),不过在互联网上*本不用。重复一遍,这里的关系是,UTF-8 是 Unicode 的实现方式之一。

UTF-8 最大的一个特点,就是它是一种变长的编码方式。它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8 的编码规则很简单,只有二条:

  • 1)对于单字节的符号:字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的;
  • 2)对于n字节的符号(n > 1):第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的 Unicode 码。

下表总结了编码规则,字母x表示可用编码的位:

跟据上表,解读 UTF-8 编码非常简单。如果一个字节的第一位是0,则这个字节单独就是一个字符;如果第一位是1,则连续有多少个1,就表示当前字符占用多少个字节。

下面,还是以汉字严为例,演示如何实现 UTF-8 编码。

严的 Unicode 是4E25(100111000100101),根据上表,可以发现4E25处在第三行的范围内(0000 0800 - 0000 FFFF),因此严的 UTF-8 编码需要三个字节,即格式是1110xxxx 10xxxxxx 10xxxxxx。然后,从严的最后一个二进制位开始,依次从后向前填入格式中的x,多出的位补0。这样就得到了,严的 UTF-8 编码是11100100 10111000 10100101,转换成十六进制就是E4B8A5。

9、Unicode 与 UTF-8 之间的转换

通过上一节的例子,可以看到严的 Unicode码 是4E25,UTF-8 编码是E4B8A5,两者是不一样的。它们之间的转换可以通过程序实现。

Windows平台,有一个最简单的转化方法,就是使用内置的记事本小程序notepad.exe。打开文件后,点击文件菜单中的另存为命令,会跳出一个对话框,在最底部有一个编码的下拉条。

里面有四个选项:ANSI,Unicode,Unicode big endian和UTF-8

  • 1)ANSI是默认的编码方式:对于英文文件是ASCII编码,对于简体中文文件是GB2312编码(只针对 Windows 简体中文版,如果是繁体中文版会采用 Big5 码);
  • 2)Unicode编码这里指的是notepad.exe使用的 UCS-2 编码方式:即直接用两个字节存入字符的 Unicode 码,这个选项用的 little endian 格式;
  • 3)Unicode big endian编码与上一个选项相对应:我在下一节会解释 little endian 和 big endian 的涵义;
  • 4)UTF-8编码:也就是上一节谈到的编码方法。

选择完"编码方式"后,点击"保存"按钮,文件的编码方式就立刻转换好了。

10、Little endian 和 Big endian

上一节已经提到,UCS-2 格式可以存储 Unicode 码(码点不超过0xFFFF)。以汉字严为例,Unicode 码是4E25,需要用两个字节存储,一个字节是4E,另一个字节是25。存储的时候,4E在前,25在后,这就是 Big endian 方式;25在前,4E在后,这是 Little endian 方式。

这两个古怪的名称来自英国作家斯威夫特的《格列佛游记》。在该书中,小人国里爆发了内战,战争起因是人们争论,吃鸡蛋时究竟是从大头(Big-endian)敲开还是从小头(Little-endian)敲开。为了这件事情,前后爆发了六次战争,一个皇帝送了命,另一个皇帝丢了王位。

第一个字节在前,就是"大头方式"(Big endian),第二个字节在前就是"小头方式"(Little endian)。

那么很自然的,就会出现一个问题:计算机怎么知道某一个文件到底采用哪一种方式编码?

Unicode 规范定义,每一个文件的最前面分别加入一个表示编码顺序的字符,这个字符的名字叫做"零宽度非换行空格"(zero width no-break space),用FEFF表示。这正好是两个字节,而且FF比FE大1。

如果一个文本文件的头两个字节是FE FF,就表示该文件采用大头方式;如果头两个字节是FF FE,就表示该文件采用小头方式。

11、实例讲解

下面,举一个实例。

打开"记事本"程序notepad.exe,新建一个文本文件,内容就是一个严字,依次采用ANSI,Unicode,Unicode big endian和UTF-8编码方式保存。

然后,用文本编辑软件UltraEdit 中的"十六进制功能",观察该文件的内部编码方式:

  • 1)ANSI:文件的编码就是两个字节D1 CF,这正是严的 GB2312 编码,这也暗示 GB2312 是采用大头方式存储的。
  • 2)Unicode:编码是四个字节FF FE 25 4E,其中FF FE表明是小头方式存储,真正的编码是4E25。
  • 3)Unicode big endian:编码是四个字节FE FF 4E 25,其中FE FF表明是大头方式存储。
  • 4)UTF-8:编码是六个字节EF BB BF E4 B8 A5,前三个字节EF BB BF表示这是UTF-8编码,后三个E4B8A5就是严的具体编码,它的存储顺序与编码顺序是一致的。

UltraEdit下载地址请至官网:https://www.ultraedit.com/

▲ UltraEdit软件

12、最后简要看看中文字符集和编码

12.1GB系列字符集&编码

计算机发明之处及后面很长一段时间,只用应用于美国及西方一些发达国家,ASCII能够很好满足用户的需求。但是当天朝也有了计算机之后,为了显示中文,必须设计一套编码规则用于将汉字转换为计算机可以接受的数字系统的数。

天朝专家把那些127号之后的奇异符号们(即EASCII)取消掉,规定:一个小于127的字符的意义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(他称之为高字节)从0xA1用到 0xF7,后面一个字节(低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了。在这些编码里,还把数学符号、罗马希腊的 字母、日文的假名们都编进去了,连在ASCII里本来就有的数字、标点、字母都统统重新编了两个字节长的编码,这就是常说的"全角"字符,而原来在127号以下的那些就叫"半角"字符了。

上述编码规则就是GB2312。GB2312或GB2312-80是中国国家标准简体中文字符集,全称《信息交换用汉字编码字符集·*本集》,又称GB0,由中国国家标准总局发布,1981年5月1日实施。GB2312编码通行于中国大陆;新加坡等地也采用此编码。中国大陆几乎所有的中文系统和国际化的软件都支持GB2312。GB2312的出现,*本满足了汉字的计算机处理需要,它所收录的汉字已经覆盖中国大陆99.75%的使用频率。对于人名、古汉语等方面出现的罕用字,GB2312不能处理,这导致了后来GBK及GB 18030汉字字符集的出现。下图是GB2312编码的开始部分(由于其非常庞大,只列举开始部分,具体可查看GB2312简体中文编码表)。

▲ GB2312编码表的开始部分

由于GB 2312-80只收录6763个汉字,有不少汉字,如部分在GB 2312-80推出以后才简化的汉字(如"啰"),部分人名用字(如中国前总理***的"*"字),台湾及香港使用的繁体字,日语及朝鲜语汉字等,并未有收录在内。于是厂商微软利用GB 2312-80未使用的编码空间,收录GB 13000.1-93全部字符制定了GBK编码。根据微软资料,GBK是对GB2312-80的扩展,也就是CP936字码表 (Code Page 936)的扩展(之前CP936和GB 2312-80一模一样),最早实现于Windows 95简体中文版。虽然GBK收录GB 13000.1-93的全部字符,但编码方式并不相同。GBK自身并非国家标准,只是曾由国家技术监督局标准化司、电子工业部科技与质量监督司公布为"技术规范指导性文件"。原始GB13000一直未被业界采用,后续国家标准GB18030技术上兼容GBK而非GB13000。

GB 18030,全称:国家标准GB 18030-2005《信息技术 中文编码字符集》,是中华人民共和国现时最新的内码字集,是GB 18030-2000《信息技术 信息交换用汉字编码字符集 *本集的扩充》的修订版。与GB 2312-1980完全兼容,与GBK*本兼容,支持GB 13000及Unicode的全部统一汉字,共收录汉字70244个。

GB 18030主要有以下特点:

  • 与UTF-8相同,采用多字节编码,每个字可以由1个、2个或4个字节组成;
  • 编码空间庞大,最多可定义161万个字符;
  • 支持中国国内少数民族的文字,不需要动用造字区;
  • 汉字收录范围包含繁体汉字以及日韩汉字。

▲ GB18030编码总体结构

本规格的初版使中华人民共和国信息产业部电子工业标准化研究所起草,由国家质量技术监督局于2000年3月17日发布。现行版本为国家质量监督检验总局和中国国家标准化管理委员会于2005年11月8日发布,2006年5月1日实施。此规格为在中国境内所有软件产品支持的强制规格。

12.2BIG5字符集&编码

Big5,又称为大五码或五大码,是使用繁体中文(正体中文)社区中最常用的电脑汉字字符集标准,共收录13,060个汉字。中文码分为内码及交换码两类,Big5属中文内码,知名的中文交换码有CCCII、CNS11643。Big5虽普及于台湾、香港与澳门等繁体中文通行区,但长期以来并非当地的国家标准,而只是业界标准。倚天中文系统、Windows等主要系统的字符集都是以Big5为*准,但厂商又各自增加不同的造字与造字区,派生成多种不同版本。2003年,Big5被收录到CNS11643中文标准交换码的附录当中,取得了较正式的地位。这个最新版本被称为Big5-2003。

Big5码是一套双字节字符集,使用了双八码存储方法,以两个字节来安放一个字。第一个字节称为"高位字节",第二个字节称为"低位字节"。"高位字节"使用了0x81-0xFE,"低位字节"使用了0x40-0x7E,及0xA1-0xFE。

有关Big5的更多技术细节读者可单独深入研究,本文就不赘述了。

13、本文小结

这些字符集和编码的关系很容易让程序员混淆,现在小结一下。

简单来说:Unicode、GBK和Big5码等就是编码的值(也就是术语“字符集”),而UTF-8、UTF-16、UTF32之类就是这个值的表现形式(即术语“编码格式”)。

另外:Unicode、GBK和Big5码等字符集是不兼容的,同一个汉字在这三个字符集里的码值是完全不一样的。如"汉"的Unicode值与gbk就是不一样的,假设Unicode为a040,GBK为b030。以UTF-8为例,UTF-8码完全只针对Unicode来组织的,如果GBK要转UTF-8必须先转Unicode码,再转UTF-8就OK了。

即GBK、GB2312等与UTF8之间都必须通过Unicode编码才能相互转换:

1)GBK、GB2312 --先转--> Unicode --再转--> UTF8

2)UTF8 --先转--> Unicode --再转--> GBK、GB2312

附录:更多IM技术精华文章

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

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

[3] 零*础IM开发入门(二):什么是IM系统的实时性?

[4] 零*础IM开发入门(三):什么是IM系统的可靠性?

[5] 零*础IM开发入门(四):什么是IM系统的消息时序一致性?

[6] 移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”

[7] 移动端IM开发者必读(二):史上最全移动弱网络优化方法总结

[8] 从客户端的角度来谈谈移动端IM的消息可靠性和送达机制

[9] 现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障

[10] 史上最通俗Netty框架入门长文:*本介绍、环境搭建、动手实战

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

[12] IM通讯协议专题学习(一):Protobuf从入门到精通,一篇就够!

[13] 微信新一代通信安全解决方案:*于TLS1.3的MMTLS详解

[14] 探讨组合加密算法在IM中的应用

[15] 从客户端的角度来谈谈移动端IM的消息可靠性和送达机制

[16] IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

[17] 理解IM消息“可靠性”和“一致性”问题,以及解决方案探讨

[18] 融云技术分享:全面揭秘亿级IM消息的可靠投递机制

[19] IM群聊消息如此复杂,如何保证不丢不重?

[20] 零*础IM开发入门(四):什么是IM系统的消息时序一致性?

[21] 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

[22] 如何保证IM实时消息的“时序性”与“一致性”?

[23] 阿里IM技术分享(六):闲鱼亿级IM消息系统的离线推送到达率优化

[24] 微信的海量IM聊天消息序列号生成实践(算法原理篇)

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

[26] 网易云信技术分享:IM中的万人群聊技术方案实践总结

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

[28] 融云IM技术分享:万人群聊消息投递方案的思考和实践

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

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

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

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

[33] 阿里IM技术分享(九):深度揭密RocketMQ在钉钉IM系统中的应用实践

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

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

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

[37] 跟着源码学IM(十):*于Netty,搭建高性能IM集群(含技术思路+源码)

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


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

posted @ 2023-09-27 10:36 Jack Jiang 阅读(68) | 评论 (0)编辑 收藏

     摘要: 本文由腾讯WXG客户端开发工程师yecong分享,本文做了修订和改动。1、引言相对于传统的消费级IM应用,企业级IM应用的特殊之外在于它的用户关系是按照所属企业的组织架构来关联的起来,而组织架构的大小是无法预设上限的,这也要求企业级IM应用在遇到真正的超大规模组织架构时,如何保证它的应用性能不受限于(或者说是尽可能不受限于)企业架构规模,这是个比较有难度的技术问题。本文主要分享的是企业微信在百对百...  阅读全文

posted @ 2023-09-21 11:15 Jack Jiang 阅读(78) | 评论 (0)编辑 收藏

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

[- 1 -] 新手入门:零基础理解大型分布式架构的演进历史、技术原理、最佳实践

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

[摘要] 本文我们就来聊聊分布式架构的演进过程,希望能给大家带来眼前一亮的感觉。


[- 2 -] 一篇读懂分布式架构下的负载均衡技术:分类、原理、算法、常见方案等

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

[摘要] 本文将从负载均衡技术的分类、技术原理、常见实现算法、常用方案等入手,为您详细讲解负载均衡技术的方方面面。这其中,四层和七层负载均衡技术最为常用,它们也是本文介绍的重点。


[- 3 -] 从新手到架构师,一篇就够:从100到1000万高并发的架构演进之路

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

[摘要] 本文以设计淘宝网的后台架构为例,介绍从一百个并发到千万级并发情况下服务端的架构的14次演进过程,同时列举出每个演进阶段会遇到的相关技术,让大家对架构的演进有一个整体的认知。


[- 4 -] 腾讯资深架构师干货总结:一文读懂大型分布式系统设计的方方面面

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

[摘要] 本文结合作者多年的互联网系统设计实践经验,从最基本的技术概念开始,带你探寻服务器端系统架构的方方面面。


[- 5 -] 快速理解高性能HTTP服务端的负载均衡技术原理

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

[摘要] 本文将以简洁通俗的文字,为你讲解主流的HTTP服务端实现负载均衡的常见方案,以及具体到方案中的负载均衡算法的实现原理。理解和掌握这些方案、算法原理,有助于您今后的互联网项的技术选型和架构设计,因为没有哪一种方案和算法能解决所有问题,只有针对特定的场景使用合适的方案和算法才是最明智的选择。


[- 6 -] 知乎技术分享:从单机到2000万QPS并发的Redis高性能缓存实践之路

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

[摘要] 本文作者陈鹏是该系统的负责人,本次文章深入介绍了该系统的方方面面,值得互联网后端程序员仔细研究。


[- 7 -] 阿里技术分享:深度揭秘阿里数据库技术方案的10年变迁史

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

[摘要] 阿里数据库事业部研究员张瑞,将为你讲述双11数据库技术不为人知的故事。在零点交易数字一次次提升的背后,既是数据库技术的一次次突破,也见证了阿里技术人永不言败的精神,每一次化“不可能”为“可能”的过程都是阿里技术人对技术的不懈追求。


[- 8 -]  阿里技术分享:阿里自研金融级数据库OceanBase的艰辛成长之路

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

[摘要] OceanBase 是蚂蚁金服自研的分布式数据库,在其 9 年的发展历程里,从艰难上线到找不到业务场景濒临解散,最后在双十一的流量考验下浴火重生,成为蚂蚁金服全部核心系统的承载数据库。这一路走来的艰辛和故事,蚂蚁金服高级研究员、OceanBase 团队负责人阳振坤将为你娓娓道来。


[- 9 -] 达达O2O后台架构演进实践:从0到4000高并发请求背后的努力

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

[摘要] 达达的业务组成简单直接——商家下单、配送员接单和配送,也正因为理解起来简单,使得达达的业务量在短时间能实现爆发式增长。而支撑业务快速增长的背后,正是达达技术团队持续不断的快速技术迭代的结果,本文正好借此机会,总结并分享了这一系列技术演进的第一手实践资料,希望能给同样奋斗在互联网创业一线的你带来启发。


[- 10 -] 优秀后端架构师必会知识:史上最全MySQL大表优化方案总结

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

[摘要] 本文将总结和分享当MySQL单表记录数过大时,增删改查性能急剧下降问题的优化思路,这也是资深后端架构师、程序员所必备的知识内容之一,希望本文对你有用。


[- 11 -] 通俗易懂:如何设计能支撑百万并发的数据库架构?

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

[摘要] 本篇文章我们一起来学习一下,对于一个支撑日活百万用户的高并发系统,数据库架构应该如何设计呢?


[- 12 -] 多维度对比5款主流分布式MQ消息队列,妈妈再也不担心我的技术选型了

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

[摘要] 本文将从17个维度综合对比Kafka、RabbitMQ、ZeroMQ、RocketMQ、ActiveMQ这5款当前最主流的MQ消息中间件产品,希望能为您的下一次产品的架构设计和MQ消息中间件选型提供参考依据。


[- 13 -] 小米技术分享:解密小米抢购系统千万高并发架构的演进和实践

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

[摘要] 本次分享将为大家解密该系统的技术演进、设计思路、实践总结等,希望能带给您启发。


[- 14 -] 美团技术分享:深度解密美团的分布式ID生成算法

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

[摘要] 对于美团的Leaf-segment这个ID生成方案,因为生成的ID全局唯一、全局有序,所以非常适合IM这种应用场景,这也是即时通讯网整理并分享给社区的原因。


[- 15 -] 12306抢票带来的启示:看我如何用Go实现百万QPS的秒杀系统(含源码)

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

[摘要] 本文内容虽是从秒杀系统谈起,并未直接涉及即时通讯相关知识,但有关Go的高并发实践,仍然值得广大即时通讯网的技术爱好者们研究和学习,必竟业务可以不同,但技术都是相通的,或许能为你即时通讯系统的高并发架构带来新的思路和灵感。


👉52im社区本周新文:《企业微信针对百万级组织架构的客户端性能优化实践 http://www.52im.net/thread-4437-1-1.html》,欢迎阅读!👈

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

posted @ 2023-09-20 12:31 Jack Jiang 阅读(62) | 评论 (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 实现)。

v10.0 版更新内容

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

(1)Android端主要更新内容新增群名片、消息转发功能等】:

  • 1)[新增] 新增发送“群名片”消息功能;
  • 2)[新增] 新增了消息转发功能;
  • 3)[新增] 新增了实时音视频聊天记录的功能;
  • 4)[bug] 解决了加载离线消息可能导致首页“消息”列表出现重复item的问题;
  • 5)[优化] 修正了实时语音聊天呼叫ui上的提示文字错误;
  • 6)[优化] 取消了实时音视频聊天必须对方在线才能呼叫的限制;
  • 7)[优化] 安全提升,优化了http接口、文件上传接口、socket长连接的token校验逻辑;
  • 8)[优化] 更换了新的高德地图WebSevice key;
  • 9)[优化] 其它ui细节优化等。

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

  • 1)[新增] 安全提升,实现了一套新的token生成、校验机制(支持对称加密和非对称加密两种模式);
  • 2)[新增] 安全提升,启用了AppKey校验机制.

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

posted @ 2023-09-18 13:39 Jack Jiang 阅读(60) | 评论 (0)编辑 收藏

     摘要: 本文由QQ技术团队分享,本文收录时有内容修订和大量排版优化。1、引言QQ 作为国民级应用,从互联网兴起就一直陪伴着大家,是很多用户刚接触互联网就开始使用的应用。而 QQ 桌面版最近一次技术架构升级还是在移动互联网兴起之前,在多年迭代过程中,QQ 桌面版也积累了不少技术债务,随着业务的发展和技术的进步,当前的架构已经无法很好支撑对 QQ 的发展了。在 2022 年初,我们下定决心对 QQ 进行全面的...  阅读全文

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

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

[-1-] 融云技术分享:全面揭秘亿级IM消息的可靠投递机制

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

[摘要] 本文根据融云亿级IM消息系统的技术实践,总结了分布式IM消息的可靠投递机制,希望能为你的IM开发和知识学习起到抛砖引玉的作用。


 [--] IM开发技术学习:揭秘微信朋友圈这种信息推流背后的系统设计

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

[摘要] 本文将重点讨论的是“关注”功能对应的技术实现:先总结常用的基于时间线Feed流的后台技术实现方案,再结合具体的业务场景,根据实际需求在基本设计思路上做一些灵活的运用。


 [--] 阿里IM技术分享(三):闲鱼亿级IM消息系统的架构演进之路

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

[摘要] 本文分享的是闲鱼即时消息系统架构从零开始的技术变迁之路,以期更多的同行们在此基础上汲取经验,得到有价值的启发。


 [--] 阿里IM技术分享(四):闲鱼亿级IM消息系统的可靠投递优化实践

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

[摘要] 那么基于闲鱼现有的即时消息系统架构和技术体系,如何来优化它的消息稳定性、可靠性?应该从哪里开始治理?当前系统现状到底是什么样?如何客观进行衡量?希望本文能让大家看到一个不一样的闲鱼即时消息系统。


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

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

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


 [- 6 -] 阿里IM技术分享(六):闲鱼亿级IM消息系统的离线推送到达率优化

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

[摘要] 本文将要分享的是闲鱼IM消息在解决离线推送的到达率方面的技术实践,内容包括问题分析和技术优化思路等,希望能带给你启发。


 [-7-] 阿里IM技术分享(八):深度解密钉钉即时消息服务DTIM的技术设计

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

[摘要] 本篇文章内容将从模型设计原理到具体的技术架构、最底层的存储模型到跨地域的单元化等,全方位展现了 DTIM 在实际生产应用中所遇到的各种技术挑战及相应的解决方案,希望借本文内容的分享能为国内企业级IM的开发带来思考和启发。


 [-8 -]  阿里IM技术分享(九):深度揭密RocketMQ在钉钉IM系统中的应用实践

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

[摘要] 在钉钉的IM中,我们通过 RocketMQ实现了系统解耦、异步削峰填谷,还通过定时消息实现分布式定时任务等高级特性。同时与 RocketMQ 深入共创,不断优化解决了很多RocketMQ本身的问题,并且孵化出 POP 消费模式等新特性,使 RocketMQ 能够完美支持对性能稳定性和时延要求非常高的 IM 系统。本文将为你分享这些内容。


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

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

[摘要] 本文内容将从开发者的视角出发(主要是我自已的开发体会),围绕项目背景、业务需求、技术原理、开发方案等主题,一步一步的与大家一起剖析:设计一套百万消息量的小规模IM系统架构设计上需要注意的技术要点。


 [-10 -] 跟着源码学IM(十):基于Netty,搭建高性能IM集群(含技术思路+源码)

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

[摘要] 本文将根据笔者这次的业余技术实践,为你讲述如何基于Netty+Zk+Redis来搭建一套高性能IM集群,包括本次实现IM集群的技术原理和实例代码,希望能带给你启发。


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

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

[摘要] 下面就由我来介绍一下我所负责的公司IM综合消息系统所经历的架构设计历程,以及架构设计过程中的一些思路和总结,希望能给你带来启发。


 [-12 -]  直播系统聊天技术(八):vivo直播系统中IM消息模块的架构实践

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

[摘要] 本文针对秀场直播,结合我们一年以来通过处理不同的业务线上问题,进行了技术演进式的IM消息模块架构的升级与调整,并据此进行了技术总结、整理成文,希望借此机会分享给大家。


 [-13-] 得物从0到1自研客服IM系统的技术实践之路

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

[摘要] 本篇文章将基于工程实践,分享我们从0到1自研一套客服IM系统时在各种关键技术点上的设计思路和实践方法。


 [-14-] 海量用户IM聊天室的架构设计与实践

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

[摘要] 本文将分享网易云信针对海量用户IM聊天室的架构设计与应用实践,希望能带给你启发。


👉52im社区本周新文:《IM跨平台技术学习(九):全面解密新QQ桌面版的Electron内存优化实践 http://www.52im.net/thread-4429-1-1.html》,欢迎阅读!👈

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

posted @ 2023-09-13 11:22 Jack Jiang 阅读(71) | 评论 (0)编辑 收藏

本文由vivo 互联网服务器团队Yu Quan分享,本文收录时有内容修订和重新排版。

1、引言

如今,Android端的即时通讯IM这类应用想实现离线消息推送,难度越来越大(详见《Android P正式版即将到来:后台应用保活、消息推送的真正噩梦》、《Android保活从入门到放弃:乖乖引导用户加白名单吧》)。

于是,使用手机厂商自建的ROOM级消息推送通道进行IM离线消息推送是个不得不面对的问题,我们也正好借此文机会,一窥主流手机厂商的ROOM级推送通道的技术实现吧。

vivo手机的厂商级消息推送系统的现状是最高推送速度140w/s,单日最大消息量200亿,端到端秒级在线送达率99.9%。同时推送系统具备不可提前预知的突发大流量特点。

本文将要分享的是vivo技术团队针对消息推送系统的高并发、高时效、突发流量等特点,从长连接层容灾、逻辑层容灾、流量容灾、存储容灾等方面入手,如何保证百亿级厂商消息推送平台的高可用性的。

* 推荐阅读:vivo技术团队分享的另一篇消息推送技术文章《vivo手机上的系统级消息推送平台的架构设计实践》。

 
技术交流:

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

2、推送系统介绍

vivo推送平台是vivo公司向开发者提供的消息推送服务,通过在云端与客户端之间建立一条稳定、可靠的长连接,为开发者提供向客户端应用实时推送消息的服务,支持百亿级的通知/消息推送,秒级触达移动用户。

推送系统主要由3部分组成:

  • 1)接入网关;
  • 2)逻辑推送节点;
  • 3)长连接。

其中,长连接负责与用户手机终端建立连接,及时把消息送达到手机终端。

推送系统的特点是:

  • 1)并发高;
  • 2)消息量大;
  • 3)送达及时性较高。

下面将针对这几个方面来分享我们的技术实践。

3、长连接层容灾的技术实现

长连接是推送系统最重要的部分,长连接的稳定性直接决定了推送系统的推送质量和性能。因此,需要对长连接层做好容灾和实时调度能力。

3.1面临的问题

原有推送系统架构是长连接层都部署在华东,所有vivo IDC逻辑节点通过VPC与华东的Broker建立连接,手机端跟华东的broker进行长连接通信。

这种部署方式存在以下问题。

1)问题一:华北、华南手机都需要连接华东的Broker,地域跨度大,长连接网络稳定性和时效性相对较差。

2)问题二:逻辑层跟华东的Broker之间由一条VPC连接,随着业务的发展,推送流量越来越大,带宽会出现瓶颈,有超限丢包的风险。另外当该VPC出现故障时,会造成全网消息无法送达。

注:长连接层节点名为Broker。

原始长连接架构图:

3.2解决方法

基于以上架构存在问题,我们对架构进行了优化。即将Broker进行三地部署,分别部署在华北、华东、华南。

华北、华东、华南三地用户采用就近接入方式。

优化后的架构,不仅可以保证长连接网络稳定性和时效性。同时具有较强的容灾能力,华东、华南Broker通过云网跟华北Broker连接,华北Broker通过VPC与vivo IDC连接。当华北、华东、华南某个地区Broker集群故障或者公网故障,不会影响到全网设备收发消息。

三地部署后的架构图:

3.3进一步优化

但是上述这种方式还是存在一个问题,就是某个地区Broker集群故障或者公网故障,会出现该区域部分设备无法收到推送消息的情况。

针对上述单个地区异常导致该区域部分设备无法收到推送消息的问题,我们设计了一套流量调度系统,可以做到实时流量调度和切换。global scheduler节点负责策略调度和管理。

vivo phone进行注册时:dispatcher会下发多个地区的ip地址,默认情况下,进行就近连接。单多次连接失败后,尝试连接其他ip。当某个地区Broker出现长连接数瓶颈或者VPC出现故障,可以通过global scheduler节点下发策略,让该故障地区的设备重新从dispatcher获取新的ip集的ip,与其他地区Broker建立长连接,逻辑节点下发消息到重连后的Broker。等到该地区恢复后,可以重新再下发策略,进行回调。

流量调度系统图:

4、逻辑层容灾的技术实现

长连接层做好容灾后,逻辑层也需要做相应容灾。

之前我们逻辑层都部署在一个机房,不具备机房间容灾能力,当一个机房出现断电风险,会出现服务整体不可用问题,因此我们做"同城双活"部署方案改造。

逻辑层单活架构:

逻辑层分别在vivo IDC1和vivo IDC2进行部署,网关层根据路由规则将流量按照一定比例分别下发到两个IDC,实现逻辑层同城双活。

我们发现:数据中心还是只有一个,部署在vivo IDC1,根据成本、收益,以及多数据中心数据同步延迟问题综合考虑,数据中心暂时还是以单数据中心为主。

逻辑层双活架构:

5、流量容灾的技术实现

5.1概述

做好系统架构的容灾能力后,推送系统的网关层还需要应对突发流量做相应的应对措施,做好流量控制,保证系统稳定性。历史上,我们曾经因为热点和突发新闻事件,并发推送流量巨大,导致服务出现异常,可用性降低问题。

为了应对突发大流量,保证突发流量的情况下,系统可用性不变,同时能兼顾性能和成本。为此,我们分别对比了设计了以下两种方案。

5.2常规方案

常规的方案是一般是根据历史情况估算冗余部署大量机器,来应对突发流量。

单这种方式成本较高,突发流量可能只持续5分钟或更短时间,而系统为了满足5分钟突发流量,需要冗余部署大量机器。

一旦流量超过了部署机器可承担的上限,无法及时扩容,可能导致可用性下降,甚至出现雪崩效应。

传统方案下的推送架构:

那如何设计一套既可以控制成本,面对突发大流量弹性扩容,又保证消息不漏并兼顾推送性能的方案呢?

5.3优化方案

优化后的方案:

  • 1)在原有架构的基础上,在接入层增加缓冲通道,当流量洪峰到来时,对于系统可处理的上限能力外的流量,打入缓冲队列;
  • 2)通过消息队列形式,增加bypass接入层,限速消费消息队列;
  • 3)在流量洪峰过去后,提升bypass消费速度,处理缓存队列消息;
  • 4)bypass接入层通过docker部署,支持动态扩缩容,默认最小化集群,当消息队列积压很多,并且下游有能力处理时,提升消费速度,bypass根据CPU负载动态扩容,快速消费消息队列;
  • 5)处理完毕后动态缩容。

消息队列:选用吞吐量较大的KAFKA中间件,并且与离线计算KAFKA集群共用,能充分利用资源。

bypass接入层:采用docker部署,支持根据CPU负载和时间动态扩缩容。默认最小集群部署。对于已知的流量高峰时段,可以提前扩容服务,保证流量快速处理。未知时段流量高峰,可以bypass接入层,根据CPU负载情况进行动态扩缩容。

增加缓存队列后的推送架构:

5.4进一步优化

进行上述改造后:还存在一个问题,就是如何进行接入层全局控速。

我们采用的方式是:收集下游推送节点的推送流量情况。

比如:流量达到系统可承受上限的80%时下发限速指令,调整接入层推送速度。让消息先积压在消息队列,等到下游流量降低之后,下发解除限速指令,让bypass接入层加速消费消息队列,进行推送。

增加控速后的推送架构:

优化后方案与传统方案对比:

6、存储容灾的技术实现

6.1问题

做好并发流量控制后,能很好的预发突发热点问题。但在推送系统内部,由于使用Redis集群缓存消息,出现过因为Redis集群故障导致消息无法及时送达问题。

因此:我们考虑对Redis集群做相关容灾方案设计,实现系统在Redis集群故障期间,也能及时推送消息并保证消息不丢失。

推送消息体缓存在Redis集群中,推送时从Redis中获取消息体,如果Redis集群宕机,或者内存故障,会导致离线消息体丢失。

6.2方案

原有消息流程:

1)方案一:

引入另一个对等Redis集群,采用推送双写方式,双写两个Redis集群。该方案需要冗余部署规模对等的备Redis集群。推送系统需要双写Redis操作。

2)方案二:

原有Redis集群,采用RDB+AOF方式同步到另一个备Redis集群。

该方案不在需要推送系统双写Redis改造,直接利用将原有Redis集群数据同步到另一个备Redis集群。也需要冗余部署规模对等的备Redis集群。可能存在部分数据同步延迟导致推送失败问题。

3)方案三:

应用另一个分布式存储系统,磁盘KV,兼容Redis协议,同时具有持久化能力。可以保证消息体不丢失。但是为了节省成本,不再直接使用Redis集群对等资源。

而是根据推送特点,推送分为单推、群推。单推是一对一推送,一个用户一条消息体。群推是一对多推送,一个消息体对应多个用户。

群推往往是任务级别推送。因此我们使用一个相对小一些的磁盘KV集群,主要用于冗余存储,群推消息体,即任务级别的消息。对于单推,还是只保存到Redis中,不进行冗余存储。

如果Redis集群故障,对于单推消息,推送系统可以携带消息体往下游推送,确保消息可以继续下发。对于群推消息,因为消息体冗余存储在磁盘KV中,当Redis集群故障后,可以降级到读取磁盘KV。

6.3优化

方案三还存在一个问题,就是磁盘KV的写入性能和Redis集群不是一个数量级,特别是时延,磁盘KV在平均在5ms左右。

而Redis集群却在0.5ms。如果在推送系统对群推消息体进行双写。这个时延是不能接受的。

因此只能采用异步写入磁盘KV的方式。

这里将备份群推消息体,先写入消息中间件KAFKA,由bypass节点消费KAKFA进行异步写入磁盘KV。这样在使用的灾备磁盘KV资源较少的前提下,保证推送系统的高并发能力,同时可以保证群推消息体不丢失,Redis异常时,单推消息携带消息体推送,群推消息体读取磁盘KV。

存储容灾方案对比:

7、本文小结

本文从长连接层容灾、逻辑层容灾、流量容灾、存储容灾等几个方面讲述了推送系统容灾建设过程。系统容灾需要根据业务发展,成本收益,实现难度等多方面考虑。

当前我们长连接层已具备三地部署,逻辑层具备同城双活,数据中心为单数据中心。后续我们会持续研究和规划双数据中心,两地三中心部署架构方式来逐步加强推送系统容灾能力。

8、参考资料

[1] vivo手机上的系统级消息推送平台的架构设计实践

[2] 魅族2500万长连接的实时消息推送架构的技术实践分享

[3] 专访魅族架构师:海量长连接的实时消息推送系统的心得体会

[4] 百万在线的美拍直播弹幕系统的实时推送技术实践之路

[5] 京东京麦商家开放平台的消息推送架构演进之路

[6] 解密“达达-京东到家”的订单即时派发技术原理和实践

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

[8] 喜马拉雅亿级用户量的离线消息推送系统架构设计实践

[9] 微信直播聊天室单房间1500万在线的消息架构演进之路

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

[11] 消息推送技术干货:美团实时消息推送服务的技术演进之路

[12] 技术干货:从零开始,教你设计一个百万级的消息推送系统

9、vivo技术团队分享的其它文章

IM消息ID技术专题(七):深度解密vivo的自研分布式ID服务(鲁班)

直播系统聊天技术(八):vivo直播系统中IM消息模块的架构实践

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

vivo手机上的系统级消息推送平台的架构设计实践


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

posted @ 2023-09-07 11:17 Jack Jiang 阅读(91) | 评论 (0)编辑 收藏

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

[-1-] 微信后台基于时间序的新一代海量数据存储架构的设计实践

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

[摘要] 时隔3年,微信再次分享了基于时间序的新一代海量数据存储架构的设计实践(可以认为是《微信后台基于时间序的海量数据冷热分级架构设计实践》一文中所述架构的升级版),希望能带给你启发。


[-2-] 阿里技术分享:电商IM消息平台,在群聊、直播场景下的技术实践

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

[摘要] 本文来自淘宝消息业务团队的技术实践分享,分析了电商IM消息平台在非传统IM应用场景下的高发并、强互动群聊和直播业务中的技术特点,总结并分享了在这些场景下实现大量多对多实时消息分发投递的一些架构方面的设计实践。


[-3-] 瓜子IM智能客服系统的数据架构设计(整理自现场演讲,有配套PPT)

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

[摘要] 此次演讲,从数据架构层面讲解系统遇到的挑战及解决办法。


[-4-]阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处

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

[摘要] 业界的 IM 产品在功能上同质化较高,而企业级的 IM 产品对于高可用、安全性又有更高的要求,如何打造具备差异化的产品,又在高可用、安全性、数据一致性等方面具备较高的品质,是企业级 IM 产品成功的关键。钉钉在过去短短几年时间里,用户数已破 2 亿,企业组织数破千万,钉钉是在规划企业级 IM 产品的架构上有何过人之处?本文将围绕这个话题进行展开。


[-5-] 从游击队到正规军(一):马蜂窝旅游网的IM系统架构演进之路

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

[摘要] 本文将分享马蜂窝旅游网的IM系统架构从零演进的整个过程,希望能给你的IM技术选型和方案确定带来启发。


[-6 -] 从游击队到正规军(二):马蜂窝旅游网的IM客户端架构演进和实践总结

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

[摘要] 本文由马蜂窝电商业务 IM 移动端研发团队分享了马蜂窝电商业务 IM 移动端的架构演进过程,以及在IM技术力量和资源有限的情况下所踩过的坑等。


[-7-] 从游击队到正规军(三):基于Go的马蜂窝旅游网分布式IM系统技术实践

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

[摘要] 本文我们将结合马蜂窝旅游电商IM系统的发展历程,单独介绍基于Go重构分布式IM系统过程中的实践和总结(本文相当于《从游击队到正规军(一):马蜂窝旅游网的IM系统架构演进之路》一文的进阶篇),希望可以给有相似问题的朋友一些借鉴。


[-8 -]  微信技术分享:微信的海量IM聊天消息序列号生成实践(容灾方案篇)

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

[摘要] 本篇将会介绍 seqsvr 分布式容灾架构的演变。


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

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

[摘要] 本文将分享的是一套生产环境下的IM群聊消息系统的高可用、易伸缩、高并发架构设计实践,属于原创第一手资料,内容较专业,适合有一定IM架构经验的后端程序员阅读。


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

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

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


[-11 -] 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

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

[摘要] 本文主要聚焦这套亿级用户的IM架构的一些比较细节但很重要的热门问题上,比如:消息可靠性、消息有序性、数据安全性、移动端弱网问题等。


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

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

[摘要] 本文将在亿级消息量、分布式IM系统这个技术前提下,分析和总结实现这套系统所需要掌握的知识点,内容没有高深的技术概念,尽量做到新手老手皆能读懂。


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

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

[摘要] 本文总结了企业微信的IM消息系统架构设计,阐述了企业业务给IM架构设计带来的技术难点和挑战,以及技术方案的对比与分析。同时总结了IM后台开发的一些常用手段,适用于IM消息系统。


👉52im社区本周新文:《揭秘vivo百亿级厂商消息推送平台的高可用技术实践 http://www.52im.net/thread-4416-1-1.html》,欢迎阅读!👈

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

posted @ 2023-09-06 15:06 Jack Jiang 阅读(85) | 评论 (0)编辑 收藏

本文由网易云信资深服务端开发工程师曹佳俊分享,本文收录时有内容修订和重新排版。

1、引言

聊天室是一类非常重要的 IM 业务形态,不同于单聊和群聊,聊天室是一种大规模的实时消息分发系统。聊天室有多种技术实现方案,业界也有一些开源的实现,每种实现都有自己的特点和应用场景。

本文将分享网易云信针对海量用户IM聊天室的架构设计与应用实践,希望能带给你启发。

 
技术交流:

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

2、本文作者

曹佳俊:网易云信资深服务端开发工程师,中科院研究生毕业后加入网易,一直在网易云信负责 IM 服务器相关的开发工作。对 IM 系统构建以及相关中间件的开发有丰富的实战经验。

3、聊天室整体架构

首先,我们先来看一下网易云信当前聊天室的详细技术架构,以及我们在架构升级优化过程中做的一些事情。

如下图,是网易云信聊天室的技术架构:

主要包括以下部分:

  • 1)接入层的 ChatLink;
  • 2)网络传输层的 WE-CAN、WE-CAN bridge;
  • 3)调度层的 Dispatcher;
  • 4)服务层的 Callback、Queue、Presence、Tag、History 等;
  • 5)CDN 分发层的 CDN Manager、CDN Pusher、CDN Source。

下面,我们针对每一层展开详细分析。

4、聊天室的接入层

接入层根据客户端的类型不同会有不同的实现,例如常见客户端(iOS、Andriod、Windows、Mac 等)基于私有二进制协议,Web 端基于 Websocket 协议实现。

接入层作为距离客户端的最后一公里,其接入速度、质量以及数据安全都是至关重要的,下面我们逐一讨论。

1)接入速度和质量:

目前我们搭建了覆盖全国各省份以及全世界各大洲的边缘节点,缩短最后一公里,减少不确定性,提升服务的稳定性。

2)数据安全:

基于对称+非对称加密,客户端与服务器之前实现 0-RTT,完成秘钥交换和登录,同时也支持 RSA/AES/SM2/SM4 等各种加密算法。

接入层除了接受来自客户端的请求,还负责进行消息的单播和广播,因此接入层需要管理本节点的所有长连接,包括每个聊天室房间的连接以及每个连接的标签属性。

此外接入层会上报自己的负载信息给后端服务,方便调度层进行合理的调度。

当流量洪峰来临时,因为需要进行消息的广播,接入层往往是压力最大的,为了保证服务的稳定性,我们做了很多优化策略。

3)自适应的流控策略:

单机流控:接入层服务会监控本机整体的网络带宽使用情况,并设置 2 个阈值 T1 和 T2,当带宽使用率超过 T1 时,触发流控,如果进一步超过了 T2,则不仅触发流控还会不断的调整流控的强度。最终的目标是使带宽使用率稳定在 T1 和 T2 之间。

单连接流控:除此之外,接入层服务还会记录每个长连接的消息分发速度,并进行细粒度的调整,避免单机粗粒度流控导致单个连接分发过少或者过多,做到消息分发的平滑,即减少了带宽流量的波动尖刺,也改善了端侧的体验。

4)性能优化:

ChatLink 高负载运行时,除了网络带宽,调用链路上的各个环节都可能成为性能的瓶颈。我们通过减少编解码的次数(包括序列化、压缩等)、多线程并发、减少内存拷贝、消息合并等多种方式,显著地提升了服务性能。

5、聊天室的网络传输层

我们的IM聊天室系统最初的架构是将接入层和后端服务层都部署在同一个机房的,大部分用户都是直连 BGP 机房的 ChatLink,对于偏远地区或者海外,则通过专线的方式部署代理节点完成加速。

该方案存在明显的缺点就是服务能力上限受制于单机房的容量。此外,专线也是一笔不小的开销。

在我们接入 WE-CAN 大网后,接入层 ChatLink 可以做到客户端就近接入,提高服务质量的同时降低了成本。此外,多机房的架构也使得我们的服务能力上升了一个台阶。

为了适配 WE-CAN 大网,我们设计了 WE-CAN Bridge 层,作为大网接入协议和聊天室协议的桥接层,负责协议转换、会话管理、转发接收。通过这种分层架构,接入层和后端业务层可以少修改或者不修改,减少对已有系统的改造成本,也降低了架构升级带来的风险。

什么是WE-CAN?

WE-CAN(Communications Acceleration Network)是网易自研的新一代大规模分布式传输网络,WE-CAN的根本目标是建立一个能将任意数据从全球任一点稳定、快速、高效地发送到全球任何其他角落的通用传输网络,且这个网络是架设在公共互联网之上的 —— 即无需借助任何特殊的硬件设备或架设专线,而是通过软件方案来达到目标。

6、聊天室的调度层

调度层是客户端接入聊天室系统的前提。客户端登录聊天室之前需要先获取接入地址,分配服务我们称之为 Dispatcher。

Dispatcher 是中心化的,会接受来自 WE-CAN 和 ChatLink 的心跳信息,根据心跳情况来选择最佳接入点。

调度系统设计主要考虑的是以下两个关键点。

1)调度精度:

调度系统会根据请求方的 IP 判断地域和运营商信息,对比各个边缘节点的所属区域、运营商以及节点本身的负载(如 CPU、网络带宽等)。

此外还考虑边缘节点到中心机房的链路情况(来自 WE-CAN),计算综合打分,并把最优的若干节点作为调度结果。

2)调度性能:

面对高并发场景,比如一个大型聊天室,活动初期往往伴随着大量人员的同时进入,此时就需要调度系统做出快速的反应。

为此,我们会将上述的调度规则以及原始数据进行本地缓存优化。

此外,为了避免心跳信息滞后导致分配不合理引起节点过载,分配服务时还会动态调整负载因子,在保证调度性能的前提下,尽量做到分配结果的平滑。

7、聊天室的服务层

服务层实现了各种业务功能,包括:

  • 1)在线状态;
  • 2)房间管理;
  • 3)云端历史;
  • 4)第三回调;
  • 5)聊天室队列;
  • 6)聊天室标签等。

其中最基础的是在线状态管理和房间管理:

  • 1)在线状态管理:管理某个账号的登录状态,包括登录了哪些聊天室、登录在了哪些接入点等;
  • 2)房间管理:管理某个聊天室房间的状态,包括房间分布在哪些接入点,房间里有哪些成员等。

在线状态管理和房间管理的难点在于如何有效管理海量用户和房间。

由于 PaaS 平台的特性,使得我们可以根据不同的租户来进行 Region 划分,从而做到水平扩展。

此外:由于状态数据有快速变化的特点(短 TTL),当某些核心用户或者某个客户报备了大型活动时,可以在短时间内进行相关资源的快速拆分和隔离。

服务层除了要支持海量客户接入、水平扩展外,还有一个很重要能力,就是需要提供各种各样的扩展性功能来适配客户各种应用场景。

为此我们还提供了丰富的功能,比如:

  • 1)第三方回调:方便客户干预 C 端用户的登录、发消息等核心环节,自定义实现各种业务逻辑(因为涉及到服务调用,而这个调用是跨机房甚至是跨地区的,为了避免第三方服务故障导致云信服务异常,我们设计了隔离、熔断等机制来减少对关键流程的影响);
  • 2)聊天室队列:可以方便用户实现一些诸如麦序、抢麦等业务场景需求;
  • 3)聊天室标签:作为特色功能,支持消息的个性化分  发(其实现原理是通过客户端登录时设置标签组以及发消息时设置标签表达式,来定义消息分发和接收的规则。标签信息会同时保存在服务层以及接入层,通过将部分标签计算下推到接入层,节省了中心服务的带宽和计算资源)。

8、聊天室的CDN 分发层

当我们评价一个牛x的IM聊天室系统时,常用的一个词是无上限。

架构支持无上限不代表真的无上限。

一个IM聊天室系统,在逻辑上,各个组成单元都是可以水平扩展的,但是每个服务所依赖的物理机、交换机、机房带宽等都是有容量上限的。因此,能够合理地调配多个地域的多个机房,甚至是外部的其他资源,才能真正体现出一个聊天室系统所能支撑的容量上限。

在我们的聊天室系统中,用户所有的接入点遍布各地机房,天然的将各地的资源进行了整合,所能支撑的容量上限自然高于单机房或者单地区多机房的部署模式。

进一步的:当面临一个更大规模的聊天室,此时如果能利用一些外部的通用能力不失为一种合适的选择。融合 CDN 弹幕方案就是这样一种技术实现方案,它可以利用各大 CDN 厂商部署在各地的边缘节点,利用静态加速这样的通用能力来支持超大规模的聊天室消息分发。

基于融合 CDN 弹幕分发方案,其核心点就是弹幕的分发和管理,这是一个可选的模块,我们内部对此进行了封装,可以根据不同的业务特点来选择是否开启而不需要修改任何业务代码。

在开启融合 CDN 弹幕分发方案的情况下,所有的弹幕广播会划分成两条链路:

  • 1)重要的且需要实时送达的消息会走长连接到达客户端;
  • 2)其他的海量消息则会进入 CDN Pusher,通过各种策略进行聚合后送达 CDN Source。

客户端 SDK 会采取一定的策略定时从 CDN 边缘节点获取弹幕消息。SDK 会聚合不同来源的消息,排序后回调给用户,App 层无需关系消息来自哪里,只需根据自己的业务需求进行处理即可。

如上图,展示了 CDN 弹幕分发链路的消息流转过程。

CDN Manager 负责:

  • 1)管理不同 CDN 厂商的分配策略(登录时会通过长连接下发,且能动态调整)
  • 2)负责管理平台上各个聊天室融合 CDN 模式的开启和关闭;
  • 3)对应的 CDN Pusher 资源的调配和回收。

CDN Pusher 实际负责:

  • 1)接收来自客户端消息;
  • 2)并根据消息的类型、消息的优先级等,组装成以一个一个的静态资源,推给 CDN Source,等待 CDN 回源拉取。

9、大规模场景应用案例

在2020年8月,网易云音乐 TFBoys 的 7 周年线上演唱会就是一个聊天室大规模场景应用的典型案例。

在这场活动创造了 78w+ 的在线付费演唱会的世界纪录,其弹幕互动的实现方式采用了我们基于融合 CDN 弹幕分发方案。

事实上:在筹备环节,我们的聊天室系统达成了 20 分钟完成从 0 到 1000w 在线,上行消息 tps 达到 100w 的性能指标。

如上图:是支持本次活动弹幕分发的架构图,普通弹幕和礼物消息分别通过客户端 SDK 以及服务器 API 到达云信服务器,并最终进入弹幕广播服务,随后分流到长连接和 CDN 上,再通过 pull / push 混合的方式送达客户端。

PS:有兴趣的同学可以深入阅读关于这个案例的技术分享:《直播系统聊天技术(九):千万级实时直播弹幕的技术实践》。

10、聊天室标签应用案例

近年来,随着互联网的发展,在线教育越来越火爆,最近又兴起了“超级小班课”模式。

所谓超级小班课,指的是大型多人课堂与小班互动模式结合。在线直播场景下,文字互动作为其中重要的一环,是IM聊天室的典型应用场景。

但在超级小班课的模式下,常规的IM聊天室系统却存在各种各样的问题,不管是建立多个聊天室,还是单个聊天室进行消息过滤,都存在一些严重的问题。

由此我们开放了聊天室标签功能,完美支持了上述业务场景。

基于聊天室标签:可以灵活地支持聊天室消息定向收发、聊天室权限定向管理、聊天室成员定向查询等个性化功能,真正实现大型直播下多场景的分组互动。

比如:

  • 1)对学生进行分组标签后,方便进行因材施教;
  • 2)分小组讨论,小组间内部讨论和组间 PK 等等。

如上图,展示了超级小班课的一个场景:1 个主讲教师+ N 个互动小班+ N 个助教,所有学生被划分成了一个一个的小班,由对应的助教完成预习提醒、课后答疑、作业监督、学员学习情况反馈等工作,同时又接收来自主讲老师的直播画面,做到了大课的规模,小课的效果。

11、本文小结

以上,就是本文的全部分享,主要介绍了我们构建一个大型聊天室系统的主要技术以及架构原理。

任何系统的搭建都不是一蹴而就的,我们也会继续打磨底层技术,就像引入 WE-CAN 来提升网络传输效果,也会继续丰富完善我们的功能图谱(如独创的聊天室标签功能等)。

12、参考资料

[1] 直播系统聊天技术(九):千万级实时直播弹幕的技术实践

[2] 海量实时消息的视频直播系统架构演进之路(视频+PPT)

[3] 百万在线的美拍直播弹幕系统的实时推送技术实践之路

[4] 阿里电商IM消息平台,在群聊、直播场景下的技术实践

[5] 微信直播聊天室单房间1500万在线的消息架构演进之路

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

[7] 百万人在线的直播间实时聊天消息分发技术实践

[8] 直播间海量聊天消息的架构设计难点实践

[9] vivo直播系统中IM消息模块的架构实践

[10] 万人群聊消息投递方案的思考和实践

[11] IM中的万人群聊技术方案实践总结

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

posted @ 2023-09-01 10:39 Jack Jiang 阅读(130) | 评论 (0)编辑 收藏

本文由QQ技术团队王辉、吴浩、陈俊文分享,编辑Tina整理,本文收录时有内容修订和排版优化。

1、引言

在瞬息万变的互联网行业中,年过二十四的即时通讯IM应用 QQ 堪称超长寿的产品,见证了中国互联网崛起的完整历程。

然而,如今这个元老级产品经历了一次从内到外彻底的重构。在这次重构中,QQ 选择了 Electron 作为 UI 跨平台开发框架。

尽管 Electron 被 Slack、Visual Studio Code 和 Discord 等大型产品广泛使用,但也引发了一些网友的担忧,例如内存占用、安装包体积和启动速度等方面的问题。本文内容整理自 QQ 技术团队的采访,我们一起来看看QQ团队选择Electron作为桌面版跨端框架背后的决策与思考。

 
 
技术交流:

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

2、系列文章

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

3、老QQ桌面版的技术债

3.1多端代码不统一

QQ 的第一个版本发布于 1998 年,在 Windows 技术栈的基础上用纯原生的方式开发,在当时互联网带宽非常小的情况下,QQ 将安装包控制在了只有 200K 左右。

2007 年后智能手机开始露出苗头,腾讯行动得比较早,部分前端技术开发开始转型到了移动端,在桌面端, QQ 随着业务和组织的发展,针对三大操作系统陆续组建了三支不同的研发团队,各自负责自己的一套代码。

▲ 初版QQ的注册向导页

▲ 初版QQ的主要功能为即时聊天

三端不同代码,老产品历史包袱,加上移动时代研发人员的转型,导致桌面 QQ 维护成本很高。

QQ 技术团队介绍,拿之前的桌面 QQ 为例,Windows QQ 以前的 UI 框架用的是腾讯自研的 GF 框架,10 多年了,GF 这个框架文档还不全,新加入这个项目的团队人员,要基于这个基础框架去做一些事情,是效率很低的一件事情,慢慢的就没有人愿意去用这个框架了。简而言之,就是技术债。

PS:如果你对QQ的发展史感兴趣可以看看下面这些文章:

  1. 闲话即时通讯:腾讯的成长史本质就是一部QQ成长史
  2. 技术往事:创业初期的腾讯——16年前的冬天,谁动了马化腾的代码
  3. 技术往事:史上最全QQ图标变迁过程,追寻IM巨人的演进历史
  4. QQ的成功,远没有你想象的那么顺利和轻松
  5. 还原真实的腾讯:从最不被看好,到即时通讯巨头的草根创业史

3.2多端功能不一致

旧版的桌面端 QQ,Windows 的功能最丰富,Mac OS 次之, Linux 功能非常简洁。

比如“屏幕共享”这个功能,移动端有,Windows 端有,但是 Mac OS 端是没有的。那用户就会遇到一个问题,像 Mac OS 端无法与其它端 QQ 用户一起来使用这个功能。

“多端不统一不利于用户对于 QQ 的统一认知。我们这次的架构升级就是想尽量通过一套核心代码去拉平所有平台的体验,让它具有更好的可维护性和可扩展性,让桌面 QQ 能够更好地迭代产品交互和功能,升级用户体验,再次焕发生长的生命力。”

3.3QQ NT 项目的诞生

于是 QQ NT 项目的诞生了!

QQ NT 项目是在 2022 年 3 月份正式启动, Mac OS QQ 在 6 月份开始发布内测, 9 月份正式上架了 App Store,迭代了几个版本之后,QQ 团队就同步开发 Linux。

在 2022 年,QQ 发布了新的 macOS 和 Linux 版本,包括 QQ 后台其实也做了很大的改变和重构,核心系统做了全新重写,云原生成熟度也得到了很大的提升。

从 2023 年开始,QQ 团队聚焦做 Windows 端的开发,在 3 月底就开始内测,7 月初上架官网。

同时移动端 QQ NT 也在 7 月初完成了核心系统的重写和全量升级。

在目前全新的框架设计下,无论是核心系统、功能迭代还是设计语言上,都可以尽可能地“原子化”,来让 QQ 后续更好地迭代功能。

4、新QQ桌面版重构的技术挑战

4.1业务功能上的挑战

QQ 的重构其实是两方面的重构:

  • 1)一个是面向复杂业务的梳理重构;
  • 2)一个是面向工程技术债的全新技术重构。

重构之路也是两者相互伴随的过程。

首先:在整个 QQ 重构过程中最大的挑战来自于 QQ 功能的复杂化,QQ 有很多十分复杂的历史功能,这些功能模块也曾经由非常多不同的人经手负责过。其中哪些功能是不合理的或没有价值的,如何去做取舍往往是最难的。“虽然技术上我们做了很多事情,但技术上的实现或许并没有那么难,我们处理起来更有经验和从容。相比于技术的复杂度,业务上的往往需要考虑的更多,这本身就是很大的挑战。”

因为 QQ 已经是近 25 年的产品了,有很多细小复杂的功能。虽然这些功能看看起来很小,但用户量其实又很大,稍微改动可能就会有很多的用户反馈,QQ 团队都得非常的关注。仅从产品功能角度上看,有些功能本身就已经是很重的负债,而 QQ 团队内部有一个叫做“QQ 节能计划”的项目,会有比较严谨的项目流程去评估是否需要下架。

4.2技术重构上的挑战

技术上重构也有不少挑战,这次重构是一次跨平台的重构,而在多个平台里面比较有挑战则是 Linux 平台。

作为程序员,很多人免不了要跟 Linux 打交道。但是这么多年来,对于使用 Linux 系统的用户来讲,有一个特别让人烦恼的问题,那就是没有一个好用的 IM 聊天工具。被寄予厚望的 QQ,此前在 Linux 版本上功能也没有 Windows 和 Mac OS 版本全面,迭代速度也明显慢过其他两个版本。业界甚至猜测 Linux 第一个版本是由腾讯实习生所写,毕竟这个说法进一步加重了其初版的“简陋”特性,也为其“停更”的原因提供了更合理的解释。

QQ 技术团队表示,较之另两个版本,Linux 版本的研发最为复杂:

  • 1)一方面操作系统本身很多碎片化,市面上有非常多的发行版,也不缺乏一些千奇百怪的版本;
  • 2)另一方面因为机器运行环境或编译器的缺失,使得解决适配问题的难度很大。

许多发行版相关的机器和开发环境实际上他们并没有,有时还需要外部公司帮助进行一些测试工作。由于没有相应的开发环境,一旦出现闪退等问题,解决难度自然会变得更大。此外,有时候需要与国产操作系统厂商进行特殊的合作,甚至需要对方寄送特定的编译好的代码库,但前后往往会花费一个月的时间才能收到。

而在本次重构之后,“Linux 功能跟 Windows 一样多了”。

4.3选型Electron的质疑

技术上的另一大挑战便是外界对于 QQ 桌面端使用 Electron 的质疑,尤其是内存方面。

外界有些用户在没有使用和分析的情况下对此发表一些夸大和否定的言论,也确实给 QQ 技术团队带来不小压力,但他们却始终坚定选型方向,也相信其中的问题可以被攻克和解决。

5、为何选择Electron而非纯Native技术栈?

5.1为什么Windows端不用原生实现?

确实当时有很多人在问,为什么 Windows 不用原生去实现?为什么不用 Qt?

首先:不太想和以前一样,Windows、Mac OS、Linux 三端各由一个团队分开负责。在国内这种人才环境里面,相关的纯原生的开发人员其实非常难招了,桌面端的人才稀缺,同时也投入比较大。

而对于 Qt 技术栈,他们首先考虑的其实还是人才的问题,国内熟练 Qt 技术栈的人非常少。如果对这个框架不了解,使用它反而是一个负向作用。

至于微软的 Webview2,从本质上讲,Webview2 和 Electron 并没有太大的区别,只是相对在其中打包了一些微软自身的优化措施,其他方面也不是很完善,而且还无法跨平台。虽然内存方面相较于 Electron 做了更多的优化。但据了解,比如微软 Teams 也没有完全切到 Webview2。并且由于它没有开源,因此也没有办法基于 Webview2 做定制优化。

包括 Flutter,QQ 团队表示他们当时也有过调研。他们放弃的一个原因是 Flutter 在桌面端的完善程度并不高,也担心标准化的问题。虽然当前 Flutter 非常流行,但谁也说不好这是不是“2015 年的 React Native”。大家担心随着时间推移,这套技术可能会失去维护支持,因为本身 Google 使用 Flutter 的占比也比较小。

“虽然它很热,但我们历史上踩过了很多很多非标准化的坑,一旦某个技术栈热度一过、维护力度不够,它就会成为全新的负债,做选型时必然也是避免再有类似经历。”

5.2选择Electron的几个考量

至于为什么最后选择 Electron,QQ 技术团队表示主要是基于以下几个考量。

1)首先最看重的是框架成熟度和技术栈的标准化:

Electron 基于 Web 技术栈,有足够低的上手和使用成本,不需要为了使用框架本身,还需要投入额外巨大人力成本去做基建和周边工具链的建设,以前在 RN、Flutter 的实践上都有类似的情况。而使用 Electron,现有的 Web 前端的大部分基建都可以直接复用,而且使用 Web 开发 UI 的效率,在主流技术栈里算是很高的了。至于迭代效率我觉得从新版桌面 QQ 功能的迭代速度就可以证明,这放在以前是完全办不到的。

另外由于 Web 技术栈是标准化的,假如 Electron 修改开源协议或者要闭源了,他们也能很方便的去写出一套类似的框架。只不过现在已经有开源的了,没必要再去重复建设一个。而且随着 Web 标准长久发展,Web 技术栈也不会有大的问题,而且还会越来越好。

2)其次是技术经验及人才储备:

技术选型是否适合当前团队也是一个很重要的考虑点,团队是否有相关的技术积累,是否有人才储备来持续投入这个技术栈。

Qt 的确在性能上是一个很好的选择,但目前团队对 Qt 没有太多积累,基建基本没有,而且相关人才其实比较匮乏,招聘就更难了。

而当前 QQ 技术团队 Web 前端团队还是有比较多的积累,在 QQ 频道项目中,也完整验证了 Electron 的技术可行性。

3)最后就是 Electron 具备的桌面端跨平台的优势:

但 QQ NT 架构并不是仅指 Electron,Electron 主要是作为 UI 跨平台的框架,只是占比很小的一部分,并且 QQ 桌面端不是全部用 Electron 实现,QQ NT 最核心的部分还是 QQ 底层通用抽象的模块,称之为 NT 内核,包括核心登录、消息系统、关系链、富媒体、长连接、数据库等等模块,完全用 C++ 实现,全平台通用。因此底层是完全跨平台的架构,而 Electron 只是上层桌面端 UI 跨平台较薄的一层。

“其实我们当时选型的时候,也的确看得到大家对 Electron 的评价褒贬不一,但我们还是有信心去解决这个问题,前期也做了一些技术的 Demo 和预研。实际上 Electron 并没有糟糕到这个地步。我们觉得可能是国内很多没有用过 Electron 的开发者,对这个框架有些忌惮。其实你到 Electron 的网站去看,还是有非常多国内外的亿级 DAU 产品都使用 Electron 框架。目前这几年主流的桌面端应用基本都选择了 Electron,如 Visual Studio Code、Discord、Slack、Skype、Whatsapp、Figma 等等,新的应用基本上也是首选 Electron,版本的迭代速度和社区氛围都很在线。”

“我们觉得不需要单纯因为口碑问题,就对这个选型没有了期待。还是要从实际出发,哪种技术栈适合你的产品,看看到底能不能有技术实力去把这个事情搞定。”

6、如何有效控制Electron的内存占用?

外界之所以会觉得 Electron 内存占用高,是因为其本身是一个多进程的架构,主进程基于 Node.js, 而每个窗口都对应一个渲染进程以及 V8 实例。可以说从技术框架层面上,上手写代码很容易,但不容易去管控它的内存。

QQ 技术团队认为:Electron 的开发者更多的是前端的开发者,可能在思维上没有去考虑怎么在这样一套技术框架里,去对内存数据进行管理和管控。开发者需要从前端开发者的思维,转变为客户端开发者的思维。

综合来看:对内存的看法其实不完全是 Electron 的技术框架所导致的,更多的是门槛上、开发思维上,导致内存没有得到很好的关注和优化。其实最简单的 Electron 应用大概也就只有几十兆的内存占用。因为前端原本更多还是停留在开发即用即走的 Web 站点,很少实现一个超大客户端,缺乏控制内存的经验,所以面对 QQ 这么大一个产品的时候,你就必须非常在意内存的使用和管控。

至于优化内存的突破口,可以说是从各个层面:从消息的链路中的每条消息的收发上,数据是怎么管理,包括像窗口及会话的管理,都得精打细算,也会做一些数据本地化和一些机制的按需加载,包括渲染上他们也提出一个根本的原则:“要做到所见才占用”,既我们看到的内容才占用这一部分内存,没看到和用不到的任何场景的内存就不应该再占用,通过各种方式来去让内存达到一个设定的目标。

他们也使用了不同维度的内存分析工具,从 V8 引擎到进程,再到整个应用程序,打通整个链路进行多角度的细节分析,以此来定位内存使用的瓶颈。之后采取一系列的针对性优化策略,包括缓存策略、按需加载、优雅降级等,同时使用线上监控、自动化测试手段,包括借助开发框架、工具建设、代码审查等,来阻止性能退化。(更多细节可以参看技术文章:《IM跨平台技术学习(九):全面解密新QQ桌面版的Electron内存占用优化》)

经过一系列组合优化之后:QQ 的内存在长时间挂机的条件下,平均稳定在 220M 左右。“现在优化还是不错的,比老版本要好很多。我们认为这个难题还是可以被很好的攻克,内存并不是大家认为的这么不可控,但是也需要团队去花费相当精力去探索和实践,才能去把内存控制到一个比较理想的状态。”

7、未来展望

目前 QQ 的前端团队作为一个公线团队,不仅负责桌面 QQ 的研发,还有 QQ 基础运营、QQ 空间以及基于 QQ 生态的创新项目研发,有比较多的线上项目的开发与维护和内部研效工具的建设。涉及的技术栈,包括 H5、Electron、Cocos、小程序、WebGL、WebAssembly、WebRTC 等。他们也表示会继续夯实这些技术,同时也不断地打破立下的性能目标,希望让桌面 QQ 覆盖更多平台。

他们也正在积极拥抱 AI:让 AI 在质量和效率上辅助日常开发。比如:前端设计稿还原,之前更多是一个耗时的体力活,D2C 是 QQ 前端一直探索的方向,之前使用纯规则转换生成代码,在视觉还原上效果还不错,但是代码可读性和可维护性不能很好的满足预期,所以除了一些日抛型的运营活动有些使用之外,比较难扩大成果。现在 D2C 结合大模型,生成的代码质量高了很多,也能很方便的将代码与 UI 组件库做映射,达到可以在核心业务中高效使用,达到通过 AI 提升研发效率的目的。针对一些无设计稿的管理平台开发,使用 P2C 提效,目前也有了一些不错的案例。

另外:QQ 技术团队也在积极探索 AI 更广阔的应用场景,比如代码评审,基本的 Lint 检检是难以实现的,但将已经掌握的内存泄漏模式通过规则的形式给到 AI,可以很方便地给开发同学一些不错的建议,为性能看家护院提供多一道保障。

8、写在最后

QQ NT 项目于 2022 年 3 月份启动,Mac OS QQ 花了该团队 3 个月的开发时间,9 月份上架 App Store,迭代了几个版本后同步开始开发 Linux QQ,并于这一年的最后一天上架各 Linux 应用市场,作为给 Linux 用户的一份特殊的新年礼物。2023 年 QQ 团队开始去聚焦做 Windows QQ NT 的开发,7 月正式上架应用市场和官网。同时移动端的 QQ 从 2022 年的 Q4 开始开发,也已经完成了全量升级和发布。

另外:桌面 QQ 也是在 NT 版本中第一次支持 64 位,这需要将音视频、安全、字节码、图形库等 C++ 模块,包括 Electron 框架都重新进行编译,花费了比较大的工作量。但在 64 位系统上,QQ 从此便不再需要以 32 位应用的方式通过额外的兼容和转换来运行。毕竟额外操作会增加开销,导致性能下降。

至此:QQ 实现了多个系统平台之间架构的统一。而团队的未来规划还是不断地打破性能目标,并覆盖更多平台,同时探索更多提升研发效率的办法,加快研发速度。

腾讯 QQ 用跨平台 Electron 取代之前原生应用程序的开发模式,这一举动引发的反响确实巨大。但我们也能看出,不同于小型产品团队,在大公司里具有一定规模的产品组织架构之下,快速满足用户需求,并逐渐需要为第三、第四乃至第五种运行平台提供支持时,保持一致性和协调性并不是想象中的那么容易。而缓慢而低效,最终会令你输掉比赛。

不管使用什么跨平台开发框架,都要去选择最合适自己团队的,也因此在 Web 标准技术栈上有丰富积累的 QQ 团队才会选择 Electron。并且我们认为没有人真正讨厌 Electron,只是我们对 QQ,对国内 App 寄予了非常高的期盼。

9、相关资料

[1] Electron官方开发者手册

[2] 快速了解新一代跨平台桌面技术——Electron

[3] Electron初体验(快速开始、跨进程通信、打包、踩坑等)

[4] Electron 基础入门 简单明了,看完啥都懂了

[5] vivo的Electron技术栈选型、全方位实践总结

[6] 融云基于Electron的IM跨平台SDK改造实践总结

[7] 闲鱼IM基于Flutter的移动端跨端改造实践

[8] 网易云信基于Electron的IM消息全文检索技术实践

[9] 闲话即时通讯:腾讯的成长史本质就是一部QQ成长史

[10] 技术往事:创业初期的腾讯——16年前的冬天,谁动了马化腾的代码

[11] 技术往事:史上最全QQ图标变迁过程,追寻IM巨人的演进历史

[12] QQ的成功,远没有你想象的那么顺利和轻松

[13] 还原真实的腾讯:从最不被看好,到即时通讯巨头的草根创业史

附录:更多有关QQ、微信的技术故事

技术往事:微信估值已超5千亿,雷军曾有机会收编张小龙及其Foxmail

QQ和微信凶猛成长的背后:腾讯网络基础架构的这些年

2017微信数据报告:日活跃用户达9亿、日发消息380亿条

腾讯开发微信花了多少钱?技术难度真这么大?难在哪?

技术往事:“QQ群”和“微信红包”是怎么来的?

开发往事:深度讲述2010到2015,微信一路风雨的背后

开发往事:微信千年不变的那张闪屏图片的由来

开发往事:记录微信3.0版背后的故事(距微信1.0发布9个月时)

一个微信实习生自述:我眼中的微信开发团队

首次揭秘:QQ实时视频聊天背后的神秘组织

为什么说即时通讯社交APP创业就是一个坑?

微信七年回顾:历经多少质疑和差评,才配拥有今天的强大

前创始团队成员分享:盘点微信的前世今生——微信成功的必然和偶然

即时通讯创业必读:解密微信的产品定位、创新思维、设计法则等

QQ现状深度剖析:你还认为QQ已经被微信打败了吗?

[技术脑洞] 如果把14亿中国人拉到一个微信群里技术上能实现吗?

QQ和微信止步不前,意味着即时通讯社交应用创业的第2春已来?

那些年微信开发过的鸡肋功能,及其带给我们的思考

读懂微信:从1.0到7.0版本,一个主流IM社交工具的进化史

同为IM社交产品中的王者,QQ与微信到底有什么区别

QQ设计团队分享:新版 QQ 8.0 语音消息改版背后的功能设计思路

社交应用教父级人物的张小龙和马化腾的同与不同

专访马化腾:首次开谈个人经历、管理心得、技术创新、微信的诞生等

一文读懂微信之父张小龙:失败天才、颠覆者、独裁者、人性操控师


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

posted @ 2023-08-25 15:24 Jack Jiang 阅读(113) | 评论 (0)编辑 收藏

关于MobileIMSDK

MobileIMSDK 是一套专门为移动端开发的开源IM即时通讯框架,超轻量级、高度提炼,一套API优雅支持 UDP 、TCP 、WebSocket 三种协议,支持 iOS、Android、H5、标准Java、小程序、Uniapp,服务端基于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 实现)。

v7.0 版更新内容

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

  • 1)[新增] 新增了支持从相册中选取视频并发送;
  • 2)[bug] 解决了代码中设置聊天界面中消息文字颜色无作用的问题;
  • 3)[bug] 解决了聊天消息列表中查看短视频后返回时,最后一行消息被输入框档住的问题;
  • 4)[bug] 解决了一处因后台任务未显式结束导致的潜在内存泄漏问题;
  • 5)[bug] 当处于群聊界面是,群主更新群名称时,不能直接刷新群聊界面当前的标题上群名称的最新显示;
  • 6)[优化] 登陆界面中,密码输入框增加了密文和明文切换显示功能;
  • 7)[优化] 解决了iOS16.4+系统上因UIAlertView兼容性导致的某些功能中确认事件不能执行的问题;
  • 8)[优化] 解决了从其它界面返回到注册界面的动画跳转时,原界面导航栏变成黑色块的问题;
  • 9)[优化] 解决了聊天界面下方的功能面板打开状态下,再点“+” 号会切换到文本输入,而不是取消功能面板显示的问题;
  • 10)[优化] 升级了图片选择库以适配最新的iOS系统;
  • 11)[优化] 解决了聊天界面中发送大文件后,会立即弹出软键盘并进入文字输入状态的问题;
  • 12)[优化] 查看图片界面中,长按弹出菜单效果UI美化;
  • 13)[优化] 重新优化了闪屏、登录、帮助、忘记密码、注册、注册成功、查找用户、邀请朋友共计8个界面的UI设计;
  • 14)[优化] 其它未提及的ui细节优化和美感提升。

此版部分界面更新(更多截图点此查看):

 

posted @ 2023-08-23 13:28 Jack Jiang 阅读(80) | 评论 (0)编辑 收藏

本文由vivo互联网技术An Peng分享,本文收录时有内容修订和重新排版。

1、引言

本文通过对分布式ID的3种应用场景、实现难点以及9种分布式ID的实现方式进行介绍,并对结合vivo业务场景特性下自研的鲁班分布式ID服务从系统架构、ID生成规则与部分实现源码进行分享,希望为本文的阅读者在分布式ID的方案选型或技术自研提供参考。

 

技术交流:

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

2、专题目录

本文是“IM消息ID技术专题”系列文章的第 7 篇,专题总目录如下:

IM消息ID技术专题(一):微信的海量IM聊天消息序列号生成实践(算法原理篇)

IM消息ID技术专题(二):微信的海量IM聊天消息序列号生成实践(容灾方案篇)

IM消息ID技术专题(三):解密融云IM产品的聊天消息ID生成策略

IM消息ID技术专题(四):深度解密美团的分布式ID生成算法

IM消息ID技术专题(五):开源分布式ID生成器UidGenerator的技术实现

IM消息ID技术专题(六):深度解密滴滴的高性能ID生成器(Tinyid)

IM消息ID技术专题(七):深度解密vivo的自研分布式ID服务(鲁班)》(* 本文)

vivo技术团队分享的其它文章:

vivo的Electron技术栈选型、全方位实践总结

vivo直播系统中IM消息模块的架构实践

3、分布式ID的应用场景

3.1概述

随着系统的业务场景复杂化、架构方案的优化演进,我们在克服问题的过程中,也总会延伸出新的技术诉求。分布式ID也是诞生于这样的IT发展过程中。

在不同的关联模块内,我们需要一个全局唯一的ID来让模块既能并行地解耦运转,也能轻松地进行整合处理。

以下,首先让我们一起回顾这些典型的分布式ID场景。

3.2系统分库分表

随着系统的持续运作,常规的单库单表在支撑更高规模的数量级时,无论是在性能或稳定性上都已经难以为继,需要我们对目标逻辑数据表进行合理的物理拆分。

这些同一业务表数据的拆分,需要有一套完整的 ID生成方案来保证拆分后的各物理表中同一业务ID不相冲突,并能在后续的合并分析中可以方便快捷地计算。

以公司的营销系统的订单为例:当前不但以分销与零售的目标组织区别来进行分库存储,来实现多租户的数据隔离,并且会以订单的业务属性(订货单、退货单、调拔单等等)来进一步分拆订单数据。

具体是:

  • 1)在订单创建的时候,根据这些规则去构造全局唯一ID,创建订单单据并保存在对应的数据库中;
  • 2)在通过订单号查询时,通过ID的规则,快速路由到对应的库表中查询;
  • 3)在BI数仓的统计业务里,又需要汇总这些订单数据进行报表分析。

3.3系统多活部署

无论是面对着全球化的各国数据合规诉求,还是针对容灾高可用的架构设计,我们都会对同一套系统进行多活部署。

多活部署架构的各单元化服务,存储的单据(如订单/出入库单/支付单等)均带有部署区域属性的ID结构去构成全局唯一ID。

创建单据并保存在对应单元的数据库中,在前端根据单据号查询的场景,通过ID的规则,可快速路由到对应的单元区域进行查询。

对应多活部署架构的中心化服务,同步各单元的单据数据时,单据的ID是全局唯一,避免了汇聚数据时的ID冲突。

在公司的系统部署中,公共领域的 BPM 、待办、营销领域的系统都大范围地实施多活部署。

3.4链路跟踪技术

在微服务架构流行的大背景下,此类微服务的应用对比单体应用的调用链路会更长、更复杂,对问题的排查带来了挑战。

应对该场景的解决方案,是会在流量入口处产生全局唯一的TraceID,并在各微服务之间进行透传,进行流量染色与关联,后续通过该全局唯一的TraceID,可快速地查询与关联全链路的调用关系与状态,快速定位根因问题。

在公司的各式各样的监控系统、灰度管理平台、跨进程链路日志中,都会伴随着这么一个技术组件进行支撑服务。

4、分布式ID的核心难点

分布式ID的技术难点比较,这里我简单总结了一下。

最核心的技术难点主要是:

1)唯一性: 保持生成的ID全局唯一,在任何情况下也不会出现重复的值(如防止时间回拔,时钟周期问题);

2)高性能: ID的需求场景多,中心化生成组件后,需要高并发处理,以接近 0ms的响应大规模并发执行;

3)高可用: 作为ID的生产源头,需要100%可用,当接入的业务系统多的时候,很难调整出各方都可接受的停机发布窗口,只能接受无损发布;

4)易接入: 作为逻辑上简单的分布式ID要推广使用,必须强调开箱即用,容易上手;

5)规律性: 不同业务场景生成的ID有其特征,例如有固定的前后缀,固定的位数,这些都需要配置化管理。

5、分布式ID的常见方案

常用系统设计中主要有下图9种ID生成的方式:

以下是详细表格说明之:

上面这些ID算法里,最知名是Twitter的雪花算法(Snowflake)。

Snowflake的核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 ID。

这 64 个 bit 中,其中 1 个 bit 是不用的,然后用其中的 41 bit 作为毫秒数,用 10 bit 作为工作机器 ID,12 bit 作为序列号。

SnowFlake的ID构成:

▲ 图片引用自《深度解密美团的分布式ID生成算法 - 美团为什么不直接用Snowflake算法?

SnowFlake的ID样本:

▲ 图片引用自《深度解密美团的分布式ID生成算法 - 美团为什么不直接用Snowflake算法?

6、自研分布式ID服务(鲁班)的方案

我们的系统跨越了公共、生产制造、营销、供应链、财经等多个领域。

我们在分布式ID诉求下还有如下特点:

  • 1)在业务场景上除了常规的Long类型ID,也需要支持“String类型”、“MixId类型”(后详述)等多种类型的ID生成,每一种类型也需要支持不同的长度的ID;
  • 2)在ID的构成规则上需要涵盖如操作类型、区域、代理等业务属性的标识;需要集中式的配置管理;
  • 3)在一些特定的业务上,基于安全的考虑,还需要在尾部加上随机数来保证ID不能被轻易猜测。

综合参考了业界优秀的开源组件与常用方案均不能满足,为了统一管理这类基础技术组件的诉求,我们选择基于公司业务场景自研一套分布式ID服务:鲁班分布式ID服务。

7、分布式ID服务鲁班的整体架构

鲁班的整体架构如下图所示:

鲁班的架构说明:

8、鲁班支持多种类型的ID规则

目前鲁班分布式ID服务共提供"Long类型"、“String类型”、“MixId类型”等三种主要类型的ID,相关ID构成规则与说明如下。

8.1Long类型

1)构成规则:

静态结构由以下三部分数据组成,组成部分共19位。如下所示。

* 固定部分(4位),由FixPart+ServerPart组成:

  • 1)FixPart(4位):由大区zone 1位/代理 agent 1位/项目 project 1位/应用 app 1位,组成的4位数字编码;
  • 2)ServerPart(4位):用于定义产生全局ID的服务器标识位,服务节点部署时动态分配。

* 动态部分DynPart(13位): System.currentTimeMillis() - 固定配置时间的TimeMillis (可满足使用100年)。

* 自增部分SelfIncreasePart(2位):用于在全局ID的客户端SDK内部自增部分,由客户端SDK控制,业务接入方无感知。共 2位组成。

2)降级机制:

主要自增部分在服务器获取初始值后,由客户端SDK维护,直到自增99后再次访问服务端获取下一轮新的ID以减少服务端交互频率,提升性能,服务端获取失败后抛出异常,接入业务侧需介入进行处理。

3)样例说明:

8.2String类型

1)构成规则:

静态结构由以下五部分数据组成,组成部分共25~27位。

* 固定部分操作位op+FixPart(9~11位):

  • 1)操作位op(2~4位):2~4位由业务方传入的业务类型标识字符;
  • 2)FixPart(7位):业务接入时申请获取,由大区zone 1位,代理 agent 2位,项目 project 2位,应用 app 2位组成。

* 服务器标识部分 ServerPart(1位): 用于定义产生全局ID的服务器标识位,服务节点部署时动态分配A~Z编码。

* 动态部分DynPart(9位):System.currentTimeMillis() - 固定配置时间的TimeMillis ,再转换为32进制字符串(可满足使用100年)。

* 自增部分SelfIncreasePart(3位):用于在全局ID的客户端SDK内部自增部分,由客户端SDK控制,业务接入方无感知。

* 随机部分secureRandomPart(3位):用于在全局ID的客户端SDK的随机部分,由SecureRandom随机生成3位0-9,A-Z字母数字组合的安全随机数,业务接入方无感知。

2)降级机制:

主要自增部分由客户端SDK内部维护,一般情况下只使用001–999 共999个全局ID。也就是每向服务器请求一次,都在客户端内可以自动维护999个唯一的全局ID。

特殊情况下在访问服务器连接出问题的时候,可以使用带字符的自增来做服务器降级处理,使用产生00A, 00B... 0A0, 0A1,0A2....ZZZ. 共有36 * 36 * 36 - 1000 (999纯数字,000不用)= 45656个降级使用的全局ID。

3)样例说明:

8.3MixId类型

1)构成规则:

静态结构由以下三部分数据组成,组成部分共17位。

* 固定部分FixPart(4~6位):

  • 1)操作位op(2~4位):2~4位由业务方传入的业务类型标识字符;
  • 2)FixPart(2位):业务接入时申请获取由代理 agent 2位组成。

* 动态部分DynPart(6位): 生成ID的时间,年(2位)月(2位)日(2位)。

* 自增部分SelfIncreasePart(7位):用于在全局ID的客户端SDK内部自增部分,由客户端SDK控制,业务接入方无感知。

2)降级机制:

无,每次ID产生均需到服务端请求获取,服务端获取失败后抛出异常,接入业务侧需介入进行处理。

3)样例说明:

9、鲁班的业务自定义ID规则实现

鲁班分布式ID服务内置“Long类型”,“String类型”,“MixId类型”等三种长度与规则固定的ID生成算法。除以上三种类型的ID生成算法外,业务侧往往有自定义ID长度与规则的场景诉求。

在鲁班分布式ID服务内置ID生成算法未能满足业务场景时,为了能在该场景快速支持业务,鲁班分布式ID服务提供了业务自定义接口并通过SPI机制在服务运行时动态加载,以实现业务自定义ID生成算法场景的支持。

相关能力的实现设计与接入流程如下。

1)ID的构成部分主要分FixPart、DynPart、SelfIncreasePart三个部分。

2)鲁班分布式ID服务的客户端SDK提供 LuBanGlobalIDClient的接口与getGlobalId(...)/setFixPart(...)/setDynPart(...)/setSelfIncreasePart(...)等四个接口方法。

3)业务侧实现LuBanGlobalIDClient接口内的4个方法,通过SPI机制在业务侧服务进行加载,并向外暴露出HTTP或DUBBO协议的接口。

4)用户在鲁班分布式ID服务管理后台对自定义ID生成算法的类型名称与服务地址信息进行配置,并关联需要使用的AK接入信息。

5)业务侧使用时调用客户端SDK提供的LuBanGlobalIDClient的接口与getGlobalId方法,并传入ID生成算法类型与IdRequest入参对象,鲁班分布式ID服务接收请求后,动态识别与路由到对应ID生产算法的实现服务,并构建对象的ID返回给客户端,完成整个ID生成与获取的过程。

10、鲁班保证ID生成不重复的方案

众所周之,如何保证ID服务生成的ID不碰撞、不重复,是最基本的要求之一。

我们是这样做的:

11、鲁班的无状态无损管理

服务部署的环境在虚拟机上,ip是固定,常规的做法是在配置表里配置ip与机器码的绑定关系(这样在服务扩缩容的时候就需要人为介入操作,存在一定的遗漏配置风险,也带来了一定的运维成本)。

但在容器的部署场景,因为每次部署时IP均是动态变化的,以前通过配置表里ip与机器码的映射关系的配置实现方式显然不能满足运行在容器场景的诉求,故在服务端设计了通过心跳上报实现机器码动态分配的机制,实现服务端节点ip与机器码动态分配、绑定的能力,达成部署自动化与无损发布的目的。

相关流程如下:

需要注意的是:

服务端节点可能因为异常,非正常地退出,对于该场景,这里就需要有一个解绑的过程,当前实现是通过公司平台团队的分布式定时任务服务,检查持续5分钟(可配置)没有上报心跳的机器码分配节点进行数据库绑定信息清理的逻辑,重置相关机器码的位置供后续注册绑定使用。

12、鲁班的使用方接入SDK的设计

SDK设计主要以"接入快捷,使用简单"的原则进行设计。

1)接入时:

鲁班分布式ID服务提供了spring-starter包,应用只需再pom文件依赖该starter,在启动类里添加@EnableGlobalClient,并配置AK/SK等租户参数即可完成接入。

同时鲁班分布式ID服务提供Dubbo & Http的调用方式,通过在启动注解配置accessType为HTTP/DUBBO来确定,SDK自动加载相关依赖。

2)使用时:

根据"Long"、"String"、"MixId"等三种id类型分别提供GlobalIdLongClient、GlobalIdStringClient、GlobalIdMixIDClient等三个客户端对象,并封装了统一的入参RequestDTO对象,业务系统使用时只需构建对应Id类型的RequestDTO对象(支持链式构建),并调用对应id类型的客户端对象getGlobalID(GlobalBaseRequestDTO globalBaseRequestDTO)方法,即可完成ID的构建。

Long类型Id获取代码示例:

packagecom.vivo.it.demo.controller;

 

importcom.vivo.it.platform.luban.id.client.GlobalIdLongClient;

importcom.vivo.it.platform.luban.id.dto.GlobalLongIDRequestDTO;

importorg.springframework.beans.factory.annotation.Autowired;

importorg.springframework.web.bind.annotation.RequestMapping;

 

@RequestMapping("/globalId")

publicclassGlobalIdDemoController {

 

    @Autowired

    privateGlobalIdLongClient globalIdLongClient;

 

    @RequestMapping("/getLongId")

    publicString getLongId() {

        GlobalLongIDRequestDTO globalLongIDRequestDTO = GlobalLongIDRequestDTO.Builder()

                .setAgent("1") //代理,接入申请时确定

                .setZone("0") //大区,接入申请时确定

                .setApp("8") //应用,接入申请时确定

                .setProject("7") //项目,接入申请时确定

                .setIdNumber(2); //当次返回的id数量,只对getGlobalIDQueue有效,对getGlobalID(...)无效

        longlongId = globalIdLongClient.getGlobalID(globalLongIDRequestDTO);

        returnString.valueOf(longId);

    }

}

13、鲁班的关键运行性能优化场景

13.1内存使用优化

在项目上线初时,经常发生FGC,导致服务停顿,获取ID超时。

经过分析,鲁班分布式ID服务的服务端主要为内存敏感的应用,当高并发请求时,过多对象进入老年代从而触发FGC。

经过排查主要是JVM内存参数上线时是使用默认的,没有经过优化配置,JVM初始化的内存较少,高并发请求时JVM频繁触发内存重分配,相关的对象也流程老年代导致最终频繁发送FGC。

对于这个场景的优化思路主要是要相关内存对象在年轻代时就快速经过YGC回收,尽量少的对象进行老年代而引起FGC。

基于以上的思路主要做了以下的优化:

  • 1)增大JVM初始化内存(-Xms,容器场景里为-XX:InitialRAMPercentage);
  • 2)增大年轻代内存(-Xmn);
  • 3)优化代码,减少代码里临时对象的复制与创建。

13.2锁颗粒度优化

客户端SDK再自增值使用完或一定时间后会向服务端请求新的id生成,这个时候需要保证该次请求在多线程并发时是只请求一次。

当前设计是基于用户申请ID的接入配置,组成为key,去获取对应key的对象锁,以减少同步代码块锁的粒度,避免不同接入配置去在并发去远程获取新的id时,锁粒度过大,造成线程的阻塞,从而提升在高并发场景下的性能。

14、应用现状

当前鲁班分布式ID服务日均ID生成量亿级,平均RT在0~1ms内,单节点可支持 万级QPS,已全面应用在公司IT内部营销订单、支付单据、库存单据、履约单据、资产管理编码等多个领域的业务场景。

15、未来规划

在可用性方面,当前鲁班分布式ID服务仍对Redis、Mysql等外部DB组件有一定的依赖(如应用接入配置信息、MixId类型自增部分ID计数器),规划在该依赖极端宕机的场景下,鲁班分布式ID服务仍能有一些降级策略,为业务提供可用的服务。

同时基于业务场景的诉求,支持标准形式的雪花算法等ID类型。

16、参考资料

[1] 微信的海量IM聊天消息序列号生成实践(算法原理篇)

[2] 解密融云IM产品的聊天消息ID生成策略

[3] 深度解密美团的分布式ID生成算法

[4] 开源分布式ID生成器UidGenerator的技术实现

[5] 深度解密滴滴的高性能ID生成器(Tinyid)


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

posted @ 2023-08-16 11:31 Jack Jiang 阅读(111) | 评论 (0)编辑 收藏

本文由腾讯技术工程师remyliu分享,原题“微信万亿数据仓库架构设计与实现”,本文收录时有内容修订和重新排版。

1、引言

没有足够的特征数据,安全策略将是“无根之木,无源之水”。

微信的安全数据特征仓库应运而生,并成为整个安全业务的特征数据存储中心,每天服务了万亿级的特征数据读写请求,为整个微信安全策略提供了可靠的数据支撑,是微信安全基石之所在。

然而,微信安全特征数据仓库不仅仅是一个存储中心,更是一个特征管理和数据质量管理的中心。

微信的安全数据特征仓库在演进过程中,一直致力于提升特征管理能力和数据质量保障,实现了特征的管理、共享、分析和数据质量检测等功能。

本文将介绍微信的安全数据特征仓库的背景起源、技术演进、当前的架构设计和实践,以及数据质量保证系统的实现。希望给中大型IM系统的安全数据特征仓库的设计带来启发。

 
 
技术交流:

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

2、安全策略开发流程

安全业务的核心逻辑是在安全策略中实现的。整个的策略开发流程包括特征数据的收集,安全策略的编写实现,和策略的反馈评估(如下图所示)。

其中特征数据的收集是必不可少的环节,数据的质量将直接影响安全策略的效果。

特征数据收集主要包括:

  • 1)数据接入;
  • 2)特征的计算;
  • 3)特征的存储。

传统特征数据收集流程:

如上图所示:在数据仓库还未建立时,业务同学通过消费离线存储mmdata和tdw接入数据,通过Flink流式计算或者自定义模块对数据进行加工,计算出需要的特征,最终存储到自行维护的KV,然后在安全策略平台上编写安全策略,读取KV中的数据, 实现需要的安全逻辑。

3、为什么需要安全特征数据仓库

前面提到在还未建立数据仓库时,业务同学都按照自己的方式去存储计算出的特征,大多通过自行申请部署KV来存储(如下图中的架构):如A同学把部署一套KV集群,存储特征到KV表中,B同学把特征存储到同KV集群的不同表中,C同学又额外申请了另外一套KV集群存储。

传统安全后台(各业务特征分散存储):

这种特征的分散存储,导致业务同学只了解自己熟悉的特征,难以交流和共享,特征缺乏统一的管理,数据质量难以保证,不同的存储方式,也导致特征访问接口的混乱,业务系统的可靠性也难以保证。

针对上述的问题:我们希望把所有业务的特征,按统一的规范,建立统一的存储,方便特征的共享、管理和维护、并建立数据质量保障体系, 为策略提供可靠的数据。所以我们需要开发数据仓库。

问题和目标:

4、安全业务的后台架构

当前,我们已经把所有的安全策略统一到安全策略平台进行开发和管理,特征数据的接入和计算统一到了Flink实时计算平台和特征平台。

数据仓库作为承上启下的部分,是整个业务体系中不可或缺的部分。

总结一下它作用就是:

  • 1)对上为在安全策略平台上的安全策略提供了数据读写;
  • 2)对下为实时计算平台和特征平台计算输出的特征提供了存储。

安全业务后台架构:

5、安全特征数据仓库的存储选型

微信的安全业务特征数据主要有2种类型:

  • 1)离线特征:用来满足离线计算数据导入线上实时使用的需求(通常特征离线计算,定期的批量后台上线,提供在线读,但不支持实时写入);
  • 2)实时特征:用来满足实时的在线读写需求。

微信内部有多种非常成熟稳定的自研KV:实时读写KV(简称实时KV)、离线写实时读KV(简称离线KV)、***KV等等,这些KV已经在多个业务被验证,有非常好的性能和可靠性,有团队做长期的维护,为此数据仓库的底层存储采用了微信自研的KV。

微信自研的KV主要特点如下:

具体就是:

  • 1)离线KV适合离线特征要求的场景:拥有非常好的读性能,并且提供了版本管理功能,在处理有问题数据时可以非常方便的可以回退版本,采用这种KV存储时,value一般是protobuf对象,新增特征时可以在pb中增加字段;
  • 2)实时KV适合实时特征的场景:在线实时读写性能优秀,而且支持数据过期淘汰,该KV提供了类MySQL表的概念,KV表定义类似于一个MySQL表,而每一个安全业务特征刚好可以用表的一个字段表示。

6、数据仓库的架构设计和演进

6.1统一存储统一接口

数据仓库第一个版本,针对特征存储分散访问接口混乱问题,首先部署了公共的实时KV/离线KV集群,并实现了一个接入层。新增特征和历史特征放到公共的KV存储集群,并且在接入层屏蔽了底层KV的细节,提供了统一的读写特征的接口。

数据仓库架构1.0版:

接入层支持任意多个KV集群,支持多个表,为屏蔽KV的细节,接入层为每个特征分配唯一的标识<sceneid, columnid>,读写特征数据使用唯一标识进行,不需要关注KV类型和KV表ID,方便业务的接入使用。

统一接口:

接入层还实现配置管理、参数校验、模块校验、权限校验、流水上报、PV统计等功能。

6.2读写分离和多IDC同步

1)读写分离:数据仓库的读请求量远远多于实时写入量,为了提高性能,减少读写之间的相互影响,接入层做了读写分离,将读和写接口拆分到两个模块。

2)数据多IDC同步:数据仓库和业务都采用的是多IDC部署,为了不降低查询性能,不希望业务跨IDC访问存储,所以底层的KV也是多IDC部署。这里就带来一个问题,特征数据如何在多IDC的KV之间进行同步? 例如业务在上海写入一个特征,希望在深圳也能读到这个特征。

这里按特征类型进行分类处理:

  • 1)离线特征数据同步:离线特征数据上线流程是通过离线计算在文件系统中生成一个文件,然后将文件导入到离线KV, 而离线KV支持多个IDC共享同一份数据,数据文件只需要生成一份,所有IDC的离线KV拉取同一个文件,新数据最终能同步到所有IDC上;
  • 2)实时特征数据同步:实时特征的同步采用微信自研的分布式队列组件,该组件提供了高可靠、高可用、高吞吐、低延时的数据消息队列服务。数据仓库写接入模块在写入数据时,同时将数据写一份到分布式队列,使用队列做跨IDC的数据同步,在其他IDC启动进程消费队列中的数据,写入到本IDC的实时KV,实现实时特征数据的同步。

数据仓库架构2.0版:

6.3异步写和替代分布式队列

1)异步写入:前一个版本中实时特征是同步写入,影响业务的性能,业务希望是异步写入。

2)替代分布式队列:前一个版本中分布式队列采用的是公共的集群,众多业务使用,出现过数据仓库受干扰影响特征数据同步。

为此:在数据仓库中新增一个异步消息队列模块写MQ,用于异步写入。和分布式队列相比,MQ更轻量,而且MQ我们可以自行维护,更可控。所以新架构中通过MQ实现实时特征的多IDC数据的同步,替代了分布式队列,保证数据同步不受其他业务影响。

数据仓库架构3.0版:

6.4运营系统

前面3个版本解决了特征存储分散、读写接口不统一、数据同步、读写性能问题,但是特征的上线依然采用的是配置发布上线的方式,效率依然低效。

更重要的是特征缺乏统一的管理,共享困难,难以满足业务的需求。

业务常常也有各种疑问:

为此数据仓库新增运营系统模块,实现了特征申请、特征上线、特征管理&分析、特征值查询/修改、特征数据质量管理等功能。

数据仓库架构4.0版:

1)特征申请:

用户不再需要手动的修改配置文件来新增特征,可直接通过WEB页面申请,填写必要的特征信息,通过通用审批系统进行审批。

2)特征上线:

用户不在需要手动的发布配置上线特征,无论是新增的实时特征还是离线特征,审批通过后将自动化的上线,提升体验和效率。

3)特征管理:

特征管理支持对特征meta信息进行查询和修改,包括特征所属的业务分类(索引)、特征类型、特征负责人、给特征打tag等等,业务可以方便的查询需要特征信息,避免重复的计算,方便各业务共享特征。

▲ 特征管理页面

4)特征分析:

追踪特征的原始数据来源、计算过程、数据流路径、最终的存储信息等等, 可以追踪特征完整生产流程。

▲ 特征分析页面

5)特征值查询&修改:运营系统支持在WEB页面查询特征值和修改特征值;

▲ 特征值查询页面

6)特征数据质量管理:保障数据质量, 下一章节详细讲述。

7、数据质量保障手段1:安全特征标准化

数据仓库主要通过两个方面来保障数据质量:特征的标准化和数据空跑系统。本节分享特征的标准化。

特征的标准化是保证数据仓库数据质量的手段之一,标准化是指对数据仓库中的特征进行规范化处理,使得特征能够达到一致性、可重复性等标准,从而提高数据的可靠性和准确性。

对于新增实时/离线特征:数据仓库制定了的特征规范文档,并按规范文档的要求,特征申请/管理页面必须正确的补充完整特征信息,如特征类型、业务分类等等,后台对每个特征都会进行校验,不符合规范的特征无法录入。

另外:数据仓库还提供了接入编程指导文档,并给出完整的C++编程实例,致力于提供标准化的编程最佳实践。

8、数据质量保障手段2:数据空跑系统

离线特征数据来自于业务离线计算在分布式文件系统中生成数据文件,然后将文件上线。

历史上曾因为生成的数据文件存在错误,存在错误的文件数据被上线到离线KV,导致策略出现故障。

为了保障离线特征数据的质量,数据仓库设计了一套空跑系统,在上线前对数据文件进行检查,避免存在问题的数据上线到现网。

数据空跑架构:

数据空跑架构如上图所示,离线特征数据的上线也纳入到了运营系统的管理中。

整个的空跑流程如下。

1)业务发起数据上线:运营系统将数据上线到备用的离线KV表,也就是用于空跑的KV表;

2)打开空跑开关:按一定的比率采样现网的读请求,旁路到新增的读MQ模块,该模块读空跑表的数据,和当前现网做对比, 分析差异率。这里采用的动态采样, 如果表的PV高则采样率低,PV低则采样率高或者100%采样,避免请求量小的表无法进行空跑,而请求量大的表空跑流量太高又消耗太多资源。

3)计算和分析差异率:如果差异率超过了阈值,就自动的拦截数据上线,如果阈值检查通过,就继续后续的检查流程,最终自动上线数据文件到现网离线KV。

差异率示例会如下图(详细的展示了具体的差异细节):

离线特征数据上线完整流程:

完整的数据上线流程如上图所示:空跑差异检测通过后,需要检查数据文件完整性,防止文件被修改或者覆盖,最后数据再上线到现网数据仓库系统,通知业务数据上线成功。如果中间任何一个步骤出错将告警给业务负责人,提醒人工介入处理。

9、本文小结

微信后台安全特征数据仓库将分散的特征全部集中统一管理,提供统一的访问接口,标准化每个一个特征,建立了统一的规范。

并且在此基础保障了数据的质量,夯实了整个安全业务的基础,助力一站式的数据-策略开发,极大的提升了安全对抗的效率,实现了数据价值的最大化。

10、相关资料

[1] 探讨组合加密算法在IM中的应用

[2] IM聊天系统安全手段之通信连接层加密技术

[3] IM聊天系统安全手段之传输内容端到端加密技术

[4] 理论联系实际:一套典型的IM通信协议设计详解(含安全层设计)

[5] 微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解

[6] 移动端安全通信的利器——端到端加密(E2EE)技术详解

[7] 通俗易懂:一篇掌握即时通讯的消息传输安全原理

[8] 基于Netty的IM聊天加密技术学习:一文理清常见的加密概念、术语等

[9] 手把手教你为基于Netty的IM生成自签名SSL/TLS证书

11、微信团队的其它技术文章

IM全文检索技术专题(一):微信移动端的全文检索优化之路

IM全文检索技术专题(二):微信移动端的全文检索多音字问题解决方案

微信团队分享:iOS版微信的高性能通用key-value组件技术实践

微信团队分享:iOS版微信是如何防止特殊字符导致的炸群、APP崩溃的?

微信团队原创分享:iOS版微信的内存监控系统技术实践

iOS后台唤醒实战:微信收款到账语音提醒技术总结

微信团队分享:微信Android版小视频编码填过的那些坑

企业微信客户端中组织架构数据的同步更新方案优化实战

微信团队披露:微信界面卡死超级bug“15。。。。”的来龙去脉

微信后台基于时间序的海量数据冷热分级架构设计实践

微信团队原创分享:Android版微信的臃肿之困与模块化实践之路

微信后台团队:微信后台异步消息队列的优化升级实践分享

微信团队原创分享:微信客户端SQLite数据库损坏修复实践

微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解

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

iOS版微信安装包“减肥”实战记录

移动端IM实践:iOS版微信界面卡顿监测方案

微信“红包照片”背后的技术难题

移动端IM实践:iOS版微信小视频功能技术方案实录

移动端IM实践:Android版微信如何大幅提升交互性能(一)

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

IPv6技术详解:基本概念、应用现状、技术实践(上篇)

微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

微信团队分享:Kotlin渐被认可,Android版微信的技术尝鲜之旅

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

微信团队分享:极致优化,iOS版微信编译速度3倍提升的实践总结

IM“扫一扫”功能很好做?看看微信“扫一扫识物”的完整技术实现

微信团队分享:微信直播聊天室单房间1500万在线的消息架构演进之路

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

IM全文检索技术专题(四):微信iOS端的最新全文检索技术优化实践

微信团队分享:微信后台在海量并发请求下是如何做到不崩溃的

微信Windows端IM消息数据库的优化实践:查询慢、体积大、文件损坏等

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

posted @ 2023-08-11 11:41 Jack Jiang 阅读(80) | 评论 (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 实现)。

v9.0 版更新内容

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

(1)Android端主要更新内容适配最新Android系统等多项升级和优化】:

  • 1)[升级] 提升targetSdkVersion至33;
  • 2)[升级] 适配最新Andriod 13+系统的动态权限申请逻辑;
  • 3)[升级] 解决了Android13+系统全面屏手机上,APP下方出现大约15dp的黑色空白问题;
  • 4)[升级] 解决了Android13+手机上无法显示Notification通知的问题(Android13新增了通知权限,需动态申请后才能显示);
  • 5)[优化] 重新优化了闪屏、登录、帮助、忘记密码、注册、注册成功、查找用户、实时语音、实时视频等共计13个界面的UI设计;
  • 6)[优化] 其它未提及的ui细节优化和美感提升。
  • 7)[bug] 解决了从好友列表中打开群聊界面,不显示“返回”按钮的问题。
  • 8)[bug] 解决了当处于群聊界面时,群主更新群名称时,不能同步刷新群聊界面标题上的群名称显示。

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

  • 1)[优化] 解决了桥接模式下与最新rabbitmq库不兼容从而断线重连不成功,导致MQ中消息堆积的问题:
  • 2)[优化] 解决了桥接模式下MQ断线自动恢复时未主动清理Chanel,导致Chanel越来越多的问题;

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

posted @ 2023-07-26 12:53 Jack Jiang 阅读(94) | 评论 (0)编辑 收藏

本文由网易云信李兴分享,原题“深度剖析“圈组”深度剖析“圈组”关系系统设计”,为了提升内容品质,本文收录时有修订。

1、引言

上篇《百万级成员实时社群技术实现(消息系统篇)》中,我们分享了云信“圈组”(“圈组”是云信的类Discord产品实现方案)消息系统的技术设计和实践。

本篇接上篇,将继续分享云信“圈组”的关系系统在技术架构上的设计和实现。希望带给你启发。

 
技术交流:

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

2、系列文章

本文是系列文章中的第 3 篇:

3、作者介绍

李兴:网易云信资深服务端开发工程师,毕业于浙江大学,硕士毕业后加入网易,负责云信 IM等业务的服务器开发。专注于即时通讯以及相关中间件等技术。

4、“圈组”的关系业务特点

4.1概述

在互联网行业盛行一句话,技术是为业务服务的。具体到技术实践中,一个重要方面就是要面向业务特点设计技术方案。

因此,想要了解“圈组”的关系系统设计,就要首先了解“圈组”的关系业务特点。

4.2业务特点

“圈组”的关系业务特点是什么?

  • 1)其一:是关系复杂,即关系主体多、管理机制杂、联动耦合重;
  • 2)其二:是规模巨大,即成员数量可达百万量级、变更批量可达百万量级。

所谓关系复杂,具体来讲:首先是关系主体多。

在“圈组”业务中,关系主体包括:

  • 1)服务器:承载社群关系,负责社群成员关系维护;
  • 2)频道:从属于服务器,承载内容关系,负责内容互动关系维护;
  • 3)身份组:可从属于服务器或频道,承载身份权限关系,负责身份设定和权限配置;
  • 4)频道分组:从属于服务器,又关联一组频道,承载频道模版关系,负责分类频道和共享配置。

其次是:管理机制杂。

在“圈组”业务中,仅就成员管理机制而言:

  • 1)服务器成员采用邀请/申请机制;
  • 2)频道成员采用公开/私密模式+黑/白名单机制;
  • 3)身份组成员采用加入/移出机制;
  • 4)频道分组成员与频道成员采用同步机制。

最后是:联动耦合。

在“圈组”业务中,以频道成员维护为例:频道成员不仅受到公开/私密模式+黑/白名单配置变更的影响,而且会伴随服务器成员变更、身份组变更、身份组成员变更等做联动变更。

所谓规模巨大,具体来讲:

  • 1)一方面:成员数量可达百万量级(在“圈组”业务中,服务器成员数量可以达到数百万人);
  • 2)进一步:百万成员服务器下的频道和身份组,其成员数量也可以达到百万量级;
  • 3)另一面:是变更批量可达百万量级。

所谓变更批量可达百万量级,包括:删除百万成员的服务器/频道/身份组,增删频道/频道分组黑白名单中的百万成员身份组等。

从“圈组”关系业务的两大特点出发,可以发现:“圈组”关系是不同于群组关系的全新业务场景,将会面临全新的技术难点。

5、“圈组”关系系统的技术难点

5.1概述

技术难点主要有两个方面:

  • 1)其一:是多关系主体、多管理机制在层级结构下关联耦合导致的业务逻辑的复杂性;
  • 2)其二:是成员数量、变更批量规模巨大导致的业务处理在时间、空间、资源等开销上的复杂性。

5.2业务逻辑复杂性

1)首先“圈组”有多级结构:

包括服务器/频道二级结构、服务器/频道分组/频道三级结构等。

单个关系主体变更,不仅涉及自身的变更,而且涉及上下级关系主体的变更,可以说牵一发动全身。相比而言,群组是没有层级的,群组变更只要独善其身就好。

2)其次“圈组”有身份组:

一个身份组是一组有共同权限的服务器成员的集合,不同身份组的成员可以相互交叉,身份组会作为整体参与到成员管理中。

也就是说,成员变更不再只是个别成员(1-100人)的进入退出,将会出现整组成员(1-1000000人)的大进大出。相比而言,群组是没有身份组的,群组特殊成员包括群主、管理员等也都数量不多、互不重复。

3)最后“圈组”有多种成员管理机制:

服务器成员和身份组成员的管理机制与群组类似,频道成员和频道分组成员的管理机制却是全新模式。

频道分为公开和私密两种:

  • 1)公开模式默认允许所有服务器成员可见,但要排除黑名单身份组和黑名单成员;
  • 2)私密模式默认不许所有服务器成员可见,但要放开白名单身份组和白名单成员。

除了受到公开/私密模式+黑/白名单配置变更的影响,频道成员也受到所依赖的关系主体(服务器成员、身份组、身份组成员)变更的影响。进一步,频道成员还受到所同步的频道分组变更的影响。相比而言,群组成员的邀请/申请机制,可以说是小巫见大巫。

5.3业务处理复杂性

1)首先是成员数量规模巨大:

由于成员数量可达百万,整个成员列表的存储空间开销、网络传输开销,变得十分巨大,不论全量成员列表数据的服务器缓存,还是全量成员列表数据从服务器到客户端的同步,都将变得难以实现。

2)其次是变更批量规模巨大:

单次接口调用的关系变更,可能伴随百万规模的联动关系变更,这会导致巨大的处理时间开销、计算资源开销,不论所有变更同步完成处理,还是所有变更单机完成处理,都将变得难以实现。

3)最后是通知消息规模巨大:

关系系统不仅需要做关系变更的数据处理,而且需要通知变更结果到客户端。由于在“圈组”中各个关系主体的成员数量规模巨大,使得单个变更需要扩散为百万通知同时下发,所需计算资源开销、网络传输开销十分巨大。

相比而言,群组方案因为成员数量、变更批量规模有限,并不涉及这些技术难点。

从“圈组”关系系统的两个方面技术难点出发,可以发现:“圈组”关系系统面临不同于群组的全新技术难点,想要解决这些技术难点,需要创新的技术方案。

6、“圈组”的整体架构

“圈组”方案的整体架构:

上面展示了“圈组”方案的整体架构,可以看到“圈组”整体是一个分层架构。

从上到下看:

1)客户层:包括可供客户端集成的移动端、桌面端、跨平台 SDK,和可供服务器调用的 OpenAPI;

2)接入层:包括 LBS 服务、长连接服务和 API 网关,分别对应客户端 SDK 和用户服务器;

3)网络层:包括自研的全球实时传输网络 WE-CAN;

4)业务层:包括用于 SDK 业务处理的 App 服务和用于 OpenAPI 业务处理的 WebServer 服务;

5)服务层:划分有登录、消息、关系、身份组、支持等服务模块,每个服务模块包括有多个微服务或消费者;

6)基础设施层:包括系统所用的数据库和中间件。

7、“圈组”关系系统的架构

上图展示了“圈组”关系系统的技术架构。可以看到“圈组”关系系统遍及“圈组”架构的接入层、网络层、业务层和服务层。

从功能出发整体上分为三个部分:

  • 1)关系操作同步处理模块;
  • 2)关系事件异步处理模块;
  • 3)变更通知在线广播模块。

下面具体讨论三个方案要点的技术细节,包括频道成员关系管理、变更通知在线广播和关系数据云端检索。

8、关系系统技术实现1:频道成员关系管理

频道成员关系管理,是“圈组”中极具挑战性的问题。

频道成员涉及多关系主体、多管理机制、联动变更耦合严重,成员数量和变更批量规模巨大,可以说是“圈组”关系业务的典型代表。

频道成员关系管理在业务逻辑和业务处理两方面的复杂性可想而知。

针对频道成员关系管理问题,“圈组”设计了两大机制加以解决。

包括:

  • 1)终态维护与过渡计算相结合机制;
  • 2)事件按序异步并行处理机制。

终态维护与过渡计算相结合机制,具体来讲:频道成员关系数据最终被维护在持久化数据库中,并在频道成员没有变更的终态阶段,直接支持频道成员数据的查询需求。当频道成员发生变更时,由于变更逻辑和变更处理两方面的复杂性,完成关系变更需要一段时间,称之为过渡阶段。

在过渡阶段,数据库持久化的频道成员表数据是不完全准确的,无法直接支持频道成员数据的查询需求。此时转为由频道成员配置元数据直接计算频道成员以支持查询需求。因为频道成员配置元数据的变更是同步处理的,所以在过渡阶段由频道成员配置元数据直接计算频道成员可以保证查询准确性。通过将频道成员关系管理分为终态和过渡两个阶段,并在不同阶段采用不同频道成员查询方案,不仅解决了单纯由计算获取频道成员资源开销大的问题,而且解决了频道成员变更延迟导致由数据库获取频道成员结果不准确的问题。

除了频道成员的获取查询问题,频道成员的变更处理也很重要。

事件按序异步并行处理机制,就是用于解决频道成员的变更处理问题:

  • 1)其一:通过将影响频道成员关系的变更操作分层级、系统化定义为变更事件,显著降低频道成员关系管理的业务逻辑复杂性;
  • 2)其二:通过 ID 哈希、分布式锁、事件版本号控制等保证变更事件的按序处理,有效避免事件处理乱序导致的持久化数据错误;
  • 3)其三:通过消息队列中转事件并在消费者上异步处理,有效解决联动变更批量过大导致接口调用阻塞的问题;
  • 4)其四:通过在单个事件处理中的多线程并行加速和本地缓存重用加速,显著缩短频道成员关系变更的时间延迟。

9、关系系统技术实现2:变更通知在线广播

关系系统不仅需要做关系变更的数据处理,而且需要通知变更结果到客户端。

在百万量级的“圈组”关系中,每条关系变更通知,都会面临海量扩散的接收者。除了通知分发量激增,不同接收者对于通知接收的缓急差异也值得关注。

针对变更通知在线广播问题, 我们设计了两大机制:

  • 1)变更分类通知机制;
  • 2)数据通知拉取机制。

在变更分类通知机制中:一方面,根据相关人员在变更中的角色,划分为参与者和观察者分类做通知,即参与者一定通知,观察者按照订阅需求通知。其中参与者一般是变更中的少数关键人员,观察者则是除了参与者之外可以看到变更结果的其它人员。通过分类通知,不同接收者对于通知接收的缓急差异得到合理关注,变更通知的扩散规模也得到精准缩小。

另一方面,观察者按照订阅需求通知,可以充分发挥“圈组”的在线广播订阅模式的优势。所谓在线广播订阅模式,是指在用户登陆之后,需要订阅感兴趣的服务器/频道的通知,“圈组”系统会记录下这些订阅信息,当有新的通知时,“圈组”系统通过订阅关系而非成员列表 + 在线状态获取需要在线广播的用户列表,从而不再需要遍历服务器/频道的所有成员及其在线状态。通过采用在线广播订阅模式,不仅显著降低变更通知在线广播的计算开销和带宽开销,而且可以实现变更通知在线广播在长连接服务集群的并行加速和水平扩展。

变更通知的最终目的是将变更后的数据给到客户端:不同于群组,“圈组”并不将变更后的数据直接由通知带给客户端,而是采用通知客户端有变更再触发客户端拉取结果数据的机制。

究其原因,不同于群组将关系数据全量同步到客户端,“圈组”客户端不再存储关系数据的全量镜像,因此不再需要通过全量历史 + 增量变更的方式维护客户端上的关系数据全量镜像。

与此同时,订阅变更通知的观察者也并不是每时每刻都要关心变更的结果数据,关心某次变更结果数据的观察者相比订阅变更通知的观察者在数量上会少很多,因此,数据通知拉取机制会显著降低变更通知的资源开销。

另外,相比带变更数据通知,只通知有变更,便于直接合并相同类型的通知,而不用关心合并变更数据存在的时序、并发等问题,如此,数据通知拉取机制可以通过短时间内通知合并显著降低服务器在线广播开销和客户端通知接收开销。

10、关系系统技术实现3:关系数据云端检索

在“圈组”中,伴随关系规模的大幅增长,群组基于应用服务器全量查询关系数据或客户端全量同步关系数据实现精准查询和灵活排序的方案不再适用。

对此,“圈组”采用了关系数据云端检索的方案。

“圈组”关系数据云端检索方案可支持服务器、频道、成员等的检索能力。

从检索场景上分,包括:

  • 1)广场检索:用于检索感兴趣的服务器。可以根据名称、类别等多种维度检索。检索结果可以根据预定义字段(成员数量等)或自定义值(数据热度等)等进行排序;
  • 2)内部检索:用于检索用户可见的服务器、频道、成员等。可以根据名称、昵称等多种维度检索。检索结果可以根据预定义字段(创建时间等)或自定义值(数据热度等)等进行排序。

11、相关资料

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

[2] 以微博类应用场景为例,总结海量社交系统的架构设计步骤

[3] IM开发技术学习:揭秘微信朋友圈这种信息推流背后的系统设计

[4] 直播系统聊天技术(四):百度直播的海量用户实时消息系统架构演进实践

[5] 喜马拉雅亿级用户量的离线消息推送系统架构设计实践

[6] 企业微信客户端中组织架构数据的同步更新方案优化实战

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


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

posted @ 2023-07-21 14:56 Jack Jiang 阅读(93) | 评论 (0)编辑 收藏

本文由网易云信资深服务器开发工程师曹佳俊分享,原题“深度剖析“圈组”消息系统设计 | “圈组”技术系列文章”,为了提升内容品质,本文有修订和删节。

1、引言

鉴于实时社群产品Discord在IM垂直应用领域的爆火,类似的需求越来越多,云信的“圈组”就是针对这种应用场景的技术产品。

“圈组”产品发布后获得了很大的关注,很多云信用户在接入SDK的同时对于“圈组”的底层技术细节和原理也非常关注,为此我们决定推出“圈组”相关的技术文章,分享云信在“圈组”技术设计上的一些思考和实践。

本文是序列文章的第2篇,将要分享的是云信的实时社群产品“圈组”(“圈组”云信的类Discord产品实现方案)的消息系统技术设计实践。

 
 技术交流:

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

2、系列文章

本文是系列文章中的第 2 篇:

3、作者介绍

曹佳俊:网易云信资深服务器开发工程师,毕业于中国科学院,硕士毕业后加入网易,负责云信 IM/RTC 信令等业务的服务器开发。专注于即时通讯、RTC 信令以及相关中间件等技术,是云信开源项目 Camellia 的作者。

4、“圈组”的技术特点

在介绍“圈组”的技术细节之前,我们先了解一下圈组的技术特点。

“圈组”产品最大的特点是什么?

  • 1)首先:是 server/channel 的二级结构;
  • 2)其次:是构建在二级结构之上的大规模社群(单个 server 数十万甚至上百万成员);
  • 3)以及:使用复杂的身份组系统来管理如此规模的社群组织和成员。

那么对于这样一个新颖的 IM 系统,在技术上应该如何实现呢?

5、“圈组”和传统IM群组的技术差异

5.1概述

一种简单的思路是改造已有的 IM 系统,对于“圈组”这样的类 Discord 社群,第一个思路是拓展我们的群组功能,猛一看在很多方面确实挺像的。

我们做了个简单的对比:

从上面的表格可以看到,“圈组”和群组最大的不同:

  • 1)是容量的区别;
  • 2)是二级结构。

其他的诸如身份组、个性化推送策略,似乎只要适配的做一下就可以了。

那么是不是只要想办法提升一下群组的容量,再在业务层封装一下二级结构就可以了呢?

答案显然是否定的,或者至少说基于群组去扩展不是一个很好的想法。

5.2二级结构的差异

首先是二级结构。

在类 Discord 的二级结构中,成员的管理在 server 层,而 channel 成员是继承自 server 的,而且在 channel 之上还有很多可见性的配置(我们的“圈组”提供了黑白名单机制,而Discord 则提供了查看频道权限)。

在这种机制之下,任何 server 层面的成员变动,都可能影响全部或者部分频道的成员列表。

面对这种复杂的结构,群组有两种思路去实现:

  • 1)一种是 N 个群,逻辑上隶属于同一个 server;
  • 2)一种是一个群映射为一个 server。

不管哪种方式,先不说消息投递这块的逻辑,仅成员管理上逻辑的耦合和交织的复杂性,足以劝退任何人。

5.3容量的差异

常规IM群组的容量一般只有数百,最多可以扩展到数千。

对于IM群组成员的管理,我们一般采取全量+增量同步相结合的方案,客户端和服务器映射到相同的群组镜像(群信息+群成员等)。此时很多操作,例如群成员的展示、检索,消息的艾特等,都可以基于纯客户端进行。

而“圈组”要求几十万甚至上百万的容量,显然客户端无法一次性获取到所有成员,如果你一次性加入多个 server,那成员的数量将更加膨胀。

因此在“圈组”这种大规模社群的设计中,很多逻辑都会转向云端,此时不管是 SDK 还是服务器,均需要修改原有的设计逻辑。

5.4消息规模差异

此外,大规模社群带来的是消息爆炸。

在原有的IM群组设计中,假设一个人同时加入了 1000 个群,那么这 1000 个群内的所有消息均会在第一时间下发给给客户端。

但是在一般的业务场景中,不会所有的群都同时活跃,假设这 1000 个群变成了 1000 个服务器/频道,作为一种社群组织,同时活跃的可能性将大大增加,而且每个服务器/频道的人数远远超过普通的群组,叠加之后带来的消息爆炸现象在原有的群组体系中将带来极大的压力。

压力包括多方面:

  • 1)首先是海量消息的存储压力;
  • 2)其次是海量消息在线广播/离线消息推送带来的带宽和服务器压力;
  • 3)以及客户端在面对大量消息冲击时如何有效地接受和合理的展示。

5.5小结

除了容量、二级结构、消息规模,包括身份组、成员管理、个性化推送策略等等都存在巨大差异。

是否真的适合在群组中添加这些复杂逻辑呢,强行绑定在一起会不会既没有一个好用的类 Discord 平台,也使得原始的群组功能繁杂,反而降低了易用性呢?

经过上面的一些分析,我们基本可以得出一个结论:在已有的群组基础上扩展来实现一个类 Discord 功能的社群,显然不是一个很好的思路。

那么还有其他“捷径”吗?

IM聊天室也是一个潜在的选项,聊天室的一大特点就是支持超大规模同时在线(参见《千万级实时直播弹幕的技术实践》),容量似乎已经不是问题,但是当考虑添加其他一些强社交关系的特性时(如成员、身份组等)就显得有点为难了,聊天室本身就是来去自如的一个开放空间,这个和圈组的产品本身定位互相冲突的。

因此基于聊天室扩展的方案也基本 pass 掉了。

6、“圈组”的技术难点

基于上述种种的思考和讨论,最终选择脱离已有 IM 体系,从零研发一套全新的社群方案“圈组”,“圈组”不是一个简单的 IM 功能,而是一套可以独立运行的 IM 系统。

经过上面的讨论,相信大家对“圈组”本身的技术特点和难点也有所理解。

可以归纳为以下几点:

  • 1)二级结构下成员无上限的社交关系系统设计;
  • 2)超大社群下消息系统设计;
  • 3)复杂高效的身份组系统设计;

7、“圈组”技术实现之整体架构  

“圈组”整体架构:

上面展示了“圈组”服务整体的架构。

可以看到整个“圈组”服务是一个分层的架构:

  • 1)首先是接入层,包括 LBS 服务和长链接服务器以及 API 网关,对应客户端 SDK 和用户服务器;
  • 2)后面是网络层,包括大网 WE-CAN 和协议路由服务;
  • 3)其次是服务层,划分了多个服务模块,每个模块都包括多个微服务;
  • 4)最后是基础设施。

8、“圈组”技术实现之消息系统架构

这其中和消息系统相关联的包括接入层、网络层、以及后端的登录/订阅/消息/检索等模块。

基本架构如下:

消息系统中第一个要讨论的点就是消息的存储和分发方式,包括在线广播、离线推送、历史消息三个维度。

下面几节我们将对消息系统中各模块分别展开介绍。

9、“圈组”消息系统技术实现1:在线广播

对于一般的IM群组来说,在线广播的一般过程是这样的:依次查询群组里的所有人的在线状态,如果在线,则将消息发送给对应的长链接服务器。

显然这种机制无法复制到“圈组”,因为在“圈组”的一个服务器里可能存在超过 100w 的人。

此外:IM聊天室的广播模式也不能直接复用,因为在聊天室架构中,每个长链接映射到一个聊天室,因此当你登录到某个聊天室的时候,你只会收到该聊天室的消息。而对于“圈组”来说,每个用户会同时加入多个服务器/频道,而且会同时收到多个服务器/频道的消息。

针对“圈组”的上述特点:我们设计了消息订阅模式,也就是用户登录之后,需要订阅感兴趣的相关服务器/频道,服务器会记录下这个订阅信息。当有新消息的时候,服务器通过订阅关系(而不是在线状态)查询到需要广播的列表,通过这种方式就不再需要遍历服务器/频道里的所有用户。

但是当一个服务器/频道里在线人数非常多的时候,这个订阅关系仍然是巨大的。

为此:我们设计了一种两层订阅模型,即所有的订阅关系会保存在长链接服务器上(QChatLink/QChatWebLink),同时长链接服务器会定时发送心跳给后端的订阅服务器,心跳信息相比原始的订阅信息会大大简化,比如长链接服务器上会记录账号 A 订阅了某个频道 A 的消息,如果有 1w 个账号,则有 1w 条订阅记录,而心跳信息里只会上报有 1w 个人订阅了某个频道 A 的消息,具体的账号列表则被精简掉了。当一条消息需要广播时,消息服务会访问订阅服务,获取到该服务器/频道被订阅的长链接服务器列表,并依次给该列表中的长链接服务器发送消息下发通知,长链接服务器收到通知后会根据订阅详情再广播给所有客户端。

此外:我们还提供了多种订阅类型,当你非常关心某个频道消息时(比如页面正停留在该频道),此时你可以订阅该频道的消息。对于其他频道,如果你仅仅需要知道该频道有多少条未读消息(或者有无未读消息),则可以选择订阅该频道的未读计数(或者未读状态),此时服务下发时仅会广播精简的消息体用于维护客户端未读计数,并且当未读计数达到一定阈值之后(比如 99+),服务器可以选择不再下发任何通知消息而不影响用户体验。

通过上文介绍的消息订阅模型,极大地提高了超大型的圈组频道/服务器消息在线广播的效率,降低了服务器压力。

除此之外:我们还设计了针对小型频道的特殊策略,对于小型频道,即使不订阅,服务器也会下发消息通知给频道里所有人,从而减轻端侧消息订阅模型的维护成本。针对消息订阅机制本身,后续我们也会根据不同的业务场景,提供更多一站式的策略来帮助降低接入成本,提升整体的易用性。

10、“圈组”消息系统技术实现2:离线推送

在强社交的场景下,离线消息推送对于维持用户粘性+提升产品体验有很大的作用。

从技术角度看的话,主要解决2个问题:

1)第一个是超大型服务器/频道的消息推送的效率问题;

2)另一个是提供足够丰富的推送策略来帮助 C 端用户,避免被过量的推送消息给打扰。

针对第一个问题,我们针对不同规模的服务器/频道采取了不同的策略:

  • 1)对于小型频道:采用类似于群组的消息推送模型;
  • 2)对于大型频道:对于每一条需要推送的消息,会根据目标用户的 ID 进行任务分片,多个节点并行操作,提高推送效率。

此外:分片会采用一致性策略,保证单个用户固定为某些节点,从而提高缓存命中效率。

针对第二个问题,推送策略可以用以下几句话来描述:

  • 1)既关注促活,又保证不打扰;
  • 2)大型 server 是游乐场,只推送与用户相关的重要消息(如 @消息);
  • 3)小型 server 是与朋友相处的小天地,支持消息的全部推送。

并且:未来用户还可以自定义消息的高低优先级,并搭配不同的推送配置(如不同的免打扰配置等),如下图所示。

11、“圈组”消息系统技术实现3:历史消息

历史消息的存储在“圈组”的场景中也需要一些特别的设计。

同样以传统IM群组为例,一般来说消息的存储方式有两种,写扩散和读扩散。在小型的IM群组或者多人会话中,写扩散模式可以简化设计,但是当群组规模扩大到一定程度(如万人群),读扩散就成了选择。

而对于“圈组”这种单个服务器可能上百万人的“群组”中,除了常规的读扩散之外,我们还设计了多级缓存的结构来应对海量的读请求。

基本的存储架构大致如下:

消息的存储主要包括两部分:

  • 1)一部分是消息本身;
  • 2)一部分是未读计数。

首先是写入:对于上述两者,我们都会使用中心化的缓存服务器来存储最近的数据,并使用异步+批量+聚合等手段,通过 MQ 异步落库,从而平衡写入效率(单条写入性能低)和写入读取延迟(异步写入有延迟)的问题,并且针对不同数据类型的特点,我们也选择了不同的存储方案(历史消息使用分布式时间序列数据库,未读计数使用分布式 k-v 数据库),最大化地提升消息存储和查询的性能和效率。

有写就有读,针对读取操作:

  • 1)所有最近的消息和未读计数均会存储在中心化缓存中,并通过先进先出和缓存过期等不同的策略来确保缓存中存储的永远是最新和最热的数据;
  • 2)对于消息 ID 和消息内容本身,中心化缓存中也会有不同的数据结构和过期策略,来平衡缓存命中率和缓存容量消耗;
  • 3)当缓存过期了,如果有关联的读写请求,将会触发缓存的重建,以保证缓存的命中率始终保持在较高水位;
  • 4)当有高频的读请求,还会触发热点 cache 的检测,并将一部分读请求下沉到各个计算节点的内存中,以应对突发流量的冲击。

上述针对“圈组”的特别设计,消息存储系统可以应对几十数百人的小型圈组频道,也可以从容应对上百万的超大型频道。

12、相关资料

[1] IM群聊消息究竟是存1份(即扩散读)还是存多份(即扩散写)?

[2] 网易云信技术分享:IM中的万人群聊技术方案实践总结

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

[4] 融云IM技术分享:万人群聊消息投递方案的思考和实践

[5] 微信直播聊天室单房间1500万在线的消息架构演进之路

[6] 百万人在线的直播间实时聊天消息分发技术实践

[7] 千万级实时直播弹幕的技术实践

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

[9] 深度揭密RocketMQ在钉钉IM系统中的应用实践

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

[11] 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

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

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

posted @ 2023-07-12 13:42 Jack Jiang 阅读(80) | 评论 (0)编辑 收藏

本文由腾讯产品体验设计师volihuang分享,原题“千万级增长,实时社交产品Discord拆解”,本文收录时有内容修订和大量排版优化。

1、引言

对于大多数人而言,对即时通讯IM应用的认知仍然停留在微信、QQ这类经典的即时通讯聊天场景。

实际上,如今的即时通讯技术已渗透到各种业态中,包括本系列文章将要分享的目前大热的Discord实时社群软件(Discord主要用于游戏社交),研究Discord软件包括技术实现上和产品定义上或许可以对你在其它业态中更好的应用即时通讯技术带来启发,也这是整理分系列文章的初衷。

本文为系列文章的首篇,文章内容不讨论Discord具体的技术实现,仅从其产品定义的角度上对Discord软件进行详尽和具体的介绍,希望能帮助你对Discord从产品形态上有较为完整的认知,也方便你阅读本系列文章的后续篇章。

 
 技术交流:

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

2、系列文章

本文是系列文章中的第 1 篇:

3、Discord是什么

3.1席卷游戏圈的社群

Discord是一家游戏实时聊天应用与社区,Discord从游戏语音、IM工具服务起家,随后转向直播平台,进而开设游戏商店的社区平台,成为游戏玩家在游戏中沟通协作的首选工具。Discord于2015年5月公开发行。

在 2018 年,它就已经席卷游戏圈,成了最受游戏玩家亲睐的「语音聊天工具」。在“英雄联盟”美服,几乎每局游戏开始前,都会有人发送 Discord 频道链接,邀请队友通过 Discord 沟通,而不是使用游戏内置的语音工具。

从语音聊天工具,到游戏玩家社区,Discord 似乎正在开创一种全新的互联网社会形态。它预示了一种比 reddit、Facebook 可能更理想的全新未来。

3.2从「工具」到「社区」

Discord 绝不是最「简单易用」的一个,但 Discord 却在思考如何从最底层优化产品,给到用户更多「可能性」.在疫情的大环境下,从2020年2月到7月,Discord的用户数量增加了47%,学习小组开始使用Discord;老师用它上课;朋友们用它来玩,就像平时放学后或周末一样。

3.3UI界面概览

4、Discord的发展历程

Discord相较于传统图文沟通模式的社群有着显著的优点:在Discord上社区建立者可以通过权限设置,轻松的进行用户细分,精准高效的传递信息;也可以进行社交媒体整合,为自己的其他社群进行引流。而Discord建立如此丰富的功能主要分为三个阶段来实现:

4.1第一阶段:游戏语音工具

核心增长点:极致的基础用户体验。

在工具阶段,Discord不断打磨全面超越竞品的基础体验,从界面审美、多端支持、延迟、降噪等等方面都处于市场领先地位。

通过极致的用户体验与因此收获的口碑传播,获取了第一批深度的种子用户。而这些用户逐渐围绕所玩的游戏形成了游戏社群。

4.2第二阶段:游戏社群

核心增长点:平台设计+能力开放+内容运营+用户质量。

在游戏社群阶段,Discord通过平台设计、能力开放、内容运营等方式加速了游戏社群的形成和壮大,游戏品类用户需求的溢出创造了更多的品类。

平台设计:完全免费设计、PC/Web/移动多端支持、免注册即可使用、无任何广告等,这些产品设计加速了用户的裂变;好友列表、加入服务器等沉淀的关系链继而让用户继续留存。Discord在产品设计中始终按照做一个平台的思路来设计,期望快速获得大量用户以形成网络效应。

能力开放:开放了较多的API能力,如支持游戏厂商接入语音sdk、支持同步Twitch直播状态、同步Steam游戏状态等等。这给用户和其他平台方提供强大的额外价值。

如音视频流可直接接入Discord,在服务器内就可以和好友一同观看Twitch/Youtube。如得知好友的游戏状态可以快速加入相同游戏一起开黑等。这也是平台设计的思路,开放能力接入第三方以获取赋能。

4.3第三阶段:全品类社群/社区

核心增长点:强大的管理能力(机器人开放平台/服务器权限/服务器模板…)。

Discord中服务器的管理能力非常丰富,通过设置不同的频道组和频道、设置身份权限、引入机器人等等手段,数十万人的社群也能够进行得有条不紊。

5、Discord的现状

现阶段,Discord 估计有 3 亿用户,其中包括 1.5 亿月活跃用户,平台上有 1900 万个服务器,涵盖游戏、投资、政治、动漫等领域。2020 年,Discord 每周有 670 万服务器处于活跃状态,基本上每周都有某个给定话题的对话讨论。2021 年,Discord 每周活跃服务器数据增长到了 1900 万。

来自移动产业数据平台 Apptopia 的消息显示,线上社区 App「Discord」的下载总量在近期已突破 5 亿次,同时应用内购营收总额突破 1 亿美元。

Discord 平台上单个日活跃用户(DAU)与平台的平均互动时长,是游戏直播平台 Twitch 的两倍,同时还是 Facebook Gaming、TikTok、Reddit 以及 Snap 等头部社交平台的两倍以上。

但是,即便在如此惊人的增长之后,Discord 似乎并没有太多商业化的动作。2020 年,Discord 的每用户平均收入 (ARPU) 仅为 1.30 美元,在公共社交媒体公司中排名非常靠后。


6、Discord平台机制介绍

6.1基本

Discord以其多样化的平台机制设定,为使用者提供了多种多样免费的功能。

它们是:

  • 1)以高音质、几乎零延迟、无限时间与尽可能多的朋友交谈;
  • 2)只需单击两次,即可将游戏直播带给服务器中的任何人,而且不会存在任何延迟;
  • 3) 使用单独的音量滑块一次观看多个流媒体;
  • 4)可以创建几乎无限量的文本聊天室,甚至可以追溯到几年前的档案;
  • 5)与朋友分享小文件;
  • 6)将机器人融入其中,可以向所有人广播音乐;
  • 7)Discord 支持视频流和屏幕截图等功能。

下面,我们详细介绍Discord中的功能设置。

6.2服务器机制

在 Discord 中有一种别于一般通讯软体之群组的群体聊天,称作服务器(类似社团),服务器拥有者可以在服务器中创造属于自己的社群。

例如:MINECRAFT在Discord的服务器,成员数已超过100w人,达到Discord目前设置的服务器上限。

MINECRAFT界面:

此外,在服务器搜索界面搜索MINECRAFT,可发现Discord上有6000+个MINECRAFT相关服务器,分布于社交、娱乐、同好、动画漫画、创作者等不同板块,绝大部分由玩家自发成立,在其中分享素材及想法。

6.3身份组机制

在 Discord 中可以建立非常多不同的身份组,使用者可以完全自订身分组的颜色、名称、权限、符号等等,身份组会直接影响使用者的名称颜色及用户列表的排序。

6.4频道机制

在伺服器中可以建立名为频道的聊天管道,分为语音、文字,其中的语音频道可以用来直播游戏与聊天等,频道可以设定与身份组整合各种权限,让 Discord 社群系统更加多样化。

文字方面:Discord 使用markdown语法,目的是对富文本一定程度的支持。

语音方面:Discord 使用opus音频格式,目的是压缩语音来降低延迟。

“哈利波特:魔法觉醒”的频道介绍列表:

6.5用户机制

每个 Discord 用户都有一个唯一的四位个人识别码,用户名后有一个"#"(例如ABCD#1234)。这使得多个用户能够拥有相同的用户名,并且用户可以很容易地找到朋友。

用户信息示意图:

6.6机器人

在 Discord 中所有使用者皆可以创立机器人,机器人主要是使用 Python 和 Java 编写,透过 Discord API 的语法扩充来编程。机器人可以发送讯息、图片、嵌入式讯息、嵌入式按钮、新增反应等,大致上与人类使用者权限无太大差异,不过在机器人的名称旁会有一个蓝色的 BOT 标志。机器人一样受到身份组权限的控管。

Topwar中的机器人消息及调用指令:

6.7整合

每个频道皆可以使用Webhook来抓取其他资讯,这使得在使用时甚至可以将Facebook、微博的贴文直接同步到Discord的频道中,另外频道也可以追踪另一个公告频道,来直接同步公告频道中的所有讯息。

6.8软件技术

尽管 Discord 的服务器由于其分布式特性无法匹配对应的传统硬件或虚拟服务器,不过其服务器和频道仍可类比于因特网中继聊天技术。用户可以在 Discord 上创建服务器并设定其他用户的加入条件。

Discord 的客户端使用Web技术构建在 Electron 框架上,这使得它可在多平台运行,既可在网页上运行,又可在个人计算机上作为应用程序运行。除了从 Discord 游戏商店下载和玩游戏为 Windows 独有之外,客户端的所有版本都支持相同的功能集(不包括与桌面音频的屏幕共享)。

Discord 是专门设计用于游戏互动的软件,因为它包括诸如低延迟、用户免费语音聊天服务器和专用服务器基础设施等功能。

6.9与游戏互联

在服务器和用户的层面上,Discord 允许用户连接到 twitch 或其他游戏账号。这种集成方式在一些应用程序中提供了独特的消息传递方法。

例如:如果用户使用自己的账号登录steam 玩游戏,Discord 便可以确定该用户正在玩该游戏。

6.10Nitro

虽然软件本身是免费的,但开发人员致力于研究如何将其商业化以营利,以Nitro计划的方式为对emoji和、贴图、个人化个人资料页面、语音及直播画质提升及文字字数限制进行付费使用。

7、Discord中的用户角色

Discord中的角色为用户提供特定权限。

例如:可以为主持人创建一个角色,并为该角色授予禁止用户和删除邮件的权限。 分配给该角色的任何用户都将继承这些权限。 使用角色可以使不必为每个用户分配权限。

要管理角色,请打开服务器设置,然后单击左侧的“角色”类别。 可以通过单击页面上“角色”标题侧面的小加按钮来添加新角色。 选择一个角色来管理权限。

有很长的权限列表,但重要的权限涉及通过创建新的渠道或角色来管理服务器的能力,通过禁止或删除邮件来管理用户,以及将用户移入和移出语音聊天。

还有一个管理员角色,它提供除服务器所有者特定的权限之外的所有权限(例如:删除服务器)。

8、Discord中的频道

服务器上的每个频道都按类别进行组织。 要创建新通道或类别,请右键单击通道窗格中的任意位置,然后单击“创建通道”或“创建类别”命令。

创建频道时,请为其命名并选择是应该是文字频道还是语音频道。 通道名称不能包含空格(键入空格只会创建连字符)或大写字母。

频道也有自己的频道特定权限,可以通过单击频道旁边的齿轮来访问这些权限。 这些权限默认与频道所属的类别同步,但如果更改它们,它们将保持这种状态,直到再次同步。

还可以将类别和频道设为私有。 当创建频道时,只需选择“私人频道”,然后启用希望能够访问该频道的角色。

如果只想向频道添加一些人,最好为该频道创建一个新角色,然后将用户添加到该角色。

下面我们讲介绍常见频道类型。

8.1)欢迎频道/规则频道:

欢迎频道一般包括服务器及游戏内容的大概说明、禁止的事项、频道发言规范等信息。可以由公告或文本频道设置而成。也可再次频道设置本地化相关选项(如语言)。

8.2)游戏活动公告频道组:

官方针对游戏内活动及社群相关活动的推宣,以公告频道的形式呈现。

8.3)游戏直播、其他社交媒体链接:

可以选择同步自身的twitter也可将自身所有媒体链接以消息的形式呈现,有助于游戏自身社交平台间的相互引流。

8.4)二创内容频道组:

通常包含玩家的绘画创作、视频创作、cosplay等,官方可在此频道中发布相应活动的信息并发放相应的活动奖励。

8.5)玩家公共讨论区频道组:

设置所有玩家都可参与的公共频道,为玩家提供交友、游戏内容交流甚至闲聊的空间。

8.6)语音讨论频道组:

为玩家建立可公共使用的语音频道,方便玩家与好友进行组队语音交流

8.7)娱乐频道组:

歌房:一起听歌的语音频道。

9、Discord中的机器人

除了聊天功能和社交架构之外,Discord 平台最引人注目的部分可能是其蓬勃发展的机器人生态系统。

在 2020 年的一篇博文中,Discord 宣布已经创建了超过 300 万个机器人,其中一些已经在数百万个服务器端上使用。

机器人举例:

  • 1)MEE6 是一个特别受欢迎的机器人应用,超过 1400 万服务器使用它来创建自定义欢迎消息、主动引导不良行为者、分配社区角色、并为积极参与社区活动的用户授予“XP”(“经验点”);
  • 2)ldleRPG 是一个提供更多创意服务的机器人应用,一旦它与服务器集成,社区成员就可以参与角色扮演游戏,这个游戏风格与《龙与地下城》相似,而且可以通过聊天命令参与。

从用户的角度来看,Discord 的机器人生态系统其实非常重要,因为可以扩展功能并增加游戏感。

而站在企业角度来看,机器人生态系统能从业务层面提供支撑,因为它允许开发人员在其应用程序接口(API)上进行构建。

10、Discord带来的启发

Discord背后的模式值得以社交的视角进行借鉴,辅助游戏端外社群运营。

1)首先:学会给用户创造一个新习惯,融入用户的生活场景,让用户对社区产生粘性。

Discord在提供给游戏玩家一个新的实时通话的社交平台的同时,其实是在给用户培养一个新的使用习惯,培养出来有社交互动需求的用户在玩游戏的时候,会的使用discord的习惯。

在培养用户的使用习惯以及粘性的这个过程中,需要团队专注于解决用户的核心需求,并且持续的提供技术支持。也就是要专注做好一个社交平台应该做的事情。

国内其实也有一个很好的例子。早年中国也有本土产出的用于服务游戏玩家“开黑”这定需求的社交软件,比方说,早年新浪上线的语音聊天产品UT,同期的在线群聊产品,以及后来的黑马YY语音。

2)其次:专注于解决用户的核心需求,找准定位,求同存异,保持用户的好感度。

从Discord的案例来说,它一开始的定位非常明确,就是小而精,针对于游戏群体的实时通话软件,然后在不断的完善功能的同时,扩大用户群体然后迅猛增长。

Discord专注于提升用户的体验并且保持用户社交的私密性,解决了解决用户的核心需求——网络实时社交。

11、相关资料

[1] 快速了解新一代跨平台桌面技术——Electron

[2] 盘点移动互联网时代的社交产品进化史(上篇):谁主沉浮

[3] 盘点移动互联网时代的社交产品进化史(下篇):大浪淘沙

[4] 中国互联网社交二十年:全民见证的互联网创业演义

[5] 别做梦了,社交产品哪有那么容易成功

[6] 同为IM社交产品中的王者,QQ与微信到底有什么区别

[7] 渐行渐远的人人网:十年亲历者的互联网社交产品复盘和反思

[8] 即时通讯创业必读:解密微信的产品定位、创新思维、设计法则等

[9] QQ的成功,远没有你想象的那么顺利和轻松

[10] 同为IM社交产品中的王者,QQ与微信到底有什么区别

[11] 还原真实的腾讯:从最不被看好,到即时通讯巨头的草根创业史

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

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

本文由云信IM技术团队分享,原题“千万级在线直播弹幕方案”,本文有修订和改动。

1、引言

疫情期间,线上演唱会是一种很常见的直播娱乐形式,由于线下社交距离的限制,线上形式演唱会比以往更火爆,而对技术的要求也更高。

本文基于网易云信针对TFBOYS某场线上演唱会的技术支持,为你分享千万级在线用户量的直播系统中实时弹幕功能的技术实践,希望能带给你启发。

 

技术交流:

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

2、系列文章

本文是系列文章中的第 9 篇:

3、弹幕整体技术方案

本次的弹幕方案以IM聊天室技术为基础,提供了登录直播间、发送弹幕、礼物消息等能力。同时按照千万级在线广播的目标,为期设计了基于CDN的弹幕广播服务。

直播间收发实时消息(也就是弹幕、礼物)的主要流程如下:

  • 1)获取直播间接入地址;
  • 2)登录直播间;
  • 3)收发消息(弹幕、礼物)。

下面将围绕以上流程的三个阶段,在技术上分别阐述如何实现千万级在线直播实时弹幕的能力。

4、弹幕技术方案之获取直播间接入地址

为了提供稳定高可用的实时弹幕服务,需要通过GSLB(Global Server Load Balancing)服务给用户分配最佳的接入地址。

GSLB服务需要从以下几个维度综合考虑:

  • 1)用户网络类型;
  • 2)机房网络容量;
  • 3)服务器负载;
  • 4)成本。

1)用户网络类型和机房网络容量:

为了用户能够快速、稳定的登录直播间收发消息,一般要根据用户所在地理位置以及网络运营商类型综合考虑给用户分类接入服务器。

机房一般提供BGP网络、三线网络两种接入方案,分配服务根据用户IP地址分析用户的地域、运营商类型并分配最佳接入地址。

一般优先按运营商类型分配三线地址(例如电信用户分配电信接入地址),如果是小运营商或无法识别的IP地址则分配BGP地址,两种接入方式用户都可以获得稳定的网络环境。

2)服务器负载:

单台服务器能够承载的TCP长链接有限,尤其是在高并发进入直播间的情况下,握手协议需要完成链路加密工作,对系统的CPU资源消耗比较大,因此需要实现一套良好的均衡分配策略。

3)一套基于服务器负载均衡的分配策略:

长链接接入服务器周期性上报当前服务器负载到负载均衡服务集群,负载信息存储在共享缓存中,接入分配服务根据负载信息动态分配接入地址。

一般情况下用户请求直播间地址,地址分配服务会查询负载均衡服务(或者直接查询负载缓存),然后根据获取到的信息分配当前负载最低的服务器。

在千万级别的在线直播活动场景下,开播时大量用户并发进入直播间,分配服务可达50万到100万TPS,这么高的TPS下如果还用“一般分配”方案,负载均衡(缓存)服务的TPS和集群之间的机房网络带宽非常高,单台服务器亦可能因为负载信息滞后导致超负荷分配。

为解决机房内带宽和超负载分配的问题,我们对分配方案进行了优化:

  • 1)长链接服务器上报负载的周期从1秒调整到5毫秒,负载均衡服务器可以更实时的同步负载信息;
  • 2)“地址分配”服务不再按请求查询负载信息,而是开启单独的同步线程周期性(同样是5毫秒)同步负载数据,从而有效降低负责信息同步的TPS和网络开销;
  • 3)“地址分配”服务不在按最低负载分配,而是将服务接入地址按负载排序,单个接入地址分配一定次数后按顺序分配下一个接入地址(避免低负载服务器瞬间被打爆)。

在实际方案落地中,需要结合负载、用户网络类型、机房线路容量等因素综合分配。

5、弹幕技术方案之登录直播间

登录直播间主要有两项任务:

  • 1)握手;
  • 2)身份认证。

1)握手:

SDK建立TCP长链接后,首先向服务器发送握手协议,主要提供SDK版本、协议版本、支持的加密算法等信息,服务器根据SDK提供的信息选择合适的协议版本以及加密算法,建立安全的通信链路。

我们支持的非对称算法包括:RSA、SM2等算法。支持的对称加密算法包括:AES,SM4等(SM2、SM4为国密算法)。

非对称加密算法对CPU资源消耗非常高,为了提高性能一般可以考虑选择合适的密钥长度,另外针对Java平台建议考虑使用JNI技术提高非对称加密计算性能。

2)身份认证:

引言中提到的该次直播活动是在线付费直播,因此身份认证包含了账号认证和业务认证两部分,即用户必须使用正确的账号密码登录App,且必须付费购买直播门票才有权限观看直播。

为优化系统性能,实时弹幕服务将“地址分配和鉴权”服务进行了特殊优化:

鉴权中心提供用户进入直播间弹幕服务的身份鉴权策略配置。在该次直播活动中采用了动态Token的鉴权机制,即根据用户账号、登录时间、分配的接入地址以及鉴权中心按时间区间生成的“随机数以及对应的Token算法”动态计算鉴权Token。

用户打开直播App,首先完成账号鉴权。在进入直播间时通过业务中心完成直播付费身份认证和弹幕服务地址分配(同步获取到弹幕服务的动态鉴权token),最后根据接入地址登录弹幕服务,弹幕服务依据鉴权中心的策略校验Token正确性。

动态Token鉴权采用进程本地计算的方式。可以在不访问用户服务的情况下完成身份鉴权,在提高登录认证的性能同时有效的降低了业务成本。

6、弹幕技术方案之收发消息(弹幕、礼物)

实时收发消息是直播间的核心业务,主要分为弹幕和礼物两类:

  • 1)礼物因涉及付费等因素一般通过客户方业务服务器发送;
  • 2)弹幕消息则可以通过聊天室长链接发送。

在千万级直播间场景下,因消息量太高,因此需要从消息量、消息体大小、消息比例等多个方面优化,因此我们设计了一套基于优先级队列的弹幕服务。

首先:为了节约消息产生的带宽,在大型直播项目开始阶段,就需要对消息格式进行优化,充分精简消息体大小。例如将礼物消息展示相关的资源文件提前预加载到直播App中,礼物消息转化为业务编号,可极大的减少消息大小;

其次:针对上行消息设计流控机制。为了能全局控制上行消息体量,设计了逐级流控方案。上层级根据下层级能够支撑处理能力设计相对较粗粒度的本地流控机制。在弹幕反垃圾业务阶段,因需要全局控制消息量,因此采用分布式全局流控方案;弹幕广播阶段则根据业务广播需求再一次进行消息流控。

上行消息通过反垃圾监测后被投递到弹幕服务处理。基于优先级队列的弹幕服务首先按业务划分不同的消息队列,例如:系统广播、高优先级礼物、低优先级、弹幕,然后按队列分配消息比例,最后根据单位时间(1秒)内用户需要接收到的消息量计算各个队列应该投递的消息数量。在实际投递消息的过程中,若前一个队列消息量不足,可将剩余的消息数量叠加到下一个队列,以确保每一个周期都发送足够的消息给用户。

弹幕可通过长连接或CDN广播给其他用户。为了给用户提供极致的弹幕体验,充分发挥边缘加速的优势,在千万级在线直播场景下优先选择CDN方案(如下图所示)。

基于CDN广播弹幕有两种方案:

1)基于推流的方案:类似于直播视频推流技术,即将消息伪装成视频流的形式推送到CDN,直播App以订阅数据流的方式同步弹幕信息;

2)静态文件加速方案:即弹幕服务将不同队列中的消息组装成一个静态文件,直播App周期性的到CDN服务器下载弹幕静态文件。

相对来说:

  • 1)静态文件加速方案实现更简单但实时性不高(取决于弹幕同步的周期时长);
  • 2)推流的方案消息实时性更高,但实现相对复杂,且需要考虑到不同终端的兼容性。

实际项目中可根据场景和终端类型灵活选择不同的方案。

为了保障服务的可靠性,可考虑融合CDN的方案,即同时将消息推送到多家CDN厂商,并结合CDN厂商的容量比例以及网络延迟情况综合调度(例如基于权重的轮巡调度策略)。

7、弹幕稳定性设计之单元化部署

ChatLink和ChatServer采用单元化部署的方案,有以下优点:

  • 1)单元内依赖的核心服务单元之间相互独立,水平扩展能力好,且单元内服务故障不影响其他单元,可以有效避免整个服务不可用的问题;
  • 2)跨机房部署,避免单个机房容量不足,或单机房不可用问题;
  • 3)弹幕方案采用了单元无状态的设计理念,因此不需要考虑单元之间同步数据的问题。

单个直播间的“接入服务”和“弹幕服务”因需要全局控制未采用单元化部署方案,但是在实施阶段采用了跨机房部署的方案(包括依赖的存储资源、服务),可以避免单个机房故障导致服务不可用的问题。

8、弹幕稳定性设计之单点服务高可用

针对“接入服务”和“弹幕服务”,除了采用跨机房部署外,在服务设计上核心依赖的存储资源、服务,采用主备模式。

例如:心跳负载依赖的缓存服务,单个缓存实例本身高可用,但考虑到极端情况(例如缓存集群内超过一半的服务器宕机导致服务不可用),因此采用主备缓存集群方案,当主集群不可用后,业务主动切换到备用集群,可保障业务在5秒内恢复正常。

9、幕稳定性设计之系统监控与数据大盘

为了实时了解系统运行状态,在弹幕方案中实现了秒级数据大盘方案。

监控大盘围绕用户和消息主要展示以下信息:

  • 1)用户地域分布变化;
  • 2)上行消息量;
  • 3)广播消息量;
  • 4)机房出口带宽;
  • 5)CDN带宽;
  • 6)消息流控比例;
  • 7)端侧CDN弹幕同步指标(成功比例、延迟状况)。

为了达成秒级监控的目标,数据收集采用了“业务预聚合+数据中心合并”的实时计算方案。即业务服务直接在本地进程内聚合计算指标上报到数据中心,数据中心仅需要按时间窗口合并监控指标数据即可输出到监控大盘。

10、弹幕稳定性设计之故障与应急预案演练

为确保活动顺利完成,弹幕方案还进行了多次故障与应急预案演练措施。

具体包含两个方面。

1)预设故障演练:即针对高可用设计方案的故障演练,按预设有计划的制造故障,主要验证高可用方案是否生效。

2)随机故障演练:无计划的随机制造故障,主要用于检查应急预案、异常监控报警、数据大盘等应急监测机制是否生效。

11、相关资料

[1] 海量实时消息的视频直播系统架构演进之路(视频+PPT)

[2] 百万在线的美拍直播弹幕系统的实时推送技术实践之路

[3] 阿里电商IM消息平台,在群聊、直播场景下的技术实践

[4] 微信直播聊天室单房间1500万在线的消息架构演进之路

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

[6] 百万人在线的直播间实时聊天消息分发技术实践

[7] 直播间海量聊天消息的架构设计难点实践

[8] vivo直播系统中IM消息模块的架构实践

[9] 万人群聊消息投递方案的思考和实践

[10] IM中的万人群聊技术方案实践总结

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

posted @ 2023-06-29 11:32 Jack Jiang 阅读(93) | 评论 (0)编辑 收藏

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

[- 1 -] IM系统的MQ消息中间件选型:Kafka还是RabbitMQ?

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

[摘要] MQ消息中间件可以理解一个水池,水池的这头是消息生产者,水池的那头是消息消费者,生产者和消息者无需直接对接,这将带来很多好处:业务解耦、架构分布式化等,生产者和消费者互相完全透明。但市面上的MQ消息中间件产品很多,作为IM系统中必不可少的一环,我们该如何选型?那么请继续阅读本文。


[- 2 -] 腾讯资深架构师干货总结:一文读懂大型分布式系统设计的方方面面

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

[摘要] 本文适合有过几年工作经验、正处于技术上升期的程序员阅读,内容少有浮夸,多为实践经验总结,希望能为您的技术成长加油助力。


[- 3 -] 以微博类应用场景为例,总结海量社交系统的架构设计步骤

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

[摘要] 本文让我们结合典型的互联网应用架构设计原则,通过一个模拟的微博应用场景,和你一起看看在微博这种海量社交应用实践中究竟如何分步进行架构设计的。


[- 4 -]快速理解高性能HTTP服务端的负载均衡技术原理

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

[摘要] 本文将以简洁通俗的文字,为你讲解主流的HTTP服务端实现负载均衡的常见方案,以及具体到方案中的负载均衡算法的实现原理。理解和掌握这些方案、算法原理,有助于您今后的互联网项的技术选型和架构设计,因为没有哪一种方案和算法能解决所有问题,只有针对特定的场景使用合适的方案和算法才是最明智的选择。


[- 5 -] 子弹短信光鲜的背后:网易云信首席架构师分享亿级IM平台的技术实践

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

[摘要] 本文内容来自对网易云信首席架构师周梁伟的采访,采访内容主要围绕网易云信这种海量用户IM云平台的关键技术难点以及对应的技术实践。


[- 6 -] 知乎技术分享:从单机到2000万QPS并发的Redis高性能缓存实践之路

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

[摘要] 知乎存储平台团队基于开源Redis 组件打造的知乎 Redis 平台,经过不断的研发迭代,目前已经形成了一整套完整自动化运维服务体系,提供很多强大的功能。本文作者陈鹏是该系统的负责人,本次文章深入介绍了该系统的方方面面,值得互联网后端程序员仔细研究。


[- 7 -] IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列

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

[摘要] 对于即时通讯开发者来说,正确地理解MQ消息队列,对于IM或消息推送系统的架构设计、方案选型等都大有裨益。


[- -]  新手入门:零基础理解大型分布式架构的演进历史、技术原理、最佳实践

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

[摘要] 即时通讯网作为IM和推送技术研究、学习和分享的社区,整理了大量的跟IM和推广技术有关的基础技术资料(比如网络基础、通信理论、架构基础等),本文内容虽然看起来跟IM和推送技术没有直接的关联性,但因为设计IM和推送系统的技术思路和原理跟典型大型互联网分布式架构都是一脉相承的,因而读懂本文内容对于IM和推送系统的架构设计同样大有裨益。


[- 9 -] 阿里技术分享:深度揭秘阿里数据库技术方案的10年变迁史

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

[摘要] 今天,阿里数据库事业部研究员张瑞,将为你讲述双11数据库技术不为人知的故事。在零点交易数字一次次提升的背后,既是数据库技术的一次次突破,也见证了阿里技术人永不言败的精神,每一次化“不可能”为“可能”的过程都是阿里技术人对技术的不懈追求。


[- 10 -] 阿里技术分享:阿里自研金融级数据库OceanBase的艰辛成长之路

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

[摘要] OceanBase 是蚂蚁金服自研的分布式数据库,在其 9 年的发展历程里,从艰难上线到找不到业务场景濒临解散,最后在双十一的流量考验下浴火重生,成为蚂蚁金服全部核心系统的承载数据库。这一路走来的艰辛和故事,蚂蚁金服高级研究员、OceanBase 团队负责人阳振坤将为你娓娓道来。


[- 11 -] 即时通讯新手入门:一文读懂什么是Nginx?它能否实现IM的负载均衡?

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

[摘要] Nginx(及其衍生产品)是目前被大量使用的服务端反向代理和负载均衡方案,从某种意义上来讲,Nginx几乎是低成本、高负载Web服务端代名词。


[- 12 -] 即时通讯新手入门:快速理解RPC技术——基本概念、原理和用途

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

[摘要] 本文将带你从基本概念、原理和用途方面,快速理解快速理解RPC技术,以便您在进行IM集群开发时能更好的进行方案设计和实现。


[- 13 -]  多维度对比5款主流分布式MQ消息队列,妈妈再也不担心我的技术选型了

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

[摘要] 本文将从17个维度综合对比Kafka、RabbitMQ、ZeroMQ、RocketMQ、ActiveMQ这5款当前最主流的MQ消息中间件产品,希望能为您的下一次产品的架构设计和MQ消息中间件选型提供参考依据。


[- 14 -] IM开发基础知识补课(六):数据库用NoSQL还是SQL?读这篇就够了!

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

[摘要] 本文将分析传统数据库(即SQL数据库)存在的一些问题,以及盘点目前市面上几大类 NoSQL 特性、优缺点等,希望给大家提供一些在不同业务场景下存储技术选型方面的参考。


[- 15 -] IM开发基础知识补课(九):想开发IM集群?先搞懂什么是RPC!

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

[摘要] 本文将以通俗易懂的白话形式,帮你快速理解IM集群中的关键技术——RPC。


[- 16 -] IM开发基础知识补课(十):大型IM系统有多难?万字长文,搞懂异地多活!

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

[摘要] 本文从一个简单的系统例子开始,从单机架构、主从副本、同城灾备、同城双活,再到异地双活、异地多活,由浅入深、循序渐进地讲解了大型分布式系统异地多活容灾架构的技术原理和基本的实现思路,非常适合入门者学习。


👉52im社区本周新文:《直播系统聊天技术(九):千万级实时直播弹幕的技术实践 http://www.52im.net/thread-4299-1-1.html》,欢迎阅读!👈


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

posted @ 2023-06-28 12:23 Jack Jiang 阅读(89) | 评论 (0)编辑 收藏

本文由得物技术团队Uni分享,本文有内容修订和大量排版优化。

1、引言

关于Java网络编程中的同步IO和异步IO的区别及原理的文章非常的多,具体来说主要还是在讨论Java BIO和Java NIO这两者,而关于Java AIO的文章就少之又少了(即使用也只是介绍了一下概念和代码示例)。

在深入了解AIO之前,我注意到以下几个现象:

  • 1)2011年Java 7发布,它增加了AIO(号称异步IO网络编程模型),但12年过去了,平时使用的开发框架和中间件却还是以NIO为主(例如网络框架Netty、Mina,Web容器Tomcat、Undertow),这是为什么?
  • 2)Java AIO又称为NIO 2.0,难道它也是基于NIO来实现的?
  • 3)Netty为什么会舍去了AIO的支持?(点此查看);
  • 4)AIO看起来貌似只是解决了有无,实际是发布了个寂寞?

Java AIO的这些不合常理的现象难免会令人心存疑惑。所以决定写这篇文章时,我不想只是简单的把AIO的概念再复述一遍,而是要透过现象,深入分析、思考和并理解Java AIO的本质。

 

技术交流:

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

2、我们所理解的异步

AIO的A是Asynchronous(即异步)的意思,在了解AIO的原理之前,我们先理清一下“异步”到底是怎样的一个概念。

说起异步编程,在平时的开发还是比较常见的。

例如以下的代码示例:

@Async

publicvoidcreate() {

    //TODO

}

 

publicvoidbuild() {

    executor.execute(() -> build());

}

不管是用@Async注解,还是往线程池里提交任务,他们最终都是同一个结果,就是把要执行的任务,交给另外一个线程来执行。

这个时候,我们可以大致的认为,所谓的“异步”,就是用多线程的方式去并行执行任务。

3、Java BIO和NIO到底是同步还是异步?

Java BIO和NIO到底是同步还是异步,我们先按照异步这个思路,做异步编程。

3.1BIO代码示例

byte[] data = newbyte[1024];

InputStream in = socket.getInputStream();

in.read(data);

// 接收到数据,异步处理

executor.execute(() -> handle(data));

 

publicvoidhandle(byte[] data) {

    // TODO

}

如上:BIO在read()时,虽然线程阻塞了,但在收到数据时,可以异步启动一个线程去处理。

3.2NIO代码示例

selector.select();

Set<SelectionKey> keys = selector.selectedKeys();

Iterator<SelectionKey> iterator = keys.iterator();

while(iterator.hasNext()) {

    SelectionKey key = iterator.next();

    if(key.isReadable()) {

        SocketChannel channel = (SocketChannel) key.channel();

        ByteBuffer byteBuffer = (ByteBuffer) key.attachment();

        executor.execute(() -> {

            try{

                channel.read(byteBuffer);

                handle(byteBuffer);

            } catch(Exception e) {

 

            }

        });

    }

}

 

publicstaticvoidhandle(ByteBuffer buffer) {

    // TODO

}

同理:NIO虽然read()是非阻塞的,通过select()可以阻塞等待数据,在有数据可读的时候,异步启动一个线程,去读取数据和处理数据。

3.3产生的理解偏差

此时我们信誓旦旦地说,Java的BIO和NIO是异步还是同步,取决你的心情,你高兴给它个多线程,它就是异步的。

果真如此么?

在翻阅了大量博客文章之后,基本一致的阐明了——BIO和NIO是同步的。

那问题点出在哪呢,是什么造成了我们理解上的偏差呢?

那就是参考系的问题,以前学物理时,公交车上的乘客是运动还是静止,需要有参考系前提,如果以地面为参考,他是运动的,以公交车为参考,他是静止的。

Java IO也是一样,需要有个参考系,才能定义它是同步还是异步。

既然我们讨论的是关于Java IO是哪一种模式,那就是要针对IO读写操作这件事来理解,而其他的启动另外一个线程去处理数据,已经是脱离IO读写的范围了,不应该把他们扯进来。

3.4尝试定义异步

所以以IO读写操作这事件作为参照,我们先尝试的这样定义,就是:发起IO读写的线程(调用read和write的线程),和实际操作IO读写的线程,如果是同一个线程,就称之为同步,否则是异步。

按上述定义:

  • 1)显然BIO只能是同步,调用in.read()当前线程阻塞,有数据返回的时候,接收到数据的还是原来的线程;
  • 2)而NIO也称之为同步,原因也是如此,调用channel.read()时,线程虽然不会阻塞,但读到数据的还是当前线程。

按照这个思路,AIO应该是发起IO读写的线程,和实际收到数据的线程,可能不是同一个线程。

是不是这样呢?我们将在上一节直接上Java AIO的代码,我们从 实际代码中一窥究竟吧。

4、一个Java AIO的网络编程示例

4.1AIO服务端程序代码

publicclassAioServer {

 

    publicstaticvoidmain(String[] args) throwsIOException {

        System.out.println(Thread.currentThread().getName() + " AioServer start");

        AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open()

                .bind(newInetSocketAddress("127.0.0.1", 8080));

        serverChannel.accept(null, newCompletionHandler<AsynchronousSocketChannel, Void>() {

 

            @Override

            publicvoidcompleted(AsynchronousSocketChannel clientChannel, Void attachment) {

                System.out.println(Thread.currentThread().getName() + " client is connected");

                ByteBuffer buffer = ByteBuffer.allocate(1024);

                clientChannel.read(buffer, buffer, newClientHandler());

            }

 

            @Override

            publicvoidfailed(Throwable exc, Void attachment) {

                System.out.println("accept fail");

            }

        });

        System.in.read();

    }

}

 

publicclassClientHandler implementsCompletionHandler<Integer, ByteBuffer> {

    @Override

    publicvoidcompleted(Integer result, ByteBuffer buffer) {

        buffer.flip();

        byte[] data = newbyte[buffer.remaining()];

        buffer.get(data);

        System.out.println(Thread.currentThread().getName() + " received:"+ newString(data, StandardCharsets.UTF_8));

    }

 

    @Override

    publicvoidfailed(Throwable exc, ByteBuffer buffer) {

 

    }

}

4.2AIO客户端程序

publicclassAioClient {

    publicstaticvoidmain(String[] args) throwsException {

        AsynchronousSocketChannel channel = AsynchronousSocketChannel.open();

        channel.connect(newInetSocketAddress("127.0.0.1", 8080));

        ByteBuffer buffer = ByteBuffer.allocate(1024);

        buffer.put("Java AIO".getBytes(StandardCharsets.UTF_8));

        buffer.flip();

        Thread.sleep(1000L);

        channel.write(buffer);

 }

}

4.3异步的定义猜想结论

分别运行服务端和客户端程序:

在服务端运行结果里:

1)main线程发起serverChannel.accept的调用,添加了一个CompletionHandler监听回调,当有客户端连接过来时,Thread-5线程执行了accep的completed回调方法。

2)紧接着Thread-5又发起了clientChannel.read调用,也添加了个CompletionHandler监听回调,当收到数据时,是Thread-1的执行了read的completed回调方法。

这个结论和上面异步猜想一致:发起IO操作(例如accept、read、write)调用的线程,和最终完成这个操作的线程不是同一个,我们把这种IO模式称之AIO。

当然了,这样定义AIO只是为了方便我们理解,实际中对异步IO的定义可能更抽象一点。

5、 AIO示例引发思考1:“执行completed()方法的线程是谁创建、什么时候创建?”

一般,这样的问题,需要从程序的入口的开始了解,但跟线程相关,其实是可以从线程栈的运行情况来定位线程是怎么运行。

只运行AIO服务端程序,客户端不运行,打印一下线程栈(备注:程序在Linux平台上运行,其他平台略有差异)。如下图所示。

分析线程栈,发现,程序启动了那么几个线程:

  • 1)线程Thread-0阻塞在EPoll.wait()方法上;
  • 2)线程Thread-1、Thread-2~Thread-n(n和CPU核心数量一致)从阻塞队列里take()任务,阻塞等待有任务返回。

此时可以暂定下一个结论:AIO服务端程序启动之后,就开始创建了这些线程,且线程都处于阻塞等待状态。

另外:发现这些线程的运行都跟epoll有关系!

提到epoll,我们印象中,Java NIO在Linux平台底层就是用epoll来实现的,难道Java AIO也是用epoll来实现么?

为了证实这个结论,我们从下一个问题来展开讨论。

6、 AIO示例引发思考2:AIO注册事件监听和执行回调是如何实现的?

带着这个问题,去阅读JDK分析源码时,发现源码特别的长,而源码解析是一项枯燥乏味的过程,很容易把阅读者给逼走劝退掉。

对于长流程和逻辑复杂的代码的理解,我们可以抓住它几个脉络,找出哪几个核心流程。

以注册监听read为例clientChannel.read(...),它主要的核心流程是:注册事件 -> 监听事件 -> 处理事件。

注册事件:

注:注册事件调用EPoll.ctl(...)函数,这个函数在最后的参数用于指定是一次性的,还是永久性。上面代码events | EPOLLONSHOT字面意思看来,是一次性的。

监听事件:

处理事件:

 

核心流程总结:

在分析完上面的代码流程后会发现:每一次IO读写都要经历的这三个事件是一次性的,也就是在处理事件完,本次流程就结束了,如果想继续下一次的IO读写,就得从头开始再来一遍。这样就会存在所谓的死亡回调(回调方法里再添加下一个回调方法),这对于编程的复杂度大大提高了。

7、 AIO示例引发思考3:监听回调的本质是什么?

7.1概述

先说一下结论:所谓监听回调的本质,就是用户态线程调用内核态的函数(准确的说是API,例如read、write、epollWait),该函数还没有返回时,用户线程被阻塞了。当函数返回时,会唤醒阻塞的线程,执行所谓回调函数。

对于这个结论的理解,要先引入几个概念。

7.2系统调用与函数调用

函数调用:找到某个函数,并执行函数里的相关命令。

系统调用:操作系统对用户应用程序提供了编程接口,所谓API。

系统调用执行过程:

  • 1)传递系统调用参数;
  • 2)执行陷入指令,用用户态切换到核心态(这是因为系统调用一般都需要再核心态下执行);
  • 3)执行系统调用程序;
  • 4)返回用户态。

7.3用户态和内核态之间的通信

用户态->内核态:通过系统调用方式即可。

内核态->用户态:内核态根本不知道用户态程序有什么函数,参数是啥,地址在哪里。所以内核是不可能去调用用户态的函数,只能通过发送信号,比如kill 命令关闭程序就是通过发信号让用户程序优雅退出的。

既然内核态是不可能主动去调用用户态的函数,为什么还会有回调呢,只能说这个所谓回调其实就是用户态的自导自演。它既做了监听,又做了执行回调函数。

7.4用实际例子验证结论

为了验证这个结论是否有说服力,举个例子:平时开发写代码用的IntelliJ IDEA,它是如何监听鼠标、键盘事件和处理事件的。

按照惯例,先打印一下线程栈,会发现鼠标、键盘等事件的监听是由“AWT-XAWT”线程负责的,处理事件则是“AWT-EventQueue”线程负责。如下图所示。

定位到具体的代码上:可以看到“AWT-XAWT”正在做while循环,调用waitForEvents函数等待事件返回。如果没有事件,线程就一直阻塞在那边。如下图所示。

8、Java AIO的本质是什么?

8.1Java AIO的本质,就是只在用户态实现了异步

由于内核态无法直接调用用户态函数,Java AIO的本质,就是只在用户态实现异步,并没有达到理想意义上的异步。

1)理想中的异步:

何谓理想意义上的异步?这里举个网购的例子。

两个角色,消费者A、快递员B:

  • 1)A在网上购物时,填好家庭地址付款提交订单,这个相当于注册监听事件;
  • 2)商家发货,B把东西送到A家门口,这个相当于回调。

A在网上下完单,后续的发货流程就不用他来操心了,可以继续做其他事。B送货也不关心A在不在家,反正就把货扔到家门口就行了,两个人互不依赖,互不相干扰。

假设A购物是用户态来做,B送快递是内核态来做,这种程序运行方式过于理想了,实际中实现不了。

2)现实中的异步:

A住的是高档小区,不能随意进去,快递只能送到小区门口。

A买了一件比较重的商品,比如一台电视,因为A要上班不在家里,所以找了一个好友C帮忙把电视搬到他家。

A出门上班前,跟门口的保安D打声招呼,说今天有一台电视送过来,送到小区门口时,请电话联系C,让他过来拿。

具体就是:

  • 1)此时,A下单并跟D打招呼,相当于注册事件。在AIO中就是EPoll.ctl(...)注册事件;
  • 2)保安在门口蹲着相当于监听事件,在AIO中就是Thread-0线程,做EPoll.wait(..);
  • 3)快递员把电视送到门口,相当于有IO事件到达;
  • 4)保安通知C电视到了,C过来搬电视,相当于处理事件(在AIO中就是Thread-0往任务队列提交任务,Thread-1 ~n去取数据,并执行回调方法)。

整个过程中,保安D必须一直蹲着,寸步不能离开,否则电视送到门口,就被人偷了。

好友C也必须在A家待着,受人委托,东西到了,人却不在现场,这有点失信于人。

所以实际的异步和理想中的异步,在互不依赖,互不干扰,这两点相违背了。保安的作用最大,这是他人生的高光时刻。

异步过程中的注册事件、监听事件、处理事件,还有开启多线程,这些过程的发起者全是用户态一手操办。所以说Java AIO本质只是在用户态实现了异步,这个和BIO、NIO先阻塞,阻塞唤醒后开启异步线程处理的本质一致。

8.2Java AIO的其它真相

Java AIO跟NIO一样:在各个平台的底层实现方式也不同,在Linux是用epoll、Windows是IOCP、Mac OS是KQueue。原理是大同小异,都是需要一个用户线程阻塞等待IO事件,一个线程池从队列里处理事件。

Netty之所以移除掉AIO:很大的原因是在性能上AIO并没有比NIO高。Linux虽然也有一套原生的AIO实现(类似Windows上的IOCP),但Java AIO在Linux并没有采用,而是用epoll来实现。

Java AIO不支持UDP。

AIO编程方式略显复杂,比如“死亡回调”。

9、参考资料

[1] 少啰嗦!一分钟带你读懂Java的NIO和经典IO的区别

[2] 史上最强Java NIO入门:担心从入门到放弃的,请读这篇!

[3] Java的BIO和NIO很难懂?用代码实践给你看,再不懂我转行!

[4] Java新一代网络编程模型AIO原理及Linux系统AIO介绍

[5] 从0到1的快速裂变:详解快的打车架构设计及技术实践

[6] 新手入门:目前为止最透彻的的Netty高性能原理和框架架构解析

[7] 史上最通俗Netty框架入门长文:基本介绍、环境搭建、动手实战

[8] 高性能网络编程(五):一文读懂高性能网络编程中的I/O模型

[9] 高性能网络编程(六):一文读懂高性能网络编程中的线程模型

[10] 高性能网络编程(七):到底什么是高并发?一文即懂!

[11] 从根上理解高性能、高并发(二):深入操作系统,理解I/O与零拷贝技术

[12] 从根上理解高性能、高并发(三):深入操作系统,彻底理解I/O多路复用

[13] 从根上理解高性能、高并发(四):深入操作系统,彻底理解同步与异步

[14] 从根上理解高性能、高并发(五):深入操作系统,理解高并发中的协程

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

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

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

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

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

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


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

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

[摘要今天下午跟大家分享的主题是:微信团队是如何从0到1实现“有把握”的微信春晚摇一摇红包系统的。


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

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

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


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

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

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


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

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

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


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

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

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


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

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

[摘要本文将为读者剖析支付宝红包系统背后的技术细节。


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

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

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


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

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

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


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

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

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


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

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

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


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

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

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


👉52im社区本周新文:《到底什么是Java AIO?为什么Netty会移除AOI?一文搞懂AIO的本质!http://www.52im.net/thread-4283-1-1.html》,欢迎阅读!👈

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

posted @ 2023-06-19 13:40 Jack Jiang 阅读(92) | 评论 (0)编辑 收藏

► 相关链接:

一、技术准备

您是否已对Web端即时通讯技术有所了解?

您需要对WebSocket技术有所了解:

WebSocket标准文档、API手册:

二、开发工具准备

1)WebStorm:

(JackJiang 使用的版本号如上图所示,建议你也使用此版或较新版本)

2)一站式下载地址:WebStorm官方下载地址点此进入

三、工程文件用途说明

3.1文件概览

纯原生JS实现,无任何重框架依赖:

MobileIMSDK-H5端SDK本身只是JS文件源码的集合,本工程中自带的前端Demo的目的只是为了方便随时测试MobileIMSDK-H5端的SDK代码而已,在此工程中的使用也仅仅只涉及了一个主Demo页面而已。

工程目录说明:

3.2详细说明

SDK 各模块/文件作用说明:

四、主要 API 接口

4.1主要 API 接口概览

如下图所示:所有 SDK 接口均由/mobileimsdk/mobileimsdk-client-sdk.js 提供。,接口设计跟MobileIMSDK 的APP版一样,均为高内聚和低侵入的回调方式传入SDK处理逻辑,无需(也不建议)开发者直接修改sdk级代码。

▲ 图上为浏览器端SDK的对外接口文件位置

▲ 图上为浏览器SDK为开发者提供的回调接口

▲ 图上浏览器端SDK的对外接口文件全图

4.2主要 API 接口用途说明

1)IMSDK.isLogined():

  • 用途:是否已经完成过首次登陆。
  • 说明 :用户一旦从自已的应用中完成登陆IM服务器后,本方法就会一直返回true(直到退出登陆IM)。
  • 返回值:{boolean},true表示已完成首次成功登陆(即已经成功登陆过IM服务端了,后面掉线时不影响此标识),否则表示尚未连接IM服务器。

2)IMSDK.isOnline():

  • 用途:是否在线。
  • 说明 :表示网络连接是否正常。
  • 返回值:{boolean},true表示网络连接正常,否则表示已掉线,本字段只在this._logined=true时有意义(如果都没有登陆到IM服务器,怎么存在在线或掉线的概念呢)。

3)IMSDK.getLoginInfo():

  • 用途:返回登陆时提交的登陆信息(用户名、密码/token等)。
  • 说明 :格式形如:{loginUserId:'',loginToken:''},此返回值的内容由调用登陆函数 loginImpl()时传入的内容决定。字段定义详见:PLoginInfo
  • 返回值:{boolean},true表示网络连接正常,否则表示已掉线,本字段只在this._logined=true时有意义(如果都没有登陆到IM服务器,怎么存在在线或掉线的概念呢)。

4)IMSDK.sendData(p, fnSucess, fnFail, fnComplete):

  • 用途:向某人发送一条消息。
  • 参数p:{Protocal} 要发送的消息协议包对象,Protocal详情请见“/module/mb_constants.js”下的createCommonData函数说明。
  • 返回值:{int} 0表示成功,否则表示错误码,错码详见“/module/mb_constants.js”下的MBErrorCode对象属性说明。

5)IMSDK.disconnectSocket():

  • 用途:客户端主动断开客户端socket连接。
  • 说明 :当开发者登陆IM后,需要退出登陆时,调用本函数就对了,本函数相当于登陆函数 loginImpl()的逆操作。

6)IMSDK.setDebugCoreEnable(enable):

  • 用途:是否开启MobileIMSDK-Uniapp端核心算法层的log输入,方便开发者调试。
  • 参数enable :{boolean} true表示开启log输出,否则不输出,开发者不调用本函数的话系统默认是false(即不输出log)。

7)IMSDK.setDebugSDKEnable(enable):

  • 用途:是否开启MobileIMSDK-Uniapp端框架层的log输入,方便开发者调试。
  • 参数enable :{boolean} true表示开启log输出,否则不输出,开发者不调用本函数的话系统默认是false(即不输出log)。

8)IMSDK.setDebugPingPongEnable(enable):

  • 用途:是否开启MobileIMSDK-Uniapp端框架层的底层网络WebSocket心跳包的log输出,方便开发者调试。
  • 参数enable :{boolean} true表示开启log输出,否则不输出,开发者不调用本函数的话系统默认是false(即不输出log)。
  • 注意:必须 setDebugEnable(true) 且 setDebugPingPongEnable(true) 时,心跳log才会真正输出,方便控制。
  • 返回值:true表示开启log输出,否则不输出,开发者不调用本函数的话系统默认是false(即不输出log)。

9)IMSDK.loginImpl(varloginInfo, wsUrl):

  • 用途:登陆/连接MobileIMSDK服务器时调用的方法。
  • 说明 :登陆/连接MobileIMSDK服务器由本函数发起
  • 参数varloginInfo:{PLoginInfo} 必填项,登陆要提交给Websocket服务器的认证信息,不可为空,对象字段定义见:PLoginInfo
  • 参数wsUrl:{string} 必填项:要连接的Websocket服务器地址,不可为空,形如:wss://yousite.net:3000/websocket。

10)IMSDK.callback_onIMLog(message, toConsole):

  • 用途:由开发者设置的回调方法:用于debug的log输出。
  • 推荐用法 :开发者可在此回调中按照自已的意图打印MobileIMSDK微信小程序端框架中的log,方便调试时使用。
  • 参数1: {String}:必填项,字符串类型,表示log内容。
  • 参数2: {boolean}:选填项,true表示输出到console,否则默认方式(由开发者设置的回调决定)。

11)IMSDK.callback_onIMData(p, options):

  • 用途:由开发者设置的回调方法:用于收到聊天消息时在UI上展现出来(事件通知于收到IM消息时)。
  • 推荐用法:开发者可在此回调中处理收到的各种IM消息。
  • 参数1: {Protocal}:详情请见“/module/mb_constants.js”下的Protocal类定义)。

12)IMSDK.callback_onIMAfterLoginSucess():

  • 用途:由开发者设置的回调方法:客户端的登陆请求被服务端成功认证完成后的回调(事件通知于 登陆/认证 成功后)。
  • 推荐用法 :开发者可在此回调中进行登陆IM服务器成功后的处理。

13)IMSDK.callback_onIMAfterLoginFailed(isReconnect):

  • 用途:由开发者设置的回调方法:客户端的登陆请求被服务端认证失败后的回调(事件通知于 登陆/认证 失败后)。
  • 说明 :补充说明:登陆/认证失败的原因可能是用户名、密码等不正确等,但具体逻辑由服务端的 callBack_checkAuthToken回调函数去处理。
  • 推荐用法:开发者可在此回调中提示用户登陆IM服务器失败。。
  • 参数1: {boolean}:true表示是掉线重连后的认证失败(在登陆其间可能用户的密码信息等发生了变更),否则表示首次登陆时的认证失败。

14)IMSDK.callback_onIMReconnectSucess():

  • 用途:由开发者设置的回调方法:掉线重连成功后的回调(事件通知于掉线重连成功后)。
  • 推荐用法 :开发者可在此回调中处理掉线重连成功后的界面状态更新等,比如设置将界面上的“离线”文字更新成“在线”。

15)IMSDK.callback_onIMDisconnected():

  • 用途:由开发者设置的回调方法:网络连接已断开时的回调(事件通知于与服务器的网络断开后)。
  • 推荐用法 :开发者可在此回调中处理掉线时的界面状态更新等,比如设置将界面上的“在线”文字更新成“离线”。

16)IMSDK.callback_onIMPing():

  • 用途:由开发者设置的回调方法:本地发出心跳包后的回调通知(本回调并非MobileIMSDK-Uniapp端核心逻辑,开发者可以不需要实现!)。
  • 推荐用法 :开发者可在此回调中处理底层网络的活动情况。

17)IMSDK.callback_onIMPong():

  • 用途:由开发者设置的回调方法:收到服务端的心跳包反馈的回调通知(本回调并非MobileIMSDK-Uniapp端核心逻辑,开发者可以不需要实现!)。
  • 推荐用法 :开发者可在此回调中处理底层网络的活动情况。

18)IMSDK.callback_onIMShowAlert(alertContent):

  • 用途:由开发者设置的回调方法:框架层的一些提示信息显示回调(本回调并非MobileIMSDK-Uniapp端核心逻辑,开发者可以不需要实现!)。
  • 说明 :开发者不设置的情况下,框架默认将调用wx.showModal()显示提示信息,否则将使用开发者设置的回调——目的主要是给开发者自定义这种信息的UI显示,提升UI体验,别无它用】。
  • 参数1:{String}:必填项,文本类型,表示提示内容。

19)IMSDK.callback_onIMKickout(kickoutInfo):

  • 用途:由开发者设置的回调方法:收到服务端的“踢出”指令(本回调并非MobileIMSDK-Uniapp端核心逻辑,开发者可以不需要实现!)。
  • 参数1 :{PKickoutInfo}:非空,详见:PKickoutInfo

20)IMSDK.callback_onMessagesLost(lostMessages):

  • 用途:由开发者设置的回调方法:消息未送达的回调事件通知。
  • 发生场景 :比如用户刚发完消息但网络已经断掉了的情况下,表现形式如:就像手机qq或微信一样消息气泡边上会出现红色图标以示没有发送成功)。
  • 建议用途:应用层可通过回调中的指纹特征码找到原消息并可以UI上将其标记为“发送失败”以便即时告之用户。
  • 参数1:{Array<rotocal>}:由框架的QoS算法判定出来的未送达消息列表。

21)IMSDK.callback_onMessagesBeReceived(theFingerPrint):

  • 用途:由开发者设置的回调方法:消息已被对方收到的回调事件通知。
  • 说明 :目前,判定消息被对方收到是有两种可能:
  • 1) 对方确实是在线并且实时收到了;
  • 2) 对方不在线或者服务端转发过程中出错了,由服务端进行离线存储成功后的反馈(此种情况严格来讲不能算是“已被收到”,但对于应用层来说,离线存储了的消息原则上就是已送达了的消息:因为用户下次登陆时肯定能通过HTTP协议取到)。
  • 建议用途:应用层可通过回调中的指纹特征码找到原消息并可以UI上将其标记为“发送成功”以便即时告之用户。
  • 参数1:{String}:已被收到的消息的指纹特征码(唯一ID),应用层可据此ID找到原先已发的消息并可在UI是将其标记为”已送达“或”已读“以便提升用户体验。

五、前端开发指南

5.1如何引入SDK文件到您的前端工程中?

很简单:只需要将第2节中提到的SDK所有JS文件复制到您的Uniapp工程下即可。

SDK内容见下图:

5.2如何在代码中调用SDK?

第一步:在你的网页中引用SDK的js文件(具体例子详见Demo中的index.html文件)

第二步:直接在你的JS文件中编写回调配置代码具体例子详见Demo中的index.js文件

第三步:在你的JS文件中调用IM的登陆方法即可具体例子详见Demo中的index.js文件

注意:上图中登录连接的IP地址请设置为您的MobileIMSDK服务器地址哦。

六、Demo运行方法(在WebStorm中直接预览)

6.1重要说明

特别说明:MobileIMSDK的H5端(包括Demo在内),全部是静态的HTML+JS资源,可以通过WebStorm自带的HTML页面预览功能,直接自动加载到电脑的浏览器中运行和预览。

6.2预览方法

1)在Demo中的index.html文件中,移动鼠标,会在右上角出现如下图所示的浮出菜单:

2)点击右上角浮出菜单上相应的浏览器就可以自动预览了这里以我电脑上已安装的Edge浏览器为例):

七、Demo运行方法(在Web服务器中部署并访问)

7.1重要说明

特别说明:MobileIMSDK的H5端(包括Demo在内),全部是静态的HTML+JS资源,对于服务端是没有任何依赖的,只需要保证浏览器端能加载到即可,可以把它们放置在Tomcat、Apache、IIS、Nginx等等传统Web服务器中即可,无需任何动态运行环境。

7.2安装Tomcat

提示:以下Demo的部署,以Java程序员最常用和Tomcat为例(Apache、IIS、Nginx等依此类推)。

Tomcat的安装就没什么好说的,直接官网下载对应的版本即可:https://tomcat.apache.org/download-90.cgi

7.3配置要连接的MobileIMSDK服务器IP

注意:下图中登陆连接的IP地址请设置为您的MobileIMSDK服务器地址哦。

友情提示: MobileIMSDK的服务端该怎么部署就不是本手册要讨论的内容了,你可以参见《即时通讯框架MobileIMSDK的Demo使用帮助:Server端》。

▲ 配置要连接的服务器IP以上代码详见demo/index.js 文件

7.4部署Demo

说“部署”有点扯蛋,因为Demo(包括SDK)在内,全是HTML静态内容,只需要直接复制到任何一种Web服务器即可。

以下是复制到Tomcat服务器网页目录后的截图:

7.5启动Tomcat

提示:本手册中仅以启Tomcat为例,Apache、IIS、Nginx等Web服务器的启动请自动百度。

运行startup.bat启动Tomcat:

7.6Demo的运行效果预览

八、Demo功能预览和说明

九、Demo运行效果实拍图

1)Demo在手机端浏览器中的真机实拍图:

2)Demo在电脑端浏览器中的真机实拍图:

十、更多Demo运行效果截图

1)Demo在PC端浏览器运行效果:

2)Demo在手机端浏览器运行效果:

 

3)Demo在PC端各主流浏览器的运行效果:

十一、常见问题(FAQ)

11.1为什么浏览控制台下有些log不显示?

原因是浏览器控制台下的日志级别默认进行了过滤,勾选所有日志级别,就能看到SDK的详细日志输出了。

勾选所有的日志输出级别:

然后就能看到SDK中详细的日志输出了(就像下图这样),方便调试和研究:

十二、引用资料

[1] WebSocket 标准API手册

[2] MobileIMSDK开源框架的API文档

[3] MobileIMSDK开源IM框架源码Github地址点此

[4] MobileIMSDK-H5端基本介绍

[5] MobileIMSDK-H5端的开发手册(* 精编PDF版)

[6] MobileIMSDK的Demo使用帮助:Server端

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

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

一、关于RainbowChat-Web

RainbowChat-Web是一套Web网页端IM系统,是RainbowChat的姊妹系统(RainbowChat是一套基于开源IM聊天框架 MobileIMSDK(Github地址) 的产品级移动端IM系统)。

二、v5.0 版更新内容

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

  • 1)[bug][前端]     - 解决了当首页“消息”无item时,从好友列表中删除某人时不自动清空聊天面板和右侧详情面板的问题;
  • 2)[bug][前端]     - 解决了处于群列表Tab时,退群或解散群不会更新群列表中“当前群聊”数字的问题 ;
  • 3)[bug][前端]     - 解决了处于群列表Tab时,点击创建群聊后,不会在群聊列表中自动选中此创建的群的问题;
  • 4)[优化]             - 升级核心通信层框架MobileIMSDK-Web至最新v5.1版;
  • 5)[优化][前端]    - 优化了当发送名片消息时,如名片者未设置头像,则在聊天消息界面中显示默认头像(提升体验);
  • 6)[优化][服务端] - 进一步加固了uid登陆时的sql注入风险;
  • 7)[优化][服务端] - 解决与最新rabbitmq-client库不兼容从而断线重连不成功,导致MQ中消息堆积的问题:
  • 8)[优化][服务端] - 解决MQ断线自动恢复时消费者Chennal未主动清理,导致空channel越来越多的问题;
  • 9)[优化][前端]    - 解决了被踢出群的情况下,仍能退群、邀请别人入群等问题;
  • 10)[优化][前端]  - 解决了高版本Tomcat下文件名中包含了特殊符号的大文件无法下载的问题。
  • 11)[新增][前端]  - 聊天区上方实现了聊天对象信息的显示(可显示昵称、群名称等信息);
  • 12)[新增][前端]  - 新增了消息送达状态图标的显示(包括发送中、发送成功、发送失败3种状态)。

三、v5.0 版新增特性截图

聊天区上方聊天对象信息的演示运行截图更多运行截图):

消息送达状态的演示运行截图更多运行截图):

四、主要界面截图概览

 ▲ 主界面(更多截图更多演示视频

▲ 主界面(聊天窗全屏时)(更多截图更多演示视频

▲ 主界面(聊天窗关闭时)(更多截图更多演示视频 

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

     摘要: 本文由will分享,个人博客zhangyaoo.github.io,原题“基于Netty的IM系统设计与实现”,有修订和重新排版。1、引言本文将要分享的是如何从零实现一套基于Netty框架的分布式高可用IM系统,它将支持长连接网关管理、单聊、群聊、聊天记录查询、离线消息存储、消息推送、心跳、分布式唯一ID、红包、消息同步等功能,并且还支持集群部署。本文中针对这套架构和系统设...  阅读全文

posted @ 2023-06-08 14:57 Jack Jiang 阅读(137) | 评论 (0)编辑 收藏

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

[- 1 -] 浅谈IM系统的架构设计

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

[摘要] 下面把我近年来从技术上我对IM系统(即时消息的传输,不包括语音,视频,文件的传输)的理解和设计分享出来,浅薄之见,望大家别见笑,欢迎给出批评意见。


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

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

[摘要] 有过移动端开发经历的开发者都深有体会:移动端IM的开发,与传统PC端IM有很大的不同,尤其无线网络的不可靠性、移动端硬件设备资源的有限性等问题,导致一个完整的移动端IM架构设计和实现都充满着大量的挑战。本文将简述移动端IM最重要的架构设计和通信协议选择方面的坑点,希望为IM开发者同行带来些许启发。


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

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

[摘要] 本文分享了一套完整的海量在线用户的移动端IM架构设计,来自于作者的真实项目实践总结,包含了详细的算法原理图、数据结构定义、表结构定义等等。


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

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

[摘要] 无论是IM消息通信系统还是客户消息系统,其本质都是一套消息发送与投递系统,或者说是一套网络通信系统,其本质两个词:存储与转发。推荐:如有兴趣,本文作者的另一篇《一套高可用、易伸缩、高并发的IM群聊架构方案设计实践》,适合进行IM群聊架构设计的参考。


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

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

[摘要] 京东的客服即时通讯系统名为咚咚是。咚咚之于京东相当于旺旺之于淘宝,它们都是服务于买家和卖家的沟通。自从京东开始为第三方卖家提供入驻平台服务后,咚咚也就随之诞生了。


[- 6-] 蘑菇街即时通讯/IM服务器开发之架构选择

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

[摘要] 由于IM服务器里面的内容比较多,这个可以是一个系列的内容,所以这里只介绍服务器的架构以及为什么选择这样的架构。


[- 7 -] 腾讯QQ1.4亿在线用户的技术挑战和架构演进之路PPT

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

[摘要] 众所周知海量互联网服务能力是世界公认的技术难题。经过十多年的发展,腾讯在海量互联网服务方面已有不少技术积累。PPT中以QQ IM后台服务为例,重现了QQ在线用户从百万级到亿级的整个过程中遇到的技术挑战,并与与会者分享了众多在海量互联网后台服务研发运营方面不为人知的秘密。


[- 8-]  微信后台基于时间序的海量数据冷热分级架构设计实践

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

[摘要] 时隔3年,微信团队再次分享了本文所述架构的最新升级版本及其改造过程,有兴趣可以前往阅读《微信后台基于时间序的新一代海量数据存储架构的设计实践》。


[- 9 -] 微信技术总监谈架构:微信之道——大道至简(演讲全文)

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

[摘要] 微信——腾讯战略级产品,创造移动互联网增速记录,10个月5000万手机用户,433天之内完成用户数从零到一亿的增长过程,千万级用户同时在线,摇一摇每天次数过亿...在技术架构上,微信是如何做到的?日前,在腾讯大讲堂在中山大学校园宣讲活动上,腾讯广研助理总经理、微信技术总监周颢在两小时的演讲中揭开了微信背后的秘密。


[- 10-] 如何解读《微信技术总监谈架构:微信之道——大道至简》

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

[摘要] 最近在朋友圈看到有人分享腾讯微信技术总监周颢的一个技术报告,题目是《微信技术总监谈架构:微信之道——大道至简》(演讲全文整理、演讲PPT讲稿下载),我也转发了一下。然后就被本司妹子看到了,非让我解释一下。


[- 11-] 快速裂变:见证微信强大后台架构从0到1的演进历程(一)

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

[摘要] 2个月的开发时间,微信后台系统经历了从0到1的过程。从小步慢跑到快速成长,经历了平台化到走出国门,微信交出的这份优异答卷,解题思路是怎样的?


[- 12-] 17年的实践:腾讯海量产品的技术方法论

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

[摘要] 在首届腾讯云技术峰会上,腾讯公司副总裁姚星完整的介绍了腾讯整体技术发展脉络。


[- 13-] 移动端IM中大规模群消息的推送如何保证效率、实时性?

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

[摘要] 当然,实际在生产环境下,群消息的发送都会想尽办法进行压缩,并开展各种改善性能的处理办法,而不是像上述举例里的直接扩散写(即2000人群里,一条消息被简单地复制为2000条一对一的消息投递)。具体有哪些优先策略?本文或许可以带给你一些启发。


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

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

[摘要] 本文内容主要涉及IM系统中的消息系统架构,探讨一种适用于大用户量的消息同步以及存储系统的架构实现,能够支持消息系统中的高级特性『多端同步』以及『消息漫游』。在性能和规模上,能够做到全量消息云端存储,百万TPS以及毫秒级延迟的消息同步能力。


[- 15-]WhatsApp技术实践分享:32人工程团队创造的技术神话

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

[摘要] 我们再次回顾了当时HighScalability创始人Tod Hoff撰文分析的收购原因和WhatsApp的高可靠架构,内容虽然并不完整,以今天的眼前来看成,仍有有许多值得学习的地方。


[- 16-]微信朋友圈千亿访问量背后的技术挑战和实践总结

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

[摘要] 朋友圈的数据是永远存储的,而且随着业务的快速发展,存储容量、带宽和设备的消耗大量增加,尤其重大节日带来的使用量增长,更加剧了消耗,也给运维人员的保障带来了巨大压力。


[- 17-]王者荣耀2亿用户量的背后:产品定位、技术架构、网络方案等

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

[摘要] 今天分几部分和大家介绍王者后台开发过程中的一些内容和思考:包括王者整个背景的介绍,后端的架构,上线之后做了什么样的调整,还有网络同步方案,反作弊方案等。

👉52im社区本周新文:《跟着源码学IM(十一):一套基于Netty的分布式高可用IM详细设计与实现(有源码) http://www.52im.net/thread-4257-1-1.html》,欢迎阅读!👈

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

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

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

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 阅读(170) | 评论 (0)编辑 收藏

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

posted @ 2023-05-18 12:04 Jack Jiang 阅读(140) | 评论 (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 阅读(101) | 评论 (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 阅读(87) | 评论 (0)编辑 收藏

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

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

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

posted @ 2023-05-06 11:21 Jack Jiang 阅读(86) | 评论 (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 阅读(71) | 评论 (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 阅读(75) | 评论 (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 阅读(77) | 评论 (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 阅读(68) | 评论 (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 阅读(80) | 评论 (0)编辑 收藏

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

posted @ 2023-04-13 17:11 Jack Jiang 阅读(126) | 评论 (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 阅读(79) | 评论 (0)编辑 收藏

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

posted @ 2023-04-07 12:21 Jack Jiang 阅读(105) | 评论 (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 阅读(122) | 评论 (0)编辑 收藏

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

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

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

posted @ 2023-03-23 14:53 Jack Jiang 阅读(88) | 评论 (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 阅读(96) | 评论 (0)编辑 收藏

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

posted @ 2023-03-09 14:30 Jack Jiang 阅读(84) | 评论 (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 阅读(69) | 评论 (0)编辑 收藏

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

posted @ 2023-03-02 14:25 Jack Jiang 阅读(88) | 评论 (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 阅读(49) | 评论 (0)编辑 收藏

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

posted @ 2023-02-23 14:18 Jack Jiang 阅读(78) | 评论 (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 阅读(71) | 评论 (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 阅读(48) | 评论 (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 阅读(121) | 评论 (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 阅读(58) | 评论 (0)编辑 收藏

     摘要: 本文引用了“鲜枣课堂”的《史上最强5G科普》文章内容。为了更好的内容呈现,在引用和收录时内容有改动,转载时请注明原文来源。1、内容概述➊ 5G技术的关注度越来越高:在此之前,5G技术对于普通老百姓来说,似乎还很遥远,关注度并不高。但从去年开始,美帝赤裸裸打压中兴和华为的国际事件,让5G技术在国内有了很高的关注度。美帝打压中兴、华为固然是坏事,但因为这个事情,相当于反过来为5...  阅读全文

posted @ 2023-02-04 16:21 Jack Jiang 阅读(73) | 评论 (0)编辑 收藏

     摘要: 本文由金蝶随手记技术团队丁同舟分享。1、引言跟移动端IM中追求数据传输效率、网络流量消耗等需求一样,随手记客户端与服务端交互的过程中,对部分数据的传输大小和效率也有较高的要求,普通的数据格式如 JSON 或者 XML 已经不能满足,因此决定采用 Google 推出的 Protocol Buffers 以达到数据高效传输。本文将基于随手记团队的Protobuf应用实践,分享了Protobuf的技术原...  阅读全文

posted @ 2023-01-28 16:57 Jack Jiang 阅读(112) | 评论 (0)编辑 收藏

     摘要: 1、前言Protobuf是Google开源的一种混合语言数据标准,已被各种互联网项目大量使用。Protobuf最大的特点是数据格式拥有极高的压缩比,这在移动互联时代是极具价值的(因为移动网络流量到目前为止仍然昂贵的),如果你的APP能比竞品更省流量,无疑这也将成为您产品的亮点之一。现在,尤其IM、消息推送这类应用中,Protobuf的应用更是非常广泛,基于它的优秀表现,微信和手机QQ这样的主流IM...  阅读全文

posted @ 2023-01-05 16:14 Jack Jiang 阅读(146) | 评论 (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 阅读(105) | 评论 (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 阅读(98) | 评论 (0)编辑 收藏

     摘要: 本文由陶文分享,InfoQ编辑发布,有修订和改动。1、前言本系列的前几篇主要是从各个角度讲解Protobuf的基本概念、技术原理这些内容,但回过头来看,对比JSON这种事实上的数据协议工业标准,Protobuf到底性能到底高多少?本篇将以Protobuf为基准,对比市面上的一些主流的JSON解析库,通过全方位测试来证明给你看看Protobuf到底比JSON快几倍。学习交流:- 移动端IM开发入门文...  阅读全文

posted @ 2022-12-16 12:43 Jack Jiang 阅读(122) | 评论 (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 阅读(98) | 评论 (0)编辑 收藏

     摘要: 本文由腾讯PCG后台开发工程师的SG4YK分享,进行了修订和和少量改动。1、引言近日学习了 Protobuf 的编码实现技术原理,借此机会,正好总结一下并整理成文。接上篇《由浅入深,从根上理解Protobuf的编解码原理》,本篇将从Base64再到Base128编码,带你一起从底层来理解Protobuf的数据编码原理。本文结构总体与 Protobuf 官方文档相似,不少内容也来自官方文档,并在官方...  阅读全文

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

     摘要: 本文由码农的荒岛求生陆小风分享,为了提升阅读体验,进行了较多修订和排版。1、引言搞即时通讯IM方面开发的程序员,在谈到通讯层实现时,必然会提到网络编程。那么计算机网络编程中的一个非常基本的问题:到底该怎样组织Client与server之间交互的数据呢?本篇文章我们不讨论IM系统中的那些高端技术话题,我们回归到通讯的本质——也就是数据在网络中交互时的编解码原理,并由浅入深从底...  阅读全文

posted @ 2022-11-24 11:43 Jack Jiang 阅读(133) | 评论 (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 阅读(89) | 评论 (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 阅读(215) | 评论 (0)编辑 收藏

     摘要: 本文由IBM开发者社区分享,有较多修订和改动。1、引言在当今移动网络时代,手机流量和电量是宝贵的资源,对于移动端最常见的即时通讯IM应用,由于实时通信基于Socket长连接,它对于流量和电量的需求较一般应用来说更高(详见《移动端IM实践:WhatsApp、Line、微信的心跳策略分析》)。在IM应用中,优化数据流量消耗过多的基本方法就是使用高度压缩的通讯协议,而数据压缩后流量减小带来的自然结果也就...  阅读全文

posted @ 2022-11-10 11:49 Jack Jiang 阅读(112) | 评论 (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 阅读(86) | 评论 (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 阅读(109) | 评论 (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 阅读(99) | 评论 (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 阅读(90) | 评论 (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 阅读(102) | 评论 (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 阅读(78) | 评论 (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 阅读(120) | 评论 (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 阅读(91) | 评论 (0)编辑 收藏

     摘要: 本文由vivo技术团队Yang Kun分享,原题“electron 应用开发优秀实践”,即时通讯网有修订。1、引言在上篇《Electron初体验(快速开始、跨进程通信、打包、踩坑等)》的分享中,我们已经对Electron跨端框架的开发有了大概的了解。本篇将基于vivo技术团队的技术实践,详细阐述了vivo在使用Electron进行跨端桌面开发时的技术栈选型考量,同时分享了在...  阅读全文

posted @ 2022-10-08 10:16 Jack Jiang 阅读(142) | 评论 (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 阅读(101) | 评论 (0)编辑 收藏

     摘要: 本文由蘑菇街前端技术团队分享,原题“Electron 从零到一”,有修订和改动。1、引言在上篇《快速了解新一代跨平台桌面技术——Electron》,我们已经对Electron跨端框架有了基本的认识。本篇将带你简单上手Electron框架开发跨平台桌面端,内容包括一个快速开始例子、跨进程通信原理、打包和分发、以及一些典型的技术踩坑等。希望能带给你启发。...  阅读全文

posted @ 2022-09-22 11:10 Jack Jiang 阅读(171) | 评论 (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 阅读(95) | 评论 (0)编辑 收藏

     摘要: 本文由微信客户端技术团队工程师“Jon”分享,原题“Windows微信:消息数据库架构演进”,有较多修订。1、引言本文分享的是,微信客户端团队基于对微信用户日常使用场景和数据分析,通过分离重要和非重要数据、采用可靠的分库策略等,对微信Windows端IM本地数据库的架构进行的优化和改造,并最终得到一个具备良好实践效果的技术改造方案。 以下是...  阅读全文

posted @ 2022-09-05 11:50 Jack Jiang 阅读(131) | 评论 (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 阅读(93) | 评论 (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长连接会话恢复

一次完整的握手阶段结束后,客户端和服务器端都保存有这个 Session ID。

在本次会话关闭,下一次再次连接时:客户端在 Client Hello 子消息中附带这个 Session ID 值,服务器端接收到请求后,将 Session ID 与自己在 Server Cache 中保存的 Session ID 进行匹配。

如果匹配成功:服务器端就会恢复上一次的 TLS 连接,使用之前协商过的密钥,不重新进行密钥协商,服务器收到带 Session ID 的 Client Hello 且匹配成功后,直接发送 ChangeCipherSpec 子协议,告诉 TLS 记录层将连接状态切换成可读和可写,就完成会话的恢复。

基于Session ID 会话恢复原理:

虽然使用 Session ID 进行会话恢复可以减少耗时的步骤,但由于 Session ID 主要保存在服务器 Server Cache 中,若再次连接请求时由于负载均衡设定将请求重定位到了其他服务器上,此时新的服务器 Server Cache 中没有缓存与客户端匹配的 Session ID,会导致会话无法恢复无法进行,因此不建议选用  Session ID 方式进行会话恢复。

7.3 基于SessionTicket的SSL/TLS长连接会话恢复

一次完整的握手过程后,服务器端将本次的会话数据(会话标识符、证书、密码套件和主密钥等)进行加密,加密后生成一个 ticket ,并将 ticket 通过 NewSessionTicket 子消息发送给客户端,由客户端来保存,下一次连接时客户端就将 ticket 一起发送给服务器端,待服务器端解密校验无误后,就可以恢复上一次会话。

基于SessionTicket 会话恢复原理:

由于加解密都是在服务端闭环进行,多服务只需要共享密钥就可以完成此过程,相较于 Session ID 的方式,可以不依赖 Server Cache,因此 SessionTicket 会话恢复方式更有利于大型分布式系统使用。

8、本文小结

本文分享了IM即时通讯的通信连接层安全知识和加密技术等。

并着重强调了两方面内容。首先,在IM即时通讯系统中使用具备 CA 认证的 SSL/TLS 证书可以保证传输安全,防止传输过程被监听、防止数据被窃取,确认连接的真实性。其次,利用 SessionTicket 快速地进行会话恢复可以提高整体系统性能,降低连接延时。

本文的下篇《即时通讯安全篇(十一):IM聊天系统安全手段之传输内容端到端加密技术》,将继续分享基于IM传输内容的端到端加密技术,敬请关注。

9、参考资料

[1] TCP/IP详解 - 第11章·UDP:用户数据报协议

[2] TCP/IP详解 - 第17章·TCP:传输控制协议

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

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

[5] 零基础IM开发入门(二):什么是IM系统的实时性?

[6] 对称加密技术在Android平台上的应用实践

[7] 非对称加密技术的原理与应用实践

[8] 常用加解密算法与通讯安全讲解

[9]微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解

[10] 为什么要用HTTPS?深入浅出,探密短连接的安全性

[11] 探讨组合加密算法在IM中的应用

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

posted @ 2022-08-22 11:35 Jack Jiang 阅读(123) | 评论 (0)编辑 收藏

     摘要: 本文引用自InfoQ社区“5亿用户如何高效沟通?钉钉首次对外揭秘即时消息服务DTIM”一文,作者陈万红等、策划褚杏娟,有修订和改动。一、引言本文是国内企业IM的事实王者钉钉首次对外深度解密其即时消息服务(即DingTalk IM,简称DTIM)的技术设计实践。本篇文章内容将从模型设计原理到具体的技术架构、最底层的存储模型到跨地域的单元化等,全方位展现了 DTIM 在实际生产...  阅读全文

posted @ 2022-08-15 12:32 Jack Jiang 阅读(224) | 评论 (0)编辑 收藏

     摘要: 本文由vivo互联网服务器团队李青鑫分享,有较多修订和改动。1、引言本文内容来自vivo互联网服务器团队李青鑫在“2021 vivo开发者大会”现场的演讲内容整理而成(现场演讲稿可从本文末附件中下载)。本文将要分享的是手机厂商vivo的系统级推送平台在架构设计上的技术实践和总结。这也是目前为止首次由手机厂商分享的自建系统级推送平台的技术细节,我们也得以借此机会一窥厂商ROO...  阅读全文

posted @ 2022-08-09 12:11 Jack Jiang 阅读(120) | 评论 (0)编辑 收藏

一、关于RainbowChat-Web

RainbowChat-Web是一套Web网页端IM系统,是RainbowChat的姊妹产品(RainbowChat是一套基于开源IM聊天框架 MobileIMSDK(Github地址) 的产品级移动端IM系统)。

不同于市面上某些开源或淘宝售卖的demo级代码,RainbowChat-Web的产品级代码演化自真正运营过的商业产品,其所依赖的通信层核心SDK(即MobileIMSDK-Web)已在数年内经过大量客户及其辐射的最终用户的使用和验证。

二、v4.1 版更新内容

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

  • 1)[bug][前端]解决了掉线后发出的消息,在被判定未送达的情况下,重连成功时会再次重发的问题(这是MobileIMSDK-Web的bug);
  • 2)[优化][前端]解决了发送的html等内容,对方显示正常,而自已这边显示不正常的问题(没被转义);
  • 3)[优化][服务端-独立交付版]解决了log4j2的两个jar包冲突导致在linux下不能正常输出log的问题;
  • 4)[优化][服务端-RainbowChatMQserver]优化了使用mysql8.0驱动时,不能正确读取SQL异常信息的问题(会报空指针异常);
  • 5)[优化][前端]解决了位置消息发送功能无法正常使用的问题(高德地图官方API升级,已适配并升级完成);
  • 6)[优化][前端]解决了位置消息查看时的地图控制工具不正常的问题(高德地图官方API升级,已适配并升级完成)。

升级后的位置消息相关功能截图(更多截图点此查看):

三、关于兼容性

截止目前:RainbowChat-Web努力保证在各主流系统、主流浏览器、不同分辨率屏幕上的一致体验,包括但不限于:Chrome、Safari、FireFox、Edge、360浏览器、世界之窗浏览器等▼

▲ 在各种主流浏览器上的运行情况更多截图点此进入更多演示视频点此进入

▲ 超宽屏上的显示情况更多截图点此进入更多演示视频点此进入

 

▲ 不同系统、不同分辨率屏幕的真机运行情况更多截图点此进入更多演示视频点此进入) 

四、主要界面截图概览

 

▲ 主界面更多截图点此进入更多演示视频点此进入

▲ 主界面(聊天窗全屏时)更多截图点此进入更多演示视频点此进入

▲ 主界面(聊天窗关闭时)更多截图点此进入更多演示视频点此进入

posted @ 2022-08-06 12:14 Jack Jiang 阅读(120) | 评论 (0)编辑 收藏

     摘要: 本文由vivo互联网技术团队LinDu、Li Guolin分享,有较多修订和改动。1、引言IM即时消息模块是直播系统的重要组成部分,一个稳定、有容错、灵活的、支持高并发的消息模块是影响直播系统用户体验的重要因素。本文针对秀场直播,结合我们一年以来通过处理不同的业务线上问题,进行了技术演进式的IM消息模块架构的升级与调整,并据此进行了技术总结、整理成文,希望借此机会分享给大家。在目前大部分主流的直播...  阅读全文

posted @ 2022-08-01 12:37 Jack Jiang 阅读(132) | 评论 (0)编辑 收藏

本文由作者“大白菜”分享,有较多修订和改动。注意:本系列是给IM初学者的文章,IM老油条们还望海涵,勿喷!

1、引言

前两篇《编码实践篇(单聊功能)》、《编码实践篇(群聊功能)》分别实现了控制台版本的IM单聊和群聊的功能。

通过前两篇这两个小案例来体验的只是Netty在IM系统这种真实的开发实践,但对比在真实的Netty应用开发当中,本系列的案例是非常的简单的,主要目的其实是让大家可以更好地了解其原理,从而写出更高质量的 Netty 代码。

不过,虽然 Netty 的性能很高,但是也不能保证随意写出来的项目就是性能很高的,所以本篇将主要讲解几个基于Netty的IM系统的优化实战技术点。

学习交流:

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

2、写在前面

建议你在阅读本文之前,务必先读本系列的前三篇《IM系统设计篇》、《编码实践篇(单聊功能)》、《编码实践篇(群聊功能)》。

最后,在开始本文之前,请您务必提前了解Netty的相关基础知识,可从本系列首篇《IM系统设计篇》中的“知识准备”一章开始。

3、系列文章

本文是系列文章的第3篇,以下是系列目录:

4、基于Netty的IM系统常见优化方向

常见优化方向脑图:

我们逐条详细解释一下这些优化的目的:

  • 1)心跳检测:主要是避免连接假死现象;
  • 2)连接断开:则删除通道绑定属性、删除对应的映射关系,这些信息都是保存在内存当中的,如果不删除则造成资源浪费;
  • 3)性能问题:用户 ID 和 Channel 的关系绑定存在内存当中,比如:Map,key 是用户 ID,value 是 Channel,如果用户量多的情况(客户端数量过多),那么服务端的内存将被消耗殆尽;
  • 4)性能问题:每次服务端往客户端推送消息,都需从Map里查找到对应的Channel,如果数量较大和查询频繁的情况下如何保证查询性能;
  • 5)安全问题:HashMap 是线程不安全的,并发情况下,我们如何去保证线程安全;
  • 6)身份校验:如何 LoginHandler 是负责登录认证的业务 Handler,AuthHandler 是负责每次请求时校验该请求是否已经认证了,这些 Handler 在链接就绪时已经被添加到 Pipeline 管道当中,其实,我们可以采用热插拔的方式去把一些在做业务操作时用不到的 Handler 给剔除掉。

以上是基于Netty的IM系统开发当中,需要去注意的技术优化点,当然还有很多其他的细节,比如:线程池这块,需要大家慢慢去从实战中积累。

5、本篇优化方向

本篇主要的优化内容主要是在第二篇单聊功能第三篇群聊功能的基础上继续完善几点。

具体的优化方向如下:

  • 1)无论客户端还是服务端都分别只有一个 Handler,这样的话,业务越来越多,Handler 里面的代码就会越来越臃肿,我们应该想办法把 Handler 拆分成各个独立的 Handler;
  • 2)如果拆分的 Handler 很多,每次有连接进来,那么都会触发 initChannel () 方法,所有的 Handler 都得被 new 一遍,我们应该把这些 Handler 改成单例模式(不需要每次都 new,提高效率);
  • 3)发送消息时,无论是单聊还是群聊,对方不在线,则把消息缓存起来,等待其上线再推送给他;
  • 4)连接断开时,无论是主动和被动,需要删除 Channel 属性、删除用户和 Channel 映射关系。

6、业务拆分以及单例模式优化

6.1 概述

主要优化细节如下:

  • 1)自定义 Handler 继承 SimpleChannelInboundHandler,那么解码的时候,会自动根据数据格式类型转到相应的 Handler 去处理;
  • 2)@Shareable 修饰 Handler,保证 Handler 是可共享的,避免每次都创建一个实例。

6.2 登录Handler优化

@ChannelHandler.Sharable

public class ClientLogin2Handler extends SimpleChannelInboundHandler<LoginResBean> {

    //1.构造函数私有化,避免创建实体

    private ClientLogin2Handler(){}

    //2.定义一个静态全局变量

    public static ClientLogin2Handler instance=null;

    //3.获取实体方法

    public static ClientLogin2Handler getInstance(){

        if(instance==null){

            synchronized(ClientLogin2Handler.class){

                if(instance==null){

                    instance=new ClientLogin2Handler();

                }

            }

        }

        return instance;

    }

 

    protected void channelRead0(

        ChannelHandlerContext channelHandlerContext,

        LoginResBean loginResBean) throws Exception {

 

        //具体业务代码,参考之前

    }

}

6.3 消息发送Handler优化

@ChannelHandler.Sharable

public class ClientMsgHandler extends SimpleChannelInboundHandler<MsgResBean> {

    //1.构造函数私有化,避免创建实体

    private ClientMsgHandler(){}

    //2.定义一个静态全局变量

    public static ClientMsgHandler instance=null;

    //3.获取实体方法

    public static ClientMsgHandler getInstance(){

        if(instance==null){

            synchronized(ClientMsgHandler.class){

                if(instance==null){

                    instance=new ClientMsgHandler();

                }

            }

        }

        return instance;

    }

 

    protected void channelRead0(

        ChannelHandlerContext channelHandlerContext,

        MsgResBean msgResBean) throws Exception {

 

        //具体业务代码,参考之前

    }

}

6.4 initChannel方法优化

.handler(newChannelInitializer<SocketChannel>() {

    @Override

    public void initChannel(SocketChannel ch) {

        //1.拆包器

        ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,5,4));

        //2.解码器

        ch.pipeline().addLast(new MyDecoder());

        //3.登录Handler,使用单例获取

        ch.pipeline().addLast(ClientLogin2Handler.getInstance());

        //4.消息发送Handler,使用单例获取

        ch.pipeline().addLast(ClientMsgHandler.getInstance());

        //5.编码器

        ch.pipeline().addLast(new MyEncoder());

    }

});

6.5 小结

这种业务拆分以及单例模式优优化是Netty开发当中很常用的,可以更好的维护基于Netty的代码并提高应用性能。

7、数据缓存优化

为了提高用户体验,在发送消息(推送消息)时,如果接收方不在线,则应该把消息缓存起来,等对方上线时,再推送给他。

7.1 数据缓存到集合

//1.定义一个集合存放数据(真实项目可以存放数据库或者redis缓存),这样数据比较安全。

private List<Map<Integer,String>> datas=new ArrayList<Map<Integer,String>>();

 

//2.服务端推送消息

private void pushMsg(MsgReqBean bean,Channel channel){

    Integer touserid=bean.getTouserid();

    Channel c=map.get(touserid);

 

    if(c==null){//对方不在线

        //2.1存放到list集合

        Map<Integer,String> data=new HashMap<Integer, String>();

        data.put(touserid,bean.getMsg());

        datas.add(data);

 

        //2.2.给消息“发送人”响应

        MsgResBean res=new MsgResBean();

        res.setStatus(1);

        res.setMsg(touserid+">>>不在线");

        channel.writeAndFlush(res);

 

    }else{//对方在线

        //2.3.给消息“发送人”响应

        MsgResBean res=new MsgResBean();

        res.setStatus(0);

        res.setMsg("发送成功);

        channel.writeAndFlush(res);

 

        //2.4.给接收人推送消息

        MsgRecBean res=new MsgRecBean();

        res.setFromuserid(bean.getFromuserid());

        res.setMsg(bean.getMsg());

        c.writeAndFlush(res);

    }

}

7.2 上线推送

private void login(LoginReqBean bean, Channel channel){

    Channel c=map.get(bean.getUserid());

    LoginResBean res=new LoginResBean();

    if(c==null){

        //1.添加到map

        map.put(bean.getUserid(),channel);

        //2.给通道赋值

        channel.attr(AttributeKey.valueOf("userid")).set(bean.getUserid());

        //3.登录响应

        res.setStatus(0);

        res.setMsg("登录成功");

        res.setUserid(bean.getUserid());

        channel.writeAndFlush(res);

 

        //4.根据user查找是否有尚未推送消息

        //思路:根据userid去lists查找.......

 

    }else{

        res.setStatus(1);

        res.setMsg("该账户目前在线");

        channel.writeAndFlush(res);

    }

}

8、连接断开事件处理优化

如果客户端网络故障导致连接断开了(非主动下线),那么服务端就应该能监听到连接的断开,且此时应删除对应的 map 映射关系。但是映射关系如果没有删除掉,将导致服务器资源没有得到释放,进而影响客户端的下次同一个账号登录以及大量的客户端掉线时性能。

8.1 正确写法

实例:

public class ServerChatGroupHandler extends ChannelInboundHandlerAdapter {

    //映射关系

    private static Map<Integer, Channel> map=new HashMap<Integer, Channel>();

    //连接断开,触发该事件

    @Override

    public void channelInactive(ChannelHandlerContext ctx) throws Exception {

        //1.获取Channel

        Channel channel=ctx.channel();

 

        //2.从map里面,根据Channel找到对应的userid

        Integer userid=null;

        for(Map.Entry<Integer, Channel> entry : map.entrySet()){

            Integer uid=entry.getKey();

            Channel c=entry.getValue();

            if(c==channel){

                userid=uid;

            }

        }

        //3.如果userid不为空,则需要做以下处理

        if(userid!=null){

            //3.1.删除映射

            map.remove(userid);

            //3.2.移除标识

            ctx.channel().attr(AttributeKey.valueOf("userid")).remove();

        }

    }

}

8.2 错误写法

Channel 断开,服务端监听到连接断开事件,但是此时 Channel 所绑定的属性已经被移除掉了,因此这里无法直接获取的到 userid。

实例:

public class ServerChatGroupHandler extends ChannelInboundHandlerAdapter {

    //映射关系

    private static Map<Integer, Channel> map=new HashMap<Integer, Channel>();

 

    //连接断开,触发该事件

    @Override

    public void channelInactive(ChannelHandlerContext ctx) throws Exception {

        //1.获取Channel绑定的userid

        Object userid=channel.attr(AttributeKey.valueOf("userid")).get();

 

        //2.如果userid不为空

        if(userid!=null){

            //1.删除映射

            map.remove(userid);

            //2.移除标识

            ctx.channel().attr(AttributeKey.valueOf("userid")).remove();

        }

    }

}

9、本篇小结

本篇内容还是相对容易理解的,主要是优化前面两篇实现的IM聊天功能,优化内容是业务 Handler 的拆分以及使用单例模式、接受人不在线则缓存数据、等其上线再推送、监听连接断开删除对应的映射关系。

限于篇幅,本系列文章文章没办法真正讲解开发一个完整IM系统所涉及的方方面面,如果有兴趣,可以继续阅读更有针对性的IM开发文章,比如IM架构设计IM通信协议IM通信安全群聊优化弱网优化网络保活等。

10、参考资料

[1] 新手入门:目前为止最透彻的的Netty高性能原理和框架架构解析

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

[3] 浅谈IM系统的架构设计

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

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

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

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

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

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

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

[11] 探探的IM长连接技术实践:技术选型、架构设计、性能优化

[12] 拿起键盘就是干,教你徒手开发一套分布式IM系统

[13] 万字长文,手把手教你用Netty打造IM聊天

[14] 基于Netty实现一套分布式IM系统

[15] SpringBoot集成开源IM框架MobileIMSDK,实现即时通讯IM聊天功能

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

posted @ 2022-07-25 12:02 Jack Jiang 阅读(129) | 评论 (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.2更新内容 

【重要说明】:

MobileIMSDK v6.2 为次要版本,进行了若干优化! 查看详情

【新增的特性】:

  1. [服务端] 新增两个聊天消息前置处理回调,方便开发者进行内容鉴黄、过滤、修改等运营管理;
  2. [服务端] 新增新增了一个与 Web 互通情况下的 C2C 模式回调,用于开发者在互通模式下实现离线消息 Push 逻辑;

【其它优化和提升】:

  1. [Andriod] 支持最新的 Andriod 12,解决了 Demo 工程中的 Andriod12 兼容问题;
  2. [Andriod] 解决了 Demo 工程在最新 Android Studio 编译时报方法数超过 65535 的经典问题;
  3. [服务端] 升级 log4j2 至 2.17.0,解决 Log4j2 远程代码执行高危漏洞;
  4. [服务端] 为 ServerEventListener 类中的 onUserLogout 回调增加 beKickoutCode 参数;
  5. [服务端] [优化] 尝试解决与 Web 互通情况下,MQProvider 中的 work 方法会因异步消息导致的 AlreadCloseException 问题;

【版本地址】:

https://gitee.com/jackjiang/MobileIMSDK/releases/6.2

posted @ 2022-07-20 10:29 Jack Jiang 阅读(95) | 评论 (0)编辑 收藏

     摘要: 本文由作者“大白菜”分享,有较多修订和改动。注意:本系列是给IM初学者的文章,IM老油条们还望海涵,勿喷!1、引言接上两篇《IM系统设计篇》、《编码实践篇(单聊功能)》,本篇主要讲解的是通过实战编码实现IM的群聊功能,内容涉及群聊技术实现原理、编码实践等知识。学习交流:- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM》- 开源IM框架源码:https://...  阅读全文

posted @ 2022-07-18 15:06 Jack Jiang 阅读(108) | 评论 (0)编辑 收藏

     摘要: 本文由作者“大白菜”分享,个人博客 cmsblogs.cn,有较多修订和改动。注意:本系列是给IM初学者的文章,IM老油条们还望海涵,勿喷!1、引言接上篇《IM系统设计篇》,本篇主要讲解的是通过实战编码实现IM的单聊功能,内容涉及技术原理、编码实践。补充说明:因为本系列文章主要目的是引导IM初学者在基于Netty的情况下,如何一步一步从零写出IM的逻辑和思维能力,因而为了简...  阅读全文

posted @ 2022-07-11 11:39 Jack Jiang 阅读(103) | 评论 (0)编辑 收藏

本文收作者“大白菜”分享,有改动。注意:本系列是给IM初学者的文章,IM老油条们还望海涵,勿喷!

1、引言

这又是一篇基于Netty的IM编码实践文章,因为合成一篇内容太长,读起来太累,所以也就顺着作者的思路分开成4篇,读起来心理压力也就没那么大了。

这个系列的几篇文章分享的是:假设在没有任何成型的第3方IM库或SDK的情况下,以网络编程的基础技术视野,思考和实践如何基于Netty网络库从零写一个可以聊天的IM系统的过程,没有眼花缭乱的架构设计、也没有高端大气的模式设计方法论,有的只是从IM入门者的角度的思路和实战,适合IM初学者阅读。

本篇主要是徒手撸IM系列的开篇,主要讲解的是的IM设计思路,不涉及实践编码,希望给你带来帮助。

学习交流:

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

2、知识准备

* 重要提示:本系列文章主要是代码实战分享,如果你对即时通讯(IM)技术理论了解的不多,建议先详细阅读:《零基础IM开发入门:什么是IM系统?》、《新手入门一篇就够:从零开发移动端IM》。

不知道 Netty 是什么?这里简单介绍下:

Netty 是一个 Java 开源框架。Netty 提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。

也就是说,Netty 是一个基于 NIO 的客户、服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。

Netty 相当简化和流线化了网络应用的编程开发过程,例如,TCP 和 UDP 的 Socket 服务开发。

Netty的基础入门好文章:

如果你连Java的NIO都不知道是什么,下面的文章建议优先读:

Netty源码和API的在线查阅地址:

3、系列文章

本文是系列文章的第1篇,以下是系列目录:

  1. 基于Netty,徒手撸IM(一):IM系统设计篇》(* 本文
  2. 《基于Netty,徒手撸IM(二):编码实践篇(单聊功能)》
  3. 《基于Netty,徒手撸IM(三):编码实践篇(群聊功能)》
  4. 《基于Netty,徒手撸IM(一):编码实践篇(系统优化)》

4、需求分析

业务场景: 本次实战就是模拟微信的IM聊天,每个客户端和服务端建立连接,并且可以实现点对点通信(单聊),点对多点通信(群聊)。

设计思路: 我们要实现的是点(客户端)对点(客户端)的通讯,但是我们大部分情况下接触的业务都是客户端和服务端之间的通讯(所谓的C/S模式?),客户端只需要知道服务端的 IP 地址和端口号即可发起通讯了。那么客户端和客户端应该怎么去设计呢?

技术思考:难道是手机和手机之间建立通讯连接(所谓的P2P),互相发送消息吗?

这种方案显然不是很好的方案:

  • 1)首先: 客户端和客户端之间通讯,首先需要确定对方的 IP 地址和端口号,显然不是很现实;
  • 2)其次: 即使有办法拿到对方的 IP 地址和端口号,那么每个点(客户端)既作为服务端还得作为客户端,无形之中增加了客户端的压力。

其实:我们可以使用服务端作为IM聊天消息的中转站,由服务端主动往指定客户端推送消息。如果是这种模式的话,那么 Http 协议是无法支持的(因为Http 是无状态的,只能一请求一响应的模式),于是就只能使用 TCP 协议去实现了。

Jack Jiang注:此处作者表述不太准确,因为虽然HTTP是无状态的,但一样可以实现即时通讯能力,有兴趣的读者可以阅读以下几篇文章,了解一下这些曾经利用HTTP实现即时通讯聊天的技术方法:

  1. 新手入门贴:史上最全Web端即时通讯技术原理详解
  2. Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE
  3. 网页端IM通信技术快速入门:短轮询、长轮询、SSE、WebSocket

5、IM单聊思路设计

5.1 通讯架构原理

以下是通讯架构原理图:

 

如上图所示,通讯流程解析如下:

  • 1)实现客户端和客户端之间通讯,那么需要使用服务端作为通讯的中转站,每个客户端都必须和服务端建立连接;
  • 2)每个客户端和服务端建立连接之后,服务端保存用户 ID 和通道的映射关系,其中用户 ID 作为客户端的唯一标识;
  • 3)客户端 A 往客户端 B 发送消息时,先把消息发送到服务端,再有服务端往客户端 B 进行推送。

针对上述第“3)”点,服务端如何找到客户端 B 呢?

客户端 A 往服务端发送消息时,消息携带的信息有:“客户端 A 用户 ID”、“客户端 B 用户 ID”、“消息内容”。这样服务端就能顺利找到服务端 B 的通道并且进行推送消息了。

5.2 消息推送流程

每个客户端和服务端建立连接的时候,必须把个人用户信息上传到服务端,由服务端统一保存映射关系。如果某个客户端下线了,则服务端监听到连接断开,删除对应的映射关系。

其次:发起群聊的时候,需要传递 touser 字段,服务端根据该字段在映射表里面查找到对应的连接通道并发起消息推送。

上述逻辑原理如下图所示:

5.3 更多的细节

其实在真正要做IM之前,要考虑的技术细节还是很多的,以下这几篇文章就步及到了典型的几个IM热门技术点,有兴趣的一定要读一读:

  1. 移动端IM开发需要面对的技术问题
  2. 谈谈移动端 IM 开发中登录请求的优化
  3. IM消息送达保证机制实现(一):保证在线实时消息的可靠投递
  4. IM消息送达保证机制实现(二):保证离线消息的可靠投递
  5. 如何保证IM实时消息的“时序性”与“一致性”?

6、IM群聊思路设计

群聊指的是一个组内多个用户之间的聊天,一个用户发到群组的消息会被组内任何一个成员接收 。

具体架构思路如下所示:

如上图所示,群聊通讯流程解析如下。

1)群聊其实和单聊整体上思路都是一致的,都是需要保存每个用户和通道的对应关系,方便后期通过用户 ID 去查找到对应的通道,再跟进通道推送消息。

2)如何把消息发送给多个组内的成员呢?

其实很简单,服务端再保存另外一份映射关系,那就是聊天室和成员的映射关系。发送消息时,首先根据聊天室 ID 找到对应的所有成员,然后再跟进各个成员的 ID 去查找到对应的通道,最后由每个通道进行消息的发送。

3)成员加入某个群聊组的时候,往映射表新增一条记录,如果成员退群的时候则删除对应的映射记录。

通过上面的架构图可以发现,群聊和单聊相比,其实就是多了一份映射关系而已。

其实群聊是IM里相对来说技术难度较高的功能,有兴趣的读者可以阅读下面这几篇:

  1. IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?
  2. IM群聊消息如此复杂,如何保证不丢不重?
  3. 移动端IM中大规模群消息的推送如何保证效率、实时性?
  4. 现代IM系统中聊天消息的同步和存储方案探讨
  5. 关于IM即时通讯群聊消息的乱序问题讨论
  6. IM群聊消息的已读回执功能该怎么实现?
  7. IM群聊消息究竟是存1份(即扩散读)还是存多份(即扩散写)?
  8. 一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践

另外,对于超大规模群聊,技术难度更是指数上升:

  1. 网易云信技术分享:IM中的万人群聊技术方案实践总结
  2. 阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处
  3. IM群聊消息的已读未读功能在存储空间方面的实现思路探讨
  4. 企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等
  5. 融云IM技术分享:万人群聊消息投递方案的思考和实践
  6. 微信直播聊天室单房间1500万在线的消息架构演进之路

7、本文小结

本篇主要是帮助读者掌握单聊和群聊的核心设计思路。

单聊: 主要是服务器保存了一份用户和通道之间的映射关系,发送消息的时候,根据接收人 ID 找到其对应的通道 Channel,Channel 的 write () 可以给客户端发送消息。

群聊: 保存两份关系,分别是用户 ID 和 Channel 之间的关系、群组 ID 和用户 ID 的关系。推送消息的时候,首先根据聊天组 ID 找到其对应的成员,遍历每个成员再进行找出其对应的通道即可。

整体来说,思路还是很简单的,掌握了该设计思路以后,你会发现设计一款 IM 聊天软件其实也不是很复杂。

8、相关文章

如果你觉得对本系列文章还不够详细,可以系统学习以下系列文章:

  1. 跟着源码学IM(一):手把手教你用Netty实现心跳机制、断线重连机制
  2. 跟着源码学IM(二):自已开发IM很难?手把手教你撸一个Andriod版IM
  3. 跟着源码学IM(三):基于Netty,从零开发一个IM服务端
  4. 跟着源码学IM(四):拿起键盘就是干,教你徒手开发一套分布式IM系统
  5. 跟着源码学IM(五):正确理解IM长连接、心跳及重连机制,并动手实现
  6. 跟着源码学IM(六):手把手教你用Go快速搭建高性能、可扩展的IM系统
  7. 跟着源码学IM(七):手把手教你用WebSocket打造Web端IM聊天
  8. 跟着源码学IM(八):万字长文,手把手教你用Netty打造IM聊天
  9. 跟着源码学IM(九):基于Netty实现一套分布式IM系统
  10. 跟着源码学IM(十):基于Netty,搭建高性能IM集群(含技术思路+源码)
  11. SpringBoot集成开源IM框架MobileIMSDK,实现即时通讯IM聊天功能

9、参考资料

[1] 新手入门:目前为止最透彻的的Netty高性能原理和框架架构解析

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

[3] 浅谈IM系统的架构设计

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

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

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

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

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

[9] 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

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

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

[12] 探探的IM长连接技术实践:技术选型、架构设计、性能优化

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

posted @ 2022-07-04 18:38 Jack Jiang 阅读(164) | 评论 (0)编辑 收藏

本文由作者jhon_11分享,有大量修订和改动。

1、引言

如何设计一款高性能、高并发、高可用的im综合消息平台是很多公司发展过程中会碰到且必须要解决的问题。比如一家公司内部的通讯系统、各个互联网平台的客服咨询系统,都是离不开一款好用且维护的方便im综合消息系统。

那么,我们应该怎么样来设计一款三高特性的im系统,并能同时支持各个业务线的接入(比如:内部OA通讯、客服咨询、消息推送等等功能)有呢?

下面就由我来介绍一下我所负责的公司IM综合消息系统所经历的架构设计历程,以及架构设计过程中的一些思路和总结,希望能给你带来启发。

学习交流:

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

2、初版IM架构

2.1 概述

im第一版设计的初衷是公司需要一款im消息中间件用于支撑客服咨询业务。

但是,考虑到为了方便日后其他业务线也能接入消息沟通平台,所以一开始就将整个消息中心的能力需求给到中间件团队进行开发,以便除客服外的各业务线接入综合消息中心,从而实现多元的消息实时触达能力。

2.2 初版架构介绍

初版架构图如下图所示:

针对上面的架构图,我们逐个解释一下各模块的作用。

1)存储端:

在初版的架构下,存储端我们使用tidb、redis作为主要存储:

  • [1] redis用于存储消息已读未读,缓存连接信息等功能;
  • [2] tidb作为开源的分布式数据库,选择它是为了方便消息的存储。

2)mq消息总线:

我们使用rocketmq来实现消息总线(PS:即分布式情况下,不同im实例间通过MQ进行消息交互)。

消息总线是整个im的核心,使用rocketmq能支持十万级别的tps。基本所有服务都要从消息总线中消费消息进行业务处理。

3)zookeeper注册中心:各个服务会注册到zk中,方便服务之间内部进行调用,同样也可以暴露服务给外部进行调用。

4)link服务:

link服务主要用于接收客户端的ws(WebSocket协议)、tcp、udp等协议的连接。

同时调用用户服务进行认证,并投递连接成功的消息给位置服务进行消费,存储连接信息。

ws(WebSocket协议)过来的消息先到link再投递到消息总线。

5)消息分发服务:

消息分发服务主要用于接收消息总线推过来的消息进行处理,按照im内部消息协议构造好消息体后,又推送到消息总线中(比如会推给会话服务、消息盒子、link服务)。

6)位置服务:

存储link的(WebSocket协议)连接、tcp连接等信息,并使用redis进行缓存(key为userId),方便根据UserId查询到该用户所登录的客户端连接在哪个link上。

一个用户在相同设备只能登录一个,但可以支持多端登录。

7)用户服务:用于存储所有用户,提供认证查询接口。

8)消息盒子:存储所有消息,提供消息查询、消息已读未读、消息未读数、消息检索等功能。

9)会话服务:管理会话、群聊会话、单聊会话等功能。

2.3 整体时序图

整体架构的时序图如下:

3、初版IM架构存在的问题及思考

在上节的架构设计介绍中,我们详细分享了初版IM系统架构的设计思路以及具体流程。

那么在初版IM架构设计中还存在什么样的问题,又该如何优化呢?我们一条条来看看。

3.1 使用MQ消息总线的问题

正如上节所分享的那样,我们初版IM架构中,link服务到消息分发服务的消息使用的MQ消息总线。

初版架构设计中,link服务将消息下推给消息分发服务进行处理时,使用的是mq消息总线(通俗了说,IM集群内不同IM实例间的通信是依赖于MQ进行的消息传递),而mq消息总线必然做对有一定的时延(而且时延受制于MQ本身的系统实现和技术策略)。

举个例子:

当两个处于不同IM实例的客户端A和B聊天时,A用户发送消息到link --> 消息总线 --> 消息分发服务 --> 消息总线 --> link --> B用户。

正如上面这个例子,im消息投递流程太长了,并且这样也会大大降低系统的吞吐量。

3.2 消息落库为写扩散的问题

其实现阶段我们使用的是跟微信一样的写扩散策略(详见《企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等》)。

那么为啥微信使用写扩散不是缺陷,而对于我们的IM架构来说确是缺陷呢?

微信的技术特性:

  • 1)微信号称没有存储用户的聊天记录,全是实时推送;
  • 2)微信聊天记录全部会在我们手机端存储一份,两台手机终端上的聊天记录并不互通,并且互不可见。

我们的IM综合消息中心技术特性:

  • 1)综合消息中心是会有拉取历史聊天记录(服务端拉取)的功能,存储了全量消息;
  • 2)综合消息中心的客户端,需要支持网页版本。

综上所述:

  • 1)写扩散对微信这样有移动端的富客户端版本的即时通讯产品十分友好,每个消息在消息分发的时候给处于这个会话(单聊,群聊)下的所有用户所在客户端先推送消息,没找到连接就针对这个用户写一个离线缓存消息,那么下次该用户登录进来,可以从缓存中拉取到该消息,并且清掉缓存;
  • 2)写扩散对于我们这类通用综合消息平台并不友好,由于接入方大部分是网页版的客户端,所以没有缓存消息的能力,浏览器刷新就没有了任何消息,所以需要实时去服务端拉取历史消息。假设我是写扩散,在一个群聊中有五百个用户,针对这五百个用户在这个会话,我需要去写五百条消息,大大的增加了写io,并且还不能写缓存(得写数据库)。

3.3 tidb存在不稳定性和事务并发的问题

tidb是目前主流的开源分布式数据库,查询效率高、无需分库分表。

但同样的,tidb存在一些隐藏的问题:

  • 1)tidb在高并发情况下,并发事务会导致事务失败,具体原因不知;
  • 2)tidb排错成本高,公司很少有tidb专业运维,经常遇到不走索引的情况。

3.4 群聊、单聊冗余在同一个服务的问题

在我们初版的IM架构设计中,单聊和群聊是冗余在会话服务中的,并且冗余在同一张表的。

其实单聊、群聊从数据角度来说,还是会有些不同(比如业务属性)虽然都是会话,我们还是需要将这两个服务拆分开,细粒度的服务拆分能更好的把控整体的逻辑。

4、升级版IM架构

4.1 初始架构问题

正如前面两节分享的那样,渐渐的我们发现初版im架构有很大的不足之处。

在生产上暴露出了以下问题:

  • 1)tps没达到预期,吞吐量不能满足公司业务的发展;
  • 2)使用的存储中间件难以维护(主要是tidb),试错成本高,经常在生产暴露问题,并且速度越来越慢;
  • 3)消息写扩散没有太大必要,并大大增加了系统io次数(原因见上一节);
  • 4)一些特性无法支持,比如消息图文检索,消息已读未读。

4.2 升级版im架构介绍

本次升级后的im架构如下图所示:

如上图所示,改版后的各模块情况如下:

  • 1)存储端:存储端我们改用了mysql,针对消息服务单独使用了主从mysql集群(主节点用于写消息、从节点用于消息检索)——;
  • 2)mq消息总线:与第一版相比没有改动;
  • 3)link服务:与第一版相比,改动了link服务到消息分发服务的消息推送方式(由MQ总线方式变更为tcp实时推送);
  • 4)消息分发服务:集成了消息处理能力、路由能力,每台消息分发服务拥有所有link服务的tcp连接;
  • 5)单聊服务:负责单聊会话的管理能力;
  • 6)群聊服务:负责群聊会话的管理能力;
  • 7)用户服务:提供用户认证,登录\注册能力。

5、详细对比针对初版IM架构的改动

升级版的IM架构,对比初始初始,具体主要是下面这些改动。

5.1 改进了不同im实例间的消息分发方式

针对初版MQ消息总结的问题,升级版架构中,我们将link到消息分发服务改为tcp实时连接,百万客户端连接同一台link机器,消息实时触达能力tps达到16万。

link到消息分发服务的改版是本次设计的亮点之一,完全消除了mq推送的时延性,并且路由简单,几乎实时触达。

举个例子:当两个处于不同IM实例的客户端A和B聊天时

  • 1)初版架构中是:A用户发送消息到link --> 消息总线 --> 消息分发服务 --> 消息总线 --> link --> B用户;
  • 2)升级版架构是:用户A --> link --> 消息分发 --> link --> 用户B。

而且:link服务到消息分发服务集群的消息推送使用轮询负载均衡的方式,保证公平,不会导致个别机器负载过高。

5.2 取消了位置服务

取消了位置服务(这里的位置不是指的IM消息里的地理位置消息哦),消息分发服务集成位置服务的能力。

消息分发服务本身业务简单,不需要再单独划分位置服务,因为会增加网络io,并且消息分发服务直连link,而让它负责路由则更加方便。

5.3 存储由tidb改成了mysql

存储端由tidb改成了mysql,增强了可维护性,消息服务使用mysql主从读写分离方式,提高了消息落库速度与检索速度的同时,也减轻数据库压力。

前面有提到过使用tidb这样维护成本高,排查问题难的分布式数据库是一件很痛苦的事情。

而我们使用mysql更加稳定,大家对mysql的学习成本相对较低。针对消息服务使用读写分离的方式,能大大提高消息的吞吐量。

5.4 实现了初版无法实现的特性功能

升级版架构中,我们实现了初版无法实现的特性功能,比如消息已读未读、红包推送、商品链接推送等功能。

新版综合消息中心加入了消息已读未读、发送红包、链接推送等功能,但这些功能带有一定的业务特性,毕竟不是所有Im都需要,可通过配置取消这些功能。

5.5 消息由写扩散改为读扩散

升级版IM架构中,消息存储由写扩散改为了读扩散。

前面我们有提到写扩散和读扩散的利弊,对于网页端IM我们更适合使用读扩散,只需要落一条消息,大大提高消息服务的吞吐量.

5.6 增加了门面服务

升级版IM架构中,我们增加门面服务 im-logic,用于暴露给第三方业务线接口调用。

初版架构中,都是im的各个服务各自暴露接口给到外部进行调用, 而升级版架中我们统一使用logic服务暴露给外部调用。

在logic服务针对调用可以做一些处理,这样不会影响到整体im的通用,不会增加im底层代码的复杂度,从而将业务逻辑与底层进行解耦。

6、优化后的效果对比

针对升级版和初版IM架构,我们也做了一些对比测试,具体的测试过程就是详细展开了。

以下是测试结果:

7、业务线接入im综合消息系统的业务划分思考

7.1 到底该如何设计高性能通用im综合消息系统

关于业务线接入im综合消息系统的业务划分,我也做了一些总结和思考,为了更形象和易于理解,我这里以客服系统以及企业微信为例来进行分析。

假如我开发了一款通用的im综合消息系统,现在有很多业务方需要接入我们,我们该如何进行业务域的清晰划分就显得尤为重要,需要在妥协与不妥协中进行平衡。

就像当前市面上开源的im消息平台来说,存在的问题主要是:要么是集成了很多的业务逻辑,要么就只是一款单纯的客服系统,再或者就是一款IM好友聊天系统,中间的业务划分并不明确。当然,这也有好处,拿来就能用,并不需要进行二次业务封装。

那么,到底如何将im设计为一款真正的高性能通用im综合消息系统呢?

通用的综合消息消息平台只需要有通用的底层能力:

以下案例假设在我已经按照上述架构设计了一版im综合消息中心。

7.2 以客服系统为例

客服系统:

客服系统不光需要实现自身业务,还需要整合im的消息能力(消费im的消息),来进行场景分析,实现会话变更、信令消息推送等逻辑。

客服系统内部需要根据im的底层支持能力进行相应的业务封装以及客服系统的客服用户池,c端用户池如何初始化到im的用户中心这些问题都是需要考虑进去的。

7.3 内部OA通信为例

内部OA通信:

 

员工内部OA通信系统需要集成IM好友功能,需要根据im的用户中心封装组织架构,用户权限等功能。

同时,内部通信系统需要根据im实现消息已读未读,群聊列表,会话列表拉取等功能。

8、本文小结

im的综合消息平台是一款需要高度结合业务的中间件系统,它直接与业务打交道,跟普通的中间件有根本的区别。

一款好用的im综合消息平台,直接取决于你的通用性,可扩展性以及系统吞吐能力。

希望这篇文章所分享的内容,能对大家开发im时候的思路有所启迪。

9、参考资料

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

[2] 从游击队到正规军(一):马蜂窝旅游网的IM系统架构演进之路

[3] 瓜子IM智能客服系统的数据架构设计(整理自现场演讲,有配套PPT)

[4] 阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处

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

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

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

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

[9] 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

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

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

[12] 阿里IM技术分享(三):闲鱼亿级IM消息系统的架构演进之路

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

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

posted @ 2022-06-28 10:40 Jack Jiang 阅读(130) | 评论 (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.2 版更新内容

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

(1)Android端主要更新内容新增“扫一扫”等功能及优化!】:

  • 1)[bug]解决了客户端被踢掉后,再次登陆时提示socket错误的问题;
  • 2)[优化]优化了扫码加群界面中,群头像加载失败时的默认显示样式;
  • 3)[优化]优化了切换账号和被踢时跳转到登陆界面的切换性能;
  • 4)[优化]重构了主要类代码,更方便集成;
  • 5)[新增]搜索功能(支持好友、群聊、聊天记录搜索(与微信逻辑一样));
  • 6)[新增]“聊信信息”界面中新增“查找聊天记录”功能;
  • 7)[新增]“群聊信息”界面中新增“查找聊天记录”、“清空聊天记录”功能。

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

  • 1)[优化][服务端]升级了MobileIMSDK至v6.2beta(改动了onUserLoginout方法参数);
  • 2)[优化][服务端]解决了log4j2的两个jar包冲突导致在linux下不能正常输出log的问题.

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

posted @ 2022-06-25 22:37 Jack Jiang 阅读(101) | 评论 (0)编辑 收藏

     摘要: 本文由字节跳动技术团队开发工程师王浩分享,即时通讯网收录时有较多修订。1、引言对于移动互联网时代的用户来说,短视频应用再也不是看看视频就完事,尤其抖音这种头部应用,已经是除了传统IM即时通讯软件以外的新型社交产品了。对于中国人一年一度最重的节日——春节来说,红包是必不可少的节日特定社交元素,而抖音自然不会被错过。在2022年的春节活动期间,抖音将视频和春节红包相结合,用户可...  阅读全文

posted @ 2022-06-20 17:12 Jack Jiang 阅读(166) | 评论 (0)编辑 收藏

本文由B站微服务技术团队资深开发工程师周佳辉原创分享。

1、引言

如果你在 2015 年就使用 B 站,那么你一定不会忘记那一年 B 站工作日选择性崩溃,周末必然性崩溃的一段时间。

也是那一年 B 站投稿量激增,访问量随之成倍上升,而过去的 PHP 全家桶也开始逐渐展露出颓势,运维难、监控难、排查故障难、调用路径深不见底。

也就是在这一年,B 站开始正式用 Go 重构 B 站,从此B站的API网关技术子开始了从0到1的持续演进。。。

* 补充说明:本次 API 网关演进也以开源形式进行了开发,源码详见本文“12、本文源码”。

PS:本文分享的API网关涉及到的主要是HTTP短连接,虽然跟长连接技术有些差异,但从架构设计思路和实践上是一脉相承的,所以也就收录到了本《长连接网关技术专题》系列文章中。

学习交流:

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

2、关于作者

周佳辉:哔哩哔哩资深开发工程师。始终以简单为核心的技术设计理念,追求极致简单有效的后端架构。

2017 年加入 B 站,先后从事账号、网关、基础库等开发工作。编码 C/V 技能传授者,技术文档背诵者。开源社区爱好者,安全技术爱好者,云计算行业活跃用户,网络工程熟练工。史诗级 bug 生产者,熟练掌握 bug 产生的各类场景。

3、专题目录

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

4、正式用Go重构B站

鉴于引言中所列举的各种技术问题,也是在2015年,财队开始正式用 Go 重构 B 站。

B站第一个 Go 项目——bilizone,由冠冠老师(郝冠伟)花了一个周末时间编码完成。

commit 4ccb1497ca6d94cec0ea1b2555dd1859e6f4f223

Author: felixhao <g******[url=mailto:1@gmail.com]1@gmail.com[/url]>

Date:   Wed Jul 1 18:55:00 2015 +0800

    project init

commit 6e338bc0ee638621e01918adb183747cf2a9e567

Author: 郝冠伟 <h*******@bilibili.com>

Date:   Wed Jul 1 11:21:18 2015 +0800

    readme

▲ 郝冠伟:哔哩哔哩主站技术中心架构师

bilizone 其实还是一个大而全的应用,bilizone 在当时重构的主要意义是将谁也理不清的 PHP 逻辑梳理成了一个比较标准的 Go 应用。

bilizone 在当时最大的意义就是为用户终端提供了基本稳定的数据结构、相对可靠的接口和比较有效的监控。

但因 bilizone 依旧是一个单体应用,所以它依旧继承了单体应用所具有的缺点:

  • 1)代码复杂度高:方法被滥用、超时设置混乱、牵一发而动全身;
  • 2)一挂全挂:最常见的比如,超时设置不合理、goroutine 大量堆积、雪崩;
  • 3)测试及维护成本高:小改动都需要测试所有 case,运维发布胆战心惊。

所以此时B站的崩溃频率虽然已经有所降低,但一炸全炸的问题依旧是一个心腹大患。

5、基于微服务的B站架构初具雏形

鉴于bilizone所面临的单体应用技术缺点,接下来的一次重构,让B站基于微服务的全局架构面貌就将初具雏形。

为了实现微服务模式下的 bilibili,我们将一个 bilizone 应用拆分成多个独立业务应用,如账号、稿件、广告等等,这些业务通过 SLB 直接对外提供 API。

当时的调用模式如下图所示:

但是随着功能拆分后,我们对外暴露了一批微服务,但是因为缺乏统一的出口而面临了不少困难。

这些困难主要是:

  • 1)客户端与微服务直接通信,强耦合;
  • 2)需要多次请求,客户端聚合数据,工作量巨大,延迟高;
  • 3)协议不利于统一,各个部门间有差异,反而需要通过客户端来兼容;
  • 4)面向“端”的 API 适配,耦合到了内部服务;
  • 5)多终端兼容逻辑复杂,每个服务都需要处理;
  • 6)统一逻辑无法收敛,比如安全认证、限流。

6、基于BFF模式的微服务架构

基于上节的初阶微服务架构带来的技术问题,以及我们想要将对端的处理进行内聚的想法,我们自然的而然的就想到在客户端与后端服务之间加一个 app-interface 的组件,这就是接下来的 BFF(Backend for Frontend)模式。

app-interface 的工作模式如下图所示:

有了这个 BFF 之后,我们可以在该服务内进行大量的数据聚合,按照业务场景来设计粗粒度的 API。

这样,后续服务的演进也带来了很多优势:

  • 1)轻量交互:协议精简、聚合;
  • 2)差异服务:数据裁剪以及聚合、针对终端定制化 API;
  • 3)动态升级:原有系统兼容升级,更新服务而非协议;
  • 4)沟通效率提升:协作模式演进为移动业务和网关小组。

BFF 可以认为是一种适配服务,将后端的微服务为客户端的需要进行适配(主要包括聚合裁剪和格式适配等逻辑),向终端设备暴露友好和统一的 API,方便无线设备接入访问后端服务,在其中可能还伴随有埋点、日志、统计等需求。

然而,这个时期的 BFF 还有一个致命的一个问题是——整个 app-interface 属于 single point of failure,严重代码缺陷或者流量洪峰可能引发集群宕机所有接口不可用。

7、基于多套BFF模式的微服务架构

针对上节中BFF模式下架构的技术问题,于是我们在上述基础上进一步迭代,将 app-interface 进行业务拆分。

进而多套 BFF 的模式横空出世:

由此模式开始,基本确定了 B 站微服务接口的对接模式,这套模式也随之在全公司内推广开来。

8、垂直BFF模式时代(2016年至2019年)

接上节,当 B 站网关的架构发展为多套垂直 BFF 之后,开发团队围绕该模式平稳迭代了相当长的一段时间。

而后随着B站业务的发展,团队人员的扩充和几次组织架构调整,此时开始出现直播、电商等独立业务,这些业务的发展我们之后再细说。

而在这些调整之后,有一个团队的职责越来越清晰:主站网关组。

主站网关组的主要职责就是维护上述各类功能的 BFF 网关,此时 bilibili 的主要流量入口为粉板 App。这里可以简单细说一下粉板 App 上的所有业务组成。

主站业务:

  • 1)网关组维护的 BFF,如推荐、稿件播放页等;
  • 2)业务层自行维护的 BFF,如评论、弹幕、账号等。

独立业务:

  • 1)电商服务;
  • 2)直播服务;
  • 3)动态服务。

主站业务的 BFF 其实被分为两类:

  • 1)一类是由网关组负责的 BFF;
  • 2)另一类是业务自行维护的 BFF。

而这两类 BFF 的技术栈其实基本一致,基本功能职责也相差不多。如此划分的原因是让网关组可以更专注于迭代客户端特性功能,免去理解部分独立业务场景的接口,如登陆页应该让对安全更专业账号的同学自行维护。

在这里我们也可以简述一下,一个新需求应该如何决定参与的 BFF :

  • 1)如果这个功能能由业务层的业务 BFF 独立完成,则网关组不需介入;
  • 2)如果该功能是一个客户端特性需求,如推荐流等复合型业务,需要对接公司大量部门时,则由网关同学参与开发 BFF。

当时主站技术部的后端同学遵循以上两个规则,基本能够满足业务的快速开发和迭代。

我把这段时间称为垂直 BFF 时代,因为基本主站每个业务或多或少都有各种形式的网关存在,大家通过这个网关向外提供接口,该网关和 SLB 进行直接交互。

9、基于业务的统一API网关架构

接上节,我们再来谈一谈几项重要的业务:电商、直播和动态。

电商和直播其实并不是同一时期衍生的,直播在主站 PHP 时期就诞生了,而电商相对更晚一些。

当时直播的技术栈组成有 C++、PHP、Go,其中早期大部分业务逻辑由 PHP 和 C++ 实现,稍晚一些也开始逐步试用主站的 Go 实现部分业务逻辑。其中 PHP 负责对终端提供接口,C++ 主要实现核心业务功能。因此我们可以简单理解为直播使用由 PHP 编写的 BFF 网关。

动态团队其实派生自直播团队,因此技术栈和直播当时基本一致,这里可以简单省略。

而众所周知,大部分电商团队的技术栈都是 Java 和 Spring 或 Dubbo。

因这几个业务实现上几乎没有相似的地方,且大家对 gRPC 协议逐渐地认同,因此技术栈上大家基本没有大一统的想法,互相能调通即可。

而随着 B 站团队进一步的壮大、流量持续的增长,进而经历了诸多线上故障、事故分析之后,大家慢慢发现了这套架构下的各种问题。

这些问题主要是:

  • 1)单个复杂模块也会导致后续业务集成的高难度,根据康威法则,复杂聚合型 BFF 和多团队之间就出现不匹配问题,团队之间沟通协调成本高,交付效率低下;
  • 2)很多跨横切面逻辑,比如安全认证,日志监控,限流熔断等。随着时间的推移,功能的迭代,代码变得越来越复杂,技术债越堆越多。

此时:我们可能还需要一个能协调横跨切面的组件,将路由、认证、限流、安全等组件全部上提,能够统一更新发布,把业务集成度高的 BFF 层和通用功能服务层进行分层,进而大家开始引入基于业务的“统一API网关”架构(如下图所示)。

在新的架构中:统一网关承担了重要的角色,它是解耦拆分和后续升级迁移的利器。

在统一网关的配合下:单块 BFF 实现了解耦拆分,各业务线团队可以独立开发和交付各自的微服务,研发效率大大提升。

另外:把跨横切面逻辑从 BFF 剥离到网关上去以后,BFF 的开发人员可以更加专注业务逻辑交付,实现了架构上的关注分离(Separation of Concerns)。

10、从基于业务的多网关到全局统一网关(2022年至今)

在这两三年的时间里,各个业务团队或多或少都有自己业务网关组建独立的维护团队,也为网关的功能作出过相当多的投入。

但随着 B 站业务的发展,公司级中间件功能的不断更替演进,如果将对接各个中间件的工作在每个网关上都实现一次的话带来的人力投入和沟通成本会相当巨大,且实现标准不统一、运营方式不统一无法起到 API 网关所带来的最佳收益。

因此微服务团队开发了一款 B 站内部意义上的标准 API 网关(全局统一API网关),该 API 网关汇集以往各型网关中流量治理的优秀经验,对相关功能做出完善设计改进。

该 API 网关的目前的主要功能除了常规的限流、熔断、降级、染色外,还会基于这些基础功能和公司各类中间件的基础上,提供各种额外能力。

这些额外进阶型AP 质量治理的相关功能主要是:

  • 1)全链路灰度;
  • 2)流量采样分析、回放;
  • 3)流量安全控制;
  • ...

业务团队在接入 API 网关后都可以一并获得这些功能,为业务的迅速迭代做出力所能及的保障。

11、不仅仅是 API 网关

在开发 API 网关的同时,我们也会更进一步关注业务团队开发、对接 API 时的体验,我们将以网关作为统一标准 API 规范的起点,为业务团队提供更有效的 API 开发生态。

这些API 开发生态可能是:

  • 1)规划 API 业务域,简化 SRE 运维;
  • 2)标准 API 元信息平台;
  • 3)精确的 API 文档和调试工具;
  • 4)类型安全的 API 集成 SDK;
  • 5)API 兼容性保障服务。

API 网关是我们 API 治理生态中的一个标志性里程碑,我们希望在 API 网关的开发中能够多多倾听大家的意见,希望能有更多的声音来帮助我们理清思路。

本次 API 网关演进也以开源形式进行了开发,在这里欢迎大家指导(本次源码详见本文“12、本文源码)。

12、本文源码

主地址:https://github.com/go-kratos/gateway

备地址:https://github.com/52im/gateway

或从原文链接中下载附件:http://www.52im.net/thread-3941-1-1.html

13、参考资料

[1] 喜马拉雅自研亿级API网关技术实践

[2] 手淘亿级移动端接入层网关的技术演进之路

[3] 从100到1000万高并发的架构演进之路

[4] 一文读懂大型分布式系统设计的方方面面

[5] 零基础理解大型分布式架构的演进历史、技术原理、最佳实践

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

posted @ 2022-06-14 11:56 Jack Jiang 阅读(144) | 评论 (0)编辑 收藏

本文引用了文章“月活 12.8 亿的微信是如何防止崩溃的?”和论文“Overload Control for Scaling WeChat Microservices”的内容,有大量改动、优化和修订。

1、引言

微信是一款国民级的即时通讯IM应用,月活用户早就超过10亿,而且经常过年过节会遇到聊天消息量暴增的情况,服务是很容易出现过载的,但事实是微信的后台服务一直比较稳定,那么他们是怎么做到的呢?

本文以微信发表的论文《Overload Control for Scaling Wechat Microservices》 为基础(论文PDF原文下载见文末附件),分享了微信基于大规模微服务架构的后台过载管控和保护策略,以及微信根据IM业务特点的一些独特的架构设计做法,其中很多方法很有借鉴意义,值得一读。

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

2、微信所面临的并发压力

截止论文《Overload Control for Scaling Wechat Microservices》发表前,微信后端有超过3000多个服务(包括即时聊天、社交关系、移动支付和第三方授权等),占用20000多台机器(随着微信的广泛普及,这些数字仍在不断增加)。

面向前端请求的入口服务每天需要处理10亿到100亿级别的请求,而每个这样的请求还会触发更多内部的关联服务,从整体来看,微信后端需要每秒处理数亿个请求。

随着微信的不断发展,这些服务子系统一直在快速进行更新迭代。以2018 年的3月到5月为例,在短短的两个月时间里,微信的各服务子系统平均每天发生近千次的变更,运维压力可想而之。

另外:微信每天请求量的分布很不平均,高峰期请求量能达到平时的3倍。而在特殊日子里(比如过年的时候),高峰期的流量能飙升到平时的10倍。有时朋友圈里有什么刷屏的活动,流量肯定也会突增。由此可见,微信后端系统的并发压力相当之大。

而且:微信后端的这些服务所处的环境也是不断变化的,包括硬件故障、代码bug、系统变更等,都会导致服务可承受的容量动态变化。

3、微信的后端服务架构

微信后端采用的也是微服务架构。说是微服务,其实我理解就是采用统一的 RPC 框架搭建的一个个独立的服务,服务之间互相调用,实现各种各样的功能,这也是现代服务的基本架构。毕竟谁也不希望看到我朋友圈崩了,导致跟我聊天也不行了,这也是微信的典型好处。

微信后端的微服务架构一般分为3层:

如上图所示,这3层服务分别是:

  • 1)“入口跳板”服务(接收外部请求的前端服务);
  • 2)“共享跳板”服务(中间层协调服务);
  • 3)“基础服务”(不再向其他服务发出请求的服务,也就是充当请求的接收器)。

微信后端的大多数服务属于“共享跳板”服务,“入口跳板”服务比如登录、发送聊天消息、支付服务等。“基础服务”也就是日常最好理解的这些信息数据接口类,比如账户数据、个人信息、好友/联系人信息等。

按照微信后端服务的请求量(每日在十亿到百亿之间),入口协议触发对“共享跳板”服务和“基础服务”更多的请求,核心服务每秒要处理上亿次的请求,也就是显而易见的了。

4、什么是过载保护

1)什么是服务过载?

服务过载就是服务的请求量超过服务所能承受的最大值,从而导致服务器负载过高,响应延迟加大。

用户侧表现就是无法加载或者加载缓慢,这会引起用户进一步的重试,服务一直在处理过去的无效请求,导致有效请求跌 0,甚至导致整个系统产生雪崩。

2)为什么会发生服务过载?

互联网天生就会有突发流量、秒杀、抢购、突发大事件、节日甚至恶意攻击等,都会造成服务承受平时数倍的压力,比如微博经常出现某明星官宣结婚或者离婚导致服务器崩溃的场景,这就是服务过载。

3)过载保护的好处

过载保护主要是为了提升用户体验,保障服务质量,在发生突发流量时仍然能够提供一部分服务能力,而不是整个系统瘫痪。

系统瘫痪就意味着用户流失、口碑变差、夫妻吵架,甚至威胁生命安全(假如腾讯文档崩溃,这个文档正好用于救灾)。

而微信团队在面对这种量级的高并发请求挑战,做法是精细化的服务过载控制。我们继续往下学习。

5、微信面临的过载控制技术挑战

过载控制对于大规模在线应用程序来说至关重要,这些应用程序需要在不可预测的负载激增的情况下实现 24×7 服务可用性。

传统的过载控制机制是为具有少量服务组件、相对狭窄的“前门”和普通依赖关系的系统而设计的。

而微信这种现代即时通讯im应用的全时在线服务特性,在架构和依赖性方面正变得越来越复杂,远远超出了传统过载控制的设计目标。

这些技术痛点包括:

  • 1)由于发送到微信后端的服务请求没有单一的入口点,因此传统的全局入口点(网关)集中负载监控方法并不适用;
  • 2)特定请求的服务调用图可能依赖于特定于请求的数据和服务参数,即使对于相同类型的请求也是如此(因此,当特定服务出现过载时,很难确定应该限制哪些类型的请求以缓解这种情况);
  • 3)过多的请求中止浪费了计算资源,并由于高延迟而影响了用户体验;
  • 4)由于服务的调用链极其复杂,而且在不断演化,导致有效的跨服务协调的维护成本和系统开销过高。

由于一个服务可能会向它所依赖的服务发出多个请求,并且还可能向多个后端服务发出请求,因此我们必须特别注意过载控制。我们使用一个专门的术语,叫作“后续过载”,用于描述调用多个过载服务或多次调用单个过载服务的情况。

“后续过载”给有效的过载控制带来了挑战。当服务过载时随机执行减载可以让系统维持饱和的吞吐量,但后续过载可能会超预期大大降低系统吞吐量 …

即:在大规模微服务场景下,过载会变得比较复杂,如果是单体服务,一个事件只用一个请求,但微服务下,一个事件可能要请求很多的服务,任何一个服务过载失败,就会造成其他的请求都是无效的。如下图所示。

 比如:在一个转账服务下,需要查询分别两者的卡号, 再查询 A 时成功了,但查询 B 失败,对于查卡号这个事件就算失败了。比如查询成功率只有 50%, 那对于查询两者卡号这个成功率只有 50% * 50% = 25% 了, 一个事件调用的服务次数越多,那成功率就会越低。

6、微信的过载控制机制

微信的微服务过载控制机制叫“DAGOR”(因为微信把它的服务间关系模型叫“directed acyclic graph ”,简称DAG)。

显然这种微服务底层的机制必须是和具体的业务实现无关的。DAGOR还必须是去中心化的,否则的话在微信这么大且分布不均的流量下,过载控制很难做到实时和准确。同时也无法适应微服务快速的功能迭代发布(平均每天要发生近1000次的微服务上下线)。

此外,DAGOR还需要解决一个问题:服务调用链很长,如果底层服务因为过载保护丢弃了请求,上层服务耗费的资源全浪费了,而且很影响用户体验(想想进度条走到99%告诉你失败了)。所以过载控制机制在各服务之间必须有协同作用,有时候需要考虑整个调用链的情况。

首先我们来看怎么检测到服务过载。

7、微信如何判断过载

通常判断过载可以使用吞吐量、延迟、CPU 使用率、丢包率、待处理请求数、请求处理事件等等。

微信使用在请求在队列中的平均等待时间作为判断标准。平均等待时间就是从请求到达,到开始处理的时间。

为啥不使用响应时间?因为响应时间是跟服务相关的,很多微服务是链式调用,响应时间是不可控的,也是无法标准化的,很难作为一个统一的判断依据。

那为什么也不使用 CPU 负载作为判断标准呢? 因为 CPU 负载高不代表服务过载,因为一个服务请求处理及时,CPU 处于高位反而是比较良好的表现。实际上 CPU 负载高,监控服务是会告警出来,但是并不会直接进入过载处理流程。

腾讯微服务默认的超时时间是 500ms,通过计算每秒或每 2000 个请求的平均等待时间是否超过 20ms,判断是否过载,这个 20ms 是根据微信后台 5 年摸索出来的门槛值。

采用平均等待时间还有一个好处是:独立于服务,可以应用于任何场景,而不用关联于业务,可以直接在框架上进行改造。

当平均等待时间大于 20ms 时,以一定的降速因子过滤调部分请求,如果判断平均等待时间小于 20ms,则以一定的速率提升通过率,一般采用快降慢升的策略,防止大的服务波动,整个策略相当于一个负反馈电路。

 

8、微信的过载控制策略

微信后台一旦检测到服务过载,就需要按照一定的过载保户策略对请求进行过滤控制,来决定哪些请求能被过载服务处理,哪些是需要丢弃的。

前面我们分析过,对于链式调用的微服务场景,随机丢弃请求会导致整体服务的成功率很低。所以请求是按照优先级进行控制的,优先级低的请求会优先丢弃。

那么从哪些维度来进行优化级的分级呢?

8.1 基于业务的优先级控制

对于微信来说,不同的业务场景优先级是不同的, 比如:

  • 1)登录场景是最重要的业务(不能登录一切都白瞎);
  • 2)支付消息比普通im聊天消息优先级高(因为用户对金钱是更敏感的);
  • 3)普通消息又比朋友圈消息优先级高(必竟微信的本质还是im聊天)。

所以在微信内是天然存在业务优先级的。

微信的做法是,预先定义好所有业务的优先级并保存在一个Hash Table里:

没有定义的业务,默认是最低优先级。

业务优先级在各个业务的入口服务(Entry Services)中找到请求元信息里。由于一个请求成功与否依赖其下游服务所有的后续请求,所以下游服务的所有后续请求也会带上相同的业务优先级。当服务过载时,会处理优先级更高的请求,丢弃优先级低的请求。

然而,只用业务优先级决定是否丢弃请求,容易造成系统颠簸,比如:

  • 1)支付请求突然上涨导致过载,消息请求被丢弃;
  • 2)丢弃消息请求后,系统负载降低了,又开始处理消息请求;
  • 3)然而,处理消息请求又导致服务过载,又会在下一个窗口抛弃消息请求。

这样反复调整服务请求管制,整体体验非常不好。所以微信需要更精细化的服务请求管制。

PS:微信尝试过提供API让服务提供方自己修改业务优先级,后来在实践中发现这种做法在不同的团队中极难管理,且对于过载控制容易出错,最终放弃了。

8.2 基于用户的优先级控制

很明显,正如上节内容所述,只基于业务优先级的控制是不够的:

  • 1)首先不可能因为负载高,丢弃或允许通过一整个业务的请求,因为每个业务的请求量很大,那一定会造成负载的大幅波动;
  • 2)另外如果在业务中随机丢弃请求,在过载情况下还是会导致整体成功率很低。

为了解决这个问题,微信引入用户优先级。

微信在每个业务优先级内按用户ID计算出的128个优先级:

首先用户优先级也不应该相同,对于普通人来说通过 hash 用户唯一 ID计算用户优先级(这个hash函数每小时变一次,让所有用户都有机会在相对较长的时间内享受到高优先级,保证“公平”)。跟业务优先级一样,单个用户的访问链条上的优先级总是一致的。

这里有个疑问:为啥不采用会话 ID 计算优先级呢?

从理论上来说采用会话 ID 和用户 ID 效果是一样的,但是采用会话 ID 在用户重新登录时刷新,这个时候可能用户的优先级可能变了。在过载的情况下,他可能因为提高了优先级就恢复了。

这样用户会养成坏习惯,在服务有问题时就会重新登录,这样无疑进一步加剧了服务的过载情况。

于是,因为引入了用户优先级,那就和业务优先级组成了一个二维控制平面。根据负载情况,决定这台服务器的准入优先级(B,U),当过来的请求业务优先级大于 B,或者业务优先级等于 B,但用户优先级高于 U 时,则通过,否则决绝。

下图就是这个“优先级(B,U)”控制逻辑(我们会在后面再具体讨论):

8.3 自适应优先级调整

在大规模微服务场景下,服务器的负载变化是非常频繁的。所以服务器的准入优先级是需要动态变化的,微信分了几十个业务优先级,每个业务优先级下有 128 个用户优先级,所以总的优先级是几千个。

如何根据负载情况调整优先级呢?

最简单的方式是从右到左遍历:每调整一次判断下负载情况。这个时间复杂度是 O(n), 就算使用二分法,时间复杂度也为 O(logn),在数千个优先级下,可能需要数十次调整才能确定一个合适的优先级,每次调整好再统计优先级,可能几十秒都过去了,这个方法无疑是非常低效的。

微信提出了一种基于直方图统计的方法快速调整准入优先级:服务器上维护者目前准入优先级下,过去一个周期的(1s 或 2000 次请求)每个优先级的请求量。当过载时,通过消减下一个周期的请求量来减轻负载。假设上一个周期所有优先级的通过的请求总和是 N,下一个周期的请求量要减少 N*a,怎么去减少呢?每提升一个优先级就减少一定的请求量,一直提升到 减少的数目大于目标量,恢复负载使用相反的方法,只不是系数为 b ,比 a 小,也是为了快降慢升。根据经验值 a 为 5%,b 为 1%。

为了进一步减轻过载机器的压力,能不能在下游过载的情况下不把请求发到下游呢?否则下游还是要接受请求、解包、丢弃请求,白白的浪费带宽,也加重了下游的负载。

为了实现这个能力:在每次请求下游服务时,下游把当前服务的准入优先级返回给上游,上游维护下游服务的准入优先级,如果发现请求优先级达不到下游服务的准入门槛,直接丢弃,而不再请求下游,进一步减轻下游的压力。

9、实验数据

微信的这套服务过载控制策略(即DAGOR)在微信的生产环境已经运作多年,这是对它的设计可行性的最好证明。

但并没有为学术论文提供必要的图表,所以微信同时进行了一组模拟实验。

下面的图表突出显示了基于排队时间而非响应时间的过载控制的好处。在发生后续过载的情况下,这些好处最为明显(图右)。

10、小结一下

微信的整个过载控制逻辑流程如下图所示:

针对上面这张图,我们来解读一下:

  • 1)当用户从微信发起请求,请求被路由到接入层服务,分配统一的业务和用户优先级,所有到下游的字请求都继承相同的优先级;
  • 2)根据业务逻辑调用 1 个或多个下游服务,当服务收到请求,首先根据自身服务准入优先级判断请求是接受还是丢弃(服务本身根据负载情况周期性的调整准入优先级);
  • 3)当服务需要再向下游发起请求时,判断本地记录的下游服务准入优先级(如果小于则丢弃,如果没有记录或优先级大于记录则向下游发起请求);
  • 4)下游服务返回上游服务需要的信息,并且在信息中携带自身准入优先级;
  • 5)上游接受到返回后解析信息,并更新本地记录的下游服务准入优先级。

微信的整个过载控制策略有以下三个特点:

  • 1)业务无关的:使用请求等待时间而不是响应时间,制定用户和业务优先级,这些都与业务本身无关;
  • 2)高效且公平: 请求链条的优先级是一致的,并且会定时改变 hash 函数调整用户优先级,过载情况下,不会总是影响固定的用户;
  • 3)独立控制和联合控制结合:准入优先级取决于独立的服务,但又可以联合下游服务的情况,优化服务过载时的表现。

11、写在最后

微信团队的分享只提到过载控制,但我相信服务调用方应该还有一些其他机制,能够解决不是因为下游服务过载,而是因为网络抖动导致的请求超时问题。

微信的这套微服务过载控制机制(即DAGOR)提供的服务无关、去中心化、高效和公平等特性很好地在微信后端跑了很多年。

最后,微信团队还分享了他们设计和运维DAGOR宝贵经验:

  • 1)大规模微服务架构中的过载控制必须在每个服务中实现分散和自治;
  • 2)过载控制应该要考虑到各种反馈机制(例如 DAGOR 的协作准入控制),而不是仅仅依赖于开环启发式;
  • 3)应该通过分析实际工作负载来了解过载控制设计。

12、参考资料

[1] Overload Control for Scaling WeChat Microservices

[2] 罗神解读“Overload Control for Scaling WeChat Microservices”

[3] 2W台服务器、每秒数亿请求,微信如何不“失控”?

[4] DAGOR:微信微服务过载控制系统

[5] 月活 12.8 亿的微信是如何防止崩溃的?

[6] 微信朋友圈千亿访问量背后的技术挑战和实践总结

[7] QQ 18年:解密8亿月活的QQ后台服务接口隔离技术

[8] 微信后台基于时间序的海量数据冷热分级架构设计实践

[9] 架构之道:3个程序员成就微信朋友圈日均10亿发布量[有视频]

[10] 快速裂变:见证微信强大后台架构从0到1的演进历程(一)

[11] 一份微信后台技术架构的总结性笔记

13、论文原文

论文PDF请下载此附件:

因无法上传附件,请从此链接:http://www.52im.net/thread-3930-1-1.html文末的“参考资料”附件中下载

论文PDF全部内容概览:

本文已同步发布于:http://www.52im.net/thread-3930-1-1.html

posted @ 2022-06-06 16:31 Jack Jiang 阅读(606) | 评论 (0)编辑 收藏

本文由蘑菇街前端开发工程师“三体”分享,原题“蘑菇街云端直播探索——启航篇”,有修订。

1、引言

随着移动网络网速的提升与资费的降低,视频直播作为一个新的娱乐方式已经被越来越多的用户逐渐接受。特别是最近这几年,视频直播已经不仅仅被运用在传统的秀场、游戏类板块,更是作为电商的一种新模式得到迅速成长。

本文将通过介绍实时视频直播技术体系,包括常用的推拉流架构、传输协议等,让你对现今主流的视频直播技术有一个基本的认知。

学习交流:

本文已同步发布于:http://www.52im.net/thread-3922-1-1.html

2、蘑菇街的直播架构概览

目前蘑菇街直播推拉流主流程依赖于某云直播的服务。

云直播提供的推流方式有两种:

  • 1)一是通过集成SDK的方式进行推流(用于手机端开播);
  • 2)另一种是通过RTMP协议向远端服务器进行推流(用于PC开播端或专业控台设备开播)。

除去推拉流,该云平台也提供了云通信(IM即时通讯能力)和直播录制等云服务,组成了一套直播所需要的基础服务。

3、推拉流架构1:厂商SDK推拉流

如上题所示,这一种推拉流架构方式需要依赖腾讯这类厂商提供的手机互动直播SDK,通过在主播端APP和用户端APP都集成SDK,使得主播端和用户端都拥有推拉流的功能。

这种推拉流架构的逻辑原理是这样的:

  • 1)主播端和用户端分别与云直播的互动直播后台建立长连接;
  • 2)主播端通过UDT私有协议向互动直播后台推送音视频流;
  • 3)互动直播后台接收到音视频流后做转发,直接下发给与之建立连接的用户端。

这种推拉流方式有几点优势:

  • 1)只需要在客户端中集成SDK:通过手机就可以开播,对于主播开播的要求比较低,适合直播业务快速铺开;
  • 2)互动直播后台仅做转发:没有转码,上传CDN等额外操作,整体延迟比较低;
  • 3)主播端和用户端都可以作为音视频上传的发起方:适合连麦、视频会话等场景。

4、推拉流架构2:旁路推流

之前介绍了通过手机SDK推拉流的直播方式,看起来在手机客户端中观看直播的场景已经解决了。

那么问题来了:如果我想要在H5、小程序等其他场景下观看直播,没有办法接入SDK,需要怎么处理呢?

这个时候需要引入一个新的概念——旁路推流。

旁路推流指的是:通过协议转换将音视频流对接到标准的直播 CDN 系统上。

目前云直播开启旁路推流后,会通过互动直播后台将音视频流推送到云直播后台,云直播后台负责将收到音视频流转码成通用的协议格式并且推送到CDN,这样H5、小程序等端就可以通过CDN拉取到通用格式的音视频流进行播放了。

目前蘑菇街直播旁路开启的协议类型有HLS、FLV、RTMP三种,已经可以覆盖到所有的播放场景,在后续章节会对这几种协议做详细的介绍。

5、推拉流架构3:RTMP推流

随着直播业务发展,一些主播逐渐不满足于手机开播的效果,并且电商直播需要高保真地将商品展示在屏幕上,需要通过更加高清专业的设备进行直播,RTMP推流技术应运而生。

我们通过使用OBS等流媒体录影程序,对专业设备录制的多路流进行合并,并且将音视频流上传到指定的推流地址。由于OBS推流使用了RTMP协议,因此我们称这一种推流类型为RTMP推流。

我们首先在云直播后台申请到推流地址和秘钥,将推流地址和秘钥配置到OBS软件当中,调整推流各项参数,点击推流以后,OBS就会通过RTMP协议向对应的推流地址推送音视频流。

这一种推流方式和SDK推流的不同之处在于音视频流是直接被推送到了云直播后台进行转码和上传CDN的,没有直接将直播流转推到用户端的下行方式,因此相比SDK推流延迟会长一些。

总结下来RTMP推流的优势和劣势比较明显。

优势主要是:

  • 1)可以接入专业的直播摄像头、麦克风,直播的整体效果明显优于手机开播;
  • 2)OBS已经有比较多成熟的插件,比如目前蘑菇街主播常用YY助手做一些美颜的处理,并且OBS本身已经支持滤镜、绿幕、多路视频合成等功能,功能比手机端强大。

劣势主要是:

  • 1)OBS本身配置比较复杂,需要专业设备支持,对主播的要求明显更高,通常需要一个固定的场地进行直播;
  • 2)RTMP需要云端转码,并且本地上传时也会在OBS中配置GOP和缓冲,延时相对较长。

6、高可用架构方案:云互备

业务发展到一定阶段后,我们对于业务的稳定性也会有更高的要求,比如当云服务商服务出现问题时,我们没有备用方案就会出现业务一直等待服务商修复进度的问题。

因此云互备方案就出现了:云互备指的是直播业务同时对接多家云服务商,当一家云服务商出现问题时,快速切换到其他服务商的服务节点,保证业务不受影响。

直播业务中经常遇到服务商的CDN节点下行速度较慢,或者是CDN节点存储的直播流有问题,此类问题有地域性,很难排查,因此目前做的互备云方案,主要是备份CDN节点。

目前蘑菇街整体的推流流程已经依赖了原有云平台的服务,因此我们通过在云直播后台中转推一路流到备份云平台上,备份云在接收到了直播流后会对流转码并且上传到备份云自身的CDN系统当中。一旦主平台CDN节点出现问题,我们可以将下发的拉流地址替换成备份云拉流地址,这样就可以保证业务快速修复并且观众无感知。

7、视频直播数据流解封装原理

介绍流协议之前,先要介绍我们从云端拿到一份数据,要经过几个步骤才能解析出最终需要的音视频数据。

如上图所示,总体来说,从获取到数据到最终将音视频播放出来要经历四个步骤。

第一步:解协议。

协议封装的时候通常会携带一些头部描述信息或者信令数据,这一部分数据对我们音视频播放没有作用,因此我们需要从中提取出具体的音视频封装格式数据,我们在直播中常用的协议有HTTP和RTMP两种。

第二步:解封装。

获取到封装格式数据以后需要进行解封装操作,从中分别提取音频压缩流数据和视频压缩流数据,封装格式数据我们平时经常见到的如MP4、AVI,在直播中我们接触比较多的封装格式有TS、FLV。

第三步:解码音视频。

到这里我们已经获取了音视频的压缩编码数据。

我们日常经常听到的视频压缩编码数据有H.26X系列和MPEG系列等,音频编码格式有我们熟悉的MP3、ACC等。

之所以我们能见到如此多的编码格式,是因为各种组织都提出了自己的编码标准,并且会相继推出一些新的议案,但是由于推广和收费问题,目前主流的编码格式也并不多。

获取压缩数据以后接下来需要将音视频压缩数据解码,获取非压缩的颜色数据和非压缩的音频抽样数据。颜色数据有我们平时熟知的RGB,不过在视频的中常用的颜色数据格式是YUV,指的是通过明亮度、色调、饱和度确定一个像素点的色值。音频抽样数据通常使用的有PCM。

第四步:音视频同步播放。

最后我们需要比对音视频的时间轴,将音视频解码后的数据交给显卡声卡同步播放。

PS:如果你对上述流程还不太理解,建议进一步阅读以下系列文章:

  1. 移动端实时音视频直播技术详解(一):开篇
  2. 移动端实时音视频直播技术详解(二):采集
  3. 移动端实时音视频直播技术详解(三):处理
  4. 移动端实时音视频直播技术详解(四):编码和封装
  5. 移动端实时音视频直播技术详解(五):推流和传输
  6. 移动端实时音视频直播技术详解(六):延迟优化

另外:有关音视频编解码技术的文章,也可以详细学习以下文章:

  1. 视频编解码之:《理论概述》、《数字视频介绍》、《编码基础》、《预测技术介绍
  2. 认识主流视频编码技术H.264
  3. 如何开始音频编解码技术的学习
  4. 音频基础及编码原理入门
  5. 常见的实时语音通讯编码标准
  6. 实时视频编码H.264的特点与优势》、《视频编码H.264、VP8的前世今生
  7. 详解音频编解码的原理、演进和应用选型》、《零基础,史上最通俗视频编码技术入门

8、视频直播传输协议1:HLS

首先介绍一下HLS协议。HLS是HTTP Live Streaming的简写,是由苹果公司提出的流媒体网络传输协议。

从名字可以明显看出:这一套协议是基于HTTP协议传输的。

说到HLS协议:首先需要了解这一种协议是以视频切片的形式分段播放的,协议中使用的切片视频格式是TS,也就是我们前文提到的封装格式。

在我们获取TS文件之前:协议首先要求请求一个M3U8格式的文件,M3U8是一个描述索引文件,它以一定的格式描述了TS地址的指向,我们根据M3U8文件中描述的内容,就可以获取每一段TS文件的CDN地址,通过加载TS地址分段播放就可以组合出一整段完整的视频。

使用HLS协议播放视频时:首先会请求一个M3U8文件,如果是点播只需要在初始化时获取一次就可以拿到所有的TS切片指向,但如果是直播的话就需要不停地轮询M3U8文件,获取新的TS切片。

获取到M3U8后:我们可以看一下里面的内容。首先开头是一些通用描述信息,比如第一个分片序列号、片段最大时长和总时长等,接下来就是具体TS对应的地址列表。如果是直播,那么每次请求M3U8文件里面的TS列表都会随着最新的直播切片更新,从而达到直播流播放的效果。

HLS这种切片播放的格式在点播播放时是比较适用的,一些大的视频网站也都有用这一种协议作为播放方案。

首先:切片播放的特性特别适用于点播播放中视频清晰度、多语种的热切换。比如我们播放一个视频,起初选择的是标清视频播放,当我们看了一半觉得不够清晰,需要换成超清的,这时候只需要将标清的M3U8文件替换成超清的M3U8文件,当我们播放到下一个TS节点时,视频就会自动替换成超清的TS文件,不需要对视频做重新初始化。

其次:切片播放的形式也可以比较容易地在视频中插入广告等内容。

在直播场景下,HLS也是一个比较常用的协议,他最大的优势是苹果大佬的加持,对这一套协议推广的比较好,特别是移动端。将M3U8文件地址喂给video就可以直接播放,PC端用MSE解码后大部分浏览器也都能够支持。但是由于其分片加载的特性,直播的延迟相对较长。比如我们一个M3U8有5个TS文件,每个TS文件播放时长是2秒,那么一个M3U8文件的播放时长就是10秒,也就是说这个M3U8播放的直播进度至少是10秒之前的,这对于直播场景来说是一个比较大的弊端。

HLS中用到的TS封装格式,视频编码格式是通常是H.264或MPEG-4,音频编码格式为AAC或MP3。

一个ts由多个定长的packtet组成,通常是188个字节,每个packtet有head和payload组成,head中包含一些标识符、错误信息、包位置等基础信息。payload可以简单理解为音视频信息,但实际上下层还有还有两层封装,将封装解码后可以获取到音视频流的编码数据。

9、视频直播传输协议2:HTTP-FLV

HTTP-FLV协议,从名字上就可以明显看出是通过HTTP协议来传输FLV封装格式的一种协议。

FLV是Flash Video的简写,是一种文件体积小,适合在网络上传输的封包方式。FlV的视频编码格式通常是H.264,音频编码是ACC或MP3。

HTTP-FLV在直播中是通过走HTTP长连接的方式,通过分块传输向请求端传递FLV封包数据。

在直播中,我们通过HTTP-FLV协议的拉流地址可以拉取到一段chunked数据。

打开文件后可以读取到16进制的文件流,通过和FLV包结构对比,可以发现这些数据就是我们需要的FLV数据。

首先开头是头部信息:464C56转换ASCII码后是FLV三个字符,01指的是版本号,05转换为2进制后第6位和第8位分别代表是否存在音频和视频,09代表头部长度占了几个字节。

后续就是正式的音视频数据:是通过一个个的FLV TAG进行封装,每一个TAG也有头部信息,标注这个TAG是音频信息、视频信息还是脚本信息。我们通过解析TAG就可以分别提取音视频的压缩编码信息。

FLV这一种格式在video中并不是原生支持的,我们要播放这一种格式的封包格式需要通过MSE对影视片的压缩编码信息进行解码,因此需要浏览器能够支持MSE这一API。由于HTTP-FLV的传输是通过长连接传输文件流的形式,需要浏览器支持Stream IO或者fetch,对于浏览器的兼容性要求会比较高。

FLV在延迟问题上相比切片播放的HLS会好很多,目前看来FLV的延迟主要是受编码时设置的GOP长度的影响。

这边简单介绍一下GOP:在H.264视频编码的过程中,会生成三种帧类型:I帧、B帧和P帧。I帧就是我们通常说的关键帧,关键帧内包括了完整的帧内信息,可以直接作为其他帧的参考帧。B帧和P帧为了将数据压缩得更小,需要由其他帧推断出帧内的信息。因此两个I帧之间的时长也可以被视作最小的视频播放片段时长。从视频推送的稳定性考虑,我们也要求主播将关键帧间隔设置为定长,通常是1-3秒,因此除去其他因素,我们的直播在播放时也会产生1-3秒的延时。

10、视频直播传输协议3:RTMP

RTMP协议实际可以与HTTP-FLV协议归做同一种类型。

他们的封包格式都是FlV,但HTTP-FLV使用的传输协议是HTTP,RTMP拉流使用RTMP作为传输协议。

RTMP是Adobe公司基于TCP做的一套实时消息传输协议,经常与Flash播放器匹配使用。

RTMP协议的优缺点非常明显。

RTMP协议的优点主要是:

  • 1)首先和HTTP-FLV一样,延迟比较低;
  • 2)其次它的稳定性非常好,适合长时间播放(由于播放时借用了Flash player强大的功能,即使开多路流同时播放也能保证页面不出现卡顿,很适合监控等场景)。

但是Flash player目前在web端属于墙倒众人推的境地,主流浏览器渐渐都表示不再支持Flash player插件,在MAC上使用能够立刻将电脑变成烧烤用的铁板,资源消耗很大。在移动端H5基本属于完全不支持的状态,兼容性是它最大的问题。

11、视频直播传输协议4:MPEG-DASH

MPEG-DASH这一协议属于新兴势力,和HLS一样,都是通过切片视频的方式进行播放。

他产生的背景是早期各大公司都自己搞自己的一套协议。比如苹果搞了HLS、微软搞了 MSS、Adobe还搞了HDS,这样使用者需要在多套协议封装的兼容问题上痛苦不堪。

于是大佬们凑到一起,将之前各个公司的流媒体协议方案做了一个整合,搞了一个新的协议。

由于同为切片视频播放的协议,DASH优劣势和HLS类似,可以支持切片之间多视频码率、多音轨的切换,比较适合点播业务,在直播中还是会有延时较长的问题。

12、如何选择最优的视频直播传输协议

视频直播协议选择非常关键的两点,在前文都已经有提到了,即低延时和更优的兼容性。

首先从延时角度考虑:不考虑云端转码以及上下行的消耗,HLS和MPEG-DASH通过将切片时长减短,延时在10秒左右;RTMP和FLV理论上延时相当,在2-3秒。因此在延时方面HLS ≈ DASH > RTMP ≈ FLV。

从兼容性角度考虑:HLS > FLV > RTMP,DASH由于一些项目历史原因,并且定位和HLS重复了,暂时没有对其兼容性做一个详尽的测试,被推出了选择的考虑范围。

综上所述:我们可以通过动态判断环境的方式,选择当前环境下可用的最低延迟的协议。大致的策略就是优先使用HTTP-FLV,使用HLS作为兜底,在一些特殊需求场景下通过手动配置的方式切换为RTMP。

对于HLS和HTTP-FLV:我们可以直接使用 hls.js 和 flv.js 做做解码播放,这两个库内部都是通过MSE做的解码。首先根据视频封装格式提取出对应的音视频chunk数据,在MediaSource中分别对音频和视频创建SourceBuffer,将音视频的编码数据喂给SourceBuffer后SourceBuffer内部会处理完剩下的解码和音视频对齐工作,最后MediaSource将Video标签中的src替换成MediaSource 对象进行播放。

在判断播放环境时我们可以参照flv.js内部的判断方式,通过调用MSE判断方法和模拟请求的方式判断MSE和StreamIO是否可用:

// 判断MediaSource是否被浏览器支持,H.264视频编码和Acc音频编码是否能够被支持解码

window.MediaSource && window.MediaSource.isTypeSupported('video/mp4; codecs="avc1.42E01E,mp4a.40.2"');

如果FLV播放不被支持的情况下:需要降级到HLS,这时候需要判断浏览器环境是否在移动端,移动端通常不需要 hls.js 通过MSE解码的方式进行播放,直接将M3U8的地址交给video的src即可。如果是PC端则判断MSE是否可用,如果可用就使用hls.js解码播放。

这些判读可以在自己的逻辑里提前判断后去拉取对应解码库的CDN,而不是等待三方库加载完成后使用三方库内部的方法判断,这样在选择解码库时就可以不把所有的库都拉下来,提高加载速度。

13、同层播放如何解决

电商直播需要观众操作和互动的部分比起传统的直播更加多,因此产品设计的时候很多的功能模块会悬浮在直播视频上方减少占用的空间。这个时候就会遇到一个移动端播放器的老大难问题——同层播放。

同层播放问题:是指在移动端H5页面中,一些浏览器内核为了提升用户体验,将video标签被劫持替换为native播放器,导致其他元素无法覆盖于播放器之上。

比如我们想要在直播间播放器上方增加聊天窗口,将聊天窗口通过绝对定位提升z-index置于播放器上方,在PC中测试完全正常。但在移动端的一些浏览器中,video被替换成了native播放器,native的元素层级高于我们的普通元素,导致聊天窗口实际显示的时候在播放器下方。

要解决这个问题,首先要分多个场景。

首先在iOS系统中:正常情况下video标签会自动被全屏播放,但iOS10以上已经原生提供了video的同层属性,我们在video标签上增加playsinline/webkit-playsinline可以解决iOS系统中大部分浏览器的同层问题,剩下的低系统版本的浏览器以及一些APP内的webview容器(譬如微博),用上面提的属性并不管用,调用三方库iphone-inline-video可以解决大部分剩余问题。

在Android端:大部分腾讯系的APP内置的webview容器用的都是X5内核,X5内核会将video替换成原生定制的播放器已便于增强一些功能。X5也提供了一套同层的方案(该方案官方文档链接已无法打开),给video标签写入X5同层属性也可以在X5内核中实现内联播放。不过X5的同层属性在各个X5版本中表现都不太一样(比如低版本X5中需要使用X5全屏播放模式才能保证MSE播放的视频同层生效),需要注意区分版本。

在蘑菇街App中,目前集成的X5内核版本比较老,在使用MSE的情况下会导致X5同层参数不生效。但如果集成新版本的X5内核,需要对大量的线上页面做回归测试,成本比较高,因此提供了一套折中的解决方案。通过在页面URL中增加一个开关参数,容器读取到参数以后会将X5内核降级为系统原生的浏览器内核,这样可以在解决浏览器视频同层问题的同时也将内核变动的影响范围控制在单个页面当中。

14、相关文章

[1] 移动端实时音视频直播技术详解(四):编码和封装

[2] 移动端实时音视频直播技术详解(五):推流和传输

[3] 实现延迟低于500毫秒的1080P实时音视频直播的实践分享

[4] 浅谈开发实时视频直播平台的技术要点

[5] 直播系统聊天技术(七):直播间海量聊天消息的架构设计难点实践

[6] 从0到1:万人在线的实时音视频直播技术实践分享(视频+PPT) [附件下载]

[7] 实时视频编码H.264的特点与优势

[8] 视频编码H.264、VP8的前世今生

[9] 零基础,史上最通俗视频编码技术入门

[10] 视频编解码之编码基础

[11] 零基础入门:实时音视频技术基础知识全面盘点

[12] 实时音视频面视必备:快速掌握11个视频技术相关的基础概念

[13] 写给小白的实时音视频技术入门提纲

本文已同步发布于:http://www.52im.net/thread-3922-1-1.html

posted @ 2022-05-31 15:26 Jack Jiang 阅读(299) | 评论 (0)编辑 收藏

     摘要: 本文作者张彦飞,原题“聊聊TCP连接耗时的那些事儿”,有少许改动。1、引言对于基于互联网的通信应用(比如IM聊天、推送系统),数据传递时使用TCP协议相对较多。这是因为在TCP/IP协议簇的传输层协议中,TCP协议具备可靠的连接、错误重传、拥塞控制等优点,所以目前在应用场景上比UDP更广泛一些。相信你也一定听闻过TCP也存在一些缺点,能常都是老生常谈的开销要略大。但是各路技...  阅读全文

posted @ 2022-05-26 16:10 Jack Jiang 阅读(166) | 评论 (0)编辑 收藏

     摘要: 本文作者“Carson”,现就职于腾讯公司,原题“高效保活长连接:手把手教你实现自适应的心跳保活机制”,有较多修订和改动。1、引言当要实现IM即时通讯聊天、消息推送等高实时性需求时,我们一般会选择长连接的通信方式。而真正当实现长连接方式时,会遇到很多技术问题,比如最常见的长连接保活问题。今天,我将通过本篇文章,手把手教大家实现一套可自适应的心跳保活机...  阅读全文

posted @ 2022-05-18 15:09 Jack Jiang 阅读(218) | 评论 (0)编辑 收藏

本文由ELab技术团队分享,原题“探秘HTTPS”,有修订和改动。

1、引言

对于IM开发者来说,IM里最常用的通信技术就是Socket长连接和HTTP短连接(通常一个主流im会是这两种通信手段的结合)。从通信安全的角度来说,Socket长连接的安全性,就是基于SSL/TLS加密的TCP协议来实现的(比如微信的mmtls,见《微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解);而对于HTTP短连接的安全性,也就是HTTPS了。

到底什么是HTTPS?为什么要用HTTPS?今天就借此机会,跟大家一起深入学习一下HTTPS的相关知识,包括HTTP的发展历程、HTTP遇到的问题、对称与非对称加密算法、数字签名、第三方证书颁发机构等概念。

学习交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK 

本文已同步发布于:http://www.52im.net/thread-3897-1-1.html

2、系列文章

本文是IM通讯安全知识系列文章中的第9篇,此系列总目录如下:

3、写在前面

说到HTTPS,那就得回到HTTP协议。

对于HTTP协议,大家肯定都熟得不能再熟了。那么HTTPS和HTTP的区别大家了解吗?

对于这个经典的面试题,大部分人会这么回答:

  • 1)HTTPS比HTTP多了一个S(Secure):也就是说HTTPS是安全版的HTTP;
  • 2)端口号不同:HTTP使用80端口,HTTPS使用443端口;
  • 3)加密算法:HTTPS用的是非对称加密算法。

上面的回答能给几分?等看完本文我们可以再回头来看下这个回答。

那么,HTTPS是如何实现安全的短连接数据传输呢?想彻底搞明白这个问题,还是要从HTTP的发展历程说起 ......

4、HTTP协议回顾

4.1 基础常识

HTTP是Hypertext Transfer Protocal 的缩写,中文全称是超文本传输协议(详见《深入浅出,全面理解HTTP协议)。

通俗了解释就是:

  • 1)超文本是指包含但不限于文本外的图片、音频、视频等多媒体资源;
  • 2)协议是通信双方约定好的数据传输格式以及通信规则。

HTTP是TCP/IP协议簇的最高层——应用层协议:

▲ 上图引用自《深入浅出,全面理解HTTP协议

浏览器和服务器在使用HTTP协议相互传递超文本数据时,将数据放入报文体内,同时填充首部(请求头或响应头)构成完整HTTP报文并交到下层传输层,之后每一层加上相应的首部(控制部分)便一层层的下发,最终由物理层将二进制数据以电信号的形式发送出去。

HTTP的请求如下图所示:

▲ 上图引用自《深入浅出,全面理解HTTP协议

HTTP报文结构如下:

4.2 发展历程

HTTP的发展历程如下:

由HTTP的发展历程来看,最开始版本的HTTP(HTTP1.0)在每次建立TCP连接后只能发起一次HTTP请求,请求完毕就释放TCP连接。

我们都知道TCP连接的建立需要经过三次握手的过程,而每次发送HTTP请求都需要重新建立TCP连接,毫无疑问是很低效的。所以HTTP1.1改善了这一点,使用长连接的机制,也就是“一次TCP连接,N次HTTP请求”。

HTTP协议的长连接和短连接,实质上是 TCP 协议的长连接和短连接。

在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接需要客户端和服务端都支持长连接。

PS:对于IM开发者来说,为了与Socket长连接通道区分,通常认为HTTP就是“短连接”虽然这个“短连接”不一定真的“短”)。

HTTP1.0若要开启长连接,需要加上Connection: keep-alive请求头。有关HTTP协议的详细发展历程可阅读《一文读懂HTTP协议的历史演变和设计思路》一文。

4.3 安全问题

随着HTTP越来越广泛的使用,HTTP的安全性问题也逐渐暴露。

回忆一下多年前遍地都是的运营商劫持,当你访问一个本来很正常的网页,但页面上却莫名其妙出现了一些广告标签、跳转脚本、欺骗性的红包按钮,甚至有时候本来要下载一个文件,最后下载下来却变成了另外一个完全不同的东西,这些都是被运营商劫持了HTTP明文数据的现象。

下图就是似曾相识的运营商劫持效果图:

PS:关于运营商劫持问题,可以详细阅读《全面了解移动端DNS域名劫持等杂症:原理、根源、HttpDNS解决方案等》。

HTTP主要有以下3点安全性问题:

 

归纳一下就是:

  • 1)数据保密性问题:因为HTTP无状态,而且又是明文传输,所有数据内容都在网络中裸奔,包用户括身份信息、支付账号与密码。这些敏感信息极易泄露造成安全隐患;
  • 2)数据完整性问题:HTTP数据包在到达目的主机前会经过很多转发设备,每一个设备节点都可能会篡改或调包信息,无法验证数据的完整性;
  • 3)身份校验问题:有可能遭受中间人攻击,我们无法验证通信的另一方就是我们的目标对象。

因此,为了保证数据传输的安全性,必须要对HTTP数据进行加密。

5、常见的加密方式

5.1 基本情况

常见的加密方式分为三种:

  • 1)对称加密;
  • 2)非对称加密;
  • 3)数字摘要。

前两种适合数据传输加密,而数字摘要不可逆的特性常被用于数字签名。

接下来,我们逐一简要学习一下这三种常见的加密方法。

5.2 对称加密

对称加密也称为密钥加密或单向加密,就是使用同一套密钥来进行加密和解密。密钥可以理解为加密算法。

对称加密图示如下:

广泛使用的对称加密有:

对称加密算法的优缺点和适用场景:

  • 1)优点:算法公开、简单,加密解密容易,加密速度快,效率高;
  • 2)缺点:相对来说不算特别安全,只有一把钥匙,密文如果被拦截,且密钥也被劫持,那么,信息很容易被破译;
  • 3)适用场景:加解密速度快、效率高,因此适用于大量数据的加密场景。由于如何传输密钥是较为头痛的问题,因此适用于无需进行密钥交换的场景,如内部系统,事先就可以直接确定密钥。

PS:可以在线体验对称加密算法,链接是:http://www.jsons.cn/textencrypt/

小知识:base64编码也属于对称加密哦!

5.3 非对称加密

非对称加密使用一对密钥(公钥和私钥)进行加密和解密。

非对称加密可以在不直接传递密钥的情况下,完成解密,具体步骤如下:

  • 1)乙方生成两把密钥(公钥和私钥)。公钥是公开的,任何人都可以获得,私钥则是保密的;
  • 2)甲方获取乙方的公钥,然后用它对信息加密;
  • 3)乙方得到加密后的信息,用私钥解密。

以最典型的非对称加密算法RSA为例,举个例子:

想要彻底搞懂RSA,需要了解数论的知识,全部推导过程RSA加密算法。简单介绍思路:使用两个超大质数以及其乘积作为生成公钥和私钥的材料,想要从公钥推算出私钥是非常困难的(需要对超大数因式分解为两个很大质数的乘积)。目前被破解的最长RSA密钥是768个二进制位。也就是说,长度超过768位的密钥,还无法破解(至少没人公开宣布)。因此可以认为,1024位的RSA密钥基本安全,2048位的密钥极其安全。

非对称加密算法的优缺点和适用场景:

  • 1)优点:强度高、安全性强于对称加密算法、无需传递私钥导致没有密钥泄露风险;
  • 2)缺点:计算量大、速度慢;
  • 3)适用场景:适用于需要密钥交换的场景,如互联网应用,无法事先约定密钥。

实践应用过程中,其实可以与对称加密算法结合:

  • 1)利用非对称加密算法安全性较好的特点来传递对称加密算法的密钥。
  • 2)利用对称加密算法加解密速度快的特点,进行数据内容比较大的加密场景的加密(如HTTPS)。

PS:对于IM开发者来说,《探讨组合加密算法在IM中的应用》一文值得一读。

5.4 如何选择?

1)如果选择对称加密:

HTTP请求方使用对称算法加密数据,那么为了接收方能够解密,发送方还需要把密钥一同传递到接收方。在传递密钥的过程中还是可能遭到嗅探攻击,攻击者窃取密钥后依然可以解密从而得到发送的数据,所以这种方案不可行。

2)如果选择非对称加密:

接收方保留私钥,把公钥传递给发送方。发送方用公钥来加密数据,接收方使用私钥解密数据。攻击者虽然不能直接获取这些数据(因为没有私钥),但是可以通过拦截传递的公钥,然后把自己的公钥传给发送方,再用自己的私钥对发送方发送数据进行解密。

整个过程通信双方都不知道中间人的存在,但是中间人能够获得完整的数据信息。

3)两种加密方法的混合:

先使用非对称加密算法加密并传递对称加密的密钥,然后双方通过对称加密方式加密要发送的数据。看起来没什么问题,但事实是这样吗?

中间人依然可以拦截公钥的传递,并以自己的公钥作为替换,治标不治本。

想要治本,就要找到一个第三方公证人来证明公钥没有被替换,因此就引出了数字证书的概念,这也是下一节将分享的内容。

6、数字证书

6.1 CA机构

CA就是 Certificate Authority,即颁发数字证书的机构。

作为受信任的第三方,CA承担公钥体系中公钥的合法性检验的责任。

证书就是源服务器向可信任的第三方机构申请的数据文件。这个证书除了表明这个域名是属于谁的,颁发日期等,还包括了第三方证书的私钥。

服务器将公钥放在数字证书中,只要证书是可信的,公钥就是可信的。

下面两图是飞书域名的证书中部分内容的信:

6.2 数字签名

摘要算法:一般用哈希函数来实现,可以理解成一种定长的压缩算法,它能把任意长度的数据压缩到固定长度。这好比是给数据加了一把锁,对数据有任何微小的改动都会使摘要变得截然不同。

通常情况下:数字证书的申请人(服务器)将生成由私钥和公钥以及证书请求文件(Certificate Signing Request,CSR)组成的密钥对。CSR是一个编码的文本文件,其中包含公钥和其他将包含在证书中的信息(例如:域名、组织、电子邮件地址等)。密钥对和CSR生成通常在将要安装证书的服务器上完成,并且 CSR 中包含的信息类型取决于证书的验证级别。与公钥不同,申请人的私钥是安全的,永远不要向 CA(或其他任何人)展示。

生成 CSR 后:申请人将其发送给 CA,CA 会验证其包含的信息是否正确,如果正确,则使用颁发的私钥对证书进行数字签名,然后将签名放在证书内随证书一起发送给申请人。

在SSL握手阶段:浏览器在收到服务器的证书后,使用CA的公钥进行解密,取出证书中的数据、数字签名以及服务器的公钥。如果解密成功,则可验证服务器身份真实。之后浏览器再对数据做Hash运算,将结果与数字签名作对比,如果一致则可以认为内容没有收到篡改。

对称加密和非对称加密是公钥加密、私钥解密, 而数字签名正好相反——是私钥加密(签名)、公钥解密(验证),如下图所示。

限于篇幅,关于数字证书的内容本文就不再赘述,想详细了解的可以阅读:

7、为什么要使用HTTPS

图解HTTP》一书中提到HTTPS就是身披SSL外壳的HTTP。

7.1 SSL

SSL 在1999年被更名为TLS

所以说:HTTPS 并不是一项新的应用层协议,只是 HTTP 通信接口部分由 SSL 和 TLS 替代而已。

具体就是:HTTP 会先直接和 TCP 进行通信,而HTTPS 会演变为先和 SSL 进行通信,然后再由 SSL 和 TCP 进行通信。

SSL是一个独立的协议,不只有 HTTP 可以使用,其他应用层协议也可以使用,比如FTP、SMTP都可以使用SSL来加密。

7.2 HTTPS请求流程

HTTPS请求全流程如下图:

如上图所示:

  • 1)用户在浏览器发起HTTPS请求,默认使用服务端的443端口进行连接;
  • 2)HTTPS需要使用一套CA 数字证书,证书内会附带一个服务器的公钥Pub,而与之对应的私钥Private保留在服务端不公开;
  • 3)服务端收到请求,返回配置好的包含公钥Pub的证书给客户端;
  • 4)客户端收到证书,校验合法性,主要包括是否在有效期内、证书的域名与请求的域名是否匹配,上一级证书是否有效(递归判断,直到判断到系统内置或浏览器配置好的根证书),如果不通过,则显示HTTPS警告信息,如果通过则继续;
  • 5)客户端生成一个用于对称加密的随机Key,并用证书内的公钥Pub进行加密,发送给服务端;
  • 6)服务端收到随机Key的密文,使用与公钥Pub配对的私钥Private进行解密,得到客户端真正想发送的随机Key;
  • 7)服务端使用客户端发送过来的随机Key对要传输的HTTP数据进行对称加密,将密文返回客户端;
  • 8)客户端使用随机Key对称解密密文,得到HTTP数据明文;
  • 9)后续HTTPS请求使用之前交换好的随机Key进行对称加解密。

7.3 HTTPS到底解决了什么问题

HTTPS确实解决了HTTP的三个安全性问题:

  • 1) 保密性:结合非对称加密和对称加密实现保密性。用非对称加密方式加密对称加密的秘钥,再用对称加密方式加密数据;
  • 2) 完整性:通过第三方CA的数字签名解决完整性问题;
  • 3) 身份校验:通过第三方CA的数字证书验证服务器的身份。

7.4 HTTPS优缺点

最后我们总结一下HTTPS的优缺点:

可以看到:HTTPS的确是当今安全传输HTTP的最优解,但他并不是完美的,仍会有漏洞。

8、参考资料

[1] 深入浅出,全面理解HTTP协议

[2] HTTP协议必知必会的一些知识

[3] 从数据传输层深度解密HTTP

[4] 一文读懂HTTP协议的历史演变和设计思路

[5] 你知道一个TCP连接上能发起多少个HTTP请求吗?

[6] 如果这样来理解HTTPS,一篇就够了

[7] 一分钟理解 HTTPS 到底解决了什么问题

[8] 你知道,HTTPS用的是对称加密还是非对称加密?

[9] HTTPS时代已来,打算更新你的HTTP服务了吗?

[10] 一篇读懂HTTPS:加密原理、安全逻辑、数字证书等

[11] 全面了解移动端DNS域名劫持等杂症:原理、根源、HttpDNS解决方案等

(本文已同步发布于:http://www.52im.net/thread-3897-1-1.html

posted @ 2022-05-13 16:27 Jack Jiang 阅读(133) | 评论 (0)编辑 收藏

关于MobileIMSDK

MobileIMSDK 是一套专为移动端开发的原创开源IM通信层框架:

  • 历经8年、久经考验;
  • 超轻量级、高度提炼,lib包50KB以内;
  • 精心封装,一套API同时支持UDP、TCP、WebSocket三种协议(可能是全网唯一开源的);
  • 客户端支持 iOSAndroid标准JavaH5小程序(开发中..)、Uniapp(开发中..);
  • 服务端基于Netty,性能卓越、易于扩展;:point_left:
  • 可与姊妹工程 MobileIMSDK-Web 无缝互通实现网页端聊天或推送等;:point_left:
  • 可应用于跨设备、跨网络的聊天APP、企业OA、消息推送等各种场景。

关于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.1 版更新内容

此版更新内容:

(1)Android端主要更新内容【新增“扫一扫”等功能及优化!】:

  • 1)[新增]“扫一扫”界面及完整功能(支持扫码加好友、加群);
  • 2)[新增]“我的二维码”界面及完整功能;
  • 3)[新增]“群聊二维码”界面及完整功能;
  • 4)[升级]升级okhttp库至4.9.3;
  • 5)[优化]其它小优化。

(2)服务端主要更新内容:

  • 1)[优化]针对扫码加群等功能的相关修改。

此版主要新增功能运行截图更多截图点此查看):

posted @ 2022-05-11 17:49 Jack Jiang 阅读(138) | 评论 (0)编辑 收藏

     摘要: 一、前言MobileIMSDK 是什么?MobileIMSDK  是一套专门为移动端开发的开源IM即时通讯框架,超轻量级、高度提炼,一套API优雅支持UDP 、TCP 、WebSocket 三种协议,支持iOS、Android、H5、标准Java平台,服务端基于Netty编写。工程地址是:1)Gitee码云地址:https://www.oschina.net/p/mobilei...  阅读全文

posted @ 2022-05-05 15:15 Jack Jiang 阅读(191) | 评论 (0)编辑 收藏

本文由融云技术团队原创分享,原题“IM 消息数据存储结构设计”,内容有修订。

1、引言

在如今的移动互联网时代,IM类产品已是我们生活中不可或缺的组成部分。像微信、钉钉、QQ等是典型的以 IM 为核心功能的社交产品。另外也有一些应用虽然IM功能不是核心,但IM能力也是其整个应用极其重要的组成部分,比如在线游戏、电商直播等应用。

在IM技术应用场景越来越广泛的前提下,对即时通讯IM技术的学习和掌握就显的越来越有必要。

在IM庞大的技术体系中,消息系统无疑是最核心的,而消息系统中,最关键的部分是消息的分发和存储,而离线消息和历史消息又是这个关键环节中不可回避的技术要点。

本文将基于IM消息系统的技术实践,分享关于离线消息和历史消息的正确理解,以及具体的技术配合和实践,希望能为你的离线消息和历史消息技术设计带来最佳实践灵感。

学习交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK 

本文同步发布于:http://www.52im.net/thread-3887-1-1.html

2、相关文章

技术相关文章:

  1. 什么是IM系统的可靠性?
  2. 闲鱼IM的在线、离线聊天数据同步机制优化实践
  3. 闲鱼亿级IM消息系统的可靠投递优化实践
  4. 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等
  5. IM消息送达保证机制实现(二):保证离线消息的可靠投递
  6. 我是如何解决大量离线消息导致客户端卡顿的

融云技术团队分享的其它文章:

  1. 融云安卓端IM产品的网络链路保活技术实践
  2. 全面揭秘亿级IM消息的可靠投递机制
  3. 解密融云IM产品的聊天消息ID生成策略
  4. 万人群聊消息投递方案的思考和实践
  5. 基于WebRTC的实时音视频首帧显示时间优化实践
  6. 融云IM技术分享:万人群聊消息投递方案的思考和实践

3、IM消息投递的一般做法

在通常的IM消息系统中,对于实时消息、离线消息、历史消息大概都是下面这样的技术思路。

对于在线用户:消息会直接实时发送到在线的接收方,消息发送完成后,服务器端并不会对消息进行落地存储。

而对于离线的用户:服务器端会将消息存入到离线库,当用户登录后,从离线库中将离线消息拉走,然后服务器端将离线消息删除。

这样实现的缺点就是消息不持久化,导致消息无法支持消息漫游,降低了消息的可靠性。

PS:实际上,这其实也不能算是缺点,因为一些场景下存储历史消息并不是必须的,所谓的消息漫游能力也不是必备的,比如微信。

而在我们设计的消息系统中,服务器只要接收到了发送方发上来的消息,在转发给接收方的同时也会在离线数据库及历史消息库中进行消息的落地存储,而历史消息的落地也就能支持消息漫游等相关功能了。

4、什么是离线消息和历史消息?

关于离线消息和历史消息,在技术上,我们是这样定义。

1)离线消息:

离线消息就是用户(即接收方)在离线过程中收到的消息,这些消息大多是用户比较关心的消息,具有一定的时效性。

以我们的系统经验来说,我们的离线消息默认只保存最近七天的消息。

用户(即接收方)在下次登录后会全量获取这些离线消息,然后在客户端根据聊天会话进行离线消息的UI展示(比如显示一个未读消息气泡等)。

PS:用户离线的可能性在技术上其实是由很多种情况组成的,比如对方不在线、对方网络断掉了、对方手机崩溃了、服务器发送时出错了等等,严格来讲——只要无法实时发送成的消息,都算“离线消息”。

2)历史消息:

历史消息存储了用户所有的聊天消息,这些消息包括发出的消息以及接收到的消息。

在客户端获取历史消息时,通常是按照会话进行分页获取的。

以我们的系统经验来说,历史消息的存储时间我们设计默认为半年,当然这个时间可以按实际的产品运营规则来定,没有硬性规定。

5、IM消息的发送及存储流程

以下是我们系统整体的消息发送及存储流程:

 如上图所示:当用户发送聊天消息到服务器端后,首先会进入到消息系统中,消息系统会对消息进行分发以及存储。

这个过程中:对于在线的接收方,会选择直接推送消息。但是遇到接收方不在线或者是消息推送失败的情况下,也会有另外的消息获取方式,比如接收方会主动向服务器拉取未收到的消息。但是接收方何时来服务器拉取消息以及从哪里拉取是未知的,所以消息存入到离线库的意义也就在这里。

消息系统存储离线的过程中,为了不影响整个系统的更为平稳,我们使用了MQ消息队列进行IO解偶,所以聊天消息实际上是异步存入到离线库中的(通过MQ进行慢IO解偶,这其实也是惯常做法)。

在分发完消息后:消息服务会同步一份消息数据到历史消息服务中,历史消息服务同样会对消息进行落地存储。

对于新的客户端设备:会有同步消息的需求(所谓的消息漫游能力),而这也正是历史消息的主要作用。在历史消息库中,客户端是可以拉取任意会话的全量历史消息的。

6、IM离线消息、历史消息在存储逻辑上的区别

6.1 概述

通过上面的图中能清晰的看到:

  • 1)离线消息我们存储介质选用的是 Redis
  • 2)历史消息我们选用的是 HBase

对于为什么选用不同的存储介质,其实我们考虑的是离线消息和历史消息不同的业务场景和读写模式。

下面我们重点介绍一下离线消息和历史消息存储的区别。

6.2 离线消息存储模式——“扩散写”

离线消息的存储模式我们用的是扩散写。

如上图所示:每个用户都有自己单独的收件箱和发件箱:

  • 1)收件箱存放的是需要向这个接收端同步的所有消息;
  • 2)发件箱里存放的是发送端发出的所有消息。

以单聊为例:聊天中的两人会话中,消息会产生两次写,即发送者的发件箱和接收端的收件箱。

而在群的场景下:写入会被更加的放大(扩散),如果群里有 N 个人,那一条群消息就会被扩散写 N 次。

小结一下:

  • 1)扩散写的优点是:接收端的逻辑会非常清晰简单,只需要从收件箱里读取一次即可,大大降低了同步消息所需的读的压力;
  • 2)扩散写的缺点是:写入会被成指数地放大,特别是针对群这种场景。

6.3 历史消息存储模式——“扩散读”

历史消息的存储模式我们用的是扩散读。

因为历史消息中,每个会话都保存了整个会话的全量消息。在扩散读这种模式下,每个会话的消息只保存一次。

对比扩散写模式,扩散读的优点和缺点如下:

  • 1)优点是:写入次数大大降低,特别是针对群消息,只需要存一次即可;
  • 2)缺点是:接收端接收消息非常的复杂和低效,因为这种模式客户端想拉取到所有消息就只能每个会话同步一次,读就会被放大,而且可能会产生很多次无效的读,因为有些会话可能根本没有新消息。

6.4 小结

在 IM 这种应用场景下,通常会用到扩散写这种消息同步模型,一条消息产生一条,但是可能会被读多次,是典型的读多写少的场景。

一个优化好的IM系统,必须从设计上平衡读写压力,避免读或者写任意一个维度达到天花板。

当然扩散写这种模式也有其弊端,比如万人群,会导致一条消息,写入了一万次。

综合来讲:我们需要根据自己的业务场景做相应设计选择,以我们的IM系统为例,就是是根据了离线和历史消息的不同场景选择了写扩散和读扩散的组合模式。适合的才是最好的,没有必要死搬硬套理论。

7、IM客户端的拉取消息逻辑

7.1 离线消息拉取逻辑

对于IM客户端而言,离线消息的获取针对的是自己的整个离线消息,包括所有的会话(直白了说,就是上线时拉取此次离线过程中的所有未收取的离线消息)。

离线消息的获取是自上而下的方式(按时间序),我们的经验是一次获取 200 条(PS:如果离线消息过多,会分页多次拉取,拉取1“次”可以理解为拉取1“页”)。

在客户端拉取离线消息的信令中,需要带上当前客户端缓存的消息的最大时间戳。

通过上节的图我们应该知道,离线消息我们存储的是一个线性结构(指的是按时间顺序),Server 会根据这个时间戳向下查找离线消息。当重装或者新安装 App 时,客户端的“当前客户端缓存的消息的最大时间戳”可以传 0 上来。

Server 也会缓存客户端拉取到的最后一条消息的时间戳,然后根据业务场景,客户端类型等因素来决定从哪里开始拉取,如果没有拉取完 Server 会在拉取消息的应答中带相应的标记位,告诉客户端继续拉取,客户端循环拉取,直到所有离线消息拉完。

7.2 历史消息拉取逻辑

历史消息的获取通常针对的是单一会话。

在拉取过程中,需要向服务端提交两个参数:

  • 1)对方的 ID(如果是单聊的话就是对方的 UserID,如果是群则是群组ID);
  • 2)当前会话的最前面消息的时间戳(即当前会话最老一条消息的时间戳)。

Server据这两个参数,可以定位到这个客户端的此会话,然后一次获取 20 条历史消息。

消息的拉取时序上采用的是自下而上的方式(也就是时间序逆序),即从最后面往前翻。只要有消息,客户端可以一直向前翻,手动触发获取会话的历史消息。

上面的拉取逻辑,在IM界面功能上通常对应的是下拉或点击“加载更多”,比如这样:

8、本文小结

本文主要分享了IM中有关离线消息和历史消息的正确,主要包括离线消息和历史消息的区别,以及二者在存储、分发、拉取逻辑方面的最佳践等。如对文中内容有异议,欢迎留言讨论。

9、参考资料

[1] 一套海量在线用户的移动端IM架构设计实践分享(含详细图文)

[2] 一套原创分布式即时通讯(IM)系统理论架构方案

[3] 从零到卓越:京东客服即时通讯系统的技术架构演进历程

[4] 一套亿级用户的IM架构技术干货(上篇):整体架构、服务拆分等

[5] 闲鱼亿级IM消息系统的架构演进之路

[6] 闲鱼亿级IM消息系统的可靠投递优化实践

[7] 闲鱼亿级IM消息系统的及时性优化实践

[8] 基于实践:一套百万消息量小规模IM系统技术要点总结

[9] IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

[10] 理解IM消息“可靠性”和“一致性”问题,以及解决方案探讨

[11] 零基础IM开发入门(一):什么是IM系统?

本文同步发布于:http://www.52im.net/thread-3887-1-1.html

posted @ 2022-04-19 14:56 Jack Jiang 阅读(233) | 评论 (0)编辑 收藏

本文由网易云信技术团队分享,原题“如何保障一场千万级大型直播?”,有修订和改动。

1、引言

本文以TFBOYS“日光旅行”七周年这场直播演唱会为案例,为你分享大型直播系统后端架构设计的方方面面,包括:基本架构、稳定性保障、安全性障、监控报警、应急预案等技术范畴。

案例中的这次演唱会采用了在线实时互动及演唱会现场的多场景导播切换,提供了主机位和三个艺人专属机位流,同时每个机位流实时转码四个清晰度档位,用户可以根据喜好选择自己想看的内容。这场演唱会最高同时在线人数达78.6万,打破线上付费演唱会世界记录。

学习交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK 

本文同步发布于:http://www.52im.net/thread-3875-1-1.html

2、本文作者

费曼:网易智企服务端开发工程师。硕士毕业于华中科技大学电信系,2016年加入网易云信,热衷于大规模分布式系统和音视频相关技术,爱好文学、体育和电影。

3、架构方面

3.1 基本

 

上图是该次TFBOYS在线演唱会的直播媒体架构简图。

可以看出一场大型活动直播涵盖的技术方案点非常庞杂,本节接下来的内容我们将以推拉流链路、全局智能调度、流量精准调度以及单元化部署,对这套直播方案做一个展开介绍。

3.2 推拉流链路

 

如上图所示,直播技术架构,分为几大部分:

  • 1)视频直播中心(LMS——Live Manage Service):负责直播流的逻辑管理和操作控制,包括存储和下发实时转码、加密等媒体处理的配置信息;
  • 2)实时互动直播服:由连麦互动和直播两部分组成,主播和连麦者的音视频数据在互动直播高性能服务器合成为一道流后推流到直播流媒体服务器;
  • 3)直播源站服务(LSS——Live Source Service):网易云信自建的直播流媒体服务器节点,结合全局智能调度系统,提供第一公里的最佳链路选择,同时融合支持接入多家CDN厂商;
  • 4)媒体处理服务(MPS——Media Processing Service):提供实时水印、实时转码、媒体数据加密等强大的流媒体处理能力;
  • 5)融合CDN与全局智能调度(GSLB——Golabal Server Load Balancing):提供敏捷智能的CDN调度策略和分配算法,结合全链路、端到端的流媒体控制,来达到最终端侧优良的用户体验;
  • 6)客户端SDK:提供推流、拉流以及上下行的调度能力,便于用户快速接入使用网易云信平台一站式的音视频解决方案。

3.3 融合CDN与智能调度

这是一个端到端的服务,通过平台的SDK执行一个类似HTTPDNS的调度,来做到真正根据用户IP做就近的接入。

针对国内相对复杂的运营商网络环境,在直播上行方面通过BGP网络以及与相关运营商在网络接入方面的合作,能够更加精准地控制网络链路的选择。

而对于下行,也提供了播放端的SDK接入,通过端到端的调度策略就近选择合适的下行链路。

调度的准确性以及最终效果,依赖及时准确的数据支撑。

我们有一个全链路、立体的数据监控体系,一方面利用CDN上的一些实时日志,另一方面结合自建节点、客户端侧上报收集链路上探测的数据,然后整合做一个实时计算来支撑整个调度的策略。

融合CDN方案,通过调度、监控、高可用等技术和手段来解决CDN网络方面的问题。但是对于技术人员来说,就和在使用一个传统的CDN网络一样没有大的差异,这些技术细节对技术人员透明无感知。

3.4 流量精准调度

大型演唱会直播活动,尤其是正式开播时的进场阶段,突发流量峰值会非常高,这就需要实时精准的智能调度策略。

融合CDN的智能调度包含两大部分:CDN分配调度和节点调度。

节点调度:比较常见的是DNS协议解析调度和IP调度(302/HTTPDNS)。前者由于DNS协议原因,调度生效时间较慢,而后者则可以做到请求级别的调度,也就是支持任意比例的负载均衡,更加及时精准。在我们的智能调度的场景里,正常情况下会遵循IP调度,在IP调度解析失败时,客户端上会启动loacl DNS解析逻辑,两者的结合确保了调度的精准和稳定可靠。

Don't put all your eggs in one basket.

“永远不要将鸡蛋放在同一个篮子里”。

从风险管控的角度来说:大型活动保障的CDN厂商资源,通常没法通过一家CDN资源进行满足。融合CDN方案则是将多家CDN厂商进行整合与流量分配调度。

通常在一次大型直播中,多家CDN厂商提供的容量(区域带宽、最高带宽)、质量会各不相同。我们则是通过动态调整调度比例,在确保不超过最大带宽的前提下,精确化按比例分配流量,以及尽可能地确保体验。

我们设计了一套针对CDN厂商的打分算法:影响因子包含当前带宽、保底带宽、最大带宽、带宽预测、带宽质量。

算法遵循以下原则:

  • 1)没超保底的带宽,比超过保底的带宽,得分更高;
  • 2)没超保底的时候,剩余保底和剩余总带宽越大,得分更高;
  • 3)超过保底的时候,剩余总带宽越大、质量越好,得分更高。

各CDN的分数之比决定了调度比例,CDN打分算法是在持续地迭代更新计算,最大化分配使用各家CDN的带宽,然后再分配各家CDN厂商的保障之外的资源。同时优先选择质量较好的厂家,避免单价CDN厂商超分配。

3.5 单元化部署

上面所说,在大型直播活动中,短时间大量涌入的用户请求,对以全局智能调度服务为主的相关非媒体流链路应用,也提出了更高的并发处理挑战。

除了上行的推流链路我们做了主备两个单元的部署,非媒体数据链路上的服务也采用了单元化的部署方案。

在此部署方案下,可用性做到任意单元机房故障,不影响整体可用性,即异地多活。

单元化部署遵循以下原则:

  • 1)单元化的依赖也必须单元化(核心业务);
  • 2)单元化粒度为应用,非api;
  • 3)单元化技术栈对应用尽量避免产生侵入性。

 

如上图所示:非单元化的业务部署在主机房,单元化的业务则部署在主机房和单元机房。

4、稳定性保障

4.1 上行链路稳定

超大型直播方案最核心的诉求就是直播稳定性,下面我们将以该次在线演唱会为案例,重点阐述一下直播的全链路稳定性架构。

上图是我们直播的媒体流链路示意简图:整体方案可以承受任何单节点、单线路、单机房网络出口的故障。

如直播源站部分:采用了多线策略收流,包含机房专线和4G背包方案,一主一备两个线路。同时每个单元的源站集群都有4层负载均衡,一台机器宕机不会影响整体可用性。LMS、LSS、MPS都是跨机房部署,所有服务模块都可配置专有资源池供使用,保证不会受其他租户影响。

整个推流链路:采用双路热流、互为主备,且部署上是互相独立的两个单元,能做到支持Rack级别的故障灾备。双路热流实现了自动主备切换,端上无需专门添加应用层的线路切换逻辑。当任何一个链路出现问题的时候,观众的直播流不会受到影响,端上平均卡顿感知时间在1s以内。

除了推流链路的整体主备单元容灾,每个单元的服务本身也会有容灾手段。比如UPS接入,可以接受30min的供电故障,比如当实时互动流出现问题时,导播台会推垫片流以保证链路数据不中断。

4.2 下行链路稳定

在访次直播活动中,全局智能调度服务会承受较大的峰值压力,在单元化部署的基础上,我们经过多轮压测和性能调优,模型上可支撑千万级用户在半分钟内全部进入直播间。

除了上述关于推流链路的高可用,下行链路也有相关的容灾策略。当GSLB智能调度服务整体不可用,在客户端SDK预埋了融合CDN的local DNS灾备逻辑与比例配置,将云端的全局智能调度fail-over到客户端的本地兜底调度,并保持大数据统计层面的各CDN厂商的流量分配均衡。

同时:客户端也会有播放体验方面的容灾策略,诸如清晰度降级、线路调整等。

5、安全性保障

除了直播全链路的稳定之外,直播安全也很重要。

该次直播活动中,为TFBOYS活动链路多环节都提供了安全保障机制(如防盗链鉴权、IP黑白名单、HTTPS等能力),以及地区、运营商等下行调度的动态限制,实现全链路安全保障。

在此基础上:此次活动采用了端到端的视频流数据加密。

直播场景的加密有几点基本要求:压缩比不变、实时性和低计算复杂度。

除此之外:在融合多cdn的方案背景下,视频流的加密必须考虑到CDN厂商的兼容性。

比如须满足以下要求:

  • 1)不破坏流媒体协议格式、视频容器格式;
  • 2)metadata/video/audio tag的header部分不加密;
  • 3)对于avcSequenceHeader和aacSequenceHeader tag整体不加密。

具体加密算法,可以采用一些流式加密算法,这里我们不再赘述。

 

6、监控与报警

6.1 概述

一场大型直播将会有大量的计算节点参与,除了媒体数据处理与分发的各个服务器节点,还有分布在国内外的海量客户端。

我们对网络链路、服务节点、设备端的健康与质量感知,都离不开数据监控系统。

同时:我们在现有系统无法自动fail-over的故障场景下,需要人工预案介入,而后者的决策判断,也强依赖于完善的全链路数据质量监控与报警系统。

6.2 全链路监控

整个直播链路的监控包含了:

  • 1)上行推流链路的流质量;
  • 2)媒体流实时转码处理;
  • 3)端上播放质量;
  • 4)智能调度系统的可用性;
  • 5)业务量水位等相关监控数据。

上行链路常见的QoS指标有:帧率、码率、RTT等,其维度包含主备线路、出口运营商、CDN厂商节点等。

端上的QoS指标则包含了:拉流成功率、首帧时长、卡顿率、httpdns缓存命中率,维度则覆盖包含CDN厂商、国家、省份、运营商、直播流、清晰度档位、客户端等。

此次直播中:内容上支持了多种机位流以及多个清晰度的转码输出流,同时通过多个CDN厂商进行分发,我们把上行链路中节点的码率、帧率,直观地通过N个指标卡集中展示在单个大盘页面上,并且通过增加预警值进行异常显示和弹窗消息告警。活动作战室现场,我们采用了多个大屏展示,非常直观地展现当前主备双推流链路的实时帧率、码率等情况,为现场地指挥保障提供了强大的数据决策支撑。

以下图为例:蓝色表示上行帧率,绿色表示正常的上行码率,红色表示码率值过低,N/A表示当前没有上行推流数据。

而在下行播放链路中,比较常用的指标就是卡顿率。

下面是我们对卡顿相关的描述:

  • 1)一次卡顿:播放器持续2s发生缓冲区空,即播放器2s没有拉到流;
  • 2)一分钟用户卡顿:1分钟窗口内,用户只要卡顿一次,则该用户计作卡顿用户;
  • 3)一分钟用户卡顿率:1分钟窗口内,卡顿用户数/总的用户数;
  • 4)一分钟用户零卡顿率:1分钟窗口内,(总的用户数 - 卡顿用户数)/总的用户数。

为什么会选择用户卡顿率这个指标,而不是使用整体的卡顿采样点/总采样数呢?

是因为:我们更想看到有多少用户没有出现过卡顿现象,这更能直观体现优质网络的整体占比。通过对各省份用户零卡顿率、用户数排行,以及各省用户卡顿率的观察,我们可以非常直观地找到卡顿严重的地区,以便重点关注,进行资源调度优化。

7、应急预案

任何一个系统,无论你号称它被设计得多么健壮,它仍然会有故障时间的存在。

硬件故障、软件bug、人为操作失误等等,这些都无可避免地存在着。他们未必是一个必须多少时间内将其彻底解决的问题,他们是我们必须认清并接受共存的一个事实。

所以:预案管理是大型直播活动保障中不可缺少的一环。

我们遵循以下的预案原则:

  • 1)预案信息明确:大盘自动监控不具备二义性,确保预案信息来源正确,触发执行预案的条件明确且有数值化约束;
  • 2)预案操作简洁:所有的预案操作都有有简洁明确(开关型)的操作输入;
  • 3)预案操作安全:所有预案要经过充分预演,同时预演操作本身需要有明确的确认机制,以确保在正常情况下不会被误触发;
  • 4)预案影响验证:明确理清预案操作的影响,QA在预演阶段需要对相关影响进行充分验证。

此次活动的前期筹备中,我们总计进行了3次直播全链路的拟真演练,以及2次联合互动现场、导播台现场的活动全流程级别的彩排,另外进行了大大小小总计数十次的各类风险预案演练。所有演练过程中发现的问题,都会进行专项解决。

风险预案这块,包含了各类资源故障、上下行链路质量、地区性网络故障、CDN异常流量水位等在内的场景应对。其中资源故障包含了机器宕机、机架整体断电、堆叠交换机宕机、机房外网出口不可用,我们均进行了风险预案演练覆盖。

下面列举几点直播解决方案中的部分预案机制:

  • 1)如果因为误操作等导致非正常解密等,可在推流不中断的情况下,动态中止流加密,客户端无任何感知影响;
  • 2)某家cdn在某地区运营商出现大面积故障瘫痪,该地区相应运营商线路的QoS指标会大幅度下降并触发报警,将故障cdn在该地区运营商进行黑名单处理,动态停止对其的调度,将流量调度至正常提供服务的cdn厂商;
  • 3)在两路热流均正常的情况下,但是正在分发的一路出现质量问题,方案可支持手动触发主备切换,让监控数据质量更好的另一路流参与分发,客户端感知时间在1s以内;
  • 4)因为一些不可抗因素,某机房出现大面积故障整体不可用,触发链路报警,此时我们会紧急将流切至另一机房,故障感知与恢复的时间在一分钟内。

8、相关文章

[1] 移动端实时音视频直播技术详解(一):开篇

[2] 移动端实时音视频直播技术详解(二):采集

[3] 移动端实时音视频直播技术详解(三):处理

[4] 移动端实时音视频直播技术详解(四):编码和封装

[5] 移动端实时音视频直播技术详解(五):推流和传输

[6] 移动端实时音视频直播技术详解(六):延迟优化

[7] 淘宝直播技术干货:高清、低延时的实时视频直播技术解密

[8] 爱奇艺技术分享:轻松诙谐,讲解视频编解码技术的过去、现在和将来

[9] 零基础入门:实时音视频技术基础知识全面盘点

[10] 实时音视频面视必备:快速掌握11个视频技术相关的基础概念

[11] 网易云信实时视频直播在TCP数据传输层的一些优化思路

[12] 浅谈实时音视频直播中直接影响用户体验的几项关键技术指标

[13] 首次披露:快手是如何做到百万观众同场看直播仍能秒开且不卡顿的?

[14] 直播系统聊天技术(一):百万在线的美拍直播弹幕系统的实时推送技术实践之路

[15] 直播系统聊天技术(二)阿里电商IM消息平台,在群聊、直播场景下的技术实践

[16] 直播系统聊天技术(三):微信直播聊天室单房间1500万在线的消息架构演进之路

[17] 直播系统聊天技术(四):百度直播的海量用户实时消息系统架构演进实践

[18] 直播系统聊天技术(五):微信小游戏直播在Android端的跨进程渲染推流实践

[19] 直播系统聊天技术(六):百万人在线的直播间实时聊天消息分发技术实践

[20] 直播系统聊天技术(七):直播间海量聊天消息的架构设计难点实践

本文同步发布于:http://www.52im.net/thread-3875-1-1.html

posted @ 2022-04-13 10:58 Jack Jiang 阅读(235) | 评论 (0)编辑 收藏

本文由小枣君分享,文案:小枣君、漫画:杨洋,来自鲜枣课堂,有少许改动,原文链接见文末。

1、引言

网络编程能力对于即时通讯技术开发者来说是基本功,而计算机网络又是网络编程的理论根基,因而深刻准确地理解计算机网络知识显然能夯实你的即时通讯应用的实践品质。

本文风格延续了社区里的《网络编程懒人入门》、《脑残式网络编程入门》两个系列,没有更多的理论堆砌,通俗而不失内涵,非常适合希望轻松快乐地学习计算机网络知识的网络编程爱好者们阅读,希望能给你带来不一样的网络知识入门视角。

本篇文章将利用简洁生动的文字,配上轻松幽默的漫画,助你从零开始快速建立起对IPv6技术的直观理解,非常适合入门者阅读。

学习交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK 

 (本文同步发布于:http://www.52im.net/thread-3868-1-1.html

2、系列文章

本文是该系列文章中的第3篇:

  1. 网络编程入门从未如此简单(一):假如你来设计网络,会怎么做?
  2. 网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?
  3. 网络编程入门从未如此简单(三):什么是IPv6?漫画式图文,一篇即懂!》(本文

本文是IPv6的轻松入门文章,希望你能喜欢。

* 推荐阅读:本文作者的另一篇也同样优秀:网络编程懒人入门(十一):一文读懂什么是IPv6,感兴趣的建议一并阅读 。

3、技术背景

随着移动网络的不断建设和普及,加速了我们迈入万物互联时代的步伐。

我们的整个互联网络,正在发生翻天覆地的变化。急剧增加的网络连接数和流量,对网络的承载和传送能力,提出了前所未有的挑战。

除了速率和带宽之外,5G在垂直行业的落地,也要求网络能够提供灵活的差异化定制服务能力。

也就是说,面对不同的行业应用场景,网络需要能够提供套餐式的服务,支持不同的QoS(Quality of Service,服务质量),支持端到端的切片。

4、IP协议

众所周知,我们现在形影不离的互联网,最早诞生于上世纪60年代。它的核心基础,就是大名鼎鼎的IP协议Internet Protocol,网际互连协议,见《技术往事:改变世界的TCP/IP协议(珍贵多图、手机慎点)。

如果没有IP协议,以及基于它的IP地址,我们就没办法刷剧、网购、吃鸡、聊微信。

说白了,互联网就是一套“快递系统”。IP地址是你的快递地址,而IP协议,则是快递公司的“工作流程和制度”。

所有我们需要传递的信息,包括文字、图片、音频、视频等,都需要被打包成一个个的“快递包裹”,然后经过快递系统的运输,送到最终目的地。

5、第一、第二代“快递系统”:IPv4

互联网诞生后,长期使用的是v4版本的IP协议,也就是大家熟知的IPv4。

我们可以把它理解为第一代快递系统,它为互联网的早期发展奠定了坚实基础。

后来,随着互联网的迅速发展扩张,原始的IPv4系统暴露出了很多的问题,进行了一些技术上的升级改进。尤其是MPLSMulti-Protocol Label Switching,多协议标签交换)技术的引入,将这个快递系统升级到了第二代。

到了最近这几年,因为前面我们提到的网络挑战,远远超过了第二代快递系统的能力范围。

6、第三代“快递系统”:IPv6

于是,IPv6以及IPv6+,作为第三代快递系统,正式闪亮登场。

IPv6,是v6版本的IP协议。而IPv6+,则是IPv6的升级加强版。

具体来说,IPv6+基于IPv6,实现了更多的创新。

这些创新,既包括以IPv6分段路由、网络切片、随流检测、新型组播和应用感知网络等协议为代表的协议创新,又包括以网络分析、自动调优、网络自愈等网络智能化为代表的技术创新。

凭借这些创新,IPv6+更适合行业用户,更能够有力支撑行业的数字化转型和发展。

接下来,我们仔细看看,IPv6+究竟带来了哪些变化和升级。

7、IPv6优势1:IP地址大幅增加

首先,IPv6最广为人知的优点就是IP地址的大幅增加。具体来说,IPv6的地址数量是IPv4的2的96次方倍(详见《一文读懂什么是IPv6》的第6节内容)。

这么说吧,如果采用IPv6,即便是给地球上的每粒沙子都赋予一个IP地址,都绰绰有余。

传统的IPv4快递系统,邮箱地址不够,快递员往往需要将快速送到门卫处或快递柜,然后再二次派送给用户(在IPv4时代,这就是NAT路由技术啦,详见《NAT详解——详细原理、P2P简介》、《什么是公网IP和内网IP?NAT转换又是什么鬼?)。

 

在IPv6快速系统下,每个用户都有属于自己的邮箱地址,快递员可以直接将快递送到用户手中。

很显然,这样不仅提升了快递的收发速度,也节省了门卫或快递柜的开支,简化了维护,减少了能耗,降低了成本。

其实,IP地址数量的压力,主要来自物联网场景。因为物的数量远远超过人的数量。而且,物联网的控制,更需要端到端的直达。这样才能有更低的时延,实现更精准的控制。

8、IPv6优势2:“快递包装”的升级

IPv6的第二个重大改进,在于“快递包装”的升级。IPv6的数据报文结构变得更加丰富,里面可以记录更多的内容和信息。

简单来说,就是运输快递的纸箱变得更高级了。

传统的快递系统,包装很简单,我们并不知道里面到底是什么物品。

IPv6的快递系统,纸箱上可以贴更多的标签,标识纸箱里的货物属性,例如重货、易碎品、紧急文件等。系统根据标签,可以快速判断这个快递包裹所需的服务,例如需要加急、需要小心轻放等。

这样一来,快递公司可以根据包裹显示的信息,为不同的客户提供更精细化的服务,采用差异化的收费标准。

快递公司还可以走精品路线,提供专属的快递通道,实现高端用户的资源独享。

IPv6+对数据包属性的精准识别,也可以帮助运营商更好地掌握整个网络中数据业务的流动趋势,更好地调动和分配资源。

例如,从A地到B地的视频大颗粒传输需求很多,那么,就可以建立视频大颗粒业务专线,更好地满足传输需求。

这就好像从A地到B地的海鲜运输需求很多,那快递公司就采购更多的冷链运输车,专门投入到这条线路上,赚取更多的利润。

9、IPv6优势3:升级了“导航能力”

传统快递系统的运输路径,是相对固定和死板的。运输车从起点到终点,经过每一个路口,都由路口指定下一步前进的方向。

 

而IPv6+的话,通过与SR(Segment Routing,分段路由)技术、SDN(Software Defined Network,软件定义网络)技术进行结合,具有更强的路径选择能力。

快递包裹在出发时,就已经从管理中心获得了从起点到终点的最佳路径。每一次选路,都按照规划进行,可以避开拥堵,也可以避免绕路。

换言之,IPv6+超强的路径编排能力,可以实现数据报文的一跳入云,大幅提升效率。

10、IPv6优势4:降低运维成本

因为网络的管理功能集中,可以更方便地将配置意图转换成脚本,自动部署给各个网络节点。

引入AI之后,更能够对故障现象进行自动分析,更快地找到原因。

甚至说,AI还可以根据对故障模型的学习,主动提前识别网络中潜在的故障风险,实现事故预防。

集中管理+AI管理,大幅降低了网络的维护难度,提升了运维效率,减少了维护成本。

11、IPv6优势5:更安全

IPv6+的安全防御能力相比IPv4有了很大的提升,真正实现了云、网、安一体化防御。

传统网络中,因为大量私网的存在,恶意行为很难溯源。也就是说,很多坏人躲在暗处,发出有问题的包裹,对快递系统造成破坏。

在IPv6+网络中,节点采用公网地址取代私网地址,这就意味着,在快递系统中运输的每一个包裹,都有真实可溯源的寄件人信息。失去了私网的伪装,破坏行为将无所遁形。

升级后的快递包装(数据报文结构),也大幅增加了破坏分子对包裹进行恶意伪造和窃听的难度,增强了包裹的安全性和私密性。

 

12、写在最后

总而言之,IPv6+是一个高速、高效、灵活、智能的先进“快递系统”。

它可以提供满足千行百业应用需求的差异化服务能力,适配不同行业的业务承载需求,支撑各个行业的数字化转型,助力消费互联网向产业互联网升级,推动整个社会数字经济的发展。

目前,IPv6在我国已经取得了显著的成果。截至今年8月,我国IPv6地址资源储备位居世界第一。IPv6活跃用户数达5.51亿,占我国全部网民数的54.52%。

IPv6+的黄金时代,已然到来!

 

13、参考资料

[1] TCP/IP详解 卷1 - 第3章 IP:网际协议

[2] 网络编程懒人入门(十一):一文读懂什么是IPv6

[3] IPv6技术详解:基本概念、应用现状、技术实践(上篇)

[4] IPv6技术详解:基本概念、应用现状、技术实践(下篇)

[5] Java对IPv6的支持详解:支持情况、相关API、演示代码等

[6] NAT详解——详细原理、P2P简介

[7] 什么是公网IP和内网IP?NAT转换又是什么鬼?

本文同步发布于:http://www.52im.net/thread-3868-1-1.html

posted @ 2022-03-30 12:56 Jack Jiang 阅读(312) | 评论 (0)编辑 收藏

本文由小米技术团队分享,原题“小爱接入层单机百万长连接演进”,有修订。

1、引言

小爱接入层是小爱云端负责设备接入的第一个服务,也是最重要的服务之一,本篇文章介绍了小米技术团队2020至2021年在这个服务上所做的一些优化和尝试,最终将单机可承载长连接数从30w提升至120w+,节省了机器30+台

提示:什么是“小爱”?

小爱(全名“小爱同学”)是小米旗下的人工智能语音交互引擎,搭载在小米手机、小米AI音箱、小米电视等设备中,在个人移动、智能家庭、智能穿戴、智能办公、儿童娱乐、智能出行、智慧酒店、智慧学习共八大类场景中使用。

(本文同步发布于:http://www.52im.net/thread-3860-1-1.html

2、专题目录

本文是专题系列文章的第7篇,总目录如下:

  1. 长连接网关技术专题(一):京东京麦的生产级TCP网关技术实践总结
  2. 长连接网关技术专题(二):知乎千万级并发的高性能长连接网关技术实践
  3. 长连接网关技术专题(三):手淘亿级移动端接入层网关的技术演进之路
  4. 长连接网关技术专题(四):爱奇艺WebSocket实时推送网关技术实践
  5. 长连接网关技术专题(五):喜马拉雅自研亿级API网关技术实践
  6. 长连接网关技术专题(六):石墨文档单机50万WebSocket长连接架构实践
  7. 长连接网关技术专题(七):小米小爱单机120万长连接接入层的架构演进》(* 本文

3、什么是小爱接入层

整个小爱的架构分层如下:

接入层主要的工作在鉴权授权层和传输层,它是所有小爱设备和小爱大脑交互的第一个服务。

由上图我们知道小爱接入层的重要功能有如下几个:

  • 1)安全传输和鉴权:维护设备和大脑的安全通道,保障身份认证有效和传输数据安全;
  • 2)维护长连接:维持设备和大脑的长连接(Websocket等),做好连接状态存储,心跳维护等工作;
  • 3)请求转发:针对每一次小爱设备的请求做好转发,保障每一次请求的稳定。

4、早期接入层的技术实现

小爱接入层最早的实现是基于AkkaPlay,我们使用它们搭建了第一个版本,该版本特点如下:

  • 1)基于Akka我们基本做到了初步的异步化,保障核心线程不被阻塞,性能尚可。
  • 2)Play框架天然支持Websocket,因此我们在有限的人力下能够快速搭建和实现,且能够保障协议实现的标准性。

5、早期接入层的技术问题

随着小爱长连接的数量突破千万大关,针对早期的接入层方案,我们发现了一些问题。

主要的问题如下:

1)长连接数量上来后,需要维护的内存数据越来越多,JVM的GC成为不可忽略的性能瓶颈,且一旦代码写的不好有GC风险。经过之前事故分析,Akka+Play版的接入层其单实例长连接数量的上限在28w左右。

2)老版本的接入层实现比较随意,其Akka Actor之间存在非常多的状态依赖而不是基于不可变的消息传递这样使得Actor之间的通信变成了函数调用,导致代码可读性差且维护很困难,没有发挥出Akka Actor在构建并发程序的优势。

3)作为接入层服务,老版本对协议的解析是有很强的依赖的,这导致它要随着版本变动而频繁上线,其上线会引起长连接重连,随时有雪崩的风险。

4)由于依赖Play框架,我们发现其长连接打点有不准确的问题(因为拿不到底层TCP连接的数据),这个会影响我们每日巡检对服务容量的评估,且依赖其他框架在长连接数量上来后我们没有办法做更细致的优化。

6、新版接入层的设计目标

基于早期接入层技术方案的种种问题,我们打算重构接入层。

对于新版接入层我们制定的目标是:

  • 1)足够稳定:上线尽可能不断连接且服务稳定;
  • 2)极致性能:目标单机至少100w长连接,最好不要受GC影响;
  • 3)最大限度可控:除了底层网络I/O的系统调用,其他所有代码都要是自己实现/或者内部实现的组件,这样我们有足够的自主权。

于是,我们开始了单机百万长连接的漫漫实践之路。。。

7、新版接入层的优化思路

7.1 接入层的依赖关系

接入层与外部服务的关系理清如下:

7.2 接入层的功能划分

接入层的主要功能划分如下:

  • 1)WebSocket解析:收到的客户端字节流,要按照WebSocket协议要求解析出数据;
  • 2)Socket状态保持:存储连接的基本状态信息;
  • 3)加密解密:与客户端通讯的所有数据都是加密过的,而与后端模块之间传输是json明文的;
  • 4)顺序化:同一个物理连接上,先后两个请求A、B到达服务器,后端服务中B可能先于A得到了应答,但是我们收到B不能立刻发送给客户端,必须等待A完成后,再按照A,B的顺序发给客户端;
  • 5)后端消息分发:接入层后面不止对接单个服务,可能根据不同的消息转发给不同的服务;
  • 6)鉴权:安全相关验证,身份验证等。

7.3 接入层的拆分思路

把之前的单一模块按照是否有状态,拆分为两个子模块。

具体如下:

  • 1)前端:有状态,功能最小化,尽量少上线;
  • 2)后端:无状态,功能最大化,上线可做到用户无感知。

所以,按照上面的原则,理论上我们会做出这样的功能划分,即前端很小、后端很大。示意图如下图所示。

8、新版接入层的技术实现

8.1 总览

模块拆分为前后端:

  • 1)前端有状态,后端无状态;
  • 2)前后端是独立进程,同机部署。

补充:前端负责建立与维护设备长连接的状态,为有状态服务;后端负责具体业务请求,为无状态服务。后端服务上线不会导致设备连接断开重连及鉴权调用,避免了长连接状态因版本升级或逻辑调整而引起的不必要抖动;

前端使用CPP实现:

  • 1)Websocket协议完全自己解析:可以从Socket层面获取所有信息,任何Bug都可以处理;
  • 2)更高的CPU利用率:没有任何额外JVM代价,无GC拖累性能;
  • 3)更高的内存利用率:连接数量变大后与连接相关的内存开销变大,自己管理可以极端优化。

后端暂时使用Scala实现:

  • 1)已实现的功能直接迁移,比重写代价要低得多;
  • 2)依赖的部分外部服务(比如鉴权)有可直接利用的Scala(Java)SDK库,而没有C++版本,若用C++重写代价非常大;
  • 3)全部功能无状态化改造,可以做到随时重启而用户无感知。

通讯使用ZeroMQ

进程间通讯最高效的方式是共享内存,ZeroMQ基于共享内存实现,速度没问题。

8.2 前端实现

整体架构:

 

如上图所示,由四个子模块组成:

  • 1)传输层:Websocket协议解析,XMD协议解析;
  • 2)分发层:屏蔽传输层的差异,不管传输层使用的什么接口,在分发层转化成统一的事件投递到状态机;
  • 3)状态机层:为了实现纯异步服务,使用自研的基于Actor模型的类Akka状态机框架XMFSM,这里面实现了单线程的Actor抽象;
  • 4)ZeroMQ通讯层:由于ZeroMQ接口是阻塞实现,这一层通过两个线程分别负责发送和接收。

8.2.1)传输层:

WebSocket 部分使用 C++ 和 ASIO 实现 websocket-lib。小爱长连接基于WebSocket协议,因此我们自己实现了一个WebSocket长连接库。

这个长连接库的特点是:

  • a. 无锁化设计,保障性能优异;
  • b. 基于BOOST ASIO 开发,保障底层网络性能。

压测显示该库的性能十分优异的:

这一层同时也承担了除原始WebSocket外,其他两种通道的的收发任务。

目前传输层一共支持以下3种不同的客户端接口:

  • a. websocket(tcp):简称ws;
  • b. 基于ssl的加密websocket(tcp):简称wss;
  • c. xmd(udp):简称xmd。

8.2.2)分发层:

把不同的传输层事件转化成统一事件投递到状态机,这一层起到适配器的作用,确保无论前面的传输层使用哪种类型,到达分发层变都变成一致的事件向状态机投递。

8.2.3)状态机处理层:

主要的处理逻辑都位于这一层中,这里非常重要的一个部分是对于发送通道的封装。

对于小爱应用层协议,不同的通道处理逻辑是完全一致的,但是在处理和安全相关逻辑上每个通道又有细节差异。

比如:

  • a. wss 收发不需要加解密,加解密由更前端的Nginx做了,而ws需要使用AES加密发送;
  • b. wss 在鉴权成功后不需要向客户端下发challenge文本,因为wss不需要做加解密;
  • c. xmd 发送的内容与其他两个不同,是基于protobuf封装的私有协议,且xmd需要处理发送失败后的逻辑,而ws/wss不用考虑发送失败的问题,由底层Tcp协议保证。

针对这种情况:我们使用C++的多态特性来处理,专门抽象了一个Channel接口,这个接口中提供的方法包含了一个请求处理的一些关键差异步骤,比如如何发送消息到客户端,如何stop连接,如何处理发送失败等等。对于3种(ws/wss/xmd)不同的发送通道,每个通道有自己的Channel实现。

客户端连接对象一创建,对应类型的具体Channel对象就立刻被实例化。这样状态机主逻辑中只实现业务层的公共逻辑即可,当在有差异逻辑调用时,直接调用Channel接口完成,这样一个简单的多态特性帮助我们分割了差异,确保代码整洁。

8.2.4)ZeroMQ 通讯层:

通过两个线程将ZeroMQ的读写操作异步化,同时负责若干私有指令的封装和解析。

8.3 后端实现

8.3.1)无状态化改造:

后端做的最重要改造之一就是将所有与连接状态相关的信息进行剔除。

整个服务以 Request(一次连接上可以传输N个Request)为核心进行各种转发和处理,每次请求与上一次请求没有任何关联。一个连接上的多次请求在后端模块被当做独立请求处理。

8.3.2)架构:

Scala 服务采用 Akka-Actor 架构实现了业务逻辑。

服务从 ZeroMQ 收到消息后,直接投递到 Dispatcher 中进行数据解析与请求处理,在 Dispatcher 中不同的请求会发送给对应的 RequestActor进行 Event 协议解析并分发给该 event 对应的业务 Actor 进行处理。最后将处理后的请求数据通过XmqActor 发送给后端 AIMS&XMQ 服务。

一个请求在后端多个 Actor 中的处理流程:

8.3.3)Dispatcher 请求分发:

前端与后端之间通过 Protobuf 进行交互,避免了Json 解析的性能消耗,同时使得协议更加规范化。

后端服务从 ZeroMQ 收到消息后,会在 DispatcherActor 中进行PB协议解析并根据不同的分类(简称CMD)进行数据处理,分类包括如下几种。

* BIND 命令:

鉴权功能,由于鉴权功能逻辑复杂,使用C++语言实现起来较为困难,目前依然放在 scala 业务层进行鉴权。该部分对设备端请求的 HTTP Headers 进行解析,提取其中的 token 进行鉴权,并将结果返回前端。

* LOGIN 命令:

设备登入,设备鉴权通过后当前连接已成功建立,此时会进行 Login 命令的执行,用于将该长连接信息发送至AIMS并记录于Varys服务中,方便后续的主动下推等功能。在 Login 过程中,服务首先将请求 Account 服务获取长连接的 uuid(用于连接过程中的路由寻址),然后将设备信息+uuid 发送至AIMS进行设备登入操作。

* LOGOUT 命令:

设备登出,设备在与服务端断开连接时需要进行 Logout 操作,用于从 Varys 服务中删除该长连接记录。

* UPDATE 与 PING 命令:

a. Update 命令,设备状态信息更新,用于更新该设备在数据库中保存的相关信息;

b. Ping 命令,连接保活,用于确认该设备处于在线连接状态。

* TEXT_MESSAGE 与 BINARY_MESSAGE:

文本消息与二进制消息,在收到文本消息或二进制消息时将根据 requestid 发送给该请求对应的RequestActor进行处理。

8.3.4)Request 请求解析:

针对收到的文本和二进制消息,DispatcherActor 会根据 requestId 将其发送给对应的RequestActor进行处理。

其中:文本消息将会被解析为Event请求,并根据其中的 namespace 和 name 将其分发给指定的业务Actor。二进制消息则会根据当前请求的业务场景被分发给对应的业务Actor。

8.4 其他优化

在完成新架构 1.0 调整过程中,我们也在不断压测长连接容量,总结几点对容量影响较大的点。

8.4.1)协议优化:

a. JSON替换为Protobuf: 早期的前后端通信使用的是 json 文本协议,后来发现 json 序列化、反序列化这部分对CPU的占用较大,改为了 protobuf 协议后,CPU占用率明显下降。

b. JSON支持部分解析:业务层的协议是基于json的,没有办法直接替换,我们通过"部分解析json"的方式,只解析很小的 header 部分拿到 namespace 和 name,然后将大部分直接转发的消息转发出去,只将少量 json 消息进行完整反序列化成对象。此种优化后CPU占用下降10%。

8.4.2)延长心跳时间:

在第一次测试20w连接时,我们发现在前后端收发的消息中,一种用来保持用户在线状态的心跳PING消息占了总消息量的75%,收发这个消息耗费了大量CPU。因此我们延长心跳时间也起到了降低CPU消耗的目的。

8.4.3)自研内网通讯库:

为了提高与后端服务通信的性能,我们使用自研的TCP通讯库,该库是基于Boost ASIO开发的一个纯异步的多线程TCP网络库,其卓越的性能帮助我们将连接数提升到120w+。

9、未来规划

经过新版架构1.0版的优化,验证了我们的拆分方向是正确的,因为预设的目标已经达到:

  • 1)单机承载的连接数 28w => 120w+(普通服务端机器 16G内存 40核 峰值请求QPS过万),接入层下线节省了50%+的机器成本;
  • 2)后端可以做到无损上线。

再重新审视下我们的理想目标,以这个为方向,我们就有了2.0版的雏形:

具体就是:

  • 1)后端模块使用C++重写,进一步提高性能和稳定性。同时将后端模块中无法使用C++重写的部分,作为独立服务模块运维,后端模块通过网络库调用;
  • 2)前端模块中非必要功能尝试迁移到后端,让前端功能更少,更稳定;
  • 3)如果改造后,前端与后端处理能力差异较大,考虑到ZeroMQ实际是性能过剩的,可以考虑使用网络库替换掉ZeroMQ,这样前后端可以从1:1单机部署变为1:N多机部署,更好的利用机器资源。

2.0版目标是:经过以上改造后,期望单前端模块可以达到200w+的连接处理能力。

10、参考资料

[1] 上一个10年,著名的C10K并发连接问题

[2] 下一个10年,是时候考虑C10M并发问题了

[3] 一文读懂高性能网络编程中的线程模型

[4] 深入操作系统,一文读懂进程、线程、协程

[5] Protobuf通信协议详解:代码演示、详细原理介绍等

[6] WebSocket从入门到精通,半小时就够!

[7] 如何让你的WebSocket断网重连更快速?

[8] 从100到1000万高并发的架构演进之路

学习交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK 

(本文同步发布于:http://www.52im.net/thread-3860-1-1.html

posted @ 2022-03-22 17:00 Jack Jiang 阅读(618) | 评论 (0)编辑 收藏

本文由阿里闲鱼技术团队书闲分享,原题“如何有效缩短闲鱼消息处理时长”,有修订和改动。

1、引言

闲鱼技术团队围绕IM这个技术范畴,已经分享了好几篇实践性总结文章,本篇将要分享的是闲鱼IM系统中在线和离线聊天消息数据的同步机制上所遇到的一些问题,以及实践性的解决方案。

学习交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK 

本文已同步发布于:http://www.52im.net/thread-3856-1-1.html

2、系列文章

本文是系列文章的第7篇,总目录如下:

  1. 阿里IM技术分享(一):企业级IM王者——钉钉在后端架构上的过人之处
  2. 阿里IM技术分享(二):闲鱼IM基于Flutter的移动端跨端改造实践
  3. 阿里IM技术分享(三):闲鱼亿级IM消息系统的架构演进之路
  4. 阿里IM技术分享(四):闲鱼亿级IM消息系统的可靠投递优化实践
  5. 阿里IM技术分享(五):闲鱼亿级IM消息系统的及时性优化实践
  6. 阿里IM技术分享(六):闲鱼亿级IM消息系统的离线推送到达率优化
  7. 阿里IM技术分享(七):闲鱼IM的在线、离线聊天数据同步机制优化实践》(* 本文

3、问题背景

随着用户数的快速增长,闲鱼IM系统也迎来了前所未有的挑战。

历经多年的业务迭代,客户端侧IM的代码已经因为多年的迭代层次结构不足够清晰,之前一些隐藏起来的聊天数据同步问题,也随着用户数的增大而被放大。

这里面的具体流程在于:后台需要同步到用户端侧的数据包,后台会根据数据包的业务类型划分成不同的数据域,数据包在对应域里面存在唯一且连续的编号,每一个数据包发送到端侧并且被成功消费后,端侧会记录当前每一个数据域已经同步过的版本编号,下一次数据同步就以本地数据域的编号开始,不断的同步到客户端。

当然用户不会一直在线等待消息,所以之前端侧采用了推拉结合的方式保证数据的同步。

具体就是:

  • 1)客户端在线时:使用ACCS实时的将最新的数据内容推送到客户端(ACCS是淘宝无线向开发者提供全双工、低延时、高安全的通道服务);
  • 2)客户端从离线状态启动后:根据本地的数据域编号,拉取不在线时候的数据差;
  • 3)当数据获取出现黑洞时:触发数据同步拉取(“黑洞”即指数据包Version不连续的状态)。

4、问题分析

当前的聊天数据同步策略确实是可以基本保障IM的数据同步的,但是也伴随着一些隐含的问题。

这些隐含的问题主要有:

  • 1)短时间密集数据推送时,会快速的触发多次数据域同步。域同步回来的数据如果存在问题,又会触发新一轮的同步,造成网络资源的浪费。冗余数据包/无效的数据内容会占用有效内容的处理资源,又对CPU和内存资源造成浪费;
  • 2)数据域中的数据包客户端是否正常消费,服务端侧无感知,只能被动地根据当前数据域信息返回数据;
  • 3)数据收取/消息数据体解析/存储落库逻辑拆分不够清晰,无法针对性的对某一层的代码拆分替换进行ABTest。

针对上述问题,我们对闲鱼IM进行了分层改造——即抽离数据同步层。这样优化,除了希望以后这个数据的同步内容可以用在IM之外,也希望随着稳定性的增加,赋能其他的业务场景。

接下来的内容,我们重点来看下解决客户端侧闲鱼IM聊天数据同步问题的一些实践思路。

5、优化思路

5.1 分层拆分

对于服务端来说:业务侧产出数据包后,会拼接上当前的数据域信息,然后通过数据同步层将数据推送到端侧。

对于客户端来说:接收到数据包后,会根据当前的数据域信息,来确定需要消费数据包的业务方,确保数据包在数据域内完整连续后,将数据体脱壳后交于业务侧消费,并且应答消费的状况。

数据同步层的抽取:把数据同步中的加壳、脱壳、校验、重试流程封装到一起,可以让上层业务只需要关心自己需要监听的数据域信息,然后当这些数据域更新数据的时候,可以获取到这些数据进行消费,而不再需要关心数据包是否完整。

这样做的话:

  • 1)业务侧只需要关心业务侧对接的协议;
  • 2)数据侧只需要关心数据侧包装的协议;
  • 3)网络层负责真实的数据传输。

整体的架构原理如下:

总结一下就是:

  • 1)对齐数据层数据传输协议、描述当前数据包体数据域信息;
  • 2)将消息的处理/合并/落库抽离成数据消费者;
  • 3)上下楼依赖抽象化,去除对于具体实现的依赖。

5.2 数据层结构模型

基于对于数据模型剥离和对当下遇见问题的解决方案规整,将数据同步层拆分为下图这样的架构。

具体的实施思路就是:

  • 1)App启动时建立ACCS长链接服务,保证推推送信道链接,并且根据当前本地数据域信息触发一次数据拉取;
  • 2)数据消费者注册消费者信息和需要监听的数据域信息,这里是一对多的关系;
  • 3)新的数据抵达端侧后,将数据包放到指定的数据域的缓冲池,批量数据归纳结束后,重新出发数据的读取;
  • 4)根据当前数据域优先级弹出最高优的数据包,判断数据域版本是否符合消费者要求,符合则将数据包脱壳后丢给消费者消费,不符合则根据上一次正确的数据包的域信息触发增量的数据域同步拉取;
  • 5)触发数据域同步拉取时,block数据读取,此时通过ACCS触达的数据依旧会在继续归纳到指定的数据域队列中,等待数据域同步拉取结果,将数据包进行排序、去重,合并到对应的数据域队列中。然后重新激活数据读取;
  • 6)数据包体被消费者正确消费后,更新域信息并且通过上行信道告知服务端已经正确处理的数据域信息。

* 数据域同步协议:

Region中携带的数据不必过多,但需将数据包的内容描述清楚,具体是:

  • 1)目标用户的ID,用以确定目标数据包是否正确;
  • 2)数据域ID和优先级信息;
  • 3)当前数据包的域优先级版本。

* 排序策略:

针对于域数据归纳,无论是在写入数据的时候进行排序还是在读取的时候进行查找都需要进行一次排序的操作,时间复杂度最优也是O(logn)级别的。

在实际coding中发现由于在一个数据域里面,数据包的Version信息是连续唯一并且不存在断层的,上一个稳定消费的数据体的Version信息自增就是下一个数据包的Version,所以这里采用了以Versio为主键的Map存储,既降低了时间复杂度,也使得唯一标识的数据包后抵达端侧的包内容可以覆盖之前的包内容。

6、新的问题及解决策略

6.1 多数据来源和唯一数据消费的平衡

每当产生一条针对于当前用户的数据包:

  • 1)如果当前ACCS长链接存在,就会通过ACCS将数据包推送到客户端;
  • 2)如果App切换到后台一段时间,或者直接被杀死,ACCS链接断开,那么只能通过离线推送到用户的通知面板。

所以:每当App切换到活跃状态,都需要根据当前本地存储的数据域信息从后台触发一次数据同步。

数据包触达到客户端侧的来源主要是ACCS长链接的推送和域同步时的拉取,但是数据包的消费是根据数据域的监听划分的唯一消费者,也就是同一时间内只能消费一个数据包。

在压力测试中:当后台短时间内密集的将数据包通过ACCS推送到端侧时,端侧接收到的数据包并不有序,不连续的数据包域版本又会触发新的数据域同步,导致同样的一份数据包会通过两个不同的渠道多次的触达到端侧,浪费了不必要的流量。

当数据域同步时:这个时间节点产生的新数据包也会推送到端侧,数据体有效,并且需要被正确的消费。

针对上述这些问题的解决策略:

即在数据消费和数据获取中间装载一个数据中间层,当触发数据域同步的时候block数据的读取并且ACCS推送下来的数据包会被存放在一个数据的中转站里面,当数据域同步拉取的数据回来后,对数据进行合并后再重启数据读取流程。

6.2 数据域优先级

需要推送到客户端侧的数据包,根据业务的不同优先级也有不同的划分。

用户和用户的聊天产生的数据包会比运营类的消息的数据包优先级要高一些,所以要当多优先级的数据包快速的抵达端侧时,高优先级数据域的数据包需要被优先消费,而数据域的优先级也是需要动态调整,需要不断变换的优先级策略。

针对这个问题的解决策略:

不同的数据域,产生不同的数据队列,高优队列里面的数据包会被优先读取消费。

每一个数据包体中带回的数据域信息,都可以标注当前的数据域优先级,当数据域优先级发生变化的时候,调整数据包消费优先级策略。

7、优化后的效果

除去结构上分层梳理,使得数据同步层和依赖的服务内容可便捷解耦/每一个环节可插拔之外,数据同步中对于消息消费时长/流量节省,压力测试场景下优化效果更加明显。

在“500ms内100条全乱序数据包推送”压力测试场景下:

  • 1)消息处理时长(接收-上屏)缩短 31%;
  • 2)流量损耗(最终拉取到端侧数据包累积大小)降低35%。

8、后续的优化计划

8.1 数据同步层能力提升

数据同步侧的目标,既要保证数据包完整的到达端侧,又要在保证稳定性的前提下尽可能的减少数据的拉取,使得每一次数据的获取都有效。

后续数据同步层会着手于有效数据率和到达率进行更进一步的优化。

针对不同的场景,动态智能调整数据同步的优先级策略。

阻塞式长链接推送,保证同一时间只存在推模式或者拉模式,进一步减少冗余数据包的推送。

8.2 IM端侧整体架构升级

升级数据同步层策略主要还是要提升IM的能力,将数据同步分层后,接下来就是将消息的处理流程化,对每一个流程都可监控可回溯,提升IM数据包的正确解析存储和落库率。

细化一下就是:

  • 1)在数据来源侧剥离开后,后续对IM的整改也会逐步的将消息的处理分层剥离;
  • 2)消息处理关键节点的流程式上报、建立完整的监控体系,让问题发现先于用户舆情;
  • 3)消息完整性的动态自检,最小化数据补偿补全。

9、参考资料

[1] IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?

[2] IM群聊消息如此复杂,如何保证不丢不重?

[3] 一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践

[4] 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

[5] 从新手到专家:如何设计一套亿级消息量的分布式IM系统

[6] 融云技术分享:全面揭秘亿级IM消息的可靠投递机制

[7] 移动端IM中大规模群消息的推送如何保证效率、实时性?

[8] 现代IM系统中聊天消息的同步和存储方案探讨

[9] 新手入门一篇就够:从零开发移动端IM

[10] IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

[11] IM消息送达保证机制实现(二):保证离线消息的可靠投递

[12] 零基础IM开发入门(四):什么是IM系统的消息时序一致性?

[13] IM开发干货分享:我是如何解决大量离线消息导致客户端卡顿的

(本文已同步发布于:http://www.52im.net/thread-3856-1-1.html

posted @ 2022-03-15 17:32 Jack Jiang 阅读(424) | 评论 (0)编辑 收藏

本文由作者小林coding分享,来自公号“小林coding”,有修订和改动。

1、引言

说到TCP协议,对于从事即时通讯/IM这方面应用的开发者们来说,再熟悉不过了。随着对TCP理解的越来越深入,很多曾今碰到过但没时间深入探究的TCP技术概念或疑问,现在是时候回头来恶补一下了。

本篇文章,我们就从系统层面深入地探讨一个有趣的TCP技术问题:拔掉网线后,再插上,原本的这条TCP连接还在吗?或者说它还“好”吗?

可能有的人会说:网线都被拔掉了,那说明物理层(也叫实体层)被断开了(关于网络协议分层模型请见《快速理解网络通信协议(上篇)》),那在物理层之上的传输层理应也会断开,所以原本的 TCP 连接就不会存在的了。就好像我们拨打有线电话的时候,如果某一方的电话线被拔了,那么本次通话就彻底断了。

答案真的是这样吗?可能并非你理解的这样哦,一起跟随笔者来深入探讨一下。

学习交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK 

本文同步发布于:http://www.52im.net/thread-3846-1-1.html

2、系列文章

本文是系列文章中的第14篇,本系列文章的大纲如下:

3、比较笼统的答案

3.1 答案

引言里我们说到:有人认为,网线都被拔掉了,那说明物理层被断开,那么物理层之上的传输层肯定也会断开,所以原来的 TCP 连接自然也就不存在了。(PS:计算机网络分层详解请见《史上最通俗计算机网络分层详解

上面这个逻辑是有问题的。

问题在于:错误的认为拔掉网线这个动作会影响传输层,事实上并不会影响!

实际上:TCP 连接在 Linux 内核中是一个名为 struct socket 的结构体,该结构体的内容包含 TCP 连接的状态等信息。

所以:当拔掉网线的时候,操作系统并不会变更该结构体的任何内容,所以 TCP 连接的状态也不会发生改变。

3.2 实验验证一下

我做了个小实验:我用 ssh 终端连接了我的云服务器,然后我通过断开 wifi 的方式来模拟拔掉网线的场景,此时查看 TCP 连接的状态没有发生变化,还是处于 ESTABLISHED 状态(如下图所示)。

通过上面实验结果可以验证我的结论:拔掉网线这个动作并不会影响 TCP 连接的状态。

不过,这个答案还是有点笼统。实际上,我们应该在更具体的场景中来看待这个问题,答案才更准确一些。

这个具体场景就是:

  • 1)当拔掉网线后,有数据传输时;
  • 2)当拔掉网线后,没有数据传输时。

针对上面这两种具体的场景,我来更具体地来分析一下。我们继续往下阅读。

4、具体场景1:拔掉网线后,有数据传输时

4.1 数据传输过程中,恰好又把网线插回去了

如果是客户端被拔掉网线后,服务端向客户端发送的数据报文会得不到任何的响应,在等待一定时长后,服务端就会触发TCP协议的超时重传机制(详见:《TCP/IP详解 - 第21章·TCP的超时与重传),然而此时重传并不能得到响应的数据报文。

如果在服务端重传报文的过程中,客户端恰好把网线插回去了,由于拔掉网线并不会改变客户端的 TCP 连接状态,并且还是处于 ESTABLISHED 状态,所以这时客户端是可以正常接收服务端发来的数据报文的,然后客户端就会回 ACK 响应报文。

此时:客户端和服务端的 TCP 连接将依然存在且工作状态不会受到影响,给应用层的感觉就像什么事情都没有发生。。。

4.2 数据传输过程中,网线一直没有插回去

上面这种情况下,如果在服务端TCP协议重传报文的过程中,客户端一直没有将网线插回去,那么服务端超时重传报文的次数达到一定阈值后,内核就会判定出该 TCP 有问题。然后就会通过 Socket 接口告诉应用程序该 TCP 连接出问题了,于是服务端的 TCP 连接就会断开。

接下来,如果客户端再插回网线,如果客户端向服务端发送了数据,由于服务端已经没有与客户端匹配的 TCP 连接信息了,因此服务端内核就会回复 RST 报文,客户端收到后就会释放该 TCP 连接。

此时:客户端和服务端的 TCP 连接已经明确被断开,原本的这个连接也就不存在了。

4.3 刨根问底:TCP数据报文到底重传几次?

本着知其然更应知其所以然的精神,我们来刨根问底一下:TCP 的数据报文到底有重传几次呢?

在 Linux 系统中,提供了一个叫 tcp_retries2 配置项,默认值是 15(如下图所示)。

如上图所示:这个内核参数是控制 TCP 连接建立的情况下,超时重传的最大次数。

不过 tcp_retries2 设置了 15 次,并不代表 TCP 超时重传了 15 次才会通知应用程序终止该 TCP 连接,内核还会基于“最大超时时间”来判定。

每一轮的超时时间都是倍数增长的,比如第一次触发超时重传是在 2s 后,第二次则是在 4s 后,第三次则是 8s 后,以此类推。

内核会根据 tcp_retries2 设置的值,计算出一个最大超时时间。

在重传报文且一直没有收到对方响应的情况时,先达到“最大重传次数”或者“最大超时时间”这两个的其中一个条件后,就会停止重传,然后就会断开 TCP 连接。

PS:有关TCP超时重传机制的详细情况,可以阅读浅析TCP协议中的疑难杂症(下篇)》。

5、具体场景2:拔掉网线后,有数据传输时

5.1 场景分析

针对拔掉网线后,没有数据传输的场景,还得具体看看是否开启了 TCP KeepAlive 机制 (详见《彻底搞懂TCP协议层的KeepAlive保活机制》)。

1)如果没有开启 TCP KeepAlive 机制:

在客户端拔掉网线后,并且双方都没有进行数据传输,那么客户端和服务端的 TCP 连接将会一直保持存在。

2)如果开启了 TCP KeepAlive 机制:

在客户端拔掉网线后,即使双方都没有进行数据传输,在持续一段时间后,TCP 就会发送KeepAlive探测报文。

根据KeepAlive探测报文响应情况,会有以下两种可能:

  • 1)如果对端正常工作:当探测报文被对端收到并正常响应, TCP 保活时间将被重置,等待下一个 TCP 保活时间的到来;
  • 2)如果对端主机崩溃或对端由于其他原因导致报文不可达:当探测报文发送给对端后,石沉大海、没有响应,连续几次,达到保活探测次数后,TCP 会报告该连接已经死亡。

所以:TCP 保活机制可以在双方没有数据交互的情况,通过TCP KeepAlive 机制的探测报文,来确定对方的 TCP 连接是否存活。

5.2 刨根问底:TCP KeepAlive 机制具体是什么样的?

TCP KeepAlive 机制的原理是这样的:

定义一个时间段,在这个时间段内,如果没有任何连接相关的活动,TCP 保活机制会开始作用,每隔一个时间间隔,发送一个探测报文。该探测报文包含的数据非常少,如果连续几个探测报文都没有得到响应,则认为当前的 TCP 连接已经死亡,系统内核将错误信息通知给上层应用程序。

在 Linux 内核可以有对应的参数可以设置保活时间、保活探测的次数、保活探测的时间间隔。

以下是 Linux 中的默认值:

net.ipv4.tcp_keepalive_time=7200

net.ipv4.tcp_keepalive_intvl=75 

net.ipv4.tcp_keepalive_probes=9

解释一下:

  • 1)tcp_keepalive_time=7200:表示保活时间是 7200 秒(2小时),也就 2 小时内如果没有任何连接相关的活动,则会启动保活机制;
  • 2)tcp_keepalive_intvl=75:表示每次检测间隔 75 秒;
  • 3)tcp_keepalive_probes=9:表示检测 9 次无响应,认为对方是不可达的,从而中断本次的连接。

也就是说在 Linux 系统中,最少需要经过 2 小时 11 分 15 秒才可以发现一个“死亡”连接。

计算公式是:

注意:应用程序若想使用 TCP 保活机制需要通过 socket 接口设置 SO_KEEPALIVE 选项才能够生效,如果没有设置,那么就无法使用 TCP 保活机制。

PS:关于TCP协议的KeepAlive 机制详见《彻底搞懂TCP协议层的KeepAlive保活机制》、《一文读懂即时通讯应用中的网络心跳包机制:作用、原理、实现思路等》。

5.3 刨根问底:TCP KeepAlive 机制的探测时间也太长了吧?

没错,确实有点长。

TCP KeepAlive  机制是 TCP 层(内核态) 实现的,它是给所有基于 TCP 传输协议的程序一个兜底的方案。

实际上:我们通常在应用层自己实现一套探测机制,可以在较短的时间内,探测到对方是否存活。

比如:一般Web 服务器都会提供 keepalive_timeout 参数,用来指定 HTTP 长连接的超时时间。如果设置了 HTTP 长连接的超时时间是 60 秒,Web 服务软件就会启动一个定时器,如果客户端在完后一个 HTTP 请求后,在 60 秒内都没有再发起新的请求,定时器的时间一到,就会触发回调函数来释放该连接。

再比如:IM、消息推送系统里的心跳机制,通过应用层的心跳机制(由客户端发出,服务端回复响应包),来灵活控制和探测长连接的健康度。

为何基于TCP协议的移动端IM仍然需要心跳保活机制?》这篇文章解释了IM这类应用中应用层心跳保活的必要性,有兴趣可以读一读。

如果对应用层心跳的具体应用没什么概念,可以看看微信的这两篇文章:

  1. 微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)
  2. 移动端IM实践:实现Android版微信的智能心跳机制

下面有几个针对im这类应用的心跳实现代码,可以具体感受学习一下:

  1. 正确理解IM长连接的心跳及重连机制,并动手实现(有完整IM源码)
  2. 一种Android端IM智能心跳算法的设计与实现探讨(含样例代码)
  3. 自已开发IM有那么难吗?手把手教你自撸一个Andriod版简易IM (有源码)
  4. 手把手教你用Netty实现网络通信程序的心跳机制、断线重连机制

6、本文小结

下面简单总结一下文中的内容,本文开头的问题并不是简单一句话能够准确说清楚的,需要分情况对待。

也就是:客户端拔掉网线后,并不会直接影响 TCP 的连接状态。所以拔掉网线后,TCP 连接是否还会存在,关键要看拔掉网线之后,有没有进行数据传输。

1)有数据传输的情况:

在客户端拔掉网线后:如果服务端发送了数据报文,那么在服务端重传次数没有达到最大值之前,客户端恰好插回网线的话,那么双方原本的 TCP 连接还是能存在并正常工作,就好像什么事情都没有发生。

在客户端拔掉网线后:如果服务端发送了数据报文,在客户端插回网线之前,服务端重传次数达到了最大值时,服务端就会断开 TCP 连接。等到客户端插回网线后,向服务端发送了数据,因为服务端已经断开了与客户端相同四元组的 TCP 连接,所以就会回 RST 报文,客户端收到后就会断开 TCP 连接。至此, 双方的 TCP 连接都断开了。

2)没有数据传输的情况:

  • a. 如果双方都没有开启 TCP keepalive 机制,那么在客户端拔掉网线后,如果客户端一直不插回网线,那么客户端和服务端的 TCP 连接状态将会一直保持存在;
  • b. 如果双方都开启了 TCP keepalive 机制,那么在客户端拔掉网线后,如果客户端一直不插回网线,TCP keepalive 机制会探测到对方的 TCP 连接没有存活,于是就会断开 TCP 连接。而如果在 TCP 探测期间,客户端插回了网线,那么双方原本的 TCP 连接还是能正常存在。

除了客户端拔掉网线的场景,还有客户端“宕机和杀死进程”的两种场景。

第一个场景:客户端宕机这件事跟拔掉网线是一样无法被服务端的感知的,所以如果在没有数据传输,并且没有开启 TCP keepalive 机制时,,服务端的 TCP 连接将会一直处于 ESTABLISHED 连接状态,直到服务端重启进程。

所以:我们可以得知一个点——在没有使用 TCP 保活机制,且双方不传输数据的情况下,一方的 TCP 连接处在 ESTABLISHED 状态时,并不代表另一方的 TCP 连接还一定是正常的。

第二个场景:杀死客户端的进程后,客户端的内核就会向服务端发送 FIN 报文,与客户端进行四次挥手(见《跟着动画来学TCP三次握手和四次挥手》)。

所以:即使没有开启 TCP KeepAlive,且双方也没有数据交互的情况下,如果其中一方的进程发生了崩溃,这个过程操作系统是可以感知的到的,于是就会发送 FIN 报文给对方,然后与对方进行 TCP 四次挥手。

7、参考资料

[1] TCP/IP详解 - 第21章·TCP的超时与重传

[2] 通俗易懂-深入理解TCP协议(上):理论基础

[3] 网络编程懒人入门(三):快速理解TCP协议一篇就够

[4] 脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手

[5] 脑残式网络编程入门(七):面视必备,史上最通俗计算机网络分层详解

[6] 技术大牛陈硕的分享:由浅入深,网络编程学习经验干货总结

[7] 网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?

[8] 不为人知的网络编程(十):深入操作系统,从内核理解网络包的接收过程(Linux篇)

[9] 为何基于TCP协议的移动端IM仍然需要心跳保活机制?

[10] 一文读懂即时通讯应用中的网络心跳包机制:作用、原理、实现思路等

[11] Web端即时通讯实践干货:如何让你的WebSocket断网重连更快速?

本文同步发布于:http://www.52im.net/thread-3846-1-1.html

posted @ 2022-03-07 18:15 Jack Jiang 阅读(258) | 评论 (0)编辑 收藏

     摘要: 本文由微信开发团队工程师“ qiuwenchen”分享,发布于WeMobileDev公众号,有修订。1、引言全文搜索是使用倒排索引进行搜索的一种搜索方式。倒排索引也称为反向索引,是指对输入的内容中的每个Token建立一个索引,索引中保存了这个Token在内容中的具体位置。全文搜索技术主要应用在对大量文本内容进行搜索的场景。微信终端涉及到大量文本搜索的业务场景主要包括:im联...  阅读全文

posted @ 2022-02-28 17:48 Jack Jiang 阅读(141) | 评论 (0)编辑 收藏

本文由融云技术团队原创分享,有修订和改动。

1、引言

在视频直播场景中,弹幕交互、与主播的聊天、各种业务指令等等,组成了普通用户与主播之间的互动方式。

从技术的角度来看,这些实时互动手段,底层逻辑都是实时聊天消息或指令的分发,技术架构类比于IM应用的话,那就相当于IM聊天室功能。

本系列文章的上篇《百万人在线的直播间实时聊天消息分发技术实践》主要分享的是消息分发和丢弃策略。本文将主要从高可用、弹性扩缩容、用户管理、消息分发、客户端优化等角度,分享直播间海量聊天消息的架构设计技术难点的实践经验。

学习交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK 

本文已同步发布于:http://www.52im.net/thread-3835-1-1.html

2、系列文章

本文是系列文章中的第7篇:

直播系统聊天技术(一):百万在线的美拍直播弹幕系统的实时推送技术实践之路

直播系统聊天技术(二):阿里电商IM消息平台,在群聊、直播场景下的技术实践

直播系统聊天技术(三):微信直播聊天室单房间1500万在线的消息架构演进之路

直播系统聊天技术(四):百度直播的海量用户实时消息系统架构演进实践

直播系统聊天技术(五):微信小游戏直播在Android端的跨进程渲染推流实践

直播系统聊天技术(六):百万人在线的直播间实时聊天消息分发技术实践

直播系统聊天技术(七):直播间海量聊天消息的架构设计难点实践》(* 本文

3、直播间的主要功能和技术特征

如今的视频直播间早已不单纯是视频流媒体技术问题,它还包含了用户可感知的多类型消息发送和管理、用户管理等任务。在万物皆可直播的当下,超大型直播场景屡见不鲜,甚至出现了人数无上限的场景,面对如此海量实时消息和指令的并发挑战,带来的技术难度已非常规手段所能解决。

我们先来归纳一下如今的典型视频直播间,相较于传统直播间所包含的主要功能特征、技术特征等。

丰富的消息类型和进阶功能:

  • 1)可发送文字、语音、图片等传统聊天功能;
  • 2)可实现点赞、礼物等非传统聊天功能的消息类型;
  • 3)可管理内容安全,包括敏感词设置,聊天内容反垃圾处理等。

聊天管理功能:

  • 1)用户管理:包括创建、加入、销毁、禁言、查询、封禁(踢人)等;
  • 2)用户白名单:白名单用户处于被保护状态不会被自动踢出,且发送消息优先级别最高;
  • 3)消息管理:包括消息优先级、消息分发控制等;
  • 4)实时统计及消息路由等能力。

人数上限和行为特征:

  • 1)人数没有上限:一些大型直播场景,如春晚、国庆大阅兵等,直播间累计观看动辄上千万人次,同时观看人数也可达数百万;
  • 2)用户进退行为:用户进出直播间非常频繁,高热度直播间的人员进出秒并发可能上万,这对服务支撑用户上下线以及用户管理的能力提出了非常大的挑战。

海量消息并发:

  • 1)消息并发量大:直播聊天室人数没有明显上限,带来了海量并发消息的问题(一个百万人数的聊天室,消息的上行已是巨量,消息分发量更是几何级上升);
  • 2)消息实时性高:如果服务器只做消息的消峰处理,峰值消息的堆积会造成整体消息延时增大。

针对上述第 2) 点,延时的累积效应会导致消息与直播视频流在时间线上产生偏差,进而影响用户观看直播时互动的实时性。所以,服务器的海量消息快速分发能力十分重要。

4、直播间聊天室的架构设计

高可用系统需要支持服务故障自动转移、服务精准熔断降级、服务治理、服务限流、服务可回滚、服务自动扩容 / 缩容等能力。

以服务高可用为目标的直播间聊天室系统架构如下:

如上图所示,系统架构主要分三层:

  • 1)连接层:主要管理服务跟客户端的长链接;
  • 2)存储层:当前使用的是 Redis,作为二级缓存,主要存储聊天室的信息(比如人员列表、黑白名单、封禁列表等,服务更新或重启时,可以从 Redis 中加载出聊天室的备份信息);
  • 3)业务层:这是整个聊天室的核心,为了实现跨机房容灾,将服务部署在多个可用区,并根据能力和职责,将其分为聊天室服务和消息服务。

聊天室服务和消息服务的具体职责:

  • 1)聊天室服务:主要负责处理管理类请求,比如聊天室人员的进出、封禁 / 禁言、上行消息处理审核等;
  • 2)消息服务:主要缓存本节点需要处理的用户信息以及消息队列信息,并负责聊天室消息的分发。

在海量用户高并发场景下,消息分发能力将决定着系统的性能。以一个百万级用户量的直播间聊天室为例,一条上行消息对应的是百万倍的分发。这种情况下,海量消息的分发,依靠单台服务器是无法实现的。

我们的优化思路是:将一个聊天室的人员分拆到不同的消息服务上,在聊天室服务收到消息后向消息服务扩散,再由消息服务分发给用户。

以百万在线的直播间聊天室为例:假设聊天室消息服务共 200 台,那平均每台消息服务管理 5000 人左右,每台消息服务在分发消息时只需要给落在本台服务器上的用户分发即可。

服务落点的选择逻辑:

  • 1)在聊天室服务中:聊天室的上行信令是依据聊天室 ID 使用一致性哈希算法来选择节点的;
  • 2)在消息服务中:依据用户 ID 使用一致性哈希算法来决定用户具体落在哪个消息服务。

一致性哈希选择的落点相对固定,可以将聊天室的行为汇聚到一个节点上,极大提升服务的缓存命中率。

聊天室人员进出、黑 / 白名单设置以及消息发送时的判断等处理直接访问内存即可,无须每次都访问第三方缓存,从而提高了聊天室的响应速度和分发速度。

最后:Zookeeper 在架构中主要用来做服务发现,各服务实例均注册到 Zookeeper。

5、直播间聊天室的扩缩容能力

5.1 概述

随着直播这种形式被越来越多人接受,直播间聊天室面对人数激增致使服务器压力逐步增大的情况越来越多。所以,在服务压力逐步增大 / 减少的过程中能否进行平滑的扩 / 缩容非常重要。

在服务的自动扩缩容方面,业内提供的方案大体一致:即通过压力测试了解单台服务器的瓶颈点  通过对业务数据的监控来判断是否需要进行扩缩 → 触发设定的条件后报警并自动进行扩缩容。

鉴于直播间聊天室的强业务性,具体执行中应该保证在扩缩容中整体聊天室业务不受影响。

5.2 聊天室服务扩缩容

聊天室服务在进行扩缩容时,我们通过 Redis 来加载成员列表、封禁 / 黑白名单等信息。

需要注意的是:在聊天室进行自动销毁时,需先判断当前聊天室是否应该是本节点的。如果不是,跳过销毁逻辑,避免 Redis 中的数据因为销毁逻辑而丢失。

聊天室服务扩缩容方案细节如下图所示:

5.3 消息服务扩缩容

消息服务在进行扩缩容时,大部分成员需要按照一致性哈希的原则路由到新的消息服务节点上。这个过程会打破当前的人员平衡,并做一次整体的人员转移。

1)在扩容时:我们根据聊天室的活跃程度逐步转移人员。

2)在有消息时:[消息服务会遍历缓存在本节点上的所有用户进行消息的通知拉取,在此过程中判断此用户是否属于这台节点(如果不是,将此用户同步加入到属于他的节点)。

3)在拉消息时:用户在拉取消息时,如果本机缓存列表中没有该用户,消息服务会向聊天室服务发送请求确认此用户是否在聊天室中(如果在则同步加入到消息服务,不在则直接丢掉)。

4)在缩容时:消息服务会从公共 Redis 获得全部成员,并根据落点计算将本节点用户筛选出来并放入用户管理列表中。

6、海量用户的上下线和管理

聊天室服务:管理了所有人员的进出,人员的列表变动也会异步存入 Redis 中。

消息服务:则维护属于自己的聊天室人员,用户在主动加入和退出房间时,需要根据一致性哈希算出落点后同步给对应的消息服务。

聊天室获得消息后:聊天室服务广播给所有聊天室消息服务,由消息服务进行消息的通知拉取。消息服务会检测用户的消息拉取情况,在聊天室活跃的情况下,30s 内人员没有进行拉取或者累计 30 条消息没有拉取,消息服务会判断当前用户已经离线,然后踢出此人,并且同步给聊天室服务对此成员做下线处理。

7、海量聊天消息的分发策略

直播间聊天室服务的消息分发及拉取方案如下图:

7.1 消息通知的拉取

在上图中:用户 A 在聊天室中发送一条消息,首先由聊天室服务处理,聊天室服务将消息同步到各消息服务节点,消息服务向本节点缓存的所有成员下发通知拉取(图中服务器向用户 B 和用户 Z 下发了通知)。

在消息分发过程中,server 做了通知合并。

通知拉取的详细流程为:

  • 1)客户端成功加入聊天,将所有成员加入到待通知队列中(如已存在则更新通知消息时间);
  • 2)下发线程,轮训获取待通知队列;
  • 3)向队列中用户下发通知拉取。

通过这个流程可保障下发线程一轮只会向同一用户发送一个通知拉取(即多个消息会合并为一个通知拉取),有效提升了服务端性能且降低了客户端与服务端的网络消耗。

7.2 消息的拉取

用户的消息拉取流程如下图:

 

如上图所示,用户 B 收到通知后向服务端发送拉取消息请求,该请求最终将由消息节点 1 进行处理,消息节点 1 将根据客户端传递的最后一条消息时间戳,从消息队列中返回消息列表(参考下图 )。

客户端拉取消息示例:

用户端本地最大时间为 1585224100000,从 server 端可以拉取到比这个数大的两条消息。

7.3 消息控速

服务器应对海量消息时,需要做消息的控速处理。

这是因为:在直播间聊天室中,大量用户在同一时段发送的海量消息,一般情况下内容基本相同。如果将所有消息全部分发给客户端,客户端很可能出现卡顿、消息延迟等问题,严重影响用户体验。

所以服务器对消息的上下行都做了限速处理。

消息控速原理:

具体的限速控制策略如下:

  • 1)服务器上行限速控制(丢弃)策略:针对单个聊天室的消息上行的限速控制,我们默认为 200 条 / 秒,可根据业务需要调整。达到限速后发送的消息将在聊天室服务丢弃,不再向各消息服务节点同步;
  • 2)服务器下行限速(丢弃)策略:服务端的下行限速控制,主要是根据消息环形队列的长度进行控制,达到最大值后最“老”的消息将被淘汰丢弃。

每次下发通知拉取后服务端将该用户标记为拉取中,用户实际拉取消息后移除该标记。

如果产生新消息时用户有拉取中标记:

  • 1)距设置标记时间在 2 秒内,则不会下发通知(降低客户端压力,丢弃通知未丢弃消息);
  • 2)超过 2 秒则继续下发通知(连续多次通知未拉取则触发用户踢出策略,不在此赘述)。

因此:消息是否被丢弃取决于客户端拉取速度(受客户端性能、网络影响),客户端及时拉取消息则没有被丢弃的消息。

8、直播间聊天室的消息优先级

消息控速的核心是对消息的取舍,这就需要对消息做优先级划分。

划分逻辑大致如下:

  • 1)白名单消息:这类消息最为重要,级别最高,一般系统类通知或者管理类信息会设置为白名单消息;
  • 2)高优先级消息:仅次于白名单消息,没有特殊设置过的消息都为高优先级;
  • 3)低优先级消息:最低优先级的消息,这类消息大多是一些文字类消息。

具体如何划分,应该是可以开放出方便的接口进行设置的。

服务器对三种消息执行不同的限速策略,在高并发时,低优先级消息被丢弃的概率最大。

服务器将三种消息分别存储在三个消息桶中:客户端在拉取消息时按照白名单消息  高优先级消息  低优先级消息的顺序拉取。

9、客户端针对大量消息的接收和渲染优化

9.1 消息的接收优化

在消息同步机制方面,如果直播间聊天室每收到一条消息都直接下发到客户端,无疑会给客户端带来极大性能挑战。特别是在每秒几千或上万条消息的并发场景下,持续的消息处理会占用客户端有限的资源,影响用户其它方面的互动。

考虑到以上问题,为聊天室单独设计了通知拉取机制,由服务端进行一系列分频限速聚合等控制后,再通知客户端拉取。

具体分为以下几步:

  • 1)客户端成功加入聊天室;
  • 2)服务端下发通知拉取信令;
  • 3)客户端根据本地存储的消息最大时间戳,去服务端拉取消息。

这里需要注意的是:首次加入直播间聊天室时,本地并没有有效时间戳,此时会传 0 给服务拉取最近 50 条消息并存库。后续再次拉取时才会传递数据库里存储的消息的最大时间戳,进行差量拉取。

客户端拉取到消息后:会进行排重处理,然后将排重后的数据上抛业务层,以避免上层重复显示。

另外:直播间聊天室中的消息即时性较强,直播结束或用户退出聊天室后,之前拉取的消息大部分不需要再次查看,因此在用户退出聊天室时,会清除数据库中该聊天室的所有消息,以节约存储空间。

9.2 消息的渲染优化

在消息渲染方面,客户端也通过一系列优化保证在直播间聊天室大量消息刷屏的场景下仍有不俗的表现。

以Andriod端为例,具体的措施有:

  • 1)采用 MVVM 机制:将业务处理和 UI 刷新严格区分。每收到一条消息,都在 ViewModel 的子线程将所有业务处理好,并将页面刷新需要的数据准备完毕后,才通知页面刷新;
  • 2)降低主线程负担:精确使用 LiveData 的 setValue() 和 postValue() 方法:已经在主线程的事件通过  setValue() 方式通知 View 刷新,以避免过多的 postValue() 造成主线程负担过重;
  • 3)减少非必要刷新:比如在消息列表滑动时,并不需要将接收到的新消息刷新出来,仅进行提示即可;
  • 4)识别数据的更新:通过谷歌的数据对比工具 DiffUtil 识别数据是否有更新,仅更新有变更的部分数据;
  • 5)控制全局刷新次数:尽量通过局部刷新进行 UI 更新。

通过以上机制:从压测结果看,在中端手机上,直播间聊天室中每秒 400 条消息时,消息列表仍然表现流畅,没有卡顿。

10、针对传统聊天消息外的自定义属性优化

10.1 概述

在直播间聊天室场景中,除了传统的聊天消息收发以外,业务层经常需要有自己的一些业务属性,如在语音直播聊天室场景中的主播麦位信息、角色管理等,还有狼人杀等卡牌类游戏场景中记录用户的角色和牌局状态等。

相对于传统聊天消息,自定义属性有必达和时效的要求,比如麦位、角色等信息需要实时同步给聊天室的所有成员,然后客户端再根据自定义属性刷新本地的业务。

10.2 自定义属性的存储

自定义属性是以 key 和 value 的形式进行传递和存储的。自定义属性的操作行为主要有两种:即设置和删除。

服务器存储自定义属性也分两部分:

  • 1)全量的自定义属性集合;
  • 2)自定义属性集合变更记录。

自定义属性存储结构如下图所示:

针对这两份数据,应该提供两种查询接口,分别是查询全量数据和查询增量数据。这两种接口的组合应用可以极大提升聊天室服务的属性查询响应和自定义分发能力。

10.3 自定义属性的拉取

内存中的全量数据,主要给从未拉取过自定义属性的成员使用。刚进入聊天室的成员,直接拉取全量自定义属性数据然后展示即可。

对于已经拉取过全量数据的成员来说,若每次都拉取全量数据,客户端想获得本次的修改内容,就需要比对客户端的全量自定义属性与服务器端的全量自定义属性,无论比对行为放在哪一端,都会增加一定的计算压力。

所以:为了实现增量数据的同步,构建一份属性变更记录集合十分必要。这样:大部分成员在收到自定义属性有变更来拉取时,都可以获得增量数据。

属性变更记录采用的是一个有序的 map 集合:key 为变更时间戳,value 里存着变更的类型以及自定义属性内容,这个有序的 map 提供了这段时间内所有的自定义属性的动作。

自定义属性的分发逻辑与消息一致:均为通知拉取。即客户端在收到自定义属性变更拉取的通知后,带着自己本地最大自定义属性的时间戳来拉取。比如:如果客户端传的时间戳为 4,则会拉取到时间戳为 5 和时间戳为 6 的两条记录。客户端拉取到增量内容后在本地进行回放,然后对自己本地的自定义属性进行修改和渲染。

11、多人群聊参考资料

[1] IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?

[2] IM群聊消息如此复杂,如何保证不丢不重?

[3] 移动端IM中大规模群消息的推送如何保证效率、实时性?

[4] 现代IM系统中聊天消息的同步和存储方案探讨

[5] 关于IM即时通讯群聊消息的乱序问题讨论

[6] IM群聊消息的已读回执功能该怎么实现?

[7] IM群聊消息究竟是存1份(即扩散读)还是存多份(即扩散写)?

[8] 一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践

[9] IM群聊机制,除了循环去发消息还有什么方式?如何优化?

[10] 网易云信技术分享:IM中的万人群聊技术方案实践总结

[11] 阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处

[12] IM群聊消息的已读未读功能在存储空间方面的实现思路探讨

[13] 企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等

[14] 融云IM技术分享:万人群聊消息投递方案的思考和实践

本文已同步发布于:http://www.52im.net/thread-3835-1-1.html

posted @ 2022-02-23 12:50 Jack Jiang 阅读(238) | 评论 (0)编辑 收藏

本文由cxuan分享,原题“原来这才是 Socket”,有修订。

1、引言

本系列文章前面那些主要讲解的是计算机网络的理论基础,但对于即时通讯IM这方面的应用层开发者来说,跟计算机网络打道的其实是各种API接口。

本篇文章就来聊一下网络应用程序员最熟悉的Socket这个东西,抛开生涩的计算机网络理论,从应用层的角度来理解到底什么是Socket。

对于 Socket 的认识,本文将从以下几个方面着手介绍:

  • 1)Socket 是什么;
  • 2)Socket 是如何创建的;
  • 3)Socket 是如何连接的;
  • 4)Socket 是如何收发数据的;
  • 5)Socket 是如何断开连接的;
  • 6)Socket 套接字的删除等。

特别说明:本文中提到的“Socket”、“网络套接字”、“套接字”,如无特殊指明,指的都是同一个东西哦。

 

学习交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK 

本文已同步发布于:http://www.52im.net/thread-3821-1-1.html

2、Socket 是什么

一个数据包经由应用程序产生,进入到协议栈中进行各种报文头的包装,然后操作系统调用网卡驱动程序指挥硬件,把数据发送到对端主机。

整个过程的大体的图示如下:

我们大家知道,协议栈其实是位于操作系统中的一些协议的堆叠,这些协议包括 TCP、UDP、ARP、ICMP、IP等。

通常某个协议的设计都是为了解决特定问题的,比如:

  • 1)TCP 的设计就负责安全可靠的传输数据;
  • 2)UDP 设计就是报文小,传输效率高;
  • 3)ARP 的设计是能够通过 IP 地址查询物理(Mac)地址;
  • 4)ICMP 的设计目的是返回错误报文给主机;
  • 5)IP 设计的目的是为了实现大规模主机的互联互通。

应用程序比如浏览器、电子邮件、文件传输服务器等产生的数据,会通过传输层协议进行传输。而应用程序是不会和传输层直接建立联系的,而是有一个能够连接应用层和传输层之间的套件,这个套件就是 Socket

在上面这幅图中,应用程序包含 Socket 和解析器,解析器的作用就是向 DNS 服务器发起查询,查询目标 IP 地址(关于DNS请见《理论联系实际,全方位深入理解DNS)。

应用程序的下面:就是操作系统内部,操作系统内部包括协议栈,协议栈是一系列协议的堆叠。

操作系统下面:就是网卡驱动程序,网卡驱动程序负责控制网卡硬件,驱动程序驱动网卡硬件完成收发工作。

在操作系统内部有一块用于存放控制信息的存储空间,这块存储空间记录了用于控制通信的控制信息。其实这些控制信息就是 Socket 的实体,或者说存放控制信息的内存空间就是Socket的实体。

这里大家有可能不太清楚所以然,所以我用了一下 netstat 命令来给大伙看一下Socket是啥玩意。

我们在 Windows 的命令提示符中输入:

netstat-ano

# netstat 用于显示Socket内容 , -ano 是可选选项

# a 不仅显示正在通信的Socket,还显示包括尚未开始通信等状态的所有Socket

# n 显示 IP 地址和端口号

# o 显示Socket的程序 PID

我的计算机会出现下面结果:

如上图所示:

  • 1)每一行都相当于一个Socket;
  • 2)每一列也被称为一个元组。

所以,一个Socket就是五元组:

  • 1)协议;
  • 2)本地地址;
  • 3)外部地址;
  • 4)状态;
  • 5)PID。

PS:有的时候也被叫做四元组,四元组不包括协议。

我们来解读一下上图中的数据,比如图中的第一行:

1)它的协议就是 TCP,本地地址和远程地址都是 0.0.0.0这表示通信还没有开始,IP 地址暂时还未确定)。

2)而本地端口已知是 135,但是远程端口还未知,此时的状态是 LISTENING(LISTENING 表示应用程序已经打开,正在等待与远程主机建立连接。关于各种状态之间的转换,大家可以阅读《通俗易懂-深入理解TCP协议(上):理论基础)。

3)最后一个元组是 PID,即进程标识符,PID 就像我们的身份证号码,能够精确定位唯一的进程。

3、Socket 是如何创建的

通过上节的讲解,现在你可能对 Socket 有了一个基本的认识,先喝口水,休息一下,让我们继续探究 Socket。

现在我有个问题,Socket 是如何创建的呢?

Socket 是和应用程序一起创建的。

应用程序中有一个 socket 组件,在应用程序启动时,会调用 socket 申请创建Socket,协议栈会根据应用程序的申请创建Socket:首先分配一个Socket所需的内存空间,这一步相当于是为控制信息准备一个容器,但只有容器并没有实际作用,所以你还需要向容器中放入控制信息;如果你不申请创建Socket所需要的内存空间,你创建的控制信息也没有地方存放,所以分配内存空间,放入控制信息缺一不可。至此Socket的创建就已经完成了。

Socket创建完成后,会返回一个Socket描述符给应用程序,这个描述符相当于是区分不同Socket的号码牌。根据这个描述符,应用程序在委托协议栈收发数据时就需要提供这个描述符。

4、Socket 是如何连接的

Socket创建完成后,最终还是为数据收发服务的。但是,在数据收发之前,还需要进行一步“连接”(术语就是 connect),建立连接有一整套过程。

这个“连接”并不是真实的连接(用一根水管插在两个电脑之间?不是你想的这样。。。)。

实际上这个“连接”是应用程序通过 TCP/IP 协议标准从一个主机通过网络介质传输到另一个主机的过程。

Socket刚刚创建完成后,还没有数据,也不知道通信对象。

在这种状态下:即使你让客户端应用程序委托协议栈发送数据,它也不知道发送到哪里。所以浏览器需要根据网址来查询服务器的 IP 地址(做这项工作的协议是 DNS),查询到目标主机后,再把目标主机的 IP 告诉协议栈。至此,客户端这边就准备好了。

在服务器上:与客户端一样也需要创建Socket,但是同样的它也不知道通信对象是谁,所以我们需要让客户端向服务器告知客户端的必要信息:IP 地址和端口号

现在通信双方建立连接的必要信息已经具备,可以开始“连接”过程了。

首先:客户端应用程序需要调用 Socket 库中的 connect 方法,提供 socket 描述符和服务器 IP 地址、端口号。

以下是connect的伪码调用:

connect(<描述符>、<服务器IP地址和端口号>)

这些信息会传递给协议栈中的 TCP 模块,TCP 模块会对请求报文进行封装,再传递给 IP 模块,进行 IP 报文头的封装,然后传递给物理层,进行帧头封装。

之后通过网络介质传递给服务器,服务器上会对帧头、IP 模块、TCP 模块的报文头进行解析,从而找到对应的Socket。

Socket收到请求后,会写入相应的信息,并且把状态改为正在连接。

请求过程完成后:服务器的 TCP 模块会返回响应,这个过程和客户端是一样的(如果大家不太清楚报文头的封装过程,可以阅读《快速理解TCP协议一篇就够)。

在一个完整的请求和响应过程中,控制信息起到非常关键的作用:

  • 1)SYN 就是同步的缩写,客户端会首先发送 SYN 数据包,请求服务端建立连接;
  • 2)ACK 就是相应的意思,它是对发送 SYN 数据包的响应;
  • 3)FIN 是终止的意思,它表示客户端/服务器想要终止连接。

由于网络环境的复杂多变,经常会存在数据包丢失的情况,所以双方通信时需要相互确认对方的数据包是否已经到达,而判断的标准就是 ACK 的值。

上面的文字不够生动,动画可以更好的说明这个过程:

PS:这个“连接”的详细理论知识,可以阅读《理论经典:TCP协议的3次握手与4次挥手过程详解》、《跟着动画来学TCP三次握手和四次挥手》,这里不再赘述。

当所有建立连接的报文都能够正常收发之后,此时套接字就已经进入可收发状态了,此时可以认为用一根管理把两个套接字连接了起来。当然,实际上并不存在这个管子。建立连接之后,协议栈的连接操作就结束了,也就是说 connect 已经执行完毕,控制流程被交回给应用程序。

另外:如果你对Socket代码更熟悉的话,可以先读读这篇《手把手教你写基于TCP的Socket长连接》。

5、Socket 是如何收发数据的

当控制流程上节中的连接过程回到应用程序之后,接下来就会直接进入数据收发阶段。

数据收发操作是从应用程序调用 write 将要发送的数据交给协议栈开始的,协议栈收到数据之后执行发送操作。

协议栈不会关心应用程序传输过来的是什么数据,因为这些数据最终都会转换为二进制序列,协议栈在收到数据之后并不会马上把数据发送出去,而是会将数据放在发送缓冲区,再等待应用程序发送下一条数据。

为什么收到数据包不会直接发送出去,而是放在缓冲区中呢?

因为只要一旦收到数据就会发送,就有可能发送大量的小数据包,导致网络效率下降(所以协议栈需要将数据积攒到一定数量才能将其发送出去)。

至于协议栈会向缓冲区放多少数据,这个不同版本和种类的操作系统有不同的说法。

不过,所有的操作系统都会遵循下面这几个标准:

1)第一个判断要素:是每个网络包能够容纳的数据长度,判断的标准是 MTU,它表示的是一个网络包的最大长度。最大长度包含头部,所以如果单论数据区的话,就会用 MTU - 包头长度,由此的出来的最大数据长度被称为 MSS。

 

2)另一个判断标准:是时间,当应用程序产生的数据比较少,协议栈向缓冲区放置数据效率不高时,如果每次都等到 MSS 再发送的话,可能因为等待时间太长造成延迟。在这种情况下,即使数据长度没有到达 MSS,也应该把数据发送出去。

但协议栈并没有告诉我们怎样平衡这两个因素,如果数据长度优先,那么效率有可能比较低;如果时间优先,那又会降低网络的效率。

经过了一段时间。。。。。。

假设我们使用的是长度有限法则:此时缓冲区已满,协议栈要发送数据了,协议栈刚要把数据发送出去,却发现无法一次性传输这么大数据量(相对的)的数据,那怎么办呢?

在这种情况下,发送缓冲区中的数据就会超过 MSS 的长度,发送缓冲区中的数据会以 MSS 大小为一个数据包进行拆分,拆分出来的每块数据都会加上 TCP,IP,以太网头部,然后被放进单独的网络包中。

到现在,网络包已经准备好发往服务器了,但是数据发送操作还没有结束,因为服务器还未确认是否已经收到网络包。因此在客户端发送数据包之后,还需要服务器进行确认。

TCP 模块在拆分数据时,会计算出网络包偏移量,这个偏移量就是相对于数据从头开始计算的第几个字节,并将算好的字节数写在 TCP 头部,TCP 模块还会生成一个网络包的序号(SYN),这个序号是唯一的,这个序号就是用来让服务器进行确认的。

服务器会对客户端发送过来的数据包进行确认,确认无误之后,服务器会生成一个序号和确认号(ACK)并一起发送给客户端,客户端确认之后再发送确认号给服务器。

我们来看一下实际的工作过程:

首先:客户端在连接时需要计算出序号初始值,并将这个值发送给服务器。

接下来:服务器通过这个初始值计算出确认号并返回给客户端(初始值在通信过程中有可能会丢弃,因此当服务器收到初始值后需要返回确认号用于确认)。

同时:服务器也需要计算出从服务器到客户端方向的序号初始值,并将这个值发送给客户端。然后,客户端也需要根据服务器发来的初始值计算出确认号发送给服务器。

至此:连接建立完成,接下来就可以进入数据收发阶段了。

数据收发阶段中,通信双方可以同时发送请求和响应,双方也可以同时对请求进行确认。

请求 - 确认机制非常强大:通过这一机制,我们可以确认接收方有没有收到某个包,如果没有收到则重新发送,这样一来,但凡网络中出现的任何错误,我们都可以即使发现并补救。

上面的文字不够生动,动画可以更好的理解请求 - 确认机制:

网卡、集线器、路由器(见《史上最通俗的集线器、交换机、路由器功能原理入门)都没有错误补救机制,一旦检测到错误就会直接丢弃数据包,应用程序也没有这种机制,起作用的只是 TCP/IP 模块。

由于网络环境复杂多变,所以数据包会存在丢失情况,因此发送序号和确认号也存在一定规则,TCP 会通过窗口管理确认号,我们这篇文章不再赘述,大家可以阅读《通俗易懂-深入理解TCP协议(下):RTT、滑动窗口、拥塞处理》来寻找答案。

PS:另一篇《我们在读写Socket时,究竟在读写什么?》中用动画详细说明了这个过程,有兴趣可以读一读。

6、Socket 是如何断开连接的

当通信双方不再需要收发数据时,需要断开连接。不同的应用程序断开连接的时机不同。

以 Web 为例:浏览器向 Web 服务器发送请求消息,Web 服务器再返回响应消息,这时收发数据就全部结束了,服务器可能会首先发起断开响应,当然客户端也有可能会首先发起(谁先断开连接是应用程序做出的判断),与协议栈无关。

无论哪一方发起断开连接的请求,都会调用 Socket 库的 close 程序。

我们以服务器断开连接为例:服务器发起断开连接请求,协议栈会生成断开连接的 TCP 头部,其实就是设置 FIN 位,然后委托 IP 模块向客户端发送数据,与此同时,服务器的Socket会记录下断开连接的相关信息。

收到服务器发来 FIN 请求后:客户端协议栈会将Socket标记为断开连接状态,然后,客户端会向服务器返回一个确认号,这是断开连接的第一步,在这一步之后,应用程序还会调用 read 来读取数据。等到服务器数据发送完成后,协议栈会通知客户端应用程序数据已经接收完毕。

只要收到服务器返回的所有数据,客户端就会调用 close 程序来结束收发操作,这时客户端会生成一个 FIN 发送给服务器,一段时间后服务器返回 ACK 号。至此,客户端和服务器的通信就结束了。

上面的文字不够生动,动画可以更好的说明这个过程:

PS:断开连接的详细理论知识,可以阅读《理论经典:TCP协议的3次握手与4次挥手过程详解》、《跟着动画来学TCP三次握手和四次挥手》,这里不再赘述。

7、Socket的删除

上述通信过程完成后,用来通信的Socket就不再会使用了,此时我们就可以删除这个Socket了。

不过,这时候Socket不会马上删除,而是等过一段时间再删除。

等待这段时间是为了防止误操作,最常见的误操作就是客户端返回的确认号丢失,至于等待多长时间,和数据包重传的方式有关,这里我们就深入展开讨论了。

关于Socket操作的全过程,如果从系统的角度来看,可能会更深入一些,建议可以深入阅读张彦飞的《深入操作系统,从内核理解网络包的接收过程(Linux篇)》一文。

8、系列文章

本文是系列文章中的第14篇,本系列文章的大纲如下:

[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?一文即懂!* 本文)

9、参考资料

[1] TCP/IP详解 - 第17章·TCP:传输控制协议

[2] TCP/IP详解 - 第18章·TCP连接的建立与终止

[3] TCP/IP详解 - 第21章·TCP的超时与重传

[4] 快速理解网络通信协议(上篇)

[5] 快速理解网络通信协议(下篇)

[6] 面视必备,史上最通俗计算机网络分层详解

[7] 假如你来设计网络,会怎么做?

[8] 假如你来设计TCP协议,会怎么做?

[10] 浅析TCP协议中的疑难杂症(下篇)

[11] 关闭TCP连接时为什么会TIME_WAIT、CLOSE_WAIT

[12] 从底层入手,深度分析TCP连接耗时的秘密

本文已同步发布于:http://www.52im.net/thread-3821-1-1.html

posted @ 2022-02-16 12:17 Jack Jiang 阅读(247) | 评论 (0)编辑 收藏

本文原题“搭建高性能的IM系统”,作者“刘莅”,内容有修订和改动。为了尊重原创,如需转载,请联系作者获得授权。

1、引言

相信很多朋友对微信、QQ等聊天软件的实现原理都非常感兴趣,笔者同样对这些软件有着深厚的兴趣。而且笔者在公司也是做IM的,公司的IM每天承载着上亿条消息的发送!

正好有这样的技术资源和条件,所以前段时间,笔者利用业余时间,基于Netty开发了一套基本功能比较完善的IM系统。该系统支持私聊、群聊、会话管理、心跳检测,支持服务注册、负载均衡,支持任意节点水平扩容。

这段时间,网上的一些读者,也希望笔者分享一些Netty或者IM相关的知识,所以今天笔者把开发的这套IM系统分享给大家。

本文将根据笔者这次的业余技术实践,为你讲述如何基于Netty+Zk+Redis来搭建一套高性能IM集群,包括本次实现IM集群的技术原理和实例代码,希望能带给你启发。

学习交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK 

本文已同步发布于:http://www.52im.net/thread-3816-1-1.html )

2、本文源码

主地址:https://github.com/nicoliuli/chat

备地址:https://github.com/52im/chat

源码的目录结构,如下图所示:

3、知识准备

* 重要提示:本文不是一篇即时通讯理论文章,文章内容来自代码实战,如果你对即时通讯(IM)技术理论了解的太少,建议先详细阅读:《新手入门一篇就够:从零开发移动端IM》。

可能有人不知道 Netty 是什么,这里简单介绍下:

Netty 是一个 Java 开源框架。Netty 提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。

也就是说,Netty 是一个基于 NIO 的客户、服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用。

Netty 相当简化和流线化了网络应用的编程开发过程,例如,TCP 和 UDP 的 Socket 服务开发。

以下是有关Netty的入门文章:

如果你连Java的NIO都不知道是什么,下面的文章建议优先读:

Netty源码和API的在线查阅地址:

4、系统架构

系统的架构如上图所示:整个系统是一个C/S系统,客户端没有做复杂的图形化界面而是用Java终端开发的(黑窗口),服务端IM实例是Netty写的socket服务。

ZK作为服务注册中心,Redis用来做分布式会话的缓存,并保存用户信息和轻量级的消息队列。

对于整个系统架构中各部分的工作原理,我们将在接下来的各章节中一一介绍。

5、服务端的工作原理

在上述架构中:NettyServer启动,每启动一台Server节点,都会把自身的节点信息,如:ip、port等信息注册到ZK上(临时节点)。

正如上节架构图上启动了两台NettyServer,所以ZK上会保存两个Server的信息。

同时ZK将监听每台Server节点,如果Server宕机ZK就会删除当前机器所注册的信息(把临时节点删除),这样就完成了简单的服务注册的功能。

6、客户端的工作原理

Client启动时,会先从ZK上随机选择一个可用的NettyServer(随机表示可以实现负载均衡),拿到NettyServer的信息(IP和port)后与NettyServer建立链接。

链接建立起来后,NettyServer端会生成一个Session(即会话),用来把当前客户端的Channel等信息组装成一个Session对象,保存在一个SessionMap里,同时也会把这个Session保存在Redis中。

这个会话特别重要,通过会话,我们能获取当前Client和NettyServer的Channel等信息。

7、Session的作用

我们启动多个Client,由于每个Client启动,都会先从ZK上随机获取NettyServer的的信息,所以如果启动多个Client,就会连接到不同的NettyServer上。

熟悉Netty的朋友都知道,Client与Server建立接连后会产生一个Channel,通过Channel,Client和Server才能进行正常的网络数据传输。

如果Client1和Client2连接在同一个Server上:那么Server通过SessionMap分别拿到Client1和Client2的会话,会话中包含Channel信息,有了两个Client的Channel,Client1和Client2便可完成消息通信。

如果Client1和Client2连接到不同的NettyServer上:Client1和Client2要进行通信,该怎么办?这个问题放在后面解答。

8、高效的数据传输

无论是IM系统,还是分布式的RPC框架,高效的网络数据传输,无疑会极大的提升系统的性能。

数据通过网络传输时,一般把对象通序列化成二进制字节流数组,然后将数据通过socket传给对方服务器,对方服务器拿到二进制字节流后再反序列化成对象,达到远程通信的目的。

在Java领域,Java序列化对象的方式有严重的性能问题,业界常用谷歌的protobuf来实现序列化反序列化(见《Protobuf通信协议详解:代码演示、详细原理介绍等)。

protobuf支持不同的编程语言,可以实现跨语言的系统调用,并且有着极高的序列化反序列化性能,本系统也采用protobuf来做数据的序列化。

关于Protobuf的基本认之,下面这几篇可以深入读一读:

  1. 强列建议将Protobuf作为你的即时通讯应用数据传输格式
  2. 全方位评测:Protobuf性能到底有没有比JSON快5倍?
  3. 金蝶随手记团队分享:还在用JSON? Protobuf让数据传输更省更快(原理篇)

另外:一套海量在线用户的移动端IM架构设计实践分享(含详细图文)》一文中,“3、协议设计”这一节有关于protobuf在IM中的实战设计和使用,可以一并学习一下。

9、聊天协议定义

我们在使用各种聊天APP时,会发各种各样的消息,每种消息都会对应不同的消息格式(即“聊天协议”)。

聊天协议中主要包含几种重要的信息:

  • 1)消息类型;
  • 2)发送时间;
  • 3)消息的收发人;
  • 4)聊天类型(群聊或私聊)。

我的这套IM系统中,聊天协议定义如下:

syntax = "proto3";

option java_package = "model.chat";

option java_outer_classname = "RpcMsg";

message Msg{

    string msg_id = 1;

    int64 from_uid = 2;

    int64 to_uid = 3;

    int32 format = 4;

    int32 msg_type = 5;

    int32 chat_type = 6;

    int64 timestamp = 7;

    string body = 8;

    repeated int64 to_uid_list = 9;

}

如上面的protobuf代码,字段的具体含义如下:

  • 1)msg_id:表示消息的唯一id,可以用UUID表示;
  • 2)from_uid:消息发送者的uid;
  • 3)to_uid:消息接收者的uid;
  • 4)format:消息格式,我们使用各种聊天软件时,会发送文字消息,语音消息,图片消息等等等等,每种消息有不同的消息格式,我们用format来表示(由于本系统是java终端,format字段没有太大含义,可有可无);
  • 5)msg_type:消息类型,比如登录消息、聊天消息、ack消息、ping、pong消息;
  • 6)chat_type:聊天类型,如群聊、私聊;
  • 7)timestamp:发送消息的时间戳;
  • 8)body:消息的具体内容,载体;
  • 9)to_uid_list:这个字段用户群聊消息提高群聊消息的性能,具体作用会在群聊原理部分详细解释。

10、私聊消息发送原理

Client1给Client2发消息时,我们需要构建上节中的消息体。

具体就是:from_uid是Client1的uid、to_uid是Client2的uid。

NettyServer收到消息后的处理逻辑是:

  • 1)解析到to_uid字段;
  • 2)从SessionMap或者Redis中保存的Session集合中获取to_uid即Client2的Session;
  • 3)从Session中取出Client2的Channel;
  • 4)然后将消息通过Client2的Channel发给Client2。

11、群聊消息发送原理

群聊消息的分发通常有两种技术实现方式,我们一一来看看。

方式一:假设一个群有100人,如果Client1给一个群的所有人发消息,其实相当于Client1分别给其余99人分别发一条消息。我们可以直接在Client端,通过循环,分别给群里的99人发消息即可,相当于Client发送给NettyServer发送了99次相同的消息(除了to_uid不同)。

上述方案有很严重的性能问题:Client1通过循环99次,分别把消息发给NettyServer,NettyServer收到这99条消息后,分别将消息发给群内其余的用户。先抛开移动端的特殊性(比如循环还没完成手机就有可能退到后台被系统挂起),显然Client1到NettyServer的99次循环存在明显不合理地方。

方式二:上节的消息体中to_uid_list字段就是为了解决这个方式一的性能问题的。Client1把群内其余99个Client的uid保存在to_uid_list中,然后NettyServer只发一条消息,NettyServer收到这一条消息后,通过to_uid_list字段解析群内其余99的Client的uid,再通过循环把消息分别发送给群内其余的Client。

可以看到:方式二的群聊时,Client1与NettyServer只进行1次消息传输,相比于方式一,效率提高了50%。

11、技术关键点1:客户端分别连接在不同IM实例时如何通信?

针对本文中的架构,如果多个Client分别连接在不同的Server上,Client之间应该如何通信呢?

为了回答这个问题,我们首先要明白Session的作用。

我们做过JavaWeb开发的朋友都知道,Session用来保存用户的登录信息。

在IM系统中也是如此:Session中保存用户的Channel信息。当Client与Server建立链接成功后,会产生一个Channel,Client和Server是通过Channel,实现数据传输。当两端链接建立起来后,Server会构建出一个Session对象,保存uid和Channel等信息,并把这个Session保存在一个SessionMap里(NettyServer的内存里),uid为key,我们可以通过uid就可以找到这个uid对应的Session。

但只有SessionMap还不够:我们需要利用Redis,它的作用是保存整个NettyServer集群全部链接成功的用户,这也是一种Session,但这种Session没有保存uid和Channel的对应关系,而是保存Client链接到NettyServer的信息,如Client链接到的这个NettyServer的ip、port等。通过uid,我们同样可以从Redis中拿到当前Client链接到的NettyServer的信息。正是有了这个信息,我们才能做到,NettyServer集群任意节点水平扩容。

当用户量少的时候:我们只需要一台NettyServer节点便可以扛住流量,所有的Client链接到同一个NettyServer上,并在NettyServer的SessionMap中保存每个Client的会话。Client1与Client2通信时,Client1把消息发给NettyServer,NettyServer从SessionMap中取出Client2的Session和Channel,将消息发给Client2。

随着用户量不断增多:一台NettyServer不够,我们增加了几台NettyServer,这时Client1链接到NettyServer1上并在SessionMap和Redis中保存了会话和Client1的链接信息,Client2链接到NettyServer2上并在SessionMap和Redis中保存了会话和Client2的链接信息。Client1给Client2发消息时,通过NettyServer1的SessionMap找不到Client2的会话,消息无法发送,于是便从Redis中获取Client2链接在哪台NettyServer上。获取到Client2所链接的NettyServer信息后,我们可以把消息转发给NettyServer2,NettyServer2收到消息后,从NettyServer2的SessionMap中获取Client2的Session和Channel,然后将消息发送给Client2。

那么:NettyServer1的消息如何转发给NettyServer2呢?答案是通过消息队列,如Redis中的list数据结构。每台NettyServer启动后都需要监听一个自己的Redis中的消息队列,这个队列用户接收其他NettyServer转发给当前NettyServer的消息。

* Jack Jiang点评:上述集群方案中,Redis既作为在线用户列表存储中心,又作为集群中不同IM长连接实例的消息中转服务(此时的Redis作用相当于MQ),那Redis不就成为了整个分布式集群的单点瓶颈了吗?

12、技术关键点2:链接断开,如何处理?

如果Client与NettyServer,由于某种原因(客户端退出、服务端重启、网络因素等)断开链接,我们必须要从SessionMap删除会话和Redis中保留的数据。

如果不清除这两类数据的话,很有可能Client1发送给Client2的消息,可能会发给其他用户,或者就算Client2处于登录状态,Client2也收到不到消息。

我们可以在Netty框架中的channelInactive方法里,处理链接断开后的会话清除操作。

13、技术关键点3:ping、pong的作用

当Client与NettyServer建立链接后,由于双端网络较差,Client与NettyServer断开链接后,如果NettyServer没有感知到,也就没有清除SessionMap和Redis中的数据,这将会造成严重的问题(对于服务端来说,这个Client的会话实际处于“假死”状态,消息是无法实时发送过去的)。

此时就需要一种ping/pong机制(也就是心跳机制啦)。

实现原理就是:通过定时任务,Client每隔一段时间给NettyServer发一个ping消息,NettyServer收到ping消息后给客户端回复一个pong消息,确保客户端和服务端能一直保持链接状态。如果Client与NettyServer断连了,NettyServer可以立即发现并清空会话数据。Netty中的我们可以在Pipeline中添加IdleStateHandler,可达到这样的目的。

如果你不明白心跳的作用,务必读以下文章:

  1. 为何基于TCP协议的移动端IM仍然需要心跳保活机制?
  2. 一文读懂即时通讯应用中的网络心跳包机制:作用、原理、实现思路等

也可以学习一下主流IM的心跳逻辑:

  1. 微信团队原创分享:Android版微信后台保活实战分享(进程保活篇)
  2. 微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)
  3. 移动端IM实践:实现Android版微信的智能心跳机制
  4. 移动端IM实践:WhatsApp、Line、微信的心跳策略分析

如果觉得理论不够直观,下面的代码实例可以直观地进行学习:

  1. 正确理解IM长连接的心跳及重连机制,并动手实现(有完整IM源码)
  2. 一种Android端IM智能心跳算法的设计与实现探讨(含样例代码)
  3. 自已开发IM有那么难吗?手把手教你自撸一个Andriod版简易IM (有源码)
  4. 手把手教你用Netty实现网络通信程序的心跳机制、断线重连机制

其实,心跳算法的实际效果,还是有一些逻辑技巧的,以下两篇建议必读:

  1. Web端即时通讯实践干货:如何让你的WebSocket断网重连更快速?
  2. 融云技术分享:融云安卓端IM产品的网络链路保活技术实践

14、技术关键点4:为Server和Client添加Hook

如果NettyServer重启了或者进程被kill掉,我们需要清除当前节点的SessionMap(其实不用清理SessionMap,数据在内存里重启会自动删除的)和Redis保存的Client的链接信息。

我们需要遍历SessionMap找出所有的uid,然后一一清除Redis的数据,然后优雅退出。此时,我们就需要为我们的NettyServer添加一个Hook,来做数据清理。

15、技术关键点5:对方不在线该如何处理消息?

Client1给对方发消息,我们通过SessionMap或Redis拿不到对方的会话数据,这就表明对方不在线。

此时:我们需要把消息存储在离线消息表中,当对方下次登录时,NettyServer查离线消息表,把消息发给登录用户(最好是批量发送,提高性能)。

IM中的离线消息处理,也不是个简单的技术点,有兴趣可以深入学习一下:

  1. IM消息送达保证机制实现(二):保证离线消息的可靠投递
  2. 阿里IM技术分享(六):闲鱼亿级IM消息系统的离线推送到达率优化
  3. IM开发干货分享:我是如何解决大量离线消息导致客户端卡顿的
  4. IM开发干货分享:如何优雅的实现大量离线消息的可靠投递
  5. 喜马拉雅亿级用户量的离线消息推送系统架构设计实践

16、写在最后

代码写成这样,也算是了确了自已手撸IM的心愿。唯一遗憾的是,时间比较紧张,还没来得及实现消息ack机制,保证消息一定会送达,这个笔者以后会补充上去的。

好了,这就是我开发的这个简易的聊天系统,麻雀虽小,五脏俱全,大家有什么不明白的地方,可以直接在下方留言,笔者会一一回复的,谢谢大家。

17、系列文章

18、参考资料

[1] 新手入门:目前为止最透彻的的Netty高性能原理和框架架构解析

[2] 写给初学者:Java高性能NIO框架Netty的学习方法和进阶策略

[3] 史上最强Java NIO入门:担心从入门到放弃的,请读这篇!

[4] Java的BIO和NIO很难懂?用代码实践给你看,再不懂我转行!

[5] 史上最通俗Netty框架入门长文:基本介绍、环境搭建、动手实战

[6] 理论联系实际:一套典型的IM通信协议设计详解

[7] 浅谈IM系统的架构设计

[8] 简述移动端IM开发的那些坑:架构设计、通信协议和客户端

[9] 一套海量在线用户的移动端IM架构设计实践分享(含详细图文)

[10] 一套原创分布式即时通讯(IM)系统理论架构方案

[11]  一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践

[12] 一套亿级用户的IM架构技术干货(上篇):整体架构、服务拆分等

[13] 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

[14] 从新手到专家:如何设计一套亿级消息量的分布式IM系统

[15] 基于实践:一套百万消息量小规模IM系统技术要点总结

本文已同步发布于:http://www.52im.net/thread-3816-1-1.html )

posted @ 2022-01-18 16:45 Jack Jiang 阅读(239) | 评论 (0)编辑 收藏

关于RainbowChat-Web

► RainbowChat-Web详细介绍:http://www.52im.net/thread-2483-1-1.html
► 历史版本更新记录:http://www.52im.net/thread-2480-1-1.html

RainbowChat-Web是一套基于MobileIMSDK-Web的网页端IM系统。

▲ 主界面更多截图点此进入更多演示视频点此进入

▲ 主界面(聊天窗全屏时)更多截图点此进入更多演示视频点此进入

v4.0 版更新内容

此版更新内容:

  • 1)[前端] [新增增加了消息“撤回”功能,体验与微信保持一致(支持3种聊天模式,包含完整的前后端处理逻辑);
  • 2)[前端] [新增增加了删除聊天消息功能
  • 3)[前端] [新增增加了设置好友备注(及附属字段)的功能;
  • 4)[前端/服务端] [优化] 升级MobileIMSDK-Web库至v5.0版(支持完整消息送达保证机制);
  • 5)[前端] [优化] 将原UI各模块代码按js文件分拆,使得代码更易理解和阅读;
  • 6)[前端] [优化] 增强了表情功能,且可与APP产品互通;

增强版的表情功能效果截图:


消息“撤回”功能效果截图:

 

消息气泡右键功能效果截图:

设置好友备注功能效果截图:

posted @ 2022-01-15 22:54 Jack Jiang 阅读(76) | 评论 (0)编辑 收藏

     摘要: 本文由ELab技术团队分享,原题“浅谈WebRTC技术原理与应用”,有修订和改动。1、基本介绍WebRTC(全称 Web Real-Time Communication),即网页即时通信。 是一个支持网页浏览器进行实时语音对话或视频对话的技术方案。从前端技术开发的视角来看,是一组可调用的API标准。 在WebRTC发布之前,开发实时音视频交互应用的成本是非常昂贵,...  阅读全文

posted @ 2022-01-10 16:19 Jack Jiang 阅读(199) | 评论 (0)编辑 收藏

本文由融云技术团队原创分享,原题“聊天室海量消息分发之消息丢弃策略”,内容有修订。

1、引言

随着直播类应用的普及,尤其直播带货概念的风靡,大用户量的直播间场景已然常态化。

大用户量直播间中的实时互动是非常频繁的,具体体现在技术上就是各种用户聊天、弹幕、礼物、点赞、禁言、系统通知等实时消息(就像下图这样)。

▲ 某电商APP的卖货直播间

如此大量的实时消息,在分发时如何处理才能不至于把服务端搞垮,而到了客户端时也不至于让APP出现疯狂刷屏和卡顿(不至于影响用户体验),这显然需要特殊的技术手段和实现策略才能应对。

其实,直播间中的实时消息分发,在技术上是跟传统的在线聊天室这种概念是一样的,只是传统互联网时代,聊天室同时在线的用户量不会这么大而已,虽然量级不同,但技术模型是完全可以套用的。

本文将基于直播技术实践的背景,分享了单直播间百万用户在线量的实时消息分发的技术经验总结,希望带给你启发。

学习交流:

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK 

本文已同步发布于:http://www.52im.net/thread-3799-1-1.html

2、系列文章

本文是系列文章中的第6篇:

3、技术挑战

我们以一个百万人观看的直播间为例进行分析,看看需要面临哪些技术挑战。

1)在直播中会有一波一波的消息高峰,比如直播中的“刷屏”消息,即大量用户在同一时段发送的海量实时消息,一般情况下此类“刷屏”消息的消息内容基本相同。如果将所有消息全部展示在客户端,则客户端很可能出现卡顿、消息延迟等问题,严重影响用户体验。

2)海量消息的情况下,如果服务端每条消息都长期存储将导致服务缓存使用量激增,使得内存、存储成为性能瓶颈。

3)在另外一些场景下,比如直播间的房间管理员进行操作后的通知消息或者系统通知,一般情况下这类消息是较为重要的,如何优先保障它的到达率。

基于这些挑战,我们的服务需要做一个基于业务场景的优化来应对。

4、架构模型

我们的架构模型图如下:

 

如上图所示,下面将针对主要服务进行简要说明。

1)直播间服务:

主要作用是:缓存直播间的基本信息。包括用户列表、禁言/封禁关系、白名单用户等。

2)消息服务:

主要作用是:缓存本节点需要处理的用户关系信息、消息队列信息等。

具体说是以下两个主要事情。

直播间用户关系同步:

  • a)成员主动加入退出时:直播间服务同步至==> 消息服务;
  • b)分发消息发现用户已离线时:消息服务同步至==> 直播间服务。

发送消息:   

  • a)直播间服务经过必要校验通过后将消息广播至消息服务;
  • b)直播间服务不缓存消息内容。

3)Zk(就是 Zookeeper 啦):

主要作用就是:将各服务实例均注册到 Zk,数据用于服务间流转时的落点计算。

具体就是:

  • a)直播间服务:按照直播间 ID 落点;
  • b)消息服务:按照用户 ID 落点。

4)Redis:

主要作为二级缓存,以及服务更新(重启)时内存数据的备份。

5、消息分发总体方案

直播间服务的消息分发完整逻辑主要包括:消息分发流程和消息拉取流程。

5.1 消息分发流程

如上图所示,我们的消息分发流程主要是以下几步:

  • 1)用户 A 在直播间中发送一条消息,首先由直播间服务处理;
  • 2)直播间服务将消息同步到各消息服务节点;
  • 3)消息服务向本节点缓存的所有成员下发通知拉取;
  • 4)如上图中的“消息服务-1”,将向用户 B 下发通知。

另外,因为消息量过大,我们在在分发的过程中,是具有通知合并机制的,通知合并机制主要提现在上述步骤 3 中。

上述步骤3的通知合并机制原理如下:

  • a)将所有成员加入到待通知队列中(如已存在则更新通知消息时间);
  • b)下发线程,轮训获取待通知队列;
  • c)向队列中用户下发通知拉取。

通过通知合并机制,我们可以可保障下发线程一轮只会向同一用户发送一个通知拉取,即多个消息会合并为一个通知拉取,从面有效提升了服务端性能且降低了客户端与服务端的网络消耗。

PS:以上通知合并机制,在大消息量的情况下,非常适合使用Actor分布式算法来实现,有兴趣的同学可以进一步学习《分布式高并发下Actor模型如此优秀》、《分布式计算技术之Actor计算模式》。

5.2 消息拉取流程

 

如上图所示,我们的消息拉取流程主要是以下几步:

  • 1)用户 B 收到通知后将向服务端发送拉取消息请求;
  • 2)该请求将由“消息服务-1”节点处理;
  • 3)“消息服务-1”将根据客户端传递的最后一条消息时间戳,从消息队列中返回消息列表(原理详见下图 ▼);
  • 4)用户 B 获取到新的消息。

上述步骤 3 中拉取消息的具体逻辑如下图所示:

6、消息分发的丢弃策略

对于直播间中的用户来说,很多消息其实并没有太多实际意义,比如大量重复的刷屏消息和动态通知等等,为了提升用户体验,这类消息是可以有策略地进行丢弃的(这是跟IM中的实时聊天消息最大的不同,IM中是不允许丢消息的)。

PS:直播间中消息分发的丢弃策略,跟上节中的通知合并机制一起,使得直接间海量消息的稳定、流畅分发得以成为可能。

我们的丢弃策略主要由以下3部分组成:

  • 1)上行限速控制(丢弃)策略;
  • 2)下行限速控制(丢弃)策略;
  • 3)重要消息防丢弃策略。

如下图所示:

我们来逐个解释一下。

1)上行限速控制(丢弃)策略:

针对上行的限速控制,我们默认是 200 条/秒,根据业务需要可调整。达到限速后发送的消息将在直播间服务丢弃,不再向各消息服务节点同步。

2)下行限速控制(丢弃)策略:

针对下行的限速控制,即对消息环形队列(见“5.2 消息拉取流程”中的拉取消息详细逻辑图)长度的控制,达到最大值后最“老”的消息将被淘汰丢弃。

每次下发通知拉取后服务端将该用户标记为“拉取中”,用户实际拉取消息后移除该标记。

拉取中标记的作用:例如产生新消息时用户具有拉取中标记,如果距设置标记时间在 2 秒内则不会下发通知(降低客户端压力,丢弃通知未丢弃消息),超过 2 秒则继续下发通知(连续多次通知未拉取则触发用户踢出策略,不在此赘述)。

因此消息是否被丢弃取决于客户端拉取速度(受客户端性能、网络影响),客户端及时拉取消息则没有被丢弃的消息。

3)重要消息防丢弃策略:

如前文所述:在直播间场景下对某些消息应具有较高优先级,不应丢弃。

例如:直播间的房间管理员进行操作后的通知消息或者系统通知。

针对此场景:我们设置了消息白名单、消息优先级的概念,保障不丢弃。如本节开始的图所示,消息环形队列可以为多个,与普通直播间消息分开则保障了重要消息不丢弃。

通过上述“1)上行限速控制(丢弃)策略”和“下行限速控制(丢弃)策略”保障了:

  • 1)客户端不会因为海量消息出现卡顿、延迟等问题;
  • 2)避免出现消息刷屏,肉眼无法查看的情况;
  • 3)同时降低了服务端存储压力,不会因为海量消息出现内存瓶颈从而影响服务。

7、写在最后

随着移动互联网的发展,直播间的实时消息业务模型和压力也在不停地扩展变化,后续可能还会遇到更多的挑战,我们的服务会与时俱进、跟进更优的方案策略进行应对。

附录:多人群聊天技术文章

[1]《IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?

[2]《IM群聊消息如此复杂,如何保证不丢不重?

[3]《移动端IM中大规模群消息的推送如何保证效率、实时性?

[4]《现代IM系统中聊天消息的同步和存储方案探讨

[5]《关于IM即时通讯群聊消息的乱序问题讨论

[6]《IM群聊消息的已读回执功能该怎么实现?

[7]《IM群聊消息究竟是存1份(即扩散读)还是存多份(即扩散写)?

[8]《一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践

[9]《IM群聊机制,除了循环去发消息还有什么方式?如何优化?

[10]《网易云信技术分享:IM中的万人群聊技术方案实践总结

[11]《阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处

[12]《IM群聊消息的已读未读功能在存储空间方面的实现思路探讨

[13]《企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等

[14]《融云IM技术分享:万人群聊消息投递方案的思考和实践

本文已同步发布于:http://www.52im.net/thread-3799-1-1.html

posted @ 2022-01-05 12:04 Jack Jiang 阅读(149) | 评论 (0)编辑 收藏

     摘要: 本文引用了作者Fundebug的“一文搞懂TCP与UDP的区别”一文的内容,感谢无私分享。1、引言网络协议是每个搞网络通信应用开发(比如IM、推送、网关等等)的程序员都必须要掌握的基础知识,TCP/IP协议簇中有两个最具有代表性的传输层协议——分别是 TCP 和 UDP。有过网络通信开发经验的同学们都知道,TCP和UDP协议是平时用的最多的两种协议,...  阅读全文

posted @ 2021-12-29 15:01 Jack Jiang 阅读(145) | 评论 (0)编辑 收藏

     摘要: 本文作者小傅哥,原题“使用DDD+Netty,开发一个分布式IM(即时通信)系统”。为了提升阅读体验,有大量修订和改动,感谢原作者。0、系列文章《跟着源码学IM(一):手把手教你用Netty实现心跳机制、断线重连机制》《跟着源码学IM(二):自已开发IM很难?手把手教你撸一个Andriod版IM》《跟着源码学IM(三):基于Netty,从零开发一个IM服务端》《跟着源码学I...  阅读全文

posted @ 2021-12-20 18:21 Jack Jiang 阅读(170) | 评论 (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.1.2更新内容 

【重要说明】:

MobileIMSDK v6.1.2 为次要版本,进行了若干优化! 查看详情

【解决的Bug】:

  1. [Andior/iOS]解决了当网络断线后,重传队列中的包不增加重次数从而一直重传的问题;
  2. [iOS] 解决了RMMapper库中,因重写父类copyWithZone方法而导致某些工程里的动画效果不生效的问题!

【其它优化和提升】:

  1. [Andiord]Andriod端Demo中补全了完整的proguard混淆配置,否则真有人对Demo进行“realease”时,会运行报错哦;
  2. [iOS] 上一个版本中的Protocal类中忘记补上“sm”字段,现在补上了;
  3. [服务端] 服务端Demo同步为最新工程,之前提交的版本未正确合并最新lib等;
  4. [服务端] 升级log4j2至2.15.0,解决Log4j2远程代码执行高危漏洞;
  5. [Andiord]Andriod端SDK和Demo工程的targetSdkVersion提升为30;
  6. [Andriod]Andriod端TCP版协议Netty库加载方式改为gradle加载;

【版本地址】:

https://gitee.com/jackjiang/MobileIMSDK/releases/6.1.2

posted @ 2021-12-16 22:07 Jack Jiang 阅读(145) | 评论 (0)编辑 收藏

     摘要: 本文由探探服务端高级技术专家张凯宏分享,原题“探探长链接项目的Go语言实践”,因原文内容有较多错误,有修订和改动。1、引言即时通信长连接服务处于网络接入层,这个领域非常适合用Go语言发挥其多协程并行、异步IO的特点。探探自长连接项目上线以后,对服务进行了多次优化:GC从5ms降到100微秒(Go版本均为1.9以上),主要gRPC接口调用延时p999从300ms下降到5ms。...  阅读全文

posted @ 2021-12-14 14:55 Jack Jiang 阅读(135) | 评论 (0)编辑 收藏

     摘要: 本文由ELab团队技术团队分享,原题“Twitter和微博都在用的 @ 人的功能是如何设计与实现的?”,有修订。1、引言第一次使用@人功能到现在已经有差不多10年了,初次使用是通过微博体验的。@人的功能现在遍布各种应用,基本上涉及社交(IM、微博)、办公(钉钉、企业微信)等场景,就是一个必不可少的功能。最近正好在调研 IM 各种功能的技术实现方案,所以也详细地了解了下@人功...  阅读全文

posted @ 2021-12-08 17:23 Jack Jiang 阅读(155) | 评论 (0)编辑 收藏

     摘要: 本文由石墨文档技术杜旻翔分享,原题“石墨文档 Websocket 百万长连接技术实践”,有修订。1、引言在石墨文档的部分业务中,例如文档分享、评论、幻灯片演示和文档表格跟随等场景,涉及到多客户端数据实时同步和服务端批量数据在线推送的需求,一般的 HTTP 协议无法满足服务端主动 Push 数据的场景,因此选择采用 WebSocket 方案进行业务开发。随着石墨文档业务发展,...  阅读全文

posted @ 2021-12-01 12:55 Jack Jiang 阅读(182) | 评论 (0)编辑 收藏

     摘要: 本文由公众号“后台技术汇”分享,原题“基于实践,设计一个百万级别的高可用 & 高可靠的 IM 消息系统”,原文链接在文末。由于原文存在较多错误和不准确内容,有大量修订和改动。1、引言大家好,我是公众号“后台技术汇”的博主“一枚少年”。本人从事后台开发工作 3 年有余了,其中让我感触最深刻的一个项...  阅读全文

posted @ 2021-11-27 13:00 Jack Jiang 阅读(192) | 评论 (0)编辑 收藏

本文由阿里闲鱼技术团队逸昂分享,原题“消息链路优化之弱感知链路优化”,有修订和改动,感谢作者的分享。

1、引言

闲鱼的IM消息系统作为买家与卖家的沟通工具,增进理解、促进信任,对闲鱼的商品成交有重要的价值,是提升用户体验最关键的环节。

然而,随着业务体量的快速增长,当前这套消息系统正面临着诸多急待解决的问题。

以下几个问题典型最为典型:

  • 1)在线消息的体验提升;
  • 2)离线推送的到达率;
  • 3)消息玩法与消息底层系统的耦合过强。

经过评估,我们认为现阶段离线推送的到达率问题最为关键,对用户体验影响较大。

本文将要分享的是闲鱼IM消息在解决离线推送的到达率方面的技术实践,内容包括问题分析和技术优化思路等,希望能带给你启发。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170 [推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK 

本文已同步发布于:http://www.52im.net/thread-3748-1-1.html )

2、系列文章

本文是系列文章的第6篇,总目录如下:

3、通信链路类型的划分

从数据通信链接的技术角度,我们根据闲鱼客户端是否在线,将整体消息链路大致分为强感知链路和弱感知链路。

强感知链路由以下子系统或模块:

  • 1)发送方客户端;
  • 2)idleapi-message(闲鱼的消息网关);
  • 3)heracles(闲鱼的消息底层服务);
  • 4)accs(阿里自研的长连接通道);
  • 5)接收方客户端组成。

整条链路的核心指标在于端到端延迟和消息到达率。

强感知链路中的双方都是在线的,消息到达客户端就可以保证接收方感知到。强感知链路的主要痛点在消息的端到端延迟。

弱感知链路与强感知链路的主要不同在于:弱感知链路的接收方是离线的,需要依赖离线推送这样的方式送达。

因此弱感知链路的用户感知度不强,其核心指标在于消息的到达率,而非延迟。

所以当前阶段,优化弱感知链路的重点也就是提升离线消息的到达率。换句话说,提升离线消息到达率问题,也就是优化弱感知链路本身。

4、消息系统架构概览

下图一张整个IM消息系统的架构图,感受下整体链路:

如上图所示,各主要组件和子系统分工如下:

  • 1)HSF是一个远程服务框架,是dubbo的内部版本;
  • 2)tair是阿里自研的分布式缓存框架,支持 memcached、Redis、LevelDB 等不同存储引擎;
  • 3)agoo是阿里的离线推送中台,负责整合不同厂商的离线推送通道,向集团用户提供一个统一的离线推送服务;
  • 4)accs是阿里自研的长连接通道,为客户端、服务端的实时双向交互提供便利;
  • 5)lindorm是阿里自研的NoSQL产品,与HBase有异曲同工之妙;
  • 6)域环是闲鱼消息优化性能的核心结构,用来存储用户最新的若干条消息。

强感知链路和弱感知链路在通道选择上是不同的:

  • 1)强感知链路使用accs这个在线通道;
  • 2)弱感知链路使用agoo这个离线通道。

5、弱感知链路到底怎么定义

通俗了说,弱感知链路指的就是离线消息推送系统。

相比较于在线消息和端内推送(也就是上面说的强感知链路),离线推送难以确保被用户感知到。

典型的情况包括:

  • 1)未发送到用户设备:即推送未送达用户设备,这种情况可以从通道的返回分析;
  • 2)发送到用户设备但没有展示到系统通知栏:闲鱼曾遇到通道返回成功,但是用户未看到推送的案例;
  • 3)展示到通知栏,并被系统折叠:不同安卓厂商对推送的折叠策略不同,被折叠后,需用户主动展开才能看到内容,触达效果明显变差;
  • 4)展示到通知栏,并被用户忽略:离线推送的点击率相比于在线推送更低。

针对“1)未发送到用户设备”,原因有:

  • 1)离线通道的token失效;
  • 2)参数错误;
  • 3)用户关闭应用通知;
  • 4)用户已卸载等。

针对“3)展示到通知栏,并被系统折叠”,原因有:

  • 1)通知的点击率;
  • 2)应用在厂商处的权重;
  • 3)推送的数量等。

针对“4)展示到通知栏,并被用户忽略”,原因有:

  • 1)用户不愿意查看推送;
  • 2)用户看到了推送,但是对内容不感兴趣;
  • 3)用户在忙别的事,无暇处理。

总之:以上这些离线消息推送场景,对于用户来说感知度不高,我们也便称之为弱感知链路。

6、弱感知链路的逻辑构成

我们的弱感知链路分为3部分,即:

  • 1)系统;
  • 2)通道;
  • 3)用户。

共包含了Hermes、agoo、厂商、设备、用户、承接页这几个环节。具体如下图所示。

从推送的产生到用户最终进入APP,共分为如下几个步骤:

  • 步骤1:Hermes是闲鱼的用户触达系统,负责人群管理、内容管理、时机把控,是整个弱感知链路的起点。;
  • 步骤2:agoo是阿里内部承接离线推送的中台,是闲鱼离线推送能力的基础;
  • 步骤3:agoo实现离线推送依靠的是厂商的推送通道(如:苹果的apns通道、Google的fcm通道、及国内各厂商的自建通道。;
  • 步骤4:通过厂商的通道,推送最终出现在用户的设备上,这是用户能感知到推送的前提条件;
  • 步骤5:如果用户刚巧看到这条推送,推送的内容也很有趣,在用户的主动点击下会唤起APP,打开承接页,进而给用户展示个性化的商品。

经过以上5个步骤,至此弱感知链路就完成了使命。

7、弱感知链路面临的具体问题

弱感知链路的核心问题在于:

  • 1)推送的消息是否投递给了用户;
  • 2)已投递到的消息用户是否有感知。

这对应推送的两个阶段:

  • 1)推送消息是否已到达设备;
  • 2)用户是否查看推送并点击。

其中:到达设备这个阶段是最基础的,也是本次优化的核心。

我们可以将每一步的消息处理量依次平铺,展开为一张漏斗图,从而直观的查看链路的瓶颈。

漏斗图斜率最大的地方是优化的重点,差异小的地方不需要优化:

通过分析以上漏斗图,弱感知链路的优化重点在三个方面:

  • 1)agoo受理率:是指我们发送推送请到的数量到可以通过agoo(阿里承接离线推送的中台)转发到厂商通道的数量之间的漏斗;
  • 2)厂商受理率:是指agoo中台受理的量到厂商返回成功的量之间的漏斗;
  • 3)Push点击率:也就通过以上通道最终已送到到用户终端的消息,是否最终转化为用户的主动“点击”。

有了优化方向,我们来看看优化手段吧。

8、我们的技术优化手段

跟随推送的视角,顺着链路看一下我们是如何进行优化的。

8.1 agoo受理率优化

用户的推送,从 Hermes 站点搭乘“班车”,驶向下一站: agoo。

这是推送经历的第一站。到站一看,傻眼了,只有不到一半的推送到站下车了。这是咋回事嘞?

这就要先说说 agoo 了,调用 agoo 有两种方式:

  • 1)指定设备和客户端,agoo直接将推送投递到相应的设备;
  • 2)指定用户和客户端,agoo根据内部的转换表,找到用户对应的设备,再进行投递。

我们的系统不保存用户的设备信息。因此,是按照用户来调用agoo的。

同时:由于没有用户的设备信息,并不知道用户是 iOS 客户端还是 Android 客户端。工程侧不得不向 iOS 和 Android 都发送一遍推送。虽然保证了到达,但是,一半的调用都是无效的。

为了解这个问题:我们使用了agoo的设备信息。将用户转换设备这一阶段提前到了调用 agoo 之前,先明确用户对应的设备,再指定设备调用 agoo,从而避免无效调用。

agoo调用方式优化后,立刻剔除了无效调用,agoo受理率有了明显提升。

至此:我们总算能对 agoo 受理失败的真正原因做一个高大上的分析了。

根据统计:推送被 agoo 拒绝的主要原因是——用户关闭了通知权限。同时,我们对 agoo 调用数据的进一步分析发现——有部分用户找不到对应的设备。 优化到此,我们猛然发现多了两个问题。

那就继续优化呗:

  • 1)通知体验优化,引导打开通知权限;
  • 2)与agoo共建设备库,解决设备转换失败的问题。

这两个优化方向又是一片新天地,我们择日再聊。

8.2 厂商推送通道受理率优化

推送到达 agoo ,分机型搭乘厂商“专列”,驶向下一站:用户设备。

这是推送经历的第二站。出站查票,发现竟然超员了。

于是乎:我们每天有大量推送因为超过厂商设定的限额被拦截。

为什么会这样呢?

实际上:提供推送通道的厂商(没错,各手机厂商的自家推送通道良莠不齐),为了保证用户体验,会对每个应用能够推送的消息总量进行限制。

对于厂商而言,这个限制会根据推送的类型和应用的用户规模设定——推送主要分为产品类的推送和营销类的推送。

厂商推送通道对于不同类型消息的限制是:

  • 1)对于产品类推送,厂商会保证到达;
  • 2)对于营销类推送,厂商会进行额度限制;
  • 3)未标记的推送,默认作为营销类推送对待。

我们刚好没有对推送进行标记,因此触发了厂商的推送限制。

这对我们的用户来说,会带来困扰。闲鱼的交易,很依赖买卖家之间的消息互动。这部分消息是需要确保到达的。

同样:订单类的消息、用户的关注,也需要保证推送给用户。

根据主流厂商的接口协议,我们将推送的消息分为以下几类,并进行相应标记:

  • 1)即时通讯消息;
  • 2)订单状态变化;
  • 3)用户关注内容;
  • 4)营销消息这几类。

同时,在业务上,我们也进行了推送的治理——将用户关注度不高的消息,取消推送,避免打扰。

经过这些优化,因为超过厂商限额而被拦截的推送实现了清零。

8.3 Push点击率优化

通过优化agoo受理率、厂商受理率,我们解决了推送到达量的瓶颈。但即使消息被最终送达,用户到底点击了没有?这才是消息推送的根本意义所在。

于是,在日常的开发测试过程中,我们发现了推送的两个体验问题:

  • 1)用户点击Push有开屏广告;
  • 2)营销Push也有权限校验,更换用户登陆后无法点击。

对于开屏广告功能,我们增加了Push点击跳过广告的能力。

针对Push的权限校验功能,闲鱼根据场景做了细分:

  • 1)涉及个人隐私的推送,保持权限校验不变;
  • 2)营销类的推送,放开权限校验。

以上是点击体验的优化,我们还需要考虑用户的点击意愿。

用户点击量与推送的曝光量、推送素材的有趣程度相关。推送的曝光量又和推送的到达量、推送的到达时机有关。

具体的优化手段是:

  • 1)在推送内容上:我们需要优化的是推送的时机和相应的素材;
  • 2)在推送时机上:算法会根据用户的偏好和个性化行为数据,计算每个用户的个性化推送时间,在用户空闲的时间推送(避免在不合适的时间打扰用户,同时也能提升用户看到推送的可能性)。
  • 3)在推送素材上:算法会根据素材的实时点击反馈,对素材做实时赛马。只发用户感兴趣的素材,提高用户点击意愿。

9、实际优化效果

通过以上我们的分析和技术优化手段,整体弱推送链路链路有了不错的提升,离线消息的到达率相对提升了两位数。

10、写在最后

本篇主要和大家聊的是只是IM消息系统链路中的一环——弱感知链路的优化,落地到到具体的业务也就是离线消息送达率问题。

整体IM消息系统,还是一个比较复杂的领域。

我们在消息系统的发展过程中,面临着如下问题:

  • 1)如何进行消息的链路追踪;
  • 2)如何保证IM消息的快速到达(见《闲鱼亿级IM消息系统的及时性优化实践》);
  • 3)如何将消息的玩法和底层能力分离;
  • 4)离线推送中如何通过用户找到对应的设备。

这些问题,我们在以前的文章中有所分享,以后也会陆续分享更多,敬请期待。

附录:相关资料

[1] Android P正式版即将到来:后台应用保活、消息推送的真正噩梦

[2] 一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践

[3] 一套亿级用户的IM架构技术干货(上篇):整体架构、服务拆分等

[4] 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

[5] 从新手到专家:如何设计一套亿级消息量的分布式IM系统

[6] 企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等

[7] 融云技术分享:全面揭秘亿级IM消息的可靠投递机制

[8] 移动端IM中大规模群消息的推送如何保证效率、实时性?

[9] 现代IM系统中聊天消息的同步和存储方案探讨

[10] 新手入门一篇就够:从零开发移动端IM

[11] 移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”

[12] 移动端IM开发者必读(二):史上最全移动弱网络优化方法总结

[13] IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

[14] IM消息送达保证机制实现(二):保证离线消息的可靠投递

[15] 零基础IM开发入门(一):什么是IM系统?

[16] 零基础IM开发入门(二):什么是IM系统的实时性?

[17] 零基础IM开发入门(三):什么是IM系统的可靠性?

[18] 零基础IM开发入门(四):什么是IM系统的消息时序一致性?

本文已同步发布于“即时通讯技术圈”公众号。

同步发布链接是:http://www.52im.net/thread-3748-1-1.html 

posted @ 2021-11-17 12:24 Jack Jiang 阅读(193) | 评论 (0)编辑 收藏

     摘要: 本文由公众号“水滴与银弹”号主Kaito原创分享,原题“搞懂异地多活,看这篇就够了”,为使文章更好理解,即时通讯网收录时有修订。1、引言前几天技术群里有群友问我52im社区里有没有IM分布式系统异地多活方面的文章,我仔细想了想,除了微信分享的几篇文章里有提到容灾和异地多活(只是大致提过,没有详细展开),确实目前还没有系统性的异地多活技术资料可供参考。...  阅读全文

posted @ 2021-11-10 15:18 Jack Jiang 阅读(195) | 评论 (0)编辑 收藏

     摘要: 本文引用了ELab团队、腾讯大讲堂两个公众号分享的文章内容,引用内容见文末参考资料,感谢原作者的无私分享。1、引言对于市面上主流的IM来说,跟二维码有关的功能,比如扫码加好友、扫码登陆、扫码加群等,都是很常见的。这是微信的扫码登录功能:这是微信的扫码加好友功能: 二维码技术使用起来很简单,本系列的前三篇文章也专门针对IM扫码登录这个功能做了详细的分享,但本着学习技术不留死角的习惯,我认为...  阅读全文

posted @ 2021-11-01 19:49 Jack Jiang 阅读(148) | 评论 (0)编辑 收藏

     摘要: 本文由融云技术团队原创分享,原题“万字干货:IM “消息”列表卡顿优化实践”,为使文章更好理解,内容有修订。1、引言随着移动互联网的普及,无论是IM开发者还是普通用户,IM即时通讯应用在日常使用中都是必不可少的,比如:熟人社交的某信、IM活化石的某Q、企业场景的某钉等,几乎是人人必装。以下就是几款主流的IM应用(看首页就知道是哪款,我就不废话了):正...  阅读全文

posted @ 2021-10-26 14:41 Jack Jiang 阅读(137) | 评论 (0)编辑 收藏

本文由阿里闲鱼技术团队有攸分享,原题“向消息延迟说bybye:闲鱼消息及时到达方案”,有修订和改动,感谢作者的分享。

1、引言

IM消息作为闲鱼用户重要的交易咨询工具,核心目标有两点:

  • 1)第一是保证用户的消息不丢失;
  • 2)第二是保证用户的消息及时送达接收方。

IM消息根据消息的接收方设备是否在线,分为离线和在线推送。数据显示目前闲鱼每天有超过一半以上的IM消息是走在线通道的,而在线消息的到达率、及时性是直接影响用户体验的。

本文将根据闲鱼IM消息系统在消息及时性方面的优化实践,详细分析了IM在线通道面临的各种技术问题,并通过相应的技术手段来优化从而保证用户消息的及时到达。

PS:如果您对IM消息可靠性还没有概念,建议先阅读这篇入门文章《零基础IM开发入门(二):什么是IM系统的实时性?》。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170 [推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK

本文同步发布于:http://www.52im.net/thread-3726-1-1.html

2、系列文章

本文是系列文章的第5篇,总目录如下:

3、当前面临的问题

3.1 端内长连接中断

在IM场景中,用户与云端通信频繁,且为了实现用户的消息及时到达,往往采用云端下推消息的方式触达用户,所以用户在线时设备与云端会维持一条TCP长连接通道,可以更轻量级的与服务端进行交互,现代IM即时通讯的下行消息都是通过长连下发的。

当前闲鱼IM消息系统使用的是ACCS长连接,ACCS是淘宝无线提供的全双工、低延时、高安全的通道服务。

但由于用户设备网络状态的不确定性,可能会发生各种各样的网络异常情况导致ACCS长连接通道中断。而长连接一旦意外中断,就会导致用户无法及时收到在线消息。

针对这个问题,我们需要尽可能及时的感知到长连中断并尝试重连。具体的优化思路会在本文后面的内容中分享。

3.2 下推的消息未达

感知长连中断并重连只能在大多数时间保证长连接的有效性,但是在长连接无效或不稳定期间下推的消息客户端可能根本收不到。

简单说就是仅仅有重连机制无法保证下行消息必达,可能有以下场景导致下行消息失败:

  • 1)服务端发送下行消息时长连畅通,消息在传输路上通道断掉,客户端无法收到;
  • 2)设备的在线状态存在延迟,服务端下行消息时认为设备在线,实际上设备已经离线,无法收到;
  • 3)客户端收到了下行消息,但端上后续处理失败(比如落库失败,消息没有成功展示给用户)。

我们通过数据埋点统计得出,ACCS长连接的下行成功率在97%左右。

ACCS长连接的下行成功率的统计方法如下:

ACCS下行成功率 = 通过ACCS成功下行且客户端收到的消息量 / 服务端认为通过ACCS成功下行的消息量

有心急的同学就要问了,丢了3%的消息吗?

并没有!这3%的消息不会丢失,只是不保证及时触达给用户。

我们的消息同步模型是推拉结合模式,在用户拉取消息时会拉取到设备当前位点与服务端最新位点的所有消息,ACCS下行失败的消息会通过主动拉模式获取到,但客户端主动拉取消息的触发时机有限。

当前客户端主动拉取消息的触发时机主要有以下几个:

  • 1)用户冷启动app,主动同步消息;
  • 2)用户主动下拉刷新;
  • 3)app后台切换前台;
  • 4)收到一条推送消息,客户端发现新消息的位点跟本地最新的位点有gap,触发同步。

可见:上述主动同步消息的触发很大程度上依赖用户行为或者有没有收到新消息,难以保证消息及时到达。

如果是用户高频打开的IM软件,这样也不会有太大的问题。但是闲鱼app的活跃度较低,有时候甚至依赖IM消息拉活,而且一条延迟的消息触达可能导致用户错过一笔交易,闲鱼消息不允许有这样的延迟发生。

基于上述分析,我们先描述一个数据指标来反映现状。

通过上面的描述可知:ACCS消息并不全都是推下来的,也可能是主动拉下来的。如果是推,必定可以及时到达;如果是拉,则受限于用户行为。

拉的这部分消息,我们定义为ACCS消息补偿到达,然后计算ACCS消息补偿到达耗时,消息范围限定为服务端ACCS成功下行但是客户端通过主动拉取同步到的消息,以往的版本这个数据在60分钟左右。

注意:这个数据并不是消息触达到用户的耗时,因为如果在线转离线触达,拉取到消息的时间取决于用户行为(用户何时打开了app),但这个数据也能大致反映在线消息的到达延迟状况。

ACCS长连接的消息补偿到达耗时的统计方法如下:

ACCS消息补偿到达耗时 = 客户端通过拉获取到ACCS消息的时间 - 服务端ACCS下行时间

接下来本文将从长连接的重连和未达消息重发两个方面详细讲述我们是如何优化在线通道稳定性的,从而优化并保证消息的及时到达。

4、优化手段1:增加长连接重连机制

4.1 长连接为什么会中断?

有因必有果,我们先来分析下有哪些原因会导致连接中断。

对于IM这种场景下来说,通常可能有以下原因:

  • 1)用户设备断网;
  • 2)设备发生了网络切换;
  • 3)设备处于弱网环境,网络不稳定;
  • 4)设备网络正常,TCP连接由于NAT超时导致连接被运营商中断。

对于APP来说,如果是用户操作导致网络状态变化的情况,会有网络状态变化事件通知,这种情况可以监听事件并主动尝试重连。但现实中的大多数情况都是“意料之外”(正如上面列举的这些断网可能性一样)。

那么既然“意料之外”的断网无法预知,技术上可以如何有效的感知到各种异常状况呢?

PS:如果要透彻理解断网、弱网、TCP链接有效性,并不是本文能讲的清楚的,可以参照下面的资料深入理解一下,值得好好学习。

关于TCP链接本身的有效性问题,可以读以下两篇:

  1. 为何基于TCP协议的移动端IM仍然需要心跳保活机制?
  2. 不为人知的网络编程(十二):彻底搞懂TCP协议层的KeepAlive保活机制

关于移动网络的复杂性问题,可以从以下几篇入门的科普文章学习一下:

  1. IM开发者的零基础通信技术入门(十一):为什么WiFi信号差?一文即懂!
  2. IM开发者的零基础通信技术入门(十二):上网卡顿?网络掉线?一文即懂!
  3. IM开发者的零基础通信技术入门(十三):为什么手机信号差?一文即懂!
  4. IM开发者的零基础通信技术入门(十四):高铁上无线上网有多难?一文即懂!

关于移动弱网带来的各种问题、优化方案等,可以通过以下几篇系统学习一下:

  1. 现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障
  2. 移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”
  3. 移动端IM开发者必读(二):史上最全移动弱网络优化方法总结
  4. 百度APP移动端网络深度优化实践分享(三):移动端弱网优化篇

4.2 心跳检测机制

像大多数链路保活场景一样,IM这种场景下最有效的检测手段就是心跳检测(如果你对TCP链路保活还没有什么概念,建议先读《为何基于TCP协议的移动端IM仍然需要心跳保活机制?)。

原理就是:客户端通过定时发送心跳包,服务端收到心跳包后再反馈给客户端,通过客户端和服务端这一来一去的配合,就可以实现客户服和服务端各自都能感知到连接是否中断。

从及时性效果来看:心跳间隔越短越好,而频繁的心跳检测势必会带来用户流量以及电量的损耗,所以我们的实现目标是如何尽可能少的心跳检测而又尽量及时地感知到长连中断的意外情况。

状态机+消息心跳队列:

在心跳协议设计上,要注意心跳包的核心目标是检测长连通道是否畅通,客户端主动上行心跳包且能收到服务端回包,就认为长连通道健康。所以心跳的上行消息以及回包的数据包应尽可能小。一般来说,通过协议头标识心跳包及响应即可(这样就能节省协议包大小)。

PS:关于心跳机制的入门文章可以详读《一文读懂即时通讯应用中的网络心跳包机制:作用、原理、实现思路等》。

4.3 心跳策略

心跳策略是实现我们上述目标的核心机制,本文仅简单列举几种心跳策略。

比如以下这几种:

  • 1)短心跳检测 初始状态连续 ping 3次 收到 ACK 后,可以认为进入稳定状态;
  • 2)常规固定时长心跳(根据app状态不同,频率可调Mid+,Mid-, Long);
  • 3)自适应心跳 根据设备网络状态变化自动适应的心跳间隔;
  • 4)冗余心跳,app后台切前台,主动心跳一次。

关于心跳策略的详细设计甚至可以单独写一篇文章,有兴趣的同学可以阅读以下推荐的文章继续深入研究。

5、优化手段2:消息ACK应答与重发机制

5.1 概述

为了解决上面的问题,我们同时也引入了消息ACK应答与重发机制。

整体思路是:客户端在收到ACCS消息并处理成功后,给服务端回一个ACK应答包,服务端下发ACCS消息时将消息加入重试队列,收到ACK应答包后更新消息到达状态,并终止重试。

整体设计流程图如下:

该方案的难点即重试处理器的实现设计,接下来我们将重点讲述这部分的详细设计。

5.2 重试队列存储设计

我们采用阿里云表格存储TimeLine模型来存储下行消息的到达状态。Timeline 模型是针对消息数据场景所设计的数据模型,它能满足消息数据场景对消息保序、海量消息存储、实时同步的特殊需求,在IM、Feed流等消息场景应用广泛。(关于TimeLine模型,这里有篇详细的文章可以学习一下《现代IM系统中聊天消息的同步和存储方案探讨

我们给每个用户设备定义一个TimeLine,timeline-id定义为userId_deviceId,sequenceId自定义为消息位点。

存储结构如下:

每通过ACCS成功下行一条消息,则插入到接收用户设备的TimeLine中,收到ACK后根据消息id更新消息到达状态。

同时由于重试动作只发生在下行消息后较短的一段时间内,所以我们设置一个比较短的全局过期时间即可,避免数据膨胀。

5.3 延迟重试设计

如上图所示:

  • 1)每通过ACCS下发一条消息,先插入到Timeline中,初始状态为未达,然后生产一条延迟N秒的延迟消息;
  • 2)每次消费到延迟消息后,读取tablestore中该消息的到达状态,如到达则终止延迟,否则继续;
  • 3)每次重试先判断设备是否在线,如果设备不在线,转发离线通道并终止重试,如果设备在线,则重推未到达的消息,并再次延迟N秒消费;
  • 4)每条消息的重试生命周期中用的同一条延迟消息,最多重试消费M次,超过次数不再重试并打日志埋点(后续可以监控这种情况并基于这个数据进行优化)。

5.4 延迟重发策略

延迟重发策略是指在重发流程中,如何选择合适的延迟时间来使得重发的效率最高。

不同用户在不同时间、地点所处的网络环境差别较大,网络恢复到稳定态所需要的时间也有差异,需要选用合适的延迟策略来保证重发效率。

最优的延迟策略的目标是在最短的时间内,使用最少的重发次数将消息投递成功。以下是几种可选的方案。

5.4.1)固定延迟时间:

要想找到最优的延迟策略,必须从数据中通过分析得到答案,天马行空的想象往往离实际相差甚远。

我们先采用固定的延迟时间(10s)最大重试6次来分析一波数据:

通过这组数据可以看到:有约85%的消息在40s内重发可以投递成功,还有12%的消息在达到最大重试次数后依旧没有收到ACK。在4次重试之后,第5次成功只有2.03%,第6次只有0.92%,继续重发的收益已经变得很低。

6次以后还有部分消息没有收到ACK,这部分消息如果用固定延迟时间策略,性价比很低,频繁重发浪费系统资源,我们需要继续改进策略。

5.4.2)固定延迟+固定步长递增:

考虑到部分用户的网络短时间无法恢复,频繁的短间隔重发价值不大,我们采用4次固定短间隔延迟N秒后,每次延迟时间都是上一次延迟时间递增固定步长M秒的策略。直到收到ACK、用户设备离线或者达到了最大延迟时间MAX(N)。

这种策略一定程度上可以解决固定延迟时间重发策略的问题,但如果用户短时间网络无法恢复,每次重发都要重新递增,也不是一种最优解。

5.4.3)自适应延迟:

设计流程图:

如上图:我们最终衍生出了自适应延迟策略。

自适应延迟是指:根据用户的网络状况,采取自动调整的延迟时间,以期望达到最高的重发效率。

具体是:新消息先通过4次固定N秒的短延迟来探测设备的网络状况,一旦网络恢复,我们将设备的N值清空(设备N值是指根据上几次重发经验,当前设备网络能回复ACK所需要的最短时间,默认情况该值为空,代表用户设备网络正常)。4次重发后依旧收不到ACK,我们尝试读取设备N值,如果为空,则取初始值,以后每次延迟都递增固定步长M,并在重发后更新当前设备的N值,直到消息收到ACK或者达到了最大延迟时间MAX(N)。

5.5 新老版本兼容性

需要注意的是老版本的app是不会回ACK的,如果下发给老版本设备的消息也加入重试队列,那此类消息将一直重试到最大次数才会终止,无端消耗资源。

所以我们设计在ACCS长连建立之后,客户端主动上行一条设备信息,其中包含app的版本号,服务端存储一定时间,在将消息加入重试队列之前,先校验接收者设备app的版本号,符合要求再加入重试队列。

6、 最终优化后的效果

消息重连重发方案上线后,我们上面定义的指标 ACCS补偿到达时间 从60分钟大幅降低至15分钟,降幅达75%。

从而印证了我们的技术分析,同时用户有关消息延迟的舆情反馈大幅下降,可见消息重发机制对保证用户消息及时到达成效显著。

7、未来展望

消息在线通道的稳定性优化至此已告一段落,未来我们将继续优化闲鱼消息的使用体验,包括基础功能的完善以及基础体验的提升。

基础功能方面:我们在近期的版本中已经支持了消息撤回、草稿功能,后续将逐步支持发送定位,会话分组、备注,消息搜索等功能。

基础体验方面:我们对消息的UI样式做了优化升级,并优化了app消息tab页的cpu及内存使用,后续将继续从流量、电量、性能方面继续优化消息的使用体验。

附录:参考资料

[1] 为何基于TCP协议的移动端IM仍然需要心跳保活机制?

[2] 不为人知的网络编程(十二):彻底搞懂TCP协议层的KeepAlive保活机制

[3] 现代IM系统中聊天消息的同步和存储方案探讨

[4] 现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障

[5] 移动端IM开发者必读(二):史上最全移动弱网络优化方法总结

[6] IM开发者的零基础通信技术入门(十二):上网卡顿?网络掉线?一文即懂!

[7] IM开发者的零基础通信技术入门(十三):为什么手机信号差?一文即懂!

[8] 移动端IM实践:实现Android版微信的智能心跳机制

[9] 融云技术分享:融云安卓端IM产品的网络链路保活技术实践

[10] Web端即时通讯实践干货:如何让你的WebSocket断网重连更快速?

本文已同步发布于“即时通讯技术圈”公众号。

同步发布链接是:http://www.52im.net/thread-3726-1-1.html

posted @ 2021-10-19 23:05 Jack Jiang 阅读(233) | 评论 (0)编辑 收藏

     摘要: 本文由作者“阿宝哥”分享,原题“你不知道的 WebSocket”,有修订和改动。1、引言本文将从基本概念、技术原理、常见易错常识、动手实践等多个方面入手,万字长文,带你一起全方位探索 WebSocket 技术。阅读完本文,你将了解以下内容:1)了解 WebSocket 的诞生背景、WebSocket 是什么及它的优点;2)了解 WebSocket 含...  阅读全文

posted @ 2021-10-11 14:35 Jack Jiang 阅读(164) | 评论 (0)编辑 收藏

     摘要: 本文由阿里闲鱼技术团队景松分享,原题“到达率99.9%:闲鱼消息在高速上换引擎(集大成)”,有修订和改动,感谢作者的分享。1、引言在2020年年初的时候接手了闲鱼的IM即时消息系统,当时的消息存在各种问题,网上的用户舆情也是接连不断。典型的问题,比如:1)“聊天消息经常丢失”;2)“消息用户头像乱了”;3)“订单状...  阅读全文

posted @ 2021-09-26 14:47 Jack Jiang 阅读(215) | 评论 (0)编辑 收藏

本文由阿里闲鱼技术团队今朝、有攸分享,本次有修订。

1、引言

闲鱼即时消息系统历经数代迭代,目前已能稳定的支撑亿级消息体量。

在此消息系统的建设过程中,我们经历了从简单到复杂、从困扰到破局,每一次的技术改变都是为了更好的解决当下业务所面临的问题。

本文分享的是闲鱼即时消息系统架构从零开始的技术变迁之路,以期更多的同行们在此基础上汲取经验,得到有价值的启发。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170 [推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK

本文同步发布于:http://www.52im.net/thread-3699-1-1.html )

2、系列文章

本文是系列文章的第3篇,总目录如下:

  1. 阿里IM技术分享(一):企业级IM王者——钉钉在后端架构上的过人之处
  2. 阿里IM技术分享(二):闲鱼IM基于Flutter的移动端跨端改造实践
  3. 阿里IM技术分享(三):闲鱼亿级IM消息系统的架构演进之路》(* 本文
  4. 阿里IM技术分享(四):闲鱼亿级IM消息系统的可靠性投递技术实践》(* 稍后发布

3、1.0版:业务初创期、最小化可用

3.1 技术背景

2014年启动闲置交易独立APP “闲鱼”,一期构建完成APP主链路,包含商品:发布→搜索→商品详情→IM会话→交易

作为初创app,业务需尽快上线验证效果,技术建设上需要完成闲鱼消息从无到有的系统搭建。

3.2 技术方案

作为即时通讯系统,最小化能力包含:

  • 1)消息存储:会话、摘要、消息;
  • 2)消息同步:推、拉;
  • 3)消息通道:长连接、厂商推送。

与一般IM会话模型不同的是,闲鱼会话以商品为主体,“人+人+商品”为要素构建会话。

因会话模型的差异,淘系已有的消息系统,短期内无法满足业务需求,而闲鱼完全自建消息系统耗时巨大。

为了保障业务高效上线,技术选型上最大化复用已有系统能力,避免重复造轮子。

所以,我们的技术方案是:

  • 1)数据模型与底层存储依赖淘系私信体系进行建设;
  • 2)消息数据获取上,客户端全量从服务端拉取消息数据;
  • 3)通讯协议使用来往SDK及mtop。

总体架构如下图,以此模式完成快速交付保障了业务最小化可用:

4、2.0版:用户量增速快、需要重建消息系统

4.1 技术背景

闲鱼用户量正快速突破100万,即时消息服务的调用量暴涨。在这样的背景下,用户反馈消息数据获取的卡顿、白屏成为常态,大量的消息Push发送下,系统告警频发。

造成这些问题的原因:1.0版的架构模式下,获取消息数据全量拉模式,客户端纯UI不做数据存储。

具体就是:

  • 1)当用户需要查看消息数据时,数据拉取成功与否取决于网络、数据访问速度,偶发性的造成卡顿、白屏;
  • 2)中心化的数据存储,读远大于写,高并发下,服务端负载过大。

针对第2)点:比如1W个用户同时在线聊天,按照当前架构并发拉取全量消息,估算5万QPS。不妨假设,同时在线聊天用户数10万时,对服务端压力可想而知。

4.2 技术方案

基于上述问题,我们决定重建消息系统架构,以应对未来更大的用户增量。

回归到IM系统的核心功能:

4.2.1)消息存储模型:

  • 1)会话模型:由owner、itemid、user、sessionType 来标识唯一会话,增加扩展属性支持个性化;
  • 2)摘要模型:作为用户会话视图,同一会话的不同用户可个性化呈现,由userid、sid标识唯一摘要;
  • 3)消息模型:由sender、消息内容、消息版本、sid组成。sid+消息版本唯一确定一条消息;
  • 4)指令模型:是一种双端约定,由服务端下发,客户端执行的指令集。如免打扰指令、删除指令等。

4.2.2)消息通道:

1)在线通道:使用淘宝无线ACCS长连接提供的全双工、低延时、高安全的通道服务;

2)离线通道:使用淘宝消息推送平台AGOO. 其屏蔽了各主流厂商对接的复杂度,直接对业务系统提供服务。

4.2.3)消息同步模型:

1)客户端建立数据库,存储消息数据:当消息数据存储在本地设备上,消息同步从全量拉取优化为全量+增量同步结合的模式。

增量和全量同步具体指的是:

  • a. 增量同步:客户端存储消息位点信息,通过与服务端最新位点比较,仅同步增量消息;
  • b. 全量同步:当用户卸载重装或位点gap过大时,客户端全量拉取历史消息数据,进行端上数据重建。

2)服务端建设个人消息域环(收件箱模型):以和客户端进行增量数据同步。同时,1.0版本架构中存在的读多写少的问题,通过个人域环的写扩散来平衡读写压力。

下图为一条消息从发送到接收的过程以及服务端和客户端的执行流程:

如上图所示:假设Ua给Ub发送一条消息,消息写扩散至Ua和Ub的各自的域环中:

  • 1)当客户端online时,接收到推送的消息位点=当前端上域版本+1,本地消息数据库merge即可;
  • 2)当客户端offline时,仅进行离线推送通知,当用户重新上线时,进行数据同步,由服务端判断触发增量同步还是全量同步。

针对第2)点,具体逻辑是:

  • 1)如果域环版本差值小于阀值,增量同步后,进行本地消息数据库merge;
  • 2)当域环版本差值大于阀值,进行全量消息拉取,做端上数据重建。

整个同步逻辑基于闲鱼的即时消息域环,域环可以看作是有着固定容量的用户消息收件箱,给一个用户发送的所有消息都会同步到他的域环中。

具体就是:

  • 1)域环存储:域环需要支持高并发数据读写,使用阿里分布式KV存储系统tair来实现;
  • 2)域环容量:为减少全量消息同步,以用户下次进入闲鱼需要同步的平均消息量来规划个人域环容量。同时利用FIFO循环覆盖历史数据;
  • 3)域环版本:用户当前消息位点,在消息进入个人域环时通过tair的counter实现域环版本严格连续递增,用于全量、增量同步判断。

上述建设完成后,闲鱼具备了自己独立的即时消息系统,当下遇到的问题得到了缓解,用户体验度有大幅提升。

5、3.0版:随着业务快速发展,系统稳定性需得到保障

5.1 技术背景

随着闲鱼业务生态的丰富,IM会话与消息内容类型不断扩展,同时在用户量的快速增长下,用户反馈消息收不到、消息延迟等舆情问题日渐突出。

5.2 问题分析

问题1:闲鱼app进程无有效保活机制,app退到后台后进程很快就会被系统挂起,导致长连接中断。此时消息推送走厂商通道,而厂商通道的实时性较差,且对消息推送的优先级设定有差异,从而造成用户感知消息延迟。

问题2:accs在线消息推送时,平均延时较短,但存在假连情况。而且目前的消息推送链路无ack机制,造成服务端以为消息发出去了但实际上客户端并没有收到,用户下次打开app后才能看到消息,用户感知消息延迟。

PS:造成假连接的原因主要是用户退到后台,accs长连中断,但是设备状态更新有延时。

问题3:目前消息同步的推模式(accs push)、拉模式(mtop),客户端未做隔离,异步进行处理,导致在某些极端情况下消息数据库处理异常,引发消息丢失。

如:某用户上线后连续收到多条消息,其中一条触发域黑洞,在进行消息同步端上数据重建时,小概率处理出错。

问题4:大部分线上消息问题发现靠舆情反馈,如消息错乱,出问题后系统无感知、无补救措施且排查困难,仅能跟随版本做修复。

问题5:业务不断丰富,孵化出基于消息系统的服务号及小程序内容营销、消息群组等,各类消息发送链路共用域环与数据存储,造成稳定性问题。

如:个人域环的消息包括IM聊天和营销消息,IM聊天由用户触发,需要保证强到达;而营销消息一般是由系统通过班车等方式批量发送,消息量级大,tps高,影响IM服务稳定性。

5.3 解案决方案

基于上述分析,我们逐个问题进行专项解决。

1)消息重发与推拉隔离:

如上图所示:

  • a. ACK:保障消息及时到达。服务端下行accs消息时,将消息加入重试队列并延迟重试,客户端在收到accs消息并处理成功后,给服务端回一个ack,服务端收到ack后更新消息到达状态,并终止重试,以此避免设备假连或网络不稳定的情况;
  • b. 重发:根据延迟重发策略决定何时重发消息,保障消息确定性到达。自适应延迟重发策略是指新消息先通过4次固定N秒的短延迟来探测设备的网络状况,然后根据网络状况来递增固定步长M的延迟策略,这种策略可以保障在最短的时间内,使用最少的重发次数将消息投递成功;
  • c. 消息队列:端上引入消息队列,按顺序处理消息,保证消息处理的准确性。同时进行推拉隔离,保障队列有序消费,解决了复杂状况下并发处理消息数据合并出错的问题。

2)数据存储拆分:

闲鱼每天发送的即时消息中有一半以上是营销消息,营销消息的发送具有明显的波峰波谷流量,高峰期会导致消息数据库抖动,影响IM消息。我来对消息、摘要、域环存储做业务隔离,以适应不同业务场景对稳定性不同的要求。

具体做法是:

  • 1)IM消息需要极高的稳定性保证,其消息及摘要继续使用mysql存储;
  • 2)营销消息存储周期短,稳定性要求低于IM,采用Lindorm存储;
  • 3)域环做实例级别隔离,保证IM域环的容量不会被其他消息占用,从而影响到消息同步。

PS:Lindorm是一种多模型的云原生数据库服务,具有成本低、自定义TTL、容量横向扩展等优势。

3)线上问题发现与恢复:

保障稳定性的关键要素是做好各种核心指标的监控,而监控首先要有数据来源,对服务端+客户端的关键链路节点埋点,基于集团UT、SLS,通过blink进行实时清洗、计算,最终形成统一规范的日志数据落至SLS,以供实时监控及链路排查。

消息系统的核心目标是保障用户消息发的出、收得到且及时收到,所以我们通过计算发送成功率、到达率、消息延迟来监控系统的稳定性。

此外,为了解决用户舆情排查困难的问题:

  • 1)我们设计了一套指令集,通过约定指令协议,服务端向指定用户下发指令,客户端执行对应指令进行异常数据上报,提高排查效率;
  • 2)扩展了强制全量同步、数据校正等指令,定向修复用户消息数据问题,相较以往出现严重bug只能让用户卸载重装解决,这种方式显然对用户是更友好的。

经过一系列专项治理,技术类舆情下降50%,从0到1建设了消息稳定性体系,用户体验进一步提升。

6、展望未来

闲鱼作为电商交易APP, 其中IM是交易的前置链路,IM的产品体验极大影响用户交易效率。

前段时间进行用户调研,从闲鱼IM的NPS低于预期(NPS是用户忠诚度衡量指标 = 推荐者%-贬损者%)。

从用户反馈来看:

  • 1)部分用户对产品功能有较强烈的诉求,诸如消息搜索、分组等;
  • 2)大部分用户对发送消息过程中的违规问题难以理解;
  • 3)仍有较多舆情反馈消息收不到或延迟。

映射到目前闲鱼的即时消息系统上,我们的系统架构依然有很多需要持续改进的地方。

典型的如:同步协议冗余,在需求迭代过程中容易引发问题、有效保活机制的缺失对消息即时送达的影响、小众机型离线消息收不到、多年的数据积累在线库臃肿等问题,影响着闲鱼业务迭代速度与NPS。

作为技术团队,下一步将提升NPS作为核心技术目标,闲鱼的即时消息系统4.0版架构正在路上 ......

附录:更多相关文章

[1] 更多阿里巴巴的技术资源:

阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处

现代IM系统中聊天消息的同步和存储方案探讨

阿里技术分享:深度揭秘阿里数据库技术方案的10年变迁史

阿里技术分享:阿里自研金融级数据库OceanBase的艰辛成长之路

来自阿里OpenIM:打造安全可靠即时通讯服务的技术实践分享

钉钉——基于IM技术的新一代企业OA平台的技术挑战(视频+PPT) [附件下载]

阿里技术结晶:《阿里巴巴Java开发手册(规约)-华山版》[附件下载]

重磅发布:《阿里巴巴Android开发手册(规约)》[附件下载]

作者谈《阿里巴巴Java开发手册(规约)》背后的故事

《阿里巴巴Android开发手册(规约)》背后的故事

干了这碗鸡汤:从理发店小弟到阿里P10技术大牛

揭秘阿里、腾讯、华为、百度的职级和薪酬体系

淘宝技术分享:手淘亿级移动端接入层网关的技术演进之路

难得干货,揭秘支付宝的2维码扫码技术优化实践之路

淘宝直播技术干货:高清、低延时的实时视频直播技术解密

阿里技术分享:电商IM消息平台,在群聊、直播场景下的技术实践

阿里技术分享:闲鱼IM基于Flutter的移动端跨端改造实践

阿里IM技术分享(三):闲鱼亿级IM消息系统的架构演进之路

 

[2] 有关IM架构设计的文章:

浅谈IM系统的架构设计

简述移动端IM开发的那些坑:架构设计、通信协议和客户端

一套海量在线用户的移动端IM架构设计实践分享(含详细图文)

一套原创分布式即时通讯(IM)系统理论架构方案

从零到卓越:京东客服即时通讯系统的技术架构演进历程

蘑菇街即时通讯/IM服务器开发之架构选择

腾讯QQ1.4亿在线用户的技术挑战和架构演进之路PPT

微信后台基于时间序的海量数据冷热分级架构设计实践

微信技术总监谈架构:微信之道——大道至简(演讲全文)

如何解读《微信技术总监谈架构:微信之道——大道至简》

快速裂变:见证微信强大后台架构从0到1的演进历程(一)

移动端IM中大规模群消息的推送如何保证效率、实时性?

现代IM系统中聊天消息的同步和存储方案探讨

微信朋友圈千亿访问量背后的技术挑战和实践总结

子弹短信光鲜的背后:网易云信首席架构师分享亿级IM平台的技术实践

微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践

社交软件红包技术解密(一):全面解密QQ红包技术方案——架构、技术实现等

从游击队到正规军(一):马蜂窝旅游网的IM系统架构演进之路

从游击队到正规军(二):马蜂窝旅游网的IM客户端架构演进和实践总结

从游击队到正规军(三):基于Go的马蜂窝旅游网分布式IM系统技术实践

瓜子IM智能客服系统的数据架构设计(整理自现场演讲,有配套PPT)

IM开发基础知识补课(九):想开发IM集群?先搞懂什么是RPC!

阿里技术分享:电商IM消息平台,在群聊、直播场景下的技术实践

一套亿级用户的IM架构技术干货(上篇):整体架构、服务拆分等

一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

从新手到专家:如何设计一套亿级消息量的分布式IM系统

企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等

融云技术分享:全面揭秘亿级IM消息的可靠投递机制

IM开发技术学习:揭秘微信朋友圈这种信息推流背后的系统设计

阿里IM技术分享(三):闲鱼亿级IM消息系统的架构演进之路

>> 更多同类文章 ……

本文已同步发布于“即时通讯技术圈”公众号。

同步发布链接是:http://www.52im.net/thread-3699-1-1.html 

posted @ 2021-09-13 15:12 Jack Jiang 阅读(320) | 评论 (0)编辑 收藏

     摘要: 本文引用自“ 豆米博客”的《JS实时通信三把斧》系列文章,有优化和改动。1、引言有关Web端即时通讯技术的文章我已整理过很多篇,阅读过的读者可能都很熟悉,早期的Web端即时通讯方案,受限于Web客户端的技术限制,想实现真正的“即时”通信,难度相当大。传统的Web端即时通讯技术从短轮询到长连询,再到Comet技术,在如此原始的HTML标准之下,为了实现...  阅读全文

posted @ 2021-09-07 10:47 Jack Jiang 阅读(181) | 评论 (0)编辑 收藏

本文由融云技术团队原创分享,原题“技术实践丨万人群聊的消息分发控速方案”,为使文章更好理解,内容有修订。

1、引言

传统意义上的IM群聊,通常都是像微信这样的500人群,或者QQ的2000人群(QQ有3000人群,但那是单独收费的,也就意味着它并非无门槛标配,能用上的人并不多)。

自从国外某号称“世界上最安全的IM”搞出万人群聊之后,万人群迅速被国内的使用者们接受。伴随着移动互联网的发展,即时通讯服务被广泛应用于各个行业(以经不再局限于传统IM社交应用领域),随着业务快速发展,传统百人、千人上限的群聊已经无法满足很多业务场景需求,所以万人甚至十万人的超大群也算是相伴而生、顺应潮流。 

▲ “纸飞机”的万人群(开发人员颤抖中...)

IM群聊一直是IM应用中比较有难度的热点技术之一,通常意义的群聊,无非就是500人群、1000人群、2000人群这样,技术实现上比单聊要复杂不少。然而对于万人群聊(甚至十万人群聊)来说,相比百人、千人群聊,技术实现上那几乎是另一个技术维度的事情,难度要高很多。

本文根据融云技术团队的实践经验,总结了万人群聊消息投递方案的一些思考和实践,希望能给你带来启发。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170 [推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK

(本文同步发布于:http://www.52im.net/thread-3687-1-1.html

2、相关文章

万人群聊有关的技术文章还可读一读以下这篇:

  1. 网易云信技术分享:IM中的万人群聊技术方案实践总结
  2. 企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等
  3. 阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处

融云技术团队分享的其它文章:

  1. 融云技术分享:融云安卓端IM产品的网络链路保活技术实践
  2. 融云技术分享:全面揭秘亿级IM消息的可靠投递机制
  3. 融云技术分享:基于WebRTC的实时音视频首帧显示时间优化实践
  4. IM消息ID技术专题(三):解密融云IM产品的聊天消息ID生成策略

3、超大群面临的技术挑战

与百人群、千人群相比,万人、甚至十万人超大群,大幅提升了群的触达人数,对于很多业务场景来说,好处不言而喻。

然而单群成员如此之大,给 IM 系统的流量冲击非常巨大,技术难度可想而之。我们先来分析一下超大群的技术挑战。

以一个万人群的模型为例:

  • 1)如果群中有人发了消息,那么这条消息需要按照 1:9999 的比例进行分发投递,如果我们按照常规消息的处理流程,那么消息处理服务压力巨大;
  • 2)消息量大的情况下,服务端向客户端直推消息的处理速度将会成为系统瓶颈,而一旦用户的消息下发队列造成了挤压,会影响到正常的消息分发,也会导致服务缓存使用量激增;
  • 3)在微服务架构中,服务以及存储(DB,缓存)之间的 QPS 和网络流量也会急剧增高;
  • 4)以群为单位的消息缓存,内存和存储开销较大(消息体的存储被放大了万倍)。

基于这些技术挑战,要想真正达成超大群的技术目标,势必要做特定的技术优化来应对。

4、一般群聊的消息投递模型

先来看看普通群聊的消息投递模型。

我们的普通群聊消息投递模型如下图所示:

如上图所示,当用户在普通群里发了一条消息后,投递路径是:

  • 1)消息先到群组服务;
  • 2)然后通过群组服务缓存的群关系,锁定这条消息最终需要分发的目标用户;
  • 3)再根据一定的策略分发到消息服务上;
  • 4)消息服务再根据用户的在线状态和消息状态来判断这条消息是直推、通知拉取还是转 Push,最终投递给目标用户。

普通群聊的消息投递,正像您期待的那样,基本上大家的实现手段都大差不差。然而对于万人群来说,这显然还不够。

下面来看看我们针对万人群聊消息投递的技术优化手段。

5、万人群聊消息投递优化手段1:控速

针对万人群的消息投递,我们的一个主要手段就是控速。

如上图所示。

首先:我们会根据服务器的核数来建立多个群消息分发队列,这些队列我们设置了不同的休眠时间以及不同的消费线程数。

通俗来讲,可以将队列这样划分为快、中、慢等队列。

其次:我们根据群成员数量的大小来将所有群映射到相应的队列中。

规则是:

  • 1)小群映射到快队列中;
  • 2)大群映射到相应的慢队列中。

然后:小群由于人数少,对服务的影响很小,所以服务利用快队列快速的将群消息分发出去,而大群群消息则利用慢队列的相对高延时来起到控速的作用。

6、万人群聊消息投递优化手段2:合并

在本文第3节中提到的万人群聊所面临的技术挑战,最主要的挑战其实就是消息进行扩散分发投递后,消息被克隆出N条,消息流量瞬间被放大。

举个例子:当一条群消息发送到 IM 服务器后,需要从群组服务投递给消息服务,如果每一个群成员都投递一次,并且投递的群消息内容是一致的话,那肯定会造成相应的资源浪费和服务压力。

那么针对这种情况,我们的解决方案就是进行消息合并投递。

原理就是:服务落点计算中我们使用的是一致性哈希,群成员落点相对固定,所以落点一致的群成员我们可以合并成一次请求进行投递,这样就大幅提高了投递效率同时减少了服务的压力。

下图是云信团队分享的万人群消息合并投递逻辑:

▲ 上图引用自《IM中的万人群聊技术方案实践总结

如上图所示,云信团队的万人群消息合并投递方案是:按Link分组路由消息,同一Link上的全部群成员只需要路由一条消息即可。

7、十万、百万级的超大群处理方案

在实际群聊业务中,还有一种业务场景是超大规模群,这种群的群人数达到了数十万甚至上百万。

这种群如果按照上述的投投递方案,势必仍会造成消息节点的巨大压力。

比如我们有一个十万人的群,消息节点五台,消息服务处理消息的上限是一秒钟 4000 条,那每台消息节点大约会分到 2 万条群消息,这已大大超出了消息节点的处理能力。

所以为了避免上述问题,我们会将群成员上线超过3000的群识别为万人群、超级群,这种级别的群可以根据服务器数量和服务器配置相应做调整针对这种超级群会用特殊的队列来处理群消息的投递。

这个特殊的队列1秒钟往后端消息服务投递的消息数是消息服务处理上限的一半(留相应的能力处理其他消息),如果单台消息服务处理的 QPS 上限是 4000,那群组服务一秒往单台消息服务最多投递 2000 条。

8、写在最后

未来,我们也会针对群消息进行引用投递,对于大群里发的消息体比较大的消息,我们给群成员只分发和缓存消息的索引,比如 MessageID。等群成员真正拉取群消息时再从将消息组装好给客户端分发下去。这样做会节省分发的流量以及存储的空间。

随着互联网的发展,群组业务的模型和压力也在不停地扩展,后续可能还会遇到更多的挑战,当然也会不断迭代出更优的处理方式来应对。

附录:更多IM群聊技术文章

快速裂变:见证微信强大后台架构从0到1的演进历程(一)

如何保证IM实时消息的“时序性”与“一致性”?

IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?

IM群聊消息如此复杂,如何保证不丢不重?

微信后台团队:微信后台异步消息队列的优化升级实践分享

移动端IM中大规模群消息的推送如何保证效率、实时性?

现代IM系统中聊天消息的同步和存储方案探讨

关于IM即时通讯群聊消息的乱序问题讨论

IM群聊消息的已读回执功能该怎么实现?

IM群聊消息究竟是存1份(即扩散读)还是存多份(即扩散写)?

一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践

[技术脑洞] 如果把14亿中国人拉到一个微信群里技术上能实现吗?

IM群聊机制,除了循环去发消息还有什么方式?如何优化?

网易云信技术分享:IM中的万人群聊技术方案实践总结

阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处

IM群聊消息的已读未读功能在存储空间方面的实现思路探讨

直播系统聊天技术(一):百万在线的美拍直播弹幕系统的实时推送技术实践之路

直播系统聊天技术(二):阿里电商IM消息平台,在群聊、直播场景下的技术实践

直播系统聊天技术(三):微信直播聊天室单房间1500万在线的消息架构演进之路

直播系统聊天技术(四):百度直播的海量用户实时消息系统架构演进实践

企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等

融云IM技术分享:万人群聊消息投递方案的思考和实践

>> 更多同类文章 ……

本文已同步发布于“即时通讯技术圈”公众号。

同步发布链接是:http://www.52im.net/thread-3687-1-1.html

posted @ 2021-08-30 11:34 Jack Jiang 阅读(194) | 评论 (0)编辑 收藏

     摘要: 本文由微医云技术团队前端工程师张宇航分享,原题“从0到1打造一个 WebRTC 应用”,有修订和改动。1、引言去年初,突如其来的新冠肺炎疫情让线下就医渠道几乎被切断,在此背景下,在线问诊模式快速解决了大量急需就医病患的燃眉之急。而作为在线问诊中重要的一环——医患之间的视频问诊正是应用了实时音视频技术才得以实现。众所周之,实时音视频聊天技术门槛很高,一...  阅读全文

posted @ 2021-08-24 12:24 Jack Jiang 阅读(307) | 评论 (0)编辑 收藏

本文由徐宁发表于腾讯大讲堂,原题“程序员如何把你关注的内容推送到你眼前?揭秘信息流推荐背后的系统设计”,有改动和修订。

1、引言

信息推流(以下简称“Feed流”)这种功能在我们手机APP中几乎无处不在(尤其是社交/社群产品中),最常用的就是微信朋友圈、新浪微博等。

对Feed流的定义,可以简单理解为只要大拇指不停地往下划手机屏幕,就有一条条的信息不断涌现出来。就像给牲畜喂饲料一样,只要它吃光了就要不断再往里加,故此得名Feed(饲养)。

大多数带有Feed流功能的产品都包含两种Feed流:

  • 1)一种是基于算法:即动态算法推荐,比如今日头条、抖音短视频;
  • 2)一种是基于关注:即社交/好友关系,比如微信、知乎。

例如下图中的微博和知乎,顶栏的页卡都包含“关注”和“推荐”这两种:

如上图中这两种Feed流,它们背后用到的技术差别会比较大。不同于“推荐”页卡那种千人千面算法推荐的方式,通常“关注”页卡所展示的内容先后顺序都有固定的规则,最常见的规则是基于时间线来排序,也就是展示“我关注的人所发的帖子、动态、心情,根据发布时间从晚到早依次排列”。

本文将重点讨论的是“关注”功能对应的技术实现:先总结常用的基于时间线Feed流的后台技术实现方案,再结合具体的业务场景,根据实际需求在基本设计思路上做一些灵活的运用。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170 [推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK

(本文同步发布于:http://www.52im.net/thread-3675-1-1.html

2、本文作者

徐宁:腾讯应用开发工程师,腾讯学院讲师,毕业于上海交通大学。目前负责腾讯智慧零售业务的后端开发工作,有丰富的视频直播,自动化营销系统开发经验。

3、Feed流技术实现方案1:读扩散

读扩散也称为“拉模式”,这应该是最符合我们认知直觉的一种技术实现方式。

原理如下图:

如上图所示:每一个内容发布者都有一个自己的发件箱(“我发布的内容”),每当我们发出一个新帖子,都存入自己的发件箱中。当我们的粉丝来阅读时,系统首先需要拿到粉丝关注的所有人,然后遍历所有发布者的发件箱,取出他们所发布的帖子,然后依据发布时间排序,展示给阅读者。

这种设计:阅读者读一次Feed流,后台会扩散为N次读操作(N等于关注的人数)以及一次聚合操作,因此称为读扩散。每次读Feed流相当于去关注者的收件箱主动拉取帖子,因此也得名——拉模式。

这种模式:

  • 1)好处是:底层存储简单,没有空间浪费;
  • 2)坏处是:每次读操作会非常重,操作非常多。

设想一下:如果我关注的人数非常多,遍历一遍我所关注的所有人,并且再聚合一下,这个系统开销会非常大,时延上可能达到无法忍受的地步。

因此:读扩散主要适用系统中阅读者关注的人没那么多,并且刷Feed流并不频繁的场景。

拉模式还有一个比较大的缺点:就是分页不方便,我们刷微博或朋友圈,肯定是随着大拇指在屏幕不断划动,内容一页一页的从后台拉取。如果不做其他优化,只采用实时聚合的方式,下滑到比较靠后的页码时会非常麻烦。

4、Feed流技术实现方案2:写扩散

据统计:大多数Feed流产品的读写比大概在100:1,也就是说大部分情况都是刷Feed流看别人发的朋友圈和微博,只有很少情况是自己亲自发一条朋友圈或微博给别人看。

因此:读扩散那种很重的读逻辑并不适合大多数场景。

我们宁愿让发帖的过程复杂一些,也不愿影响用户读Feed流的体验,因此稍微改造一下前面方案就有了写扩散。写扩散也称为“推模式”,这种模式会对拉模式的一些缺点做改进。

原理如下图:

如上图所示:系统中每个用户除了有发件箱,也会有自己的收件箱。当发布者发表一篇帖子的时候,除了往自己发件箱记录一下之外,还会遍历发布者的所有粉丝,往这些粉丝的收件箱也投放一份相同内容。这样阅读者来读Feed流时,直接从自己的收件箱读取即可。

这种设计:每次发表帖子,都会扩散为M次写操作(M等于自己的粉丝数),因此成为写扩散。每篇帖子都会主动推送到所有粉丝的收件箱,因此也得名推模式。

这种模式可想而知:发一篇帖子,背后会涉及到很多次的写操作。通常为了发帖人的用户体验,当发布的帖子写到自己发件箱时,就可以返回发布成功。后台另外起一个异步任务,不慌不忙地往粉丝收件箱投递帖子即可。

写扩散的好处在于通过数据冗余(一篇帖子会被存储M份副本),提升了阅读者的用户体验。通常适当的数据冗余不是什么问题,但是到了微博明星这里,完全行不通。比如目前微博粉丝量Top2的谢娜与何炅,两个人微博粉丝过亿。

设想一下:如果单纯采用推模式,那每次谢娜何炅发一条微博,微博后台都要地震一次。一篇微博导致后台上亿次写操作,这显然是不可行的。

另外:由于写扩散是异步操作,写的太慢会导致帖子发出去半天,有些粉丝依然没能看见,这种体验也不太好。

通常写扩散适用于好友量不大的情况,比如微信朋友圈正是写扩散模式。每一名微信用户的好友上限为5000人,也就是说你发一条朋友圈最多也就扩散到5000次写操作,如果异步任务性能好一些,完全没有问题。

关于微信朋友圈的技术资料:

5、Feed流技术实现方案2:读写混合模式

读写混合也可以称作“推拉结合”,这种方式可以兼具读扩散和写扩散的优点。

我们首先来总结一下读扩散和写扩散的优缺点:

见上图:仔细比较一下读扩散与写扩散的优缺点,不难发现两者的适用场景是互补的。

因此:在设计后台存储的时候,我们如果能够区分一下场景,在不同场景下选择最适合的方案,并且动态调整策略,就实现了读写混合模式。

原理如下图:

以微博为例:当何炅这种粉丝量超大的人发帖时,将帖子写入何炅的发件箱,另外提取出来何炅粉丝当中比较活跃的那一批(这已经可以筛掉大部分了),将何炅的帖子写入他们的收件箱。当一个粉丝量很小的路人甲发帖时,采用写扩散方式,遍历他的所有粉丝并将帖子写入粉丝收件箱。

对于那些活跃用户登录刷Feed流时:他直接从自己的收件箱读取帖子即可,保证了活跃用户的体验。

当一个非活跃的用户突然登录刷Feed流时:

  • 1)一方面需要读他的收件箱;
  • 2)另一面需要遍历他所关注的大V用户的发件箱提取帖子,并且做一下聚合展示。

在展示完后:系统还需要有个任务来判断是否有必要将该用户升级为活跃用户。

因为有读扩散的场景存在,因此即使是混合模式,每个阅读者所能关注的人数也要设置上限,例如新浪微博限制每个账号最多可以关注2000人。

如果不设上限:设想一下有一位用户把微博所有账号全部关注了,那他打开关注列表会读取到微博全站所有帖子,一旦出现读扩散,系统必然崩溃(即使是写扩散,他的收件箱也无法容纳这么多的微博)。

读写混合模式下,系统需要做两个判断:

  • 1)哪些用户属于大V,我们可以将粉丝量作为一个判断指标;
  • 2)哪些用户属于活跃粉丝,这个判断标准可以是最近一次登录时间等。

这两处判断标准就需要在系统发展过程中动态地识别和调整,没有固定公式了。

可以看出:读写结合模式综合了两种模式的优点,属于最佳方案。

然而他的缺点是:系统机制非常复杂,给程序员带来无数烦恼。通常在项目初期,只有一两个开发人员,用户规模也很小的时候,一步到位地采用这种混合模式还是要慎重,容易出bug。当项目规模逐渐发展到新浪微博的水平,有一个大团队专门来做Feed流时,读写混合模式才是必须的。

6、Feed流中的分页问题

上面几节已经叙述了基于时间线的几种Feed流常见设计方案,但实操起来会比理论要麻烦许多。

接下来专门讨论一个Feed流技术方案中的痛点——Feed流的分页。

不管是读扩散还是写扩散,Feed流本质上是一个动态列表,列表内容会随着时间不断变化。传统的前端分页参数使用page_size和page_num,分表表示每页几条,以及当前是第几页。

对于一个动态列表会有如下问题:

如上图所示:在T1时刻读取了第一页,T2时刻有人新发表了“内容11”,在T3时刻如果来拉取第二页,会导致错位出现,“内容6”在第一页和第二页都被返回了。事实上,但凡两页之间出现内容的添加或删除,都会导致错位问题。

为了解决这一问题:通常Feed流的分页入参不会使用page_size和page_num,而是使用last_id来记录上一页最后一条内容的id。前端读取下一页的时候,必须将last_id作为入参,后台直接找到last_id对应数据,再往后偏移page_size条数据,返回给前端,这样就避免了错位问题。

如下图:

采用last_id的方案有一个重要条件:就是last_id本身这条数据不可以被硬删除。

设想一下:

  • 1)上图中T1时刻返回5条数据,last_id为内容6;
  • 2)T2时刻内容6被发布者删除;
  • 3)那么T3时刻再来请求第二页,我们根本找不到last_id对应的数据了,也就无法确认分页偏移量。

通常碰到删除的场景:我们采用软删除方式,只是在内容上置一个标志位,表示内容已删除。

由于已经删除的内容不应该再返回给前端,因此软删除模式下,找到last_id并往后偏移page_size条,如果其中有被删除的数据会导致获得足够的数据条数给前端。

这里一个解决方案是找不够继续再往下找,另一种方案是与前端协商,允许返回条数少于page_size条,page_size只是个建议值。甚至大家约定好了以后,可以不要page_size参数。

7、Feed流技术方案在某直播应用中的实践

7.1 需求背景

本节将结合实际业务,分享一下实际场景中碰到的一个非常特殊的Feed流设计方案。

xx 直播是一款直播带货工具,主播可以创建一场未来时刻的直播,到时间后开播卖货,直播结束后,主播的粉丝可以查看直播回放。

这样,每个直播场次就有三种状态——预告中(创建一场直播但还未开播)、直播中、回放。

作为观众,我可以关注多位主播,这样从粉丝视角来看,也会有个直播场次的Feed流页面。

这个Feed流最特殊的地方在于它的排序规则:

解释一下这个Feed流排序规则:

  • 1)我关注的所有主播:正在直播中的场次排在最前;预告中的场次排中间;回放场次排最后;
  • 2)多场次都在直播中的:按开播时间从晚到早排序;
  • 3)多场次都在预告中的:按预计开播时间从早到晚排序;
  • 4)多场次都在回放的:按直播结束时间从晚到早排序。

7.2 问题分析

本需求最复杂的点在于Feed流内容融入的“状态”因素,状态的转变会直接导致Feed流顺序不同。

为了更清晰解释一下对排序的影响,我们可以用下图详细说明:

上图中:展示了4个主播的5个直播场次,作为观众,当我在T1时刻打开页面,看到的顺序是场次3在最上方,其余场次均在预告状态,按照预计开播时间从早到晚展示。当我在T2时刻打开页面,场次5在最上方,其余有三场在预告状态排在中间,场次3已经结束了所以排在最后。以此类推,直到所有直播都结束,所有场次最终的状态都会变为回放。

这里需要注意一点:如果我在T1时刻打开第一页,然后盯着页面不动,一直盯到T4时刻再下划到第二页,这时上一页的last_id,即分页偏移量很有可能因为直播状态变化而不知道飞到了什么位置,这会导致严重的错位问题,以及直播状态展示不统一的问题(第一页展示的是T1时刻的直播状态,第二页展示的是T4时刻的直播状态)。

7.3 解决方案

直播系统是个单向关系链,和微博有些类似,每个观众会关注少量主播,每个主播会可能有非常多的关注者。

由于有状态变化的存在,写扩散几乎无法实现。

因为:如果采用写扩散的方式,每次主播创建直播、直播开播、直播结束这三个事件发生时导致的场次状态变化,会扩散为非常多次的写操作,不仅操作复杂,时延上也无法接受。

微博之所以可以写扩散:就是因为一条微博发出后,这篇微博就不会再有任何影响排序的状态转变。

而在我们场景中:“预告中”与“直播中”是两个中间态,而“回放”状态才是所有直播的最终归宿,一旦进入回放,这场直播也就不会再有状态转变。因此“直播中”与“预告中”状态可以采用读扩散方式,“回放”状态采取写扩散方式。

最终的方案如下图所示:

如上图:会影响直播状态的三种事件(创建直播、开播、结束直播)全部采用监听队列异步处理。

我们为每一位主播维护一个直播中+预告中状态的优先级队列:

  • 1)每当监听到有主播创建直播时,将直播场次加入队列中,得分为开播的时间戳的相反数(负数);
  • 2)每当监听到有主播开播时,把这场直播在队列中的得分修改为开播时间(正数);
  • 3)每当监听到有主播结束直播,则异步地将播放信息投递到每个观众的回放队列中。

这里有一个小技巧:前文提到,直播中状态按照开播时间从大到小排序,而预告中状态则按照开播时间从小到大排序,因此如果将预告中状态的得分全部取开播时间相反数,那排序同样就成为了从大到小。这样的转化可以保证直播中与预告中同处于一个队列排序。预告中得分全都为负数,直播中得分全都为正数,最后聚合时可以保证所有直播中全都自然排在预告中前面。

另外:前文还提到的另一个问题是T1时刻拉取第一页,T4时刻拉取第二页,导致第一页和第二页直播间状态不统一。

解决这个问题的办法是通过快照方式:当观众来拉取第一页Feed流时,我们依据当前时间,将全部直播中和预告中状态的场次建立一份快照,使用一个session_id标识,每次前端分页拉取时,我们直接从快照中读取即可。如果快照中读取完毕,证明该观众的直播中和预告中场次全部读完,剩下的则使用回放队列进行补充。

照此一来,我们的Feed流系统,前端分页拉取的参数一共有4个:

每当碰到session_id和last_id为空,则证明用户想要读取第一页,需要重新构建快照。

这里还有一个衍生问题:session_id的如何取值?

答案是:

  • 1)如果不考虑同一个观众在多端登录的情况,其实每一位观众维护一个快照id即可,也就是直接将系统用户id设为session_id;
  • 2)如果考虑多端登录的情况,则session_id中必须包含每个端的信息,以避免多端快照相互影响;
  • 3)如果不心疼内存,也可以每次随机一个字符串作为session_id,并设置一个足够长的过期时间,让快照自然过期。

以上设计:其实系统计算量最大的时刻就是拉取第一页,构建快照的开销。

目前的线上数据,对于只关注不到10个主播的观众(这也是大多数场景),拉取第一页的QPS可以达到1.5万。如果将第二页以后的请求也算进来,Feed流的综合QPS可以达到更高水平,支撑目前的用户规模已经绰绰有余。如果我们拉取第一页时只获取到前10条即可直接返回,将构建快照操作改为异步,也许QPS可以更高一些,这可能是后续的优化点。

8、本文小结

几乎所有基于时间线和关注关系的Feed流都逃不开三种基本设计模式:

  • 1)读扩散;
  • 2)写扩散;
  • 3)读写混合。

具体到实际业务中,可能会有更复杂的场景,比如本文所说的:

  • 1)状态流转影响排序;
  • 2)微博朋友圈场景中会有广告接入、特别关注、热点话题等可能影响到Feed流排序的因素。

这些场景就只能根据业务需求,做相对应的变通了。

附录:更多社交应用架构设计文章

  1. 浅谈IM系统的架构设计
  2. 简述移动端IM开发的那些坑:架构设计、通信协议和客户端
  3. 一套海量在线用户的移动端IM架构设计实践分享(含详细图文)
  4. 一套原创分布式即时通讯(IM)系统理论架构方案
  5. 从零到卓越:京东客服即时通讯系统的技术架构演进历程
  6. 蘑菇街即时通讯/IM服务器开发之架构选择
  7. 腾讯QQ1.4亿在线用户的技术挑战和架构演进之路PPT
  8. 微信后台基于时间序的海量数据冷热分级架构设计实践
  9. 微信技术总监谈架构:微信之道——大道至简(演讲全文)
  10. 如何解读《微信技术总监谈架构:微信之道——大道至简》
  11. 快速裂变:见证微信强大后台架构从0到1的演进历程(一)
  12. 移动端IM中大规模群消息的推送如何保证效率、实时性?
  13. 现代IM系统中聊天消息的同步和存储方案探讨
  14. 微信朋友圈千亿访问量背后的技术挑战和实践总结
  15. 以微博类应用场景为例,总结海量社交系统的架构设计步骤
  16. 子弹短信光鲜的背后:网易云信首席架构师分享亿级IM平台的技术实践
  17. 知乎技术分享:从单机到2000万QPS并发的Redis高性能缓存实践之路
  18. 微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)
  19. 微信技术分享:微信的海量IM聊天消息序列号生成实践(容灾方案篇)
  20. 一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践
  21. 社交软件红包技术解密(一):全面解密QQ红包技术方案——架构、技术实现等
  22. 社交软件红包技术解密(二):解密微信摇一摇红包从0到1的技术演进
  23. 社交软件红包技术解密(三):微信摇一摇红包雨背后的技术细节
  24. 社交软件红包技术解密(四):微信红包系统是如何应对高并发的
  25. 社交软件红包技术解密(五):微信红包系统是如何实现高可用性的
  26. 社交软件红包技术解密(六):微信红包系统的存储层架构演进实践
  27. 社交软件红包技术解密(七):支付宝红包的海量高并发技术实践
  28. 社交软件红包技术解密(八):全面解密微博红包技术方案
  29. 社交软件红包技术解密(九):谈谈手Q红包的功能逻辑、容灾、运维、架构等
  30. 从游击队到正规军(一):马蜂窝旅游网的IM系统架构演进之路
  31. 从游击队到正规军(二):马蜂窝旅游网的IM客户端架构演进和实践总结
  32. 从游击队到正规军(三):基于Go的马蜂窝旅游网分布式IM系统技术实践
  33. 瓜子IM智能客服系统的数据架构设计(整理自现场演讲,有配套PPT)
  34. 阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处
  35. 微信后台基于时间序的新一代海量数据存储架构的设计实践
  36. 阿里技术分享:电商IM消息平台,在群聊、直播场景下的技术实践
  37. 一套亿级用户的IM架构技术干货(上篇):整体架构、服务拆分等
  38. 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等
  39. 从新手到专家:如何设计一套亿级消息量的分布式IM系统
  40. 企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等
  41. 融云技术分享:全面揭秘亿级IM消息的可靠投递机制
  42. IM开发技术学习:揭秘微信朋友圈这种信息推流背后的系统设计
  43. >> 更多同类文章 ……

本文已同步发布于“即时通讯技术圈”公众号。

同步发布链接是:http://www.52im.net/thread-3675-1-1.html

posted @ 2021-08-17 15:34 Jack Jiang 阅读(179) | 评论 (0)编辑 收藏

     摘要: 本文由美团技术团队分享,作者“健午、佳猛、陆凯、冯江”,原题“美团终端消息投递服务Pike的演进之路”,有修订。1、引言传统意义上来说,实时消息推送通常都是IM即时通讯这类应用的技术范畴,随着移动端互联网的普及,人人拥有手机、随时都是“在线”已属常态,于是消息的实时触达能力获得了广泛的需求,已经不再局限于IM即时通讯这类应用中...  阅读全文

posted @ 2021-08-09 15:36 Jack Jiang 阅读(238) | 评论 (0)编辑 收藏

1、引言

在IM客户端的使用场景中,基于本地数据的全文检索功能扮演着重要的角色,最常用的比如:查找聊天记录、联系人,就像下图这样。

▲ 微信的聊天记录查找功能

类似于IM中的聊天记录查找、联系人搜索这类功能,有了全文检索能力后,确实能大大提高内容查找的效率,不然,让用户手动翻找,确实降低了用户体验。

本文将具体来聊聊网易云信是如何实现IM客户端全文检索能力的,希望能带给你启发。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170 [推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK

(本文同步发布于:http://www.52im.net/thread-3651-1-1.html

2、关于作者

李宁:网易云信高级前端开发工程师,负责音视频 IM SDK 的应用开发、组件化开发及解决方案开发,对 React、PaaS 组件化设计、多平台的开发与编译有丰富的实战经验。

3、相关文章

IM客户端全文检索相关文章:

  1. 微信手机端的本地数据全文检索优化之路
  2. 微信团队分享:微信移动端的全文检索多音字问题解决方案

网易技术团队分享的其它文章:

  1. 网易视频云技术分享:音频处理与压缩技术快速入门
  2. 网易云信实时视频直播在TCP数据传输层的一些优化思路
  3. 网易云信技术分享:IM中的万人群聊技术方案实践总结
  4. Web端即时通讯实践干货:如何让你的WebSocket断网重连更快速?
  5. 子弹短信光鲜的背后:网易云信首席架构师分享亿级IM平台的技术实践

4、什么是全文检索

所谓全文检索,就是要在大量内容中找到包含某个单词出现位置的技术。

在传统的关系型数据库中,只能通过 LIKE 条件查询来实现,这样有几个弊端:

  • 1)无法使用数据库索引,需要遍历全表,性能较差;
  • 2)搜索效果差,只能首尾位模糊匹配,无法实现复杂的搜索需求;
  • 3)无法得到内容与搜索条件的相关性。

我们在 IM 的 iOS、安卓以及桌面端中都实现了基于 SQLite 等库的本地数据全文检索功能,但是在 Web 端和 Electron 上缺少了这部分功能。

因为在 Web 端,由于浏览器环境限制,能使用的本地存储数据库只有 IndexDB,暂不在讨论的范围内。但在 Electron 上,虽然也是内置了 Chromium 的内核,但是因为可以使用 Node.js 的能力,于是乎选择的范围就多了一些。本文内容我们具体以基于Electron的IM客户端为例,来讨论全文检索技术实现(技术思路是相通的,并不局限于具体什么端)。

PS:如果你不了解什么是Electron技术,读一下这篇《快速了解Electron:新一代基于Web的跨平台桌面技术》。

我们先来具体看下该如何实现全文检索。

要实现全文检索,离不开以下两个知识点:

  • 1)倒排索引;
  • 2)分词。

这两个技术是实现全文检索的技术以及难点,其实现的过程相对比较复杂,在聊全文索引的实现前,我们具体学习一下这两个技术的原理。

5、全文检索知识点1:倒排索引

先简单介绍下倒排索引,倒排索引的概念区别于正排索引:

  • 1)正排索引:是以文档对象的唯一 ID 作为索引,以文档内容作为记录的结构;
  • 2)倒排索引:是以文档内容中的单词作为索引,将包含该词的文档 ID 作为记录的结构。

以倒排索引库 search-index 举个实际的例子:

在我们的 IM 中,每条消息对象都有 idClient 作为唯一 ID,接下来我们输入「今天天气真好」,将其每个中文单独分词(分词的概念我们在下文会详细分享),于是输入变成了「今」、「天」、「天」、「气」、「真」、「好」。再通过 search-index 的 PUT 方法将其写入库中。

最后看下上述例子存储内容的结构:

如是图所示:可以看到倒排索引的结构,key 是分词后的单个中文、value 是包含该中文消息对象的 idClient 组成的数组。

当然:search-index 除了以上这些内容,还有一些其他内容,例如 Weight、Count 以及正排的数据等,这些是为了排序、分页、按字段搜索等功能而存在的,本文就不再细细展开了。

6、全文检索知识点2:分词

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.6 HMM 隐式马尔科夫模型

对于未登陆词,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、本文小结

本文中,我们便基于 Nodejieba 和 search-index 在 Electron 上实现了IM聊天消息的全文检索,加快了聊天记录的搜索速度。

当然,后续我们还会针对以下方面做更多的优化,比如以下两点:

1)写入性能 :在实际的使用中,发现当数据量大了以后,search-index 依赖的底层数据库 levelDB 会存在写入性能瓶颈,并且 CPU 和内存的消耗较大。经过调研,SQLite 的写入性能相对要好很多,从观测来看,写入速度只与数据量成正比,CPU 和内存也相对稳定,因此,后续可能会考虑用将 SQLite 编译成 Node 原生模块来替换 search-index。

2)可扩展性 :目前对于业务逻辑的解耦还不够彻底。倒排索引库当中存储了某些业务字段。后续可以考虑倒排索引库只根据关键字查找消息对象的 idClient,将带业务属性的搜索放到 indexDB 中,将倒排索引库与主业务库彻底解耦。

以上,就是本文的全部分享,希望我的分享能对大家有所帮助。

附录:更多IM干货技术文章

新手入门一篇就够:从零开发移动端IM

从客户端的角度来谈谈移动端IM的消息可靠性和送达机制

移动端IM中大规模群消息的推送如何保证效率、实时性?

移动端IM开发需要面对的技术问题

IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

IM消息送达保证机制实现(二):保证离线消息的可靠投递

如何保证IM实时消息的“时序性”与“一致性”?

一个低成本确保IM消息时序的方法探讨

IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?

IM群聊消息如此复杂,如何保证不丢不重?

谈谈移动端 IM 开发中登录请求的优化

移动端IM登录时拉取数据如何作到省流量?

浅谈移动端IM的多点登录和消息漫游原理

完全自已开发的IM该如何设计“失败重试”机制?

通俗易懂:基于集群的移动端IM接入层负载均衡方案分享

微信对网络影响的技术试验及分析(论文全文)

微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

自已开发IM有那么难吗?手把手教你自撸一个Andriod版简易IM (有源码)

融云技术分享:解密融云IM产品的聊天消息ID生成策略

适合新手:从零开发一个IM服务端(基于Netty,有完整源码)

拿起键盘就是干:跟我一起徒手开发一套分布式IM系统

适合新手:手把手教你用Go快速搭建高性能、可扩展的IM系统(有源码)

IM里“附近的人”功能实现原理是什么?如何高效率地实现它?

IM消息ID技术专题(一):微信的海量IM聊天消息序列号生成实践(算法原理篇)

IM开发宝典:史上最全,微信各种功能参数和逻辑规则资料汇总

IM开发干货分享:我是如何解决大量离线消息导致客户端卡顿的

零基础IM开发入门(一):什么是IM系统?

零基础IM开发入门(二):什么是IM系统的实时性?

零基础IM开发入门(三):什么是IM系统的可靠性?

零基础IM开发入门(四):什么是IM系统的消息时序一致性?

一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

IM扫码登录技术专题(三):通俗易懂,IM扫码登录功能详细原理一篇就够

理解IM消息“可靠性”和“一致性”问题,以及解决方案探讨

阿里技术分享:闲鱼IM基于Flutter的移动端跨端改造实践

融云技术分享:全面揭秘亿级IM消息的可靠投递机制

IM开发干货分享:如何优雅的实现大量离线消息的可靠投递

IM开发干货分享:有赞移动端IM的组件化SDK架构设计实践

IM开发干货分享:网易云信IM客户端的聊天消息全文检索技术实践

>> 更多同类文章 ……

(本文同步发布于:http://www.52im.net/thread-3651-1-1.html

posted @ 2021-08-03 12:42 Jack Jiang 阅读(286) | 评论 (0)编辑 收藏

本文由融云技术团队原创分享,原题“IM 消息同步机制全面解析”,为使文章更好理解,对内容进行了重新归纳和细节修订。

1、内容概述

即时通讯(IM)系统最基础、最重要的是消息的及时性与准确性,及时体现在延迟,准确则具体表现为不丢、不重、不乱序。

综合考虑业务场景、系统复杂度、网络流量、终端能耗等,我们的亿级分布式IM消息系统精心设计了消息收发机制,并不断打磨优化,形成了现在的消息可靠投递机制。

整体思路就是:

  • 1)客户端、服务端共同配合,互相补充;
  • 2)采用多重机制,从不同层面保障;
  • 3)拆分上下行,分别处理。

本文根据融云亿级IM消息系统的技术实践,总结了分布式IM消息的可靠投递机制,希望能为你的IM开发和知识学习起到抛砖引玉的作用。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170 [推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK

(本文已同步发布于:http://www.52im.net/thread-3638-1-1.html

2、推荐阅读

以下是相关文章汇总,有兴趣可以一并阅读:

零基础IM开发入门(二):什么是IM系统的实时性?

零基础IM开发入门(三):什么是IM系统的可靠性?

零基础IM开发入门(四):什么是IM系统的消息时序一致性?

IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

IM消息送达保证机制实现(二):保证离线消息的可靠投递

IM开发干货分享:如何优雅的实现大量离线消息的可靠投递

理解IM消息“可靠性”和“一致性”问题,以及解决方案探讨

如何保证IM实时消息的“时序性”与“一致性”?

IM群聊消息如此复杂,如何保证不丢不重?

从客户端的角度来谈谈移动端IM的消息可靠性和送达机制

一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

从新手到专家:如何设计一套亿级消息量的分布式IM系统

浅谈移动端IM的多点登录和消息漫游原理

完全自已开发的IM该如何设计“失败重试”机制?

IM开发干货分享:我是如何解决大量离线消息导致客户端卡顿的

以下是融云技术团队分享的其它文章:

IM消息ID技术专题(三):解密融云IM产品的聊天消息ID生成策略

融云技术分享:基于WebRTC的实时音视频首帧显示时间优化实践

融云技术分享:融云安卓端IM产品的网络链路保活技术实践

即时通讯云融云CTO的创业经验分享:技术创业,你真的准备好了?

3、客户端与服务端消息交互整体原理

3.1 概述

一个完整的IM消息交互逻辑,通常会为两段:

  • 1)消息上行段:即由消息发送者通过IM实时通道发送给服务端;
  • 2)消息下行段:由服务端按照一定的策略送达给最终的消息接收人。

3.2 消息上行段

消息上行段主要就是依赖IM的实时通道将消息传递给服务端。

这个阶段的消息可靠投递,需要从协议层进行保证,协议层需要提供可靠、有序的双向字节流传输,我们是通过自研的通信协议 RMTP(即 RongCloud Message Transfer Protocol)实现的。

客户端与服务端之间使用长连接,基于 RMTP 协议传输数据。

RMTP协议交互示意图:

如上图所示,协议层通过 QoS、 ACK 等机制,保证IM消息上行段数据传输的可靠性。

3.3 消息下行段

经过总结,消息下行段主要有三种行为。

1)客户端主动拉取消息,主动拉取有两个触发方式:

  • ① 拉取离线消息:与 IM 服务新建立连接成功,用于获取不在线的这段时间未收到的消息;
  • ② 定时拉取消息:在客户端最后收到消息后启动定时器,比如 3-5 分钟执行一次。主要有两个目的,一个是用于防止因网络、中间设备等不确定因素引起的通知送达失败,服务端客户端状态不一致,一个是可通过本次请求,对业务层做状态机保活。

2)服务端主动-发送消息(直发消息):

这是在线消息发送机制之一,简单理解为服务端将消息内容直接发送给客户端,适用于消息频率较低,并且持续交互,比如二人或者群内的正常交流讨论。

3)服务端主动-发送通知(通知拉取):

这是在线消息发送机制之一,简单理解为服务端给客户端发送一个通知,通知包含时间戳等可作为排序索引的内容,客户端收到通知后,依据自身数据,对比通知内时间戳,发起拉取消息的流程。

这种场景适用于较多消息传递:比如某人有很多大规模的群,每个群内都有很多成员正在激烈讨论。通过通知拉取机制,可以有效的减少客户端服务端网络交互次数,并且对多条消息进行打包,提升有效数据载荷。既能保证时效,又能保证性能。

客户端服务端下行段消息交互示意图:

4、客户端与服务端消息交互具体实现

正如上节所言,我们将消息的交互流程进行了拆分:即拆分出上下行。

4.1 上行

在上行过程保证发送消息顺序,为了保证消息有序, 最好的方式是按照 userId 区分,然后使用时间戳排序。那么分布式部署情况下,将用户归属到固定的业务服务器上(PS:指的是同一账号的不同端固定连接到相同的业务服务器上),会使得上行排序变得更容易。同时归属到同一个服务器,在多端维护时也更容易。

客户端连接过程:

  • 1)客户端通过 APP server ,获取到连接使用的 token;
  • 2)客户端使用 token 通过导航服务,获取具体连接的 IM 接入服务器(CMP),导航服务通过 userId 计算接入服务器,然后下发,使得某一客户端可以连接在同一台接入服务器(CMP)。

示意图如下:

小结一下就是:客户端发出消息后,通过接入服务,按照 userId 投递到指定消息服务器,生成消息 Id, 依据最后一条消息时间,确认更新当前消息的时间戳(如果存在相同时间戳则后延)。然后将时间戳,以及消息 Id,通过 Ack 返回给客户端 ; 然后对上行消息使用 userId + 时间戳进行缓存以及持久化存储,后续业务操作均使用此时间戳。

以上业务流程我们称为上行流程,上行过程存储的消息为发件箱消息。

PS:关于消息ID,需要补充说明一下:

我们采用全局唯一的消息 ID 生成策略。保证消息可通过 ID 进行识别,排重。消息ID的结构如下图所示。

如何实现分布式场景下唯一 ID 生成,具体请阅读:《IM消息ID技术专题(三):解密融云IM产品的聊天消息ID生成策略》。

4.2 下行

消息节点在处理完上行流程后,消息按照目标用户投递到所在消息节点,进入下行流程。

下行过程,按照目标 userId 以及本消息在上行过程中生成的时间戳,计算是否需要更新时间戳(正向)。

如果需要更新则对时间戳进行加法操作,直到当前用户时间戳不重复。

如此处理后,目标用户的存储以及客户端接收到消息后的排重可以做到一致,并且可以做到同一个会话内的时间戳是有序的。从而保证同一个接收用户的消息不会出现乱序。

至此:我们已经介绍完了消息的下行交互过程,消息下行过程中的具体实现方式并不简单,以下将详细展开。

1)直发消息:

即服务端主动发送(给目标客户端)的消息:

  • 1)客户端 SDK 依据本地存储的最新消息时间戳判断,用来做排序等逻辑;
  • 2)对同一个用户直发消息1条,其他转通知。通知拉取时候客户端选择本地最新一条消息时间戳作为开始拉取时间;
  • 3)在消息发送过程中,如果上一条消息发送流程未结束,下一条消息则不用直发(s_msg),而是用通知(s_ntf)。

直发逻辑示意图:

2)通知拉取:

即服务端主动发送通知(给目标客户端):

  • 1)服务端在通知体中携带当前消息时间戳。投递给客户端;
  • 2)客户端收到通知后,比对本地消息时间戳,选择是否发拉取消息信令;
  • 3)服务端收到拉取消息信令后,以信令携带的时间戳为开始,查询出消息列表(200 条或者 5M),并给客户端应答;
  • 4)客户端收到后,给服务端 ack,服务端维护状态;
  • 5)客户端拉取消息时使用的时间戳,是客户端本地最新一条消息的时间戳。

示意图:

在上图中,3-7 步可能需要循环多次,有以下考虑:

  • a、客户端一次收到的消息过多,应答体积过于庞大,传输过程对网络质量要求更高, 因此按照数量以及消息体积分批次进行;
  • b、一次拉取到的消息过多,客户端处理会占用大量资源,可能会有卡顿等,体验较差。

3)服务端直发消息与通知拉取切换逻辑:

主要涉及到的是状态机的更新。

下面示意图集成直发消息与通知拉取过程针对状态机的更新:

至此,消息收发的整个核心流程介绍完毕,余下的内容将介绍多端在线的消息同步处理。

5、多端在线的消息同步

多端按照消息的上下行两个阶段,同样区分为发送方多端同步以及接收方多端同步。

5.1 发送方多端同步

在前面客户端连接 IM 服务过程中(见本文 4.1节),我们已经将同一个用户的多个客户端汇聚在了同一台服务,那么维护一个 userId 的多端就会变得很简单。

具体逻辑是:

  • 1)用户多个终端链接成功后,发送一条消息,这个消息到达 CMP(IM 接入服务) 后,CMP 做基础检查,然后获此用户的其他终端连接;
  • 2)服务把客户端上行的消息,封装为服务端下行消息,直接投递给用户的其他客户端。这样完成了发送方的多端抄送,然后将这条消息投递到 IM 服务。进入正常发送投递流程。

针对上面的第2)点,发送方的多端同步没有经过 IM Server,这么做的好处是:

  • 1)比较快速;
  • 2)经过越少的服务节点,出问题的几率越小。

5.2 接收方多端同步

具体逻辑是:

  • 1)IM 服务收到消息后,先判断接收方的投递范围,这个范围指的是接收方用户的哪些的终端要接收消息;
  • 2)IM 服务将范围以及当前消息,发送到 CMP,CMP 依据范围,匹配接收方的终端,然后投递消息。

接收方多端消息同步范围的应用场景,一般都是针对所有终端。

但有一些特殊业务:比如我在 A 客户端上,控制另外某个端的状态,可能需要一些命令消息, 这时候需要这个作用范围,针对性的投递消息。

到此,我们分享完了有关 IM 消息核心处理流程,通过层层拆解逻辑,提供了可靠的消息投递机制。

附录:更多IM架构设计的文章

浅谈IM系统的架构设计

简述移动端IM开发的那些坑:架构设计、通信协议和客户端

一套海量在线用户的移动端IM架构设计实践分享(含详细图文)

一套原创分布式即时通讯(IM)系统理论架构方案

从零到卓越:京东客服即时通讯系统的技术架构演进历程

蘑菇街即时通讯/IM服务器开发之架构选择

腾讯QQ1.4亿在线用户的技术挑战和架构演进之路PPT

微信后台基于时间序的海量数据冷热分级架构设计实践

微信技术总监谈架构:微信之道——大道至简(演讲全文)

如何解读《微信技术总监谈架构:微信之道——大道至简》

快速裂变:见证微信强大后台架构从0到1的演进历程(一)

17年的实践:腾讯海量产品的技术方法论

移动端IM中大规模群消息的推送如何保证效率、实时性?

现代IM系统中聊天消息的同步和存储方案探讨

IM开发基础知识补课(二):如何设计大量图片文件的服务端存储架构?

IM开发基础知识补课(三):快速理解服务端数据库读写分离原理及实践建议

IM开发基础知识补课(四):正确理解HTTP短连接中的Cookie、Session和Token

WhatsApp技术实践分享:32人工程团队创造的技术神话

微信朋友圈千亿访问量背后的技术挑战和实践总结

王者荣耀2亿用户量的背后:产品定位、技术架构、网络方案等

IM系统的MQ消息中间件选型:Kafka还是RabbitMQ?

腾讯资深架构师干货总结:一文读懂大型分布式系统设计的方方面面

以微博类应用场景为例,总结海量社交系统的架构设计步骤

快速理解高性能HTTP服务端的负载均衡技术原理

子弹短信光鲜的背后:网易云信首席架构师分享亿级IM平台的技术实践

知乎技术分享:从单机到2000万QPS并发的Redis高性能缓存实践之路

IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列

微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

微信技术分享:微信的海量IM聊天消息序列号生成实践(容灾方案篇)

新手入门:零基础理解大型分布式架构的演进历史、技术原理、最佳实践

一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践

阿里技术分享:深度揭秘阿里数据库技术方案的10年变迁史

阿里技术分享:阿里自研金融级数据库OceanBase的艰辛成长之路

社交软件红包技术解密(一):全面解密QQ红包技术方案——架构、技术实现等

社交软件红包技术解密(二):解密微信摇一摇红包从0到1的技术演进

社交软件红包技术解密(三):微信摇一摇红包雨背后的技术细节

社交软件红包技术解密(四):微信红包系统是如何应对高并发的

社交软件红包技术解密(五):微信红包系统是如何实现高可用性的

社交软件红包技术解密(六):微信红包系统的存储层架构演进实践

社交软件红包技术解密(七):支付宝红包的海量高并发技术实践

社交软件红包技术解密(八):全面解密微博红包技术方案

社交软件红包技术解密(九):谈谈手Q红包的功能逻辑、容灾、运维、架构等

社交软件红包技术解密(十):手Q客户端针对2020年春节红包的技术实践

社交软件红包技术解密(十一):解密微信红包随机算法(含代码实现)

即时通讯新手入门:一文读懂什么是Nginx?它能否实现IM的负载均衡?

即时通讯新手入门:快速理解RPC技术——基本概念、原理和用途

多维度对比5款主流分布式MQ消息队列,妈妈再也不担心我的技术选型了

从游击队到正规军(一):马蜂窝旅游网的IM系统架构演进之路

从游击队到正规军(二):马蜂窝旅游网的IM客户端架构演进和实践总结

从游击队到正规军(三):基于Go的马蜂窝旅游网分布式IM系统技术实践

IM开发基础知识补课(六):数据库用NoSQL还是SQL?读这篇就够了!

瓜子IM智能客服系统的数据架构设计(整理自现场演讲,有配套PPT)

阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处

微信后台基于时间序的新一代海量数据存储架构的设计实践

IM开发基础知识补课(九):想开发IM集群?先搞懂什么是RPC!

阿里技术分享:电商IM消息平台,在群聊、直播场景下的技术实践

一套亿级用户的IM架构技术干货(上篇):整体架构、服务拆分等

一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

从新手到专家:如何设计一套亿级消息量的分布式IM系统

企业微信的IM架构设计揭秘:消息模型、万人群、已读回执、消息撤回等

融云技术分享:全面揭秘亿级IM消息的可靠投递机制

>> 更多同类文章 ……

本文已同步发布于“即时通讯技术圈”公众号。

▲ 本文在公众号上的链接是:点此进入。同步发布链接是:http://www.52im.net/thread-3638-1-1.html

posted @ 2021-07-26 15:20 Jack Jiang 阅读(148) | 评论 (0)编辑 收藏

一、更新内容简介

本次为主要版本更新(本次更新内容见文末“MobileIMSDK v6.0更新内容 ”一节),强势升级,将同时支持TCP、UDP、WebSocket三种协议,精心封装之下,实现同一套API、三种协议同时并存。

可能是市面上唯一同时支持UDP+TCP+WebSocket三种协议的同类开源IM框架。

二、MobileIMSDK简介

MobileIMSDK 是一套专为移动端开发的原创IM通信层框架:

  • 历经8年、久经考验;
  • 超轻量级、高度提炼,lib包50KB以内;
  • 精心封装,一套API同时支持UDP、TCP、WebSocket三种协议(可能是全网唯一开源的);
  • 客户端支持 iOS、Android、标准Java、H5、小程序(开发中..)、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 v6.0更新内容 

【重要说明】:

MobileIMSDK v6 为全新版本,新增了对WebSocket协议的优雅支持、多端互踢支持等! 查看详情

【新增重要特性】:

  1. 服务端新增WebSocket协议支持,一套API优雅支持TCP、UDP、WebSocket 3种协议;
  2. 支持多端互踢功能(可应对复杂的移动端网络变动逻辑对多端互踢算法的影响);

【解决的Bug】:

  1. [Andriod]解决了断线后,fireDisconnectedToServer()方法中的一处空指针隐患;
  2. [iOS] 修复了TCP版代码中,调用[ClientCoreSDK releaseCore]方法会触发自动登陆逻辑的bug;
  3. [服务端] 解决了UDP协议下,重连情况下的被踢者已被服务端注销会话后,客户端才发回登陆响应ACK应答,导致服务端错误地向未被踢者发出已登陆者重复登陆响应的问题;

【其它优化和提升】:

  1. [Andriod]废弃了SDK、Demo代码中的所有AsyncTask的使用;
  2. [Andriod]将所有可使用Lambda表达式的代码全部用Lambda进行了简化。
  3. [iOS] 解决了XCode12上编译SDK的.a包,打包成胖子.a时报“have the same architectures (arm64) and can't be in the same fat output file”的问题;
  4. [iOS] Demo中所有使用过时的UIAlertView改为UIAlertController实现;
  5. [iOS] 解决了iOS端SDK工程中两处因类名重构导致的在XCode12.5.1上编译出错。
  6. [服务端] 将服务端Demo中的Log4j日志框架升级为最新的Log4j2;
  7. [服务端] 服务端可控制是否为每条消息生成发送时间戳(可辅助用于客户端的消息排序逻辑等)。

七、相关链接

posted @ 2021-07-22 16:02 Jack Jiang 阅读(156) | 评论 (0)编辑 收藏

     摘要: 本文作者潘唐磊,腾讯WXG(微信事业群)开发工程师,毕业于中山大学。内容有修订。1、内容概述本文总结了企业微信的IM消息系统架构设计,阐述了企业业务给IM架构设计带来的技术难点和挑战,以及技术方案的对比与分析。同时总结了IM后台开发的一些常用手段,适用于IM消息系统。* 推荐阅读:企业微信团队分享的另一篇《企业微信客户端中组织架构数据的同步更新方案优化实战》也值得一读。学习交流:- 即时...  阅读全文

posted @ 2021-07-19 16:24 Jack Jiang 阅读(205) | 评论 (0)编辑 收藏

本文由喜马拉雅技术团队李乾坤原创,原题《推送系统实践》,感谢作者的无私分享。

1、引言

1.1 什么是离线消息推送

对于IM的开发者来说,离线消息推送是再熟悉不过的需求了,比如下图就是典型的IM离线消息通知效果。

1.2 Andriod端离线推送真心不易

移动端离线消息推送涉及的端无非就是两个——iOS端和Andriod端,iOS端没什么好说的,APNs是唯一选项。

Andriod端比较奇葩(主要指国内的手机),为了实现离线推送,各种保活黑科技层出不穷,随着保活难度的不断升级,可以使用的保活手段也是越来越少,有兴趣可以读一读我整理的下面这些文章,感受一下(文章是按时间顺序,随着Andriod系统保活难度的提升,不断进阶的)。

上面这几篇只是我整理的这方面的文章中的一部分,特别注意这最后一篇《Android保活从入门到放弃:乖乖引导用户加白名单吧(附7大机型加白示例)》。是的,当前Andriod系统对APP自已保活的容忍度几乎为0,所以那些曾今的保活手段在新版本系统里,几乎统统都失效了。

自已做保活已经没戏了,保离线消息推送总归是还得做。怎么办?按照现时的最佳实践,那就是对接种手机厂商的ROOM级推送通道。具体我就不在这里展开,有兴趣的地可以详读《Android P正式版即将到来:后台应用保活、消息推送的真正噩梦》。

自已做保活、自建推送通道的时代(这里当然指的是Andriod端啦),离线消息推送这种系统的架构设计相对简单,无非就是每台终端计算出一个deviceID,服务端通过自建通道进行消息透传,就这么点事。

而在自建通道死翘翘,只能依赖厂商推送通道的如今,小米华为魅族OPPOvivo(这只是主流的几家)等等,手机型号太多,各家的推送API、设计规范各不相同(别跟我提什么统一推送联盟,那玩意儿我等他3年了——详见《万众瞩目的“统一推送联盟”上场了),这也直接导致先前的离线消息推送系统架构设计必须重新设计,以适应新时代的推送技术要求。

1.3 怎么设计合理呢

那么,针对不同厂商的ROOM级推送通道,我们的后台推送架构到底该怎么设计合理呢?

本文分享的离线消息推送系统设计并非专门针对IM产品,但无论业务层的差别有多少,大致的技术思路上都是相通的,希望借喜马拉雅的这篇分享能给正在设计大用户量的离线消息推送的你带来些许启发。

* 推荐阅读:喜马拉雅技术团队分享的另一篇《长连接网关技术专题(五):喜马拉雅自研亿级API网关技术实践》,有兴趣也可以一并阅读。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170 [推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK

本文同步发布于:http://www.52im.net/thread-3621-1-1.html

2、技术背景

首先介绍下在喜马拉雅APP中推送系统的作用,如下图就是一个新闻业务的推送/通知。

离线推送主要就是在用户不打开APP的时候有一个手段触达用户,保持APP的存在感,提高APP的日活。

我们目前主要用推送的业务包括:

  • 1)主播开播:公司有直播业务,主播在开直播的时候会给这个主播的所有粉丝发一个推送开播提醒
  • 2)专辑更新:平台上有非常多的专辑,专辑下面是一系列具体的声音,比如一本儿小说是一个专辑,小说有很多章节,那么当小说更新章节的时候给所有订阅这个专辑的用户发一个更新的提醒:
  • 3)个性化、新闻业务等。

既然想给一个用户发离线推送,系统就要跟这个用户设备之间有一个联系的通道。

做过这个的都知道:自建推送通道需要App常驻后台(就是引言里提到的应用“保活”),而手机厂商因为省电等原因普遍采取“激进”的后台进程管理策略,导致自建通道质量较差。目前通道一般是由“推送服务商”去维护,也就是说公司内的推送系统并不直接给用户发推送(就是上节内容的这篇里提到的情况:《Android P正式版即将到来:后台应用保活、消息推送的真正噩梦)。

这种情况下的离线推送流转流程如下:

国内的几大厂商(小米华为魅族OPPOvivo等)都有自己官方的推送通道,但是每一家接口都不一样,所以一些厂商比如小米、个推提供集成接口。发送时推送系统发给集成商,然后集成商根据具体的设备,发给具体的厂商推送通道,最终发给用户。

给设备发推送的时候,必须说清楚你要发的是什么内容:即title、message/body,还要指定给哪个设备发推送。

我们以token来标识一个设备, 在不同的场景下token的含义是不一样的,公司内部一般用uid或者deviceId标识一个设备,对于集成商、不同的厂商也有自己对设备的唯一“编号”,所以公司内部的推送服务,要负责进行uid、deviceId到集成商token 的转换。

3、整体架构设计

如上图所示,推送系统整体上是一个基于队列的流式处理系统。

上图右侧:是主链路,各个业务方通过推送接口给推送系统发推送,推送接口会把数据发到一个队列,由转换和过滤服务消费。转换就是上文说的uid/deviceId到token的转换,过滤下文专门讲,转换过滤处理后发给发送模块,最终给到集成商接口。

App 启动时:会向服务端发送绑定请求,上报uid/deviceId与token的绑定关系。当卸载/重装App等导致token失效时,集成商通过http回调告知推送系统。各个组件都会通过kafka 发送流水到公司的xstream 实时流处理集群,聚合数据并落盘到mysql,最终由grafana提供各种报表展示。

4、业务过滤机制设计

各个业务方可以无脑给用户发推送,但推送系统要有节制,因此要对业务消息有选择的过滤。

过滤机制的设计包括以下几点(按支持的先后顺序):

  • 1)用户开关:App支持配置用户开关,若用户关闭了推送,则不向用户设备发推送;
  • 2)文案排重:一个用户不能收到重复的文案,用于防止上游业务方发送逻辑出错;
  • 3)频率控制:每一个业务对应一个msg_type,设定xx时间内最多发xx条推送;
  • 4)静默时间:每天xx点到xx点不给用户发推送,以免打扰用户休息。
  • 5)分级管理:从用户和消息两维度进行分级控制。

针对第5点,具体来说就是:

  • 1)每一个msg/msg_type有一个level,给重要/高level业务更多发送机会;
  • 2)当用户一天收到xx条推送时,不是重要的消息就不再发给这些用户。

5、分库分表下的多维查询问题

很多时候,设计都是基于理论和经验,但实操时,总会遇到各种具体的问题。

喜马拉雅现在已经有6亿+用户,对应的推送系统的设备表(记录uid/deviceId到token的映射)也有类似的量级,所以对设备表进行了分库分表,以 deviceId 为分表列。

但实际上:经常有根据 uid/token 的查询需求,因此还需要建立以 uid/token 到 deviceId 的映射关系。因为uid 查询的场景也很频繁,因此uid副表也拥有和主表同样的字段。

因为每天会进行一两次全局推,且针对沉默用户(即不常使用APP的用户)也有专门的推送,存储方面实际上不存在“热点”,虽然使用了缓存,但作用很有限,且占用空间巨大。

多分表以及缓存导致数据存在三四个副本,不同逻辑使用不同副本,经常出现不一致问题(追求一致则影响性能), 查询代码非常复杂且性能较低。

最终我们选择了将设备数据存储在tidb上,在性能够用的前提下,大大简化了代码。

6、特殊业务的时效性问题

6.1 基本概念

推送系统是基于队列的,“先到先推”。大部分业务不要求很高的实时性,但直播业务要求半个小时送达,新闻业务更是“欲求不满”,越快越好。

若进行新闻推送时:队列中有巨量的“专辑更新”推送等待处理,则专辑更新业务会严重干扰新闻业务的送达。

6.2 这是隔离问题?

一开始我们认为这是一个隔离问题:比如10个消费节点,3个专门负责高时效性业务、7个节点负责一般业务。当时队列用的是rabbitmq,为此改造了 spring-rabbit 支持根据msytype将消息路由到特定节点。

该方案有以下缺点:

  • 1)总有一些机器很忙的时候,另一些机器在“袖手旁观”;
  • 2)新增业务时,需要额外配置msgType到消费节点的映射关系,维护成本较高;
  • 3)rabbitmq基于内存实现,推送瞬时高峰时占用内存较大,进而引发rabbitmq 不稳定。

6.3 其实是个优先级问题

后来我们觉察到这是一个优先级问题:高优先级业务/消息可以插队,于是封装kafka支持优先级,比较好的解决了隔离性方案带来的问题。具体实现是建立多个topic,一个topic代表一个优先级,封装kafka主要是封装消费端的逻辑(即构造一个PriorityConsumer)。

备注:为描述简单,本文使用 consumer.poll(num) 来描述使用 consumer 拉取 num 个消息,与真实 kafka api 不一致,请知悉。

PriorityConsumer实现有三种方案,以下分别阐述。

1)poll到内存后重新排序:java 有现成的基于内存的优先级队列PriorityQueue 或PriorityBlockingQueue,kafka consumer 正常消费,并将poll 到的数据重新push到优先级队列。

  • 1.1)如果使用有界队列,队列打满后,后面的消息优先级再高也put 不进去,失去“插队”效果;
  • 1.2)如果使用无界队列,本来应堆在kafka上的消息都会堆到内存里,OOM的风险很大。

2)先拉取高优先级topic的数据:只要有就一直消费,直到没有数据再消费低一级topic。消费低一级topic的过程中,如果发现有高一级topic消息到来,则转向消费高优先级消息。

该方案实现较为复杂,且在晚高峰等推送密集的时间段,可能会导致低优先级业务完全失去推送机会。

3)优先级从高到低,循环拉取数据:

一次循环的逻辑为:

consumer-1.poll(topic1-num);

cosumer-i.poll(topic-i-num);

consumer-max.priority.poll(topic-max.priority-num)

如果topic1-num=topic-i-num=topic-max.priority-num,则该方案是没有优先级效果的。topic1-num 可以视为权重,我们约定:topic-高-num=2 * topic-低-num,同一时刻所有topic 都会被消费,通过一次消费数量的多少来变相实现“插队效果”。具体细节上还借鉴了“滑动窗口”策略来优化某个优先级的topic 长期没有消息时总的消费性能。

从中我们可以看到,时效问题先是被理解为一个隔离问题,后被视为优先级问题,最终转化为了一个权重问题。

7、过滤机制的存储和性能问题

在我们的架构中,影响推送发送速度的主要就是tidb查询和过滤逻辑,过滤机制又分为存储和性能两个问题。

这里我们以xx业务频控限制“一个小时最多发送一条”为例来进行分析。

第一版实现时:redis kv 结构为 <deviceId_msgtype,已发送推送数量>

频控实现逻辑为:

  • 1)发送时,incr key,发送次数加1;
  • 2)如果超限(incr命令返回值>发送次数上限),则不推送;
  • 3)若未超限且返回值为1,说明在msgtype频控周期内第一次向该deviceId发消息,需expire key设置过期时间(等于频控周期)。

上述方案有以下缺点:

  • 1)目前公司有60+推送业务, 6亿+ deviceId,一共6亿*60个key ,占用空间巨大;
  • 2)很多时候,处理一个deviceId需要2条指令:incr+expire。

为此,我们的解决方法是:

  • 1)使用pika(基于磁盘的redis)替换redis,磁盘空间可以满足存储需求;
  • 2)委托系统架构组扩充了redis协议,支持新结构ehash。

ehash基于redis hash修改,是一个两级map <key,field,value>,除了key 可以设置有效期外,field也可以支持有效期,且支持有条件的设置有效期。

频控数据的存储结构由<deviceId_msgtype,value>变为 <deviceId,msgtype,value>,这样对于多个msgtype,deviceId只存一次,节省了占用空间。

incr 和 expire 合并为1条指令:incr(key,filed,expire),减少了一次网络通信:

  • 1)当field未设置有效期时,则为其设置有效期;
  • 2)当field还未过期时,则忽略有效期参数。

因为推送系统重度使用 incr 指令,可以视为一条写指令,大部分场景还用了pipeline 来实现批量写的效果,我们委托系统架构组小伙伴专门优化了pika 的写入性能,支持“写模式”(优化了写场景下的相关参数),qps达到10w以上。

ehash结构在流水记录时也发挥了重要作用,比如<deviceId,msgId,100001002>,其中 100001002 是我们约定的一个数据格式示例值,前中后三个部分(每个部分占3位)分别表示了某个消息(msgId)针对deviceId的发送、接收和点击详情,比如头3位“100”表示因发送时处于静默时间段所以发送失败。

附录:更多消息推送技术文章

iOS的推送服务APNs详解:设计思路、技术原理及缺陷等

信鸽团队原创:一起走过 iOS10 上消息推送(APNS)的坑

Android端消息推送总结:实现原理、心跳保活、遇到的问题等

扫盲贴:认识MQTT通信协议

一个基于MQTT通信协议的完整Android推送Demo

IBM技术经理访谈:MQTT协议的制定历程、发展现状等

求教android消息推送:GCM、XMPP、MQTT三种方案的优劣

移动端实时消息推送技术浅析

扫盲贴:浅谈iOS和Android后台实时消息推送的原理和区别

绝对干货:基于Netty实现海量接入的推送服务技术要点

移动端IM实践:谷歌消息推送服务(GCM)研究(来自微信)

为何微信、QQ这样的IM工具不使用GCM服务推送消息?

极光推送系统大规模高并发架构的技术实践分享

从HTTP到MQTT:一个基于位置服务的APP数据通信实践概述

魅族2500万长连接的实时消息推送架构的技术实践分享

专访魅族架构师:海量长连接的实时消息推送系统的心得体会

深入的聊聊Android消息推送这件小事

基于WebSocket实现Hybrid移动应用的消息推送实践(含代码示例)

一个基于长连接的安全可扩展的订阅/推送服务实现思路

实践分享:如何构建一套高可用的移动端消息推送系统?

Go语言构建千万级在线的高并发消息推送系统实践(来自360公司)

腾讯信鸽技术分享:百亿级实时消息推送的实战经验

百万在线的美拍直播弹幕系统的实时推送技术实践之路

京东京麦商家开放平台的消息推送架构演进之路

了解iOS消息推送一文就够:史上最全iOS Push技术详解

基于APNs最新HTTP/2接口实现iOS的高性能消息推送(服务端篇)

解密“达达-京东到家”的订单即时派发技术原理和实践

技术干货:从零开始,教你设计一个百万级的消息推送系统

长连接网关技术专题(四):爱奇艺WebSocket实时推送网关技术实践

喜马拉雅亿级用户量的离线消息推送系统架构设计实践

>> 更多同类文章 ……

本文已同步发布于“即时通讯技术圈”公众号。

▲ 本文在公众号上的链接是:点此进入。同步发布链接是:http://www.52im.net/thread-3621-1-1.html

posted @ 2021-07-12 15:31 Jack Jiang 阅读(454) | 评论 (0)编辑 收藏

本文由阿里闲鱼技术团队祈晴分享,本次有修订和改动,感谢作者的技术分享。

1、内容概述

本文总结了阿里闲鱼技术团队使用Flutter在对闲鱼IM进行移动端跨端改造过程中的技术实践等,文中对比了传统Native与现在大热的Flutter跨端方案在一些主要技术实现上的差异,以及针对Flutter技术特点的具体技术实现,值得同样准备使用Flutter开发IM的技术同行们借鉴和参考。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170 [推荐]

- 移动端IM开发入门文章:新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK

本文同步发布于:http://www.52im.net/thread-3615-1-1.html

2、闲鱼IM现状

闲鱼IM的移动端框架构建于2016至2017年间,期间经过多次迭代升级导致历史包袱累积多,后面又经历IM界面的Flutter化,从而造成了客户端架构愈加复杂。

从开发层面总结闲鱼IM移动端当前架构主要存在如下几个问题:

  • 1)研发效率较低:当前架构涉及到Android/iOS双端的逻辑代码以及Flutter的UI代码,定位问题往往只能从Flutter UI表相倒查到Native逻辑层;
  • 2)架构层次较差:架构设计上分层不清晰,业务逻辑夹杂在核心的逻辑层致使代码变更风险大;
  • 3)性能测试略差:核心数据源存储Native内存,需经Flutter Plugin将数据源序列化上抛Flutter侧,在大批量数据源情况下性能表现较差。

从产品层面总结闲鱼IM移动端当前架构的主要问题如下:

  • 1)定位问题困难:线上舆情反馈千奇百怪,测试始终无法复现相关场景,因此很多时候只能靠现象猜测本质;
  • 2)疑难杂症较多:架构的不稳定性造成出现的问题反复出现,当前疑难杂症主要包括未读红点计数、iPhone5C低端机以及多媒体发送等多个问题;
  • 3)问题差异性大:Android和iOS两端逻辑代码差异大,包括埋点逻辑都不尽相同,排查问题根源时双端都会有不同根因,解决方案也不相同。

3、业界的移动端跨端方案

为解决当前IM的技术痛点,闲鱼今年特起关于IM架构升级项目,重在解决客户端中Andriod和iOS双端一致性的痛点,初步设想方案就是实现跨端统一的Android/iOS逻辑架构。

在当前行业内跨端方案可初步归类如下图架构:

在GUI层面的跨端方案有WeexReactNative、H5、Uni-APP等,其内存模型大多需要通过桥接到Native模式存储。

在逻辑层面的跨端方案大致有C/C++等与虚拟机无关语言实现跨端,当然汇编语言也可行。

此外有两个独立于上述体系之外的架构就是Flutter和KMM(谷歌基于Kotlin实现类似Flutter架构),其中Flutter运行特定DartVM,将内存数据挂载其自身的isolate中。

考虑闲鱼是Flutter的前沿探索者,方案上优先使用Flutter。然而Flutter的isolate更像一个进程的概念(底层实现非使用进程模式),相比Android,同一进程场景中,Android的Dalvik虚拟机多个线程运行共享一个内存Heap,而DartVM的Isolate运行隔离各自的Heap,因而isolate之间通讯方式比较繁琐(需经过序列化反序列化过程)。

整个模型如下图所示:

若按官方混合架构实现Flutter应用,开启多个FlutterAcitivty/FlutterController,底层会生成多个Engine,对应会存在多个isolate,而isolate通讯类似于进程通讯(类似socket或AIDL),这里借鉴闲鱼FlutterBoost的设计理念,FlutterIM架构将多个页面的Engine共享,则内存模型就天然支持共享读取。

原理图如下:

4、闲鱼IM基于Flutter的架构设计

4.1 新老架构对比

如下图所示:是一个老架构方案,其核心问题主要集中于Native逻辑抽象差,其中逻辑层面还设计到多线程并发使得问题倍增,Android/iOS/Flutter交互繁杂,开发维护成本高,核心层耦合较为严重,无插拔式概念.

考虑到历史架构的问题,演进如下新架构设计:

如上图所示,架构从上至下依次为:

  • 1)业务层;
  • 2)分发层;
  • 3)逻辑层;
  • 4)数据源层。

数据源层来源于推送或网络请求,其封装于Native层,通过Flutter插件将消息协议数据上抛到Flutter侧的核心逻辑层,处理完成后变成Flutter DB的Enitity实体,实体中挂载一些消息协议实体。

核心逻辑层将繁杂数据扁平化打包挂载到分发层中的会话内存模型数据或消息内存模型数据,最后通过观察者模式的订阅分发到业务逻辑中。

Flutter IM重点集中改造逻辑层和分发层,将IM核心逻辑和业务层面数据模型进行封装隔离,核心逻辑层和数据库交互后将数据封装到分发层的moduleData中,通过订阅方式分发到业务层数据模型中。

此外在IM模型中DB也是重点依赖的,个人对DB数据库管理进行全面封装解,实现一种轻量级,性能佳的Flutter DB管理框架。

4.2 DB存储模型

Flutter IM架构的DB存储依赖数据库插件,目前主流插件是Sqflite

其存储模型如下:

依据上图Sqflite插件的DB存储模型会有2个等待队列:

  • 一个是Flutter层同步执行队列;
  • 一个是Native层的线程执行队列。

其Android实现机制是HandlerThread,因此Query/Save读写在会同一线程队列中,导致响应速度慢,容易造成DB SQL堆积,此外缺失缓存模型。

于是个人定制如下改进方案:

Flutter侧通过表的主键设计查询时候会优先从Entity Cache层去获取,若缓存不存在,则通过Sqflite插件查询。

同时改造Sqflite插件成支持sync/Async同步异步两种方式操作,对应到Native侧也会有同步线程队列和异步线程队列,保证数据吞吐率。但是这里建议查询使用异步,存储使用同步更稳妥,主要怕出现多个相同的数据元model同一时间进入异步线程池中,存储先后顺序无法有效的保证。

4.3 ORM数据库方案

IM架构重度依赖DB数据库,而当前业界还没有一个完备的数据库ORM管理方案,参考了Android的OrmLite/GreenDao,个人自行设计一套Flutter ORM数据库管理方案。

其核心思想如下:

由于Flutter不支持反射,因此无法直接像Android的开源数据库方式操作,但可通过APT方式,将Entity和Orm Entity绑定于一身,操作OrmEntity即操作Entity,整个代码风格设计也和OrmLite极其相似。

参考代码如下:

4.4 IM内存数据模型

基于Flutter的IM移动端架构在内存数据模型主要划分为会话和消息两个颗粒度:

  • 1)会话内存数据模型交托于SessionModuleData:会话内存数据有一个根节点RootNotice,然后其挂载PSessionMessageNotice(这里PSessionMessageNotice是ORM映射的会话DB表模型)子节点集合。
  • 2)消息内存数据模型交托于MessageModuleData:消息内存数据会有一个MessageConatiner容器管理,其内部挂载此会话中的PMessage(PMessage是ORM映射的消息DB表模型)消息集合。

依据上一章节,PSessionMessageNotice设计了一个OrmEnitity Cache,考虑到IM中会话数是有限的,因此PSessionMessageNotice都是直接缓存到Cache中。

这种做法的好处是各地去拿会话数据元时候都是缓存中同一个对象,容易保证多次重复读写的数据一致性。而PSessionMessageNotice考虑到其数量可以无限多的特殊性,因此这里将其挂载到MessageContainer的内存管理中,在退出会话的时机会校验容器中PMessage集合的数量,适当缩容可以减少内存开销。

模型如下图所示:

4.5 状态管理方案

基于Flutter的IM移动端架构状态管理方案比较简单,对数据源Session/Message维度使用观察者模式的订阅分发方式实现,架构类似于EventBus模式,页面级的状态管理无论使用fish-redux、scopeModel或者provider几乎影响面不大,核心还是需保留一种插拔式抽象更重要。

架构如下图:

4.6 IM同步模型方案

当前现状的消息同步模型:

如上图所示是,模型中存在ACCS Thread/Main Thread/Region Thread等多线程并发场景,导致易出现多线程高并发的问题。

native的推送和网络请求同步的隔离方案通过Lock的锁机制,并且通过队列降频等方式处理,流程繁琐且易出错。整体通过Region Version Gap去判断是否有域空洞,进而执行域同步补充数据。

改进的同步模型如下:

如上图所示,在Flutter侧天然没多线程场景,通过一种标记位的转化同步异步实现类似Handler消息队列,架构清晰简约了很多,避免锁带来的开销以及同步问题。

5、本次改造进展以及性能对比

1)针对架构层面:

在基于Flutter的IM架构中,重点将双端逻辑差异性统一成同一份Dart代码,完全磨平Android/iOS的代码差异性带来的问题。

带来的好处很明显:

  • 1)降低开发维护、测试回归、视觉验收的一半成本,极大提高研发效率;
  • 2)架构上进行重构分层,实现一种解耦合,插拔式的IM架构;
  • 3)同时Native到Flutter侧的大量数据上抛序列化过程改造程Flutter引用传递,解决极限测试场景下的私聊卡顿问题。

2)针对线上舆情:

  • 1)补齐UT和TLog的集团日志方式做到可追踪,可排查;
  • 2)针对于很多现存的疑难杂症重点集中专项解决,比如iphone5C的架构在Flutter侧统一规划;
  • 3)未读红点计数等问题也在架构模型升级中修复;
  • 4)此外多媒体音视频发送模块进行改造升级。

3)性能数据对比:

当IM架构的逻辑层和UI层都切换成Flutter后,和原先架构模式初步对比,整体内存水位持平。

其中:

  • 1)私聊场景下小米9测试结构内存下降40M,功耗降低4mah,CPU降低1%;
  • 2)极限测试场景下新架构内存数据相比于旧架构有一个较为明显的改观(主要由于两个界面都使用Flutter场景下,页面切换的开销降低很多)。

6、未来展望

JS跨端不安全,C++跨端成本有点高,Flutter会是一个较好选择。彼时闲鱼FlutterIM架构升级根本目的从来不是因Flutter而Flutter,是由于历史包袱的繁重,代码层面的维护成本高,新业务的扩展性差,人力配比不协调以及疑难杂症的舆情持续反馈等等因素造成我们不得不去探索新方案。

经过闲鱼IM超复杂业务场景验证Flutter模式的逻辑跨端可行性,闲鱼在Flutter路上会一直保持前沿探索,最后能反馈到生态圈。

总结一句话,探索过程在于你勇于迈出第一步,后面才会不断惊喜发现。

(原文链接:点此进入,本次有修订和改动)

附录:更多文章汇总

[1] 更多阿里团队的文章分享:

阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处

现代IM系统中聊天消息的同步和存储方案探讨

阿里技术分享:深度揭秘阿里数据库技术方案的10年变迁史

阿里技术分享:阿里自研金融级数据库OceanBase的艰辛成长之路

来自阿里OpenIM:打造安全可靠即时通讯服务的技术实践分享

钉钉——基于IM技术的新一代企业OA平台的技术挑战(视频+PPT) [附件下载]

阿里技术结晶:《阿里巴巴Java开发手册(规约)-华山版》[附件下载]

重磅发布:《阿里巴巴Android开发手册(规约)》[附件下载]

作者谈《阿里巴巴Java开发手册(规约)》背后的故事

《阿里巴巴Android开发手册(规约)》背后的故事

干了这碗鸡汤:从理发店小弟到阿里P10技术大牛

揭秘阿里、腾讯、华为、百度的职级和薪酬体系

淘宝技术分享:手淘亿级移动端接入层网关的技术演进之路

难得干货,揭秘支付宝的2维码扫码技术优化实践之路

淘宝直播技术干货:高清、低延时的实时视频直播技术解密

阿里技术分享:电商IM消息平台,在群聊、直播场景下的技术实践

阿里技术分享:闲鱼IM基于Flutter的移动端跨端改造实践

 

[2] 更多IM开发综合文章:

新手入门一篇就够:从零开发移动端IM

移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”

移动端IM开发者必读(二):史上最全移动弱网络优化方法总结

从客户端的角度来谈谈移动端IM的消息可靠性和送达机制

现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障

移动端IM中大规模群消息的推送如何保证效率、实时性?

移动端IM开发需要面对的技术问题

开发IM是自己设计协议用字节流好还是字符流好?

IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

IM消息送达保证机制实现(二):保证离线消息的可靠投递

如何保证IM实时消息的“时序性”与“一致性”?

一个低成本确保IM消息时序的方法探讨

IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?

IM群聊消息如此复杂,如何保证不丢不重?

谈谈移动端 IM 开发中登录请求的优化

移动端IM登录时拉取数据如何作到省流量?

浅谈移动端IM的多点登录和消息漫游原理

完全自已开发的IM该如何设计“失败重试”机制?

通俗易懂:基于集群的移动端IM接入层负载均衡方案分享

微信对网络影响的技术试验及分析(论文全文)

开源IM工程“蘑菇街TeamTalk”的现状:一场有始无终的开源秀

如约而至:微信自用的移动端IM网络层跨平台组件库Mars已正式开源

子弹短信光鲜的背后:网易云信首席架构师分享亿级IM平台的技术实践

微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

自已开发IM有那么难吗?手把手教你自撸一个Andriod版简易IM (有源码)

融云技术分享:解密融云IM产品的聊天消息ID生成策略

IM开发基础知识补课(六):数据库用NoSQL还是SQL?读这篇就够了!

适合新手:从零开发一个IM服务端(基于Netty,有完整源码)

拿起键盘就是干:跟我一起徒手开发一套分布式IM系统

适合新手:手把手教你用Go快速搭建高性能、可扩展的IM系统(有源码)

IM里“附近的人”功能实现原理是什么?如何高效率地实现它?

IM“扫一扫”功能很好做?看看微信“扫一扫识物”的完整技术实现

IM消息ID技术专题(一):微信的海量IM聊天消息序列号生成实践(算法原理篇)

IM消息ID技术专题(二):微信的海量IM聊天消息序列号生成实践(容灾方案篇)

IM消息ID技术专题(三):解密融云IM产品的聊天消息ID生成策略

IM消息ID技术专题(四):深度解密美团的分布式ID生成算法

IM消息ID技术专题(五):开源分布式ID生成器UidGenerator的技术实现

IM消息ID技术专题(六):深度解密滴滴的高性能ID生成器(Tinyid)

IM开发宝典:史上最全,微信各种功能参数和逻辑规则资料汇总

IM开发干货分享:我是如何解决大量离线消息导致客户端卡顿的

零基础IM开发入门(一):什么是IM系统?

零基础IM开发入门(二):什么是IM系统的实时性?

零基础IM开发入门(三):什么是IM系统的可靠性?

零基础IM开发入门(四):什么是IM系统的消息时序一致性?

IM开发干货分享:如何优雅的实现大量离线消息的可靠投递

IM开发干货分享:有赞移动端IM的组件化SDK架构设计实践

一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

IM扫码登录技术专题(一):微信的扫码登录功能技术原理调试分析

IM扫码登录技术专题(二):市面主流的扫码登录技术原理调试分析

IM扫码登录技术专题(三):通俗易懂,IM扫码登录功能详细原理一篇就够

理解IM消息“可靠性”和“一致性”问题,以及解决方案探讨

阿里技术分享:闲鱼IM基于Flutter的移动端跨端改造实践

>> 更多同类文章 ……

本文已同步发布于“即时通讯技术圈”公众号。

▲ 本文在公众号上的链接是:点此进入。同步发布链接是:http://www.52im.net/thread-3615-1-1.html

posted @ 2021-07-05 14:55 Jack Jiang 阅读(193) | 评论 (0)编辑 收藏

     摘要: 本文作者张彦飞,原题“127.0.0.1 之本机网络通信过程知多少 ”,首次发布于“开发内功修炼”,转载请联系作者。本次有改动。1、引言继《你真的了解127.0.0.1和0.0.0.0的区别?》之后,这是我整理的第2篇有关本机网络方面的网络编程基础文章。这次的文章由作者张彦飞原创分享,写作本文的原因是现在本机网络 IO 应用非常广。在 php 中 一...  阅读全文

posted @ 2021-06-28 15:32 Jack Jiang 阅读(224) | 评论 (0)编辑 收藏

     摘要: 本文由微信开发团队工程师“virwu”分享。1、引言近期,微信小游戏支持了视频号一键开播,将微信升级到最新版本,打开腾讯系小游戏(如跳一跳、欢乐斗地主等),在右上角菜单就可以看到发起直播的按钮一键成为游戏主播了(如下图所示)。然而微信小游戏出于性能和安全等一系列考虑,运行在一个独立的进程中,在该环境中不会初始化视频号直播相关的模块。这就意味着小游戏的音视频数据必须跨进程传输...  阅读全文

posted @ 2021-06-21 15:32 Jack Jiang 阅读(161) | 评论 (0)编辑 收藏

本文引用了“拍乐云Pano”的“深入浅出理解视频编解码技术”和“揭秘视频千倍压缩背后的技术原理之预测技术”文章部分内容,感谢原作者的分享。

1、引言

从 20 世纪 90 年代以来,数字音视频编解码技术迅速发展,一直是国内外研究的热点领域。随着5G的成熟和广泛商用,带宽已经越来越高,传输音视频变得更加容易。视频直播、视频聊天,已经完全融入了每个人的生活。

视频为何如此普及呢?是因为通过视频能方便快捷地获取到大量信息。但视频数据量非常巨大,视频的网络传输也面临着巨大的挑战。于是视频编解码技术就出场了。

具体到实时视频场景,不仅仅是数据量的问题,实时通信对时延要求、设备适配、带宽适应的要求也非常高,要解决这些问题,始终离不开视频编解码技术的范畴。

本文将从视频编解码技术的基础知识入手,引出视频编解码技术中非常基础且重要的预测技术,学习帧内预测和帧间预测的技术原理。

本文已同步发布于:http://www.52im.net/thread-3581-1-1.html

2、相关文章

如果你是音视频技术初学者,以下3篇入门级干货非常推荐一读:

零基础,史上最通俗视频编码技术入门

零基础入门:实时音视频技术基础知识全面盘点

实时音视频面视必备:快速掌握11个视频技术相关的基础概念

3、为什么需要视频编解码

首先,来复习一下视频编解码方面的理论常识。

视频是由一系列图片按照时间顺序排列而成:

  • 1)每一张图片为一帧;
  • 2)每一帧可以理解为一个二维矩阵;
  • 3)矩阵的每个元素为一个像素。

一个像素通常由三个颜色进行表达,例如用RGB颜色空间表示时,每一个像素由三个颜色分量组成。每一个颜色分量用1个字节来表达,其取值范围就是0~255。编码中常用的YUV格式与之类似,这里不作展开。

1280x720@60fps的视频序列为例,十秒钟的视频有:1280*720*3*60*10 = 1.6GB

如此大量的数据,无论是存储还是传输,都面临巨大的挑战。视频压缩或者编码的目的,也是为了保证视频质量的前提下,将视频减小,以利于传输和存储。同时,为了能正确还原视频,需要将其解码。

PS:限于篇幅,视频编解码方面的技术原理就不在此展开,有兴趣强烈推荐从这篇深入学习:即时通讯音视频开发(十九):零基础,史上最通俗视频编码技术入门》。

总之,视频编解码技术的主要作用就是:在可用的计算资源内,追求尽可能高的视频重建质量和尽可能高的压缩比,以达到带宽和存储容量的要求。

为何突出“重建质量”?

因为视频编码是个有损的过程,用户只能从收到的视频流中解析出“重建”画面,它与原始的画面已经不同,例如观看低质量视频时经常会碰到的“块”效应。

如何在一定的带宽占用下,尽可能地保持视频的质量,或者在保持质量情况下,尽可能地减少带宽利用率,是视频编码的基本目标。

用专业术语来说,即视频编解码标准的“率失真”性能:

  • 1)“率”是指码率或者带宽占用;
  • 2)“失真”是用来描述重建视频的质量。

与编码相对应的是解码或者解压缩过程,是将接收到的或者已经存储在介质上的压缩码流重建成视频信号,然后在各种设备上进行显示。

4、什么是视频编解码标准

视频编解码标准,通常只定义上述的解码过程。

例如 H.264 / AVC 标准,它定义了什么是符合标准的视频流,对每一个比特的顺序和意义都进行了严格地定义,对如何使用每个比特或者几个比特表达的信息也有精确的定义。

正是这样的严格和精确,保证了不同厂商的视频相关服务,可以很方便地兼容在一起,例如用 iPhone、Android Phone 或者 windows PC 都可以观看同一在线视频网站的同一视频。

世界上有多个组织进行视频编码标准的制定工作,国际标准组织 ISO 的 MPEG 小组、国际电信联盟 ITU-T 的 VCEG 小组、中国的 AVS 工作组、Google 及各大厂商组成的开放媒体联盟等。

视频编码标准及发展历史:

自 VCEG 制定 H.120标准开始,视频编码技术不断发展,先后成功地制定了一系列满足不同应用场景的视频编码标准。VCEG 组织先后制定了H.120、H.261、H.262(MPEG-2 Part 2)、H.263、H.263+、H.263++

MPEG也先后制定了MPEG-1、MPEG-2、MPEG-4 Part 2。以及两个国际组织合作制定的H.264/AVC、H.265/HEVC、H.266/VVC

中国自主知识产权的 AVS、AVS2、AVS3 视频编码标准;Google 制定的 VP8、VP9。

Google、思科、微软、苹果等公司组成的开放媒体联盟(AOM)制定的 AV1。

这里特别提一下H.264/AVC:H.264/AVC虽有近20年历史,但它优秀的压缩性能、适当的运算复杂度、优秀的开源社区支持、友好的专利政策、强大的生态圈等多个方面的因素,依旧让它保持着强大的生命力,特别是在实时通信领域。像 ZOOM、思科 Webex 等视频会议产品和基于 WebRTC SDK 的视频服务,大多数主流场景都采用 H.264/AVC。

有关视频编解码标准,这里就不深入展开。更多详细资料,可以读一下下面这些精选文章:

即时通讯音视频开发(五):认识主流视频编码技术H.264

即时通讯音视频开发(十三):实时视频编码H.264的特点与优势

即时通讯音视频开发(十七):视频编码H.264、VP8的前世今生

爱奇艺技术分享:轻松诙谐,讲解视频编解码技术的过去、现在和将来

5、混和编码框架

纵观视频编解码标准历史,每一代视频标准都在率失真性能上有着显著的提升,他们都有一个核心的框架,就是基于块的混合编码框架(如下图所示)。它是由J. R. Jain 和A. K. Jain在1979年的国际图像编码学会(PCS 1979)上提出了基于块运动补偿和变换编码的混合编码框架。

我们一起来对该框架进行拆解和分析。

从摄像头采集到的一帧视频:通常是 YUV 格式的原始数据,我们将它划分成多个方形的像素块依次进行处理(例如 H.264/AVC 中以16x16像素为基本单元),进行帧内/帧间预测、正变换、量化、反量化、反变换、环路滤波、熵编码,最后得到视频码流。从视频第一帧的第一个块开始进行空间预测,因当前正在进行编码处理的图像块和其周围的图像块有相似性,我们可以用周围的像素来预测当前的像素。我们将原始像素减去预测像素得到预测残差,再将预测残差进行变换、量化,得到变换系数,然后将其进行熵编码后得到视频码流。

接下来:为了可以使后续的图像块可以使用已经编码过的块进行预测,我们还要对变换系统进行反量化、反变换,得到重建残差,再与预测值进行求合,得到重建图像。最后我们对重建图像进行环路滤波、去除块效应等,这样得到的重建图像,就可以用来对后续图像块进行预测了。按照以上步骤,我们依次对后续图像块进行处理。

对于视频而言:视频帧与帧的间隔大约只有十到几十毫秒,通常拍摄的内容不会发生剧烈变化,它们之间存在非常强的相关性。

如下图所示,将视频图像分割成块,在时间相邻的图像之间进行匹配,然后将匹配之后的残差部分进行编码,这样可以较好地去除视频信号中的视频帧与帧之间的冗余,达到视频压缩的目的。这就是运动补偿技术,直到今天它仍然是视频编解码的核心技术之一。

运动估计和运动补偿:

变换编码的核心思想:是把视频数据分割成块,利用正交变换将数据的能量集中到较少几个变换系数上。结合量化和熵编码,我们可以获得更有效的压缩。视频编码中信息的损失和压缩比的获得,很大程度上来源于量化模块,就是将源信号中的单一样本映射到某一固定值,形成多到少的映射,从而达到压缩的目的,当然在压缩的过程中就引入了损失。量化后的信号再进行无损的熵编码,消除信号中的统计冗余。熵编码的研究最早可以追溯到 20 世纪 50 年代,经过几十年的发展,熵编码在视频编码中的应用更加成熟、更加精巧,充分利用视频数据中的上下文信息,将概率模型估计得更加准确,从而提高了熵编码的效率。例如H.264/AVC中的Cavlc(基于上下文的变长编码)、Cabac(基于上下文的二进制算术编码)。算术编码技术在后续的视频编码标准,如AV1、HEVC/H.265、VVC/H.266 中也有应用。

视频编码发展至今,VVC/H.266 作为最新制定的标准,采纳了一系列先进的技术,对混合编码框架的各个部分都进行了优化和改进,使得其率失真性能相比前一代标准,又提高了一倍。

例如:VVC/H.266 采用了128x128大小的基本编码单元,并且可以继续进行四叉树划分,支持对一个划分进行二分、三分;色度分量独立于亮度分量,支持单独进行划分;更多更精细的帧内预测方向、帧间预测模式;支持多种尺寸和形式的变换、环内滤波等。

VVC/H.266 的制定,目标是对多种视频内容有更好支持,例如屏幕共享内容、游戏、动漫、虚拟现实内容(VR、AR)等。其中也有特定的技术被采纳进标准,例如调色板模式、帧内运动补偿、仿射变换、跳过变换、自适应颜色变换等。   

回到本文的正题,接下来的内容,我们着重介绍视频编解码中的预测技术。

6、帧内预测技术

视频数据被划分成方块之后,相邻的方块的像素,以及方块内的像素,颜色往往是逐渐变化的,他们之间有比较强的有相似性。这种相似性,就是空间冗余。既然存在冗余,就可以用更少的数据量来表达这样的特征。

比如:先传输第一个像素的值,再传输第二个像素相对于第一个像素的变化值,这个变化值往往取值范围变小了许多,原来要8个bit来表达的像素值,可能只需要少于8个bit就足够了。

同样的道理,以像素块为基本单位,也可以进行类似的“差分”操作。我们从示例图中,来更加直观地感受一下这样的相似性。

如上图中所标出的两个8x8的块:其亮度分量(Y)沿着“左上到右下”的方向,具有连续性,变化不大。

假如:我们设计某种特定的“模式”,使其利用左边的块来“预测”右边的块,那么“原始像素”减去“预测像素”就可以减少传输所需要的数据量,同时将该“模式”写入最终的码流,解码器便可以利用左侧的块来“重建”右侧的块。

极端一点讲:假如左侧的块的像素值经过一定的运算可以完全和右侧的块相同,那么编码器只要用一个“模式”的代价,传输右侧的块。

当然,视频中的纹理多种多样,单一的模式很难对所有的纹理都适用,因此标准中也设计了多种多样的帧内预测模式,以充分利用像素间的相关性,达到压缩的目的。

例如下图所示的H.264中9种帧内预测方向:以模式0(竖直预测)为例,上方块的每个像素值(重建)各复制一列,得到帧内预测值。其它各种模式也采用类似的方法,不过,生成预测值的方式稍有不同。有这么多的模式,就产生了一个问题,对于一个块而言,我们应该采用哪种模式来进行编码呢?最佳的选择方式,就是遍历所有的模式进行尝试,计算其编码的所需的比特数和产生的质量损失,即率失真优化,这样明显非常复杂,因而也有很多种其它的方式来推断哪种模式更好,例如基于SATD或者边缘检测等。

从H.264的9种预测模式,到AV1的56种帧内方向预测模式,越来越多的模式也是为了更加精准地预测未编码的块,但是模式的增加,一方面增加了传输模式的码率开销,另一方面,从如此重多的模式中选一个最优的模式来编码,使其能达到更高的压缩比,这对编码器的设计和实现也提出了更高的要求。

7、帧间预测技术

以下5张图片是一段视频的前5帧:可以看出,图片中只有Mario和砖块在运动,其余的场景大多是相似的,这种相似性就称之为时间冗余。编码的时候,我们先将第一帧图片通过前文所述的帧内预测方式进行编码传输,再将后续帧的Mario、砖块的运动方向进行传输,解码的时候,就可以将运动信息和第一帧一起来合成后续的帧,这样就大大减少了传输所需的bit数。这种利用时间冗余来进行压缩的技术,就是运动补偿技术。该技术早在H.261标准中,就已经被采用。

细心地读者可能已经发现:Mario和砖块这样的物体怎么描述,才能让它仅凭运动信息就能完整地呈现出来?

其实视频编码中并不需要知道运动的物体的形状,而是将整帧图像划分成像素块,每个像素块使用一个运动信息。即基于块的运动补偿。

下图中红色圈出的白色箭头即编码砖块和Mario时的运动信息,它们都指向了前一帧中所在的位置。Mario和砖块都有两个箭头,说明它们都被划分在了两个块中,每一个块都有单独的运动信息。这些运动信息就是运动矢量。运动矢量有水平和竖直两个分量,代表是的一个块相对于其参考帧的位置变化。参考帧就是已经编码过的某一(多)个帧。

当然:传输运动矢量本身就要占用很多 bit。为了提高运动矢量的传输效率,主要有以下措施。

一方面:可以尽可能得将块划分变大,共用一个运动矢量,因为平坦区域或者较大的物体,他们的运动可能是比较一致的。从 H.264 开始,可变块大小的运动补偿技术被广泛采用。

另一方面:相邻的块之间的运动往往也有比较高的相似性,其运动矢量也有较高的相似性,运动矢量本身也可以根据相邻的块运动矢量来进行预测,即运动矢量预测技术;

最后:运动矢量在表达物体运动的时候,有精度的取舍。像素是离散化的表达,现实中物体的运动显然不是以像素为单位进行运动的,为了精确地表达物体的运动,需要选择合适的精度来定义运动矢量。各视频编解码标准都定义了运动矢量的精度,运动矢量精度越高,越能精确地表达运动,但是代价就是传输运动矢量需要花费更多的bit。

H.261中运动矢量是以整像素为精度的,H.264中运动矢量是以四分之一像素为精度的,AV1中还增加了八分之一精度。一般情况,时间上越近的帧,它们之间的相似性越高,也有例外,例如往复运动的场景等,可能相隔几帧,甚至更远的帧,会有更高的相似度。

为了充分利用已经编码过的帧来提高运动补偿的准确度,从H.264开始引入了多参考帧技术。

即:一个块可以从已经编码过的很多个参考帧中进行运动匹配,将匹配的帧索引和运动矢量信息都进行传输。

那么如何得到一个块的运动信息呢?最朴素的想法就是,将一个块,在其参考帧中,逐个位置进行匹配检查,匹配度最高的,就是最终的运动矢量。

匹配度:常用的有SAD(Sum of Absolute Difference)、SSD(Sum of Squared Difference)等。逐个位置进行匹配度检查,即常说的全搜索运动估计,其计算复杂度可想而知是非常高的。为了加快运动估计,我们可以减少搜索的位置数,类似的有很多算法,常用的如钻石搜索、六边形搜索、非对称十字型多层次六边形格点搜索算法等。

以钻石搜索为例,如下图所示,以起始的蓝色点为中心的9个匹配位置,分别计算这9个位置的SAD,如果SAD最小的是中心位置,下一步搜索中心点更近的周围4个绿色点的SAD,选择其中SAD最小的位置,继续缩小范围进行搜索;如果第一步中SAD最小的点不在中心,那么以该位置为中心,增加褐色的5或者3个点,继续计算SAD,如此迭代,直到找到最佳匹配位置。

编码器在实现时,可根据实际的应用场景,对搜索算法进行选择。

例如:在实时音视频场景下,计算复杂度是相对有限的,运动估计模块要选择计算量较小的算法,以平衡复杂度和编码效率。当然,运动估计与运动补偿的复杂度还与块的大小,参考帧的个数,亚像素的计算等有关,在此不再深入展开。

更多预测技术方面的原理这里就不再赘述。如果你对上面所述的预测技术理解上感到力不从心,这里有篇入门级的文章,可以先读读这篇《即时通讯音视频开发(四):视频编解码之预测技术介绍》。

8、写在最后

音视频编解码技术,归根结底就是在有限的资源下(网络带宽、计算资源等),让音质更清晰、视频更高质。

这其中,对于视频来说,质量的提升仍然有很多可以深入研究的热点问题。

比如:基于人眼的主观质量优化,主要利用人眼的视觉特性,将掩蔽效应、对比度灵敏度、注意力模型等与编码相结合,合理分配码率、减少编码损失引起的视觉不适。

AI在视频编解码领域的应用:包括将多种人工智能算法,如分类器、支持向量机、CNN等对编码参数进行快速选择,也可以使用深度学习对视频进行编码环外与编码环内的处理,如视频超分辨率、去噪、去雾、自适应动态范围调整等编码环外处理,达到提升视频质量的目的。

此外还有打破传统混合编码框架的深度神经网络编码,如Nvidia的Maxine视频会议服务,利用深度学习来提取特征,然后对特征进行传输以节省带宽。

附录:更多精华文章

[1] 实时音视频开发的其它精华资料:

[2] 开源实时音视频技术WebRTC的文章:

本文已同步发布于“即时通讯技术圈”公众号。

▲ 本文在公众号上的链接是:点此进入。同步发布链接是:http://www.52im.net/thread-3581-1-1.html

posted @ 2021-06-15 11:25 Jack Jiang 阅读(139) | 评论 (0)编辑 收藏

本文作者“商文默”,有修订和改动。

1、写在前面

即时通讯网整理的大量IM技术文章中(见本文末“参考资料”一节),有关消息可靠性和一致性问题的文章占了很大比重,原因是IM这类系统抛开各种眼花缭乱的产品功能和技术特性,保证消息的可靠性和一致性几乎是IM产品必需的素质。

试想如果一个IM连发出的消息都不知道对方到底能不能收到、发出的聊天内容对方看到的到底是不是“胡言乱语”(严重乱序问题),这样的APP用户肯定不会让他在手机上过夜(肯定第一时间卸载了),因为最基本的聊天逻辑都无法实现,它已经失去了IM软件本身的意义。

不过,另一个方面来讲,IM系统是不标准的(虽然曾经XMPP这种协议试图解决这个问题,但事实证明那根本不现实),各家几乎都是自已的私有协议、不同的实现逻辑,这也决定了即使同一个技术问题,对于IM来说很难有固定的实现套路和标准的解决方案。

所以,对于本文来说,文中作者虽然提供了有关IM消息“可靠性”与“一致性”问题的解决方案,但方案到底合不合理、适不适合你,这就是仁者见仁、智者见智的事了。用人话说就是:本文内容仅供参考,具体的解决方案请务结合自已的系统构架和实现情况,多阅读几篇即时通讯网上有关这个技术话题的文章,取其精华,找到适合自已的技术方案和思路才是最明智的。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170 [推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK

本文同步发布于:http://www.52im.net/thread-3574-1-1.html

2、本文引言

丛所周之,即时通讯聊天(IM)系统必需要解决消息可靠性及消息一致性问题(PS:如果具体IM系统是什么你都还没弄明白,先读这篇《零基础IM开发入门(一):什么是IM系统?)。

这两个问题,通俗来说就是:

  • 1)消息可靠性:简单来说就是不丢消息,会话一方发送消息,消息成功到达对方并正确显示;
  • 2)消息一致性:包括发送一方消息一致及会话双方消息一致,要求消息不重复,不乱序。

本文会从典型的IM消息发送逻辑开始,简单易懂地阐明消息可靠性、一致性问题的原理及可参考的技术解决方法,或许技术方案并不完美,但希望能为你的IM技术问题解决带来启发。

3、典型IM消息发送过程

IM的消息发送一般的实现过程可以分为两个阶段:

  • 1)发送方发送消息、服务端接收、返回消息 ACK 给发送方;
  • 2)服务端将消息推送到接收方。

判断消息发送是否成功主要依据第一阶段——即服务器是否接受到消息。

对于消息发送者来说,消息状态可以分为三类:

  • 1)正在发送;
  • 2)发送成功;
  • 3)发送失败。

具体来说,这三类状态的具体意义是:

  • 1)正在发送:发送方触发发送事件开始,到收到服务端返回消息对应 ACK 之前;
  • 2)发送成功:发送方收到消息对应 ACK 回复;
  • 3)发送失败:超过一定重发次数,未收到消息对应 ACK 回复。

对应的消息发送流程如下图所示:

4、IM消息可靠性

限于篇幅,对于IM消息可靠性的基本概念和详细原理建议阅读《零基础IM开发入门(三):什么是IM系统的可靠性?》,本文着重谈谈解决思路。

4.1 重发机制

保证消息发送第一阶段(见本文“3、典型IM消息发送过程”一节)消息成功发送的方法是设立重发机制:

  • 1)依据一定时长内是否收到消息对应 ACK,判断消息是否要重发;
  • 2)如果超过预设时长,就重新发送;
  • 3)当重发次数超过预设次数,就不再重发,判定该消息发送失败,修改消息发送状态。

PS:具体的完整方案级代码实现,可以参考MobileIMSDK  中有关QoS机制的代码实现。

4.2 会话记录检查

消息发送第二阶段(见本文“3、典型IM消息发送过程”一节)服务端推送消息到接收方,如果连接断开,会丢失消息。

所以要保证消息完整,就需要在建立连接后,根据上一条消息(已经 ACK)时间戳,获取会话记录,一次返回一段时间内所有消息(PS:中大型应用中,消息的拉取也不是个简单事情,详情可以阅读《IM开发干货分享:如何优雅的实现大量离线消息的可靠投递)。

另一种保证方法是加入定时轮询,检查消息完整性,具体的思路如下图所示。

建立连接流程图:

4.3 需要考虑的两个问题

消息重发、会话记录检查需要考虑两个问题:

  • 1)消息是否会重复发送;
  • 2)消息顺序是否会被打乱。

举两个例子。

关于消息重发问题:

  • 1)如果丢消息的点在消息达到服务端之前,服务端并没有收到消息,发送方重新发送丢失消息,服务端接收成功,不会产生两条相同消息;
  • 2)而如果服务端接收到消息,返回 ACK 丢失,这时再发送一次相同消息,就可能造成消息重复。

关于消息顺序问题:

  • 1)如果发送方连发三条消息,第一、第三条成功被服务端接收,第二条丢了,那第三条消息是否会被记录?
  • 2)如果这时第二条消息达到服务端,其顺序是在第三条时间之前还是之后(服务端一般都会给记录打一个时间戳)?

5、IM消息一致性

同上节一样,对于IM消息一致性的基本概念和详细原理建议阅读《零基础IM开发入门(四):什么是IM系统的消息时序一致性?》。

5.1 使用 uuid 消息去重

对于消息重发问题,可以给每条消息增加属性 uuid 作为消息唯一标识,重发消息 uuid 不变,前端根据 uuid 去重。大致思路就是这样。

PS:对于IM来说,消息ID也是个很大的技术话题,有兴趣可以读下面这个系列:

IM消息ID技术专题(一):微信的海量IM聊天消息序列号生成实践(算法原理篇)

IM消息ID技术专题(二):微信的海量IM聊天消息序列号生成实践(容灾方案篇)

IM消息ID技术专题(三):解密融云IM产品的聊天消息ID生成策略

IM消息ID技术专题(四):深度解密美团的分布式ID生成算法

IM消息ID技术专题(五):开源分布式ID生成器UidGenerator的技术实现

IM消息ID技术专题(六):深度解密滴滴的高性能ID生成器(Tinyid)

5.2 使用向量时钟进行消息排序

对于消息排序问题:因为在聊天中,消息的顺序对于发送方的表述有重要的影响,消息不完整或顺序颠倒都可能造成语意不连贯,甚至曲解。所以需要保证发送方发送消息顺序,而会话双方消息排序需要考虑实际情况。

在一般的认知里:状态是正在发送的消息,应该还没有被对方看到,只有发送成功的消息,才会被对方看到。但在实现中,消息发送成功是以服务器接收消息并返回 ACK 成功为判断依据,而不是被对方接收到。

那么就会出现这样一个问题:如果一条消息状态是正在发送,此时收到一条消息,那么收到的消息是在正在发送的消息之前还是之后?

这是一个上下文关系,关键问题是:发送方是以哪条所见消息为依据发送消息的。

这里提供一种思路:借鉴分布式系统中的向量时钟算法(见《分布式系统中的向量时钟算法)。

先简单描述向量时钟算法:

向量时钟算法用于在分布式系统中生成事件偏序关系,并纠正因果关系。一个系统包含 N 个节点,每个节点产生的消息体中包含该节点的逻辑时钟,整体系统的向量时钟由 N 维逻辑时钟组成,并在每个节点产生的消息体中传递。

简单来说,向量时钟算法的实现原理如下:

  • 1)初始状态,向量值为 0;
  • 2)每次节点处理完节点事件,该节点时钟+1;
  • 3)每次节点发送消息,将包含自身时钟的系统向量时钟一起发送;
  • 4)每次节点收到消息,更新向量时钟,该节点时钟+1,其他节点对比每个节点本地保留的向量时钟值和消息体中向量时钟值,取最大值;
  • 5)节点同时收到多条消息,判断接收消息的向量时钟之间是否存在偏序关系。

针对上述的第5)点:

  • 1)如果存在偏序关系,则合并向量时钟,取偏序较大的向量时钟;
  • 2)如果不存在偏序关系,则不能合并。

偏序关系:如果 A 向量中的每一维都大于等于 B 向量,则 A、B 之间存在偏序关系,否则不存在偏序关系。

对于IM为聊天消息排序来说,其实就是处理聊天消息的上下文语境,决定消息之间的因果关系。

参考向量时钟算法:假设有 N 个消息会话方,系统的向量时钟由 N 维时钟组成,向量时钟在各方发送的消息体中传递,并依据向量时钟排序。

具体实现思路如下:

  • 1)系统向量时钟设为 (0, 0, …, N);
  • 2)节点发送消息,更新系统向量时钟,该节点时钟加一,其他节点不变;
  • 3)节点接收消息,更新系统向量时钟,该节点时钟加一;其他节点对比每个节点本地保留的向量时钟的值和消息中向量时钟的值,取最大值;
  • 4)依据消息体内系统向量时钟的偏序关系决定消息顺序。

针对上述第4)点:

  • 1)如果可以确定偏序关系,则根据偏序关系由小到大显示;
  • 2)如果多条消息不能确定偏序关系,则按照自然顺序(接收到的顺序)显示。

向量时钟在理论上可以解决大部分消息一致性的问题,但在实现中还需要考虑实际使用时的体验。

这其中最需要关注的问题是:是否要强制排序,或者说,如果实际显示顺序和向量时钟之间的偏序关系不一致,是否要移动消息之间的顺序。

举个例子:在一个有多人的会话中,如果有一方网速特别慢,收不到消息,也发不出消息。在他看到的最后的消息之后,其他人已经开始新的话题,这时他关于上一个话题的消息终于发送成功,并被其他人收到。

此时就存在这样一个问题:这条关于上一个话题的消息是显示在最后,还是移到较早时间?

  • 1)如果显示在最后,但消息内容和目前的话题不相关,其他人可能会感到莫名其妙;
  • 2)如果把消息移到较早时间,那么这条消息可能不会被其他人看到,或者看到前面多了一条消息,会有种突兀的感觉。

IM 的场景很多,也很复杂,更多的时候需要从产品角度考虑问题。

对于消息是否需要排序的问题,这里只提出一个比较通用的方案:建议会话中不强制排序,会话历史记录中按照向量时钟的偏序关系进行排序。

6、本文小结

对于 IM 系统消息可靠性及一致性问题,通过消息重发机制保证消息成功被服务端接收,通过会话记录检查保证收取消息完整,从而保证整个消息发送过程的可靠性。使用 uuid 消息去重,参考向量时钟算法进行消息排序,为保证消息一致性提供一种解决方案。

总之,IM这类系统看似简单,实则水深似海,如果你是IM开发新手,可以从《新手入门一篇就够:从零开发移动端IM》这篇入手系统学习。如果你自认为已是IM老手,这里整理的 IM中大型架构设计 方面的文章或许可以参考一下。

7、参考资料

[1] 零基础IM开发入门(三):什么是IM系统的可靠性?

[2] 零基础IM开发入门(四):什么是IM系统的消息时序一致性?

[3] IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

[4] IM消息送达保证机制实现(二):保证离线消息的可靠投递

[5] 如何保证IM实时消息的“时序性”与“一致性”?

[6] 一个低成本确保IM消息时序的方法探讨

[7] IM群聊消息如此复杂,如何保证不丢不重?

[8] 完全自已开发的IM该如何设计“失败重试”机制?

[9] IM开发干货分享:如何优雅的实现大量离线消息的可靠投递

[10] 从客户端的角度来谈谈移动端IM的消息可靠性和送达机制

[11] 一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等

[12] 从新手到专家:如何设计一套亿级消息量的分布式IM系统

本文已同步发布于“即时通讯技术圈”公众号。

▲ 本文在公众号上的链接是:点此进入。同步发布链接是:http://www.52im.net/thread-3574-1-1.html

posted @ 2021-06-07 20:34 Jack Jiang 阅读(167) | 评论 (0)编辑 收藏

     摘要: 本文由喜马拉雅技术团队原创分享,原题《喜马拉雅自研网关架构实践》,有改动。1、引言网关是一个比较成熟的产品,基本上各大互联网公司都会有网关这个中间件,来解决一些公有业务的上浮,而且能快速的更新迭代。如果没有网关,要更新一个公有特性,就要推动所有业务方都更新和发布,那是效率极低的事,有网关后,这一切都变得不是问题。喜马拉雅也是一样,用户数增长达到 6 亿多的级别,Web 服务个数达到500+,目前我...  阅读全文

posted @ 2021-05-31 10:30 Jack Jiang 阅读(237) | 评论 (0)编辑 收藏

     摘要: 本文来自“糊糊糊糊糊了”的分享,原题《实时消息推送整理》,有优化和改动。1、写在前面对Web端即时通讯技术熟悉的开发者来说,我们回顾网页端IM的底层通信技术,从短轮询、长轮询,到后来的SSE以及WebSocket,使用门槛越来越低(早期的长轮询Comet这类技术实际属于hack手段,使用门槛并不低),技术手段越来越先进,网页端即时通讯技术的体验也因此越来越好。但上周在编辑《...  阅读全文

posted @ 2021-05-25 12:18 Jack Jiang 阅读(171) | 评论 (0)编辑 收藏

本文由爱奇艺技术团队原创分享,原题《构建通用WebSocket推送网关的设计与实践》,有优化和改动。

1、引言

丛所周之,HTTP协议是一种无状态、基于TCP的请求/响应模式的协议,即请求只能由客户端发起、由服务端进行响应。在大多数场景,这种请求/响应的Pull模式可以满足需求。但在某些情形:例如消息推送(IM中最为常见,比如IM的离线消息推送)、实时通知等应用场景,需要实时将数据同步到客户端,这就要求服务端支持主动Push数据的能力。

传统的Web服务端推送技术历史悠久,经历了短轮询、长轮询等阶段的发展(见《新手入门贴:史上最全Web端即时通讯技术原理详解),一定程度上能够解决问题,但也存在着不足,例如时效性、资源浪费等。HTML5标准带来的WebSocket规范基本结束了这一局面,成为目前服务端消息推送技术的主流方案。

在系统中集成WebSocket十分简单,相关讨论与资料很丰富。但如何实现一个通用的WebSocket推送网关尚未有成熟的方案。目前的云服务厂商主要关注iOS和安卓等移动端推送,也缺少对WebSocket的支持。本文分享了爱奇艺基于Netty实现WebSocket长连接实时推送网关时的实践经验总结。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170 [推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK

本文同步发布于:http://www.52im.net/thread-3539-1-1.html

2、专题目录

本文是系列文章的第4篇,总目录如下:

长连接网关技术专题(一):京东京麦的生产级TCP网关技术实践总结

长连接网关技术专题(二):知乎千万级并发的高性能长连接网关技术实践

长连接网关技术专题(三):手淘亿级移动端接入层网关的技术演进之路

长连接网关技术专题(四):爱奇艺WebSocket实时推送网关技术实践》(* 本文

其它相关技术文章:

绝对干货:基于Netty实现海量接入的推送服务技术要点

京东到家基于Netty的WebSocket应用实践分享

爱奇艺技术团队分享的其它文章:

爱奇艺技术分享:轻松诙谐,讲解视频编解码技术的过去、现在和将来

爱奇艺技术分享:爱奇艺Android客户端启动速度优化实践总结

爱奇艺移动端网络优化实践分享:网络请求成功率优化篇

3、旧方案存在的技术痛点

爱奇艺号是我们内容生态的重要组成,作为前台系统,对用户体验有较高要求,直接影响着创作者的创作热情。

目前,爱奇艺号多个业务场景中用到了WebSocket实时推送技术,包括:

  • 1)用户评论:实时的将评论消息推送到浏览器;
  • 2)实名认证:合同签署前需要对用户进行实名认证,用户扫描二维码后进入第三方的认证页面,认证完成后异步通知浏览器认证的状态;
  • 3)活体识别:类似实名认证,当活体识别完成后,异步将结果通知浏览器。

在实际的业务开发中,我们发现,WebSocket实时推送技术在使用中存在一些问题。

这些问题是:

  • 1)首先:WebSocket技术栈不统一,既有基于Netty实现的,也有基于Web容器实现的,给开发和维护带来困难;
  • 2)其次:WebSocket实现分散在在各个工程中,与业务系统强耦合,如果有其他业务需要集成WebSocket,面临着重复开发的窘境,浪费成本、效率低下;
  • 3)第三:WebSocket是有状态协议的,客户端连接服务器时只和集群中一个节点连接,数据传输过程中也只与这一节点通信。WebSocket集群需要解决会话共享的问题。如果只采用单节点部署,虽然可以避免这一问题,但无法水平扩展支撑更高负载,有单点的风险;
  • 4)最后:缺乏监控与报警,虽然可以通过Linux的Socket连接数大致评估WebSocket长连接数,但数字并不准确,也无法得知用户数等具有业务含义的指标数据;无法与现有的微服务监控整合,实现统一监控和报警。

PS:限于篇幅本文不详细介绍WebSocket技术本身,有兴趣可以详读《WebSocket从入门到精通,半小时就够!》。

4、新方案的技术目标

如上节所示,为了解决旧方案中存在的问题,我们需要实现统一的WebSocket长连接实时推送网关。

这套新的网关需要具备如下特点:

  • 1)集中实现长连接管理和推送能力:统一技术栈,将长连接作为基础能力沉淀,便于功能迭代和升级维护;
  • 2)与业务解耦:将业务逻辑与长连接通信分离,使业务系统不再关心通信细节,也避免了重复开发,浪费研发成本;
  • 3)使用简单:提供HTTP推送通道,方便各种开发语言的接入。业务系统只需要简单的调用,就可以实现数据推送,提升研发效率;
  • 4)分布式架构:实现多节点的集群,支持水平扩展应对业务增长带来的挑战;节点宕机不影响服务整体可用性,保证高可靠;
  • 5)多端消息同步:允许用户使用多个浏览器或标签页同时登陆在线,保证消息同步发送;
  • 6)多维度监控与报警:自定义监控指标与现有微服务监控系统打通,出现问题时可及时报警,保证服务的稳定性。

5、新方案的技术选型

在众多的WebSocket实现中,从性能、扩展性、社区支持等方面考虑,最终选择了Netty。Netty是一个高性能、事件驱动、异步非阻塞的网络通信框架,在许多知名的开源软件中被广泛使用。

PS:如果你对Netty知之甚少,可以详读以下两篇:

WebSocket是有状态的,无法像直接HTTP以集群方式实现负载均衡,长连接建立后即与服务端某个节点保持着会话,因此集群下想要得知会话属于哪个节点有点困难。

解决以上问题一般有两种技术方案:

  • 1)一种是使用类似微服务的注册中心来维护全局的会话映射关系;
  • 2)一种是使用事件广播由各节点自行判断是否持有会话,两种方案对比如下表所示。

WebSocket集群方案:

综合考虑实现成本与集群规模,选择了轻量级的事件广播方案。

实现广播可以选择基于RocketMQ的消息广播、基于Redis的Publish/Subscribe、基于ZooKeeper的通知等方案,其优缺点对比如下表所示。从吞吐量、实时性、持久化、实现难易等方面考虑,最终选择了RocketMQ。

广播的实现方案对比:

6、新方案的实现思路

6.1 系统架构

网关的整体架构如下图所示:

网关的整体流程如下:

1)客户端与网关任一节点握手建立起长连接,节点将其加入到内存维护的长连接队列。客户端定时向服务端发送心跳消息,如果超过设定的时间仍没有收到心跳,则认为客户端与服务端的长连接已断开,服务端会关闭连接,清理内存中的会话。

2)当业务系统需要向客户端推送数据时,通过网关提供的HTTP接口将数据发向网关。

3)网关在接收到推送请求后,将消息写入RocketMQ。

4)网关作为消费者,以广播模式消费消息,所有节点都会接收到消息。

5)节点接收到消息后判断推送的消息目标是否在自己内存中维护的长连接队列里,如果存在则通过长连接推送数据,否则直接忽略。

网关以多节点方式构成集群,每节点负责一部分长连接,可实现负载均衡,当面对海量连接时,也可以通过增加节点的方式分担压力,实现水平扩展。

同时,当节点出现宕机时,客户端会尝试重新与其他节点握手建立长连接,保证服务整体的可用性。

6.2 会话管理

WebSocket长连接建立起来后,会话维护在各节点的内存中。SessionManager组件负责管理会话,内部使用了哈希表维护了UID与UserSession的关系。

UserSession代表用户维度的会话,一个用户可能会同时建立多个长连接,因此UserSession内部同样使用了一个哈希表维护Channel与ChannelSession的关系。

为了避免用户无限制的创建长连接,UserSession在内部的ChannelSession超过一定数量后,会将最早建立的ChannelSession关闭,减少服务器资源占用。SessionManager、UserSession、ChannelSession的关系如下图所示。

SessionManager组件:

6.3 监控与报警

为了了解集群建立了多少长连接、包含了多少用户,网关提供了基本的监控与报警能力。

网关接入了Micrometer,将连接数与用户数作为自定义指标暴露,供Prometheus进行采集,实现了与现有的微服务监控系统打通。

Grafana中方便地查看连接数、用户数、JVM、CPU、内存等指标数据,了解网关当前的服务能力与压力。报警规则也可以在Grafana中配置,当数据异常时触发奇信(内部报警平台)报警。

7、新方案的性能压测

压测准备:

  • 1)压测选择两台配置为4核16G的虚拟机,分别作为服务器和客户端;
  • 2)压测时选择为网关开放了20个端口,同时建立20个客户端;
  • 3)每个客户端使用一个服务端端口建立起5万连接,可以同时创建百万个连接。

连接数(百万级)与内存使用情况如下图所示:

给百万个长连接同时发送一条消息,采用单线程发送,服务器发送完成的平均耗时在10s左右,如下图所示。

服务器推送耗时: 

一般同一用户同时建立的长连接都在个位数。以10个长连接为例,在并发数600、持续时间120s条件下压测,推送接口的TPS大约在1600+,如下图所示。

长连接10、并发600、持续时间120s的压测数据:

当前的性能指标已满足我们的实际业务场景,可支持未来的业务增长。

8、新方案的实际应用案例

为了更生动的说明优化效果,文章最后,我们也以封面图添加滤镜效果为例,介绍一个爱奇艺号使用新WebSocket网关方案的案例。

爱奇艺号自媒体发表视频时,可选择为封面图添加滤镜效果,引导用户提供提供更优质的封面。

当用户选择一个封面图后,会提交异步的后台处理任务。当异步任务处理完成后,通过WebSocket将不同滤镜效果处理后的图片返回给浏览器,业务场景如下图所示。

从研发效率方面考虑,如果在业务系统中集成WebSocket,至少需要1-2天的开发时间。

如果直接使用新的WebSocket网关的推送能力,只需要简单的接口调用就实现了数据推送,开发时间降低到分钟级别,研发效率大大提高。

从运维成本方面考虑,业务系统不再含有与业务逻辑无关的通信细节,代码的可维护性更强,系统架构变得更加简单,运维成本大大降低。

9、写在最后

WebSocket是目前实现服务端推送的主流技术,恰当使用能够有效提供系统响应能力,提升用户体验。通过WebSocket长连接网关可以快速为系统增加数据推送能力,有效减少运维成本,提高开发效率。

长连接网关的价值在于:

  • 1)它封装了WebSocket通信细节,与业务系统解耦,使得长连接网关与业务系统可独立优化迭代,避免重复开发,便于开发与维护;
  • 2)网关提供了简单易用的HTTP推送通道,支持多种开发语言接入,便于系统集成和使用;
  • 3)网关采用了分布式架构,可以实现服务的水平扩容、负载均衡与高可用;
  • 4)网关集成了监控与报警,当系统异常时能及时预警,保证服务的健康和稳定。

目前,新的WebSocket长连接实时网关已在爱奇艺号图片滤镜结果通知、MCN电子签章等多个业务场景中得到应用。

未来还有许多方面需要探索,例如消息的重发与ACK、WebSocket二进制数据的支持、多租户的支持等。

附录:更多相关技术资料

[1] 有关WEB端即时通讯开发:

新手入门贴:史上最全Web端即时通讯技术原理详解

Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE

SSE技术详解:一种全新的HTML5服务器推送事件技术

Comet技术详解:基于HTTP长连接的Web端实时通信技术

新手快速入门:WebSocket简明教程

WebSocket详解(一):初步认识WebSocket技术

WebSocket详解(二):技术原理、代码演示和应用案例

WebSocket详解(三):深入WebSocket通信协议细节

WebSocket详解(四):刨根问底HTTP与WebSocket的关系(上篇)

WebSocket详解(五):刨根问底HTTP与WebSocket的关系(下篇)

WebSocket详解(六):刨根问底WebSocket与Socket的关系

socket.io实现消息推送的一点实践及思路

LinkedIn的Web端即时通讯实践:实现单机几十万条长连接

Web端即时通讯技术的发展与WebSocket、Socket.io的技术实践

Web端即时通讯安全:跨站点WebSocket劫持漏洞详解(含示例代码)

开源框架Pomelo实践:搭建Web端高性能分布式IM聊天服务器

使用WebSocket和SSE技术实现Web端消息推送

详解Web端通信方式的演进:从Ajax、JSONP 到 SSE、Websocket

MobileIMSDK-Web的网络层框架为何使用的是Socket.io而不是Netty?

理论联系实际:从零理解WebSocket的通信原理、协议格式、安全性

微信小程序中如何使用WebSocket实现长连接(含完整源码)

八问WebSocket协议:为你快速解答WebSocket热门疑问

Web端即时通讯实践干货:如何让你的WebSocket断网重连更快速?

WebSocket从入门到精通,半小时就够!

WebSocket硬核入门:200行代码,教你徒手撸一个WebSocket服务器

>> 更多同类文章 ……

[2] 有关推送技术的文章:

一个基于MQTT通信协议的完整Android推送Demo

求教android消息推送:GCM、XMPP、MQTT三种方案的优劣

移动端实时消息推送技术浅析

绝对干货:基于Netty实现海量接入的推送服务技术要点

极光推送系统大规模高并发架构的技术实践分享

魅族2500万长连接的实时消息推送架构的技术实践分享

专访魅族架构师:海量长连接的实时消息推送系统的心得体会

基于WebSocket实现Hybrid移动应用的消息推送实践(含代码示例)

一个基于长连接的安全可扩展的订阅/推送服务实现思路

实践分享:如何构建一套高可用的移动端消息推送系统?

Go语言构建千万级在线的高并发消息推送系统实践(来自360公司)

腾讯信鸽技术分享:百亿级实时消息推送的实战经验

百万在线的美拍直播弹幕系统的实时推送技术实践之路

京东京麦商家开放平台的消息推送架构演进之路

技术干货:从零开始,教你设计一个百万级的消息推送系统

长连接网关技术专题(四):爱奇艺WebSocket实时推送网关技术实践

>> 更多同类文章 ……

本文已同步发布于“即时通讯技术圈”公众号。

▲ 本文在公众号上的链接是:点此进入。同步发布链接是:http://www.52im.net/thread-3539-1-1.html

posted @ 2021-05-17 23:12 Jack Jiang 阅读(283) | 评论 (0)编辑 收藏

     摘要: 本文引用了作者“大古同学”的“二维码扫码登录是什么原理”一文的主要内容,为了更好的理解和阅读,即时通讯网收录时有修订和改动,感谢原作者的分享。1、引言自从微信的PC端使用扫码登陆认证逻辑后,这种方式似乎在越来越多的IM中看到(虽然我个人认为这种登录方式很酷,但并不方便,尤其手机不大身边的时候)。 ▲ 上图微信PC端的扫码登录界面...  阅读全文

posted @ 2021-05-10 13:42 Jack Jiang 阅读(184) | 评论 (0)编辑 收藏

     摘要: 本文原题“百度直播消息服务架构实践”,由百度APP消息中台团队原创分享于“百度Geek说”公众号,为了让文章内容更通俗易懂,本次已做排版优化和内容重新划分,原文链接在文末。1、引言一套完整的直播系统核心功能有两个:1)实时音视频的推拉流;2)直播间消息流的收发(包括聊天消息、弹幕、指令等)。本文主要分享的是百度直播的消息系统的架构设计实践和演进过程。...  阅读全文

posted @ 2021-04-27 15:17 Jack Jiang 阅读(195) | 评论 (0)编辑 收藏

     摘要: 文中引用了参考资料中的部分内容,本文参考资料详见文末“参考资料”一节,感谢资料分享者。1、引言对于IM开发者而言,网络保活这件事再熟悉不过了,比如这是我最近一篇有关网络保活话题文章《一文读懂即时通讯应用中的网络心跳包机制:作用、原理、实现思路等》,以及我分享的大量代码实战编码中也都必须要考虑这个问题的实现,比如最近的这篇《跟着源码学IM(五):正确理解IM长连接、心跳及重连...  阅读全文

posted @ 2021-04-19 15:10 Jack Jiang 阅读(284) | 评论 (0)编辑 收藏

     摘要: 本文作者芋艿,原题“使用 Netty 实现 IM 聊天贼简单”,本底价有修订和改动。一、本文引言上篇《跟着源码学IM(七):手把手教你用WebSocket打造Web端IM聊天》中,我们使用 WebSocket 实现了一个简单的 IM 功能,支持身份认证、私聊消息、群聊消息。然后就有人发私信,希望使用纯 Netty 实现一个类似的功能,因此就有了本文。注:源码请从同步链接附件...  阅读全文

posted @ 2021-04-12 15:43 Jack Jiang 阅读(312) | 评论 (0)编辑 收藏

     摘要: 本文作者芋艿,原题“芋道 Spring Boot WebSocket 入门”,本次有修订和改动。一、引言WebSocket如今在Web端即时通讯技术应用里使用广泛,不仅用于传统PC端的网页里,也被很多移动端开发者用于基于HTML5的混合APP里。对于想要在基于Web的应用里添加IM、推送等实时通信功能,WebSocket几乎是必须要掌握的技术。本文将基于Tomcat和Spr...  阅读全文

posted @ 2021-04-06 22:05 Jack Jiang 阅读(216) | 评论 (0)编辑 收藏

     摘要: 本文原作者Chank,原题“如何设计一个亿级消息量的 IM 系统”,为了提升内容质量,本次有修订和改动。1、写有前面本文将在亿级消息量、分布式IM系统这个技术前提下,分析和总结实现这套系统所需要掌握的知识点,内容没有高深的技术概念,尽量做到新手老手皆能读懂。本文不会给出一套通用的IM方案,也不会评判某种架构的好坏,而是讨论设计IM系统的常见难题跟业界的解决方案。因为也没有所...  阅读全文

posted @ 2021-03-29 22:36 Jack Jiang 阅读(247) | 评论 (0)编辑 收藏

本文内容和编写思路是基于邓昀泽的“大规模并发IM服务架构设计”、“IM的弱网场景优化”两文的提纲进行的,感谢邓昀泽的无私分享。

1、引言

接上篇《一套亿级用户的IM架构技术干货(上篇):整体架构、服务拆分等》,本文主要聚焦这套亿级用户的IM架构的一些比较细节但很重要的热门问题上,比如:消息可靠性、消息有序性、数据安全性、移动端弱网问题等。

以上这些热门IM问题每个话题其实都可以单独成文,但限于文章篇幅,本文不会逐个问题详细深入地探讨,主要以抛砖引玉的方式引导阅读者理解问题的关键,并针对问题提供专项研究文章链接,方便有选择性的深入学习。希望本文能给你的IM开发带来一些益处。

本文已同步发布于“即时通讯技术圈”公众号,欢迎关注。公众号上的链接是:点此进入

2、系列文章

为了更好以进行内容呈现,本文拆分两了上下两篇。

本文是2篇文章中的第2篇:

一套亿级用户的IM架构技术干货(上篇):整体架构、服务拆分等

一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等》(本文)

本篇主要聚焦这套亿级用户的IM架构的一些比较细节但很重要的热门问题上。

3、消息可靠性问题

消息的可靠性是IM系统的典型技术指标,对于用户来说,消息能不能被可靠送达(不丢消息),是使用这套IM的信任前提。

换句话说,如果这套IM系统不能保证不丢消息,那相当于发送的每一条消息都有被丢失的概率,对于用户而言,一定会不会“放心”地使用它,即“不信任”这套IM。

从产品经理的角度来说,有这样的技术障碍存在,再怎么费力的推广,最终用户都会很快流失。所以一套IM如果不能保证消息的可靠性,那问题是很严重的。

PS:如果你对IM消息可靠性的问题还没有一个直观的映象的话,通过《零基础IM开发入门(三):什么是IM系统的可靠性?》这篇文章可以通俗易懂的理解它。

如上图所示,消息可靠性主要依赖2个逻辑来保障:

  • 1)上行消息可靠性;
  • 2)下行消息可靠性。

1)针对上行消息的可靠性,可以这样的思路来处理:

用户发送一个消息(假设协议叫PIMSendReq),用户要给这个消息设定一个本地ID,然后等待服务器操作完成给发送者一个PIMSendAck(本地ID一致),告诉用户发送成功了。

如果等待一段时间,没收到这个ACK,说明用户发送不成功,客户端SDK要做重试操作。

2)针对下行消息的可靠性,可以这样的思路来处理:

服务收到了用户A的消息,要把这个消息推送给B、C、D 3个人。假设B临时掉线了,那么在线推送很可能会失败。

因此确保下行可靠性的核心是:在做推送前要把这个推送请求缓存起来。

这个缓存由存储系统来保证,MsgWriter要维护一个(离线消息列表),用户的一条消息,要同时写入B、C、D的离线消息列表,B、C、D收到这个消息以后,要给存储系统一个ACK,然后存储系统把消息ID从离线消息列表里拿掉。

针对消息的可靠性问题,具体的解决思路还可以从另一个维度来考虑:即实时消息的可靠性和离线消息的可靠性。

有兴趣可以深入读一读这两篇:

IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

IM消息送达保证机制实现(二):保证离线消息的可靠投递

而对于离线消息的可靠性来说,单聊和群聊又有很大区别,有关群聊的离线消息可靠投递问题,可以深入读一读《IM开发干货分享:如何优雅的实现大量离线消息的可靠投递》。

4、消息有序性问题

消息的有序性问题是分布式IM系统中的另一个技术“硬骨头”。

因为是分布式系统,客户端和服务器的时钟可能是不同步的。如果简单依赖某一方的时钟,就会出现大量的消息乱序。

比如只依赖客户端的时钟,A比B时间晚30分钟。所有A给B发消息,然后B给A回复。

发送顺序是:

客户端A:“XXX”

客户端B:“YYY”

接收方的排序就会变成:

客户端B:“YYY”

客户端A:“XXX”

因为A的时间晚30分钟,所有A的消息都会排在后面。

如果只依赖服务器的时钟,也会出现类似的问题,因为2个服务器时间可能也不一致。虽然客户端A和客户端B时钟一致,但是A的消息由服务器S1处理,B的消息由服务器S2处理,也会导致同样消息乱序。

为了解决这种问题,我的思路是通过可以做这样一系列的操作来实现。

1)服务器时间对齐:

这部分就是后端运维的锅了,由系统管理员来尽量保障,没有别的招儿。

2)客户端通过时间调校对齐服务器时间:

比如:客户端登录以后,拿客户端时间和服务器时间做差值计算,发送消息的时候考虑这部分差值。

在我的im架构里,这个能把时间对齐到100ms这个级,差值再小的话就很困难了,因为协议在客户端和服务器之间传递速度RTT也是不稳定的(网络传输存在不可控的延迟风险嘛)。

3)消息同时带上本地时间和服务器时间:

具体可以这样的处理:排序的时候,对于同一个人的消息,按照消息本地时间来排;对于不同人的消息,按照服务器时间来排,这是插值排序算法。

PS:关于消息有序性的问题,显然也不是上面这三两句话能讲的清楚,如果你想更通俗一理解它,可以读一读《零基础IM开发入门(四):什么是IM系统的消息时序一致性?》。

另外:从技术实践可行性的角度来说,《一个低成本确保IM消息时序的方法探讨》、《如何保证IM实时消息的“时序性”与“一致性”?》这两篇中的思路可以借鉴一下。

实际上,消息的排序问题,还可以从消息ID的角度去处理(也就是通过算法让消息ID产生顺序性,从而根据消息ID就能达到消息排序的目的)。

有关顺序的消息ID算法问题,这两篇非常值得借鉴:IM消息ID技术专题(一):微信的海量IM聊天消息序列号生成实践(算法原理篇)》、《IM消息ID技术专题(三):解密融云IM产品的聊天消息ID生成策略》,我就不废话了。

5、消息已读同步问题

消息的已读未读功能,如下图所示: 

上图就是钉钉中的已读未读消息。这在企业IM场景下非常有用(因为做领导的都喜欢,你懂的)。

已读未读功能,对于一对一的单聊消息来说,还比较好理解:就是多加一条对应的回执息(当用户阅读这条消息时发回)。

但对于群聊这说,这一条消息有多少人已读、多少人未读,想实现这个效果,那就真的有点麻烦了。对于群聊的已读未读功能实现逻辑,这里就不展开了,有兴趣可以读一下这篇《IM群聊消息的已读回执功能该怎么实现?》。

回归到本节的主题“已读同步”的问题,这显示难度又进一级,因为已读未读回执不只是针对“账号”,现在还要细分到“同一账号在不同端登陆”的情况,对于已读回执的同步逻辑来说,这就有点复杂化了。

在这里,根据我这边IM架构的实践经验,提供一些思路。

具体来说就是:用户可能有多个设备登录同一个账户(比如:Web PC和移动端同时登陆),这种情况下的已读未读功能,就需要来实现已读同步,否则在设备1看过的消息,设备2看到依然是未读消息,从产品的角度来说,这就影响用户体验了。

对于我的im架构来说,已读同步主要依赖2个逻辑来保证:

  • 1)同步状态维护,为用户的每一个Session,维护一个时间戳,保存最后的读消息时间;
  • 2)如果用户打开了某个Session,且用户有多个设备在线,发送一条PIMSyncRead消息,通知其它设备。

6、数据安全问题

6.1 基础

IM系统架构中的数据安全比一般系统要复杂一些,从通信的角度来说,它涉及到socket长连接通信的安全性和http短连接的两重安全性。而随着IM在移动端的流行,又要在安全性、性能、数据流量、用户体验这几个维度上做权衡,所以想要实现一套完善的IM安全架构,要面临的挑战是很多的。

IM系统架构中,所谓的数据安全,主要是通信安全和内容安全。

6.2 通信安全

所谓的通信安全,这就要理解IM通信的服务组成。

目前来说,一个典型的im系统,主要由两种通信服务组成:

  • 1)socket长连接服务:技术上也就是多数人耳熟能详的网络通信这一块,再细化一点也就是tcp、udp协议这一块;
  • 2)http短连接服务:也就是最常用的http rest接口那些。

对于提升长连接的安全性思路,可以深入阅读《通俗易懂:一篇掌握即时通讯的消息传输安全原理》。另外,微信团队分享的《微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解》一文,也非常有参考意义。

如果是通信安全级别更高的场景,可以参考《即时通讯安全篇(二):探讨组合加密算法在IM中的应用》,文中关于组合加密算法的使用思路非常不错。

至于短连接安全性,大家就很熟悉了,开启https多数情况下就够用了。如果对于https不甚了解,可以从这几篇开始:《一文读懂Https的安全性原理、数字证书、单项认证、双项认证等》、《即时通讯安全篇(七):如果这样来理解HTTPS,一篇就够了》。

6.3 内容安全

这个可能不太好理解,上面既然实现了通信安全,那为什么还要纠结“内容安全”?

我们了解一下所谓的密码学三大作用:加密( Encryption)、认证(Authentication),鉴定(Identification) 。

详细来说就是:

加密:防止坏人获取你的数据。

认证:防止坏人修改了你的数据而你却并没有发现。

鉴权:防止坏人假冒你的身份。

在上节中,恶意攻击者如果在通信环节绕开或突破了“鉴权”、“认证”,那么依赖于“鉴权”、“认证”的“加密”,实际上也有可有被破解。

针对上述问题,那么我们需要对内容进行更加安全独立的加密处理,就这是所谓的“端到端加密”(E2E)。

比如,那个号称无法被破解的IM——Telegram,实际上就是使用了端到端加密技术。

关于端到端加密,这里就不深入探讨,这里有两篇文章有兴趣地可以深入阅读:

移动端安全通信的利器——端到端加密(E2EE)技术详解

简述实时音视频聊天中端到端加密(E2EE)的工作原理

7、雪崩效应问题

在分布式的IM架构中,存在雪崩效应问题。

我们知道,分布式的IM架构中,为了高可用性,用户每次登陆都是根据负载均衡算法分配到不同的服务器。那么问题就来了。

举个例子:假设有5个机房,其中A机房故障,导致这个机房先前服务的用户都跑去B机房。B机房不堪重负也崩溃了,A+B的用户跑去机房C,连锁反应会导致所有服务挂掉。

防止雪崩效应需要在服务器架构,客户端链接策略上有一些配合的解决方案。服务器需要有限流能力作为基础,主要是限制总服务用户数和短时间链接用户数。

在客户端层面,发现服务断开之后要有一个策略,防止大量用户同一时间去链接某个服务器。

通常有2种方案:

  • 1)退避:重连之间设置一个随机的间隔;
  • 2)LBS:跟服务器申请重连的新的服务器IP,然后由LBS服务去降低短时间分配到同一个服务器的用户量。

这2种方案互不冲突,可以同时做。

8、弱网问题

8.1 弱网问题的原因

鉴于如今IM在移动端的流行,弱网是很常态的问题。电梯、火车上、开车、地铁等等场景,都会遇到明显的弱网问题。

那么为什么会出现弱网问题?

要回答这个问题,那就需要从无线通信的原理上去寻找答案。

因为无线通信的质量受制于很多方面的因素,比如:无线信号强弱变化快、信号干扰、通信基站分布不均、移动速度太快等等。要说清楚这个问题,那就真是三天三夜都讲不完。

有兴趣的读者,一定要仔细阅读下面这几篇文章,类似的跨学科科谱式文章并不多见:

IM开发者的零基础通信技术入门(十一):为什么WiFi信号差?一文即懂!

IM开发者的零基础通信技术入门(十二):上网卡顿?网络掉线?一文即懂!

IM开发者的零基础通信技术入门(十三):为什么手机信号差?一文即懂!

IM开发者的零基础通信技术入门(十四):高铁上无线上网有多难?一文即懂!

弱网问题是移动端APP的必修课,下面这几篇总结也值得借鉴:

移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”

移动端IM开发者必读(二):史上最全移动弱网络优化方法总结

现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障

百度APP移动端网络深度优化实践分享(三):移动端弱网优化篇

8.2 IM针对弱网问题的处理

对于IM来说,弱网问题并不是很复杂,核心是做好消息的重发、排序以及接收端的重试。

为了解决好弱网引发的IM问题,通常可以通过以下手段改善:

  • 1)消息自动重发;
  • 2)离线消息接收;
  • 3)重发消息排序;
  • 4)离线指令处理。

下面将逐一展开讨论。

8.3 消息自动重发

坐地铁的时候,经常遇到列车开起来以后,网络断开,发送消息失败。

这时候产品有2种表现形式:

  • a、直接告诉用户发送失败;
  • b、保持发送状态,自动重试3-5次(3分钟)以后告诉用户发送失败。

显然:自动重试失败以后再告诉用户发送失败体验要好很多。尤其是在网络闪断情况下,重试成功率很高,很可能用户根本感知不到有发送失败。

从技术上:客户端IMSDK要把每条消息的状态监控起来。发送消息不能简单的调用一下网络发送请求,而是要有一个状态机,管理几个状态:初始状态,发送中,发送失败,发送超时。对于失败和超时的状态,要启用重试机制。

这里还有一篇关于重试机制设计的讨论帖子,有兴趣可以看看:完全自已开发的IM该如何设计“失败重试”机制?》。

IM消息送达保证机制实现(一):保证在线实时消息的可靠投递》一文中关于消息超时与重传机制的实现思路,也可以参考一下。

8.4 离线消息接收

现代IM是没有“在线”这个状态的,不需要给用户这个信息。但是从技术的层面,用户掉线了还是要正确的去感知的。

感知方法有几条:

  • a、信令长连接状态:如果长时间没收到到服务器的心跳反馈,说明掉线了;
  • b、网络请求失败次数:如果多次网络请求失败,说明”可能“掉线了;
  • c、设备网络状态检测:直接检测网卡状态就好,一般Android/iOS/Windows/Mac都有相应系统API。

正确检测到网络状态以后,发现网络从”断开到恢复“的切换,要去主动拉取离线阶段的消息,就可以做到弱网状态不丢消息(从服务器的离线消息列表拉取)。

上面文字中提到的网络状态的确定,涉及到IM里网络连接检查和保活机制问题,是IM里比较头疼的问题。

一不小心,又踩进了IM网络保活这个坑,我就不在这里展开,有兴趣一定要读读下面的文章:

为何基于TCP协议的移动端IM仍然需要心跳保活机制?

一文读懂即时通讯应用中的网络心跳包机制:作用、原理、实现思路等

微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)

移动端IM实践:实现Android版微信的智能心跳机制

移动端IM实践:WhatsApp、Line、微信的心跳策略分析

8.5 重发消息排序

弱网逻辑的另一个坑是消息排序。

假如有A、B、C  3条消息,A、C发送成功,B发送的时候遇到了网络闪断,B触发自动重试。

那么接收方的接收顺序应该是 A B C还是A C B呢?我观察过不同的IM产品,处理逻辑各不相同,这个大家有兴趣可以去玩一下。

这个解决方法是要依赖上一篇服务架构里提到的差值排序,同一个人发出的消息,排序按消息附带的本地时间来排。不同人的消息,按照服务器时间排序。

具体我这边就不再得复,可以回头看看本篇中的第四节“4、消息有序性问题”。

8.6 离线指令处理

部分指令操作的时候,网络可能出现了问题,等网络恢复以后,要自动同步给服务器。

举一个例子,大家可以试试手机设置为飞行模式,然后在微信里删除一个联系人,看看能不能删除。然后重新打开网络,看看这个数据会不会同步到服务器。

类似的逻辑也适用于已读同步等场景,离线状态看过的信息,要正确的跟服务器同步。

8.7 小结一下

IM的弱网处理,其实相对还是比较简单的,基本上自动重试+消息状态就可以解决绝大部分的问题了。

一些细节处理也并不复杂,主要原因是IM的消息量比较小,网络恢复后能快速的恢复操作。

视频会议在弱网下的逻辑,就要复杂的多了。尤其是高丢包的弱网环境下,要尽力去保证音视频的流畅性。

9、本文小结

《一套亿级用户的IM架构技术干货》这期文章的上下两篇就这么侃完了,上篇涉及到的IM架构问题倒还好,下篇一不小心又带出了IM里的各种热门问题“坑”,搞IM开发直是一言难尽。。。

建议IM开发的入门朋友们,如果想要系统地学习移动端IM开发的话,应该去读一读我整理的那篇IM开发“从入门到放弃”的文章(哈哈哈),就是这篇《新手入门一篇就够:从零开发移动端IM》。具体我就不再展开了,不然这篇幅又要刹不住车了。。。

10、参考资料

[1] 大规模并发IM服务架构设计

[2] IM的弱网场景优化

[3] 零基础IM开发入门(三):什么是IM系统的可靠性?

[4] IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

[5] IM开发干货分享:如何优雅的实现大量离线消息的可靠投递

[6] 即时通讯安全篇(二):探讨组合加密算法在IM中的应用

[7] 微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解

附录:更多IM开发文章汇总

零基础IM开发入门(一):什么是IM系统?

零基础IM开发入门(二):什么是IM系统的实时性?

IM开发干货分享:如何优雅的实现大量离线消息的可靠投递

IM开发干货分享:有赞移动端IM的组件化SDK架构设计实践

IM开发宝典:史上最全,微信各种功能参数和逻辑规则资料汇总

IM开发干货分享:我是如何解决大量离线消息导致客户端卡顿的

从客户端的角度来谈谈移动端IM的消息可靠性和送达机制

腾讯技术分享:社交网络图片的带宽压缩技术演进之路

移动端IM中大规模群消息的推送如何保证效率、实时性?

移动端IM开发需要面对的技术问题

开发IM是自己设计协议用字节流好还是字符流好?

请问有人知道语音留言聊天的主流实现方式吗?

IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?

IM群聊消息如此复杂,如何保证不丢不重?

谈谈移动端 IM 开发中登录请求的优化

移动端IM登录时拉取数据如何作到省流量?

通俗易懂:基于集群的移动端IM接入层负载均衡方案分享

微信对网络影响的技术试验及分析(论文全文)

本文已同步发布于“即时通讯技术圈”公众号。

▲ 本文在公众号上的链接是:点此进入。同步发布链接是:http://www.52im.net/thread-3445-1-1.html

posted @ 2021-03-22 16:10 Jack Jiang 阅读(197) | 评论 (0)编辑 收藏

1、引言

经历过稍有些规模的IM系统开发的同行们都有体会,要想实现大规模并发IM(比如亿级用户和数十亿日消息量这样的规模),在架构设计上需要一些额外的考虑,尤其是要解决用户高并发、服务高可用,架构和实现细节上都需要不短时间的打磨。

我在过往的工作经历里,亲手设计和实现了一套亿级用户量的IM,平台上线并经过6年多的验证,稳定性和可用性被验证完全达到预期。

这套IM系统,从上线至今已6年有余,本人也已经离职创业近2年,但当初设计和开发这套系统时积累和收获了大量的第一手实践经验和技术心得。

因此,想借本文把当时的架构设计经历记录下来,作为同行交流和参考,希望能提供一些启发,少走弯路。

本文已同步发布于“即时通讯技术圈”公众号,欢迎关注。公众号上的链接是:点此进入

2、系列文章

为了更好以进行内容呈现,本文拆分两了上下两篇。

本文是2篇文章中的第1篇:

一套亿级用户的IM架构技术干货(上篇):整体架构、服务拆分等》(本文)

《一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等(稍后发布...)》

本篇主要总结和分享这套IM架构的总体设计和服务拆分等。

3、原作者

本文基于邓昀泽的“大规模并发IM服务架构设计”一文进行的扩展和修订,感谢原作者的分享。

邓昀泽:毕业于北京航空航天大学,现蓝猫微会创始人兼CEO,曾就职于美团、YY语音、微软和金山软件等公司,有十多年研发管理经验。

4、技术指标

在这套IM系统的架构上,技术上我们坚持高要求,经过数年的验证,也确实达到了设计预期。

这4大技术指标是:

具体解释就是:

  • 1)高可靠:确保不丢消息;
  • 2)高可用:任意机房或者服务器挂掉,不影响服务;
  • 3)实时性:不管用户在哪里,在线用户消息在1秒内达到(我们实际是75%消息可以做到120ms);
  • 4)有序性:确保用户消息的有序性,不会出现发送和接受的乱序。

5、架构拆分

从整体架构上来说,亿级用户量的IM架构整体上偏复杂。

传统开源的IM服务喜欢把所有服务做到1-2个服务里(Connector+Service模型),这样带来的问题比较严重。

传统开源的IM的问题主要体现在:

  • 1)服务代码复杂,难以持续开发和运维;
  • 2)单一业务逻辑出问题,可能会影响到其它逻辑,导致服务的全面不可用。

因此,我在做架构设计的时候尽量追求微服务化。即把整体架构进行分拆为子系统,然后子系统内按照业务逻辑分拆为微服务。

系统拆分如下图:

4个子系统的职责是:

  • 1)IM业务系统:服务IM相关的业务逻辑(比如好友关系、群关系、用户信息等);
  • 2)信令系统:负责用户登录,用户在线状态的维护,以及在线用户的下行推送;
  • 3)推送系统:负责消息的在线推送和离线推送;
  • 4)存储系统:负责消息和文件的存储和查询;

其中:信令系统和推送系统是基础设施,不只是可以为IM业务服务,也可以承载其它类似的业务逻辑(比如客服系统)。

在部署层面:采用存储3核心机房,信令和推送节点按需部署的方式(国内业务推荐8-10个点)。实际上我们只做了了北京3个机房,上海1个机房和香港一个机房的部署,就基本上满足了大陆+香港的业务需求。

下面将逐个介绍这4个子系统的细节方面。

6、IM业务系统

一说到IM,很多人脑海里跳出的第一个关键就是“即时通信”,技术上理所当然的联想到了socket,也就是大家成天嘴上说的:“长连接”。换句话说,很多对IM不了解或了解的不多的人,认为IM里的所有数据交互、业务往来都是通过“长连接”来实现的,这样话,对于本文章中拆分出的“IM业务系统”就有点不理解了。

实际上,早期的IM(比如20年前的QQ、MSN、ICQ),确实所有数据基本都是通过“长连接”(也就是程序员所说的“socket”)实现。

但如今,移动端为主端的IM时代,IM系统再也不是一个条“长连接”走天下。

现在,一个典型的IM系统数据往来通常拆分成两种服务:

  • 1)socket长连接服务(也就是本文中的“推送服务”);
  • 2)http短连接服务(就是最常用的http rest接口那些,也就是本文中的“IM业务系统”)。

通俗一点,也也就现在的IM系统,通常都是长、短连接配合一起实现的。 

比如论坛里很多热门技术方案都是这样来做的,比如最典型的这两篇:《IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?》、《IM消息送达保证机制实现(二):保证离线消息的可靠投递》,文记里提到的“推”其实就是走的“长连接”、“拉”就上指的http短连接。

对于socket长连接服务就没什么好说,就是大家最常理解的那样。

IM业务系统详细来说,就是专注处理IM相关的业务逻辑,比如:

  • 1)维护用户数据:用户基本信息等;
  • 2)维护好友关系:好友请求、好友列表、好友信息等;
  • 3)维护群组信息:群创建、解散、成员管理等;
  • 4)提供数据:离线拉取、历史记录同步;
  • 5)其它逻辑:比如通过存储和推送系统,存储消息和发送通知;

按照微服务的原则,IM业务系统也被分拆为多个服务,比如:

  • 1)GInfo服务:群组信息维护;
  • 2)IM服务:处理1V1消息;
  • 3)GIM服务:处理群组消息。

7、信令系统

7.1 基本情况

信令系统主要职责是3部分: 

 

1)维护用户在线状态:

因为用户规模庞大,必然是多个集群,每个集群多台服务器为用户提供服务。

考虑到服务器运维的复杂性,我们要假定任何一个集群,任何一个服务器都可能会挂掉,而且在这种情况下要能够继续为用户提供服务。

在这种情况下,如果用户A给用户B发消息,我们需要知道用户B在哪个服务器上,才能把消息正确推送给用户B。用户在哪个信令服务,这个信息就是在线状态数据。

2)下行消息推送:

跟上一个职责有关,用户在线的时候,如果有其它用户给他发消息,那就最好不要走离线推送,而是走在线推送。

在线推送的最后一个环节,是把用户消息推送给用户设备,因为就需要知道用户登录到哪个服务器上。

3)业务分发:

信令服务不只可以处理IM请求,也可以处理其它类型的业务请求。为了处理不同的业务,就需要有分发能力。

具体做法是通过一个SVID(service id)来实现,不同的业务携带不同的SVID,信令服务就知道如何分发了。

用户通过登录服务把数据(比如IM消息)发送到信令系统,信令系统根据SVID转发给IM系统。不管后台有多少个业务,用户只需要一条链接到信令。

7.2 服务拆分

信令系统为了实现以上这3个职责,同时要确保我们服务可平行扩展的能力和稳定性,在实际的技术实现上,我们实际上把信令服务分拆为3个服务模块。

如下图所示: 

下面将逐个介绍这3个子服务。

7.3 Login服务

Login服务主要负责维护用户长链接:

  • 1)每个用户一条链接到Login服务,并按时间发心跳包给Login服务;
  • 2)服务定时检查用户链接状态和心跳包,比如发现2个心跳周期都没收到心跳,就认为用户掉线了(有假在线问题,有兴趣同学可回贴讨论)。

Login服务收到用户登录请求以后,验证uid/cookie,如果成功就把这个用户的登录信息发送给online。

此过程主要记录的信息包含:

  • 1)uid(用户id);
  • 2)Login服务器IP/Port;
  • 3)Route服务器的IP/Port。

如果用户发送IM消息,先发送到Login,Login转发给Route,Route根据服务的类型(SVID),发现是IM协议就发送给后端的IM服务。

Login对并发要求比较高,一般要支持TCP+UDP+Websocket几种方式,单服务可以做到10-250万之间。从服务稳定性角度触发,建议是控制VM的CPU/内存,单服务器以20-50万为合适。

Login服务器本身没有状态,任何一个Login服务断掉,用户端检测到以后重连另一个Login服务器就可以了,对整体服务可靠性基本没有影响。

7.4 Online服务

Online服务主要负责维护用户的在线信息:

  • 1)如果用户掉线,Online服务里信息就是空;
  • 2)如果用户在线,Online就能找到用户登录在哪个集群,哪个Login服务器上。

Online业务相对简单:多个Login服务器会连接到Online,定期同步用户登录和离线信息。

Online主要职责是:把用户状态信息存储在Redis集群里。因此也是无状态的,任何一个Online服务挂掉,不影响整体服务能力。

如果集群规模不大,用户规模也不大,Online服务也可以收到Login服务里去。

如果规模比较大,建议分拆出来,一方面简化Login的逻辑复杂度,同时避免写Redis的慢操作放在Login服务里。因为Login要同时处理50万以上的并发链接,不适合在循环里嵌入慢操作。

7.5 Route服务

Route服务的设计核心,是作为信令系统跟其它子系统的交互层。Route下接Login服务,可以接受用户业务信息(IM),也可以往用户推送下行消息。

多个后端业务系统可以接入到Route,按照服务类型(SVID, service id)注册。比如IM服务可以接入到Route, 注册SVID_IM。这样Login接收到SVID=SVID_IM的消息,转发给Route,Route就可以根据SVID转发给IM相关的服务。

Route简单的根据SVID做转发,不处理具体的业务逻辑,因此也是无状态的。一个信令集群可以有多个Route服务,任何服务挂了不影响整体服务能力。

8、推送系统

推送系统的核心任务:是接收到给用户发送下行消息的请求以后,去信令服务查询用户是否在线,如果在线走信令推送,如果不在线走离线推送(如iOS的APNS、华为推送、小米推送等)。

因为推送服务可能出现大规模并发蜂拥,比如大群激烈讨论的时候,会触发亿级的TPS。因此推送服务用Kafka做了削峰。

我在实际的技术实现上,将推送系统进行了如下细分: 

具体就是:

  • 1)PushProxy:接受用户的推送请求,写入Kafka;
  • 2)Kafka:缓存推送服务;
  • 3)PushServer:从Kafka获取推送请求,判断用户是否在线;
  • 4)PushWorker:真正推送给信令或者APNS,华为推送等。

这里同样,除了Kafka以外每个服务都是无状态的,因为也可以实现平行扩展和容错,任何服务挂掉不影响整体服务可用性。

9、存储系统

存储服务主要是负责消息的存储和查询,因为消息量巨大,对存储服务的并发能力和存储量要求巨大。

为了平衡性能、空间和成本,存储服务按数据的热度进行了分级和区别对待。

具体是:

  • 1)短期消息(7天):存储在Redis里;
  • 2)近期消息(1-3个月):存储在Mysql里,以备用户实时查询;
  • 3)历史信息:存储在HBase里,作为历史数据慢查询。

同时,为了应对超大群的大量消息处理,存储服务在实际的技术实现上,也做了比较细的分拆。

存储服务具体拆分如下图:

具体的业务划分就是:

  • 1)MsgProxy:负责接受IM子系统的存储请求,写入Kafka;
  • 2)MsgWriter:从Kafka获取写请求,按需写入Redis和Mysql;
  • 3)MsgReader:接受用户的消息查询请求,从Redis,Mysql或者HBase读数据;
  • 4)运维工具:主要是数据库的运维需求。

消息队列(Kafka)在这里角色比较重要,因为对于高并发请求(100万人公众号),需要通过消息队列来做削峰和并行。

在具体部署上:可能是3-4个MsgProxy,后端可以对应15个左右的MsgWriter。MsgWriter是比较慢的,需要同时操作多个数据库,还要保证操作的原子性。

10、本篇小结

本篇主要总结了这套亿级用户量IM系统的总体架构设计,为了高性能和横向扩展性,基于微信的理念将整个架构在实现上分成了4个子系统,分别是:IM业务系统、信令系统、推送系统、存储系统。

针对这4个子系统,在实际的技术应用层上,又进行了进一步的服务拆分和细化,使得整个架构伸缩性大大增强。

—— 下篇《一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等》稍后发布,敬请期待 ——

附录:相关文章

浅谈IM系统的架构设计

简述移动端IM开发的那些坑:架构设计、通信协议和客户端

一套海量在线用户的移动端IM架构设计实践分享(含详细图文)》(* 力荐

一套原创分布式即时通讯(IM)系统理论架构方案》(* 力荐

从零到卓越:京东客服即时通讯系统的技术架构演进历程》(* 力荐

蘑菇街即时通讯/IM服务器开发之架构选择

腾讯QQ1.4亿在线用户的技术挑战和架构演进之路PPT

微信后台基于时间序的海量数据冷热分级架构设计实践

移动端IM中大规模群消息的推送如何保证效率、实时性?

现代IM系统中聊天消息的同步和存储方案探讨》(* 力荐

以微博类应用场景为例,总结海量社交系统的架构设计步骤

一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践》(* 力荐

社交软件红包技术解密(一):全面解密QQ红包技术方案——架构、技术实现等

社交软件红包技术解密(二):解密微信摇一摇红包从0到1的技术演进

社交软件红包技术解密(三):微信摇一摇红包雨背后的技术细节

社交软件红包技术解密(四):微信红包系统是如何应对高并发的

社交软件红包技术解密(五):微信红包系统是如何实现高可用性的

社交软件红包技术解密(六):微信红包系统的存储层架构演进实践

社交软件红包技术解密(七):支付宝红包的海量高并发技术实践

社交软件红包技术解密(八):全面解密微博红包技术方案

从游击队到正规军(一):马蜂窝旅游网的IM系统架构演进之路》(* 力荐

从游击队到正规军(二):马蜂窝旅游网的IM客户端架构演进和实践总结

从游击队到正规军(三):基于Go的马蜂窝旅游网分布式IM系统技术实践

瓜子IM智能客服系统的数据架构设计(整理自现场演讲,有配套PPT)

阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处

微信后台基于时间序的新一代海量数据存储架构的设计实践

一套亿级用户的IM架构技术干货(上篇):整体架构、服务拆分等

>> 更多同类文章 ……

 

本文已同步发布于“即时通讯技术圈”公众号。

▲ 本文在公众号上的链接是:点此进入。同步发布链接是:http://www.52im.net/thread-3393-1-1.html

posted @ 2021-03-15 23:07 Jack Jiang 阅读(458) | 评论 (0)编辑 收藏

     摘要: 本文由微信开发团队工程师“ kellyliang”原创发表于“微信后台团队”公众号,收录时有修订和改动。1、引言随着直播和类直播场景在微信内的增长,这些业务对临时消息(在线状态时的实时消息)通道的需求日益增长,直播聊天室组件应运而生。直播聊天室组件是一个基于房间的临时消息信道,主要提供消息收发、在线状态统计等功能。本文将回顾微信直播聊天室单房间海量用...  阅读全文

posted @ 2021-03-06 17:08 Jack Jiang 阅读(299) | 评论 (0)编辑 收藏

     摘要: 本文引用了“一文读懂什么是进程、线程、协程”一文的主要内容,感谢原作者的无私分享。1、系列文章引言1.1 文章目的作为即时通讯技术的开发者来说,高性能、高并发相关的技术概念早就了然与胸,什么线程池、零拷贝、多路复用、事件驱动、epoll等等名词信手拈来,又或许你对具有这些技术特征的技术框架比如:Java的Netty、Php的workman、Go的gnet等熟练掌握。但真正到...  阅读全文

posted @ 2021-03-03 13:02 Jack Jiang 阅读(224) | 评论 (0)编辑 收藏

本文原题“你管这破玩意儿叫TCP?”,由闪客sun分享,转载请联系作者。

1、引言

网络编程能力对于即时通讯技术开发者来说是基本功,而计算机网络又是网络编程的理论根基,因而深刻准确地理解计算机网络知识显然能夯实你的即时通讯应用的实践品质。

本文风格类似于《网络编程懒人入门》、《脑残式网络编程入门》两个系列,但通俗又不失内涵,简洁又不简陋,非常适合对计算机网络知识有向往但又有惧怕的网络编程爱好者们阅读,希望能给你带来不一样的网络知识入门视角。

本篇将运用通俗易懂的语言,配上细致精确的图片动画,循序渐进地引导你理解TCP协议的主要特性和技术原理,让TCP协议的学习不再如此枯燥和生涩,非常适合入门者阅读。

本文已同步发布于“即时通讯技术圈”公众号,欢迎关注。公众号上的链接是:点此进入

2、系列文章

本文是该系列文章中的第2篇:

本文主要涉及计算机网络的传输层,希望让TCP协议的学习不再枯燥和生涩。

3、初识传输层

你是一台电脑,你的名字叫 A。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_1-1.png
经过上篇《假如你来设计网络,会怎么做?》的一番折腾,只要你知道另一位伙伴 B 的 IP 地址,且你们之间的网络是通的,无论多远,你都可以将一个数据包发送给你的伙伴 B。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_1-2.png

上篇中分享的这就是物理层、数据链路层、网络层这三层所做的事情。

站在第四层的你,就可以不要脸地利用下三层所做的铺垫,随心所欲地发送数据,而不必担心找不到对方了。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_1-3.gif

虽然你此时还什么都没干,但你还是给自己这一层起了个响亮的名字,叫做传输层。

你本以为自己所在的第四层万事大吉,啥事没有,但很快问题就接踵而至。

4、问题来了

前三层协议只能把数据包从一个主机搬到另外一台主机,但是到了目的地以后,数据包具体交给哪个程序(进程)呢?

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_2-1.png

所以:你需要把通信的进程区分开来,于是就给每个进程分配一个数字编号,你给它起了一个响亮的名字:端口号。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_2-2.png

然后:你在要发送的数据包上,增加了传输层的头部:源端口号与目标端口号。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_2-3.png

OK,这样你将原本主机到主机的通信,升级为了进程和进程之间的通信。

你没有意识到,你不知不觉实现了UDP协议

当然 UDP 协议中不光有源端口和目标端口,还有数据包长度和校验值,我们暂且略过。

就这样,你用 UDP 协议无忧无虑地同 B 进行着通信,一直没发生什么问题。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_2-4.gif

但很快,你发现事情变得非常复杂 ... ...

5、丢包问题

由于网络的不可靠,数据包可能在半路丢失,而 A 和 B 却无法察觉。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_3-1.gif

对于丢包问题,只要解决两个事就好了。

第一个:A 怎么知道包丢了?
答案是:让 B 告诉 A。

第二个:丢了的包怎么办?
答案是:重传。

于是你设计了如下方案:A 每发一个包,都必须收到来自 B 的确认(ACK),再发下一个,否则在一定时间内没有收到确认,就重传这个包。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_3-2.gif

你管它叫停止等待协议。

只要按照这个协议来,虽然 A 无法保证 B 一定能收到包,但 A 能够确认 B 是否收到了包,收不到就重试,尽最大努力让这个通信过程变得可靠,于是你们现在的通信过程又有了一个新的特征,可靠交付。

6、效率问题

停止等待虽然能解决问题,但是效率太低了。

A 原本可以在发完第一个数据包之后立刻开始发第二个数据包,但由于停止等待协议,A 必须等数据包到达了 B ,且 B 的 ACK 包又回到了 A,才可以继续发第二个数据包。这效率慢得可不是一点两点。

于是:你对这个过程进行了改进,采用流水线的方式,不再傻傻地等。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_4-1.gif

7、顺序问题

但是网路是复杂的、不可靠的。

这导致的问题是:有的时候 A 发出去的数据包,分别走了不同的路由到达 B,可能无法保证和发送数据包时一样的顺序。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_5-1.gif

对应于我们的例子:在流水线中有多个数据包和ACK包在乱序流动,他们之间对应关系就乱掉了。

如果回到上面的停止等待协议,那么A 每收到一个包的确认(ACK)再发下一个包,那就根本不存在顺序问题。但,应该有更好的办法吧?

是的,更好的办法就是:A 在发送的数据包中增加一个序号(seq),同时 B 要在 ACK 包上增加一个确认号(ack)。这样不但解决了停止等待协议的效率问题,也通过这样标序号的方式解决了顺序问题。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_5-2.gif

而 B 这个确认号意味深长:比如 B 发了一个确认号为 ack = 3,它不仅仅表示 A 发送的序号为 2 的包收到了,还表示 2 之前的数据包都收到了。这种方式叫累计确认累计应答

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_5-3.gif

注意:实际上 ack 的号是收到的最后一个数据包的序号 seq + 1,也就是告诉对方下一个应该发的序号是多少。但图中为了便于理解,ack 就表示收到的那个序号,不必纠结。

8、流量问题

有的时候,A 发送数据包的速度太快,而 B 的接收能力不够,但 B 却没有告知 A 这个情况。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_6-1.gif

怎么解决呢?

很简单:B 告诉 A 自己的接收能力,A 根据 B 的接收能力,相应控制自己的发送速率就好了。

B 怎么告诉 A 呢?B 跟 A 说"我很强"这三个字么?那肯定不行,得有一个严谨的规范。

于是 B 决定:每次发送数据包给 A 时,顺带传过来一个值,叫窗口大小(win),这个值就表示 B 的接收能力

同理:每次 A 给 B 发包时也带上自己的窗口大小,表示 A 的接收能力。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_6-2.gif

B 告诉了 A 自己的窗口大小值,A 怎么利用它去做 A 这边发包的流量控制呢?

很简单:假如 B 给 A 传过来的窗口大小 win = 5,那 A 根据这个值,把自己要发送的数据分成这么几类。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_6-3.png

图片过于清晰,就不再文字解释了。

当 A 不断发送数据包时,已发送的最后一个序号就往右移动,直到碰到了窗口的上边界,此时 A 就无法继续发包,达到了流量控制。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_6-4.gif

但是:当 A 不断发包的同时,A 也会收到来自 B 的确认包,此时整个窗口会往右移动,因此上边界也往右移动,A 就能发更多的数据包了。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_6-5.gif

以上都是在窗口大小不变的情况下。而 B 在发给 A 的 ACK 包中,每一个都可以重新设置一个新的窗口大小,如果 A 收到了一个新的窗口大小值,A 会随之调整。

如果 A 收到了比原窗口值更大的窗口大小,比如 win = 6,则 A 会直接将窗口上边界向右移动 1 个单位。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_6-6.gif

如果 A 收到了比原窗口值小的窗口大小,比如 win = 4,则 A 暂时不会改变窗口大小,更不会将窗口上边界向左移动,而是等着 ACK 的到来,不断将左边界向右移动,直到窗口大小值收缩到新大小为止。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_6-7.gif

OK,终于将流量控制问题解决得差不多了,你看着上面一个个小动图,给这个窗口起了一个更生动的名字:滑动窗口。

9、拥塞问题

但有的时候,不是 B 的接受能力不够,而是网络不太好,造成了网络拥塞。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_7-1.gif

拥塞控制与流量控制有些像,但流量控制是受 B 的接收能力影响,而拥塞控制是受网络环境的影响。

拥塞控制的解决办法依然是通过设置一定的窗口大小。只不过,流量控制的窗口大小是 B 直接告诉 A 的,而拥塞控制的窗口大小按理说就应该是网络环境主动告诉 A。

但网络环境怎么可能主动告诉 A 呢?只能 A 单方面通过试探,不断感知网络环境的好坏,进而确定自己的拥塞窗口的大小。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_7-2.gif

拥塞窗口大小的计算有很多复杂的算法,就不在本文中展开了(有兴趣可以深入阅读《[通俗易懂]深入理解TCP协议(下):RTT、滑动窗口、拥塞处理》)。

假如拥塞窗口的大小为  cwnd,上一部分流量控制的滑动窗口的大小为 rwnd,那么窗口的右边界受这两个值共同的影响,需要取它俩的最小值。

窗口大小 = min(cwnd, rwnd)

含义很容易理解:当 B 的接受能力比较差时,即使网络非常通畅,A 也需要根据 B 的接收能力限制自己的发送窗口。当网络环境比较差时,即使 B 有很强的接收能力,A 也要根据网络的拥塞情况来限制自己的发送窗口。正所谓受其短板的影响嘛~

10、连接问题

有的时候,B 主机的相应进程还没有准备好或是挂掉了,A 就开始发送数据包,导致了浪费。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_8-1.gif

这个问题在于:A 在跟 B 通信之前,没有事先确认 B 是否已经准备好,就开始发了一连串的信息。就好比你和另一个人打电话,你还没有"喂"一下确认对方有没有在听,你就巴拉巴拉说了一堆。

这个问题该怎么解决呢?

地球人都知道:三次握手嘛!

  • A:我准备好了(SYN)
  • B:我知道了(ACK),我也准备好了(SYN)
  • A:我知道了(ACK)

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_8-2.gif

A 与 B 各自在内存中维护着自己的状态变量,三次握手之后,双方的状态都变成了连接已建立(ESTABLISHED)。

虽然就只是发了三次数据包,并且在各自的内存中维护了状态变量,但这么说总觉得太 low,你看这个过程相当于双方建立连接的过程,于是你灵机一动,就叫它面向连接吧。

注意:这个连接是虚拟的,是由 A 和 B 这两个终端共同维护的,在网络中的设备根本就不知道连接这回事儿!

但凡事有始就有终,有了建立连接的过程,就要考虑释放连接的过程。

这就是网络编程中耳熟能详的四次挥手啦!

  • A:再见,我要关闭了(FIN)
  • B:我知道了(ACK)。给 B 一段时间把自己的事情处理完...
  • B:再见,我要关闭了(FIN)
  • A:我知道了(ACK)

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_8-3.gif

11、小结一下

以上讲述的,就是 TCP 协议的核心思想,上面过程中需要传输的信息,就体现在 TCP 协议的头部,这里放上最常见的 TCP 协议头解读的图。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_9-1.png

不知道你现在再看下面这句话,是否能理解:

TCP 是面向连接的、可靠的、基于字节流的传输层通信协议。

“面向连接、可靠”,这两个词通过上面的讲述很容易理解,那什么叫做基于字节流呢?

很简单:TCP 在建立连接时,需要告诉对方 MSS(最大报文段大小)。

也就是说:如果要发送的数据很大,在 TCP 层是需要按照 MSS 来切割成一个个的 TCP 报文段 的。

切割的时候我才不管你原来的数据表示什么意思,需要在哪里断句啥的,我就把它当成一串毫无意义的字节,在我想要切割的地方咔嚓就来一刀,标上序号,只要接收方再根据这个序号拼成最终想要的完整数据就行了。

在我 TCP 传输这里,我就把它当做一个个的字节,也就是基于字节流的含义了。

网络编程入门从未如此简单(二):假如你来设计TCP协议,会怎么做?_10-1.png

12、写在最后

一提到 TCP,可能很多人都想起被三次握手和四次挥手所支配的恐惧。

但其实你跟着本文中的思路你就会发现,三次握手与四次挥手只占 TCP 所解决的核心问题中很小的一部分,只是因为它在面试中很适合作为知识点进行考察,所以在很多人的印象中就好像 TCP 的核心就是握手和挥手似的。

本文希望你能从问题出发,真正理解 TCP 所想要解决的问题,你会发现很多原理就好像生活常识一样顺其自然,并不复杂,希望你有收获~

最后,如果对TCP的理解仍存在疑惑,可以继续阅读以下精选的资料:

本文已同步发布于“即时通讯技术圈”公众号。

▲ 本文在公众号上的链接是:点此进入。同步发布链接是:http://www.52im.net/thread-3339-1-1.html

posted @ 2021-02-24 12:47 Jack Jiang 阅读(307) | 评论 (0)编辑 收藏

     摘要: 本文原题“如果让你来设计网络”,由闪客sun分享,转载请联系作者。1、引言网络编程能力对于即时通讯技术开发者来说是基本功,而计算机网络又是网络编程的理论根基,因而深刻准确地理解计算机网络知识显然能夯实你的即时通讯应用的实践品质。本文风格类似于52im社区里的《网络编程懒人入门》、《脑残式网络编程入门》两个系列,但通俗又不失内涵,简洁又不简陋,非常适合对计算机网络知识有向往但...  阅读全文

posted @ 2021-02-02 15:24 Jack Jiang 阅读(221) | 评论 (0)编辑 收藏

本文原题“高并发高性能服务器是如何实现的”,转载请联系作者。

1、系列文章引言

1.1 文章目的

作为即时通讯技术的开发者来说,高性能、高并发相关的技术概念早就了然与胸,什么线程池、零拷贝、多路复用、事件驱动、epoll等等名词信手拈来,又或许你对具有这些技术特征的技术框架比如:Java的Netty、Php的workman、Go的gnet等熟练掌握。但真正到了面视或者技术实践过程中遇到无法释怀的疑惑时,方知自已所掌握的不过是皮毛。

返璞归真、回归本质,这些技术特征背后的底层原理到底是什么?如何能通俗易懂、毫不费力真正透彻理解这些技术背后的原理,正是《从根上理解高性能、高并发》系列文章所要分享的。

1.2 文章源起

我整理了相当多有关IM、消息推送等即时通讯技术相关的资源和文章,从最开始的开源IM框架MobileIMSDK,到网络编程经典巨著《TCP/IP详解》的在线版本,再到IM开发纲领性文章《新手入门一篇就够:从零开发移动端IM》,以及网络编程由浅到深的《网络编程懒人入门》、《脑残式网络编程入门》、《高性能网络编程》、《不为人知的网络编程》系列文章。

越往知识的深处走,越觉得对即时通讯技术了解的太少。于是后来,为了让开发者门更好地从基础电信技术的角度理解网络(尤其移动网络)特性,我跨专业收集整理了《IM开发者的零基础通信技术入门》系列高阶文章。这系列文章已然是普通即时通讯开发者的网络通信技术知识边界,加上之前这些网络编程资料,解决网络通信方面的知识盲点基本够用了。

对于即时通讯IM这种系统的开发来说,网络通信知识确实非常重要,但回归到技术本质,实现网络通信本身的这些技术特征:包括上面提到的线程池、零拷贝、多路复用、事件驱动等等,它们的本质是什么?底层原理又是怎样?这就是整理本系列文章的目的,希望对你有用。

1.3 文章目录

从根上理解高性能、高并发(一):深入计算机底层,理解线程与线程池

从根上理解高性能、高并发(二):深入操作系统,理解I/O与零拷贝技术

从根上理解高性能、高并发(三):深入操作系统,彻底理解I/O多路复用

从根上理解高性能、高并发(四):深入操作系统,彻底理解同步与异步

从根上理解高性能、高并发(五):深入操作系统,理解高并发中的协程

从根上理解高性能、高并发(六):通俗易懂,高性能服务器到底是如何实现的》(* 本文

1.4 本篇概述

接上篇《从根上理解高性能、高并发(五):深入操作系统,理解高并发中的协程》,本篇是高性能、高并发系列的第6篇文章(也是完结篇)。

本篇是本系列文章的完结篇,你将能了解到,一个典型的服务器端是如何利用前5篇中讲解的各单项技术从而实现高性能高并发的。

本文已同步发布于“即时通讯技术圈”公众号,欢迎关注。公众号上的链接是:点此进入

2、本文作者

应作者要求,不提供真名,也不提供个人照片。

本文作者主要技术方向为互联网后端、高并发高性能服务器、检索引擎技术,网名是“码农的荒岛求生”。感谢作者的无私分享。

3、正文引言

当你在阅读本篇文章的时候,有没有想过,服务器是怎么把这篇文章发送给你的呢?

说起来很简单:不就是一个用户请求吗?服务器根据请求从数据库中捞出这篇文章,然后通过网络发回去吗。

其实有点复杂:服务器端到底是如何并行处理成千上万个用户请求的呢?这里面又涉及到哪些技术呢?

这篇文章就是来为你解答这个问题的。

4、多进程

历史上最早出现也是最简单的一种并行处理多个请求的方法就是利用多进程

比如在Linux世界中,我们可以使用fork、exec等系统调用创建多个进程,我们可以在父进程中接收用户的连接请求,然后创建子进程去处理用户请求。

就像这样:

这种方法的优点就在于:

  • 1)编程简单,非常容易理解;
  • 2)由于各个进程的地址空间是相互隔离的,因此一个进程崩溃后并不会影响其它进程;
  • 3)充分利用多核资源。

多进程并行处理的优点很明显,但是缺点同样明显:

  • 1)各个进程地址空间相互隔离,这一优点也会变成缺点,那就是进程间要想通信就会变得比较困难,你需要借助进程间通信(IPC,interprocess communications)机制,想一想你现在知道哪些进程间通信机制,然后让你用代码实现呢?显然,进程间通信编程相对复杂,而且性能也是一大问题;
  • 2)我们知道创建进程开销是比线程要大的,频繁的创建销毁进程无疑会加重系统负担。

幸好,除了进程,我们还有线程。

5、多线程

不是创建进程开销大吗?不是进程间通信困难吗?这些对于线程来说统统不是问题。

什么?你还不了解线程,赶紧看看这篇《深入计算机底层,理解线程与线程池》,这里详细讲解了线程这个概念是怎么来的。

由于线程共享进程地址空间,因此线程间通信天然不需要借助任何通信机制,直接读取内存就好了。

线程创建销毁的开销也变小了,要知道线程就像寄居蟹一样,房子(地址空间)都是进程的,自己只是一个租客,因此非常的轻量级,创建销毁的开销也非常小。

我们可以为每个请求创建一个线程,即使一个线程因执行I/O操作——比如读取数据库等——被阻塞暂停运行也不会影响到其它线程。

就像这样:

但线程就是完美的、包治百病的吗,显然,计算机世界从来没有那么简单。

由于线程共享进程地址空间,这在为线程间通信带来便利的同时也带来了无尽的麻烦。

正是由于线程间共享地址空间,因此一个线程崩溃会导致整个进程崩溃退出,同时线程间通信简直太简单了,简单到线程间通信只需要直接读取内存就可以了,也简单到出现问题也极其容易,死锁、线程间的同步互斥、等等,这些极容易产生bug,无数程序员宝贵的时间就有相当一部分用来解决多线程带来的无尽问题。

虽然线程也有缺点,但是相比多进程来说,线程更有优势,但想单纯的利用多线程就能解决高并发问题也是不切实际的。

因为虽然线程创建开销相比进程小,但依然也是有开销的,对于动辄数万数十万的链接的高并发服务器来说,创建数万个线程会有性能问题,这包括内存占用、线程间切换,也就是调度的开销。

因此,我们需要进一步思考。

6、事件驱动:Event Loop

到目前为止,我们提到“并行”二字就会想到进程、线程。

但是:并行编程只能依赖这两项技术吗?并不是这样的!

还有另一项并行技术广泛应用在GUI编程以及服务器编程中,这就是近几年非常流行的事件驱动编程:event-based concurrency。

PS:搞IM服务端开发的程序员肯定不陌生,著名的Java NIO高性能网络编程框架Netty中EvenLoop 这个接口意味着什么(有关Netty框架的高性能原理可以读这篇《新手入门:目前为止最透彻的的Netty高性能原理和框架架构解析》)。

大家不要觉得这是一项很难懂的技术,实际上事件驱动编程原理上非常简单。

这一技术需要两种原料:

  • 1)event;
  • 2)处理event的函数,这一函数通常被称为event handler;

剩下的就简单了:你只需要安静的等待event到来就好,当event到来之后,检查一下event的类型,并根据该类型找到对应的event处理函数,也就是event handler,然后直接调用该event handler就好了。

That's it !

以上就是事件驱动编程的全部内容,是不是很简单!

从上面的讨论可以看到:我们需要不断的接收event然后处理event,因此我们需要一个循环(用while或者for循环都可以),这个循环被称为Event loop。

使用伪代码表示就是这样:

while(true) {

    event = getEvent();

    handler(event);

}

Event loop中要做的事情其实是非常简单的,只需要等待event的带来,然后调用相应的event处理函数即可。

注意:这段代码只需要运行在一个线程或者进程中,只需要这一个event loop就可以同时处理多个用户请求。

有的同学可以依然不明白:为什么这样一个event loop可以同时处理多个请求呢?

原因很简单:对于网络通信服务器来说,处理一个用户请求时大部分时间其实都用在了I/O操作上,像数据库读写、文件读写、网络读写等。当一个请求到来,简单处理之后可能就需要查询数据库等I/O操作,我们知道I/O是非常慢的,当发起I/O后我们大可以不用等待该I/O操作完成就可以继续处理接下来的用户请求。

现在你应该明白了吧:虽然上一个用户请求还没有处理完我们其实就可以处理下一个用户请求了,这也是并行,这种并行就可以用事件驱动编程来处理。

这就好比餐厅服务员一样:一个服务员不可能一直等上一个顾客下单、上菜、吃饭、买单之后才接待下一个顾客,服务员是怎么做的呢?当一个顾客下完单后直接处理下一个顾客,当顾客吃完饭后会自己回来买单结账的。

看到了吧:同样是一个服务员也可以同时处理多个顾客,这个服务员就相当于这里的Event loop,即使这个event loop只运行在一个线程(进程)中也可以同时处理多个用户请求。

相信你已经对事件驱动编程有一个清晰的认知了,那么接下来的问题就是,这个事件也就是event该怎么获取呢?

7、事件来源:IO多路复用

在《深入操作系统,彻底理解I/O多路复用》这篇文章中我们知道,在Linux/Unix世界中一切皆文件,而我们的程序都是通过文件描述符来进行I/O操作的,当然对于网络编程中的socket也不例外。

那我们该如何同时处理多个文件描述符呢?

IO多路复用技术正是用来解决这一问题的:通过IO多路复用技术,我们一次可以监控多个文件描述,当某个“文件”(实际可能是im网络通信中socket)可读或者可写的时候我们就能得到通知啦。

这样IO多路复用技术就成了event loop的原材料供应商,源源不断的给我们提供各种event,这样关于event来源的问题就解决了。

当然:关于IO多路复用技术的详细讲解请参见《深入操作系统,彻底理解I/O多路复用》,本文作为纲领性文章,就不再赘述了。

至此:关于利用事件驱动来实现并发编程的所有问题都解决了吗?event的来源问题解决了,当得到event后调用相应的handler,看上去大功告成了。

想一想还有没有其它问题?

8、问题:阻塞式IO

现在:我们可以使用一个线程(进程)就能基于事件驱动进行并行编程,再也没有了多线程中让人恼火的各种锁、同步互斥、死锁等问题了。

但是:计算机科学中从来没有出现过一种能解决所有问题的技术,现在没有,在可预期的将来也不会有。

那上述方法有什么问题吗?

不要忘了,我们event loop是运行在一个线程(进程),这虽然解决了多线程问题,但是如果在处理某个event时需要进行IO操作会怎么样呢?

在《深入操作系统,理解I/O与零拷贝技术》一文中,我们讲解了最常用的文件读取在底层是如何实现的,程序员最常用的这种IO方式被称为阻塞式IO。

也就是说:当我们进行IO操作,比如读取文件时,如果文件没有读取完成,那么我们的程序(线程)会被阻塞而暂停执行,这在多线程中不是问题,因为操作系统还可以调度其它线程。

但是:在单线程的event loop中是有问题的,原因就在于当我们在event loop中执行阻塞式IO操作时整个线程(event loop)会被暂停运行,这时操作系统将没有其它线程可以调度,因为系统中只有一个event loop在处理用户请求,这样当event loop线程被阻塞暂停运行时所有用户请求都没有办法被处理。你能想象当服务器在处理其它用户请求读取数据库导致你的请求被暂停吗?

因此:在基于事件驱动编程时有一条注意事项,那就是不允许发起阻塞式IO。

有的同学可能会问,如果不能发起阻塞式IO的话,那么该怎样进行IO操作呢?

PS:有阻塞式IO,就有非阻塞式IO。我们继续往下讨论。

9、解决方法:非阻塞式IO

为克服阻塞式IO所带来的问题,现代操作系统开始提供一种新的发起IO请求的方法,这种方法就是异步IO。对应的,阻塞式IO就是同步IO,关于同步和异步这两个概念可以参考《从根上理解高性能、高并发(四):深入操作系统,彻底理解同步与异步》。

异步IO时,假设调用aio_read函数(具体的异步IO API请参考具体的操作系统平台),也就是异步读取,当我们调用该函数后可以立即返回,并继续其它事情,虽然此时该文件可能还没有被读取,这样就不会阻塞调用线程了。此外,操作系统还会提供其它方法供调用线程来检测IO操作是否完成。

就这样,在操作系统的帮助下IO的阻塞调用问题也解决了。

10、基于事件驱动并行编程的难点

虽然有异步IO来解决event loop可能被阻塞的问题,但是基于事件编程依然是困难的。

首先:我们提到,event loop是运行在一个线程中的,显然一个线程是没有办法充分利用多核资源的,有的同学可能会说那就创建多个event loop实例不就可以了,这样就有多个event loop线程了,但是这样一来多线程问题又会出现。

另一点在于编程方面,在《从根上理解高性能、高并发(四):深入操作系统,彻底理解同步与异步》这篇文章中我们讲到过,异步编程需要结合回调函数(这种编程方式需要把处理逻辑分为两部分:一部分调用方自己处理,另一部分在回调函数中处理),这一编程方式的改变加重了程序员在理解上的负担,基于事件编程的项目后期会很难扩展以及维护。

那么有没有更好的方法呢?

要找到更好的方法,我们需要解决问题的本质,那么这个本质问题是什么呢?

11、更好的方法

为什么我们要使用异步这种难以理解的方式编程呢?

是因为:阻塞式编程虽然容易理解但会导致线程被阻塞而暂停运行。

那么聪明的你一定会问了:有没有一种方法既能结合同步IO的简单理解又不会因同步调用导致线程被阻塞呢?

答案是肯定的:这就是用户态线程(user level thread),也就是大名鼎鼎的协程(关于协程请详读本系列的上篇《从根上理解高性能、高并发(五):深入操作系统,理解高并发中的协程》,本文就不再赘述了)。

虽然基于事件编程有这样那样的缺点,但是在当今的高性能高并发服务器上基于事件编程方式依然非常流行,但已经不是纯粹的基于单一线程的事件驱动了,而是 event loop + multi thread + user level thread。

关于这一组合,同样值得拿出一篇文章来讲解,我们将在后续文章中详细讨论。

12、本文小结

高并发技术从最开始的多进程一路演进到当前的事件驱动,计算机技术就像生物一样也在不断演变进化,但不管怎样,了解历史才能更深刻的理解当下。希望这篇文章能对大家理解高并发服务器有所帮助。

附录:更多高性能、高并发文章精选

高性能网络编程(一):单台服务器并发TCP连接数到底可以有多少

高性能网络编程(二):上一个10年,著名的C10K并发连接问题

高性能网络编程(三):下一个10年,是时候考虑C10M并发问题了

高性能网络编程(四):从C10K到C10M高性能网络应用的理论探索

高性能网络编程(五):一文读懂高性能网络编程中的I/O模型

高性能网络编程(六):一文读懂高性能网络编程中的线程模型

高性能网络编程(七):到底什么是高并发?一文即懂!

以网游服务端的网络接入层设计为例,理解实时通信的技术挑战

知乎技术分享:知乎千万级并发的高性能长连接网关技术实践

淘宝技术分享:手淘亿级移动端接入层网关的技术演进之路

一套海量在线用户的移动端IM架构设计实践分享(含详细图文)

一套原创分布式即时通讯(IM)系统理论架构方案

微信后台基于时间序的海量数据冷热分级架构设计实践

微信技术总监谈架构:微信之道——大道至简(演讲全文)

如何解读《微信技术总监谈架构:微信之道——大道至简》

快速裂变:见证微信强大后台架构从0到1的演进历程(一)

17年的实践:腾讯海量产品的技术方法论

腾讯资深架构师干货总结:一文读懂大型分布式系统设计的方方面面

以微博类应用场景为例,总结海量社交系统的架构设计步骤

新手入门:零基础理解大型分布式架构的演进历史、技术原理、最佳实践

从新手到架构师,一篇就够:从100到1000万高并发的架构演进之路

本文已同步发布于“即时通讯技术圈”公众号。

▲ 本文在公众号上的链接是:点此进入。同步发布链接是:http://www.52im.net/thread-3315-1-1.html

posted @ 2021-01-25 16:36 Jack Jiang 阅读(272) | 评论 (0)编辑 收藏

     摘要: 本文原题“程序员应如何理解高并发中的协程”,转载请联系作者。1、系列文章引言1.1 文章目的作为即时通讯技术的开发者来说,高性能、高并发相关的技术概念早就了然与胸,什么线程池、零拷贝、多路复用、事件驱动、epoll等等名词信手拈来,又或许你对具有这些技术特征的技术框架比如:Java的Netty、Php的workman、Go的gnet等熟练掌握。但真正到了面视或者技术实践过程...  阅读全文

posted @ 2021-01-18 14:51 Jack Jiang 阅读(175) | 评论 (0)编辑 收藏

     摘要: 本文原题“从小白到高手,你需要理解同步与异步”,转载请联系作者。1、系列文章引言1.1 文章目的作为即时通讯技术的开发者来说,高性能、高并发相关的技术概念早就了然与胸,什么线程池、零拷贝、多路复用、事件驱动、epoll等等名词信手拈来,又或许你对具有这些技术特征的技术框架比如:Java的Netty、Php的workman、Go的gnet等熟练掌握。但真正到了面视或者技术实践...  阅读全文

posted @ 2021-01-12 14:15 Jack Jiang 阅读(195) | 评论 (0)编辑 收藏

本文原题“终于明白了,一文彻底理解I/O多路复用”,转载请联系作者。

1、系列文章引言

1.1 文章目的

作为即时通讯技术的开发者来说,高性能、高并发相关的技术概念早就了然与胸,什么线程池、零拷贝、多路复用、事件驱动、epoll等等名词信手拈来,又或许你对具有这些技术特征的技术框架比如:Java的Netty、Php的workman、Go的nget等熟练掌握。但真正到了面视或者技术实践过程中遇到无法释怀的疑惑时,方知自已所掌握的不过是皮毛。

返璞归真、回归本质,这些技术特征背后的底层原理到底是什么?如何能通俗易懂、毫不费力真正透彻理解这些技术背后的原理,正是《从根上理解高性能、高并发》系列文章所要分享的。

1.2 文章源起

我整理了相当多有关IM、消息推送等即时通讯技术相关的资源和文章,从最开始的开源IM框架MobileIMSDK,到网络编程经典巨著《TCP/IP详解》的在线版本,再到IM开发纲领性文章《新手入门一篇就够:从零开发移动端IM》,以及网络编程由浅到深的《网络编程懒人入门》、《脑残式网络编程入门》、《高性能网络编程》、《不为人知的网络编程》系列文章。

越往知识的深处走,越觉得对即时通讯技术了解的太少。于是后来,为了让开发者门更好地从基础电信技术的角度理解网络(尤其移动网络)特性,我跨专业收集整理了《IM开发者的零基础通信技术入门》系列高阶文章。这系列文章已然是普通即时通讯开发者的网络通信技术知识边界,加上之前这些网络编程资料,解决网络通信方面的知识盲点基本够用了。

对于即时通讯IM这种系统的开发来说,网络通信知识确实非常重要,但回归到技术本质,实现网络通信本身的这些技术特征:包括上面提到的线程池、零拷贝、多路复用、事件驱动等等,它们的本质是什么?底层原理又是怎样?这就是整理本系列文章的目的,希望对你有用。

1.3 文章目录

从根上理解高性能、高并发(一):深入计算机底层,理解线程与线程池

从根上理解高性能、高并发(二):深入操作系统,理解I/O与零拷贝技术

从根上理解高性能、高并发(三):深入操作系统,彻底理解I/O多路复用》(* 本文

《从根上理解高性能、高并发(四):深入操作系统,彻底理解同步与异步 (稍后发布..)》

《从根上理解高性能、高并发(五):高并发高性能服务器到底是如何实现的 (稍后发布..)》

1.4 本篇概述

接上篇《深入操作系统,理解I/O与零拷贝技术》,本篇是高性能、高并发系列的第3篇文章,上篇里我们讲到了I/O技术,本篇将以更具象的文件这个话题入手,带你一步步理解高性能、高并发服务端编程时无法回避的I/O多路复用及相关技术。

本文已同步发布于“即时通讯技术圈”公众号,欢迎关注。公众号上的链接是:点此进入

2、本文作者

应作者要求,不提供真名,也不提供个人照片。

本文作者主要技术方向为互联网后端、高并发高性能服务器、检索引擎技术,网名是“码农的荒岛求生”,公众号“码农的荒岛求生”。感谢作者的无私分享。

3、什么是文件?

在正式展开本文的内容之前,我们需要先预习一下文件以及文件描述符的概念。

程序员使用I/O最终都逃不过文件这个概念。

在Linux世界中文件是一个很简单的概念,作为程序员我们只需要将其理解为一个N byte的序列就可以了:

b1, b2, b3, b4, ....... bN

实际上所有的I/O设备都被抽象为了文件这个概念,一切皆文件(Everything is File),磁盘、网络数据、终端,甚至进程间通信工具管道pipe等都被当做文件对待。

所有的I/O操作也都可以通过文件读写来实现,这一非常优雅的抽象可以让程序员使用一套接口就能对所有外设I/O操作。

常用的I/O操作接口一般有以下几类:

  • 1)打开文件,open;
  • 2)改变读写位置,seek;
  • 3)文件读写,read、write;
  • 4)关闭文件,close。

程序员通过这几个接口几乎可以实现所有I/O操作,这就是文件这个概念的强大之处。

4、什么是文件描述符?

在上一篇《深入操作系统,理解I/O与零拷贝技术》中我们讲到:要想进行I/O读操作,像磁盘数据,我们需要指定一个buff用来装入数据。

一般都是这样写的:

read(buff);

但是这里我们忽略了一个关键问题:那就是,虽然我们指定了往哪里写数据,但是我们该从哪里读数据呢?

从上一节中我们知道,通过文件这个概念我们能实现几乎所有I/O操作,因此这里少的一个主角就是文件。

那么我们一般都怎样使用文件呢?

举个例子:如果周末你去比较火的餐厅吃饭应该会有体会,一般周末人气高的餐厅都会排队,然后服务员会给你一个排队序号,通过这个序号服务员就能找到你,这里的好处就是服务员无需记住你是谁、你的名字是什么、来自哪里、喜好是什么、是不是保护环境爱护小动物等等,这里的关键点就是:服务员对你一无所知,但依然可以通过一个号码就能找到你。

同样的:在Linux世界要想使用文件,我们也需要借助一个号码,根据“弄不懂原则”,这个号码就被称为了文件描述符(file descriptors),在Linux世界中鼎鼎大名,其道理和上面那个排队号码一样。

因此:文件描述仅仅就是一个数字而已,但是通过这个数字我们可以操作一个打开的文件,这一点要记住。

有了文件描述符,进程可以对文件一无所知,比如文件在磁盘的什么位置、加载到内存中又是怎样管理的等等,这些信息统统交由操作系统打理,进程无需关心,操作系统只需要给进程一个文件描述符就足够了。

因此我们来完善上述程序:

int fd = open(file_name); // 获取文件描述符

read(fd, buff);

怎么样,是不是非常简单。

5、文件描述符太多了怎么办?

经过了这么多的铺垫,终于要到高性能、高并发这一主题了。

从前几节我们知道,所有I/O操作都可以通过文件样的概念来进行,这当然包括网络通信。

如果你有一个IM服务器,当三次握手建议长连接成功以后,我们会调用accept来获取一个链接,调用该函数我们同样会得到一个文件描述符,通过这个文件描述符就可以处理客户端发送的聊天消息并且把消息转发给接收者。

也就是说,通过这个描述符我们就可以和客户端进行通信了:

// 通过accept获取客户端的文件描述符

int conn_fd = accept(...);

Server端的处理逻辑通常是接收客户端消息数据,然后执行转发(给接收者)逻辑:

if(read(conn_fd, msg_buff) > 0) {

do_transfer(msg_buff);

}

是不是非常简单,然而世界终归是复杂的,当然也不是这么简单的。

接下来就是比较复杂的了。

既然我们的主题是高并发,那么Server端就不可能只和一个客户端通信,而是可能会同时和成千上万个客户端进行通信。这时你需要处理不再是一个描述符这么简单,而是有可能要处理成千上万个描述符。

为了不让问题一上来就过于复杂,我们先简单化,假设只同时处理两个客户端的请求。

有的同学可能会说,这还不简单,这样写不就行了:

if(read(socket_fd1, buff) > 0) { // 处理第一个

do_transfer();

}

if(read(socket_fd2, buff) > 0) { // 处理第二个

do_transfer();

在上一篇《深入操作系统,理解I/O与零拷贝技术》中我们讨论过,这是非常典型的阻塞式I/O,如果此时没有数据可读那么进程会被阻塞而暂停运行。这时我们就无法处理第二个请求了,即使第二个请求的数据已经就位,这也就意味着处理某一个客户端时由于进程被阻塞导致剩下的所有其它客户端必须等待,在同时处理几万客户端的server上。这显然是不能容忍的。

聪明的你一定会想到使用多线程:为每个客户端请求开启一个线程,这样一个客户端被阻塞就不会影响到处理其它客户端的线程了。注意:既然是高并发,那么我们要为成千上万个请求开启成千上万个线程吗,大量创建销毁线程会严重影响系统性能。

那么这个问题该怎么解决呢?

这里的关键点在于:我们事先并不知道一个文件描述对应的I/O设备是否是可读的、是否是可写的,在外设的不可读或不可写的状态下进行I/O只会导致进程阻塞被暂停运行。

因此要优雅的解决这个问题,就要从其它角度来思考这个问题了。

6、“不要打电话给我,有需要我会打给你”

大家生活中肯定会接到过推销电话,而且不止一个,一天下来接上十个八个推销电话你的身体会被掏空的。

这个场景的关键点在于:打电话的人并不知道你是不是要买东西,只能来一遍遍问你。因此一种更好的策略是不要让他们打电话给你,记下他们的电话,有需要的话打给他们,这样推销员就不会一遍一遍的来烦你了(虽然现实生活中这并不可能)。

在这个例子中:你,就好比内核,推销者就好比应用程序,电话号码就好比文件描述符,和你用电话沟通就好比I/O。

现在你应该明白了吧,处理多个文件描述符的更好方法其实就存在于推销电话中。

因此相比上一节中:我们通过I/O接口主动问内核这些文件描述符对应的外设是不是已经就绪了,一种更好的方法是,我们把这些感兴趣的文件描述符一股脑扔给内核,并霸气的告诉内核:“我这里有1万个文件描述符,你替我监视着它们,有可以读写的文件描述符时你就告诉我,我好处理”。而不是弱弱的问内核:“第一个文件描述可以读写了吗?第二个文件描述符可以读写吗?第三个文件描述符可以读写了吗?。。。”

这样:应用程序就从“繁忙”的主动变为了清闲的被动,反正文件描述可读可写了内核会通知我,能偷懒我才不要那么勤奋。

这是一种更加高效的I/O处理机制,现在我们可以一次处理多路I/O了,为这种机制起一个名字吧,就叫I/O多路复用吧,这就是 I/O multiplexing。

7、I/O多路复用(I/O multiplexing)

multiplexing一词其实多用于通信领域,为了充分利用通信线路,希望在一个信道中传输多路信号,要想在一个信道中传输多路信号就需要把这多路信号结合为一路,将多路信号组合成一个信号的设备被称为Multiplexer(多路复用器),显然接收方接收到这一路组合后的信号后要恢复原先的多路信号,这个设备被称为Demultiplexer(多路分用器)。

如下图所示:

回到我们的主题。

所谓I/O多路复用指的是这样一个过程:

  • 1)我们拿到了一堆文件描述符(不管是网络相关的、还是磁盘文件相关等等,任何文件描述符都可以);
  • 2)通过调用某个函数告诉内核:“这个函数你先不要返回,你替我监视着这些描述符,当这堆文件描述符中有可以进行I/O读写操作的时候你再返回”;
  • 3)当调用的这个函数返回后我们就能知道哪些文件描述符可以进行I/O操作了。

也就是说通过I/O多路复用我们可以同时处理多路I/O。那么有哪些函数可以用来进行I/O多路复用呢?

以Linux为例,有这样三种机制可以用来进行I/O多路复用:

  • 1)select;
  • 2)poll;
  • 3)epoll。

接下来我们就来介绍一下牛掰的I/O多路复用三剑客。

8、I/O多路复用三剑客

本质上:Linux上的select、poll、epoll都是阻塞式I/O,也就是我们常说的同步I/O。

原因在于:调用这些I/O多路复用函数时如果任何一个需要监视的文件描述符都不可读或者可写那么进程会被阻塞暂停执行,直到有文件描述符可读或者可写才继续运行。

8.1 select:初出茅庐

在select这种I/O多路复用机制下,我们需要把想监控的文件描述集合通过函数参数的形式告诉select,然后select会将这些文件描述符集合拷贝到内核中。

我们知道数据拷贝是有性能损耗的,因此为了减少这种数据拷贝带来的性能损耗,Linux内核对集合的大小做了限制,并规定用户监控的文件描述集合不能超过1024个,同时当select返回后我们仅仅能知道有些文件描述符可以读写了,但是我们不知道是哪一个。因此程序员必须再遍历一边找到具体是哪个文件描述符可以读写了。

因此,总结下来select有这样几个特点:

  • 1)我能照看的文件描述符数量有限,不能超过1024个;
  • 2)用户给我的文件描述符需要拷贝的内核中;
  • 3)我只能告诉你有文件描述符满足要求了,但是我不知道是哪个,你自己一个一个去找吧(遍历)。

因此我们可以看到,select机制的这些特性在高并发网络服务器动辄几万几十万并发链接的场景下无疑是低效的。

8.2 poll:小有所成

poll和select是非常相似的。

poll相对于select的优化仅仅在于解决了文件描述符不能超过1024个的限制,select和poll都会随着监控的文件描述数量增加而性能下降,因此不适合高并发场景。

8.3 epoll:独步天下

在select面临的三个问题中,文件描述数量限制已经在poll中解决了,剩下的两个问题呢?

针对拷贝问题:epoll使用的策略是各个击破与共享内存。

实际上:文件描述符集合的变化频率比较低,select和poll频繁的拷贝整个集合,内核都快被烦死了,epoll通过引入epoll_ctl很体贴的做到了只操作那些有变化的文件描述符。同时epoll和内核还成为了好朋友,共享了同一块内存,这块内存中保存的就是那些已经可读或者可写的的文件描述符集合,这样就减少了内核和程序的拷贝开销。

针对需要遍历文件描述符才能知道哪个可读可写这一问题,epoll使用的策略是“当小弟”。

在select和poll机制下:进程要亲自下场去各个文件描述符上等待,任何一个文件描述可读或者可写就唤醒进程,但是进程被唤醒后也是一脸懵逼并不知道到底是哪个文件描述符可读或可写,还要再从头到尾检查一遍。

但epoll就懂事多了,主动找到进程要当小弟替大哥出头。

在这种机制下:进程不需要亲自下场了,进程只要等待在epoll上,epoll代替进程去各个文件描述符上等待,当哪个文件描述符可读或者可写的时候就告诉epoll,epoll用小本本认真记录下来然后唤醒大哥:“进程大哥,快醒醒,你要处理的文件描述符我都记下来了”,这样进程被唤醒后就无需自己从头到尾检查一遍,因为epoll小弟都已经记下来了。

因此我们可以看到:在epoll这种机制下,实际上利用的就是“不要打电话给我,有需要我会打给你”这种策略,进程不需要一遍一遍麻烦的问各个文件描述符,而是翻身做主人了——“你们这些文件描述符有哪个可读或者可写了主动报上来”。

这种机制实际上就是大名鼎鼎的事件驱动——Event-driven,这也是我们下一篇的主题。

实际上:在Linux平台,epoll基本上就是高并发的代名词。

9、本文小结

基于一切皆文件的设计哲学,I/O也可以通过文件的形式实现,高并发场景下要与多个文件交互,这就离不开高效的I/O多路复用技术。

本文我们详细讲解了什么是I/O多路复用以及使用方法,这其中以epoll为代表的I/O多路复用(基于事件驱动)技术使用非常广泛,实际上你会发现但凡涉及到高并发、高性能的场景基本上都能见到事件驱动的编程方法,当然这也是下一篇我们要重点讲解的主题《从根上理解高性能、高并发(四):深入操作系统,彻底理解同步与异步》,敬请期待!

附录:更多高性能、高并发文章精选

高性能网络编程(一):单台服务器并发TCP连接数到底可以有多少

高性能网络编程(二):上一个10年,著名的C10K并发连接问题

高性能网络编程(三):下一个10年,是时候考虑C10M并发问题了

高性能网络编程(四):从C10K到C10M高性能网络应用的理论探索

高性能网络编程(五):一文读懂高性能网络编程中的I/O模型

高性能网络编程(六):一文读懂高性能网络编程中的线程模型

高性能网络编程(七):到底什么是高并发?一文即懂!

以网游服务端的网络接入层设计为例,理解实时通信的技术挑战

知乎技术分享:知乎千万级并发的高性能长连接网关技术实践

淘宝技术分享:手淘亿级移动端接入层网关的技术演进之路

一套海量在线用户的移动端IM架构设计实践分享(含详细图文)

一套原创分布式即时通讯(IM)系统理论架构方案

微信后台基于时间序的海量数据冷热分级架构设计实践

微信技术总监谈架构:微信之道——大道至简(演讲全文)

如何解读《微信技术总监谈架构:微信之道——大道至简》

快速裂变:见证微信强大后台架构从0到1的演进历程(一)

17年的实践:腾讯海量产品的技术方法论

腾讯资深架构师干货总结:一文读懂大型分布式系统设计的方方面面

以微博类应用场景为例,总结海量社交系统的架构设计步骤

新手入门:零基础理解大型分布式架构的演进历史、技术原理、最佳实践

从新手到架构师,一篇就够:从100到1000万高并发的架构演进之路

本文已同步发布于“即时通讯技术圈”公众号。

▲ 本文在公众号上的链接是:点此进入。同步发布链接是:http://www.52im.net/thread-3287-1-1.html

posted @ 2021-01-05 15:06 Jack Jiang 阅读(221) | 评论 (0)编辑 收藏

1、系列文章引言

1.1 文章目的

作为即时通讯技术的开发者来说,高性能、高并发相关的技术概念早就了然与胸,什么线程池、零拷贝、多路复用、事件驱动、epoll等等名词信手拈来,又或许你对具有这些技术特征的技术框架比如:Java的Netty、Php的workman、Go的nget等熟练掌握。但真正到了面视或者技术实践过程中遇到无法释怀的疑惑时,方知自已所掌握的不过是皮毛。

返璞归真、回归本质,这些技术特征背后的底层原理到底是什么?如何能通俗易懂、毫不费力真正透彻理解这些技术背后的原理,正是《从根上理解高性能、高并发》系列文章所要分享的。

1.2 文章源起

我整理了相当多有关IM、消息推送等即时通讯技术相关的资源和文章,从最开始的开源IM框架MobileIMSDK,到网络编程经典巨著《TCP/IP详解》的在线版本,再到IM开发纲领性文章《新手入门一篇就够:从零开发移动端IM》,以及网络编程由浅到深的《网络编程懒人入门》、《脑残式网络编程入门》、《高性能网络编程》、《不为人知的网络编程》系列文章。

越往知识的深处走,越觉得对即时通讯技术了解的太少。于是后来,为了让开发者门更好地从基础电信技术的角度理解网络(尤其移动网络)特性,我跨专业收集整理了《IM开发者的零基础通信技术入门》系列高阶文章。这系列文章已然是普通即时通讯开发者的网络通信技术知识边界,加上之前这些网络编程资料,解决网络通信方面的知识盲点基本够用了。

对于即时通讯IM这种系统的开发来说,网络通信知识确实非常重要,但回归到技术本质,实现网络通信本身的这些技术特征:包括上面提到的线程池、零拷贝、多路复用、事件驱动等等,它们的本质是什么?底层原理又是怎样?这就是整理本系列文章的目的,希望对你有用。

1.3 文章目录

1.4 本篇概述

接上篇《深入计算机底层,理解线程与线程池》,本篇是高性能、高并发系列的第2篇文章,在这里我们来到了I/O这一话题。你有没有想过,当我们执行文件I/O、网络I/O操作时计算机底层到底发生了些什么?对于计算机来说I/O是极其重要的,本篇将带给你这个问的答案。

2、本文作者

应作者要求,不提供真名,也不提供个人照片。

本文作者主要技术方向为互联网后端、高并发高性能服务器、检索引擎技术,网名是“码农的荒岛求生”,公众号“码农的荒岛求生”。感谢作者的无私分享。

3、不能执行I/O的计算机是什么?

相信对于程序员来说I/O操作是最为熟悉不过的了,比如:

  • 1)当我们使用C语言中的printf、C++中的"<<",Python中的print,Java中的System.out.println等时;
  • 2)当我们使用各种语言读写文件时;
  • 3)当我们通过TCP/IP进行网络通信时;
  • 4)当我们使用鼠标龙飞凤舞时;
  • 5)当我们拿起键盘在评论区指点江山亦或是埋头苦干努力制造bug时;
  • 6)当我们能看到屏幕上的漂亮的图形界面时等等。

以上这一切,都是I/O!

想一想:如果没有I/O计算机该是一种多么枯燥的设备,不能看电影、不能玩游戏,也不能上网,这样的计算机最多就是一个大号的计算器。

既然I/O这么重要,那么到底什么才是I/O呢?

4、什么是I/O?

I/O就是简单的数据Copy,仅此而已!

这一点很重要!

既然是copy数据,那么又是从哪里copy到哪里呢?

如果数据是从外部设备copy到内存中,这就是Input。

如果数据是从内存copy到外部设备,这就是Output。

内存与外部设备之间不嫌麻烦的来回copy数据就是Input and Output,简称I/O(Input/Output),仅此而已。

5、I/O与CPU

现在我们知道了什么是I/O,接下来就是重点部分了,大家注意,坐稳了。

我们知道现在的CPU其主频都是数GHz起步,这是什么意思呢?

简单说就是:CPU执行机器指令的速度是纳秒级别的,而通常的I/O比如磁盘操作,一次磁盘seek大概在毫秒级别,因此如果我们把CPU的速度比作战斗机的话,那么I/O操作的速度就是肯德鸡。

也就是说当我们的程序跑起来时(CPU执行机器指令),其速度是要远远快于I/O速度的。那么接下来的问题就是二者速度相差这么大,那么我们该如何设计、该如何更加合理的高效利用系统资源呢?

既然有速度差异,而且进程在执行完I/O操作前不能继续向前推进,那么显然只有一个办法,那就是等待(wait)。

同样是等待,有聪明的等待,也有傻傻的等待,简称傻等,那么是选择聪明的等待呢还是选择傻等呢?

假设你是一个急性子(CPU),需要等待一个重要的文件,不巧的是这个文件只能快递过来(I/O),那么这时你是选择什么事情都不干了,深情的注视着门口就像盼望着你的哈尼一样专心等待这个快递呢?还是暂时先不要管快递了,玩个游戏看个电影刷会儿短视频等快递来了再说呢?

很显然,更好的方法就是先去干其它事情,快递来了再说。

因此:这里的关键点就是快递没到前手头上的事情可以先暂停,切换到其它任务,等快递过来了再切换回来。

理解了这一点你就能明白执行I/O操作时底层都发生了什么。

接下来让我们以读取磁盘文件为例来讲解这一过程。

6、执行I/O时底层都发生了什么

在上一篇《深入计算机底层,理解线程与线程池》中,我们引入了进程和线程的概念。

在支持线程的操作系统中,实际上被调度的是线程而不是进程,为了更加清晰的理解I/O过程,我们暂时假设操作系统只有进程这样的概念,先不去考虑线程,这并不会影响我们的讨论。

现在内存中有两个进程,进程A和进程B,当前进程A正在运行。

如下图所示:

进程A中有一段读取文件的代码,不管在什么语言中通常我们定义一个用来装数据的buff,然后调用read之类的函数。

就像这样:

read(buff);

这就是一种典型的I/O操作,当CPU执行到这段代码的时候会向磁盘发送读取请求。

注意:与CPU执行指令的速度相比,I/O操作操作是非常慢的,因此操作系统是不可能把宝贵的CPU计算资源浪费在无谓的等待上的,这时重点来了,注意接下来是重点哦。

由于外部设备执行I/O操作是相当慢的,因此在I/O操作完成之前进程是无法继续向前推进的,这就是所谓的阻塞,即通常所说的block。

操作系统检测到进程向I/O设备发起请求后就暂停进程的运行,怎么暂停运行呢?很简单:只需要记录下当前进程的运行状态并把CPU的PC寄存器指向其它进程的指令就可以了。

进程有暂停就会有继续执行,因此操作系统必须保存被暂停的进程以备后续继续执行,显然我们可以用队列来保存被暂停执行的进程。

如下图所示,进程A被暂停执行并被放到阻塞队列中(注意:不同的操作系统会有不同的实现,可能每个I/O设备都有一个对应的阻塞队列,但这种实现细节上的差异不影响我们的讨论)。

这时操作系统已经向磁盘发送了I/O请求,因此磁盘driver开始将磁盘中的数据copy到进程A的buff中。虽然这时进程A已经被暂停执行了,但这并不妨碍磁盘向内存中copy数据。

注意:现代磁盘向内存copy数据时无需借助CPU的帮助,这就是所谓的DMA(Direct Memory Access)。

这个过程如下图所示:

让磁盘先copy着数据,我们接着聊。

实际上:操作系统中除了有阻塞队列之外也有就绪队列,所谓就绪队列是指队列里的进程准备就绪可以被CPU执行了。

你可能会问为什么不直接执行非要有个就绪队列呢?答案很简单:那就是僧多粥少,在即使只有1个核的机器上也可以创建出成千上万个进程,CPU不可能同时执行这么多的进程,因此必然存在这样的进程,即使其一切准备就绪也不能被分配到计算资源,这样的进程就被放到了就绪队列。

现在进程B就位于就绪队列,万事俱备只欠CPU。

如下图所示:

当进程A被暂停执行后CPU是不可以闲下来的,因为就绪队列中还有嗷嗷待哺的进程B,这时操作系统开始在就绪队列中找下一个可以执行的进程,也就是这里的进程B。

此时操作系统将进程B从就绪队列中取出,找出进程B被暂停时执行到的机器指令的位置,然后将CPU的PC寄存器指向该位置,这样进程B就开始运行啦。

如下图所示:

注意:接下来的这段是重点中的重点!

注意观察上图:此时进程B在被CPU执行,磁盘在向进程A的内存空间中copy数据,看出来了吗——大家都在忙,谁都没有闲着,数据copy和指令执行在同时进行,在操作系统的调度下,CPU、磁盘都得到了充分的利用,这就是程序员的智慧所在。

现在你应该理解为什么操作系统这么重要了吧。

此后磁盘终于将全部数据都copy到了进程A的内存中,这时磁盘通知操作系统任务完成啦,你可能会问怎么通知呢?这就是中断。

操作系统接收到磁盘中断后发现数据copy完毕,进程A重新获得继续运行的资格,这时操作系统小心翼翼的把进程A从阻塞队列放到了就绪队列当中。

如下图所示:

注意:从前面关于就绪状态的讨论中我们知道,操作系统是不会直接运行进程A的,进程A必须被放到就绪队列中等待,这样对大家都公平。

此后进程B继续执行,进程A继续等待,进程B执行了一会儿后操作系统认为进程B执行的时间够长了,因此把进程B放到就绪队列,把进程A取出并继续执行。

注意:操作系统把进程B放到的是就绪队列,因此进程B被暂停运行仅仅是因为时间片到了而不是因为发起I/O请求被阻塞。

如下图所示:

进程A继续执行,此时buff中已经装满了想要的数据,进程A就这样愉快的运行下去了,就好像从来没有被暂停过一样,进程对于自己被暂停一事一无所知,这就是操作系统的魔法。

现在你应该明白了I/O是一个怎样的过程了吧。

这种进程执行I/O操作被阻塞暂停执行的方式被称为阻塞式I/O,blocking I/O,这也是最常见最容易理解的I/O方式,有阻塞式I/O就有非阻塞式I/O,在这里我们暂时先不考虑这种方式。

在本节开头我们说过暂时只考虑进程而不考虑线程,现在我们放宽这个条件,实际上也非常简单,只需要把前图中调度的进程改为线程就可以了,这里的讨论对于线程一样成立。

7、零拷贝(Zero-copy)

最后需要注意的一点就是:上面的讲解中我们直接把磁盘数据copy到了进程空间中,但实际上一般情况下I/O数据是要首先copy到操作系统内部,然后操作系统再copy到进程空间中。

因此我们可以看到这里其实还有一层经过操作系统的copy,对于性能要求很高的场景其实也是可以绕过操作系统直接进行数据copy的,这也是本文描述的场景,这种绕过操作系统直接进行数据copy的技术被称为Zero-copy,也就零拷贝,高并发、高性能场景下常用的一种技术,原理上很简单吧。

PS:对于搞即时通讯开发的Java程序员来说,著名的高性能网络框架Netty就使用了零拷贝技术,具体可以读《NIO框架详解:Netty的高性能之道》一文的第12节。如果对于Netty框架很好奇但不了解的话,可以因着这两篇文章入门:《新手入门:目前为止最透彻的的Netty高性能原理和框架架构解析》、《史上最通俗Netty入门长文:基本介绍、环境搭建、动手实战》。

8、本文小结

本文讲解的是程序员常用的I/O(包括所谓的网络I/O),一般来说作为程序员我们无需关心,但是理解I/O背后的底层原理对于设计比如IM这种高性能、高并发系统是极为有益的,希望这篇能对大家加深对I/O的认识有所帮助。

接下来的一篇《从根上理解高性能、高并发(三):深入操作系统,彻底理解I/O多路复用》将要分享的是I/O技术的一大突破,正是因为它,才彻底解决了高并发网络通信中的C10K问题(见《高性能网络编程(二):上一个10年,著名的C10K并发连接问题),敬请期待!

附录:更多高性能、高并发文章精选

高性能网络编程(一):单台服务器并发TCP连接数到底可以有多少

高性能网络编程(二):上一个10年,著名的C10K并发连接问题

高性能网络编程(三):下一个10年,是时候考虑C10M并发问题了

高性能网络编程(四):从C10K到C10M高性能网络应用的理论探索

高性能网络编程(五):一文读懂高性能网络编程中的I/O模型

高性能网络编程(六):一文读懂高性能网络编程中的线程模型

高性能网络编程(七):到底什么是高并发?一文即懂!

以网游服务端的网络接入层设计为例,理解实时通信的技术挑战

知乎技术分享:知乎千万级并发的高性能长连接网关技术实践

淘宝技术分享:手淘亿级移动端接入层网关的技术演进之路

一套海量在线用户的移动端IM架构设计实践分享(含详细图文)

一套原创分布式即时通讯(IM)系统理论架构方案

微信后台基于时间序的海量数据冷热分级架构设计实践

微信技术总监谈架构:微信之道——大道至简(演讲全文)

如何解读《微信技术总监谈架构:微信之道——大道至简》

快速裂变:见证微信强大后台架构从0到1的演进历程(一)

17年的实践:腾讯海量产品的技术方法论

腾讯资深架构师干货总结:一文读懂大型分布式系统设计的方方面面

以微博类应用场景为例,总结海量社交系统的架构设计步骤

新手入门:零基础理解大型分布式架构的演进历史、技术原理、最佳实践

从新手到架构师,一篇就够:从100到1000万高并发的架构演进之路

本文已同步发布于“即时通讯技术圈”公众号。

▲ 本文在公众号上的链接是:点此进入。同步发布链接是:http://www.52im.net/thread-3280-1-1.html

posted @ 2020-12-28 14:42 Jack Jiang 阅读(201) | 评论 (0)编辑 收藏

     摘要: 本文原题“聊聊TCP连接耗时的那些事儿”,本次收录已征得作者同意,转载请联系作者。有少许改动。1、系列文章引言1.1 文章目的作为即时通讯技术的开发者来说,高性能、高并发相关的技术概念早就了然与胸,什么线程池、零拷贝、多路复用、事件驱动、epoll等等名词信手拈来,又或许你对具有这些技术特征的技术框架比如:Java的Netty、Php的workman、Go的nget等熟练掌...  阅读全文

posted @ 2020-12-23 16:19 Jack Jiang 阅读(401) | 评论 (0)编辑 收藏

本文由淘宝消息业务团队李历岷(花名骨来)原创分享,首次发表于公众号“淘系技术”,有修订和改动。

1、引言

本文来自淘宝消息业务团队的技术实践分享,分析了电商IM消息平台在非传统IM应用场景下的高发并、强互动群聊和直播业务中的技术特点,总结并分享了在这些场景下实现大量多对多实时消息分发投递的一些架构方面的设计实践。

目前,阿里的IM消息业务团队负责新零售领域 IM 消息平台的建设,通过 IM即时通讯产品(push、聊天机器人、单聊、群聊、消息号和聊天室)构建连接消费者和商家的沟通和触达渠道,每天处理百亿级的消费规模,支撑了直播互动、客服服务、商家群运营、品牌资讯、营销推送等电商领域 BC 互通的业务场景。

本文同步发布于:http://www.52im.net/thread-3252-1-1.html

2、技术背景

2020年双11,第一次改变节奏,从光棍节变成双节棍,从一个峰变成了两个峰,在新的挑战下,如何做好技术保障,做好技术支撑,所有技术人都进入了一个新的学习过程。

新的形势下,显著特点是时间跨度长、活动周期长以及用户互动玩法更多。从单用户CC分享到群内分享,以及直播间互动消息等,作为电商的IM消息平台,承接着整个互动的场地。

用户在整个“互动消息”场景下,可以进行实时分享、聊天、客服沟通、商家优惠、商家优惠活动和红包以及商品秒杀等。

“消息”作为用户和用户之间架起“连接”的重要桥梁,消息连接了用户和用户、用户和商家、用户和平台等。

如何做到高并发强互动下消息有序地呈现在用户面前,是消息团队亘古不变的主题,尤其是在用户的互动行为不确定性情况下,在面对不确定性的流量和规模时,系统应该怎样做到“丝般顺滑”的体验呢?本文将带着读者一起来进行深入探讨。

3、强互动消息场景的技术挑战

不同于传统社区IM消息平台,电商IM消息平台有自已的互动场景特点。

3.1 直播间

淘宝直播带来新的流量变化,百万在线已经成为常态化,大量的直播间7X24小时直播带货,用户在直播频道页频繁地进出不同的直播间。

有时候被某个直播间吸引,停在那里等着优惠、红包和宝贝,随着主播在直播间喊一嗓子,推送一张宝贝卡片,几十万人蜂拥而至秒杀。这样的场景每天都在上演 ...

3.2 互动PK群

主互动玩法“超级星秀猫瓜分20亿红包”开启的时候,意味着大量互动拉赞、分享到好友、分享到群成为流量的入口,无论淘口令/图片等。

大量的消息卡片被转发、二次转发带来的分享裂变效应,每天09:00和晚上22:00成为活跃的峰值,每个组队的用户拉群互赞,这样的场景从10月20日到11月11日持续每天固定时段上演 ...

3.3 不确定性流量

分享面板入口一次列表排布改变,营销活动的一次优惠推送,直播频道页一次运营活动都可能导致直播间/群的流量瞬间波动。

纷涌而至的用户带来了大量的互动行为,各种点击/分享/消息发送纷至沓来。

如何应对这样的流量和规模,作为平台系统,必须能够做到应对不确定性流量能力和机制,必须从流量入口到流量出口端到端考虑整体的全链路架构,是否存在单点瓶颈和缺口。

尤其在大促前期,系统架构梳理、强弱依赖梳理、上下游链路串联、破坏性压测、脉冲流量压测和全链路压测保障和优化,以及配合相关的流量控制、预案保护、业务流量隔离机制、资源调控等手段,才得以做到“不确定性流量”向“确定性流量”转变,才可以更大程度上保障系统高可用和极致用户体验。

4、强互动群聊中的消息架构实践

4.1 传统IM中“写扩散”架构的瓶颈

随着2018年淘系电商首推“双11合伙人计划”,更简单直接的双11玩法,给大众带来更多期待和惊喜。

尤其是盖楼互赞活动更是把“群聊”推上风口浪尖, 在手淘APP内部分享比在微信和钉钉等社交/企业软件分享更加便捷和高效,用户不停地在群内互动分享拉赞、通过好友助力提升盖楼积分。

基于传统的IM架构技术,尤其在群内聊天或者分享,每条消息按照群内人数进行写扩散,按照主互动500人群规模来计算,平均群大小320+,1:N的写入必然导致写入DB的RT以及存储压力,按照DB库承接120w/s写入速度,导致消息上行3K/s的极限,而实际参与互动分享的用户在峰值的时候远大于这部分互动分享和聊天消息流量。

其次集群的写入不可能完全给IM聊天消息,还有其它的营销活动、交易、物流等通知类型的消息。

基于传统IM的“写扩散”架构,在高并发、强互动场景下遇到了瓶颈,导致消息大量的延迟下推,影响最终用户体验。

4.2 “读扩散”架构的应用

基于写扩散架构的消息扩散比是1:N,那能否做到消息扩散比是1:1呢?

答案是肯定的:针对群内的消息可以分为“非个性化消息”和“个性化消息”,所谓“非个性化消息”就是大家看到都是一样的,应该只需要写一条数据,群内成员可以共享取这条数据(所谓“个性化消息”,指定某个成员发送的单边消息,譬如进群欢迎语等)。

在群内,99.99%都是“非个性化消息”,也就是可以从1:N压缩到1:1写入。

基于这个理论假设,需要考虑“读扩散”让每个用户的消息从对应的“群会话消息队列同步“数据,而不是从”用户队列同步“数据。

其中同步队列围绕队列offset偏移量进行,通过队列的自增syncId保证有序,每个客户端维护相应的队列的同步位点,采取“客户端存储位点的去中心化“方案,实现”下行消息的推拉“结合。

通过队列位点syncId进行比对,如果服务端消息队列syncId-客户端队列syncId=1,表示云端消息无空洞,否则携带客户端的队列和对应的syncId到云端重新同步区间数据,实现最终一致性。

传统的IM产品:腾讯QQ、腾讯微信、网易云通讯、抖音IM、钉钉IM、脉脉IM、支付宝IM。

PS:市面上APP80%都具备IM聊天能力,均采取写扩散简单模式进行云端消息同步。

4.3 “读扩散”、“写扩散”技术方案对比

4.3.1)写扩散技术:

优点:

  • 1)整体架构简洁,方案简单,维护用户同步队列实现数据同步机制;
  • 2)无论是单聊还是群聊等会话消息,写入用户维度同步队列,集中获取同步数据;
  • 3)推和拉情况下,存储模型和数据处理简单,且天然支持个性化数据。

缺点:

  • 1)群会话消息,天然存在1:N写入扩散比,存储压力N倍压力,在线用户收到消息延迟增大;
  • 2)多个群内消息队列混合在同步队列,无优先级处理能力,无法针对互动群等做隔离。

4.3.2)读扩散技术:

优点:

  • 1)降低写扩散N倍的DB存储压力,减少下行在线用户端到端扩散的RT时间;
  • 2)提升消息上行集群整体的吞吐量,用户体验更流畅;
  • 3)端到端实现会话级别的同步优先级队列,实现差异化服务。

缺点:

  • 1)整体架构偏复杂,需要维护每个动态会话消息同步队列,端侧需要实时感知新增的动态同步队列;
  • 2)客户端冷启动需要分散读取多个会话消息同步队列数据,对于存储会带来读QPS压力。

4.4 读写扩散混合模式

核心在于架构的演进推进“读写扩散混合模式“落地,结合两者的优点进行云端一体化数据同步技术,覆盖几千万互动群用户,保证整体峰值上行消息以及用户在群内端到端延迟体验,做到一条上行消息500ms以内到达群内其他用户端侧,让整体用户体验提升明显,群内强互动成为可能。

5、电商直播互动中的消息架构实践

5.1 技术挑战

电商直播呈现大直播若干个(大于30W同时在线)、中直播间几百个、小直播几万个这样分布,尤其是晚会和主播带来的热点直播间效应,对系统整体的IM消息架构存在热点带来严重挑战。

热点问题的产生需要从不确定性的流量来源说起。

直播间人员规模天然和群聊不一样(单个群<=500人),一个直播间可以突破40万-200万之间设备同时在线。

直播间在另一个层面是“特殊的群”,群维护了群和群成员强关系,直播间维护直播和设备之间的订阅弱关系,在扩散维度群按照500人进行分库分表切片模式分发下行消息,直播间需要以直播间几十万设备作为分段切片进行分发。同时直播间的指令消息如果不加以干预,会形成超大的流量热点和扩散问题。那么针对这个问题如何应对?

直播间互动全链路和核心处理节点简易时序图如下:

 

即:观众互动消息 -> 网关接入 -> 应用系统Buffer(秒级直播间维度消息) -> 编码、合并、批量消息流 -> 直播间维度设备扩散 -> 设备长连通道推送 -> 设备接收 -> 解码消息 -> 业务处理。

5.2 应对手段

5.2.1)充分利用直播间在线人数:

针对大直播间和小直播间区分对待,充分利用在线人数这个关键性指标。

譬如小直播间不做buffer队列处理(所谓buffer,就是维护topic维度的缓冲队列),支持N秒或消息条数的异步flush机制,实现削峰过程。

其中针对“可靠消息”进行持久化缓存存储,如果当前消息推送失败,重试3次或者下一条消息再次携带失败的可靠消息,整体按照推拉结合的方式,端侧做重复消息去重控制。

5.2.2)用户进出房间关系维护:

从用户第一次进直播间,发起订阅请求,最终通过大小直播间分片进行路由到指定的直播间,针对特殊大直播间提前做好集群分片。

或者通过每天的离线数据分析大直播间的账号,主播开播创建直播间的时候,提前做好分片确定性,在脉冲绑定关系的时候,流量分散到N台订阅集群进行绑定关系建立。

5.2.3)流控策略考虑:

流控不等于一刀切,而是针对不同的subType指令进行控制。

针对可靠消息(红包、优惠、宝贝卡片)等进行持久化存储,利用多次消息下推携带机制,同时兼顾端侧拉取机制,保证消息最终一致性且在3秒以内到达端侧。

5.2.4)一致性hash问题-热点直播间:

一致性Hash的架构必然存在热点问题,如果在直播间进行分散架构,必然存在指令风暴问题。基于此,需要进行Hash热点二次打散处理。

针对这样的热点问题技术上是可行的,热点问题散列到多台IP机器上进行流量承接,另外需要考虑直播间维度的统计数据分布式合并等问题,需要用到分布式锁并发写入统计数据,且直播维度数据合并计算,类似JDKStriped64原理。

6、“群聊”和“直播互动”的消息架构差异思考

因为早期两套系统各自演进应对不同的流量和产品需求,用户规模化和产品要求带来的差异化架构。

对比“群聊”和“直播间互动”两类互动场景,群聊基于消息、会话、会话视图以及附加消息存储和消息漫游能力进行整体设计。而对于直播间来说,围绕直播间大规模实时互动进行抽象设计,充分实现buffer/批量/订阅关系切片等机制。

对于关系来说:群关系是强关系,需要用户确认加群,才可以进群、退群、查看群好友等。对于直播间来说是弱关系,用户进直播、退出直播都是自动完成关系建立和取消,当然用户可以后续进入回放直播间。

因此:在功能上和模型设计上需要进一步思考,尤其现有回放直播间需要一套录制/回放指令机制,保存互动指令等关键性指令数据,而这点在消息IM场景完全支持了,包括用户可以漫游历史消息等。

技术的发展不会一尘不变,针对合适的场景进行差异化架构和设计才是最重要的,同样在应对不确定性流量这个场景下,解决问题的方式是不完全相同的,这个过程需要反复迭代和优化,围绕端到端用户体验这个核心目标进行技术演进才是最重要的价值选择和方向判断。

7、不确定性流量的消息QoS思考

不确定性的流量如何转为确定性流量,是技术必须要解决的“确定性”问题。

尤其面对流量需要确定性进行分解,分优先级保障不同的消息QoS能力是“高可用架构”永恒不变的主题,就像应用系统的限流,需要分场景进行流控一样。

基于这样的思考推演,QoS分级机制来承诺消息服务SLA,最终才可以做到隔离/优先级/差异化处理,完成整体的消息顺滑体验。

 

8、写在最后

面对不确定性的流量,需要进行流量再细分以及面向不同的场景采取不同的处理方案去应对,惯用的手段是指令合并处理、链路隔离和共享、租户存储隔离、流量打标机制区分场景来源等,以及有相对确定性的流量大脑进行观测,在峰值流量来临之前,需要具备流量感知和预警机制,做好流量的优先级划分,应急预案是快速失败限流还是慢速等待消费以及优先级控制等机制。

同时在系统层面,需要做到水平扩展能力,也就是能否通过弹性扩容的方式应对高流量的峰值,另外需要做到整体全链路合理的架构设计,避免“写入放大”以及“读取放大”的单点问题产生,需要针对入口流量和出口流量进行比对,是否可以做到上下游1:1的情况下,尽可能地避免单点瓶颈带来集群瓶颈乃至整体不可用。

“高可用架构“是技术人员永恒不变的主题之一,随着用户规模增长以及集中流量爆发的情形下,更需要敏锐地找到全链路单点问题,提前预判定义出面临的问题。然后给出合理的优化方案,最终灰度切流以及全链路压测验证保证整体方案有序推进,尤其面对的在线系统优化,好比开着飞机换轮胎一样。具备优化效果数据和监控是衡量每一步的预期收益,只有这样才可以做好“架构演进”,才可以持续交付更好的用户产品体验,赢得用户的喜爱,以及互动效果和产品流畅性才可以得到用户满意度提升。架构演进是个动态化的过程,需要持续投入和改进,推动全链路整体落地。

附录:更多相关资料

[1] 有关阿里巴巴的文章分享:

阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处

现代IM系统中聊天消息的同步和存储方案探讨

阿里技术分享:深度揭秘阿里数据库技术方案的10年变迁史

阿里技术分享:阿里自研金融级数据库OceanBase的艰辛成长之路

来自阿里OpenIM:打造安全可靠即时通讯服务的技术实践分享

钉钉——基于IM技术的新一代企业OA平台的技术挑战(视频+PPT) [附件下载]

阿里技术结晶:《阿里巴巴Java开发手册(规约)-华山版》[附件下载]

重磅发布:《阿里巴巴Android开发手册(规约)》[附件下载]

作者谈《阿里巴巴Java开发手册(规约)》背后的故事

《阿里巴巴Android开发手册(规约)》背后的故事

干了这碗鸡汤:从理发店小弟到阿里P10技术大牛

揭秘阿里、腾讯、华为、百度的职级和薪酬体系

淘宝技术分享:手淘亿级移动端接入层网关的技术演进之路

难得干货,揭秘支付宝的2维码扫码技术优化实践之路

淘宝直播技术干货:高清、低延时的实时视频直播技术解密

阿里技术分享:电商IM消息平台,在群聊、直播场景下的技术实践

[2] 有关IM架构设计的文章:

浅谈IM系统的架构设计

简述移动端IM开发的那些坑:架构设计、通信协议和客户端

一套海量在线用户的移动端IM架构设计实践分享(含详细图文)

一套原创分布式即时通讯(IM)系统理论架构方案

从零到卓越:京东客服即时通讯系统的技术架构演进历程

蘑菇街即时通讯/IM服务器开发之架构选择

腾讯QQ1.4亿在线用户的技术挑战和架构演进之路PPT

微信后台基于时间序的海量数据冷热分级架构设计实践

微信技术总监谈架构:微信之道——大道至简(演讲全文)

如何解读《微信技术总监谈架构:微信之道——大道至简》

快速裂变:见证微信强大后台架构从0到1的演进历程(一)

17年的实践:腾讯海量产品的技术方法论

移动端IM中大规模群消息的推送如何保证效率、实时性?

现代IM系统中聊天消息的同步和存储方案探讨

IM开发基础知识补课(二):如何设计大量图片文件的服务端存储架构?

IM开发基础知识补课(三):快速理解服务端数据库读写分离原理及实践建议

IM开发基础知识补课(四):正确理解HTTP短连接中的Cookie、Session和Token

WhatsApp技术实践分享:32人工程团队创造的技术神话

微信朋友圈千亿访问量背后的技术挑战和实践总结

王者荣耀2亿用户量的背后:产品定位、技术架构、网络方案等

IM系统的MQ消息中间件选型:Kafka还是RabbitMQ?

腾讯资深架构师干货总结:一文读懂大型分布式系统设计的方方面面

以微博类应用场景为例,总结海量社交系统的架构设计步骤

快速理解高性能HTTP服务端的负载均衡技术原理

子弹短信光鲜的背后:网易云信首席架构师分享亿级IM平台的技术实践

知乎技术分享:从单机到2000万QPS并发的Redis高性能缓存实践之路

IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列

微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

微信技术分享:微信的海量IM聊天消息序列号生成实践(容灾方案篇)

新手入门:零基础理解大型分布式架构的演进历史、技术原理、最佳实践

一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践

阿里技术分享:深度揭秘阿里数据库技术方案的10年变迁史

阿里技术分享:阿里自研金融级数据库OceanBase的艰辛成长之路

社交软件红包技术解密(一):全面解密QQ红包技术方案——架构、技术实现等

社交软件红包技术解密(二):解密微信摇一摇红包从0到1的技术演进

社交软件红包技术解密(三):微信摇一摇红包雨背后的技术细节

社交软件红包技术解密(四):微信红包系统是如何应对高并发的

社交软件红包技术解密(五):微信红包系统是如何实现高可用性的

社交软件红包技术解密(六):微信红包系统的存储层架构演进实践

社交软件红包技术解密(七):支付宝红包的海量高并发技术实践

社交软件红包技术解密(八):全面解密微博红包技术方案

社交软件红包技术解密(九):谈谈手Q红包的功能逻辑、容灾、运维、架构等

社交软件红包技术解密(十):手Q客户端针对2020年春节红包的技术实践

社交软件红包技术解密(十一):解密微信红包随机算法(含代码实现)

即时通讯新手入门:一文读懂什么是Nginx?它能否实现IM的负载均衡?

即时通讯新手入门:快速理解RPC技术——基本概念、原理和用途

多维度对比5款主流分布式MQ消息队列,妈妈再也不担心我的技术选型了

从游击队到正规军(一):马蜂窝旅游网的IM系统架构演进之路

从游击队到正规军(二):马蜂窝旅游网的IM客户端架构演进和实践总结

从游击队到正规军(三):基于Go的马蜂窝旅游网分布式IM系统技术实践

IM开发基础知识补课(六):数据库用NoSQL还是SQL?读这篇就够了!

瓜子IM智能客服系统的数据架构设计(整理自现场演讲,有配套PPT)

阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处

微信后台基于时间序的新一代海量数据存储架构的设计实践

IM开发基础知识补课(九):想开发IM集群?先搞懂什么是RPC!

阿里技术分享:电商IM消息平台,在群聊、直播场景下的技术实践

>> 更多同类文章 ……

本文已同步发布于“即时通讯技术圈”公众号:

▲ 本文在公众号上的链接是:点此进入,原文链接是:http://www.52im.net/thread-3252-1-1.html

posted @ 2020-12-18 22:04 Jack Jiang 阅读(216) | 评论 (0)编辑 收藏

     摘要: 本文作者张彦飞,原题“图解Linux网络包接收过程”,内容有少许改动。1、引言因为要对百万、千万、甚至是过亿的用户提供各种网络服务,所以在一线互联网企业里面试和晋升后端开发同学的其中一个重点要求就是要能支撑高并发,要理解性能开销,会进行性能优化。而很多时候,如果你对网络底层的理解不深的话,遇到很多线上性能瓶颈你会觉得狗拿刺猬,无从下手。这篇文章将用图解的方式,从操作系统这一...  阅读全文

posted @ 2020-12-09 15:13 Jack Jiang 阅读(237) | 评论 (0)编辑 收藏

     摘要: 本文由朱益盛、杨晖、傅啸分享,来自IBM Developer社区,原题“使用 Java 开发兼容 IPv6 的网络应用程序”,本次收录时有改动。1、引言前几天,有个群友跟我讨论用 MobileIMSDK 写的IM服务端想支持IPv6的问题。因为众所周之的原因,IPv4早就不够用,现在国内从国家层面都在大力推广IPv6的普及,所以包括事业单位、国企在内,现在搞信息化...  阅读全文

posted @ 2020-12-07 19:31 Jack Jiang 阅读(521) | 评论 (0)编辑 收藏

     摘要: 本文由淘宝直播音视频算法团队原创分享,原题“5G时代|淘宝直播高画质低延时技术探索”,收录时有改动。1、引言目前,5G技术应用正在逐步推进,相比目前广泛使用的4G, 它具有更高的速率,更大的容量,同时延迟更低, 可靠性更高。在5G时代,得益于网络带宽的提升,视频未来将成为主流的传播媒介。越来越多的业务和应用将视频化、直播化。 大量互动的内容将通过5G以低延时的方式以视频的形...  阅读全文

posted @ 2020-11-26 15:41 Jack Jiang 阅读(288) | 评论 (0)编辑 收藏

     摘要: 原作者江成军,原题“还在被Java NIO虐?该试试Netty了”,收录时有修订和改动。1、阅读对象本文适合对Netty一无所知的Java NIO网络编程新手阅读,为了做到这一点,内容从最基本介绍到开发环境的配置,再到第一个Demo代码的编写,事无巨细都用详细的图文进行了说明。所以本文这对于新手来说帮助很大,但对于老司机来说,就没有必要了。老司机请绕道哦。PS:是的,用Ja...  阅读全文

posted @ 2020-11-18 14:35 Jack Jiang 阅读(472) | 评论 (0)编辑 收藏

     摘要: 本文作者Ahab,原题“视频相关的理论知识与基础概念”,收录时有修订和改动。1、引言随着移动互联网的普及,实时音视频技术已经在越来越多的场景下发挥重要作用,已经不再局限于IM中的实时视频聊天、实时视频会议这种功能,在远程医疗、远程教育、智能家居等等场景也司空见惯。虽然实时音视频技术的应用越来越普及,但对于程序员来说,这方面的技术门槛仍然存在(准备地说是仍然很高),想要在短时...  阅读全文

posted @ 2020-11-12 15:45 Jack Jiang 阅读(209) | 评论 (0)编辑 收藏

本文引用了沈剑《如何保证IM实时消息的“时序性”与“一致性”?》一文的图片和内容(由于太懒,图没重新画),原文链接在文末。

1、引言

本文接上篇《零基础IM开发入门(三):什么是IM系统的可靠性?》,讲解IM系统中消息时序的一致性问题。

所谓的一致性,在IM中通常指的是消息时序的一致性,那就是:

  • 1)聊天消息的上下文连续性;
  • 2)聊天消息的绝对时间序。

再具体一点,IM消息的一致性体现在:

  • 1)单聊时:要保证发送方发出聊天消息的顺序与接收方看到的顺序一致;
  • 2)群聊时:要保证所有群员看到的聊天消息,与发送者发出消息时的绝对时间序是一致的。

IM系统中消息时序的一致性问题是个看似简单,实则非常有难度的技术热点话题之一,本文尽量以通俗简显的文字为你讲解IM消息时序一致性问题的产品意义、发生原因、解决思路等

  • 学习交流:

- 即时通讯/推送技术开发交流5群:215477170 [推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK

(本文同步发布于:http://www.52im.net/thread-3189-1-1.html

2、系列文章

零基础IM开发入门(一):什么是IM系统?

零基础IM开发入门(二):什么是IM系统的实时性?

零基础IM开发入门(三):什么是IM系统的可靠性?

零基础IM开发入门(四):什么是IM系统的消息时序一致性?》(* 本文

《零基础IM开发入门(五):什么是IM系统的安全性? (稍后发布)》

《零基础IM开发入门(六):什么是IM系统的的心跳机制? (稍后发布)》

《零基础IM开发入门(七):如何理解并实现IM系统消息未读数? (稍后发布)》

《零基础IM开发入门(八):如何理解并实现IM系统的多端消息漫游? (稍后发布)》

3、消息时序的一致性,对于IM的意义

现如今,由于移动互联网的普及,现代人的实际社交关系,几乎完全是靠IM这种即时通讯社交工具所组织起来的,IM这种工具的重要性不言而喻。

IM在现代人的生活中,越来越重要,但也越来平常。现在想联系一个人,第一时间想到的不是打个电话,而是发个“微信”或“QQ”。是的,IM这玩意承载的意义越来越多。

消息时序的一致性问题,对于IM的意义,毫无疑问带来的不只是简简单单的所谓用户体验问题。我们来看看例子。

假设:你跟女神的表白正进入到关键阶段,聊着聊着就因为这烂IM,导致聊天消息前言不搭后语,此刻1000公里外你的女神真一脸蒙逼的盯着手机看你的“醉话”,后果是多么严重——这半年来的“舔狗”生活、忍辱负重,算是白白被程序员这群“格子衫”、“地中海”们给祸害了。

再往严重了说,就因为这烂IM,让你失去了这难得的借助女神优良基因,改造家族后代颜值的绝佳机会,无不让人痛心疾首。。。

上面这个例子,说的还只是单聊,如果是群聊,则问题可能还会被无限放大:试想一个技术交流群,正在激烈的争吵着“php是世界最好语言”这种话题的时候,忽然就想砸手机了,不是因为吵的太凶,而因为消息顺序全乱完全没法看,已经严重影响键盘侠们积极发表个人意见了。

4、凭什么说保证消息时序的一致性很困难?

4.1 基本认知

在普通IM用户的眼里,消息无非是从一台手机传递到另一台手机而已,保证时序有何困难?

是的,普通用户这么认为,从技术上讲,他只是单纯的将IM消息的收发过程理解为单线程的工作模式而已。

实际上,在IM这种高性能场景下,服务端为了追求高吞吐、高并发,用到了多线程、异步IO等等技术。

在这种情况下,“高并发”与“顺序”对于IM服务端来说,本来就是矛盾的,这就有点鱼与熊掌的味道了(两者很难兼得)。

所以,要实现IM场景下的消息时序一致性,需要做出权衡,而且要考虑的技术维度相当多。这就导致具体技术实施起来没有固定的套路,而由于开发者技术能力的参差不齐,也就使得很多IM系统在实际的效果上会有较大问题,对于用户而言也将直接在产品体验上反应出来。

下面将具体说明技术难点所在。

4.2 没有全局时钟

如上图所示,一个真正堪用的生产系统,显示不可能所有服务都跑在一台服务器上,分布式环境是肯定的。

那么:在分布式环境下,客户端+服务端后台的各种后台服务,都各自分布在不同的机器上,机器之间都是使用的本地时钟,没有一个所谓的“全局时钟”(也没办法做到真正的全局时钟),那么所谓的消息时序也就没有真正意义上的时序基准点。所以消息时序问题显然不是“本地时间”可以完全决定的。

4.3 多发送方问题

服务端分布式的情况下,不能用“本地时间”来保证时序性,那么能否用接收方本地时间表示时序呢?

遗憾的是,由于多个客户端的存在(比如群聊时),即使是一台服务器的本地时间,也无法表示“绝对时序”。

如上图所示:绝对时序上,APP1先发出msg1,APP2后发出msg2,都发往服务器web1,网络传输是不能保证msg1一定先于msg2到达的,所以即使以一台服务器web1的时间为准,也不能精准描述msg1与msg2的绝对时序。

4.4 多接收方问题

多发送方不能保证时序,假设只有一个发送方,能否用发送方的本地时间表示时序呢?遗憾的是,由于多个接收方的存在,无法用发送方的本地时间,表示“绝对时序”。

如上图,绝对时序上,web1先发出msg1,后发出msg2,由于网络传输及多接收方的存在,无法保证msg1先被接收到先被处理,故也无法保证msg1与msg2的处理时序。

4.5 网络传输与多线程问题

既然多发送方与多接收方都难以保证绝对时序,那么假设只有单一的发送方与单一的接收方,能否保证消息的绝对时序一致性呢?

结论是悲观的,由于网络传输与多线程的存在,这仍然不行。

如上图所示,web1先发出msg1、后发出msg2,即使msg1先到达(网络传输其实还不能保证msg1先到达),由于多线程的存在,也不能保证msg1先被处理完。

5、如何保证绝对的消息时序一致性?

通过上一章内容的总结,我们已经对IM中消息时序一致性问题所产生的缘由,有了较为深刻的认识。

从纯技术的角度来说,假设:

  • 1)只有一个发送方;
  • 2)一个接收方;
  • 3)上下游连接只有一条socket连接;
  • 4)通过阻塞的方式通讯。

这样的情况下,难道不能保证先发出的消息被先处理,进而被先展示给消息的接收者吗?

是的,可以!

但实际生产情况下不太可能出现这种IM系统,必竟单发送方、单接收方、单socket连接、阻塞方式,这样的IM一旦做出来,产品经理会立马死给你看。。。

6、实用的优化思路

6.1 一对一单聊的消息一致性保证思路

假设两人一对一聊天,发送方A依次发出了msg1、msg2、msg3三条消息给接收方B,这三条消息该怎么保证显示时序的一致性(发送与显示的顺序一致)?

我们知道,发送方A依次发出的msg1、msg2、msg3三条消息,到底服务端后,再由服务端中转发出时,这个顺序由于多线程的网络的问题,是有可能乱序的。

那么结果就可能是这样: 

如上图所示,会出现与发出时的消息时序不一致问题(收到的消息顺序是:msg3、msg1、msg2)。

不过,实际上一对一聊天的两个人,并不需要全局消息时序的一致(因为聊天只在两人的同一会话在发生),只需要对于同一个发送方A,发给B的消息时序一致就行了。

常见优化方案,在A往B发出的消息中,加上发送方A本地的一个绝对时序(比如本机时间戳),来表示接收方B的展现时序。

那么当接收方B收到消息后,即使极端情况下消息可能存在乱序到达,但因为这个乱序的时间差对于普通用户来说体感是很短的,在UI展现层按照消息中自带的绝对时序排个序后再显示,用户其实是没有太多感知的。

6.2 多对多群聊的消息一致性保证思路

假设N个群友在一个IM群里聊天,应该怎样保证所有群员收到消息的显示时序一致性呢?

首先:不能像一对聊天那样利用发送方的绝对时序来保证消息顺序,因为群聊发送方不单点,时间也不一致。

或许:我们可以利用服务器的单点做序列化。

如上图所示,此时IM群聊的发送流程为:

  • 1)sender1发出msg1,sender2发出msg2;
  • 2)msg1和msg2经过接入集群,服务集群;
  • 3)service层到底层拿一个唯一seq,来确定接收方展示时序;
  • 4)service拿到msg2的seq是20,msg1的seq是30;
  • 5)通过投递服务讲消息给多个群友,群友即使接收到msg1和msg2的时间不同,但可以统一按照seq来展现。

这个方法:

  • 1)优点是:能实现所有群友的消息展示时序相同;
  • 2)缺点是:这个生成全局递增序列号的服务很容易成为系统瓶颈。

还有没有进一步的优化方法呢?

从技术角度看:群消息其实也不用保证全局消息序列有序,而只要保证一个群内的消息有序即可,这样的话,“消息id序列化”就成了一个很好的思路。

上图这个方案中,service层不再需要去一个统一的后端拿全局seq(序列号),而是在service连接池层面做细小的改造,保证一个群的消息落在同一个service上,这个service就可以用本地seq来序列化同一个群的所有消息,保证所有群友看到消息的时序是相同的。

关于IM的系统架构下使用怎么样实现消息序列化,或者说全局消息ID的生成方案,这又是另一个很热门的技术话题。

有兴趣,可以深入阅读下面这个系列:

IM消息ID技术专题(一):微信的海量IM聊天消息序列号生成实践(算法原理篇)

IM消息ID技术专题(二):微信的海量IM聊天消息序列号生成实践(容灾方案篇)

IM消息ID技术专题(三):解密融云IM产品的聊天消息ID生成策略

IM消息ID技术专题(四):深度解密美团的分布式ID生成算法

IM消息ID技术专题(五):开源分布式ID生成器UidGenerator的技术实现

IM消息ID技术专题(六):深度解密滴滴的高性能ID生成器(Tinyid)

这个系列中,尤其微信的趋势递增ID生成思路(注意:趋势递增不是严格递增,趋势递增意味着中问有ID被跳过也没事),对于分布式IM的消息ID来说是非常切实可行的。

是的,对于IM系统来说,绝对意义上的时序很难保证,但通过服务端生成的单调递增消息ID的方式,利用递增ID来保证时序性,也是一个很可性的方案。

7、小结一下

IM系统架构下,消息的绝对时序是很困难的,原因多种多样,比如:没有全局时钟、多发送方、多接收方、多线程、网络传输不确定性等。

一对一单聊时,其实只需要保证发出的时序与接收的时序一致,就基本能让用户感觉不到乱序了。

多对多的群聊情况下,保证同一群内的所有接收方消息时序一致,也就能让用户感觉不到乱序了,方法有两种,一种单点绝对时序,另一种实现消息id的序列化(也就是实现一种全局递增消息ID)。

8、参考资料

[1] 如何保证IM实时消息的“时序性”与“一致性”?,作者:沈剑

[2] 一个低成本确保IM消息时序的方法探讨,作者:封宇

附录:更多IM开发热门技术点

移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”

移动端IM开发者必读(二):史上最全移动弱网络优化方法总结

现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障

移动端IM中大规模群消息的推送如何保证效率、实时性?

移动端IM开发需要面对的技术问题

开发IM是自己设计协议用字节流好还是字符流好?

请问有人知道语音留言聊天的主流实现方式吗?

如何保证IM实时消息的“时序性”与“一致性”?

一个低成本确保IM消息时序的方法探讨

IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?

IM群聊消息如此复杂,如何保证不丢不重?

谈谈移动端 IM 开发中登录请求的优化

移动端IM登录时拉取数据如何作到省流量?

浅谈移动端IM的多点登录和消息漫游原理

完全自已开发的IM该如何设计“失败重试”机制?

微信对网络影响的技术试验及分析(论文全文)

IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列

微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

IM开发基础知识补课(六):数据库用NoSQL还是SQL?读这篇就够了!

IM里“附近的人”功能实现原理是什么?如何高效率地实现它?

IM的扫码登录功能如何实现?一文搞懂主流应用的扫码登录技术原理

IM开发宝典:史上最全,微信各种功能参数和逻辑规则资料汇总

本文已同步发布于“即时通讯技术圈”公众号。

▲ 本文在公众号上的链接是:点此进入,原文链接是:http://www.52im.net/thread-3189-1-1.html

posted @ 2020-11-04 14:31 Jack Jiang 阅读(182) | 评论 (0)编辑 收藏

本文编写时引用了“聊聊IM系统的即时性和可靠性”一文的部分内容和图片,感谢原作者。

1、引言

上一篇《零基础IM开发入门(二):什么是IM系统的实时性?》讲到了IM系统的“立足”之本——“实时性”这个技术特征,本篇主要讲解IM系统中的“可靠性”这个话题,内容尽量做到只讲原理不深入展开,避开深层次的技术性探讨,确保通俗易懂。


阅读对象:本系列文章主要阅读对象为零IM基础的开发者或产品经理,目标是告诉你“IM系统是什么?”,尽量不深入探讨具体的技术实现,确保通俗易懂,老少皆宜。

如您想从技术维度系统学习IM技术并着手自已的IM开发(即解决“IM系统要怎么做?”这个疑问),请从此文开始:《新手入门一篇就够:从零开发移动端IM》。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170[推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK

(本文同步发布于:http://www.52im.net/thread-3182-1-1.html

2、系列文章

零基础IM开发入门(一):什么是IM系统?

零基础IM开发入门(二):什么是IM系统的实时性?

零基础IM开发入门(三):什么是IM系统的可靠性?》(* 本文

零基础IM开发入门(四):什么是IM系统的消息时序一致性?

《零基础IM开发入门(五):什么是IM系统的安全性? (稍后发布)》

《零基础IM开发入门(六):什么是IM系统的的心跳机制? (稍后发布)》

《零基础IM开发入门(七):如何理解并实现IM系统消息未读数? (稍后发布)》

《零基础IM开发入门(八):如何理解并实现IM系统的多端消息漫游? (稍后发布)》

3、正文概述

一般来说,IM系统的消息“可靠性”,通常就是指聊天消息投递的可靠性(准确的说,这个“消息”是广义的,因为还存用户看不见的各种指令,为了通俗,统称“消息”)。

从用户行为来讲,消息“可靠性”应该分为两种类型:

  • 1)在线消息的可靠性:即发送消息时,接收方当前处于“在线”状态;
  • 2)离线消息的可靠性:即发送消息时,接收方当前处于“离线”状态。

从具体的技术表现来讲,消息“可靠性”包含两层含义:

  • 1)消息不丢:这很直白,发出去的消息不能像进了黑洞一样,一脸懵逼可不行;
  • 2)消息不重:这是丢消息的反面,消息重复了也不能容忍。

对于“消息不丢”这个特征来说,细化下来,它又包含两重含义:

  • 1)已明确被对方收到;
  • 2)已明确未被对方收到。

是的,对于第1)重含义好理解,第2)重含义的意思是:当对方没有成功收到时,你的im系统也必须要感知到,否则,它同样属于被“丢”范畴。

总之,一个成型的im系统,必须包含这两种消息“可靠性”逻辑,才能堪用,缺一不可。

消息的可靠性(不丢失、不重复)无疑是IM系统的重要指标,也是IM系统实现中的难点之一。本文以下文字,将从在线消息的可靠性和离线消息的可靠性进行讨论。

4、典型的在线消息收发流程

先看下面这张典型的im消息收发流程: 

是的,这是一个典型的服务端中转型IM架构。

所谓“服务端中转型IM架构”是指:一条消息从客户端A发出后,需要先经过 IM 服务器来进行中转,然后再由 IM 服务器推送给客户端B,这种模式也是目前最常见的 IM 系统的消息分发架构。

你可能会说,IM不可以是P2P模式的吗?是的,目前来说主流IM基本都是服务器中转这种方式,P2P模式在IM系统中用的很少。

原因是以下两个很明显的弊端:

  • 1)P2P模式下,IM运营者很容易被用户架空(无法监管到用户行为,用户涉黄了怕不怕?);
  • 2)P2P模式下,群聊这种业务形态,很难实现(我要在千人群中发消息给,不可能我自已来分发1000次吧)。

话题有点跑偏,我们回到正题:在上面这张图里,客户A发送消息到服务端、服务端中转消息给客户B,假设这两条数据链接中使用的通信协议是TCP,你认为在TCP所谓可靠传输协议加持下,真的能保证IM聊天消息的可靠性吗?

答案是否定的。我们继续看下节。

5、TCP并不能保证在线消息的“可靠性”

接上节,在一个典型的服务端中转型IM架构中,即使使用“可靠的传输协议”TCP,也不能保证聊天消息的可靠性。为什么这么说?

要回答这个问题,网上的很多文章,都会从服务端的角度举例:比如消息发送时操作系统崩溃、网络闪断、存储故障等等,总之很抽象,不太容易理解。

这次我们从客户端角度来理解,为什么使用了可靠传输协议TCP的情况下IM聊天消息仍然不可靠的问题。

具体来说:如何确保 IM 消息的可靠性是个相对复杂的话题,从客户端发送数据到服务器,再从服务器送达目标客户端,最终在 UI 成功展示,其间涉及的环节很多,这里只取其中一环「接收端如何确保消息不丢失」来探讨,粗略聊下我接触过的两种设计思路。

说到可靠送达:第一反应会联想到 TCP 的可靠性。数据的可靠送达是个通用性的问题,无论是网络二进制流数据,还是上层的业务数据,都有可靠性保障问题,TCP 作为网络基础设施协议,其可靠性设计的可靠性是毋庸置疑的,我们就从 TCP 的可靠性说起。

在 TCP 这一层:所有 Sender 发送的数据,每一个 byte 都有标号(Sequence Number),每个 byte 在抵达接收端之后都会被接收端返回一个确认信息(Ack Number), 二者关系为 Ack = Seq + 1。简单来说,如果 Sender 发送一个 Seq = 1,长度为 100 bytes 的包,那么 receiver 会返回一个 Ack = 101 的包,如果 Sender 收到了这个Ack 包,说明数据确实被 Receiver 收到了,否则 Sender 会采取某种策略重发上面的包。

第一个问题是:既然 TCP 本身是具备可靠性的,为什么还会出现消息接收端(Receiver)丢失消息的情况?

看下图一目了然:

▲ 上图引用自《从客户端的角度来谈谈移动端IM的消息可靠性和送达机制

一句话总结上图的含义:网络层的可靠性不等同于业务层的可靠性。

数据可靠抵达网络层之后,还需要一层层往上移交处理,可能的处理有:

  • 1)安全性校验;
  • 2)binary 解析;
  • 3)model 创建;
  • 4)写 db;
  • 5)存入 cache;
  • 6)UI 展示;
  • 7)以及一些边界问题:比如断网、用户突然退出登陆、磁盘已满、内存溢出、app奔溃、突然关机等等。

项目的功能特性越多,网络层往上的处理出错的可能性就越大。

举个最简单的场景为例子:消息可靠抵达网络层之后,写 db 之前 IM APP 崩溃(不稀奇,是 App 都有崩溃的可能),虽然数据在网络层可靠抵达了,但没存进 db,下次用户打开 App 消息自然就丢失了,如果不在业务层再增加可靠性保障(比如:后面要提到的网络层面的消息重发保障),那么意味着这条消息对于接收端来说就永远丢失了,也就自然不存在“可靠性”了。

从客户端角度理解IM的可能性以及解决办法,可以详细阅读:从客户端的角度来谈谈移动端IM的消息可靠性和送达机制》,本节引用的是该文中“4、TCP协议的可靠性之外还会出现消息丢失?”一节的文字。

6、为在线消息增加“可靠性”保障

那么怎样在应用层增加可靠性保障呢?

有一个现成的机制可供我们借鉴:TCP协议的超时、重传、确认机制。

具体来说就是:

  • 1)在应用层构造一种ACK消息,当接收方正确处理完消息后,向发送方发送ACK;
  • 2)假如发送方在超时时间内没有收到ACK,则认为消息发送失败,需要进行重传或其他处理。

增加了确认机制的消息收发过程如下: 

我们可以把整个过程分为两个阶段。

阶段1:clientA -> server

  • 1-1:clientA向server发送消息(msg-Req);
  • 1-2:server收取消息,回复ACK(msg-Ack)给clientA;
  • 1-3:一旦clientA收到ACK即可认为消息已成功投递,第一阶段结束。

无论msg-A或ack-A丢失,clientA均无法在超时时间内收到ACK,此时可以提示用户发送失败,手动进行重发。

阶段2:server -> clientB

  • 2-1:server向clientB发送消息(Notify-Req);
  • 2-2:clientB收取消息,回复ACK(Notify-ACk)给server;
  • 2-3:server收到ACK之后将该消息标记为已发送,第二阶段结束。

无论msg-B或ack-B丢失,server均无法在超时时间内收到ACK,此时需要重发msg-B,直到clientB返回ACK为止。

关于IM聊天消息的可靠性保障问的深入讨论,可以详读:IM消息送达保证机制实现(一):保证在线实时消息的可靠投递》,该文会深入讨论这个话题。

7、典型的离线消息收发流程

说完在线消息的“可靠性”问题,我们该了解一下离线消息了。

7.1 离线消息的收发也存在“不可靠性”

下图是一张典型的IM离线消息流程图:

如上图所示,和在线消息收发流程类似。

离线消息收发流程也可划分为两个阶段:

阶段1:clientA -> server

  • 1-1:clientA向server发送消息(msg-Req) ;
  • 1-2:server发现clientB离线,将消息存入offline-DB。

阶段2:server -> clientB

  • 2-1:clientB上线后向server拉取离线消息(pull-Req) ;
  • 2-2:server从offline-DB检索相应的离线消息推送给clientB(pull-res),并从offline-DB中删除。

显然:离线消息收发过程同样存在消息丢失的可能性。

举例来说:假设pull-res没有成功送达clientB,而offline-DB中已删除,这部分离线消息就彻底丢失了。

7.2 离线消息的“可靠性”保障

与在线消息收发流程类似,我们同样需要在应用层增加可靠性保障机制。

下图是增加了可靠性保障后的离线消息收发流程: 

与初始的离线消息收发流程相比,上图增加了1-3、2-4、2-5步骤:

  • 1-3:server将消息存入offline-DB后,回复ACK(msg-Ack)给clientA,clientA收到ACK即可认为消息投递成功;
  • 2-4:clientB收到推送的离线消息,回复ACK(res-Ack)给server;
  • 2-5:server收到res-ACk后确定离线消息已被clientB成功收取,此时才能从offline-DB中删除。

当然,上述的保障机制,还存在性能优化空间。

当离线消息的量较大时:如果对每条消息都回复ACK,无疑会大大增加客户端与服务器的通信次数。这种情况我们通常使用批量ACK的方式,对多条消息仅回复一个ACK。在某此后IM的实现中是将所有的离线消息按会话进行分组,每组回复一个ACK,假如某个ACK丢失,则只需要重传该会话的所有离线消息。

有关离线消息的可靠性保障机制的详细讨论,可以详读:IM消息送达保证机制实现(二):保证离线消息的可靠投递》、《IM开发干货分享:如何优雅的实现大量离线消息的可靠投递》,这两篇文章可以给你更深入具体的答案。

8、聊天消息重复的问题

上面章节中,通过在应用层加入重传、确认机制后,我们确实是杜绝了消息丢失的可能性。

但由于重试机制的存在,我们会遇到一个新的问题:那就是同一条消息可能被重复发送。

举一个最简单的例子:假设client成功收到了server推送的消息,但其后续发送的ACK丢失了,那么server将会在超时后再次推送该消息,如果业务层不对重复消息进行处理,那么用户就会看到两条完全一样的消息。

消息去重的方式其实非常简单,一般是根据消息的唯一标志(id)进行过滤。

具体过程在服务端和客户端可能有所不同:

  • 1)客户端 :我们可以通过构造一个map来维护已接收消息的id,当收到id重复的消息时直接丢弃;
  • 2)服务端 :收到消息时根据id去数据库查询,若库中已存在则不进行处理,但仍然需要向客户端回复Ack(因为这条消息很可能来自用户的手动重发)。

关于消息的去重问题,在一对一聊天的情况下,逻辑并不复杂,但在群聊模式下,会将问题复杂化,有关群聊消息不丢和去重的详细讨论,可以深入阅读:《IM群聊消息如此复杂,如何保证不丢不重?》。

9、本文小结

保证消息的可靠性是IM系统设计中很重要的一环,能不能做到“消息不丢”、“消息不重”,对用户的体验影响极大。

所谓“可靠的传输协议”TCP也并不能保障消息在应用层的可靠性。

我们一般通过在应用层的ACK应答和重传机制,来实现IM消息的可靠性保障。但由此带来的消息重复问题,需要我们额外进行处理,最简单的方法就是通过消息ID进行幂等去重。

关于IM系统消息可靠性的理论基础,我们就探讨到这里,有疑问的读者,可以在本文末尾留意,欢迎积极讨论。

10、参考资料

[1] IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

[2] IM消息送达保证机制实现(二):保证离线消息的可靠投递

[3] IM开发干货分享:如何优雅的实现大量离线消息的可靠投递

[4] 从客户端的角度来谈谈移动端IM的消息可靠性和送达机制

[5] 聊聊IM系统的即时性和可靠性

[6] 学习笔记4——IM系统如何保证消息的可靠性

[7] IM群聊消息如此复杂,如何保证不丢不重?

附录:更多IM开发热门技术点

移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”

移动端IM开发者必读(二):史上最全移动弱网络优化方法总结

现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障

移动端IM中大规模群消息的推送如何保证效率、实时性?

移动端IM开发需要面对的技术问题

开发IM是自己设计协议用字节流好还是字符流好?

请问有人知道语音留言聊天的主流实现方式吗?

如何保证IM实时消息的“时序性”与“一致性”?

一个低成本确保IM消息时序的方法探讨

IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?

IM群聊消息如此复杂,如何保证不丢不重?

谈谈移动端 IM 开发中登录请求的优化

移动端IM登录时拉取数据如何作到省流量?

浅谈移动端IM的多点登录和消息漫游原理

完全自已开发的IM该如何设计“失败重试”机制?

微信对网络影响的技术试验及分析(论文全文)

IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列

微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

IM开发基础知识补课(六):数据库用NoSQL还是SQL?读这篇就够了!

IM里“附近的人”功能实现原理是什么?如何高效率地实现它?

IM的扫码登录功能如何实现?一文搞懂主流应用的扫码登录技术原理

IM消息ID技术专题(一):微信的海量IM聊天消息序列号生成实践(算法原理篇)

IM消息ID技术专题(二):微信的海量IM聊天消息序列号生成实践(容灾方案篇)

IM消息ID技术专题(三):解密融云IM产品的聊天消息ID生成策略

IM消息ID技术专题(四):深度解密美团的分布式ID生成算法

IM消息ID技术专题(五):开源分布式ID生成器UidGenerator的技术实现

IM消息ID技术专题(六):深度解密滴滴的高性能ID生成器(Tinyid)

IM开发宝典:史上最全,微信各种功能参数和逻辑规则资料汇总

本文已同步发布于“即时通讯技术圈”公众号。

▲ 本文在公众号上的链接是:点此进入,原文链接是:http://www.52im.net/thread-3182-1-1.html

posted @ 2020-10-29 14:09 Jack Jiang 阅读(169) | 评论 (0)编辑 收藏

     摘要: 本文原题“Node.js - 200 多行代码实现 Websocket 协议”,为了提升内容品质,有较大修订。1、引言最近正在研究 WebSocket 相关的知识,想着如何能自己实现 WebSocket 协议。到网上搜罗了一番资料后用 Node.js 实现了一个WebSocket协议服务器,倒也没有想象中那么复杂,除去注释语句和 console 语句后,大约 200 行代码...  阅读全文

posted @ 2020-10-21 14:41 Jack Jiang 阅读(266) | 评论 (0)编辑 收藏

     摘要: 本文原题“WebSocket:5分钟从入门到精通”,作者“程序猿小卡_casper”,原文链接见文末参考资料部分。本次收录时有改动。1、引言自从HTML5里的WebSocket出现后,彻底改变了以往Web端即时通讯技术的基础通道这个“痛点”(在此之前,开发者们不得不弄出了诸如:短轮询、长轮询、Comet、SSE等技术,可谓苦之...  阅读全文

posted @ 2020-10-14 14:40 Jack Jiang 阅读(383) | 评论 (0)编辑 收藏

     摘要: 本文由融云技术团队原创投稿,作者是融云WebRTC高级工程师苏道,转载请注明出处。1、引言在一个典型的IM应用里,使用实时音视频聊天功能时,视频首帧的显示,是一项很重要的用户体验指标。本文主要通过对WebRTC接收端的音视频处理过程分析,来了解和优化视频首帧的显示时间,并进行了总结和分享。(本文同步发布于:http://www.52im.net/thread-3169-1-1.html)2、什么是...  阅读全文

posted @ 2020-09-28 22:17 Jack Jiang 阅读(260) | 评论 (0)编辑 收藏

本文引用自“蚂蚁金服科技”公众号,原文由支付宝技术团队原创分享。 本次收录时有改动。

1、引言

最早接触2维码扫码功能,是在2011年,那会移动互联网正是起步阶段,大家都感觉智能手机可以更强大,但到底要做些什么功能,都是在探索和创新。2维码扫描功能就是这些创新功能之一。

当然,2维码扫描说到底还是图像识别,这种技术不是一般的公司能搞定的,所以大家用的最多的2维码扫描库就是ZXing。这个库,很多人应该非常熟悉,用过这个库的人,基本都记住了下面这个图片(ZXing的logo)。

▲ ZXing工程的logo

这个库的使用前题就是需要手机摄像头有自动对焦功能,那会手机成本还没现在这么低,所以自动对焦功能不是所有手机都具备,也就限制了2维码扫码功能在一些较低端的手机上的使用,同时也制约了扫码功能的普及。

后来的事情大家都知道了,微信这种社交IM越来越受欢迎,微信里可以用来扫码加好友的“扫一扫”功能,让2维码扫描功能几乎变成了IM软件的标配。

 

▲ 早期微信里的“扫一扫”功能

现在的微信,不仅可以扫2维友加好友,还可以扫码支付以及各种图像识别方面的功能,越做越丰富。2维码扫码功能从一个单一的图像识别技术,逐渐演变成了移动线联网的入口功能。

从去年开始,微信对2维码扫描功能进行了升级,不仅可以在UI上让用户知道被扫描2维码的中心点,还能同时识别最多3个2维码,相当强大。

 

▲ 现在的微信可以同时识别最多3个2维码(注意绿点)

如上图所示,原本大家都习以为常的2维码扫描功能,原来还可以做的这么友好。

正好看到支付宝分享的这篇2维码扫描优化文章,市面上真正分享这方面的技术的文章几乎没有,而2维码扫码加友作为IM中最常见的功能之一,对于即时通讯网的开发者来说,虽然不需要自已从底层开发,但了解这方面的知识,还是很有必要的。

本文要分享的是支付宝针对2维码扫描功能,在2维码残缺、变形、变色等等恶劣条件下,是如何提升扫码识别率、识别速度的技术实践总结。希望能带给你启发。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170[推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK

(本文同步发布于:http://www.52im.net/thread-3150-1-1.html

2、技术背景

随着支付宝的线下场景不断扩大,收钱码、口碑、共享单车、充电宝、停车缴费等产品让我们的生活越来越便利。

二维码因为成本低、兼容性好成为了线上线上最主要的连接工具,也因此面临更多新的挑战。

因为二维码是一种点阵式信息编码方式,任何视觉上的缺损、弯曲以及光线作用都会极大的影响识别成功率,如果识别困难也就意味着用户可能选择放弃,影响支付体验也影响用户心智。

用户扫码体验的最关键的主要有以下几个因素:

  • 1)识别率:这是扫码服务的基础指标,识别率能直接体现识别能力,识别率如果无法提高意味着大量的用户将无法使用更便捷的服务;
  • 2)识别耗时:包括 app 启动耗时以及图像识别耗时,这是衡量一个用户从点击 app 到正确识别到内容耗时,每增加 1s,将有相当大量的用户放弃等待并离开;
  • 3)精准反馈:识别结果不仅需要及时反馈给用户,还需要非常精准,特别是在目前线下有多个二维码的场景下,需要避免用户二次操作。

本文将从以上三个方面,分享支付宝扫码技术团队是如何为用户打造一个又准又快又稳的极致扫码体验。

我们对用户反馈进行了大量统计分析,发现绝大部分识别失败都是因为二维码并不标准,并且很遗憾的是在使用我们早期的扫码版本进行识别率测试时发现识别率只有 60%。下面的文字,将首先从提高识别率的方向着手。

3、提高识别率策略1:优化桩点查找算法长宽比耐受

以往的扫码算法,检查长宽比例时允许差异 40%,但是由于使用前向误差,判断结果跟长宽的先后顺序相关,这会导致有些长宽比失调的码,横着扫不出来,但是旋转 90 度竖着却能扫出来了(^OMG^)。

优化策略总结:

  • 1)通过修改长宽比的判定规则,长宽比将不再受先后顺序影响;
  • 2)对于已知长度,修改规则将可接受的宽度范围扩大,增强长宽比的耐受。

在我们对比测试集中,识别率提高了 1% 左右。

4、提高识别率策略2:新增1:5:1桩点识别模式模式

在一张图片中,要找到二维码,关键在找二维码特征定位点: 

三个角的回字型图案,这就是二维码特征定位点。

中间区域的黑白色块比例是1:1:3:1:1:

以往的扫码算法,桩点识别是通过状态机 查找11311模式后 取中间位置确定x位置(此时扫描线在第一行11311比例处)在x位置纵向搜索11311模式, 确定y位置再以 (x,y) 位置横向搜索11311比例,修正x位置。

这种模式在桩点污损的情况下,识别能力较差只要在任何一次11311模式搜索中遇到干扰点,哪怕是一个像素的椒盐噪声也能使桩点查找失败。(支付宝蓝的桩点,会在蓝色区域产生大量噪点,导致识别率低下)

为此,我们新增了一种桩点识别方式。在状态机达到151模式的时候,开始尝试确认桩点。(此时扫描线在第一行151比例处)。

优化效果:

  • 1)新的查找方法将不再受桩点中心或边缘部分被污损的影响,支付宝蓝色桩点码识别率明显提升;
  • 2)修改后识别率整体提升了接近 1%,但识别失败的耗时有所提升。

5、提高识别率策略3:添加一种对角线过滤规则

在枚举所有可能桩点组合 O(N^3) 之前,对所有可疑桩点进行一次对角线检查过滤。由于桩点对角线也应该满足 11311模式 ,用这个规则做一次过滤可疑有效减少运算量,也就有效降低了识别成功和失败的耗时。

6、提高识别率策略4:基于 Logistic Regression 的二维码分类器

在以往的扫码算法中在拿到三个桩点后,基于夹角,长度偏差,单位长度查三个数值,用简单公式计算得到阈值,判断是否为可能的二维码,误判概率较大。

为此,我们引入机器学习中的逻辑回归算法模型。

基于支付宝丰富的二维码数据集,训练出逻辑回归模型,作为二维码分类器,明显降低了误判概率,也将明显降低无二维码时识别失败的耗时。

7、提高识别率策略5:修改跳行扫描的间隔数

由于输入的相机帧分辨率高,像素点多,运算量大,以往的扫码算法在水平跟垂直方向跳行采样进行计算。但在实际运算中,由于跳过了太多列,错过了11311模式中某些1位置的点,导致桩点查找失败。

我们通过将跳行计算行数修改为可配置项,通过线上 AB 灰度测试得到最合适的跳行策略,整体配置此跳行策略后,识别率得到明显提升。

上述优化在测试集的表现: 

综上优化:扫码核心识别能力,在7744张图片测试集上提高了6.95个百分点。

8、特殊策略优化

除此上述通用扫码优化之外,我们还对特殊场景扫码能力进行提高。

8.1 畸变?不怕不怕!

线下场景复杂多变。饮料瓶身上变形的二维码、超市小票卷起边角弯曲的二维码、路边小贩凹凸不平甚至折叠的二维码......这些畸变的二维码容易增加识别难度,甚至导致识别失败。

以往的扫码算法抗畸变策略中,先用透视变换关系建立映射关系。

优点是:适应性好,满足大多数应用场景。

不足也明显:对 Version 1 的码,因为映射关系退化为仿射变换,效果较差,手机必须和码平面平行才能方便识别。当物料表面不是平面的时候,效果较差。

优化策略:

  • 1)假设采样坐标系到二维码坐标系遵守一个更复杂的映射关系,并且假设物料表面的卷曲较小,通过使用二次函数可以较好的拟合这个映射关系;
  • 2)实际发票上的二维码版本普遍大于等于 7,高版本二维码具有多个辅助定位点,更利于构造二次映射表;
  • 3)基于以上推论,使用新的映射代替旧的透视变换,进行更精准的采样。

用新的策略,发票码这个场景的二维码识别能力提升明显。

▲注意:由于采用了增强算法,请对准二维码稍作等待

样本测试结果:

8.2 容错识别能力提升

商户或者供应商生成二维码后,通常会在二维码的中间部分贴上 Logo,这部分有可能会使二维码 Decode 时出错。

优化策略:

对于采样后拿到的 BitMatrix,对于中间部分一块矩形区域内的点,采用某些策略来改变中间点的值,使它能够通过容错边界的检查。目前采用两种策略,第一种是反转,第二种是每一个点随机取值。目前所取的矩形区域是长、宽的四分之一。

通过此项优化后,扫码的容错能力也得到明显提升。

9、更小的识别耗时

针对识别效率,我们使用了GPU计算二值化,降低识别单帧耗时。

所谓图像二值化就是将图像上的像素点的灰度值设置为 0 或 255,也就是将整个图像呈现出明显的只有黑和白的视觉效果。下图左边为原图,右边是二值化处理过的图。

在扫码算法解码前,有二值化计算,图像的二值化计算能使图像中数据量大为减少,并弱化图像模糊、颜色对比度不强、光线过强/太弱、图像污损等情况下其他信息的干扰,更利于检测识别。

传统算法是在 CPU 上进行二值化运算,非常消耗 CPU 资源,但其实 GPU 更擅长大规模并行计算,所以我们选择使用 GPU 来做二值化计算。在安卓平台上使用 RenderScript,iOS 平台上使用 Metal,都是很底层的框架。

1)iOS优化结果:统一电池、角度、光线等环境变量, 在iPhone6上测试扫码核心5种摄像头二值化算法。

表现如下: 

 

可以看出,在图像二值化方面 Metal 有相当高的优势,相比原来的单纯 CPU 处理快了接近 150%, 同时降低了近50个百分点的CPU资源。

2)Andriod优化结果:由于Android机型众多,我们抽取了线上数据,可以看到GPU 在二值化处理中显著降低了单帧耗时30%以上。 

10、算法分级、场景分类、科学调度

线下物料千奇百怪,扫码算法为了解决一些不理想的场景,如二维码有遮挡、污损、模糊或角度很不好的特殊情况,需要使用一些比较耗时但比较强大的算法,但普通情况不需要这些算法。

所以,我们对识码算法定了优先级,通过时间推移、跳帧触发等方式调度。

优先级:

  • 1)高优先级:每帧执行;
  • 2)中优先级:降帧率执行;
  • 3)低优先级:低帧率执行。

不同优先级的功能执行时机可配置。不同功能属于哪个优先级可配置

特殊场景算法能力:

  • 1)反色码识别能力;
  • 2)容错边界码识别能力;
  • 3)污损桩点识别能力等;
  • 4)条码识别能力。

附录:更多阿里团队分享的文章

社交软件红包技术解密(七):支付宝红包的海量高并发技术实践

阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处

来自阿里OpenIM:打造安全可靠即时通讯服务的技术实践分享

淘宝技术分享:手淘亿级移动端接入层网关的技术演进之路

阿里技术分享:深度揭秘阿里数据库技术方案的10年变迁史

阿里技术分享:阿里自研金融级数据库OceanBase的艰辛成长之路

作者谈《阿里巴巴Java开发手册(规约)》背后的故事

淘宝技术分享:手淘亿级移动端接入层网关的技术演进之路

《阿里巴巴Android开发手册(规约)》背后的故事

手机淘宝消息推送系统的架构与实践(音频+PPT) [附件下载]

重磅发布:《阿里巴巴Android开发手册(规约)》[附件下载]

阿里技术结晶:《阿里巴巴Java开发手册-v1.6.0-泰山版》[附件下载]

(本文同步发布于:http://www.52im.net/thread-3150-1-1.html

posted @ 2020-09-25 14:29 Jack Jiang 阅读(287) | 评论 (0)编辑 收藏

本文在编写时参考了博客作者“鹿呦呦”和在线课程“即时消息技术剖析与实战”的相关资料,一并表示感谢。

1、引言

随着移动互联网络的发展,IM技术的应用已经不仅限于聊天应用本身,它早已融入各种应用形态中,比如:直播中的主播互动、联网游戏中的玩家互动、外卖/打车应用中的实时位置共享、在线教育应用中的互动白板等。

在这些风格迥异的应用场景下,IM技术所呈现出来的功能形态虽有不同,但“实时性”这个技术特征并无区别。

那么,对于技术门外汉来说,到底什么是IM的“实时性”?该如何理解它?这就是本文想要讨论的主题。

区别于强大的原生应用,Web端的IM系统,在很长一段时间内想实现真正的“实时性”,是非常困难的,因为无法直接使用UDP、TCP通信协议,在HTML5中的WebSocket出现之前,Web端几乎没有真正意义上的“双向实时通信”这种技术存在。

正因为如此,理解Web端即时通信技术的演进,也就自然而然能循序渐进地体会到IM系统中的“实时性”了。所以本文将围绕Web端即时通讯技术,为你展开IM“实时性”这个话题。

友情提示:本系列文章侧重于理论概念的讲述,篇幅有限,点到即止,如需系统、深入、具体地学习IM技术的方方面面,请从此文入手:《新手入门一篇就够:从零开发移动端IM》(史诗级文章,适合从入门到放弃)。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170 [推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK

(本文同步发布于:http://www.52im.net/thread-3143-1-1.html

2、系列文章目录

IM开发快速入门(一):什么是IM系统?

IM开发快速入门(二):什么是IM系统的实时性?》(* 本文

《IM开发快速入门(三):什么是IM系统的可靠性? (稍后发布)》

《IM开发快速入门(四):什么是IM系统的一致性? (稍后发布)》

《IM开发快速入门(五):什么是IM系统的安全性? (稍后发布)》

《IM开发快速入门(六):什么是IM系统的的心跳机制? (稍后发布)》

《IM开发快速入门(七):如何理解并实现IM系统消息未读数? (稍后发布)》

《IM开发快速入门(八):如何理解并实现IM系统的多端消息漫游? (稍后发布)》

3、短轮询技术

在早期的Web时代,技术的创造者们无法预见如今各种选进的技术应用形式,他们认为数据只是用来“看”的,也数据的获取基本就是“请求 -> 响应”这种一问一答形式。包括我们平时浏览的各种门户网站都是采用的“请求响应”模式。

这种依赖于用户“主动”请求的数据获取模式,如果想实现IM系统,是无法即时获得最新的聊天消息的,因为用户并不知道新消息什么时候到来,而服务端也没有办法主动通知用户。

在这个时期,虽然技术和思路都受当时技术水平的限制,但IM总不能不做吧。

于是,一种被称为“短轮询”的数据获取模式出现了。在“短轮询”模式下,IM客户端定时轮询服务端,以便让用户知道是否有新的聊天消息存在。

这种模式下,服务端收到请求后,即刻查询是否存在新消息,有就返回给客户端,没有则返回空并立即关闭连接。

相较于前面用户需要“手动”去刷新页面的方式,这种模式只是将用户的“手动”变为“自动”而已,技术本质并没有发生任何实质性改变。

短轮询这种模式,就好比旧时代一个等待重要邮件的人,他需要每天自已跑到邮局,主动去问是否有自己的信件,有就拿回家,如果没有,则第二天继续去问。一来一去,非常低效。

技术原理总结如下图所示:

短轮询这种模式有好处,也有坏处。

好处是:

  • 1)技术简单,容易实现;
  • 2)可维护性强,因为它没什么复杂的。

坏处是:

  • 1)因为无法预知数据是否存在,所以多数请求是无用的,浪费计算资源;
  • 2)为了提升实时性,高频率的请求会加大服务端的性能负载。

总结一下就是,短轮询这种模式对于IM技术大拿来说,显的非常low,因为技术实现实在是简单粗暴。

4、长轮询技术

正如你所见,用短轮询技术来保证IM的实时性,确实难说优雅。不过,这难不倒无所不能的程序员,一种被称为“长轮询”的数据获取模式出现了。

从技术上来说,长轮询实现的IM相较于短轮询最大的改进在于:短轮询情况下,服务端不管有没有新消息,请求结束就会立即断开连接。而长轮询时,如果本次请求没有新消息发生,糨不会马上断开连接并返回,而是会将本次连接“挂起”一段时间,如果在这段“挂起”时间内有新的聊天消息出现,就能马上读取并立即返回给客户端,接着结束本次连接。一段时间后又会再次发起请求,如此周而复始。

长轮询这种模式,拿上节等待邮件的这个例子来说,就好比收信的人每天到邮局去问是否有信件,如果没有,他不马上回家,而是在邮局待上一段时间,如果这段时间过去了,还是没有,就先回家,接着第二天再来。

技术原理总结如下图所示: 

长轮询的优点是:

  • 1)相较于短连询,一定程度降低了服务端请求负载;
  • 2)相较于短连询,实时性有提升,因为它是主动“等”消息。

长轮询的缺点是:

  • 1)长论询模式下,连接“挂起”的这段时间内,服务端需要配合开启单独的消息查询线程,仍然存在无用功;
  • 2)相较于短连询模式,在一次长轮询结束、下次轮询发起前的窗口期内,仍然存在“实时性”盲区。

实际上,在Web端即时通讯技术里,长轮询有个专业的术语叫“Comet”,有兴趣可以详细学习《Comet技术详解:基于HTTP长连接的Web端实时通信技术》。

5、轮询无法实现真正的“实时性”

对于Web端即时通讯技术来说,上面提到的无论是短轮询,还是长轮询,它们都存在“实时性”盲区。

我们回到上两节介绍的短轮询和长轮询技术原理图。

先看看短轮询这张图:

很明显,短轮询在每次轮询结束和下次轮询开始的间隔期内,是无法感知到新消息的,这也便形成了“实时性盲区”。换句话说,短轮询技术在“实时性盲区”内,无法做到“实时”。

再来看看长轮询:

跟短轮询道理一样,长轮询在每次轮询结束和下次轮询开始的间隔期,依然会形成“实时性盲区”。

要理解纠结轮询技术的实时性缺陷,就得了解它们背后的技术——HTTP协议了。

HTTP协议设计的目的,就是为了实现“请求--响应”这种模式的数据交互,也就是众所周之的“短连接”设计。而无论是短轮询还是长轮询,都跳不出HTTP的先天技术逻辑(请求--响应--断开)。

所以,归根到底,想要基于HTTP协议来实现IM,要达到真正的“实时性”,是相当勉强的。因为HTTP设计的目的,就是用“短连接”来简化传统TCP长连接通信带来的复杂性,而IM的实时性恰好要用到的又是TCP的长连接特性,所以这就是个悖论。

要真正实现Web端的IM“实时性”,肯定不能强行HTTP上做文章了,我们需要新的技术。

6、WebSocket让Web端IM真正的“实时性”变成可能

好消息是,HTML5中带来了WebSocket技术。WebSocket是真正的全双式双向通信技术(详见:《WebSocket从入门到精通,半小时就够!》)。

下图上旧式轮询技术跟WebSocket的对比图:

从上图可以看出:

  • 1)轮询技术一问一答,在下一个请求发起之前,存在“实时性”盲区;
  • 2)WebSocket一旦建立连接后,数据可以随时双向通信(即客户端可以随时向服务端发消息,服务端也可以随时通知客户端有新消息)。

举个例子就是:轮询技术相当于传统的邮件传递方法(你得自已去邮局问有没有新邮件),而WebSocket相当于现代的电话系统,只要你拨通后,随时可以实时收听到对方的声音,对方也能随时收听到你的声音。完美!

总结一下WebSocket 的优点是:

  • 1)真正的实时性:支持客户端与服务端真正的双向实时通信;
  • 2)大幅降低负载:少了轮询技术中高频率无用的请求,可大大降低服务端QPS压力;
  • 3)网络开销降低:一次连接,随时使用,再也不用轮询技术中每次发起HTTP请求(随之而来的是每次HTTP的大量冗余协议头信息等)。

7、本文小结

本文以Web端即时通讯技术的演进为例,从短轮询到长轮询,再到WebSocket,理论联系实际地讲解了Web端IM“实时性”的技术变迁,从而帮助读者理解IM中“实时性”这个最为关键的技术特征。

附录:更多Web端即时通讯资料

新手入门贴:史上最全Web端即时通讯技术原理详解

Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE

SSE技术详解:一种全新的HTML5服务器推送事件技术

Comet技术详解:基于HTTP长连接的Web端实时通信技术

新手快速入门:WebSocket简明教程

WebSocket详解(一):初步认识WebSocket技术

WebSocket详解(二):技术原理、代码演示和应用案例

WebSocket详解(三):深入WebSocket通信协议细节

WebSocket详解(四):刨根问底HTTP与WebSocket的关系(上篇)

WebSocket详解(五):刨根问底HTTP与WebSocket的关系(下篇)

WebSocket详解(六):刨根问底WebSocket与Socket的关系

socket.io实现消息推送的一点实践及思路

LinkedIn的Web端即时通讯实践:实现单机几十万条长连接

Web端即时通讯技术的发展与WebSocket、Socket.io的技术实践

Web端即时通讯安全:跨站点WebSocket劫持漏洞详解(含示例代码)

开源框架Pomelo实践:搭建Web端高性能分布式IM聊天服务器

使用WebSocket和SSE技术实现Web端消息推送

详解Web端通信方式的演进:从Ajax、JSONP 到 SSE、Websocket

MobileIMSDK-Web的网络层框架为何使用的是Socket.io而不是Netty?

理论联系实际:从零理解WebSocket的通信原理、协议格式、安全性

微信小程序中如何使用WebSocket实现长连接(含完整源码)

八问WebSocket协议:为你快速解答WebSocket热门疑问

快速了解Electron:新一代基于Web的跨平台桌面技术

一文读懂前端技术演进:盘点Web前端20年的技术变迁史

Web端即时通讯基础知识补课:一文搞懂跨域的所有问题!

Web端即时通讯实践干货:如何让你的WebSocket断网重连更快速?

WebSocket从入门到精通,半小时就够!

>> 更多同类文章 ……

本文已同步发布于“即时通讯技术圈”公众号:

▲ 本文在公众号上的链接是:点此进入,原文链接是:http://www.52im.net/thread-3143-1-1.html

posted @ 2020-09-18 13:56 Jack Jiang 阅读(201) | 评论 (0)编辑 收藏

1、引言

在中大型IM系统中,聊天消息的唯一ID生成策略是个很重要的技术点。不夸张的说,聊天消息ID贯穿了整个聊天生命周期的几乎每一个算法、逻辑和过程,ID生成策略的好坏有可能直接决定系统在某些技术点上的设计难易度。

有中小型IM场景下,消息ID可以简单处理,反正只要唯一就行,而中大型场景下,因为要考虑到分布式的性能、一致性等,所以要考虑的问题点又是另一回事。

总之就是,IM的消息ID生成这件事,可深可浅,看似简单但实际可探索的边界可以很大,这也是为什么即时通讯网为此专门整理了《IM消息ID技术专题》系列文章的原因。做技术所谓厚积薄发,了解的越多,你的技术可操作空间也就越大,希望随着这个系列文章的阅读,可以为你在ID生成这一块的技术选型带来更多有益的启发。

另外,因为即时通讯网主要关注的是即时通讯方面的系统开发,但并不意味着这个系统文章只适用于IM或消息推送等实时通信系统,它同样适用于其它需要唯一ID的应用中。

本文将要分享的是滴滴开源的分布式ID生成器Tinyid的技术原理、使用方法等等,希望能进一步为你打开这方面的技术视野。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170[推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK

(本文同步发布于:http://www.52im.net/thread-3129-1-1.html

2、专题目录

本文是“IM消息ID技术专题”系列文章的第6篇,专题总目录如下:

IM消息ID技术专题(一):微信的海量IM聊天消息序列号生成实践(算法原理篇)

IM消息ID技术专题(二):微信的海量IM聊天消息序列号生成实践(容灾方案篇)

IM消息ID技术专题(三):解密融云IM产品的聊天消息ID生成策略

IM消息ID技术专题(四):深度解密美团的分布式ID生成算法

IM消息ID技术专题(五):开源分布式ID生成器UidGenerator的技术实现

IM消息ID技术专题(六):深度解密滴滴的高性能ID生成器(Tinyid)》(* 本文

3、什么是Tinyid?

Tinyid是滴滴用Java开发的一款分布式id生成系统,基于数据库号段算法实现。

Tinyid是在美团的ID生成算法Leaf的基础上扩展而来,支持数据库多主节点模式,它提供了REST API和Java客户端两种获取方式,相对来说使用更方便。不过,和美团的Leaf算法不同的是,Tinyid只支持号段一种模式(并不支持Snowflake模式)。(有关美团的Leaf算法,可以详读《IM消息ID技术专题(四):深度解密美团的分布式ID生成算法

Tinyid目前在滴滴客服部门使用,且通过tinyid-client方式接入,每天生成的是亿级别的id。性能上,据称单实例能达到1千万QPS。

它的开源地址是:

PS:滴滴在Tinyid工程页面写了一句话,“tinyid,并不是滴滴官方产品,只是滴滴拥有的代码”,我语文不好,这句该怎么理解呢?

4、Tinyid的主要技术特性

主要特性总结一下就是:

  • 1)全局唯一的long型ID:即id极限数量是2的64次方;
  • 2)趋势递增的id:趋势递增的意思是,id是递增但不一定是连续的(这跟微信的ID生成策略类似);
  • 3)提供 http 和 java-client 方式接入;
  • 4)支持批量获取ID;
  • 5)支持生成1,3,5,7,9…序列的ID;
  • 6)支持多个db的配置。

适用的场景:只关心ID是数字,趋势递增的系统,可以容忍ID不连续,可以容忍ID的浪费。

不适用场景:像类似于订单ID的业务,因生成的ID大部分是连续的,容易被扫库、或者推算出订单量等信息。

另外:微信的聊天消息ID生成算法也是基于号段、趋势递增这种逻辑,如果有兴趣,可以详见:《IM消息ID技术专题(一):微信的海量IM聊天消息序列号生成实践(算法原理篇)》。

5、Tinyid的技术优势

性能方面:

  • 1)http方式:访问性能取决于http server的能力,网络传输速度;
  • 2)java-client方式:id为本地生成,号段长度(step)越长,qps越大,如果将号段设置足够大,则qps可达1000w+。

可用性方面:

  • 1)当db不可用时,因为server有缓存,所以还可以使用一段时间;
  • 2)如果配置了多个db,则只要有1个db存活,则服务可用;
  • 3)使用tiny-client时,只要server有一台存活,则理论上server全挂,因为client有缓存,也可以继续使用一段时间。

6、Tinyid的技术原理详解

6.1 ID生成系统的技术要点

在简单系统中,我们常常使用db的id自增方式来标识和保存数据,随着系统的复杂,数据的增多,分库分表成为了常见的方案,db自增已无法满足要求。

这时候全局唯一的id生成系统就派上了用场,当然这只是id生成其中的一种应用场景。

那么,一个成熟的id生成系统应该具备哪些能力呢?

  • 1)唯一性:无论怎样都不能重复,id全局唯一是最基本的要求;
  • 2)高性能:基础服务尽可能耗时少,如果能够本地生成最好;
  • 3)高可用:虽说很难实现100%的可用性,但是也要无限接近于100%的可用性;
  • 4)易用性:能够拿来即用,接入方便,同时在系统设计和实现上要尽可能的简单。

6.2 Tinyid的实现原理

我们先来看一下最常见的id生成方式,db的auto_increment,相信大家都非常熟悉。

我也见过一些同学在实战中使用这种方案来获取一个id,这个方案的优点是简单,缺点是每次只能向db获取一个id,性能比较差,对db访问比较频繁,db的压力会比较大。

那么,是不是可以对这种方案优化一下呢?可否一次向db获取一批id呢?答案当然是可以的。

一批id,我们可以看成是一个id范围,例如(1000,2000],这个1000到2000也可以称为一个“号段”,我们一次向db申请一个号段,加载到内存中,然后采用自增的方式来生成id,这个号段用完后,再次向db申请一个新的号段,这样对db的压力就减轻了很多,同时内存中直接生成id,性能则提高了很多。

PS:简单解释一下什么是号段模式:

号段模式就是从数据库批量的获取自增ID,每次从数据库取出一个号段范围,例如 (1,1000] 代表1000个ID,业务服务将号段在本地生成1~1000的自增ID并加载到内存。

那么保存db号段的表该怎设计呢?我们继续往下看。

6.3 DB号段算法描述

如上表,我们很容易想到的是db直接存储一个范围(start_id,end_id],当这批id使用完毕后,我们做一次update操作,update start_id=2000(end_id), end_id=3000(end_id+1000),update成功了,则说明获取到了下一个id范围。仔细想想,实际上start_id并没有起什么作用,新的号段总是(end_id,end_id+1000]。

所以这里我们更改一下,db设计应该是这样的:

如上表所示:

  • 1)我们增加了biz_type,这个代表业务类型,不同的业务的id隔离;
  • 2)max_id则是上面的end_id了,代表当前最大的可用id;
  • 3)step代表号段的长度,可以根据每个业务的qps来设置一个合理的长度;
  • 4)version是一个乐观锁,每次更新都加上version,能够保证并发更新的正确性 。

那么我们可以通过如下几个步骤来获取一个可用的号段:

A、查询当前的max_id信息:select id, biz_type, max_id, step, version from tiny_id_info where biz_type='test';

B、计算新的max_id: new_max_id = max_id + step;

C、更新DB中的max_id:update tiny_id_info set max_id=#{new_max_id} , verison=version+1 where id=#{id} and max_id=#{max_id} and version=#{version};

D、如果更新成功,则可用号段获取成功,新的可用号段为(max_id, new_max_id];

E、如果更新失败,则号段可能被其他线程获取,回到步骤A,进行重试。

6.4 号段生成方案的简单架构

如上述内容,我们已经完成了号段生成逻辑。

那么我们的id生成服务架构可能是这样的:

如上图,id生成系统向外提供http服务,请求经过我们的负载均衡router,到达其中一台tinyid-server,从事先加载好的号段中获取一个id。

如果号段还没有加载,或者已经用完,则向db再申请一个新的可用号段,多台server之间因为号段生成算法的原子性,而保证每台server上的可用号段不重,从而使id生成不重。

可以看到:

  • 1)如果tinyid-server如果重启了,那么号段就作废了,会浪费一部分id;
  • 2)同时id也不会连续;
  • 3)每次请求可能会打到不同的机器上,id也不是单调递增的,而是趋势递增的(不过这对于大部分业务都是可接受的)。

6.5 简单架构的问题

到此一个简单的id生成系统就完成了,那么是否还存在问题呢?

回想一下我们最开始的id生成系统要求:高性能、高可用、简单易用。

在上面这套架构里,至少还存在以下问题:

  • 1)当id用完时需要访问db加载新的号段,db更新也可能存在version冲突,此时id生成耗时明显增加;
  • 2)db是一个单点,虽然db可以建设主从等高可用架构,但始终是一个单点;
  • 3)使用http方式获取一个id,存在网络开销,性能和可用性都不太好。

6.6 优化办法及最终架构

1)双号段缓存:

对于号段用完需要访问db,我们很容易想到在号段用到一定程度的时候,就去异步加载下一个号段,保证内存中始终有可用号段,则可避免性能波动。

2)增加多db支持:

db只有一个master时,如果db不可用(down掉或者主从延迟比较大),则获取号段不可用。实际上我们可以支持多个db,比如2个db,A和B,我们获取号段可以随机从其中一台上获取。那么如果A,B都获取到了同一号段,我们怎么保证生成的id不重呢?tinyid是这么做的,让A只生成偶数id,B只生产奇数id,对应的db设计增加了两个字段,如下所示

delta代表id每次的增量,remainder代表余数,例如可以将A,B都delta都设置2,remainder分别设置为0,1则,A的号段只生成偶数号段,B是奇数号段。通过delta和remainder两个字段我们可以根据使用方的需求灵活设计db个数,同时也可以为使用方提供只生产类似奇数的id序列。

3)增加tinyid-client:

使用http获取一个id,存在网络开销,是否可以本地生成id?

为此我们提供了tinyid-client,我们可以向tinyid-server发送请求来获取可用号段,之后在本地构建双号段、id生成,如此id生成则变成纯本地操作,性能大大提升,因为本地有双号段缓存,则可以容忍tinyid-server一段时间的down掉,可用性也有了比较大的提升。

4)tinyid最终架构:

最终我们的架构可能是这样的:

下面是更具体的代码调用逻辑:

如上图所示,下面是关于这个代码调用逻辑图的说明:

  • 1)nextId和getNextSegmentId是tinyid-server对外提供的两个http接口;
  • 2)nextId是获取下一个id,当调用nextId时,会传入bizType,每个bizType的id数据是隔离的,生成id会使用该bizType类型生成的IdGenerator;
  • 3)getNextSegmentId是获取下一个可用号段,tinyid-client会通过此接口来获取可用号段;
  • 4)IdGenerator是id生成的接口;
  • 5)IdGeneratorFactory是生产具体IdGenerator的工厂,每个biz_type生成一个IdGenerator实例。通过工厂,我们可以随时在db中新增biz_type,而不用重启服务;
  • 6)IdGeneratorFactory实际上有两个子类IdGeneratorFactoryServer和IdGeneratorFactoryClient,区别在于,getNextSegmentId的不同,一个是DbGet,一个是HttpGet;
  • 7)CachedIdGenerator则是具体的id生成器对象,持有currentSegmentId和nextSegmentId对象,负责nextId的核心流程。nextId最终通过AtomicLong.andAndGet(delta)方法产生。

具体的代码实现,有兴趣可以直接阅读源码:

7、Tinyid的最佳实践

1)tinyid-server推荐部署到多个机房的多台机器:

多机房部署可用性更高,http方式访问需使用方考虑延迟问题。

2)推荐使用tinyid-client来获取id,好处如下:

a、id为本地生成(调用AtomicLong.addAndGet方法),性能大大增加;

b、client对server访问变的低频,减轻了server的压力;

c、因为低频,即便client使用方和server不在一个机房,也无须担心延迟;

d、即便所有server挂掉,因为client预加载了号段,依然可以继续使用一段时间

注:使用tinyid-client方式,如果client机器较多频繁重启,可能会浪费较多的id,这时可以考虑使用http方式。

3)推荐db配置两个或更多:

db配置多个时,只要有1个db存活,则服务可用 多db配置,如配置了两个db,则每次新增业务需在两个db中都写入相关数据。

8、Tinyid该怎么调用?

关于怎么调用。鉴于篇幅原因,就不再具体去写了,有兴趣的话,可以读一下这篇《Tinyid:滴滴开源千万级并发的分布式ID生成器》。

9、参考资料

[1] 面试总被问分布式ID怎么办? 滴滴(Tinyid)甩给他

[2] Tinyid:滴滴开源千万级并发的分布式ID生成器

[3] tinyid工程中文readme

[4] 滴滴开源的Tinyid如何每天生成亿级别的ID?

附录:更多IM开发热门技术文章

新手入门一篇就够:从零开发移动端IM

移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”

移动端IM开发者必读(二):史上最全移动弱网络优化方法总结

从客户端的角度来谈谈移动端IM的消息可靠性和送达机制

现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障

移动端IM中大规模群消息的推送如何保证效率、实时性?

移动端IM开发需要面对的技术问题

开发IM是自己设计协议用字节流好还是字符流好?

请问有人知道语音留言聊天的主流实现方式吗?

IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

IM消息送达保证机制实现(二):保证离线消息的可靠投递

如何保证IM实时消息的“时序性”与“一致性”?

一个低成本确保IM消息时序的方法探讨

IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?

IM群聊消息如此复杂,如何保证不丢不重?

谈谈移动端 IM 开发中登录请求的优化

移动端IM登录时拉取数据如何作到省流量?

浅谈移动端IM的多点登录和消息漫游原理

完全自已开发的IM该如何设计“失败重试”机制?

自已开发IM有那么难吗?手把手教你自撸一个Andriod版简易IM (有源码)

IM开发基础知识补课(六):数据库用NoSQL还是SQL?读这篇就够了!

适合新手:从零开发一个IM服务端(基于Netty,有完整源码)

拿起键盘就是干:跟我一起徒手开发一套分布式IM系统

适合新手:手把手教你用Go快速搭建高性能、可扩展的IM系统(有源码)

IM里“附近的人”功能实现原理是什么?如何高效率地实现它?

IM开发基础知识补课(七):主流移动端账号登录方式的原理及设计思路

IM要做手机扫码登录?先看看微信的扫码登录功能技术原理

IM开发宝典:史上最全,微信各种功能参数和逻辑规则资料汇总

IM开发干货分享:我是如何解决大量离线消息导致客户端卡顿的

IM开发干货分享:如何优雅的实现大量离线消息的可靠投递

IM开发干货分享:有赞移动端IM的组件化SDK架构设计实践

>> 更多同类文章 ……

本文已同步发布于“即时通讯技术圈”公众号,欢迎关注:

▲ 本文在公众号上的链接是:点此进入,原文链接是:http://www.52im.net/thread-3129-1-1.html

posted @ 2020-09-08 22:31 Jack Jiang 阅读(338) | 评论 (0)编辑 收藏

     摘要: 本文由小米信息技术团队研发工程师陈刚原创,原题“当我们在谈论高并发的时候究竟在谈什么?”,为了更好的内容呈现,即时通讯网收录时有修订和改动。1、引言在即时通讯网社区里,多是做IM、消息推送、客服系统、音视频聊天这类实时通信方面的开发者,在涉及到即时通讯技术时聊的最多的话题就是高并发、高吞吐、海量用户。代码还没开始写,就考虑万一哪天这IM用户量破百万、千万该怎么办的问题,是多...  阅读全文

posted @ 2020-09-03 23:08 Jack Jiang 阅读(293) | 评论 (0)编辑 收藏

本文内容编写时,参考了网上的资料,详见“参考资料”部分,感谢分享者。

1、引言

这个系列文章已经整理了10篇,但都没有涉及到具体的红包算法实现,主要有以下两方面原因。

一方面是各社交/IM产品中的红包功能同质化严重,红包算法的“可玩性”便是“核心竞争力所在”,这是同质化功能的差异化竞争思路,不会随便公开。

另一方面,市场上还存在各种抢红包插件这类灰产存在,一旦公开这些算法,很可能又被这帮插件开发者们搞出什么幺蛾子。

所以,这样的情况下,如果要做社交/IM产品中的红包功能,红包随便算法该怎么实现,基本上只能自已琢磨,很难找到大厂算法直接套用。

本着即时通讯网一贯的im知识传播精神,我收集整理并参考了大量的网上资料,综合了比较靠谱的信息来源,便有了本文。本文根据有限的资料,分享了微信红包随机算法实现中的一些技术要点,并整理了两种比较靠谱的红包算法实现思路(含可运行的实现代码),希望能给你的红包算法开发带来启发。

申明:本文资料整理自网络,仅供学习研究之用,如有不妥,请通知作者。

学习交流:

- 即时通讯开发交流5群:215477170 [推荐]

- 移动端IM开发入门文章:新手入门一篇就够:从零开发移动端IM

- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK  [推荐]

本文已同步发布于“即时通讯技术圈”公众号,欢迎关注:

▲ 本文在公众号上的链接是:点此进入,原文链接是:http://www.52im.net/thread-3125-1-1.html

2、系列文章

3、微信红包算法要点汇总

这是目前能找到的仅有的一份,有微信团队人员参与的微信红包算法技术要点的讨论资料。分享于2015年,差不多是微信红包刚火没多久,大概是微信技术团队的人当时没有现在这些技术之外的顾虑,所以作了有限的分享,资料难得,本次重新整理了一下,可以作为参考资料使用。以下是资料正文。

资料来源:来自InfoQ的某架构群的技术讨论,由朱玉华整理(个人博客是:zhuyuhua.com(目前已无法访问))。

资料背景:起因是有朋友在朋友圈咨询微信红包的架构,于是在微信团队成员参与讨论的情况下,我(指“朱玉华”)整理了这次讨论的技术要点,也就是下面的内容(内容为问答形式)。

3.1、算法实现的技术要点

问:微信的金额什么时候算?

答:微信金额是拆的时候实时算出来,不是预先分配的,采用的是纯内存计算,不需要预算空间存储。

为什么采取实时计算金额?原因是:实时效率更高,预算才效率低下。预算还要占额外存储。因为红包只占一条记录而且有效期就几天,所以不需要多大空间。就算压力大时,水平扩展机器是。

问:关于实时实时性,为什么明明抢到红包,点开后发现没有?

答:2014年的红包一点开就知道金额,分两次操作,先抢到金额,然后再转账。

2015年的红包的拆和抢是分离的,需要点两次,因此会出现抢到红包了,但点开后告知红包已经被领完的状况。进入到第一个页面不代表抢到,只表示当时红包还有。

问:关于分配算法,红包里的金额怎么算?为什么出现各个红包金额相差很大?

答:随机,额度在 0.01 和剩余平均值 2 之间。 例如:发 100 块钱,总共 10 个红包,那么平均值是 10 块钱一个,那么发出来的红包的额度在 0.01元~20元之间波动。

当前面 3 个红包总共被领了 40 块钱时,剩下 60 块钱,总共 7 个红包,那么这 7 个红包的额度在:0.01~(60/7 * 2)=17.14之间。

注意:这里的算法是每被抢一个后,剩下的会再次执行上面的这样的算法(Tim老师也觉得上述算法太复杂,不知基于什么样的考虑)。

这样算下去,会超过最开始的全部金额,因此到了最后面如果不够这么算,那么会采取如下算法:保证剩余用户能拿到最低1分钱即可。

如果前面的人手气不好,那么后面的余额越多,红包额度也就越多,因此实际概率一样的。

问:红包的设计

答:微信从财付通拉取金额数据过来,生成个数/红包类型/金额放到redis集群里,app端将红包ID的请求放入请求队列中,如果发现超过红包的个数,直接返回。根据红包的逻辑处理成功得到令牌请求,则由财付通进行一致性调用,通过像比特币一样,两边保存交易记录,交易后交给第三方服务审计,如果交易过程中出现不一致就强制回归。

问:并发性处理:红包如何计算被抢完?

答:cache会抵抗无效请求,将无效的请求过滤掉,实际进入到后台的量不大。cache记录红包个数,原子操作进行个数递减,到 0 表示被抢光。财付通按照 20万笔每秒入账准备,但实际还不到 8万每秒

问:通如何保持8w每秒的写入?

答:多主sharding,水平扩展机器。

问:数据容量多少?

答:一个红包只占一条记录,有效期只有几天,因此不需要太多空间。

问:查询红包分配,压力大不?

答:抢到红包的人数和红包都在一条cache记录上,没有太大的查询压力。

问:一个红包一个队列?

答:没有队列,一个红包一条数据,数据上有一个计数器字段。

问:有没有从数据上证明每个红包的概率是不是均等?

答:不是绝对均等,就是一个简单的拍脑袋算法。

问:拍脑袋算法,会不会出现两个最佳?

答:会出现金额一样的,但是手气最佳只有一个,先抢到的那个最佳。

问:每领一个红包就更新数据么?

答:每抢到一个红包,就cas更新剩余金额和红包个数。

问:红包如何入库入账?

答:数据库会累加已经领取的个数与金额,插入一条领取记录。入账则是后台异步操作。

问:入帐出错怎么办?比如红包个数没了,但余额还有?

答:最后会有一个take all操作。另外还有一个对账来保障。

问:既然在抢的时候有原子减了就不应该出现抢到了拆开没有的情况?

答:这里的原子减并不是真正意义上的原子操作,是Cache层提供的CAS,通过比较版本号不断尝试。

问:cache和db挂了怎么办?

答:主备 +对账。

问:为什么要分离抢和拆?

答:总思路是设置多层过滤网,层层筛选,层层减少流量和压力。

这个设计最初是因为抢操作是业务层,拆是入账操作,一个操作太重了,而且中断率高。 从接口层面看,第一个接口纯缓存操作,搞压能力强,一个简单查询Cache挡住了绝大部分用户,做了第一道筛选,所以大部分人会看到已经抢完了的提示。

问:抢到红包后再发红包或者提现,这里有什么策略吗?

答:大额优先入账策略。

针对上面的技术要点,有人还画了张原理图(这是网上能找到的相对清晰的版本): 

3.2、微信抢红包的过程模拟

针对上节中整理的资料,当有人在微信群里发了一个 N 人的红包、总金额 M 元,后台大概的技术逻辑如下。

3.2.1)发红包后台操作:

  • 1)在数据库中增加一条红包记录,存储到CKV,设置过期时间;
  • 2)在Cache(可能是腾讯内部kv数据库,基于内存,有落地,有内核态网络处理模块,以内核模块形式提供服务))中增加一条记录,存储抢红包的人数N。

3.2.2)抢红包后台操作:

  • 1)抢红包分为抢和拆:抢操作在Cache层完成,通过原子减操作进行红包数递减,到0就说明抢光了,最终实际进入后台拆操作的量不大,通过操作的分离将无效请求直接挡在Cache层外面。
  • 这里的原子减操作并不是真正意义上的原子减操作,是其Cache层提供的CAS,通过比较版本号不断尝试,存在一定程度上的冲突,冲突的用户会放行,让其进入下一步拆的操作,这也解释了为啥有用户抢到了拆开发现领完了的情况。
  • 2)拆红包在数据库完成:通过数据库的事务操作累加已经领取的个数和金额,插入一条领取流水,入账为异步操作,这也解释了为啥在春节期间红包领取后在余额中看不到。
  • 拆的时候会实时计算金额,其金额为1分到剩余平均值2倍之间随机数,一个总金额为M元的红包,最大的红包为 M * 2 /N(且不会超过M),当拆了红包后会更新剩余金额和个数。财付通按20万笔每秒入账准备,实际只到8万每秒。

4、微信红包算法模拟实现1(含代码)

根据上一节的微信红包随机算法技术要点资料,实现了一个算法,以下供参考。(注:本节内容引用自《微信红包随机算法初探》一文)

4.1、算法约定

算法很简单,跟微信的算法一样,不是提前算好,而是抢红包时计算。

即:金额随机,额度在0.01和剩余平均值*2之间。(参见上一节的 “关于分配算法,红包里的金额怎么算?为什么出现各个红包金额相差很大?” 内容)

4.2、代码实现

算法的逻辑主要是:

public static double getRandomMoney(RedPackage _redPackage) {

    // remainSize 剩余的红包数量

    // remainMoney 剩余的钱

    if(_redPackage.remainSize == 1) {

        _redPackage.remainSize--;

        return (double) Math.round(_redPackage.remainMoney * 100) / 100;

    }

    Random r     = newRandom();

    double min   = 0.01; //

    double max   = _redPackage.remainMoney / _redPackage.remainSize * 2;

    double money = r.nextDouble() * max;

    money = money <= min ? 0.01: money;

    money = Math.floor(money * 100) / 100;

    _redPackage.remainSize--;

    _redPackage.remainMoney -= money;

    return money;

}

LeftMoneyPackage数据结构如下:

class RedPackage {

    int remainSize;

    double remainMoney;

}

测试时初始化相关数据是:

static void init() {

    redPackage.remainSize  = 30;

    redPackage.remainMoney = 500;

}

附件是可以运行的完整Java代码文件:

(无法上传附件,如有需要请从此链接处下载:http://www.52im.net/thread-3125-1-1.html

4.3、测试结果

4.3.1 单次测试

按上述代码中的初始化数据(30人抢500块),执行了两次,结果如下:

//第一次

15.69   21.18   24.11   30.85   0.74    20.85   2.96    13.43   11.12   24.87   1.86    19.62   5.97    29.33   3.05    26.94   18.69   34.47   9.4 29.83   5.17    24.67   17.09   29.96   6.77    5.79    0.34    23.89   40.44   0.92

//第二次

10.44   18.01   17.01   21.07   11.87   4.78    30.14   32.05   16.68   20.34   12.94   27.98   9.31    17.97   12.93   28.75   12.1    12.77   7.54    10.87   4.16    25.36   26.89   5.73    11.59   23.91   17.77   15.85   23.42   9.77

第一次随机红包数据图表如下: 

▲ x轴为抢的顺序,y轴为抢到的金额

第二次随机红包数据图表如下:

▲ x轴为抢的顺序,y轴为抢到的金额

4.3.2 多次均值

重复执行200次的均值:

▲ x轴为抢的顺序,y轴为该次抢到金额的概率均值

重复执行2000次的均值: 

▲ x轴为抢的顺序,y轴为该次抢到金额的概率均值

从以上两张图的均值结果可以看出,这个算法中每一次能抢到的金额几率几乎是均等的,从随机性来说比较合理。

5、微信红包算法模拟实现2(含代码)

我对随机算法很感兴趣,正巧最近研究的方向有点偏随机数这块,所以也自己实现了一下微信的红包分发算法(算法要点参考的是本文第三节内容)。(注:本节内容引用自《微信红包算法的分析》一文)

5.1、代码实现

从第三节中可以了解到,微信并不是一开始就预分配所有的红包金额,而是在拆时进行计算的。这样做的好处是效率高,实时性。本次的代码中,红包具体是怎么计算的呢?请参见第4节中的“关于分配算法,红包里的金额怎么算?为什么出现各个红包金额相差很大?”。

那基于这个思想,可以写出一个红包分配算法:

/**

 * 并不完美的红包算法

 */

public static double rand(double money, int people, List<Double> l) {

    if(people == 1) {

        double red = Math.round(money * 100) / 100.0;

        l.add(red);

        return0;

    }

    Random random = newRandom();

    double min = 0.01;

    double max = money / people * 2.0;

    double red = random.nextDouble() * max;

    red = red <= min ? min : red;

    red = Math.floor(red * 100) / 100.0;

    l.add(red);

    double remain = Math.round((money - red) * 100) / 100.0;

    return remain;

}

算法整体思路很简单,就在在最后一个人的时候要注意,此时不进行随机数计算,而是直接将剩余金额作为红包。

5.2、第一次分析

采用上述算法,可以对用户的抢红包行为做分析。这里的模仿行为是:30 元的红包,10 人抢。操作 100 次。

可以得出如下结果: 

▲ x轴为抢的顺序,y轴为该次抢到金额

从上图中可以很轻易的看出来,越后抢的人,风险越大,同时收益也越大,有较大几率获得“手气最佳”。

那红包面值的分布性如何呢?

▲ x轴为抢的顺序,y轴为该次抢到金额重复 100 次后的平均值

从上图可以看出,都是比较接近平均值(3 元)的。

那重复 1000 次呢?

▲ x轴为抢的顺序,y轴为该次抢到金额重复 1000 次后的平均值

更接近了。。。

可以看出,这个算法可以让大家抢到红包面额在概率上是大致均等的。

5.3、不足之处

有人提出了这个问题: 

他接下来放了好几张他试验的截图。我这里取了一张,如果有兴趣,可以去知乎的问题里查看更多图片。

而此时,我哥们在和我的在讨论中,也告诉我,确实存在某个规律,可能让最后一个抢的人占有某些微小的优势,比如,多 0.01 的之类。

例如发 6 个,总额 0.09 的包,最后一个抢的有极大概率是 0.03。

然而我之前的代码却没办法体现出这一点。

比如 10 人拆 0.11 元的包,我的结果是:

可见以上代码还存在不足之处。

于是我就有一个猜测:

微信可能不是对全金额进行随机的,可能在派发红包之前,已经对金额做了处理,比如,事先减去(红包个数*0.01),之后在每个红包的随机值基础上加 0.01,以此来保证每个红包最小值都是 0.01。

这个猜测或许可以解开那位知友和我哥们这边的疑惑。

5.4、完善算法

在原先的基础上对代码进行简单的修正:

public static double rand(double money, int people, List<Double> l) {

    if(people == 1) {

        double red = Math.round(money * 100) / 100.0;

        l.add(red+0.01);

        return 0;

    }

    Random random = newRandom();

    double min = 0;

    double max = money / people * 2.0;

    double red = random.nextDouble() * max;

    red = red <= min ? min : red;

    red = Math.floor(red * 100) / 100.0;

    l.add(red+0.01);

    double remain = Math.round((money - red) * 100) / 100.0;

    return remain;

}

这个算法,在第一次调用时传入 money 的值是总金额减去红包数*0.01,大概像这样:

_money = _money - people * 0.01;

5.5、第二次分析

5.5.1 验证上次的不足之处

1)10 人抢 0.11 元的包:

2)2 人抢 0.03 元的包: 

3)6 人抢 0.09 的包:

5.5.2 修改后的代码会不会对已知结论造成影响?

30 元的红包,10 人抢,操作 100 次。

▲ x轴为抢的顺序,y轴为该次抢到金额 

▲ x轴为抢的顺序,y轴为该次抢到金额重复 100 次后的平均值

由上面两图可见,结论基本上没有改变。

5.6、结论

经过上述代码实践可知:

1)先抢后抢,金额期望都是相同的;

2)微信的红包算法很可能是预先分配给每人 0.01 的“底额”;

3)后抢者风险高,收益大。

5.7、补充

上几张后面测试的图,补充一下之前的观点,发 n 个红包,总金额是(n+1)*0.01,最后一个领的一定是手气最佳。

 

大家也可以试试。

以上,大概可以证明,微信红包是在分配前先给每个人 0.01 的最低金额的!

6、参考资料

[1] 微信红包随机算法初探

[2] 微信红包算法的分析

[3] 微信红包的架构设计简介

[4] 微信红包的随机算法是怎样实现的?

另外,知乎上对于微信红包算法的讨论问题很多人参与,有兴趣可以上去看看,或许会有更多启发:《微信红包的随机算法是怎样实现的?》。

附录:更多微信相关资源

IM开发宝典:史上最全,微信各种功能参数和逻辑规则资料汇总

微信本地数据库破解版(含iOS、Android),仅供学习研究 [附件下载]

(本文同步发布于:http://www.52im.net/thread-3125-1-1.html

posted @ 2020-08-26 14:32 Jack Jiang 阅读(289) | 评论 (0)编辑 收藏

本文由手机淘宝技术团队原创分享,吴志华(天施)、洪海(孤星)、陈虓将(仲升)等专家参与了本文创作,首次发表于公众号“淘系技术”,收录整理时有修订和改动。

1、引言

移动端网络的优化是超级APP们永恒的话题,而对于无线电商来说这更为重要,因为网络请求体验跟用户的购买行为息息相关。

手机淘宝从过去的HTTP API网关,到后来扛住双十一战场主要流量的自研高性能、全双工、安全的ACCS(阿里云通道服务),无论是基础架构的演进、网络调优、协议的优化、异地多活、网络调度上,都有不少宝贵的经验与大家分享,本文借此机会总结了整个技术演进过程。

* 阅读对象:本文属于移动端网络优化的深水区总结性文章,适合有一定移动端网络应用经验的开发者阅读(尤其对移动弱网有一定了解的),初学者如果没有相关知识积累的话,可以简单了解无需深入。如果你对移动弱网很有兴趣,可以进一步阅读本文末尾“附录”部分的推荐文章。

本文已同步发布于“即时通讯技术圈”公众号,欢迎关注:

▲ 本文在公众号上的链接是:点此进入,原文链接是:http://www.52im.net/thread-3110-1-1.html

2、相关文章

Netty干货分享:京东京麦的生产级TCP网关技术实践总结

知乎技术分享:知乎千万级并发的高性能长连接网关技术实践

手机淘宝消息推送系统的架构与实践(音频+PPT) [附件下载]

3、技术背景

回想移动电商在双十一业务开始兴起的时候,当时双十一当天移动成交243亿占整体571亿的42.6%。

业务高速发展希望更多主动推送去触达用户,一些新的玩法和互动形式,需要连接买家与买家、买家与卖家、买家与达人,因为没有有效的通道能力,业务采取的是不停去轮询服务器,一来对服务器造成不必要的压力,二来对于用户手机的电量流量也是极大的浪费,关键在双十五这种大促的情况下,不必要的请求过大甚至会导致后端集群限流,从而影响到用户体验。

信息传播形态的变化的背后是移动化带来新的技术特征导致的结果。移动电商领域,手机淘宝一直是先行者。移动电商从最初的复制WEB的业务形态到移动特性不断涌现,更多的互动形式的出现,向社交化、娱乐化不断迈进的今天,一个单纯的商品的陈列架形式已经不能满足业务的需求。

业务上需要实时的触达用户,充分发挥移动的特性,将消费时间的碎片利用起来,事实也证明了用户的消费时间随着移动化的进程不断发生变化,逐步分布到全天的碎片时间中。同时货架形态也在向社区化、娱乐化的方向发展,这些都对网络层连接用户有了更高的要求。更多的媒体形态和展示方式,对网络层提出了更多元的要求。

大家可以关注到手机淘宝内的消息盒子这些产品都是业务求变的体现,业务的变化倒逼技术的前进。

4、移动网络环境的挑战性一直都存在

移动网络的速度随便3g、4g、5g的普及,速度有很大提升,但网络环境的多样性和差异性使移动网络的环境更加复杂,在过去双十一前还常遇到一些移动网络劫持的事情。网络劫持这块问题的排查效率很低,需要找到用户、复现现场,甚至找网工、运营商配合排查,一查就是几天过去。

同时在我们的舆情反馈上总是看到用户在说“某个页面加载中、页面打不开、请求很慢、打开某个功能很慢”,面对这些问题过去我们是没有太好的办法,只能猫抓耗子一桩桩去排雷很被动。很多网络的问题是偶现的,一旦错过现在就无从查起。

诸如此类的问题,背后的原因很多:

  • 1)运营商问题;
  • 2)机房部署原因;
  • 3)客户端SDK Bug;
  • 4)弱网和网络抖动;
  • 5)DNS劫持和数据篡改。

在PC时代,我们访问网站的接入条件是相对恒定的,所以在开发时很少考虑网络对用户体验的影响。但是移动APP则不然,尤其是在国内,基础的移动网络环境还不算太好,而且我们有很多用户的访问是发生在地铁、公交车这样的移动环境下,移动基站的频繁切换进一步增加了网络的不稳定。从手机淘宝的数据可以看出,我们每天活跃用户中有不少来自于弱网环境。如果端到云的连接不稳定、高延时,那么所有的用户体验都无从谈起。

基础网络的效率就像一辆列车,时延是火车的速度(启动时间),而带宽就像火车的车厢装载量,整个传输的物理链路就像火车的铁轨。目前现实条件下的移动网络条件非常复杂,我们的目标很简单,就是想让所有用户都能在手机淘宝获得流畅的体验。

下面这张图,能够让大家更加直观的了解国内的移动网络环境。描述了从用户到IDC的端到端的路由情况,不仅数据传输耗时长且丢包率高,同时安全性也是相当糟糕的,DNS劫持、内容劫持在中国就是家常便饭。

因此,我们在改善网络通道上有很多的事情可以去做,去探索突破运营商基础网络的限制,力争为用户创造极致的购物体验。

移动端的DNS问题相当普遍,可以详读以下专题文章:

全面了解移动端DNS域名劫持等杂症:原理、根源、HttpDNS解决方案等

美图App的移动端DNS优化实践:HTTPS请求耗时减小近半

百度APP移动端网络深度优化实践分享(一):DNS优化篇

移动端网络优化之HTTP请求的DNS优化

5、整体技术架构

为了满足移动电商业务高速发展的需求,我们决定打造一个世界级的网络接入服务,构建一个无线网络下”水、电、煤“ 一样的基础设施。

这样一个基础设施需要做到的四个目标:

  • 1)全双工;
  • 2)低延时;
  • 3)高安全;
  • 4)开放。

在这四个目标之上是围绕这个接入服务配套的运维体系,帮助最终用户取得良好的端上体验的同时,帮助开发者快速构建自己的业务。 

如上图所示,在整个接入服务上我们划分为两层:

  • 1)接入网关:负责连接的保持、消息的解析、消息的分发;
  • 2)应用网关:实现各种应用层协议:API、SYNC、RPC、PUSH等,在应用网关的背后是具体的业务系统。

同时我们建立了一个统一调度服务,而不是采用传统的DNS,调度服务是我们的控制中心,通过它我们可以强有力的指挥我们的客户端,并且不会受到DNS污染的影响。

与服务端的分层架构对应的是客户端的SDK,最底层的统一网络库SDK集中了我们对网络优化的策略,并向上为各个应用网关技术的SDK提供API。

基于上面的开放架构,业务方可以选择直接开放具体的后端服务对接不同的应用网关,不需要了解网络背后的细节,并通过应用网关如API网关提供的开发工具快速生成客户端代码。业务方也可以基于这个接入层设计自己的协议。

统一接入层集中管理了用户的设备、在线状态,并提供信息的双向传递能力。

如下图所示:

网关将致力于解决中间网络的通讯,为上层的服务提供高质量的双向通讯能力。

6、稳定性与容灾

稳定性与容灾是服务端中间件永恒的主题,统一接入层这样一个汇聚网关收益和风险是并存的,一旦这个入口故障了,波及的用户范围是不可想象的,如何做的更加稳定,是一个巨大的挑战。

6.1 网关架构的优化

对于一个统一网关来说,对接的业务网关的信息传递特点是不一样的,大部分的业务在全天都是比较平缓的,但是个别营销类业务会在短时间内发布海量的信息,这样的信息发布会抢占网关的大量资源,对于用户的正常访问会产生影响。

举个例子:push服务需要通过网关推送2亿条消息,而这些消息需要在短时间内全部推送完,而同时网关在为正常的用户的交互提供服务,海量信息的推送和正常的用户交互相互竞争资源,最终会造成正常用户的交互失败,对于业务来说,这是不可接受的。

基于上面的情况考虑,整个网关在布署上分为两个集群:

  • 1)一个集群处理常态的在线用户访问;
  • 2)一个集群处理海量信息的推送。

如下图所示,通过这样的方式,避免了业务形态不同,对统一网关的冲击,将不同的业务形态进行了隔离。

6.2 异地多活

在异地多活的整体方案中,统一网关承担了快速引导流量的职责,也是这一方案顺利实施的一个重要环节。

异地多活是一个多机房的整体方案,在多个地区同时存在对等的多个机房,以用户维度划分,多机房共同承担全量用户的流量;在单个机房发生故障时,故障机房的流量可以快速的被迁引到可用机房,减少故障的恢复时间。

6.2.1)无线接入层单元化的协商机制:

先看一下web端在这异地多活中的实现方式:

从上图可以看到,浏览器的业务器求会发给CDN,由CDN上保存的分发规则,向后续的单元机房分发。

无线端也这样做吗?

  • 1)客户端拥有强大的能力,可以做的更灵活;
  • 2)CDN的分发节点带来更多的机器成本;
  • 3)对于需要双工通讯能力的客户端,消息投递更为复杂。

这些是我们思考与WEB不同的地方,是不是能做些不一样的选择?

如上图所示, 我们借助了客户端的强大能力,利用协商的机制来完成用户的请求正确被分配到不同的单元。

含以下几点:

  • 1)客户端的请求始终带上当前用户归属单元的信息;
  • 2)当请求到达服务端时,服务端判断用户归属单元是否正确,不正确将用户重定向到正确的单元 ;
  • 3)当前请求由网关在服务端上通过跨单元调用保证业务的正确性;
  • 4)当客户端归属单元更新后,后续的请求都会发到正确的单元机房。

6.2.2)无线接入层单元化的旁路调度:

协商机制看起来很不错,这里一个重磅炸弹丢过来了,机房的入口网络断了!

如上图,外网不可用,协商的机会都没有故障单元的用户无法恢复,这时旁路的调度服务出场了。

如上图,我们设计的调度中心这时又承担了单元化的旁路调度职责,当app访问的单元无法访问的时候,app会访问不同单元的调度中心,询问用户的归属单元。通过这种方式取得可用的单元节点,将用户切到正确的单元。这个方案同样适用于单机房的接入层网关不可用的场景。

6.2.3)应用层网关不可用:

某个单元机房的应用层网关不可用,这时等待应用网关排查问题需要的时间比较久,为了达到最快的故障恢复,我们通过开关把修改接入层的转发规则,将流量切到可用的单元。

如下图所示: 

7、端到端网络优化

7.1 统一网络库

在做网络优化一开始,我们想做一个通用的网络库,这个网络库包含策略、httpDNS、SPDY协议等一切系统网络优化需要的方方面面。(如果你对httpDNS不甚了解,可以详读《全面了解移动端DNS域名劫持等杂症:原理、根源、HttpDNS解决方案等》)

上层api网关请求逻辑、推送逻辑、上传下载逻辑对于这样一个通用网络库来说都是业务。在分层上将通用网络库和上层应用逻辑分开、彻底解耦,对长期持续优化网络是很有必要。

如下图所示架构: 

这样架构上分离,可以让我们更专注更系统化去做无线网络优化。

统一网络库的几个重要特性:

  • 1)灵活控制客户端网络行为策略(建连、超时处理、请求协议、是否加密);
  • 2)包含HTTPDNS;
  • 3)支持异地多活;
  • 4)更细粒度控制和调度(域名级和域名下参数级)。

1、2、3、4均由网络调度中心的集群控制,我们希望这个可以做到与业务无关,去掉一些阿里的业务属性后,这个模块大家可以理解为HTTPDNS,可以理解我们在HTTPDNS之外做了大量网络优化的端到端的工作。

7.2 就近就快接入

基于网络库我们实现了一套智能学习的网络策略,智能学习客户端在不同网络环境下建连策略,用户重新回到这个网络环境会给出最优的策略进行快速连接,并定期去更新或淘汰本地cache的历史最优网络策略。

为了建立更加迅速在各自网络下穿透性更好,接入服务器支持了多种协议和端口,客户端建连时可以极速接入网络。

我们有一个重要指标是打开客户端30秒内网络请求成功率,就是关注连的快给用户体验带来的价值。

基于调度中心,我们搭建了一个智能大数据分析平台,将客户端在在网络请求过程中的数据如建连时间、首包收取时间、整包收取时间、ssl握手时间等重要指标收集上来 。根据这些指标分析出网络异常区域,调整我们的就近就快接入规则,甚至推动IDC建设和CDN的布点完善。

7.3 弱网优化和抗抖动

在弱网优化上我们尝试了QUIC协议,在网络延时较高、丢包严重情况下比TCP有更好表现。

线上手机淘宝灰度版本实测切换到QUIC后,平均RT收益有接近20%。考虑QUIC在移动网络可能存在穿透性问题,未来我们将采取SPDY为主,QUIC为辅助的模式来完善我们的网络链接策略。

现在QUIC协议在移动端应用的越来越广泛,有兴趣的话可详细以下文章:

网络编程懒人入门(十):一泡尿的时间,快速读懂QUIC协议

技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解

让互联网更快:新一代QUIC协议在腾讯的技术实践分享

七牛云技术分享:使用QUIC协议实现实时视频直播0卡顿!

同样在一些网络环境较差情况下,我们采取长短链接结合方式,在长链接遇到请求超时或穿透性较差情况,利用短链接HTTP短链接去请求数据(在移动网络环境下HTTP协议尤其HTTP1.0的穿透性是最好的),这样可以在一些极端情况下最大程度保证用户体验。

数据如下图:

网络切换和网络抖动情况下的技术优化也是一个很重要的方面,我们经常遇到移动设备网络切换和信号不稳定的情况,在这种情况我们怎么保证用户的体验?

针对这种情况我们的思路是有策略合理增加重试。我们对一个网络请求以是否发送到socket缓冲区作为分割,将网络请求生命周期划分为“请求开始到发送到 socket缓冲区”和“已经发送到socket缓冲区到请求结束”两个阶段。在阶段一内请求失败了,会根据业务需求帮助业务请求去做重试。阶段二请求失败只针对读操作提供重试能力。

设想一个场景:用户在进电梯发起一个刷新数据请求,进到电梯因为网络抖动的原因网络链接断了,这个时候我们能够合理策略去做重试,这样当用户离开电梯时很可能网络请求重试成功,帮助用户拉到了想要的数据,提升了用户体验和客户端的网络抗抖动能力。

7.4 加密传输1秒钟法则

众所周知的传统https的整个握手流程是非常重的,在网络质量不高的情况下,造成建连过慢,用户体验惨不能睹,甚至都无法完成安全握手。然而从安全的角度我们是需要一个安全的传输通道保护用户的隐私数据。

安全与网络这一对冲突放在我们的面前,需要在技术上有所突破,因此我们自建了一套slight-ssl的技术,参考了tls1.3的协议,通过合并请求,优化加密算法,运用session-ticket等策略,最终在安全和体验之间找到了一个平衡点,在基本不牺牲用户体验的基础上,达到了安全传输的目地, 同时还大幅度提升了服务端的性能。通过技术的创新,我们实现了无线网络加密传输下1秒钟法则。

关于TLS1.3在移动端的应用,也可以详读微信团队分享的这篇《微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解》。

附录:有关移动端弱网方面的资料汇总

IM开发者的零基础通信技术入门(十一):为什么WiFi信号差?一文即懂!

IM开发者的零基础通信技术入门(十二):上网卡顿?网络掉线?一文即懂!

IM开发者的零基础通信技术入门(十三):为什么手机信号差?一文即懂!

IM开发者的零基础通信技术入门(十四):高铁上无线上网有多难?一文即懂!

现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障

聊聊iOS中网络编程长连接的那些事

移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”

移动端IM开发者必读(二):史上最全移动弱网络优化方法总结

全面了解移动端DNS域名劫持等杂症:原理、根源、HttpDNS解决方案等

美图App的移动端DNS优化实践:HTTPS请求耗时减小近半

百度APP移动端网络深度优化实践分享(一):DNS优化篇

百度APP移动端网络深度优化实践分享(二):网络连接优化篇

百度APP移动端网络深度优化实践分享(三):移动端弱网优化篇

爱奇艺移动端网络优化实践分享:网络请求成功率优化篇

美团点评的移动端网络优化实践:大幅提升连接成功率、速度等

5G时代已经到来,TCP/IP老矣,尚能饭否?

微信Mars:微信内部正在使用的网络层封装库,即将开源

如约而至:微信自用的移动端IM网络层跨平台组件库Mars已正式开源

谈谈移动端 IM 开发中登录请求的优化

腾讯原创分享(一):如何大幅提升移动网络下手机QQ的图片传输速度和成功率》 

腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(下篇)》 

腾讯原创分享(三):如何大幅压缩移动网络下APP的流量消耗(上篇)》 

IM开发者的零基础通信技术入门(十一):为什么WiFi信号差?一文即懂!

IM开发者的零基础通信技术入门(十二):上网卡顿?网络掉线?一文即懂!

IM开发者的零基础通信技术入门(十三):为什么手机信号差?一文即懂!

IM开发者的零基础通信技术入门(十四):高铁上无线上网有多难?一文即懂!

>> 更多同类文章 ……

(本文已同步发布于:http://www.52im.net/thread-3110-1-1.html

posted @ 2020-08-19 13:49 Jack Jiang 阅读(294) | 评论 (0)编辑 收藏

1、引言

最近在从头重写 MobileIMSDK 的TCP版,自已组织TCP数据帧时就遇到了字节序大小端问题。所以,借这个机会单独整理了这篇文章,希望能加深大家对字节序问题的理解,加强对IM这种基于网络通信的程序在数据传输这一层的知识掌控情况。

程序员在写应用层程序时,一般不需要考虑字节序问题,因为字节序跟操作系统和硬件环境有关,而我们编写的程序要么不需要跨平台(比如只运行在windows),要么需要跨平台时会由Java这种跨平台语言在虚拟机层屏蔽掉了。

但典型情况,当你编写网络通信程序,比如IM聊天应用时,就必须要考虑字节序问题,因为你的数据在这样的场景下要跨机器、跨网络通信,必须解决不同系统、不同平台的字节序问题。

* 阅读对象:本文属于计算机基础知识,特别适合从事网络编程方面工作(比如IM这类通信系统)的程序员阅读。面视时,面视官一般都会聊到这个知识点。

本文已同步发布于“即时通讯技术圈”公众号,欢迎关注:

▲ 本文在公众号上的链接是:点此进入 ,原文链接是:http://www.52im.net/thread-3101-1-1.html

2、什么是字节序?

字节序,是指数据在内存中的存放顺序,当字节数大于1时需要考虑(只有一个字节的情况下,比如char类型,也就不存在顺序问题啦)。

从下图中,可以直观的感受到什么是字节序问题: 

上图片改编自《C语言打印数据的二进制格式-原理解析与编程实现

3、字节序的分类

字节序常被分为两类:

  • 1)Big-Endian(大端字节序):高位字节排放在内存的低地址端,低位字节排放在内存的高地址端(这是人类读写数值的方法);
  • 2)Little-Endian(小端字节序):低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。

举个具体的例子,0x1234567 的大端字节序和小端字节序写法如下:

如上图所示:大端小端字节序最小单位1字节,即8bit;大端字节序就是和我们平时写法的顺序一样,从低地址到高地址写入0x01234567;而小端字节序就是和我们平时的写法反过来,因为字节序最小单位为1字节,所以从低地址到高地址写入0x67452301。

4、为什么会存在大端、小端字节序问题?

4.1 比较合理的解释

一个比较合理的解释是说:计算机中电路优先处理低位字节,效率比较高,因为计算机都是从低位开始的,所以计算机内部处理都是小端字节序。

而人类人类读写数值的方法,习惯用大端字节序,所以除了计算机的内部处,其他的场理合都是大端字节序,比如:网络传输和文件储存时都是用的大端字节序(关于网络字节序,会在后面继续展开说明)。

大小端字节序问题,最有可能是跟技术算硬件或软件的创造者们,在技术创立之初的一些技术条件或个人习惯有关。

所以大小端问题,体现在实际的计算机工业应用来上,不同的操作系统和不同的芯片类型可能都会有不同。

4.2 常见的操作系统和芯片使用的字节序

具体来说:DEC和Intel的机器(X86平台)一般采用小端,IBM、Motorola(Power PC)、Sun的机器一般采用大端。

当然,这不代表所有情况。有的CPU即能工作于小端, 又能工作于大端,比如:Arm、Alpha、摩托罗拉的PowerPC。 

而且,具体这类CPU是大端还是小端,和具体设置也有关。如:Power PC支持小端字节序,但在默认配置时是大端字节序。

一般来说:大部分用户的操作系统(如:Windows、FreeBsd、Linux)是小端字节序。少部分,如:Mac OS 是大端字节序。

4.3 如何判断用的是什么字节序?

怎么判断我的计算机里使用的是大端还是小端字节序呢?

下面的这段代码可以用来判断计算机是大端的还是小端。判断的思路是:确定一个多字节的值(下面使用的是4字节的整数),将其写入内存(即赋值给一个变量),然后用指针取其首地址所对应的字节(即低地址的一个字节),判断该字节存放的是高位还是低位,高位说明是Big endian,低位说明是Little endian。

#include <stdio.h>

int main ()

{

  unsigned int x = 0x12345678;

  char*c = (char*)&x;

  if(*c == 0x78) {

    printf("Little endian");

  } else{

    printf("Big endian");

  }

  return 0;

}

5、“大端”、“小端”名字由来

根据网上的资料,据说名字的由来跟乔纳森·斯威夫特的著名讽刺小说《格列佛游记》有关。

书中的故事是这样的:一般来说,大家都认为吃鸡蛋前,原始的方法是打破鸡蛋较大的一端。可是当今皇帝的祖父小时候吃鸡蛋,一次按古法打鸡蛋时碰巧将一个手指弄破了,因此他的父亲,当时的皇帝,就下了一道敕令,命令全体臣民吃鸡蛋时打破鸡蛋较小的一端,违令者重罚。

小人国内部分裂成Big-endian和Little-endian两派,区别在于一派要求从鸡蛋的大头把鸡蛋打破,另一派要求从鸡蛋的小头把鸡蛋打破。

小人国国王改变了打开鸡蛋的方位与理由,并由此招致了修改法律、引发战争和宗教改革等一序列事件的发生。

《格列佛游记》中的这则故事,原本是借以讽刺英国的政党之争。而在计算机工业中,也借用了这个故事来代指大家在数据储存字节顺序中的分歧,并把“大端”(Big-endian)、“小端”(Little-endian)的名字,沿用到了计算机中。 

上图片改编自《“字节序”是个什么鬼?

或许,借用这个故事来命名大小端字节序问题,无非就是想告诉大家,所谓的“大端”、“小端”实际上可能无关计算机性能,更多的只是创造者们在创立计算机之初,代入了个人的一些约定俗成的习惯而已。

6、什么是网络字节序?

6.1 字节序问题给网络通信带来的困扰

对于搞网络通信应用(比如IM、消息推送、实时音视频)开发的程序员来说,自已写通信底层的话是一定会遇到大小端问题的,对于网络字节序这个知识点是一定要必知必会。(当然,你要是很没追求的认为,反正我公司就让租租第3方,能用就行,具体通底层怎么写我才不想掉头发去考虑那么多。。。。 那哥也救不了你。。

上面所说的大小端字节序都是在说计算机自己,也被称作主机字节序。同型号计算机上写的程序,在相同的系统上面运行总归是没有问题。

但计算机网络的出现让大小端问题变的复杂化了,因为每个计算机都有自己的主机字节序。不同计算机之间通过网络通信时:我“说”的你听不懂,你“说”我也听不懂,这可怎么办?

6.2 TCP/IP协议强行约定了字节序方案

好消息是,TCP/IP协议很好的解决了这个问题,TCP/IP协议规定使用“大端”字节序作为网络字节序。

这样,即使不使用大端的计算机也没有关系,因为发送数据的时候可以将自己的主机字节序转换为网络字节序(即“大端”字节序),对接收到的数据转换为自己的主机字节序。这样一来,也就达到了与CPU、操作系统无关,实现了网络通信的标准化。

具体的原理就是:

  • 1)TCP/IP协议会把接收到的第一个字节当作高位字节看待,这就要求发送端发送的第一个字节是高位字节;
  • 2)而在发送端发送数据时,发送的第一个字节是该数值在内存中的起始地址处对应的那个字节。

也就是说,该数值在内存中的起始地址处对应的那个字节就是要发送的第一个高位字节(即:高位字节存放在低地址处)。由此可见,多字节数值在发送之前,在内存中就是以大端法存放的。

所以说,网络字节序就是大端字节序。

6.3 主机字机序到网络字节序的转换

那么,为了程序的兼容,程序员们每次发送和接受数据都要进行转换,这样做的目的是保证代码在任何计算机上执行时都能达到预期的效果。

通信时的这种常用的操作,Socket API这一层,一般都提供了封装好的转换函数,方便程序员使用。比如从主机字节序到网络字节序的转换函数:htons、htonl(C语言中常用),从网络字节序到主机字节序的转换函数:ntohs、ntohl(C语言中常用)。当然,也可以编写自己的转换函数。

7、实践中的大小端字节序处理

在我编写MobileIMSDK的TCP版时(MobileIMSDK是我开源的IM通信层库),同样遇到了大小端字节序问题。

以MobileIMSDK的iOS端拼装网络数据收发的代码为例:

如上图代码所示,注意以下两个大小端转换函数的使用:

  • 1)第27行“CFSwapInt32HostToBig”函数:网络发出数据之前,先将主机字节序转为网络字节序(即大端字节序);
  • 2)第53行“CFSwapInt32BigToHost”函数:收到原始网络数据后,转为主机字节序后就可以在程序中正常使用了。

如果对网络大小端转换这方面的实践感兴趣,可以自已去下载MobileIMSDK源码试一试:https://github.com/JackJiang2011/MobileIMSDK

8、参考资料

[1] “字节序”是个什么鬼?

[2] 大小端及网络字节序

[3] C语言打印数据的二进制格式-原理解析与编程实现

附录:系列文章

本文是系列文章中的第9篇,本系列大纲如下:

脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手

脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

脑残式网络编程入门(三):HTTP协议必知必会的一些知识

脑残式网络编程入门(四):快速理解HTTP/2的服务器推送(Server Push)

脑残式网络编程入门(五):每天都在用的Ping命令,它到底是什么?

脑残式网络编程入门(六):什么是公网IP和内网IP?NAT转换又是什么鬼?

脑残式网络编程入门(七):面视必备,史上最通俗计算机网络分层详解

脑残式网络编程入门(八):你真的了解127.0.0.1和0.0.0.0的区别?

脑残式网络编程入门(九):面试必考,史上最通俗大小端字节序详解》(本文)

(本文同步发布于:http://www.52im.net/thread-3101-1-1.html

posted @ 2020-08-13 14:58 Jack Jiang 阅读(285) | 评论 (0)编辑 收藏

本文作者网易智慧企业web前端开发工程师马莹莹。为了提升内容质量,收录时有修订和改动。

1、引言

在一个完善的即时通讯IM应用中,WebSocket是极其关键的一环,它为基于Web的即时通讯应用提供了一种全双工的通信机制。但为了提升IM等实际应用场景下的消息即时性和可靠性,我们需要克服WebSocket及其底层依赖的TCP连接对于复杂网络情况下的不稳定性,即时通讯的开发者们通常都需要为其设计一套完整的连接保活、验活以及断片网重连方案。

就断网重连而言,其重连响应速度将严重影响了上层应用的“即时性”和用户体验。试想打开网络一分钟后,微信的网络不能即时感知到socket连接的恢复,无法即时收发聊天消息的话,是不是很崩溃?

因此,如何在复杂网络场景下,更即时快速地感知网络变动,并快速恢复WebSocket的可用性,就变得尤为重要。本文将基于笔者的开发实践,分享WebSocket在不同状态下、不同的网络状态下,应该如何实现快速断网重连。

* 阅读对象:本文适合有过IM底层网络实际开发经验,或者对底层网络实现有较深了解的开发者阅读。如果对底层网络了解甚少,建议跳过本文,直接阅读网络本文末尾附录部分的基础后再回头来看。

* 内容点评:本文内容没有高大上,但比较干货,实用性较高,内容也很通俗,建议可详细阅读。文中虽讲的是WebSocket,但思想可以延伸应用到基于TCP协议的同类技术中。

本文已同步发布于“即时通讯技术圈”公众号,欢迎关注:

▲ 本文在公众号上的链接是:点此进入原文链接是:http://www.52im.net/thread-3098-1-1.html

2、预备知识

本文中将要分享的内容是基于实践总结,如果你对Web端的即时通讯知识还一头雾水,务必先读:《新手入门贴:史上最全Web端即时通讯技术原理详解》、《Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE》。

限于篇幅,本文不会深究WebSocket技术细节,如有兴趣请系统学习:

3、快速了解WebSocket

Websocket诞生于2008年,在2011年成为国际标准,现在所有的浏览器都已支持(详见《新手快速入门:WebSocket简明教程》)。它是一种全新的应用层协议,是专门为web客户端和服务端设计的真正的全双工通信协议,可以类比HTTP协议来了解websocket协议。

图片引用自《WebSocket详解(四):刨根问底HTTP与WebSocket的关系(上篇)

它们的不同点:

  • 1)HTTP的协议标识符是http,WebSocket的是ws;
  • 2)HTTP请求只能由客户端发起,服务器无法主动向客户端推送消息,而WebSocket可以;
  • 3)HTTP请求有同源限制,不同源之间通信需要跨域,而WebSocket没有同源限制。

它们的相同点:

  • 1)都是应用层的通信协议;
  • 2)默认端口一样,都是80或443;
  • 3)都可以用于浏览器和服务器间的通信;
  • 4)都基于TCP协议。

两者和TCP的关系图:

图片引用自《新手快速入门:WebSocket简明教程

有关Http和WebSocket的关系,可以详读:

有关WebSocket和Socket的关系,可以详读:《WebSocket详解(六):刨根问底WebSocket与Socket的关系》.

4、WebSocket重连过程拆解

首先考虑一个问题,何时需要重连?

最容易想到的是WebSocket连接断了,为了接下来能收发消息,我们需要再发起一次连接。

但在很多场景下,即便WebSocket连接没有断开,实际上也不可用了。

比如以下场景:

  • 1)设备切换网络;
  • 2)链路中间路由崩溃(常识是一条socket连接对应的网络通路上,会存在很多路由设备);
  • 3)链路的前端出口不可用(比如家庭WiFi中,网络连接正常,但实际运营商的宽带已经欠费被停机);
  • 4)服务器负载持续过高无法响应等。

这些场景下的WebSocket都没有断开,但对上层来说,都没办法正常的收发数据了。

因此在重连前,我们需要一种机制来感知连接是否可用、服务是否可用,而且要能快速感知,以便能够快速从不可用状态中恢复。

一旦感知到了连接不可用,那便可以弃旧图新了,弃用并断开旧连接,然后发起一次新连接。这两个步骤看似简单,但若想达到快,且不是那么容易的。

首先:是断开旧连接,对客户端来说,如何快速断开?协议规定客户端必须要和服务器协商后才能断开WebSocket连接,但是当客户端已经联系不上服务器、无法协商时,如何断开并快速恢复?

其次:是快速发起新连接。此快非彼快,这里的快并非是立即发起连接,立即发起连接会对服务器带来不可预估的影响。重连时通常会采用一些退避算法,延迟一段时间后再发起重连。但如何在重连间隔和性能消耗间做出权衡?如何在“恰当的时间点”快速发起连接?

带着这些疑问,我们来细看下这三个过程:

5、快速重连关键1:快速感知何时需要重连

5.1 场景

需要重连的场景可以细分为三种:

  • 1)连接明确断开了;
  • 2)连接没断但是不可用了;
  • 3)连接对端的服务不可用了。

对于第一种场景:这很简单,连接直接断开了,肯定需要重连了。

对于后两者:无论是连接不可用,还是服务不可用,对上层应用的影响都是不能再收发即时消息了。

5.2 心跳包主动探测网络可用性

所以从上面这个角度出发,感知何时需要重连的一种简单粗暴的方法就是通过心跳包超时:发送一个心跳包,如果超过特定的时间后还没有收到服务器回包,则认为服务不可用,如下图中左侧的方案(这种方法最直接)。

那如果想要快速感知呢,就只能多发心跳包,加快心跳频率。但是心跳太快对移动端流量、电量的消耗又会太多,所以使用这种方法没办法做到快速感知,可以作为检测连接和服务可用的兜底机制。

5.3 被动监听网络状态改变

如果要检测连接不可用,除了用心跳检测,还可以通过判断网络状态来实现,因为断网、切换wifi、切换网络是导致连接不可用的最直接原因,所以在网络状态由offline变为online时,大多数情况下需要重连下,但也不一定,因为webscoket底层是基于TCP的,TCP连接不能敏锐的感知到应用层的网络变化,所以有时候即便网络断开了一小会,对WebSocket连接是不会有影响的,网络恢复后,仍然能够正常地进行通信。

因此在网络由断开到连接上时,立即判断下连接是否可用,可以通过发一个心跳包判断,如果能够正常收到服务器的心跳回包,则说明连接仍是可用的,如果等待超时后仍没有收到心跳回包,则需要重连,如上图中的右侧。这种方法的优点是速度快,在网络恢复后能够第一时间感知连接是否可用,不可用的话可以快速执行恢复,但它只能覆盖应用层网络变化导致WebSocket不可用的情况。

5.4 小结

综上所述:

  • 1)定时发送心跳包检测的方案贵在稳定,能够覆盖所有场景,但速度不即时(心跳间隔是固定的);
  • 2)判断网络状态的方案速度快,无需等待心跳间隔,较为灵敏,但覆盖场景较为局限。

因此,我们可以结合两种方案:

  • 1)定时以不太快的频率发送心跳包,比如40s/次、60s/次等,具体可以根据应用场景来定;
  • 2)然后在网络状态由offline变为online时立即发送一次心跳,检测当前连接是否可用,不可用的话立即进行恢复处理。

这样在大多数情况下,上层的应用通信都能较快从不可用状态中恢复,对于少部分场景,有定时心跳作为兜底,在一个心跳周期内也能够恢复。

6、快速重连关键2:快速断开旧连接

通常情况下,在发起下一次连接前,如果旧连接还存在的话,应该先把旧连接断开。

这样做的目的:

  • 1)一来可以释放客户端和服务器的资源;
  • 2)二来可以避免之后误从旧连接收发数据。

我们知道WebSocket底层是基于TCP协议传输数据的,连接两端分别是服务器和客户端,而TCP的TIME_WAIT状态是由服务器端维持的,因此在大多数正常情况下,应该由服务器发起断开底层TCP连接,而不是客户端。

也就是说:

  • 1)要断开WebSocket连接时,如果是服务器收到指示要断开WebSocket,那它应该立即发起断开TCP连接;
  • 2)如果是客户端收到指示要断开WebSocket,那它应该发信号给服务器,然后等待底层TCP连接被服务器断开或直至超时。

那如果客户端想要断开旧的WebSocket,可以分为WebSocket连接可用和不可用两种情况来讨论。

具体如下:

  • 1)当旧连接可用时,客户端可以直接给服务器发送断开信号,然后服务器发起断开连接即可;
  • 2)当旧连接不可用时,比如客户端切换了wifi,客户端发送了断开信号,但是服务器收不到,客户端只能迟迟等待,直至超时才能被允许断开。

超时断开的过程相对来说是比较久的,那有没有办法可以快点断开?

上层应用无法改变只能由服务器发起断开连接这种协议层面的规则,所以只能从应用逻辑入手,比如在上层通过业务逻辑保证旧连接完全失效,模拟连接断开,然后在发起新连接,恢复通讯。

这种方法相当于尝试断开旧连接不行时,直接弃之,然后就能快速进入下一流程,所以在使用时一定要确保在业务逻辑上旧连接已完全失效。

比如:

  • 1)保证丢掉从旧连接收到所有数据;
  • 2)旧连接不能阻碍新连接的建立
  • 3)旧连接超时断开后不能影响新连接和上层业务逻辑等等。

7、快速重连关键3:快速发起新连接

有IM开发经验的同学应该有所了解,遇到因网络原因导致的重连时,是万万不能立即发起一次新连接的,否则当出现网络抖动时,所有的设备都会立即同时向服务器发起连接,这无异于黑客通过发起大量请求消耗网络带宽引起的拒绝服务攻击,这对服务器来说简直是灾难(即:服务端雪崩效应)。

所以在重连时通常采用一些退避算法,延迟一段时间再发起重连,如下图中左侧的流程。

如果要快速连上呢?最直接的做法就是缩短重试间隔,重试间隔越短,在网络恢复后就能越快的恢复通讯。但是太频繁的重试对性能、带宽、电量的消耗就比较严重。

如何在这之间做一个较好的权衡呢?

  • 1)一种比较合理的方式是随着重试次数增多,逐渐增大重试间隔;
  • 2)另一方面监听网络变化,在网络状态由offline变为online这种比较可能重连上的时刻,适当地减小重连间隔。

上述第2)种方案,如上图中的右侧所示,随重试次数的增多,重连间隔也会变大。这两种方式配合使用,更为合理。

除此之外,还可以结合业务逻辑,根据成功重连上的可能性适当的调整间隔,如网络未连接时或应用在后台时重连间隔可以调大一些,网络正常的状态下可以适当调小一些等等,加快重连上的速度。

8、本文小结

最后总结一下。

本文将WebSocket断网重连逻辑细分为三个步骤:

  • 1)确定何时需要重连;
  • 2)断开旧连接;
  • 3)发起新连接。

然后分别分析了在WebSocket的不同状态下、不同的网络状态下,如何快速完成这个三个步骤。

过程具体总结就是:

  • 1)首先:通过定时发送心跳包的方式检测当前连接是否可用,同时监测网络恢复事件,在恢复后立即发送一次心跳,快速感知当前状态,判断是否需要重连;
  • 2)其次:正常情况下由服务器断开旧连接,与服务器失去联系时直接弃用旧连接,上层模拟断开,来实现快速断开;
  • 3)最后:发起新连接时使用退避算法延迟一段时间再发起连接,同时考虑到资源浪费和重连速度,可以在网络离线时调大重连间隔,在网络正常或网络由offline变为online时缩小重连间隔,使之尽可能快地重连上。

以上就是我关于如何实现WebSocket快速重连的技术分享,欢迎留言与我探讨。

9、参考资料

[1] RFC 6455 文档

[2] 新手快速入门:WebSocket简明教程

[3] WebSocket详解(四):刨根问底HTTP与WebSocket的关系(上篇)

[4] WebSocket详解(五):刨根问底HTTP与WebSocket的关系(下篇)

[5] WebSocket详解(六):刨根问底WebSocket与Socket的关系

附录:更多Web端即时通讯资料

新手入门贴:史上最全Web端即时通讯技术原理详解

Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE

SSE技术详解:一种全新的HTML5服务器推送事件技术

Comet技术详解:基于HTTP长连接的Web端实时通信技术

socket.io实现消息推送的一点实践及思路

LinkedIn的Web端即时通讯实践:实现单机几十万条长连接

Web端即时通讯技术的发展与WebSocket、Socket.io的技术实践

Web端即时通讯安全:跨站点WebSocket劫持漏洞详解(含示例代码)

开源框架Pomelo实践:搭建Web端高性能分布式IM聊天服务器

使用WebSocket和SSE技术实现Web端消息推送

详解Web端通信方式的演进:从Ajax、JSONP 到 SSE、Websocket

MobileIMSDK-Web的网络层框架为何使用的是Socket.io而不是Netty?

理论联系实际:从零理解WebSocket的通信原理、协议格式、安全性

微信小程序中如何使用WebSocket实现长连接(含完整源码)

八问WebSocket协议:为你快速解答WebSocket热门疑问

快速了解Electron:新一代基于Web的跨平台桌面技术

一文读懂前端技术演进:盘点Web前端20年的技术变迁史

Web端即时通讯基础知识补课:一文搞懂跨域的所有问题!

Web端即时通讯实践干货:如何让你的WebSocket断网重连更快速?

>> 更多同类文章 ……

(本文同步发布于:http://www.52im.net/thread-3098-1-1.html

posted @ 2020-08-05 15:36 Jack Jiang 阅读(366) | 评论 (0)编辑 收藏

本文由有赞技术团队原创分享,原题“有赞 APP IM SDK 组件架构设计”,即时通讯网收录时有修订和改动,感谢原作者的无私分享。

1、引言

本文主要以Android客户端为例,记录了有赞旗下 App 中使用自研 IM,并将IM提炼成组件化SDK的设计思路。此项工作由有赞移动开发组 IM SDK 团队共同讨论完成。

 

在有赞产品中,存在大量需要交易双方沟通交流的场景,比如,客户咨询商家产品信息,售前售后简单的答疑和维权等。另外,有赞业务还存在一些特殊的复杂场景,如供应商、分销商、客户三方之间需要同步沟通,会同时存在多种沟通角色。

此时需要较为完善的即时通信(IM)解决方案,但是由于有赞针对不同的商户和使用场景有多个APP,APP自行实现IM功能代价较大,且维护起来人力分散,于是,IM SDK项目便应运而生了,APP 通过接入此给件化SDK,可以快速实现IM基本功能。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170[推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

本文已同步发布于“即时通讯技术圈”公众号,欢迎关注:

▲ 本文在公众号上的链接是:https://mp.weixin.qq.com/s/ANp1kuj65Ww5RpABl2M9RQ,原文链接是:http://www.52im.net/thread-3088-1-1.html

2、相关文章

从游击队到正规军(一):马蜂窝旅游网的IM系统架构演进之路

从游击队到正规军(二):马蜂窝旅游网的IM客户端架构演进和实践总结》(* 推荐

从游击队到正规军(三):基于Go的马蜂窝旅游网分布式IM系统技术实践

一套海量在线用户的移动端IM架构设计实践分享(含详细图文)

从零到卓越:京东客服即时通讯系统的技术架构演进历程

一套原创分布式即时通讯(IM)系统理论架构方案

蘑菇街即时通讯/IM服务器开发之架构选择

自已开发IM有那么难吗?手把手教你自撸一个Andriod版简易IM (有源码)

适合新手:从零开发一个IM服务端(基于Netty,有完整源码)

拿起键盘就是干:跟我一起徒手开发一套分布式IM系统

3、设计目标

本次IM组件化SDK的设计目标有以下几点:

  • 1)IM 主流程稳定可用:消息传输具有高可靠性;
  • 2)UI 组件直接集成进入SDK,并支持可定制化;
  • 3)富媒体发送集成进入SDK,并可按需定制需要的富媒体类型;
  • 4)实现消息传输层SDK,与带有UI的SDK的功能分离,业务调用方既可以使用消息传输SDK,处理消息,然后自行处理UI,也可以使用带有UI组件的SDK,一步实现较为完备的IM功能。

4、整体结构

下图中简要描述了有赞客户端中IM系统的基本结构 : 

如上图所示,各分层的职责分工如下:

  • 1)消息通道层:维护Socket长连接作为消息通道,消息收发流程主要在这一层中完成;
  • 2)持久化层:主要将消息存入数据库中,富媒体文件存入文件缓存中,方便第二次展示消息时候,从本地加载,而不是网络层获取;
  • 3)逻辑处理层:完成各种消息相关的逻辑处理,如排序,富媒体文件的预处理等;
  • 4)UI显示层:将数据在UI上进行呈现。

5、设计要点1:Socket长连接的创建与维护

IM SDK 所有数据收发流程,均通过Socket长连接完成,如何维护一个稳定Socket通道,是IM系统是否稳定的重要一环。 

下面描述下Socket通道几个重要的流程。

1)创建流程(连接) :

如图上所示,当IM SDK初始化后,业务调用连接请求接口,会开始连接的创建过程,创建成功后,会完成鉴权操作,当创建和鉴权都完成后,会开启消息收发线程,为了维持长连接,会有心跳机制,特别的,会开启一个心跳轮询线程。

2)心跳机制 :

心跳机制,是IM系统设计中的常见概念,简单的解释就是每隔若干时间发送一个固定信息给服务端,服务端收到后及时回复一个固定信息,如果服务端若干时间内没有收到客户端心跳信息则视客户端断开,同理如果客户端若干时间没有收到服务端心跳回值则视服务端断开。 

 

当长连接创建成功后,会开启一个轮询线程,每隔一段时间发送心跳消息给服务器端,以维持长连接。

有关IM心跳方面的专项文章,请见:

手把手教你用Netty实现网络通信程序的心跳机制、断线重连机制

为何基于TCP协议的移动端IM仍然需要心跳保活机制?

移动端IM实践:实现Android版微信的智能心跳机制

移动端IM实践:WhatsApp、Line、微信的心跳策略分析

一文读懂即时通讯应用中的网络心跳包机制:作用、原理、实现思路等

正确理解IM长连接的心跳及重连机制,并动手实现(有完整IM源码)

一种Android端IM智能心跳算法的设计与实现探讨(含样例代码)

手把手教你用Netty实现网络通信程序的心跳机制、断线重连机制

3)重连流程 :

重连被触发时,如果该次连接成功,退出重连。反之重连失败后,会判断当前重连的次数是否超过预期值(这里设为6次),并对重连次数计数,如果超过就会退出重连,反之休眠预设的时间后再次进行重连操作。

重连触发条件分为三种:

  • a. 主动连接不成功(主动连接Socket,如果连接失败,会触发重连机制);
  • b. 网络被主动断开(正常建立连接,操作过程中,网络被断开,通过系统广播触发重连);
  • c. 服务器没响应,心跳没回值(服务端心跳预设时间内没回值,客户端认为服务端已经断开,触发重连)。

有关重连机制的深入学习,可以阅读以下两篇:

4)网络状态判断:

TCP API并没有提供一个可靠的方法判断当前长连接通道状态,isConnected()和isClosed()仅仅告诉你当前的Socket状态,不是是长连接断开是一回事。 isConnected()告诉你是否Socket与Romote host保持连接,isClosed()告诉你是否Socket被关闭。 

假如你判断长连接通道是否被关闭,只能通过和流操作相关的以下方法:

  • a. read() return -1;
  • b. readLine() return null;
  • c. readXXX() throw EOPException for any other XXX;
  • d. write 将抛出IOException: Broken pipe(通道被关闭)。

所以SDK封装isConnected(方法的时候,是根据这几种情况综合判断当前的通道状态,而不是仅仅通过Socket.isConnected()或者Socket.isClosed()。

6、设计要点2:消息发送流程

消息发送流程主要有两大类:

1)一类是IM相关数据的请求,例如:历史消息列表,会话列表等;

2)另一类是IM消息的发送,主要是文字消息。

富媒体消息发送,会将富媒体文件先上传服务器后,拿到文件URL, 通过文字消息,将此URL发给接收方,接收方下载后进行UI展示)。 

以上两类消息发送,均使用上图的流程进行发送,可通过发送回调感知请求的结果。

如上图所示,消息发送流程,需要先封装消息请求,在通过发送队列发送至服务器,发送前,在将请求id和对应回调存入本地Map数据结构中。

if(requestCallBack != null) { 

  mCallBackMap.put(requestId, requestCallBack);

}

之后接收服务器推送消息(此消息带有发送请求时的请求id),在本地的Map数据找到请求id对应的回调,然后通过回调返回服务器推送过来的数据。 

请求可以通过泛型指定返回值类型,SDK中会自行解析服务器数据返回的数据,直接返回给业务调用方model对象,方便使用。(目前支持json格式的数据解析)

private void IMResponseOnSuccess(String requestid, String response) { 

        if(mCallBackMap != null) {

           IMCallBack callBack = mCallBackMap.get(requestid);

           if(callBack == null) {

               return;

           }

           if(callBack instanceofJsonResultCallback) {

               finalJsonResultCallback resultCallback = (JsonResultCallback) callBack;

               if(resultCallback.mType == String.class) {

                   callBack.onResponse(response);

               } else{

                   Object object = newGson().fromJson(response, resultCallback.mType);

                   callBack.onResponse(object);

               }

               removeCallBack(requestid);

           }

        }

}

如下的示例中,展示了一个获取会话列表的请求,可以看出目前的请求封装,和一些第三方的的网络库类似,使用起来较为方便。

RequestApi requestApi = new RequestApi(IMConstant.REQ_TYPE_GET_CONVERSATION_LIST, Enums Manager.IMType.IM_TYPE_WSC.getRequestChannel());

 

requestApi.addRequestParams("limit", 100); 

requestApi.addRequestParams("offset", 0);

 

IMEngine.getInstance().request(requestApi, newJsonResultCallback<List<ConversationEntity>>() { 

    @Override

    publicvoidonResponse(List<ConversationEntity> response) {

        mSwipeRefreshLayout.setRefreshing(false);

        mAdapter.mDataset.clear();

        mAdapter.mDataset.addAll(response);

        mAdapter.notifyDataSetChanged();

    }

 

    @Override

    publicvoidonError(intstatusCode) {

        //do something

    }

});

可以看出,该请求直接返回了一个会话类型的List集合,业务方可直接使用。

7、设计要点3:消息接收流程

消息的监听流程主要使用了一个全局监听的方式来进行,需要先注册监听器,监听器中有默认的回调。

public interface IMListener { 

    /**

     * 连接成功

     */

    void connectSuccess();

 

    /**

     * 连接失败

     */

    void connectFailure(EnumsManager.DisconnectType type);

 

    /**

     * 鉴权成功

     */

    void authorSuccess();

 

    /**

     * 鉴权失败

     */

    void authorFailure();

 

    /**

     * 接收数据成功

     */

    void receiveSuccess(int reqType, String msgId, String requestChannel, String message, int statusCode);

 

    /**

     * 接收数据失败

     */

    void receiveError(int reqType, String msgId, String requestChannel, int statusCode);

}

该监听器中可以接收如下类型的消息:

  • 1)Socket连接状态的返回结果;
  • 2)鉴权状态的返回结果,(鉴权流程因有赞业务需要);
  • 3)接收的IM消息,或者其他类型的返回消息。可根据消息类型进行后续的分发处理。

业务如需使用此全局监听器,需要自行实现此接口,并在业务初始化时,注册此监听器即可。SDK中会根据注册的监听器,在读取到服务器推送消息后,直接通过监听器到回调进行分发。

private void distributeData(IMEntity imEntity) { 

        if(mIMListener != null&& imEntity != null) {

       // 省略部分逻辑代码

       ……

       if(status == Response.SUCCESS) {

           switch(responseModel.reqType) {

               caseIMConstant.REQ_TYPE_AUTH: // 鉴权成功

                   mIMListener.authorSuccess();

                   return;

 

               caseIMConstant.REQ_TYPE_OFFLINE: //  服务端踢客户端下线

                   mIMListener.connectFailure(EnumsManager.DisconnectType.SERVER);

                   break;

 

               caseIMConstant.REQ_TYPE_HEARTBEAT: // 心跳成功

               caseIMConstant.REQ_TYPE_RECEIVER_MSG: // 收到回调消息

                   handleMessageID(responseModel.body);

                   break;

               default:

                   break;

           }

           mIMListener.receiveSuccess(responseModel.reqType, msgId, responseModel

                   .requestChannel, responseModel.body, 0);

       } else{

           mIMListener.receiveError(responseModel.reqType, msgId, responseModel

                   .requestChannel, status);

       }

   }

}

部分接收消息,如心跳,多端登录时被踢下线通知等,sdk内部会自行处理,业务基本无感知。

8、设计要点4:可定制化的UI

随着公司规模的扩大与业务线的快速迭代,可能新的业务也需要 IM 这个功能,众所周知,IM UI 功能的嵌入会占据大量的开发与调试时间, 为了解决这个痛点,决定将 IM UI 部分抽成一个 Library,实现可定制与单独维护,做到真正的敏捷开发与快速迭代。

8.1 UIKit设计 

IM UIKit暴露相应的api接口,业务方注入相应的功能定制项,针对UI的点击回调通过EventBus总线post分发,减少了业务方与UIKit的耦合,底层业务方通过MVP模式对View与Model进行解耦。

定制项一般通过如下几种方式。

1)XML(定制业务信息,资源信息,显示条数,各个业务功能开关等):

<?xml version="1.0" encoding="utf-8"?>

<resources>

    <stylename="limit">

        <!--每屏展示的条数-->

        <itemname="swiplimit">5</item>

        ......

    </style>

    ......

    ......

    <stylename="itembox">

        <itemname="showvoice">true</item>

        ......

        ......

        <itemname="more"show="true">

            <more>

                <iconstyle="mipmap">im_plus_image</icon>

                <itemname>测试</itemname>

                <callback>false</callback>

            </more>

             ......

             ......

            <more>

                <iconstyle="mipmap">ic_launcher</icon>

                <itemname>测试</itemname>

                <callback>true</callback>

            </more>

        </item>

        ......

        ......

    </style>

</resources>

2)Style(定制UI背景,气泡颜色,字体大小等):

<?xml version="1.0" encoding="utf-8"?>

<resources>

    <!--im 聊天背景-->

    <stylename="imui_background">

        <itemname="android:background">@android:color/holo_red_dark</item>

    </style>

    ......

    ......

 

    <!--气泡背景-->

    <stylename="bubble_background">

        <itemname="android:background">@mipmap/bubble_right_green</item>

    </style>

 

       <!--背景和和字段颜色定制-->

    <stylename="bg_and_textcolor"parent="bubble_background">

        <itemname="android:textColor">@android:color/holo_red_dark</item>

    </style>

    ......

    ......

</resources>

3)Model定制(传入预设的定制Model模板填入相应参数,UIKit里面做相应解析):

public class Entity {

    publicString action1;

    publicString action2;

    publicString aciton3;

    ......

}

8.2 UIKit 支持的富媒体类型

除了文字消息之外,现在主流的IM系统中也支持各种富媒体发送,在有赞IM SDK UIKit中,目前也支持几种富媒体发送。 以下是发送流程图和两类常见富媒体消息简介。

  • 1)语音消息:除了使用常见的录制和解码播放的技术之外。还利用了 AudioManager 中 requestAudioFocus,abandonAudioFocus 相关方法,实现了录制和播放语音消息,如果有第三方播放音乐,会自动暂停,录制和播放语音消息结束后,声音会自动播放。
  • 2)图片消息:通过七牛服务器设置了缩略图,接收方收到消息后,会先下载缩略图,当用户再点击进入图片详情页时,会下载大图,Andorid客户端使用Picasso加载库加载图片,并做本地缓存。

9、设计要点5:UI 中聊天会话数据加载策略

参考业界主流的IM系统方案,用户聊天时,需要将已经发送和接收到的聊天信息保存到本地,而不是每次都拉取历史数据。以达到节约流量和无网络状态下也查看数据的效果。

为此IM SDK持久化层的数据库中,也实现了简单存储加载机制,下面描述典型的数据加载场景。

1)IM会话首次请求数据流程:

2)IM下拉获取历史数据流程: 

3)IM单条消息发送持久化方案:

4)IM单条数据重发流程: 

10、设计不足之处

1)消息回执:

当前的设计方案中,没有消息回执的机制,也就是说接受方收到消息后,不会返回服务器收到消息的通知,服务器无法判断消息是否推送成功,这样在突然断网,网络模式切换,或者弱网环境下,会影响消息的到达率。 

一种可行的设计方式是,发送方增加已送到和未送达的状态,接收方收到消息后,给服务器返回已收到消息的通知,服务器再推送给发送方该状态,如果没有收到接收方回执,服务器可尝试重新推送。发送方接受到接收方的收到回执后,更新发送状态已发送,如果未收到,则显示未送达。为了防止接收方回执丢失,接收方接收消息时候,可维护本地去重队列。

2)本地请求超时的判断:

本地发起的请求,没有用定时器,完全依赖服务器返回或者出现Socket通道异常后上抛的通知作为超时判断,部分场景可能覆盖不到,需要对请求增加固定的超时处理机制,固定时候未收到请求,即认为超时。

* 推荐学习:针对以上两点不足,感兴趣的读者,可以研究一下MobileIMSDK开源工程源码https://github.com/JackJiang2011/MobileIMSDK,MobileIMSDK已经实现了完整的消息送达保证机制(包括:ACK回执、重传、去重、超时判定等等)。

(本文同步发布于:http://www.52im.net/thread-3088-1-1.html

posted @ 2020-07-29 14:09 Jack Jiang 阅读(227) | 评论 (0)编辑 收藏

     摘要: 本文引用自公众号“开发的猫”,本次收录时有改动,感谢原作者“开发的猫”的分享。1、引言随着移动网络速度越来越快、质量越来越来,实时音视频技术已经在各种应用场景下全面开花,语音通话、视频通话、视频会议、远程白板、远程监控等等。实时音视频技术的开发也越来越受到重视,但是由于音视频开发涉及知识面比较广,入门门槛相对较高,让许许多多开发者望而生畏。虽然网上有...  阅读全文

posted @ 2020-07-24 14:13 Jack Jiang 阅读(364) | 评论 (0)编辑 收藏

1、点评

IM聊天消息的可靠投递,是每个线上产品都要考虑的IM热点技术问题。

IM聊天消息能保证可靠送达,对于用户来说,就好比把钱存在银行不怕被偷一样,是信任的问题。试想,如果用户能明显感知到聊天消息无法保证送达,谁还愿意来用你的APP?谁也不希望自已的话就像浮云一样随风飘逝。

必竟用IM聊天,虽然很多时候是费话,但总有关键时刻存在——比如向女神表白(哪怕明知被拒),作为合格的舔狗一定不希望女神错过这条消息。

所以,消息的可靠投递是每款IM产品和立足之本,也是IM开发者们孜孜不倦追求的技术目标。

本文作者将以自已IM开发过程中的真实总结,分享针对大量离线聊天消息,在确保用户端体验不降级的前提下,保证离线消息的可靠投递。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170[推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

本文已同步发布于“即时通讯技术圈”公众号,欢迎关注:

▲ 本文在公众号上的链接是:https://mp.weixin.qq.com/s/T2w9h_AN_T2UnqNdVikX0Q,原文链接是:http://www.52im.net/thread-3069-1-1.html

 

2、本文作者 

fzully(柳林勇):2005年数学系毕业,先后就职于福建新大陆、福建富士通、北京世纪奥通。长期从事服务端软件开发,涉及SIP服务器、内核RTP转送、电信级AAA认证系统、IM即时通讯系统等。在分布式高性能系统设计有多年经验积累。

本作者的另一篇:《IM群聊消息的已读未读功能在存储空间方面的实现思路探讨》也已被即时通讯网收录并整理发布,有兴趣可以前往阅读。

3、相关文章

从客户端的角度来谈谈移动端IM的消息可靠性和送达机制

移动端IM中大规模群消息的推送如何保证效率、实时性?

IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

IM消息送达保证机制实现(二):保证离线消息的可靠投递》(* 强烈推荐

如何保证IM实时消息的“时序性”与“一致性”?

一个低成本确保IM消息时序的方法探讨

IM群聊消息如此复杂,如何保证不丢不重?》(* 强烈推荐

移动端IM登录时拉取数据如何作到省流量?》(* 强烈推荐

完全自已开发的IM该如何设计“失败重试”机制?

IM开发干货分享:我是如何解决大量离线消息导致客户端卡顿的》(* 强烈推荐

4、正文引言

暗恋女神良久,终于鼓起勇气决定向女神写一封情书。但如何表达才能感动女神?自感才疏学浅,于是通读四书五经、熟背唐诗宋词、遍览四大名著,已然腹有诗书气自华。一周末冥思苦想整日才写就一首七言律诗,虽无惊天地泣鬼神之势,但诚挚的爱念在字里行间里流淌,亦歌亦诗,相信会感动到女神,手机欣然发出。

发出一秒后,手心冒汗,感觉脸颊发烫,心脏像受惊吓的野兔一样快速跳动,就像第一次看见女神那时的感觉。闭着眼睛,想象女神看到消息时的情形,她是否也期盼我的表白?看到消息时是否心跳加速、小脸绯红?

一分钟后,紧盯手机屏幕,等待、期盼女神回复。

时间一分一秒地逝去,等一分钟像等一年一样漫长。

一小时后,仍然杳无音讯,难道她没看到消息么?或许在忙什么而没留意手机吧!

一天过去了,坐立不安,等待是一种痛苦的煎熬,期待和煎熬在心中交织翻滚,有几个瞬间甚至希望女神赶快拒绝自己,好让自己解脱!茶饭无味,失眠多天,整日魂不守舍。

一个月过去了,死心。

半年后,女神出嫁,婚礼那天前去祝福。席间亦随众觥筹交错,略有醉意,向女神敬酒:祝福你,但愿以后能遇见像你这样的女人。女神先是愣住、收起笑容,低下头,目光无神地看着大红地毯,长叹一声,言:我等你表白,等了一年!空气凝滞了几秒,女神强作欢颜:从今往后,各自安好吧,干杯!

我转身踱回到座位,拿起手机,打开那个App,看着曾经发出的情书,一切仿佛还在昨日,但故事脚本已被别人书写,欲哭无泪,叹老天为何如此捉弄我?为何我发的消息女神没收到啊!

失魂落魄地回到家里,从冰箱里拿出几瓶罗斯福10号来麻醉自己,在酒精强烈的作用下,迷迷入睡。

第二天醒来,我明白了一个道理:对IM系统而言,消息必达永远摆在第一位!

以上是胡说八道,以下开始正文。。。

5、用全量离线消息实现消息必达

我们在重构IM系统时,需解决上一代设计的痛点之一就是确保消息必达。

5.1 离线消息实现消息必达的流程

自然而然地会想到这么做——即由服务端为每个人保存一个“离线消息列表”。

具体的思路是这样:

  • 1)当用户在线时,由IMS主动确保消息下发且收到客户端的应答确认时,才认为消息送达客户端,相应地把消息从“离线消息列表”移除;
  • 2)如果客户端没有发回应答确认,IM服务端会再发送。

以此来确保消息一定送到客户端,看起来是很符合逻辑。当时调查过市面上多款IM,行为基本如此。

5.2 海啸般的离线消息

5.2.1)和平时期:

重构后的IM上线,内部测试及在公网运行,离线消息的工作一直很正常。

5.2.2)被签到签死了:

后来,为某客户部署的私有环境,其用户量达几十万,其中的一个组织接近三万人,全员群也接近三万人;还有,底下的部门也有相应的群组,几百到几千人群不等。

“报到”、“签到”。。。大量的类似消息被发到几千、几万人的群内,然后如果有人一两天没上线,或者被加入到多个组织内,等到其上线时,几万条离线消息像海啸一般涌来,您想象一下:手机用户刚登陆的几分钟内,是什么场景?

用户真的很无辜:我不就是登陆了一下App,叮叮咚咚响了几分钟,还卡,还发热。。。

客户端承受不起大规模离线消息的轰炸,怎么办?

5.3 临时运用方案

  • 1)对若干大组织的全员群,对非管理员禁言;
  • 2)通知所有用户不要在大群签到。

我承认,这确实不算是个正经方案。。。

6、远离全量离线消息

我承认,一开始设计离线消息时,真没想到是这样的使用场景。对于大多数IM的开发者,或许不会碰到这种场景(但凡事住最坏的可能性想,总是没错的)。

6.1 放弃以离线消息的形式实现消息必达

我开始思考什么是消息必达,以前的想法是:把用户该收的消息都送到其客户端,是消息必达。

后来,给消息必达下了新的定义:

  • 1)用户有新消息时,确保让用户知道;
  • 2)当用户要查看这些消息时,确保其可一条不漏地看到。

打个比方:

  • 1)客户要把钱给您,不必送到您家里才算送到;
  • 2)而是转账到您的银行账户上,并告知您;
  • 3)当您要用钱时,直接从银行账户上消费即可。

从此,不会在用户上线时向其发送大量离线消息(即全量推送)。

6.2 以会话列表为基础来实现消息必达

客户端在上线时,先从服务端更新会话列表,也就是你通常在每个IM客户端的首页看到的这个(如下图所示)。

上图引用自《IM开发快速入门(一):什么是IM系统?

每一个会话列表项包含如下信息(此处简化了与本文无关的成员变量):

{

        // 会话对象的角色类型,比如私聊、群聊、系统通知、业务通知。。。

        uint32  session_role;

        // 会话对象的ID

        uint32        session_id;

        // 会话时间戳,用于消息同步;

        // 指会话的最后操作时间,比如清除角标的时间,与会话最后一条的消息时间未必一致

        uint64 session_timestamp;

        // true表示新增或更新,false表示被删除

        boolis_add;

 

        // 当is_add=false时,忽略以下信息

 

        // 仅用于显示角标的未读数量,当用户查看该会话后清零,且客户端多端同步

        uint32 new_msg_count;

        // 会话的最后一条消息

        MessageItem         latest_msg;

        // 跳转消息的时间戳,即new_msg_count的最旧1条消息的时间

        uint64 goto_timestamp;

}

为方便讨论,假设以下前提:

  • 1)周五傍晚18:00下班,我关闭App,我是9527;
  • 2)有1小姐姐向我发了5条消息留言,约我周末去海边玩,她是杨幂3306;
  • 3)然后,另1小姐姐也向我发了33条消息留言,内容我不便透露,她是景甜5672;
  • 4)严正声明:我跟她们很清白,其实我喜欢的是6379。

对,既然是假设,假一点也无妨。

我下班回到家,看到手机有通知栏消息,打开App将会发生哪些事呢?

App和IM后端的交互:

1)登录后,App以18:00填充参数latest_session_time,向IMS获取会话列表(其实不是以下线时间18:00,但这样更易理解);

2)IM后端检查发现我从18:00开始,有2个会话更新了,于是向App发送应答,以增量形式携带2个会话项:杨幂3306,景甜5672。其中景甜5672的会话项信息如下:

{

        uint32  session_role = Role_User; //表示私聊

        uint32        session_id = 5672; //景甜的ID

        uint64  session_timestamp = 1594464295335672; //最后一条消息的时间戳,微秒

        boolis_add = true; // true表示是更新项

        uint32  new_msg_count = 33; // 景甜向我发了33条消息

        MessageItem         latest_msg = "房号是0520"; //最后1条消息,结构体MessageItem简略不表

        uint64  goto_timestamp = 1594463697556677; // 向我发的33条消息的最早1条的时间

}

3)App收到步骤2的应答,我在App的会话列表窗口里,能看到2项更新,景甜发来的未读消息数33条,杨幂的是5条,如下图所示:

 

4)点开景甜5672的会话,App将向IMS发起同步消息的请求,获取最新的10条聊天消息(为了显示一屏):

{

        uint32  session_role = Role_User; //表示私聊

        uint32        session_id = 5672; //景甜的ID

        uint64        begin_time  = 1594464295335672; //步骤2返回的session_timestamp

        uint64        end_time  = 1594434153444222; //景甜上午向我发的最后一条消息的时间

        uint32        max_pieces = 10; //本次最多取10条,PC屏幕大则不妨取20条

}

5)IM后端收到步骤4请求,将返回33条新消息的最后10条给App,呈现聊天窗口内,且聊天窗口上方有一个tip:“↑ 33条新消息”,如下图所示:

 
 

6)我可以向上翻动聊天记录,那么App将持续向IMS获取第2批同步消息;或者也可以点击tip:“↑ 33条新消息”,直接跳转到33条消息的最旧一条,这样支持从最旧的消息向新的翻看。

相比于客户端简单地被动接收服务端的离线通知方式,这种设计使得客户端的处理逻辑更复杂。

主要体现在:

  • 1)客户端向服务端取的同步消息是未必完整,这些存在客户端的消息,在时间区间上可能不连续的;
  • 2)客户端需要知道不同消息之间是否有断代,如果有则需要向服务端查询同步消息来merge本地信息,使其连续,即客户端要实现消息融合。

我的建议:用C++实现一个统一的底层imsdk库,来负责这些共通的消息处理和存储。避免各客户端(Windows,iOS,Android等)各自实现这些逻辑,减少工作量,也降低各端不一致的风险。

6.3 以会话列表为基础与用全量离线消息的方案对比

6.3.1)用全量离线消息实现的方案优缺点:

实现原理:由IM服务端确保消息送达客户端,客户端存储后发回确认。

方案优点:逻辑简单。

在聊天消息不同数量级时的表现:

  • a. 离线消息量不多(如几百条):没有效率问题,且消息全部达到客户端本地,方便进行查找等动作;
  • b. 离线消息量巨大(如几万条):用户登录瞬间CS间瞬时流量大,客户端瞬时要存储、更新的数据量巨大,可能出现卡顿、假死等情况。

6.3.2)用会话列表为基础的方案优缺点:

实现原理:客户端先同步会话列表,由用户驱动不定次获取同步消息。

方案缺点:逻辑复杂,客户端增加不少工作。

在聊天消息不同数量级时的表现:

  • a. 离线消息量不多(如几百条):没优势;
  • b. 离线消息量巨大(如几万条):登录时交互数据小,对IM后端、客户端、用户体验,都比较友好。

7、多终端条件下,如何得到完整消息履历?

由于同一个用户的每个终端,其会话最后更新时间、每个会话的最后一条时间可能都不一样,参照上一节的实现思路,可以得到解决方案。

具体如下:

  • 1)参照第6.2章节的“App和IM后端的交互”第1个步骤,可取到不同的增量变化的会话列表项;
  • 2)参照第6.2章节的“App和IM后端的交互”第4个步骤,可取到任一区间的同步消息,得到完整消息。

8、离线消息是否就彻底废弃了?

有若干情况,仍然需要保留离线消息,以确保消息送达。

比如以下情形:

  • 1)别人向我发送离线文件:这种情况下不能依赖同步消息来获取。因为不以离线消息通知的话,用户在没有拉取到对应的同步消息前,是不知道有离线文件的;
  • 2)撤回消息:即使接收者不拉取同步,仍然要保证在上线后其数据在第一时间被撤回。注意:这里可能存在多端撤回问题;
  • 3)用户在线时的消息下发:由于用户在线时,IM后端向客户端发送消息可能碰到网络抖动等情况,导致消息下发失败,这些消息先可以直接存在离线消息队列,IM后端可在收到客户端的心跳包时重发消息。相当于维护了一个在线消息的离线队列。

9、本文结语

曾经有一段真挚的爱情摆在我面前,如果时间倒流到半年前,我会选择一个靠谱的IM来发送消息,也许故事的脚本就由自己书写——是否要整一个时光倒流的版本,抱得美人归的那种?

不整了不整了,我得不到女神,你们才欢喜,我太了解你们了。。。各位爷欢喜就好。

附录:IM开发干货系列文章

本文是系列文章中的第26篇,总目录如下:

IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

IM消息送达保证机制实现(二):保证离线消息的可靠投递

如何保证IM实时消息的“时序性”与“一致性”?

IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?

IM群聊消息如此复杂,如何保证不丢不重?

一种Android端IM智能心跳算法的设计与实现探讨(含样例代码)

移动端IM登录时拉取数据如何作到省流量?

通俗易懂:基于集群的移动端IM接入层负载均衡方案分享

浅谈移动端IM的多点登陆和消息漫游原理

IM开发基础知识补课(一):正确理解前置HTTP SSO单点登陆接口的原理

IM开发基础知识补课(二):如何设计大量图片文件的服务端存储架构?

IM开发基础知识补课(三):快速理解服务端数据库读写分离原理及实践建议

IM开发基础知识补课(四):正确理解HTTP短连接中的Cookie、Session和Token

IM群聊消息的已读回执功能该怎么实现?

IM群聊消息究竟是存1份(即扩散读)还是存多份(即扩散写)?

IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列

一个低成本确保IM消息时序的方法探讨

IM开发基础知识补课(六):数据库用NoSQL还是SQL?读这篇就够了!

IM里“附近的人”功能实现原理是什么?如何高效率地实现它?

IM开发基础知识补课(七):主流移动端账号登录方式的原理及设计思路

IM开发基础知识补课(八):史上最通俗,彻底搞懂字符乱码问题的本质

IM的扫码登功能如何实现?一文搞懂主流应用的扫码登陆技术原理

IM要做手机扫码登陆?先看看微信的扫码登录功能技术原理

IM开发基础知识补课(九):想开发IM集群?先搞懂什么是RPC!

IM开发实战干货:我是如何解决大量离线聊天消息导致客户端卡顿的

IM开发干货分享:如何优雅的实现大量离线消息的可靠投递》(* 本文)

另外,如果您是IM开发初学者,强烈建议首先阅读《新手入门一篇就够:从零开发移动端IM》。

(本文同步发布于:http://www.52im.net/thread-3069-1-1.html

posted @ 2020-07-21 13:58 Jack Jiang 阅读(441) | 评论 (0)编辑 收藏

本文在编写时参考了博客作者“鹿呦呦”和在线课程“即时消息技术剖析与实战”的相关资料,一并表示感谢。

1、系列文章引言

IM系统看似简单(没错,很多土老板认为开发个qq和微信也就是几万块钱的事... ),实责是众多技术的应用合体,包括网络编程、移动开发、后端开发、高并发、高可用、高安全等技术范畴,再加上多端使用不同的编程语言,想要凑齐一个典型的IM产品技术栈那也不是个容易事。

而对于IM开发入门者来说,想要在众多的IM技术术语和概念中找到学习的方向和需要的资料,那也是件很让人抓狂的事。如果看到不该看的技术深水区文章,直接从入门到放弃——被活活吓退,那也是相当悲剧的。

本系列文章将尽量从理论概念入手,通俗易懂的梳理IM中的基础技术概念和热门技术点,希望能帮你理清看似一团乱麻的IM知识体系,助你找到清晰的IM技术学习方向,来日工资翻倍、迎娶白富美也未必不可能!

 

友情提示:本系列文章侧重于理论概念的讲述,篇幅有限,点到即止,如需系统、深入、具体地学习IM技术的方方面面,请从此文入手:《新手入门一篇就够:从零开发移动端IM》(史诗级文章,适合从入门到放弃)。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170[推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

2、系列文章目录

IM开发快速入门(一):什么是IM系统?》(* 本文

《IM开发快速入门(二):什么是IM系统的实时性? (稍后发布)》

《IM开发快速入门(三):什么是IM系统的可靠性? (稍后发布)》

《IM开发快速入门(四):什么是IM系统的一致性? (稍后发布)》

《IM开发快速入门(五):什么是IM系统的安全性? (稍后发布)》

《IM开发快速入门(六):什么是IM系统的的心跳机制? (稍后发布)》

《IM开发快速入门(七):如何理解并实现IM系统消息未读数? (稍后发布)》

《IM开发快速入门(八):如何理解并实现IM系统的多端消息漫游? (稍后发布)》

3、本文内容概述

本文将带你快速了解一个主流IM系统的应用场景、典型架构、技术特点和功能组成,帮你快速建立对IM系统的主观认知。

如果你不想从技术的角度理解IM原理,可以尝试阅读此文:《知识科普:IM聊天应用是如何将消息发送给对方的?(非技术篇)》。

本文已收入即时通讯网的入门纲领性文章《新手入门一篇就够:从零开发移动端IM》。

本文已同步发布于“即时通讯技术圈”公众号,欢迎关注:

▲ 本文在公众号上的链接是:https://mp.weixin.qq.com/s/h7L4UGHRl7qI1bi8WyZ5iw,原文链接是:http://www.52im.net/thread-3065-1-1.html

4、IM的应用场景

IM其实并不局限于聊天、社交这类“典型”应用中,实际上它已经广泛运用于我们身边形形色色的软件中。

聊天、直播、在线客服、物联网等所有需要实时互动、高实时性的场景等等,都需要应用到 IM 技术。

下面这些场景是我们大家都熟悉的,都用到了IM技术:

  • 1)微信、qq、钉钉等主流IM应用:这是IM技术的典型应用场景;
  • 2)微博、知乎等社区应用:它们利用IM技术实现了用户私信等点对点聊天;
  • 3)抖音、快手等直播/短视频应用:它们利用IM技术实现了与主播的实时互动;
  • 4)米家等智能家居物联网应用:利用IM技术实现实时控制、远程监控等;
  • 5)滴滴、Uber等共享家通类应用:利用IM技术实现位置共享;
  • 6)在线教育类应用:利用IM技术实现在线白板。 

5、IM的典型架构

一个典型的IM架构类似于下图这样:

本图引用自《即时消息技术剖析与实战》学习笔记1——IM系统的架构》一文

如上图所示,IM架构中的各分层职责如下:

  • 1)客户端:作为与服务端进行消息收发通信的终端;
  • 2)接入层:也叫网关层,为客户端收发消息提供入口;
  • 3)逻辑层:负责IM系统各功能的核心逻辑实现;
  • 4)存储层:负责IM系统相关数据的持久化存储,包括消息内容、账号信息、社交关系链等;
  • 5)第三方服务:保证APP在未打开或后台运行时也能收到消息通知(这主要是第第3方消息推送服务)。

尤其对于“接入层”,它的职责最为关键,具体是:

  • 1)保持海量用户连接;
  • 2)解析协议,对传输内容进行编解码;
  • 3)维护客户端的连接(也叫“Session”);
  • 4)推送消息。

以下文章适合IM架构设计入门,有兴趣可以读一读:

6、IM技术的特点

IM技术的特点主要就是以下4点: 

▶ 1)实时性:

对于IM系统,“实时”二字是精髓,也是这项技术存在关键意义所在。它保证的是消息的实时触达。

举个例子:如果跟你的好友微信或qq聊天,我发的消息他不能即时收到,或者他发的信息你也不知道什么时候能收到,这基本上也就没法聊下去了(干吗不痛快打个电话呢)。

▶ 2)可靠性:

保证消息的不丢失和不重复,是IM系统的另一个关键技术特点。试想,当你在用qq或微信跟女朋友聊天,好不容易鼓起勇气向“她”表白,结果这消息要是丢包了,那肯定得卸载应用了,搞不好砸手机都有可能。当然,好话不说二遍,消息重复也同样恼人。

以下文章对消息的不丢/不重问题进行了深入探讨,有兴趣可以详读:

▶ 3)一致性:

对于单聊消息而言,保证同一个设备的时间顺序、不同设备的漫游同步,也是相当重要的一环。

IM系统中的消息交互,就到底就是人跟人在“说话”,前言不搭理后言、或者胡言乱语式的消息展现,那不是人疯了就是程序疯了,总之就是没法再聊下去了。

以下文章对消息时序问题进行了深入探讨,有兴趣可以详读:

▶ 4)安全性:

保证数据传输安全、数据存储安全、消息内容安全,也是IM系统必不可少的特性。尤其在私聊场景下,如果不能做到安全性,聊天的体验跟被人偷窥的感觉是没有区别的。

以下文章对IM的安全问题进行了深入探讨,有兴趣可以详读:

7、IM的功能组成

浅显的角度讲,一个典型的IM功能组成,无非就是以下5样:

  • 1)联系人列表;
  • 2)聊天界面;
  • 3)消息发送通道;
  • 4)消息接收通道;
  • 5)消息存储;
  • 6)消息未读数。

我们一样一样来说说各自的用途。

▶ 1)联系人列表:

这个很好理解,使用IM系统的第一步,就是要解决“跟谁聊”的问题。从功能表象上来说,联系人列表也就是社交关系列表,无非就是个信息列表界面,有什么特殊的地方?

联系人列表看似简单,实际上它是一系列IM系统的社交关系确立动作的结果体现。

要想建立联系人列表,你可能需要实现以下逻辑:

  • 1)怎么能找到想要聊天的人?(需要实现随机查找?精确查找?)
  • 2)怎么决定要不要跟这个人聊?(需要实现对方的个人信息查看)
  • 3)开始发出好友请求;
  • 4)被请求的一方,还可以决定是“同意”还是“拒绝”(“同意”该怎么处理?“拒绝”又该怎么处理?)。

总的来说,联系人列表的建立,是一个IM系统聊天关系确立的表现,不可或缺。

▶ 2)聊天界面: 

聊天界面看似很平常,实际它就是IM系统客户端的核心功能所在,所有主要的IM功能都是通过它展现。

它应该具备的能力有:

  • 1)各种聊天功能按钮:语音留言、图片、文字、表情、文件、实时电话、实时视频等;
  • 2)各种聊天消息显示:各种消息都有不同的UI显示元素和处理逻辑;
  • 3)流畅的使用体验:大量不同类型的消息显示时,不能卡顿;
  • 4)即时显示聊天消息:网络线程收到的消息,要马上在UI上显示出来;
  • 5)历史消息的加载:上次聊过的内容也得显示出来吧。

以上只是简单罗列,这看似简单的聊天界面,能把上面列表的事情做好,工作量也不小吧。

▶ 3)消息发送通道:

下图是一个典型的IM消息收发通道示意: 

如上图所示,消息发送通道这个比较好懂,最浅显易懂的理解就是用tcp或udp,建立socket长连接,需要发消息的时候,wirte一下就过去了,好简单!

但,事情往往不是想象的这么简单:

  • 1)如何保证这条socket长连接时一直处于可用的状态?
  • 2)当socket长连接不可用时,用户此时发送的消息该怎么处理?
  • 3)怎么保证发送的消息不丢?
  • 4)怎么保证发送的消息不复重?
  • 5)怎么保证发送的消息乱序?
  • 6)当对方不在线时,发送的消息去哪了?
  • 7)发送的消息,能保证实时送到?

这么一说,事情还挺多(那不废话吗。。。)。

▶ 4)消息接收通道:

正如上节中的消息收发通道示意图所示,消息接收通道也很好理解,对方通过消息发送通道write的消息,我得收到并显示啊。

要实现一个可靠的消息接收通道,也并非易事:

  • 1)如何保证socket长连接通道能随时处于良好的边接状态(随时接收对方write的消息);
  • 2)当socket长连接断开时,对方发送消息该怎么实现?
  • 3)当socket恢复连接时,怎么恢复之前的聊天现场?
  • 4)当我收到对方的消息时,对方怎么知道我已经收到了?
  • 5)当重复收到对方的消息时,该怎么处理?
  • 6)当收到的消息时序有错乱,该怎么处理?

▶ 5)消息存储:

消息存储这个功能好理解,聊天的消息如果存储,下次再聊的时候就不知道之前聊过什么,做不到这一点,这个IM系统的聊天体验好不起来。

那么,哪些情况下需要进行消息存储呢:

  • 1)对方不在线时:聊天消息应该存储(这叫离线消息存储);
  • 2)对方在线时:聊天消息也要存到本地存储(这叫消息缓存);
  • 3)对方在线或不在线时:聊天消息都要存到服务端(用于实现多设备的消息漫游和同步)。

具体要存储的内容和时机也就上面这几样。

但技术落到实处,要做的事情同样少不了:

  • 1)离线消息该怎么多久?
  • 2)图片、短视频、大文件这类的离线消息,多媒体文件该怎么存(有可能量会很大)?
  • 3)当本地的消息积累太多时,怎么能保证本地存储的性能?
  • 4)当应用更新、升级或异常时,怎么能保证本地存储的完整性(不被破坏)?
  • 5)怎么能保证多设备消息能不丢、不重、不乱?

这么多需要考虑的内容,也挺让人抓狂。

下图是一个IM系统的典型存储架构设计,了解一下:

本图引用自《现代IM系统中聊天消息的同步和存储方案探讨》一文

存储是IM系统的基石,以下文章可以深入阅读:

▶ 6)消息未读数:

消息未读数?看起来也就是那个所有IM应用都有的未读小红点嘛。是的,看起来也好简单!

然而,消息未读数功能的实现也一样不简单:

  • 1)未读数是客户端实现还是服务端实现?
  • 2)会话未读和总未读怎么保持一致?
  • 3)多终端情况下,怎么保证未读数的一致性(我在这台设备上读没读,那台设备怎么知道的?)?

是的,看起来就这么简简单单的3件事,但深入思考一下,还真的简单不起来。

8、本文小结

IM系统的应用场景已经不单单是IM聊天应用这一种形态,它已经融入到互联网应用的方方面面,必竟谁都想自已的应用具备“实时”交互这种能力,因为体验太好了。

IM系统典型架构无非就是网络接入层、业务逻辑层、数据存储层,除开网络接入层,其它各层其实跟普通的应用系统看起来差别并不是太大。

IM系统的技术特点来说,就是实时性、可靠性、一致性、安全性,除了实时性对于多数应用来说并不关心,其它的指标也很好理解。

IM系统的功能组成上,联系人列表用于数据模型的建立、聊天界面承载了IM系统的终端展现、消息的收发通道用于实现“实时”这个特性、存储和未读数看似不是必须但用户体验上确必不可少。

附录:更多IM开发资料汇总

[1] 有关IM架构设计的文章:

浅谈IM系统的架构设计

简述移动端IM开发的那些坑:架构设计、通信协议和客户端

一套海量在线用户的移动端IM架构设计实践分享(含详细图文)

一套原创分布式即时通讯(IM)系统理论架构方案

从零到卓越:京东客服即时通讯系统的技术架构演进历程

蘑菇街即时通讯/IM服务器开发之架构选择

腾讯QQ1.4亿在线用户的技术挑战和架构演进之路PPT

微信后台基于时间序的海量数据冷热分级架构设计实践

微信技术总监谈架构:微信之道——大道至简(演讲全文)

如何解读《微信技术总监谈架构:微信之道——大道至简》

快速裂变:见证微信强大后台架构从0到1的演进历程(一)

17年的实践:腾讯海量产品的技术方法论

移动端IM中大规模群消息的推送如何保证效率、实时性?

现代IM系统中聊天消息的同步和存储方案探讨

WhatsApp技术实践分享:32人工程团队创造的技术神话

微信朋友圈千亿访问量背后的技术挑战和实践总结

王者荣耀2亿用户量的背后:产品定位、技术架构、网络方案等

IM系统的MQ消息中间件选型:Kafka还是RabbitMQ?

腾讯资深架构师干货总结:一文读懂大型分布式系统设计的方方面面

以微博类应用场景为例,总结海量社交系统的架构设计步骤

快速理解高性能HTTP服务端的负载均衡技术原理

子弹短信光鲜的背后:网易云信首席架构师分享亿级IM平台的技术实践

IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列

微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

微信技术分享:微信的海量IM聊天消息序列号生成实践(容灾方案篇)

新手入门:零基础理解大型分布式架构的演进历史、技术原理、最佳实践

一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践

社交软件红包技术解密(一):全面解密QQ红包技术方案——架构、技术实现等

社交软件红包技术解密(二):解密微信摇一摇红包从0到1的技术演进

社交软件红包技术解密(三):微信摇一摇红包雨背后的技术细节

社交软件红包技术解密(四):微信红包系统是如何应对高并发的

社交软件红包技术解密(五):微信红包系统是如何实现高可用性的

社交软件红包技术解密(六):微信红包系统的存储层架构演进实践

社交软件红包技术解密(七):支付宝红包的海量高并发技术实践

社交软件红包技术解密(八):全面解密微博红包技术方案

社交软件红包技术解密(九):谈谈手Q红包的功能逻辑、容灾、运维、架构等

社交软件红包技术解密(十):手Q客户端针对2020年春节红包的技术实践

从游击队到正规军(一):马蜂窝旅游网的IM系统架构演进之路

从游击队到正规军(二):马蜂窝旅游网的IM客户端架构演进和实践总结

IM开发基础知识补课(六):数据库用NoSQL还是SQL?读这篇就够了!

瓜子IM智能客服系统的数据架构设计(整理自现场演讲,有配套PPT)

阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处

从游击队到正规军(三):基于Go的马蜂窝旅游网分布式IM系统技术实践

微信后台基于时间序的新一代海量数据存储架构的设计实践

IM开发基础知识补课(九):想开发IM集群?先搞懂什么是RPC!

>> 更多同类文章 ……

[2] IM开发热门综合文章:

新手入门一篇就够:从零开发移动端IM

移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”

移动端IM开发者必读(二):史上最全移动弱网络优化方法总结

从客户端的角度来谈谈移动端IM的消息可靠性和送达机制

IM开发基础知识补课:正确理解前置HTTP SSO单点登录接口的原理

移动端IM中大规模群消息的推送如何保证效率、实时性?

移动端IM开发需要面对的技术问题

开发IM是自己设计协议用字节流好还是字符流好?

请问有人知道语音留言聊天的主流实现方式吗?

IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

IM消息送达保证机制实现(二):保证离线消息的可靠投递

如何保证IM实时消息的“时序性”与“一致性”?

一个低成本确保IM消息时序的方法探讨

IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?

IM群聊消息如此复杂,如何保证不丢不重?

谈谈移动端 IM 开发中登录请求的优化

移动端IM登录时拉取数据如何作到省流量?

浅谈移动端IM的多点登录和消息漫游原理

完全自已开发的IM该如何设计“失败重试”机制?

通俗易懂:基于集群的移动端IM接入层负载均衡方案分享

微信对网络影响的技术试验及分析(论文全文)

即时通讯系统的原理、技术和应用(技术论文)

开源IM工程“蘑菇街TeamTalk”的现状:一场有始无终的开源秀

如约而至:微信自用的移动端IM网络层跨平台组件库Mars已正式开源

全面掌握移动端主流图片格式的特点、性能、调优等

子弹短信光鲜的背后:网易云信首席架构师分享亿级IM平台的技术实践

IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列

微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

自已开发IM有那么难吗?手把手教你自撸一个Andriod版简易IM (有源码)

融云技术分享:解密融云IM产品的聊天消息ID生成策略

IM开发基础知识补课(六):数据库用NoSQL还是SQL?读这篇就够了!

适合新手:从零开发一个IM服务端(基于Netty,有完整源码)

拿起键盘就是干:跟我一起徒手开发一套分布式IM系统

适合新手:手把手教你用Go快速搭建高性能、可扩展的IM系统(有源码)

IM里“附近的人”功能实现原理是什么?如何高效率地实现它?

IM要做手机扫码登录?先看看微信的扫码登录功能技术原理

IM消息ID技术专题(一):微信的海量IM聊天消息序列号生成实践(算法原理篇)

IM消息ID技术专题(二):微信的海量IM聊天消息序列号生成实践(容灾方案篇)

IM消息ID技术专题(三):解密融云IM产品的聊天消息ID生成策略

IM消息ID技术专题(四):深度解密美团的分布式ID生成算法

IM消息ID技术专题(五):开源分布式ID生成器UidGenerator的技术实现

IM开发宝典:史上最全,微信各种功能参数和逻辑规则资料汇总

IM开发干货分享:我是如何解决大量离线消息导致客户端卡顿的

IM开发快速入门(一):什么是IM系统?

>> 更多同类文章 ……

(本文同步发布于:http://www.52im.net/thread-3065-1-1.html

posted @ 2020-07-09 14:16 Jack Jiang 阅读(1030) | 评论 (0)编辑 收藏

1、引言

IM系统中,特别是在企业应用场景下,消息的已读未读状态是一个强需求。

以阿里的钉钉为例,钉钉的产品定位是用于商务交流,其“强制已读回执”功能,让职场人无法再“假装不在线”、“假装没收到”。更有甚者,钉钉的群聊“强制已读回执”功能,甚至能够知道谁读了消息,谁没有读消息(老板的福音啊)。

 

▲ 钉钉里的群聊消息已读未读功能效果

功能看起来很酷,但用起来是一言难尽(上班族心里苦.... )。实际上,技术实现也并不容易。

那么,对于已读未读状态:

  • 1)如果是私聊:消息的阅读状态比较容易实现,在性能和存储上也不存在问题;
  • 2)如果是群聊:考虑到存储和处理性能,特别当处于一个云环境时,如何高效地处理群聊的已读未读状态是一个非常值得探讨的话题。

这里提到的“高效”含3个方面:

  • 1)存储空间;
  • 2)处理速度;
  • 3)传输字节数。

本文将从服务端的角度来探讨已读未读状态,在具体的技术实现上对于存储空间占用方面的思路差异。能力有限,权当个人笔记,欢迎交流。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170[推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

本文已同步发布于“即时通讯技术圈”公众号,欢迎关注:

▲ 本文在公众号上的链接是:https://mp.weixin.qq.com/s/yUkKPOBsdqLlxiFrGmwFRQ,原文链接是:http://www.52im.net/thread-3054-1-1.html

2、内容点评

在收录本文前,Jack Jiang建议原作者对某些具体的技术点进行更深入的分享,但因作者工作较忙,本文中的某些关键技术点未来的及作进一步展开。

所以,本文可以作为IM聊天消息(主要是群聊)中已读未读功能的基本实现思路方面的参考,但不建议盲目迷信文中的结论或方案,避免被一些不够具体的技术指标而误导。

3、相关文章

如果你还想了解更多有关IM群聊中已读未读功能的实现逻辑,可以进一步阅读干货文章《IM群聊消息的已读回执功能该怎么实现?》(强烈推荐)。

如果你对IM中的已读未读功能有产品方面的痛点困惑,可以参考一下微信对已读未读功能的设计定位,详见《IM热门功能思考:为什么微信里没有消息“已读”功能?》。

更多IM群聊技术方面的文章详见文本附录部分。

4、已读未读状态交互流程

发送者发送的IM聊天消息,在接收者阅读消息后,是否要求阅读者通知已读,可能是由系统配置、组织配置、群组配置等决定,也可能由发送者根据业务需求决定。以下的讨论,均假设消息需要已读未读状态。

客户端与服务端之间,关于阅读状态的命令只需3个,每个命令含请求和应答。

4.1 通知消息已读(私聊、群聊通用)

当小宝阅读了一条或若干条消息,需向服务端发送消息已读通知:“众爱卿发的x+y+z消息,朕已阅”。

服务端收到小宝的已读通知时,需完成以下事项:

  • 1)存储消息的已读状态;
  • 2)返回应答给小宝;
  • 3)向已读列表的消息的原始发送者通知消息已读。

对于第“3)”步:

  • 1)私聊的场合,比较好理解,就是发送给私聊的对方;
  • 2)群聊的场合,可很不一样:因为小宝发送的已读消息列表,可能是由众爱卿发送的。考虑这种假设:张三、李四、王五发出的群聊消息,被小宝一下都阅读了,那么小宝发出的已读通知包含的消息列表,需要被IMS分解成3个已读通知(3个不同的消息列表),分别通知给张三、李四、王五,通知内容是“爱卿(不含'"众")发的这些消息,朕已阅”。

下面是大致的逻辑流程图: 

4.2 查询消息的未读人数(私聊、群聊通用)

消息的发送者,加载消息列表到聊天窗口时,可能需要展示消息是否被已读。

对群聊而言,显示的信息可能是n人未读的提示,那么需要向服务端查询消息的未读人数,由于客户端可能在UI显示自己发出的多条消息,需支持一次请求查询多条消息。

以未读人数的方式来表示消息的阅读状态,统一了私聊、群聊的查询,使得客户端-服务端间的接口更简单,同时使客户端的实现逻辑更统一。

就像下面这样:

  • 1)对于私聊:如果未读人数n>0,表示消息未读;
  • 2)对于群聊:直接显示n人未读即可,当然,当n等于0时表示全部已读。

4.3 查询群消息的已读、未读人员清单(群聊)

当客户端希望显示某一条群聊消息的已读、未读人员列表,需向服务端发起查询。

大致的逻辑流程图如下:

5、几种具体的已读未读状态存储思路探讨

5.1 基本约定

群聊的阅读状态比私聊复杂,因此这里着重讨论群聊的阅读状态。

假设群成员数是n,各个客户端立即IM服务端发送已读通知。服务端需存储每个人的阅读状态,包括那些未读的成员。由于群的成员清单可能变化,比如今天增加了一个成员,则昨天发的消息、与今天发的消息,其接收者列表不一样。

即:

  • 1)同一个群的不同消息,对应的接收者列表可能不一样。
  • 2)换言之,每一条消息都需要记录完整的接收者列表和已读人员列表。

为了方便讨论,本章假设群成员有640人为前提。

5.2 存储思路1

每一条消息都维护:

  • 1)接收人员列表receiver_list;
  • 2)已读人员列表read_list。

具体是:

  • 1)IM Server收到一条消息时,用全体群成员构建receiver_list;
  • 2)IM Server收到群成员对这条消息的已读通知时,将此成员加入到read_list。

客户端获取此消息的数据:

  • 1)当需要获取未读人数时,用receiver_list的个数减去read_list的个数;
  • 2)当需要获取已读、未读人员列表时,需用receiver_list减去read_list得到未读人员列表。

那么,思路1每条消息的存储空间是:

640个ID + 不定数量的已读人员ID

5.3 存储思路2

每一条消息维护:

  • 1)未读人员列表unread_list;
  • 2)已读人员列表read_list。

具体是:

  • 1)IM Server收到一条消息时,用全体群成员构建unread_list;
  • 2)IM Server收到群成员对这条消息的已读通知时,将此成员从unread_list移出,同时加入到read_list。

客户端获取此消息的数据:

  • 1)当需要获取未读人数时,直接计算unread_list的个数;
  • 2)当需要获取已读、未读人员列表时,直接返回unread_list和read_list。

那么,思路2每条消息的存储空间是:

未读人员ID + 已读人员ID,合计640个ID

思路2的实现,占用的空间是案1的0.5倍~1.0倍。即案2占用的空间少,但在每次收到客户端的已读通知时,比案1多了一个操作:从unread_list进行减员。

5.4 存储思路3(我的实现)

5.4.1)探讨5.2节、5.3节的不足:

5.2节、5.3节这两种思路,都能满足功能需求,但存在巨大的存储浪费。

该群有640人,如果群内聊天每天有1024条消息,人员ID以4字节存储计算,那么为该群每天的消息阅读状态需要消耗的空间是:

5.2节思路1:1024 * (640 * 4 + 已读人数 * 4),范围是 2.5MB ~ 5MB;

5.3节思路2:1024 * 640 * 4,等于2.5MB。

这仅仅是一个群在一天之内产生的阅读状态数据,如果是在云平台运行,单此功能消耗的空间,呵呵~~

题外话:如果成员不是用4字节整型存储,而改用字符串,比如"1123356777",那就更可观了。

5.4.2)如何减少存储空间:

考虑群成员并非时时刻刻都在变化,多数情况下,群成员的列表是相对稳定的,今天的和上周(甚至更久以前)的列表甚至可能是一样的,那么有可能几百条消息,甚至几万条消息对应的群成员列表是相同的。

因此,引出本文的重点思想:

考虑让不同的消息共用群成员列表,即把消息的阅读状态与群成员列表分开存储,并记录它们之间的关联。

假定平均每1024条消息共用一个群成员列表,发了1024条消息后,群成员变化了,此后需要用新的群成员列表。

那么这一千条消息的阅读状态所占用的空间是:

群成员列表空间 + 1024条消息的阅读状态:640 * 4 + 1024 * 每条消息的阅读状态所占空间

在具备群成员列表的前提下,如何减少每条消息的阅读状态所占空间?

很自然会想到用bit来表示已读人员,因为一个32位整型可表示32个人的已读状态。bit的顺序只需与群成员列表的顺序一致即可。

当一条消息没有人已读时,阅读状态占用0字节;当群内每个人都阅读时,占用的空间最大,即640 / 32 = 20字节。

因此优化之后,这一千条消息的阅读状态所占用的空间,范围是2.5KB ~ (2.5KB + 1024 * 20B),即2.5KB ~ 22.5KB,此数值与5.2节思路1、5.3节思路2对比,有了极大幅度地下降。

如下图所示:

该表格的前提条件:

  • 1)一个群有640人;
  • 2)该群连续1024条消息对应的群成员列表是稳定的。

退一步考虑,哪怕这1024条消息对应的群成员列表不稳定,中间变化了10次,那么也仅会多出2.5KB * 10即25KB的存储空间,与案1、案2相比仍然有极大优势。

6、如何提高已读未读状态的处理速度

小宝往公司群发了一条消息我来给大家介绍一下新来的女同事,大家立即、马上、瞬间、闪电般地查看消息,感觉迟1秒就会失去秒杀女神的机会一样,意味着一瞬间会有N多条已读通知发送到IMS。

对这些消息的处理流程是一样的:

  • 1)可合并这些操作以批量形式进行存储、转发;
  • 2)由于存储消息的阅读状态是一个设置bit的过程,所以不存在互斥的问题,即使在分布式环境也可以放心操作;
  • 3)消息对应的成员列表信息可临时缓存在内存对象内,以减少查询IO,提高效率。

附录:更多IM群聊技术文章

快速裂变:见证微信强大后台架构从0到1的演进历程(一)

如何保证IM实时消息的“时序性”与“一致性”?

IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?

IM群聊消息如此复杂,如何保证不丢不重?

微信后台团队:微信后台异步消息队列的优化升级实践分享

移动端IM中大规模群消息的推送如何保证效率、实时性?

现代IM系统中聊天消息的同步和存储方案探讨

关于IM即时通讯群聊消息的乱序问题讨论

IM群聊消息的已读回执功能该怎么实现?

IM群聊消息究竟是存1份(即扩散读)还是存多份(即扩散写)?

一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践

[技术脑洞] 如果把14亿中国人拉到一个微信群里技术上能实现吗?

IM群聊机制,除了循环去发消息还有什么方式?如何优化?

网易云信技术分享:IM中的万人群聊技术方案实践总结

阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处

IM群聊消息的已读未读功能在存储空间方面的实现思路探讨

>> 更多同类文章 ……

(本文同步发布于:http://www.52im.net/thread-3054-1-1.html

posted @ 2020-07-02 14:04 Jack Jiang 阅读(506) | 评论 (0)编辑 收藏

1、引言

IM在Android上的保活问题经常在即时通讯网的论坛和技术群里被讨论,自从Android 8.0后系统大大降低了后台运行应用的保活容忍度(详见《Android P正式版即将到来:后台应用保活、消息推送的真正噩梦》),保活从黑科技横行的时代进入了技术蛮荒阶段,真要实现保活,技术难度越来越大。

不过话说回来,既然用黑科技进行保活是Andriod技术的逆潮流,那何不回头是岸,做个“良民”?

本文将以某款线上的IM产品为例,介绍它是如何引导用户在多款主流机型上加白名单的,并分享了该款IM中已制作完成的多达7款主流Andriod机型的详细加白FAQ页面资源(含完整HTML+图片),方便您进行参考、学习和研究,希望能为你的应用开发带来帮助。

特别申明:本文示例中的资源来自某款真实的IM产品,仅供学习和研究,请勿用作非法用途,如有侵权,请告之于我。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170[推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

本文已同步发布于“即时通讯技术圈”公众号,欢迎关注:

▲ 本文在公众号上的链接是:https://mp.weixin.qq.com/s/JqWloZLBYicpxElVL_HKYw ,原文链接是:http://www.52im.net/thread-3033-1-1.html

2、Android保活,变的越来越不可能了

IM产品在Android上的保活问题从早期的系统版本到现在,从未有人停止过尝试。即时通讯通讯网也随着Andriod系统版本的升级,持续整理了很多篇相关文章,比如下面这些(文章的顺序按照Android系统的版本从低到高)。

上面这些文章,我们可以看到,自从Android 8.0(即Andriod P)以后,IM以及其它需要在后台保活的产品,存活难度越来越高,黑科技几乎都不起作用了。

于是,一些技术从牛们只能从更深的Android系统层面尝试突破系统的保活限制,比如这两篇:《史上最强Android保活思路:深入剖析腾讯TIM的进程永生技术》、《Android进程永生技术终极揭密:进程被杀底层原理、APP应对被杀技巧》。

正如上面两篇文章,为了跟系统作斗争,可谓斗智斗勇。但Android系统的历史进程终究无人能阻挡,越来越严格的保活限制已经是Android官方及各大手机厂商的共识。

好吧,之前费尽心机折腾的各种黑科技,如今就像浮云一样。。。

 

3、死磕保活?别做梦了,回头是岸

正如上节所述,鉴于Andriod保活变的越来越不可能,很多原本靠黑科技保活的产品,开始重新审视保活技术实现,到底是把保活黑科技这条路走到黑,还是回归Android官方最佳实践(乖乖引导用户手动设置白名单)?

我个人认为,后者是保活技术发展的必然结果,就像之前分享的这篇文章里所做的尝试一样:《2020年了,Android后台保活还有戏吗?看我如何优雅的实现!》,规范地引导用户“加白”。

放弃“黑科技”,并不意味着技术不行,回归“良民”,反而变的一身轻松。

 

4、调用系统代码引导用户加白名单,也不完美

之前整理的《2020年了,Android后台保活还有戏吗?看我如何优雅的实现!》一文,是按照不同的机型,自动适配代码并在代码中调用系统的加白名单设置功能。

比如像下面这样的代码调用:

▲ 以下代码引用自《2020年了,Android后台保活还有戏吗?看我如何优雅的实现!

会弹出这样一个窗口:

这个方法确实不错,但因为机型不同、同机型的ROOM版本不同,代码的兼容处理,可能会相当复杂,所以方法虽好,但也并不能一劳永逸的解决所有问题。

5、应用内提供更多机型的“加白”FAQ帮助,是一个补充办法

正如上节所示,调用系统代码引导用户加白名单确实算的上“优雅”,但在不同的机型、同机型的不同系统版本上,可能差异很大,代码兼容性是个头疼的问题,总之这不是个百分百完美的办法。

这就需要一个补充手段,比如我们可以针对大量不同的机型,针对它的最行或最常用系统版本,在应用内以FAQ帮助网页的方式,为用户提供帮助。

比如可以在手机里打开像下面这样FAQ网页页面:

至少能在调用系统代码无法实现的情况下,可以让用户自主找到解决问题的办法。而这便是本文要分享,下节内容会以一个市面上做的比较好的IM应用为例,为你提供一个完整示例。

6、一个完整的“加白”FAQ帮助示例

最近发现的一款市面上的IM应用(此产品跟即时通讯网无任何关系,仅仅是作为技术研究参考对象而已),它内置的“加白”FAQ帮助就很完善。

以下是从该款IM中截下来的图: 

 

以下是该款IM应用中的运行演示视频(点此打开视频链接):

 

目前该应用中FAQ帮助已覆盖7款主流Andriod机,以下是完整示例页面链接:

可以看到,这款IM里的“加白”FAQ做的还是比较细、覆盖的机型也比较典型, 如果你有类似的想法或需求,完全可以参考这款产品的实现。尤其在一些特定的场景(比如企业内部的IM等)下,这种方式还是能解决大部分终端用户的问题的。

7、覆盖7款主流机型的“加白”FAQ页面静态资源(附件下载)

我整理了上节中提到的这款IM产品中的全部“加白”FAQ帮助页面静态资源,覆盖7款主流Andriod机型,如果你也需要同样的东西,可以参考这份完整的示例实现,打包到手机中使用之。

以下是这份静态资源示例的内容(图太长,已截掉了一部分): 

以下是这份静态资源示例的打包附件:

请从原文附件中下载:http://www.52im.net/thread-3033-1-1.html

附录:更多精品资源汇总

[1] 精品源码下载:

Java NIO基础视频教程、MINA视频教程、Netty快速入门视频 [有源码]

轻量级即时通讯框架MobileIMSDK的iOS源码(开源版)[附件下载]

开源IM工程“蘑菇街TeamTalk”2015年5月前未删减版完整代码 [附件下载]

微信本地数据库破解版(含iOS、Android),仅供学习研究 [附件下载]

NIO框架入门(四):Android与MINA2、Netty4的跨平台UDP双向通信实战 [附件下载]

NIO框架入门(三):iOS与MINA2、Netty4的跨平台UDP双向通信实战 [附件下载]

NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示 [附件下载]

NIO框架入门(一):服务端基于Netty4的UDP双向通信Demo演示 [附件下载]

用于IM中图片压缩的Android工具类源码,效果可媲美微信 [附件下载]

高仿Android版手机QQ可拖拽未读数小气泡源码 [附件下载]

一个WebSocket实时聊天室Demo:基于node.js+socket.io [附件下载]

Android聊天界面源码:实现了聊天气泡、表情图标(可翻页) [附件下载]

高仿Android版手机QQ首页侧滑菜单源码 [附件下载]

开源libco库:单机千万连接、支撑微信8亿用户的后台框架基石 [源码下载]

分享java AMR音频文件合并源码,全网最全

微信团队原创Android资源混淆工具:AndResGuard [有源码]

一个基于MQTT通信协议的完整Android推送Demo [附件下载]

Android版高仿微信聊天界面源码 [附件下载]

高仿手机QQ的Android版锁屏聊天消息提醒功能 [附件下载]

高仿iOS版手机QQ录音及振幅动画完整实现 [源码下载]

Android端社交应用中的评论和回复功能实战分享[图文+源码]

Android端IM应用中的@人功能实现:仿微博、QQ、微信,零入侵、高可扩展[图文+源码]

仿微信的IM聊天时间显示格式(含iOS/Android/Web实现)[图文+源码]

Android版仿微信朋友圈图片拖拽返回效果 [源码下载]

[2] 精品文档和工具下载:

计算机网络通讯协议关系图(中文珍藏版)[附件下载]

史上最全即时通讯软件简史(精编大图版)[附件下载]

重磅发布:《阿里巴巴Android开发手册(规约)》[附件下载]

阿里技术结晶:《阿里巴巴Java开发手册(规约)-终极版》[附件下载]

基于RTMP协议的流媒体技术的原理与应用(技术论文)[附件下载]

独家发布《TCP/IP详解 卷1:协议》CHM版 [附件下载]

良心分享:WebRTC 零基础开发者教程(中文)[附件下载]

MQTT协议手册(中文翻译版)[附件下载]

经典书籍《UNIX网络编程》最全下载(卷1+卷2、中文版+英文版)[附件下载]

音视频开发理论入门书籍之《视频技术手册(第5版)》[附件下载]

国际电联H.264视频编码标准官方技术手册(中文版)[附件下载]

Apache MINA2.0 开发指南(中文版)[附件下载]

网络通讯数据抓包和分析工具 Wireshark 使用教程(中文) [附件下载]

最新收集NAT穿越(p2p打洞)免费STUN服务器列表 [附件下载]

高性能网络编程经典:《The C10K problem(英文)》[附件下载]

即时通讯系统的原理、技术和应用(技术论文)[附件下载]

技术论文:微信对网络影响的技术试验及分析[附件下载]

华为内部3G网络资料: WCDMA系统原理培训手册[附件下载]

网络测试:Android版多路ping命令工具EnterprisePing[附件下载]

Android反编译利器APKDB:没有美工的日子里继续坚强的撸

一款用于P2P开发的NAT类型检测工具 [附件下载]

两款增强型Ping工具:持续统计、图形化展式网络状况 [附件下载]

Android保活从入门到放弃:乖乖引导用户加白名单吧(附7大机型加白示例)

[3] 精选视频、演讲PPT下载:

美图海量用户的IM架构零基础演进之路(PPT)[附件下载]

开源实时音视频工程WebRTC的架构详解与实践总结(PPT+视频)[附件下载]

QQ空间百亿级流量的社交广告系统架构实践(视频+PPT)[附件下载]

海量实时消息的视频直播系统架构演进之路(视频+PPT)[附件下载]

YY直播在移动弱网环境下的深度优化实践分享(视频+PPT)[附件下载]

QQ空间移动端10亿级视频播放技术优化揭秘(视频+PPT)[附件下载]

RTC实时互联网2017年度大会精选演讲PPT [附件下载]

微信分享开源IM网络层组件库Mars的技术实现(视频+PPT)[附件下载]

微服务理念在微信海量用户后台架构中的实践(视频+PPT)[附件下载]

移动端IM开发和构建中的技术难点实践分享(视频+PPT)[附件下载]

网易云信的高品质即时通讯技术实践之路(视频+PPT)[附件下载]

腾讯音视频实验室:直面音视频质量评估之痛(视频+PPT)[附件下载]

腾讯QQ1.4亿在线用户的技术挑战和架构演进之路PPT[附件下载]

微信朋友圈海量技术之道PPT[附件下载]

手机淘宝消息推送系统的架构与实践(音频+PPT)[附件下载]

如何进行实时音视频的质量评估与监控(视频+PPT)[附件下载]

Go语言构建高并发消息推送系统实践PPT(来自360公司)[附件下载]

网易IM云千万级并发消息处理能力的架构设计与实践PPT [附件下载]

手机QQ的海量用户移动化实践分享(视频+PPT)[附件下载]

钉钉——基于IM技术的新一代企业OA平台的技术挑战(视频+PPT)[附件下载]

微信技术总监谈架构:微信之道——大道至简(PPT讲稿)[附件下载]

Netty的架构剖析及应用案例介绍(视频+PPT)[附件下载]

声网架构师谈实时音视频云的实现难点(视频采访)

滴滴打车架构演变及应用实践(PPT讲稿)[附件下载]

微信海量用户背后的后台系统存储架构(视频+PPT)[附件下载]

在线音视频直播室服务端架构最佳实践(视频+PPT)[附件下载]

从0到1:万人在线的实时音视频直播技术实践分享(视频+PPT)[附件下载]

微信移动端应对弱网络情况的探索和实践PPT[附件下载]

Android版微信从300KB到30MB的技术演进(PPT讲稿)[附件下载]

从零开始搭建瓜子二手车IM系统(PPT)[附件下载]

极光分享:高并发海量消息推送系统架构演进(视频+PPT)[附件下载]

微信红包系统可用性设计实践(PPT) [附件下载]

微信红包数据架构演变(PPT) [附件下载]

百度网盘千万节点的P2P架构设计(PPT) [附件下载]

瓜子IM智能客服系统的数据架构设计(PPT) [附件下载]

基于C++构建微信客户端跨平台开发框架(PPT) [附件下载]

(本文同步发布于:http://www.52im.net/thread-3033-1-1.html

posted @ 2020-06-24 13:55 Jack Jiang 阅读(610) | 评论 (0)编辑 收藏

     摘要: 1、引言好久没写技术文章了,今天这篇不是原理性文章,而是为大家分享一下由笔者主导开发实施的IM即时通讯聊天系统,针对大量离线消息(包括消息漫游)导致的用户体验问题的升级改造全过程。文章中,我将从如下几个方面进行介绍:1)这款IM产品的主要业务及特点;2)IM系统业务现状和痛点;3)升级改造之路;4)消息ACK逻辑的优化。下述内容都是根据笔者开发IM的亲身经历总结下来的宝贵经验,干货满满,期待你的点...  阅读全文

posted @ 2020-06-17 13:47 Jack Jiang 阅读(397) | 评论 (0)编辑 收藏

1、内容点评

本文以轻松幽默的语气,讲解了视频编解码的一些基本常识,并以爱奇艺为例,讲述了视频编解码技术在国内的发展以及未来的一些展望。

▼ 阅读本文需要有一些音视频编解码技术的基础,否则请先阅读以下文章:

即时通讯音视频开发(一):视频编解码之理论概述

即时通讯音视频开发(二):视频编解码之数字视频介绍

即时通讯音视频开发(三):视频编解码之编码基础

即时通讯音视频开发(十九):零基础,史上最通俗视频编码技术入门

本文并未就具体的视频编解码概念进行深入的讨论,目的是尽可能以浅显易懂的方式让读者轻松了解本文标题想呈现的内容。如果您想深入了解视频编解码技术,可继续阅读以下文章。

▼ 以下是比较深入的视频编解码相关文章:

即时通讯音视频开发(四):视频编解码之预测技术介绍

即时通讯音视频开发(五):认识主流视频编码技术H.264

即时通讯音视频开发(十三):实时视频编码H.264的特点与优势

即时通讯音视频开发(十七):视频编码H.264、VP8的前世今生

即时通讯音视频开发(十八):详解音频编解码的原理、演进和应用选型

移动端实时音视频直播技术详解(四):编码和封装

[观点] WebRTC应该选择H.264视频编码的四大理由

▼ 爱奇艺技术产品团队还分享了其它两篇文章,有兴趣也可以读一读:

爱奇艺移动端网络优化实践分享:网络请求成功率优化篇

爱奇艺技术分享:爱奇艺Android客户端启动速度优化实践总结

欢迎关注“即时通讯技术圈”,更多好文会同步发布在公众号:

(本文同步发布于:http://www.52im.net/thread-3028-1-1.html

2、正文引言

初夏最火的造型是什么?不少人可能会脱口而出——“淡黄的长裙,蓬松的头发。。。”

就连我这个上古时期的老年人,都开始每周四和周六准时点开爱奇艺首页,吸一口青春美少女们。原因无他,后疫情灰色时期,还有什么能比漂亮小姐姐的灿烂笑容更能让人感觉到人间值得呢?而我上一次真情实感追完的的女团选秀,可能要追溯到……《超级女声》。

 

不管自己pick的姐姐妹妹能不能顺利出道,至少今天在屏幕上欣赏她们的颜,绝对是一件超幸福的事儿。既不用忍受电视的“马赛克画质”,还能随时随地掏出手机来欣赏妹妹们今日份的可爱。

 

不知道大家有没有同一种快乐,那就是用4G网络看蓝光1080P,已经没有“流量焦虑”了,出现缓冲旋转“小菊花”的情况的几率也在悄然减少。这种观看体验的优化,除了通信网络环境的改变之外,缔造这种视觉快乐的一项关键技术——视频编码,就像是宇宙中的暗物质——鲜为人知,但十分重要。

简单来说:视频编码技术的升级,能够让你用更少的流量、更低的带宽、更快的速度,看更高清晰度的视频画面。比如《青春有你2》溢出屏幕的元气少女感,是不是比2005年的朦胧美更令人心动呢?

 

习惯了1080P高清的用户,绝对不愿意再回到480P的自动马赛克时代了。那么,视频编码到底在高清视频的烹制中,发挥了怎样神奇的化学反应?搞秀之余,不妨来了解一下视频编码的前世今生,看看无数科技巨头如何围绕它撕得花红柳绿。

3、曾今的视频编码标准,是IT巨头们“跑马圈地”的游戏

曾今的视频编码标准,巨头们争相“入股”,视频编码标准有何诱人之处?

思科、微软、苹果、谷歌、奈飞等这些大名鼎鼎的巨头,为什么都觉得视频编码技术这波“入股不亏”,非要pick助其出道?

回答这个问题之前,有必要先简单解释一下,视频编码技术究竟是干什么的?

简单来说:就是将视频压缩成一定的格式,去除掉其中的空间冗余和时间冗余,形成更适合存储和传输的码流。之所以需要被编码压缩,最主要原因就是原始视频的数据量过于庞大。高清视频文件往往高达1G以上,如果本地播放也就算了,一旦需要将其上传、分享给他人,传输网络和存储设备都扛不住那么巨大的数据量。

所以视频平台就需要对所播放的文件进行重构:

  • 1)通过压缩编码将数据量变小,以方便传输;
  • 2)再依靠解压缩在用户端解码,将视频图像还原出来。

简单总结就是:编码效率决定了你的手机能下载多少部高清视频。

 

如果你经历过一晚上不关机终于下好一部2G大小的视频,却发现播放器弹出一行大字——“该视频无法播放”的绝望,那一定会鼓掌欢迎编解码技术的更新。

 

当然,一些“有流量任性”的小伙伴也会选择直接用4G网络在线观看视频,这时候视频大小可就没什么影响了吧?

这么想可就太天真了。视频编码技术越强,传输需要占用的带宽也就更小,就像堤坝没有加固,但冲击河道的流水变小了,自然也就不会出现出水口淤塞的问题,看视频卡顿、掉帧的事故也就不会上演了。

比如此次疫情期间,网络流量比例不断增加,为互联网服务商带来极大的挑战,传统的解决方案就是在网络带宽有限的前提下,降低视频的清晰度。如,YouTube、亚马逊旗下Prime Video、Netflix等一众互联网视频提供商都在欧洲、印度、澳大利亚等国家降低了视频画质,用户只能默认收看标清视频。

可是,吃惯了高清这盘珍馐,哪个用户还愿意忍受低画质的粗茶淡饭呢?为了留住挑剔的内容食客们,平台们不得不想尽办法,提升对视频的烹饪技艺。

那么,让我们得以随时随地追剧追综的视频编解码技术,到底有哪些呢?

目前,国际上主要有几种主流的视频编解码标准(国际上音视频编码技术的标准化),包括VPx(VP8VP9),H.26x(H.264H.265),AVS(AVS1,AVS2),AVx(AV1)等等。视频平台们用某一种通用编码格式标准,自己开发编码器,就可以用更厉害的标准批量生产视频了。

可详读以下相关文章:

即时通讯音视频开发(五):认识主流视频编码技术H.264

即时通讯音视频开发(十三):实时视频编码H.264的特点与优势

即时通讯音视频开发(十七):视频编码H.264、VP8的前世今生

[观点] WebRTC应该选择H.264视频编码的四大理由

这些标准都是什么?到底哪个更厉害?为什么每个字符我都认识但完全不知道是干什么的?甚至还有种被张含韵张韶涵张涵予张予曦张馨予等支配的恐惧,傻傻分不清楚……别急,其实就算是流媒体从业者,也很少有人将它们搞清楚。其实吧,只需要了解三个关键点,你就能轻松变成“技术派”碾压不少业内人士了。

简单来说:不同的视频编码标准,就是围绕三个要素所展开的“量子纠缠”的。

4、视频编码标准要素之一:高清

上世纪90年代,第一代视频编码标准H.261和MPEG-1就开始出现,其后几乎每十年就有一次迭代更新。

启动视频编码技术不断演进的核心要素,还是人们对于高清、更高清的不断追求。

视频编码技术每进化一代,视频压缩效率都至少提高了一倍。比如十几年前第二代视频编码标准VP8 和 H.264,只能应用在低于HD的中小分辨率视频上,稍微兼顾一点1080P分辨率。而2012年爱立信公司推出了首款H.265编解码器,所引领的第三代视频编码HEVC标准就只需H.264一半带宽,即可播放相同质量的视频。

啥意思的?如果你是一个拥有过MP4设备的互联网早期弄潮儿,同样大的存储空间,你可以多下载一倍大小的视频,告别四处借硬盘的苦日子。

在线看视频则更爽了,基于编解码标准,智能手机、平板等移动设备也能够直接在线播放 1080P 的全高清视频,还支持4K 和 8K 超高清。也就是说,只要有内容方愿意生产8K视频,平台就能给你100%还原出画面来,而不用受最高清晰度720P这样的限制。

那么,为什么HEVC标准推出2年后,采用AV1格式的消费类设备又开始出现呢?因为移动互联网的爆发,原有的编码标准依然不能完全解决带宽消耗的问题。所以更高效的视频编码标准如AVS3、H.266等,也都相继被研发人员安排上了。

为什么视频平台关于编码标准的“墙头”这么多?

试想一下,如果你用的是一个高分辨率配置的智能手机,但视频只能到480P的清晰度,为硬件高配置花的钱不就白瞎了吗?有的用户为了防止观看卡顿或模糊,还得额外下一个完美解码、格式工厂之类的第三方解码器,将视频转化一下才能看。

而只要视频平台支持更高效率的编解码标准,就能实现低带宽下播放高清视频不卡顿的效果。有现炒的热菜,谁还愿意等打包的盒饭呢?所以细心的读者会发现,编码技术的不断升级,开始让第三方编码工具悄悄退出了追剧党的工具箱。

 

5、视频编码标准要素之二:专利

尽管用户体验是视频编码技术的首要进化原则,但专利所带来的限制与成本,也成为产业风云迭起的重要诱因。

由GE、Technicolor、杜比,飞利浦和三菱等组建的H.265专利联盟HEVC Advance,就向使用该标准的厂商收取专利费。

因此,不少开源标准逐渐崛起。其中谷歌打造的VP9标准就是最负盛名的一个。不仅在实际效率上与HEVC/H.265接近,大大优于H.264及它的前身VP8,而且可以对专利免费使用。很快,YouTube全面支持VP9超高清流媒体节目,Netflix、苹果等也加入其中。

当年,爱奇艺的《破冰行动》无疑是热度最高的"爆款剧"之一,一度引起风靡,高清流畅的画面质感为其加分增色不少,就采用了基于VP9标准开发的全新编码器,就采用了基于VP9标准开发的全新编码器面部细节等方面画面真实感尤为显著。

 

而我国自主知识产权的第二代信源编码标准AVS的出现,更与专利有着不解之缘。

大家的童年有没有出现过DVD这种物件,租一部剧不用等更新一个周末看完的快乐,不亚于今天购买视频平台尊贵的“VIP中P”会员。但中国的DVD行业曾经也遇到过一次严重的专利危机。

2002年,一批出口的DVD产品因为技术专利费的缴纳问题没有解决而被扣押。于是同年6月,数字音视频编解码技术标准工作组成立,2006年,第一代视频编码标准AVS1推出,压缩效率和H.264相当,并且每个编解码器只象征性得收取1元专利费,对互联网上的软件服务更是免收专利费,从此摆脱了只能使用国际标准、被高额专利费卡脖子的窘境。

可以说,目前主流的两大标准VP9和AVS,都是在专利的锁链中生长出来的自由之翼。

6、视频编码标准要素之三:垄断

既然VP9已经开源了,那就抱紧谷歌大腿等大佬迭代再应用不就好了吗?一个国家的大部分视频都坐落在某一个标准体系上,等于将标准的议价权交到了别人手中,面对这种“垄断优势”,谷歌表示,我疯起来可能连自己都打,为了不作恶还是赶紧给自己培养个对手吧……

所以2015年,一个由谷歌倡议并参与,试图替代VP9和HEVC/H.265的新标准组织成立了,那就是开放媒体联盟Alliance for Open Media(AOM)。这个新的开源标准很快吸引了Adobe、亚马逊、AMD、奈飞、Facebook、思科、苹果、英特尔、英伟达等等巨头的参与。中国的爱奇艺也率先加入了AOM联盟。

这个由30多家领先的高科技公司组成的会员制联盟,很快开发出了新一代开源的视频编码标准AV1(AOMedia Video Codec 1.0),也就是今天能让我们看到高清版《青春有你2》,特别是选秀舞台上的说唱、劲舞的画面更加清晰平滑的“后台”。

 

AV1之所以在产业端迅速上马,成为包括奈飞、YouTube、BBC、爱奇艺等一众平台的推行目标,主要就是在用户体验上太能打了。

更高的编码效率、更低的码率,同等质量可以节省20%以上的带宽。举个例子,就是下载整期1080P版《青春有你2》,原本需要10G的手机存储,而AV1标准下只需要8G就能搞定,剩下2G空间咱们存点PLMM(漂亮妹妹)的高清大图舔颜它不香吗?

在线观看也很爽,不仅妹妹们的脸看起来会更清晰,而且高清播放所占的带宽也更小,同时下载个东西、刷个微博啥的,也不会因为网络拥挤而卡顿。

作为视频观众,谁不愿意平台默默地为我们殚精竭虑,周全每一点流量、带宽和存储卡呢?

 

不难看出,视频编码标准迭代,既是技术天花板的层层上探,也是整个视频平台必须攻占的体验高地。

7、如今,国内的视频平台正在抢跑编码标准“赛道”

具体到国内视频平台上,关于编码标准目前竞争身位如何,未来还有哪些硬仗要打,都是值得我们重点关注的话题。我们不妨具体到某一个平台的探索经历之中,用历史观的视角来捋一捋,视频编码技术到底给中国这片土地的网民,带来了哪些体验上的蝶变。

比如:以爱奇艺为例,2016年爱奇艺在万能播放器上线了AVS2格式,是当时国内唯一支持这一标准的平台;也是国内第一个实现VP9标准、AV1标准并应用的视频厂商。可以说在编码标准领域,无论是技术领先度、布局完善度上,都能够从一定程度代表中国流媒体产业的关键抉择。

有了标准,是不是只需要拿来直接上手呢?答案显然是否定的。

拿爱奇艺来说,我们的标准探索之旅,又是如何的呢?

我们就以当前效率最高的AV1标准为例,其算法运算复杂度高,所需要的编码时间很长,这样把平台所有视频都处理一遍,可能会等来用户一句“奶奶你等的AV1格式上线了”!

所以,为了提高编码效率,让处理效果能够快速细致,又不影响编码质量,达到工业应用标准,标准编码器就要靠各个平台发挥自主能动性了。

以爱奇艺为例,对每一代开源技术都保持紧密跟进的同时,也会发挥自身的技术特长来进行针对性的迭代,让同一标准在爱奇艺平台上的应用有更优秀的表现。

比如VP9标准推出时,爱奇艺的技术团队就根据开源的版本VP9编码器进行了专门的算法优化,所开发的QVP9编码器的速率是开源版本的5.4倍左右。作为国内首先支持VP9的视频厂商,其画面质量在快速镜头、轮廓边缘、面部细节等方面真实感尤为显著,压缩效率比市面主流的标准更是提升了一倍。可能也是在不知不觉间,突然发现视频中那些高速打斗的场面似乎更加细腻流畅了,人物的皮肤也变得更加立体和容易辨别,连女主角额头的青春痘都是那么的昭然若揭……

 

而伴随着用户在移动场景下观看视频的诉求越来越高,比如我本人就喜欢在地铁上刷短视频,别问,问就是流量多有钱任性!这时候要保证流畅不卡顿,主打PC端的VP9可能就有点不够了,所以对移动端设备更友好的AV1,在推出后也很快被安排的明明白白。

独立研发的QAV1编码器,不仅比H265减小将近一半的带宽,节省40%以上码率。而且速度比开源编码器SVT-AV1还快出5倍左右。比如同样是看《青春有你2》,用QAV1展示的画面效果更棒、颜值更高,反而还更省带宽,直接帮助我节省了不少流量,让满额限速来的更晚一些。

 

8、展望未来,5G让视频编解码技术有了更多的想象空间

目前,首批应用 AV1 的电影已经在爱奇艺上线,用户可以在电脑浏览器端和安卓移动端观看。做到这一步,很难吗?

答案是肯定的。举个例子,终端硬件解码芯片的成熟,与某项标准能否发挥价值有直接关系。比如H.265在硬件支持上比较广泛,就与苹果、高通、英特尔等的芯片都支持H.265的硬件解码器有关。

所以编码器往往需要结合具体的应用场景来进行改进和深度优化。

以AV1在爱奇艺的应用为例,为了更好地适应爱奇艺海量内容,QAV1通过对场景复杂度的预分析,实现了更加合理的码率分配。对于简单场景,QAV1可以自适应地降低码率,在保证画质的情况下节省用户带宽;同时对于复杂场景会适当提高码率,给用户带来更高画质的体验。

 

目前,QAV1已经支持的功能包括多种速度档次、多种码率控制方式、8K视频编码等。这种与差异化环境相匹配的细节打磨,同时兼顾了网络带宽与用户体验。

万众期待的5G,自然也需要与之匹配的视频编码标准来呼应。以爱奇艺为例来说,AVS3应用已经在路上了,用移动智能手机看8K超高清视频、浏览VR新闻资讯、与虚拟偶像互动……这些新娱乐体验,或许都将借助视频编码的技术魔术,被呈现到我们眼前。

从爱奇艺的视频编码探索中,不难看到,技术的时代快车并不容易拿到船票的。唯有长期披荆斩棘,才能顺利摘得王冠。

附录:更多音视频技术方面的资料

[1] 实时音视频开发的精华资料:

即时通讯音视频开发(一):视频编解码之理论概述

即时通讯音视频开发(二):视频编解码之数字视频介绍

即时通讯音视频开发(三):视频编解码之编码基础

即时通讯音视频开发(四):视频编解码之预测技术介绍

即时通讯音视频开发(五):认识主流视频编码技术H.264

即时通讯音视频开发(六):如何开始音频编解码技术的学习

即时通讯音视频开发(七):音频基础及编码原理入门

即时通讯音视频开发(八):常见的实时语音通讯编码标准

即时通讯音视频开发(九):实时语音通讯的回音及回音消除概述

即时通讯音视频开发(十):实时语音通讯的回音消除技术详解

即时通讯音视频开发(十一):实时语音通讯丢包补偿技术详解

即时通讯音视频开发(十二):多人实时音视频聊天架构探讨

即时通讯音视频开发(十三):实时视频编码H.264的特点与优势

即时通讯音视频开发(十四):实时音视频数据传输协议介绍

即时通讯音视频开发(十五):聊聊P2P与实时音视频的应用情况

即时通讯音视频开发(十六):移动端实时音视频开发的几个建议

即时通讯音视频开发(十七):视频编码H.264、VP8的前世今生

即时通讯音视频开发(十八):详解音频编解码的原理、演进和应用选型

即时通讯音视频开发(十九):零基础,史上最通俗视频编码技术入门

实时语音聊天中的音频处理与编码压缩技术简述

网易视频云技术分享:音频处理与压缩技术快速入门

学习RFC3550:RTP/RTCP实时传输协议基础知识

基于RTMP数据传输协议的实时流媒体技术研究(论文全文)

声网架构师谈实时音视频云的实现难点(视频采访)

浅谈开发实时视频直播平台的技术要点

还在靠“喂喂喂”测试实时语音通话质量?本文教你科学的评测方法!

实现延迟低于500毫秒的1080P实时音视频直播的实践分享

移动端实时视频直播技术实践:如何做到实时秒开、流畅不卡

如何用最简单的方法测试你的实时音视频方案

技术揭秘:支持百万级粉丝互动的Facebook实时视频直播

简述实时音视频聊天中端到端加密(E2EE)的工作原理

移动端实时音视频直播技术详解(一):开篇

移动端实时音视频直播技术详解(二):采集

移动端实时音视频直播技术详解(三):处理

移动端实时音视频直播技术详解(四):编码和封装

移动端实时音视频直播技术详解(五):推流和传输

移动端实时音视频直播技术详解(六):延迟优化

理论联系实际:实现一个简单地基于HTML5的实时视频直播

IM实时音视频聊天时的回声消除技术详解

浅谈实时音视频直播中直接影响用户体验的几项关键技术指标

如何优化传输机制来实现实时音视频的超低延迟?

首次披露:快手是如何做到百万观众同场看直播仍能秒开且不卡顿的?

Android直播入门实践:动手搭建一套简单的直播系统

网易云信实时视频直播在TCP数据传输层的一些优化思路

实时音视频聊天技术分享:面向不可靠网络的抗丢包编解码器

P2P技术如何将实时视频直播带宽降低75%?

专访微信视频技术负责人:微信实时视频聊天技术的演进

腾讯音视频实验室:使用AI黑科技实现超低码率的高清实时视频聊天

微信团队分享:微信每日亿次实时音视频聊天背后的技术解密

近期大热的实时直播答题系统的实现思路与技术难点分享

福利贴:最全实时音视频开发要用到的开源工程汇总

七牛云技术分享:使用QUIC协议实现实时视频直播0卡顿!

实时音视频聊天中超低延迟架构的思考与技术实践

理解实时音视频聊天中的延时问题一篇就够

实时视频直播客户端技术盘点:Native、HTML5、WebRTC、微信小程序

写给小白的实时音视频技术入门提纲

微信多媒体团队访谈:音视频开发的学习、微信的音视频技术和挑战等

腾讯技术分享:微信小程序音视频技术背后的故事

微信多媒体团队梁俊斌访谈:聊一聊我所了解的音视频技术

新浪微博技术分享:微博短视频服务的优化实践之路

实时音频的混音在视频直播应用中的技术原理和实践总结

以网游服务端的网络接入层设计为例,理解实时通信的技术挑战

腾讯技术分享:微信小程序音视频与WebRTC互通的技术思路和实践

新浪微博技术分享:微博实时直播答题的百万高并发架构实践

技术干货:实时视频直播首屏耗时400ms内的优化实践

爱奇艺技术分享:轻松诙谐,讲解视频编解码技术的过去、现在和将来

>> 更多同类文章 ……

[2] 开源实时音视频技术WebRTC的文章:

开源实时音视频技术WebRTC的现状

简述开源实时音视频技术WebRTC的优缺点

访谈WebRTC标准之父:WebRTC的过去、现在和未来

良心分享:WebRTC 零基础开发者教程(中文)[附件下载]

WebRTC实时音视频技术的整体架构介绍

新手入门:到底什么是WebRTC服务器,以及它是如何联接通话的?

WebRTC实时音视频技术基础:基本架构和协议栈

浅谈开发实时视频直播平台的技术要点

[观点] WebRTC应该选择H.264视频编码的四大理由

基于开源WebRTC开发实时音视频靠谱吗?第3方SDK有哪些?

开源实时音视频技术WebRTC中RTP/RTCP数据传输协议的应用

简述实时音视频聊天中端到端加密(E2EE)的工作原理

实时通信RTC技术栈之:视频编解码

开源实时音视频技术WebRTC在Windows下的简明编译教程

网页端实时音视频技术WebRTC:看起来很美,但离生产应用还有多少坑要填?

了不起的WebRTC:生态日趋完善,或将实时音视频技术白菜化

腾讯技术分享:微信小程序音视频与WebRTC互通的技术思路和实践

>> 更多同类文章 ……

(本文同步发布于:http://www.52im.net/thread-3028-1-1.html

posted @ 2020-06-10 11:54 Jack Jiang 阅读(352) | 评论 (0)编辑 收藏

本文中文译文由作者“ably.io”发布于公众号“高可用架构”,译文原题:《深入解读HTTP3的原理及应用》、英文原题:《HTTP/3 deep dive》(文末有译文和原文链接),即时通讯网收录时有少许改动,感谢原作者和译者的分享。

1、引言

HTTP3是HTTP协议的最新版本。从诞生之初,HTTP就是交换超文本文档的首选应用层协议。多年来,为了跟上互联网的发展,以及WWW上交换的内容种类增加,HTTP进行了几次重大升级,而HTTP/3就是目前的最新版本。

本文将从HTTP/3的基本概念、技术原理、应用场景和如何使用它等方面进行介绍,确保在有限的篇幅内,能让你通俗地理解它。


 

本文是系列文章中的第12篇,本系列文章的大纲如下:

网络编程懒人入门(一):快速理解网络通信协议(上篇)

网络编程懒人入门(二):快速理解网络通信协议(下篇)

网络编程懒人入门(三):快速理解TCP协议一篇就够

网络编程懒人入门(四):快速理解TCP和UDP的差异

网络编程懒人入门(五):快速理解为什么说UDP有时比TCP更有优势

网络编程懒人入门(六):史上最通俗的集线器、交换机、路由器功能原理入门

网络编程懒人入门(七):深入浅出,全面理解HTTP协议

网络编程懒人入门(八):手把手教你写基于TCP的Socket长连接

网络编程懒人入门(九):通俗讲解,有了IP地址,为何还要用MAC地址?

网络编程懒人入门(十):一泡尿的时间,快速读懂QUIC协议

网络编程懒人入门(十一):一文读懂什么是IPv6

网络编程懒人入门(十二):快速读懂Http/3协议,一篇就够!》(本文)

学习交流:

- 即时通讯/推送技术开发交流5群:215477170 [推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

欢迎关注“即时通讯技术圈”,更多好文会同步发布在公众号:

(本文同步发布于:http://www.52im.net/thread-3020-1-1.html

2、相关文章

从HTTP/0.9到HTTP/2:一文读懂HTTP协议的历史演变和设计思路

网络编程懒人入门(七):深入浅出,全面理解HTTP协议

脑残式网络编程入门(三):HTTP协议必知必会的一些知识

网络编程懒人入门(十):一泡尿的时间,快速读懂QUIC协议》(推荐)

技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解》(推荐)

3、HTTP协议的演进史

在万维网诞生之时,万维网仅仅是一群交换超文本文件的计算机。在计算机之间交换文件是一个简单的程序,包括请求和响应。在此基础上设计了一个简单的基于文本的协议。HTTP(超文本传输协议)应运而生。后来,它被起草成了一个标准化的IETF协议,定义在RFC 1945中,也被称为HTTP/1.0。

多年来,HTTP从HTTP/1.0发展到HTTP/1.1,再到HTTP/2。在每一次迭代中,协议都增加了新的功能,以处理大量的需求,如应用层需求、安全考虑、会话处理和媒体类型等。要深入了解HTTP/2及其演进史,可详读《从HTTP/0.9到HTTP/2:一文读懂HTTP协议的历史演变和设计思路》。

尽管经历了几次修订,但HTTP的底层传输机制基本没有变化。但是,随着互联网流量的激增,在移动电话的推动下,HTTP的传输机制在保证网页浏览体验的流畅性方面变得问题重重。

HTTP/3是为了处理HTTP/2.0的传输相关问题而生的,可以在各种设备上更快地访问Web。它基于一个新的传输层协议,称为QUIC(Quick UDP Internet Protocol),在UDP之上工作。这一选择与之前版本的HTTP截然不同,之前版本都是基于TCP。TCP是一个比UDP更可靠的协议,那么为什么要在UDP之上重新设计HTTP的传输层呢?


 

让我们来看看在TCP上运行HTTP的局限性,并深入了解一下基于QUIC协议的HTTP/3的设计思想。

4、什么是HTTP/3

当IETF正式标准化HTTP/2时,Google正在独立构建一个新的传输协议,名为gQUIC。它后来成为新互联网草案,并被命名为QUIC。gQUIC最初的实验证明,在网络条件较差的情况下,gQUIC在增强网页浏览体验方面的效果非常好。因此,gQUIC的发展势头越来越好,IETF的大多数成员赞成建立一个在QUIC上运行的HTTP新规范。这个新的倡议被称为HTTP/3,以区别于当前的HTTP/2标准。


 

从语法和语义上看,HTTP/3与HTTP/2相似。HTTP/3遵循相同的请求和响应消息交换顺序,其数据格式包含方法、标题、状态码和body。然而,HTTP/3的显著的偏差在于协议层在UDP之上的堆叠顺序。


 

有关QUIC的更多资料,可以看看《网络编程懒人入门(十):一泡尿的时间,快速读懂QUIC协议》、《技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解》。

5、HTTP/3 是如何工作的?

HTTP/3功能的核心是围绕着底层的QUIC协议来实现的。在讨论QUIC和UDP之前,我们有必要先列出TCP的某些限制,这也是导致QUIC发展的原因。

5.1 TCP可能会间歇性地挂起数据传输

如果一个序列号较低的数据段还没有接收到,即使其他序列号较高的段已经接收到,TCP的接收机滑动窗口也不会继续处理。这将导致TCP流瞬间挂起,在更糟糕的情况下,即使所有的段中有一个没有收到,也会导致关闭连接。这个问题被称为TCP流的行头阻塞(HoL)。


 

5.2 TCP不支持流级复用

虽然TCP确实允许在应用层之间建立多个逻辑连接,但它不允许在一个TCP流中复用数据包。使用HTTP/2时,浏览器只能与服务器打开一个TCP连接,并使用同一个连接来请求多个对象,如CSS、JavaScript等文件。在接收这些对象的同时,TCP会将所有对象序列化在同一个流中。因此,它不知道TCP段的对象级分区。

5.3 TCP会产生冗余通信

TCP连接握手会有冗余的消息交换序列,即使是与已知主机建立的连接也是如此。


 

QUIC协议在以下设计选择的基础上,通过引入一些底层传输机制的改变,解决了这些问题。

1)选择UDP作为底层传输层协议:在TCP之上建立新的传输机制,将继承TCP的上述所有缺点。因此,UDP是一个明智的选择。此外,QUIC是在用户层构建的,所以不需要每次协议升级时进行内核修改。

2)流复用和流控:QUIC引入了连接上的多路流复用的概念。QUIC通过设计实现了单独的、针对每个流的流控,解决了整个连接的行头阻塞问题。


 

3)灵活的拥塞控制机制:TCP的拥塞控制机制是刚性的。该协议每次检测到拥塞时,都会将拥塞窗口大小减少一半。相比之下,QUIC的拥塞控制设计得更加灵活,可以更有效地利用可用的网络带宽,从而获得更好的吞吐量。

4)更好的错误处理能力:QUIC使用增强的丢失恢复机制和转发纠错功能,以更好地处理错误数据包。该功能对于那些只能通过缓慢的无线网络访问互联网的用户来说是一个福音,因为这些网络用户在传输过程中经常出现高错误率。

5)更快的握手:QUIC使用相同的TLS模块进行安全连接。然而,与TCP不同的是,QUIC的握手机制经过优化,避免了每次两个已知的对等者之间建立通信时的冗余协议交换。


 

通过在QUIC之上构建基于HTTP/3的应用层,您可以获得增强型传输机制的所有优势,同时保留HTTP/2的语法和语义。但是,你也必须注意到,HTTP/2不能直接与QUIC集成,因为从应用到传输的底层帧映射是不兼容的。因此,IETF的HTTP工作组建议将HTTP/3作为新的HTTP版本,并根据QUIC协议的帧格式要求修改了帧映射。

除此之外,HTTP/3还使用了一种新的HTTP头压缩机制,称为QPACK,是对HTTP/2中使用的HPACK的增强。在QPACK下,HTTP头可以在不同的QUIC流中不按顺序到达。与HTTP/2中的TCP确保数据包的按顺序传递不同,QUIC流是不按顺序传递的,在不同的流中可能包含不同的HTTP头。因此,QPACK使用查找表机制对报头进行编码和解码。

6、为什么HTTP/3很重要?

TCP已经有40多年的历史了。它在1981年通过RFC 793从而标准化。多年来,它经历了多次更新,是一个非常强大的传输协议,可以支持互联网流量的增长。然而,由于设计上的原因,TCP从来就不适合处理有损无线环境中的数据传输。在互联网的早期,有线网络将网络中的每一台计算机连接起来。

现在,随着智能手机和便携式设备的数量超过台式机和笔记本电脑的数量,超过50%的互联网流量已经通过无线传输。这种趋势给整体的网络浏览体验带来了问题,其中最重要的是在无线覆盖率不足的情况下,TCP中的行头阻塞(关于TCP在移动网络下的不足,请阅读《5G时代已经到来,TCP/IP老矣,尚能饭否?》)。

Google的一些初步实验证明,QUIC作为Google部分热门服务的底层传输协议,极大地提高了速度和用户体验。部署QUIC作为YouTube视频的底层传输协议,导致YouTube视频流的缓冲率下降了30%,这直接影响了用户的视频观看体验。在显示谷歌搜索结果时,也有类似的改善。

网络条件较差的情况下提升非常明显,这促使谷歌更加积极地完善该协议,并最终向IETF提出标准化。

由于这些早期的试验所带来的所有改进,QUIC已经成为带领万维网走向未来的重要因素。在QUIC的支持下,HTTP从HTTP/2到HTTP/3的改头换面,朝着这个方向合理地迈出了一步。


 

7、HTTP/3的最佳用例

HTTP/3将改善我们上网的体验,特别是在仍无法使用高速无线网络的地区。尽管HTTP/2已经解决了一部分问题,然而HTTP/3更进一步。

7.1 物联网(IoT)

HTTP可能不是物联网的首选协议,但在某些情况下,基于HTTP的通信非常适合特定的应用。HTTP/3可以解决从传感器收集数据的移动电话的无线连接损耗问题。这个问题同样适用于安装在车辆或可移动资产上的独立IoT设备。通过HTTP来访问这些设备,可以更加可靠。

7.2 大数据

全球各地的企业都在觉醒,意识到从多个部门收集数据的潜力,并将其整合成更大的信息共享API,供内部和外部受众共享。这些API也为数据的货币化铺平了道路,通过托管这些数据作为流API服务可以实现数据的货币化。随着时间的推移,这些服务会吐出海量的数据。通过HTTP/3托管的流API将使它们比HTTP/2更健壮、更有弹性。

7.3 Web VR

随着浏览器能力的提升,内容格局正在快速变化。其中一个领域就是基于网络的VR。虽然还处于起步阶段,但有很多的用例可以让VR在加强协作方面发挥关键作用。网络在促进VR互动方面占据了核心位置。VR应用需要更多的带宽来渲染虚拟场景中的复杂细节,因此迁移到HTTP/3会大有收获。

8、HTTP/3的局限性

过渡到HTTP/3不仅涉及到应用层的变化,还涉及到底层传输层的变化。因此,与它的前身HTTP/2相比,HTTP/3的采用更具挑战性,因为后者只需要改变应用层。传输层承受着网络中的大量中间层审查。这些中间层,如防火墙、代理、NAT设备等会进行大量的深度数据包检查,以满足其功能需求。因此,新的传输机制的引入对IT基础设施和运维团队来说有一些影响。

然而,HTTP/3被广泛采用的另一个问题是,它是基于QUIC的,在UDP上运行。大多数的Web流量,以及IETF定义的知名服务都是在TCP之上运行的。这也是为什么长时间运行HTTP/3的UDP会话会被防火墙的默认数据包过滤策略所影响的原因。

随着IETF正在进行的标准化工作,这些问题最终都会得到解决。此外,考虑到Google在早期QUIC实验所显示的积极结果,人们对HTTP/3的支持是压倒性的,这将最终迫使中间层厂商标准化。

针对受限的IoT设备,HTTP/3由于过于繁琐从而无法采用。许多IoT应用部署的设备的外形尺寸非常小。因此,它们的RAM和CPU功率都是有限的。为了使设备在电池功率、低比特率和有损连接等限制条件下高效运行,必须执行此要求。HTTP/3在现有的UDP之上,以QUIC的形式在传输层处理,增加了HTTP/3在整个协议栈中的占用空间。这使得HTTP/3较为笨重,不适合那些IoT设备。但这种情况很少出现,而且存在专门的协议,这就避免了直接在此类设备上支持HTTP的需要。此外,还有以物联网为核心的协议,如MQTT

9、开始使用HTTP/3

IETF的HTTP工作组正致力于在2020年后期发布HTTP/3。因此它还没有被NGINX和Apache等主流web服务器正式支持。不过,有几个lib可以用来实验这个新协议,也提供了非官方的补丁。

以下是支持HTTP/3和QUIC传输lib的列表。请注意,这些实现都是基于互联网标准草案某一个版本,而这个版本很可能会被更高的版本所取代,最终的标准会在RFC中发布。

1)Quiche :

Quiche提供了通过QUIC协议发送和接收数据包的底层编程接口。它还支持HTTP/3模块,通过其QUIC协议实现发送HTTP数据包。除此之外,它还为NGINX服务器提供了一个非官方的补丁,可以安装和托管一个能够运行HTTP/3的Web服务器。除此以外,还提供了额外的程序来支持Android和iOS移动应用上使用HTTP/3。

2)Aioquic

Aioquic是QUIC的python实现。它还内置HTTP/3的测试服务器和客户端库。Aioquic建立在asyncio模块之上,asyncio模块是Python的标准异步I/O框架。

3)Neqo

Neqo 是 Mozilla 使用 Rust 实现 QUIC 和 HTTP/3。

如果你想尝试QUIC,请查看这个由QUIC工作组维护的QUIC协议的开源实现链接:https://github.com/quicwg/base-drafts/wiki/Implementations

(本文英文原文链接:点此进入、中文译文链接:点此进入

附录:更多有关HTTP协议的文章

网络编程懒人入门(七):深入浅出,全面理解HTTP协议

技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解

让互联网更快:新一代QUIC协议在腾讯的技术实践分享

从HTTP/0.9到HTTP/2:一文读懂HTTP协议的历史演变和设计思路

脑残式网络编程入门(三):HTTP协议必知必会的一些知识

脑残式网络编程入门(四):快速理解HTTP/2的服务器推送(Server Push)

Comet技术详解:基于HTTP长连接的Web端实时通信技术

WebSocket详解(四):刨根问底HTTP与WebSocket的关系(上篇)

WebSocket详解(五):刨根问底HTTP与WebSocket的关系(下篇)

快速理解高性能HTTP服务端的负载均衡技术原理

一分钟理解 HTTPS 到底解决了什么问题

一篇读懂HTTPS:加密原理、安全逻辑、数字证书等

即时通讯安全篇(八):你知道,HTTPS用的是对称加密还是非对称加密?

IM开发基础知识补课(四):正确理解HTTP短连接中的Cookie、Session和Token

即时通讯安全篇(七):如果这样来理解HTTPS原理,一篇就够了

一分钟理解 HTTPS 到底解决了什么问题

一篇读懂HTTPS:加密原理、安全逻辑、数字证书等

小白必读:闲话HTTP短连接中的Session和Token

IM开发基础知识补课:正确理解前置HTTP SSO单点登录接口的原理

基于APNs最新HTTP/2接口实现iOS的高性能消息推送(服务端篇)

全面了解移动端DNS域名劫持等杂症:原理、根源、HttpDNS解决方案等

美图App的移动端DNS优化实践:HTTPS请求耗时减小近半

HTTPS时代已来,打算更新你的HTTP服务了吗?

移动端网络优化之HTTP请求的DNS优化

(本文同步发布于:http://www.52im.net/thread-3020-1-1.html

posted @ 2020-06-03 23:18 Jack Jiang 阅读(399) | 评论 (0)编辑 收藏

     摘要: 1、引言网络优化对于移动端App产品的用户体验至关重要,也与公司的运营和营收息息相关。这里列举两个公开的数据:“《页面加载超过3秒,57%的用户会离开》”“《Amazon页面加载延长1秒,一年就会减少16亿美金营收》”网络性能对于用户体验的影响,将非常直接地反馈到业务的运营上。而且,移动网络固有的弱网问题、DNS问题、连接性能等等都无法跟传统的固定网...  阅读全文

posted @ 2020-05-29 12:06 Jack Jiang 阅读(316) | 评论 (0)编辑 收藏

     摘要: 1、引言网络优化对于移动端App产品的用户体验至关重要,也与公司的运营和营收息息相关。这里列举两个公开的数据:“《页面加载超过3秒,57%的用户会离开》”“《Amazon页面加载延长1秒,一年就会减少16亿美金营收》”网络性能对于用户体验的影响,将非常直接地反馈到业务的运营上。而且,移动网络固有的弱网问题、DNS问题、连接性能等等都无法跟传统的固定网...  阅读全文

posted @ 2020-05-29 12:05 Jack Jiang 阅读(230) | 评论 (0)编辑 收藏

1、引言

IM应用的初学者们,在补全了各种基础技术知识后(如果您仍不具备这些知识,建议马上阅读《新手入门一篇就够:从零开发移动端IM》),在动手编码实践时,很多时候纠结的并不是功能该如何实现,而是这个功能该实现成什么样(没有经验,我特玛能找谁问问?)。

比如,最常见的纠结有以下这些:

  • 1)离线聊天消息该保存多久?
  • 2)好友请求应该保存多久?
  • 3)短视频消息中的视频时长设为多大合适?
  • 4)图片、短视频、语音这些多媒体消息中,未读的文件数据保存多久?
  • 5)群管理的逻辑该怎么弄?参考微信?还是参考QQ?(关键是参考资料哪里有?)
  • 6)朋友圈限制最多发几张照片合适?
  • ... ...

嗯,这些问题,老板认为并不是问题,因为可以“参考微信”啊!

然而,微信又不会亲口说出来它的这些规则到底是多少?难不成要一个一个去试?那太扯了!

本文将根据微信官方目前已公开的资料,将它的一些常用功能参数和逻辑规则资料进行了汇总整理,希望能助力你的IM开发!(本文已发布于:http://www.52im.net/thread-3008-1-1.html

学习交流:

- 即时通讯/推送技术开发交流5群:215477170[推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM》

本文已同步发布于“即时通讯技术圈”公众号,欢迎关注:

▲ 本文在公众号上的链接是:https://mp.weixin.qq.com/s/F-pVE9vN21h0Vm8LwnYplg

2、资料来源

本文中整理的所有内容均来自微信官方知识库,如果存在不全或不准确的情况,请在评论中回复,我会逐条核实并修订。

* 特别申明:本文内容仅供研究和学习使用,请勿用作其它用途。如有不妥之处,请指出,我会及时处理。

3、阅读对象

本文适合作为新老IM开发者的备查资料。本文不适合不懂技术的普通用户阅读,因为所有内容都尽量以技术人员的视解整理和表述。

移动端IM产品中,微信是标杆,也是事实的用户体验标准。所以,无论是被老板或产品经理怼,直接说“微信也这样”,能省去很多口水仗(经验啊)。这也是整理本文的初衷,以及价值所在。

4、相关资源

微信本地数据库破解版(含iOS、Android),仅供学习研究 [附件下载]》(* 推荐研究)

仿微信的IM聊天时间显示格式(含iOS/Android/Web实现)[图文+源码]

5、微信的好友关系规则汇总

5.1 好友验证请求有效期限

有效期限为 3 天。

* 补充规则:微信的好友验证请求只保存在手机本地,当卸载重装后,好友请求会消失且无法找回。

5.2 通讯录分组/好友排序

微信通讯录分组、好友排序,是根据微信通讯录朋友昵称的首字母(或首个汉字拼音首字母)由A-Z排序。

* 补充规则:如果好昵称是特殊符号、数字或Emoji表情(比如爱心、气球等),将会归到#类中。

 

5.3 好友验证规则

  • 1)当开启“加我为朋友时需要验证”后,需你同意接受请求后,才能成为好友;
  • 2)未开启“加我为朋友时需要验证”时,任何人都能添加你为好友(无需你确认)。

* 补充规则:如果不想被他人添加好友时搜索到,微信中可以设置关闭“微信号/手机号/QQ号”等搜索方式。

 

5.4 微信有4种添加好友方式

1)搜索加好友:

输入对方的微信号/QQ号/手机号搜索添加即可,但不支持搜索昵称。

* 补充规则:如果对方将关闭了“通过QQ/手机号/微信号搜索到我”,则没有办法通过此种方法添加好友。

2)雷达加朋友:

当被添加者物理距离很近时,一起按住手机,就可以添加对方为朋友。

3)扫二维码加朋友:

扫描对方的二维码名片,就可以添加对方为朋友。

4)手机联系人:

绑定手机联系人的微信帐号,可以查看到手机通讯录联系人已开通了微信的朋友,并直接添加对方为微信好友。

5.5 好友人数上限

微信最多可以添加 5000 个好友。

5.6 通讯录黑名单功能逻辑

将对方加入黑名单后,与对方的关系逻辑如下:

  • 1)在自己的会话列表不再显示与其聊天记录,解除黑名单后会重新出现在会话列表中;
  • 2)在对方的通讯录好友列表中仍然会显示;
  • 3)将不再接收到对方的消息;
  • 4)对方无法给你发消息,会提示“对方拒绝接收您的消息”,自己可以给对方正常发送消息;
  • 5)互相无法查看更新后的头像、个性签名;
  • 6)对方将无法查看你的微信个人相册和对照片进行评论;
  • 7)互相看不到朋友圈更新,拉黑之前在朋友圈分享的照片也不在对方朋友圈展示。

5.7 当被对方删除或“拉黑”后的聊天效果

当好友将你删除或加入黑名单后,你给他发消息时,微信将出现以下提示。

对方将我加入黑名单后,我发消息时的微信提示:

对方把我删除后,我发消息时的微信提示: 

6、微信的群聊规则汇总

6.1 微信群的功能定位

微信群相当于QQ中的讨论组,所以没有QQ里的群号码这种东西。

6.2 群主规则

群的创建者默认是群主。

* 补充规则:当创建者退出该群时,群成员列表中的第一位(也就是建群以来第2个加群的人)将自动成为新群主(好奇葩的规则!)。

另外:当原群创建者(即原群主)再次加群时,身份将会是普通群员。

6.3 群员邀请规则

群成员可以拉其他人加入群,群主不能取消普通群员的这个能力。

* 补充规则:群主可以设置邀请需确认,即需群主确认后才可以让被邀请的好友加到群内。

6.4 群名称规则

每个人(不只是群主)都可以修改群名称。

* 补充规则:当群超过 100 人时,只有群主可以修改群名称。

6.5 群公告规则

只有群主可编辑群公告。

* 补充规则:群公告字数限制为最大 2000 个字(即4000字节)。

6.6 群保存规则

微信群需要手动添加到通讯录才会永久保存,否则它只会保存在本地,一旦你卸载APP后,它就会消失。除非有群内成员发送消息,你才能再次看到,除次之外,你没有别的方法可以找回它。

6.7 群人数限制

微信群最大上限为 500 人。而且,100 人以上的微信群只有已通过实名验证的微信用户才能加入。

6.8 加群验证规则

  • 1)当群人数小于40人时,好友可以自由加入或被邀请加入;
  • 2)当群人数超过40人时,加群邀请需要对方同意;
  • 3)当群人数超过100人时,对方需要通过实名验证才能接受邀请(微信中可以通过绑定银行卡进行实名验证)。

6.9 解散或退出群规则

微信没有像QQ那样的“一键解散群”功能。

可以通过中列方法实现解散群或退出群的能力:

1)如果是群主(创建者或群成员列表第一位),可以将群成员全部删除;

2)如果是普通群员,可以退出群聊。

6.10 群二维码的有效期限

微信群的二维码有效期为 7 天(从二维码生成时开始计算),失效后的2维码扫描时将提示“该二维码已过期”。

6.11 微信群消息屏蔽规则

微信没有屏蔽群聊消息的功能,如果要达到这样的效果,你只能设置不提醒新消息或退出此群。

7、微信的朋友圈规则汇总

7.1 照片数和文字数限制

  • 1)朋友圈照片单次最多可添加 9 张照片,上传照片没有文件数量限制,也没有存储容量限制。
  • 2)最多可输入 1500 个汉字(即 3000 个字节)。

7.2 朋友圈新动态提醒规则

如果关闭了朋友圈更新提醒,当好友有发布新的朋友圈动态时,“发现”按钮上将不会再出现红点提示,否则将提示。

 

7.3 朋友圈查看权限规则

当你未作任何权限设置的情况下:

  • 1)你的所有朋友可以,查看到你在朋友圈发表的所有动态;
  • 2)陌生人可以查看你最近的10条动态。

发新朋友圈时,可以设置回避的人(即设置“谁可以/不可以看”):

  • 1)公开:所有朋友可见;
  • 2)私密:仅自己可见;
  • 3)部分可见:可在通讯录中选择哪些好友可见;
  • 4)不给谁看:可在通讯录中选择哪些好友不可见。
 

可以允许或禁止陌生人查看:

可以允许或禁止陌生人(可能来自扫码但未添加好友、附近的人、摇一摇、群聊时)看到10张最近发的照片。

可以设置朋友圈查看时间范围:

可选择允许好友查看朋友圈最近三天、最近半年或者全部的内容。

可以关闭朋友圈功能:

之前通过朋友圈发表的照片,可在个人相册里查看。但好友仍可以看到。

7.4 朋友圈的评论可见规则

  • 1)评论时,只会通知发布者;
  • 2)当评论时“@”某评论者,只会通知被回复者;
  • 3)评论者只能看到朋友的所有评论(当该条朋友圈的回复者不是朋友时,是看不到他的回复的)。

7.5 朋友圈隐私规则

1)陌生人查看十张照片:

当禁止“允许陌生人查看十张照片”时,陌生人将看不到你发布的任何朋友圈动态。微信默认是允许。

2)不看他(她)的朋友圈(即屏蔽好友的朋友圈):

在您的朋友圈中不会显示对方发送的朋友圈消息。

3)不让他(她)看我的朋友圈(即内容不更新给好友):

对方查看您的朋友圈显示是空白的,不会显示您发送过的任何朋友圈消息。

 

8、微信的聊天消息规则

8.1 聊天记录保存规则

  • 1)微信聊天记录保存在本地手机,一旦卸载微信,则聊天记录永久消失;
  • 2)微信不支持聊天记录漫游功能,一旦更新手机,新手机上无法看到之前手机上的聊天记录。

点评:这里有份完整的微信本地数据库样本,可以用来研究和学习:《微信本地数据库破解版(含iOS、Android),仅供学习研究 [附件下载]》。

8.2 离线消息保存规则

  • 1)微信服务器只保存 72 小时内的离线普通消息(从对方发消息时间开始算起),过期会被服务端清理;
  • 2)微信服务器只保存 72 小时内的多媒体数据(图片、短视频、大文件),即使你的手机已收到该条消息,只要未点击查看,即被视为未读,服务器会在此期限后清理掉多媒体数据。

8.3 “对方正在输入”的显示规则

给对方发送消息后,对方在 10 秒内回复才可以看到该提示。

 

8.4 聊天消息撤回时限

微信的规则是可以撤回2分钟内发送的消息。

8.5 消息已读回执规则

微信不支持已读回执功能。微信认为已读或未读状态属于个人隐私,不希望打破这种自由沟通的感觉。

8.6 语音消息规则

  • 1)最长可录制为 60 秒的语音消息;
  • 2)语音文件格式为:AMR;
  • 3)语音文件压缩比率:60秒语音文件约为45KB。

点评:如果你的IM中,语音文件大大超过微信的这个数据量,就表达存在较大优化空间,可以从采样率等方面进行设置。

8.7 短视频消息规则

  • 1)最长可录制为 10 秒的语音消息;
  • 2)语音文件格式为:MP4;
  • 3)语音文件压缩比率:10秒短视频约文件红为1.5MB至2.0MB。

点评:如果你的IM中,短视频文件大大超过微信的这个数据量,就表达存在较大优化空间,可以从采样率等方面进行设置。

8.8 文件消息规则

微信限制最大可以上传的文件大小为 25 MB。

8.9 聊天消息时间显示规则

  • 1)当天的消息,以每5分钟为一个跨度显示时间(即格式:HH:mm);
  • 2)超过1天、小于1周的消息,将显示“星期+收发消息的时间”;
  • 3)超过1周的消息,将显示手机收发时间的日期(即格式:yyyy-MM-dd)。

点评:这里有一份仿微信的聊天界面时间显示规则代码,可以下载用一用:《仿微信的IM聊天时间显示格式(含iOS/Android/Web实现)[图文+源码]》。

9、微信的其它规则

9.1 收藏功能规则

  • * 收藏的内容:可以收藏文字、语音、图片、视频、地理位置等。
  • * 保存的位置:收藏里面的内容是保存在服务器中的,只要你不主动删除,会一直存在。
  • * 单个文件大小限制:可以收藏的单个文件大小不能超过 25 M。
  • * 存储总容量限制:微信限制收藏数据的总容量为 2 GB,当总收藏容量超出2G后,超出容量的内容,将不能再上传。

9.2 “附近的人”功能规则

  • * 技术实现:当你查看附近的人功能时,微信将通过手机GPS获取你的位置信息,同时会被保留一段时间。
  • * 位置缓存:当你使用过“附近的人”时,服务器就会留下您的地理位置信息一段时间,周围的人可以再次搜到您。

9.3 “摇一摇”功能规则

当距离很近的两个同时“摇一摇”时,不一定能摇到对方。因为微信的“摇一摇”没有距离限制,而且是由服务器随机匹配。

10、电脑版微信的特殊规则

10.1 可以发送的消息类型

微信电脑端,可以发送文字、默认表情、符号表情、动画表情(兔斯基表情)、截图、图片消息,并能同步手机上已收藏的表情并发送。

10.2 可能接收的消息类型

可以接收文字、默认表情、emoji表情、动画表情、图片、文件、语音、视频、公众号消息、名片类型消息、小视频、地理位置消息、转账消息、合并转发的聊天记录消息。

10.3 可以接收但不能查看的的消息类型

红包消息、AA收款消息(收到此类消息会提示请在手机上查看)。

10.4 发送文件的大小限制

微信电脑端,上传文件大小最大为 100 MB,一次最多可以选择10个文件同时发送。

* 补充规则:如果发送的是视频,则文件大小不能超过 25 MB。

附录:微信团队分享技术资料汇总

微信朋友圈千亿访问量背后的技术挑战和实践总结

微信团队分享:微信移动端的全文检索多音字问题解决方案

微信团队分享:iOS版微信的高性能通用key-value组件技术实践

微信团队分享:iOS版微信是如何防止特殊字符导致的炸群、APP崩溃的?

微信团队原创分享:iOS版微信的内存监控系统技术实践

iOS后台唤醒实战:微信收款到账语音提醒技术总结

腾讯技术分享:社交网络图片的带宽压缩技术演进之路

微信团队分享:视频图像的超分辨率技术原理和应用场景

微信团队分享:微信每日亿次实时音视频聊天背后的技术解密

微信团队分享:微信Android版小视频编码填过的那些坑》 

微信手机端的本地数据全文检索优化之路》 

企业微信客户端中组织架构数据的同步更新方案优化实战

微信团队披露:微信界面卡死超级bug“15。。。。”的来龙去脉

月活8.89亿的超级IM微信是如何进行Android端兼容测试的

一篇文章get微信开源移动端数据库组件WCDB的一切!

微信客户端团队负责人技术访谈:如何着手客户端性能监控和优化

微信后台基于时间序的海量数据冷热分级架构设计实践

微信团队原创分享:Android版微信的臃肿之困与模块化实践之路

微信后台团队:微信后台异步消息队列的优化升级实践分享

微信团队原创分享:微信客户端SQLite数据库损坏修复实践》 

腾讯原创分享(一):如何大幅提升移动网络下手机QQ的图片传输速度和成功率》 

腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(下篇)》 

腾讯原创分享(三):如何大幅压缩移动网络下APP的流量消耗(上篇)》 

微信Mars:微信内部正在使用的网络层封装库,即将开源》 

如约而至:微信自用的移动端IM网络层跨平台组件库Mars已正式开源》 

开源libco库:单机千万连接、支撑微信8亿用户的后台框架基石 [源码下载]》 

微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解》 

微信团队原创分享:Android版微信后台保活实战分享(进程保活篇)》 

微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)》 

Android版微信从300KB到30MB的技术演进(PPT讲稿) [附件下载]》 

微信团队原创分享:Android版微信从300KB到30MB的技术演进》 

微信技术总监谈架构:微信之道——大道至简(演讲全文)

微信技术总监谈架构:微信之道——大道至简(PPT讲稿) [附件下载]》 

如何解读《微信技术总监谈架构:微信之道——大道至简》

微信海量用户背后的后台系统存储架构(视频+PPT) [附件下载]

微信异步化改造实践:8亿月活、单机千万连接背后的后台解决方案》 

微信朋友圈海量技术之道PPT [附件下载]》 

微信对网络影响的技术试验及分析(论文全文)》 

一份微信后台技术架构的总结性笔记》 

架构之道:3个程序员成就微信朋友圈日均10亿发布量[有视频]》 

快速裂变:见证微信强大后台架构从0到1的演进历程(一)

快速裂变:见证微信强大后台架构从0到1的演进历程(二)》 

微信团队原创分享:Android内存泄漏监控和优化技巧总结》 

全面总结iOS版微信升级iOS9遇到的各种“坑”》 

微信团队原创资源混淆工具:让你的APK立减1M》 

微信团队原创Android资源混淆工具:AndResGuard [有源码]》 

Android版微信安装包“减肥”实战记录》 

iOS版微信安装包“减肥”实战记录》 

移动端IM实践:iOS版微信界面卡顿监测方案》 

微信“红包照片”背后的技术难题》 

移动端IM实践:iOS版微信小视频功能技术方案实录》 

移动端IM实践:Android版微信如何大幅提升交互性能(一)

移动端IM实践:Android版微信如何大幅提升交互性能(二)

移动端IM实践:实现Android版微信的智能心跳机制》 

移动端IM实践:谷歌消息推送服务(GCM)研究(来自微信)

移动端IM实践:iOS版微信的多设备字体适配方案探讨》 

腾讯信鸽技术分享:百亿级实时消息推送的实战经验

IPv6技术详解:基本概念、应用现状、技术实践(上篇)

IPv6技术详解:基本概念、应用现状、技术实践(下篇)

微信多媒体团队访谈:音视频开发的学习、微信的音视频技术和挑战等

腾讯技术分享:微信小程序音视频技术背后的故事

微信多媒体团队梁俊斌访谈:聊一聊我所了解的音视频技术

腾讯技术分享:微信小程序音视频与WebRTC互通的技术思路和实践

手把手教你读取Android版微信和手Q的聊天记录(仅作技术研究学习)

微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

微信技术分享:微信的海量IM聊天消息序列号生成实践(容灾方案篇)

微信团队分享:Kotlin渐被认可,Android版微信的技术尝鲜之旅

社交软件红包技术解密(二):解密微信摇一摇红包从0到1的技术演进

社交软件红包技术解密(三):微信摇一摇红包雨背后的技术细节

社交软件红包技术解密(四):微信红包系统是如何应对高并发的

社交软件红包技术解密(五):微信红包系统是如何实现高可用性的

社交软件红包技术解密(六):微信红包系统的存储层架构演进实践

QQ设计团队分享:新版 QQ 8.0 语音消息改版背后的功能设计思路

微信团队分享:极致优化,iOS版微信编译速度3倍提升的实践总结

IM“扫一扫”功能很好做?看看微信“扫一扫识物”的完整技术实现

微信团队分享:微信支付代码重构带来的移动端软件架构上的思考

IM开发宝典:史上最全,微信各种功能参数和逻辑规则资料汇总

>> 更多同类文章 ……

(本文同步发布于:http://www.52im.net/thread-3008-1-1.html

posted @ 2020-05-21 13:23 Jack Jiang 阅读(335) | 评论 (0)编辑 收藏

本文引用了公众号“鲜枣课堂”的《5G消息(RCS),到底是什么?》和公众号“InfoQ”的《5G消息来了,它会干掉微信还是变成另一个飞信?》两篇文章的部分内容,感谢原作者的分享。

1、引言

上个月3大运营商(移动、电信、联通)发布了《5G消息白皮书》(此白皮书PDF版 ▶ 点此附件下载),宣布将共同启动5G消息业务。

 

简单理解,5G消息相当于是原先短消息服务的全新升级。与以前的短消息相比,5G消息具有多媒体、能互动服务的能力,不仅有文字、图片,还能发视频、位置,甚至进行支付。

嗯,听起很熟悉——这不就是微信、支付宝们现在干的活吗?

没错!在移动互联网时代已经沦为微信这类IM巨头的管道工的运营商们,正在试图通过5G消息这个新工具抢回失去的话语权。

那么,5G消息到底是什么?是完全的创新技术还是旧式短信技术的新瓶装旧酒?它是否真的具有可以取代现时移动端主流IM产品的能力?请跟着本文,一起读懂5G消息的前世今生!

学习交流:

- 即时通讯/推送技术开发交流5群:215477170[推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

本文已同步发布于“即时通讯技术圈”公众号,欢迎关注: 

▲ 本文在公众号上的链接是:https://mp.weixin.qq.com/s/BF3ja1Uui6Pn32z0zI0H2g

2、5G消息是全新技术?

No,并不是!

“5G消息”,其实和5G并没有什么关系。它既不是5G特有的功能,也不是5G时代新开发出来的业务。它的真实身份,是诞生已有 10 多年的 RCS 技术。

3大运营商之所以要把它名名为“5G消息”,很大原因应该还是想借5G这个热点,从营销推广的角度进行的考虑,与技术无关。

RCS,全称是“Rich Communication Suite”,中文翻译过来就是“富媒体通讯套件”。

什么是“富媒体(Rich Media)”?传统电话只有语音,传统短信只有文本。而“富媒体”,包括文本、语音、图片、视频、动画、表情、位置等多种媒体形式。我们天天在用的微信,就是一种富媒体通信工具。

 

RCS,也被称为融合通信。所谓“融合”,既可以理解为多种媒体形式融合,也可以理解为IP业务和传统电信网业务的融合。

大白话来说,RCS可以理解为它是升级了传统的短信产品,使“短信”丰富化。

3、RCS技术的发展历程

我们先了解一下RCS技术的发展历程。

3.1 传统PC端IM的兴起,让电信厂商们蠢蠢欲动

我们把时间拨回到20多年前。当时,PC互联网以惊人的速度发展壮大,给人类带来了前所未有的信息大爆炸。

尤其是ICQ、MSN、OICQ(即QQ)等即时通讯工具的出现,让人们见识到多媒体通讯的无限乐趣。

 

▲ 能认全这3个IM的,都是老网民

于是,人们想到,这么有趣的通讯方式,是不是可以移植到手机上?

3.2 IMS的出现

3G移动通信标准,就是在这样的背景下建立起来的(2000年5月)。从3G起,手机的重点发展方向变成了数据业务,以满足人们日益增长的多媒体通信需求。

3G向4G的发展过程中,负责牵头标准制定的3GPP组织,考虑到传统语音通话及短信业务也需要向多媒体演进。于是,在2002年的3GPP Release 5版本中正式提出了IMS。

搞通信的读者一定对IMS这个词非常熟悉。如果是非通信专业的读者,我可以告诉你另外一个和IMS密切相关的词,那就是这几年特别火的VoLTE(Voice over LTE)。

是的,VoLTE业务,就是基于IMS实现的。

IMS的全称,叫做IP多媒体子系统(IP Multimedia Subsystem)。它包括了一系列不同的通信设备网元。

IMS的网络结构和业务流程非常复杂。对于IMS的作用,我们可以这么理解——它帮助4G LTE这个纯数据网络,实现对语音通话和短信的支持,并对它们进行强化(升级为多媒体形式)。

 

▲ IMS就是4G LTE网络的一个“插件”。有了它,4G才能打电话和发短信

在IMS的基础上,才有了VoLTE和RCS。

 

3.3 RCS的出现

2007年,RCS由一小部分GSMA(全球移动通信系统协会)成员提出,目的是为了运营商之间的多媒体消息互通。

2008年2月,GSMA正式成立RCS项目,并将其命名为“home”。此后,GSMA发布了多个版本的RCS、RCS-e(enhance,增强型)规范。

 

▲ GSMA,可以理解为全球运营商协会,主要代表运营商利益

RCS发布之后,得到了全球众多运营商的拥护。尤其是2008年4G LTE标准发布之后,RCS成为运营商们建设4G的标配。

3.4 RCS在移动端IM的挤压下持续演进

同样是2008年前后,iPhone和安卓相继问世,移动通信进入智能机时代,移动互联网市场开始井喷。

2011年左右,以WhatsApp、LINE、Facebook Message为代表的OTT通讯工具出现并迅速崛起,大量蚕食了传统运营商的语音、短信收入。

 

于是,海外运营商更加仰仗RCS,希望借此与OTT软件进行竞争。当时Vodafone、Orange、SKT、Verizon、O2等海外知名运营商都推出了自己的RCS解决方案和品牌。

2016年,为了进一步推动RCS的产品开发及全球部署,GSMA推出了RCS Universal Profile(通用配置文件,简称UP,相当于是一个规范标准),并陆续更新了多个版本。目前最新的版本,就是2019年10月发布的Version 2.4。

 

▲ RCS和UP的版本演进

3.5 RCS在国内的发展

我们回过头来看看RCS在国内的发展。

中国的3G和4G建设启动普遍晚于欧美日韩。3G就不用说了,晚了8年。4G是晚了5年。2013年底,工信部才发放了LTE商用牌照。

作为LTE的积极建设者,中国移动在2014年LTE大规模建网的同时,就非常看重IMS、VoLTE、RCS的商业价值。

因为飞信的前车之鉴,中国移动已经充分意识到传统运营商正在出现管道化的趋势,利润空间将不断被挤压,急需和OTT抢占流量入口,寻找新的业务增长点。

 

2015年,就在国内LTE网络覆盖初具规模之后,中国移动大幅提前了国内各省IMS和VoLTE网络的建设进度,并积极推动广州研究院的RCS业务验证和测试。

其实国内的三大运营商也都没有闲着,在 2017 年 4 月就完成了 RCS 三方(3大运营商)互通测试规范编制。其中,中国移动较为积极,在 2017 年 12 月即商用 RCS,包含 Native、App、PC 以及 SDK 四种终端形态。2019 年中移终端公司要求,所有在终端公司入库销售的机型都要支持 RCS Native 功能。

随着5G的到来,情况又发生了不同。

为了给5G网络腾挪更多的频谱空间,运营商必须加速2/3G网络的退网。而依附在2/3G网络上的传统语音和短信业务,必须尽快迁移到LTE和IMS网络上。(国内LTE网络的成熟覆盖,IMS的建设完成,使得RCS的推出具备了很好的时机。)

与此同时,面对OTT业务的持续打压,运营商也希望通过RCS进行最后一搏。于是,就有了这次“5G消息”业务的联合发布。

之所以叫“5G消息”,主要是希望借助5G的品牌,体现RCS业务和传统消息业务之间的代差。

4、RCS到底能实现什么样的功能和体验?

接下来我们讲讲RCS到底能实现什么样的功能,以及用户体验,何以让3大运营商重燃对搞微信等IM巨头的信心。

4.1 运营商对RCS的功能定位

中国移动在2014年曾经基于RCS提出了「三新」目标。这里面的三新,指的是:新通话、新消息以及新联系,分别指代了手机上的电话,短信,通讯录这三大入口。

  1. “新通话”以VoLTE为核心,增强用户通话质量和体验;
  2. “新消息”无缝融合多种媒体和消息格式,无缝与传统短/彩信互通;
  3. “新联系”以真实手机号码为前提,构建全新的社交、公众信息服务入口。

其实,这已经很明确地给出了RCS的功能和定位。

从总体上来看,运营商对RCS的应用场景定位分为两种:

  • 一种是个人用户与个人用户之间的消息交互;
  • 一种是企业用户与个人用户之间的消息交互。
 

4.2 RCS在普通用户间的消息交互与微信等IM相比,优势并不明显

针对场景1(即个人用户与个人用户之间的消息交互),RCS支持点对点消息,支持群发、群聊,支持语音、图片、视频多媒体消息,还支持发送位置、名片等,甚至还支持消息云备份和阅后即焚。

RCS的个人用户聊天时可以支持以下消息类型(跟IM很像): 

这些功能和我们目前的微信都差不多,RCS并没有体现出什么优势。考虑到用户习惯等原因,RCS估计很难撬动微信的霸主地位,未来可能主要是处于一个辅助性的地位。

更受运营商及整个产业关注的,其实是场景2(即企业用户与个人用户之间的消息交互)。

4.3 RCS在企业与个人的消息交互场景下,有很大的想象空间

2017年,GSMA在UP2.0规范中引入MaaP,还发布了MaaP白皮书,明确提出了面向A2P(Application to Person)行业消息的“RCS商业富媒体消息(RCS Business Messaging)”,也就是我们所说的场景2。

 

▲ RCS商业富媒体消息

MaaP,就是Messaging as a Platform,消息即平台。

RCS商业富媒体消息,为企业和个人用户之间提供消息交互接口,在图片和视频等基础上增加了交互能力,方便企业向用户输出个性化服务。

例如机票酒店预订查询、物流查询、网购订单查询等一系列轻应用功能,都可以通过RCS商业富媒体消息实现。

 

RCS商业富媒体消息的价值在于,它为企业和用户提供了一条新通道。借助这条通道,企业可以触达用户。用户也可以触达服务。

从某种意义上来说,它很像小程序、微信公众号(服务号),甚至电话客服中心。

为了实现RCS商业富媒体消息,运营商在自身网络上架设了MaaP能力增强开放平台和Chatbot聊天机器人。平台面向企业开放API接口,以提供服务。

技术架构大概是这样的: 

4.4 RCS拥有普通IM所不具备的优势

运营商对于“5G消息”(即RCS技术)这么有信心,源码它的一些独特的优势。

4.4.1)RCS优势1:它需要单独安装APP

它不需要单独安装第三方APP,手机原生就可以支持。这大幅降低了用户使用门槛,也节约了推广成本。

 

▲ 每个人的手机,都少不了这三个图标

虽然目前大部分手机并不支持5G消息,但后续各大厂商对手机进行软件升级,支持RCS UP 2.4规范之后,都可以支持。即使你不是5G手机(但至少是4G手机),也可以支持。

4.4.2)RCS优势2:无需注册账号

RCS业务和手机号码直接关联,用户号码就是账号,无需注册。

这同样降低了用户使用业务的复杂度,不仅解决了身份认证问题,还打通了“平台孤岛”(无需在每个商户单独注册账号)。

 

▲ 手机号即账号,一号通用

4.4.3)RCS优势3:无需添加好友

RCS牢牢掌握住了用户通信录这个社交金钥匙,无需添加好友,即刻就能建立社交网络。

尽管RCS拥有以上优势,但真正决定它能否走向成功的,并不是这些优势,而是它的生态和商业模式。

RCS的产业链既包括运营商、设备商、终端厂商,也包括平台服务商、内容提供商等。

设备商和终端厂商还好说,关键是平台服务商和内容服务商。它们愿不愿意投入,平台和应用该如何开发,开发能不能获得回报,如何吸引商户,要不要收费,如何收费,商户愿不愿意买单,这些都是未知数。

如果生态不能做大做强,就无法孵化更多的5G消息应用场景,也就谈不上商业价值回报。

5、现在才统一起来做“5G消息”,是否有点迟了?

从 3G 时代开始,全球电信运营商就受到 OTT(“OverTheTop”的缩写,指通过互联网向用户提供各种应用服务)厂商的冲击,国内三大运营商也不例外,传统的话音和短信业务收入大幅下降,OTT 服务虽然能带来流量收入,但也难以掩盖其增量不增收的尴尬。

随着微信等移动端IM互联网应用的不断扩张,运营商虽手握数亿用户,期间也有过大大小小的尝试与挣扎,例如中国移动的飞信、中国联通的沃友以及中国电信的易信,但最终都被边缘化。对 RCS 也有不少投入和试点,却还是雷声大雨点小,掀不起水花。三大运营商依然沦为主要提供语音、短信、流量等基础通信服务的“管道工”。

 

似乎,过度的竞争是导致运营商们错失机遇的主因之一。

某运营商直言:“过去,移动披靡一切。但后来对内‘弄不死’电信和联通,对外干不过阿里腾讯,对上交代不了国资委的考核。”。三大运营商终于联手便是 5G 消息的最大意义。

与采用私有协议的 App“孤岛式”的现状相比,由于三家运营商基于同一的国际标准(GSMA RCS UP 2.4),5G 消息在互联互通上的优势更为明显。

对比过去传统的短信业务,5G 消息可快速迭代——相关技术标准在 3 年内已迭代 5 大版本,从 UP1.0(2016 年 Q4)到最新的 UP2.4(2020 年 Q4)。

6、RCS看起来很美,但并非无懈可击

RCS确实具体先天优势,但也并非无懈可击。

RCS 仍面临三大挑战:

  • 1)用户的服务体验不一致,也给终端互联互通带来挑战(它无法做到像微信这样的IM一样,每款手机上安装的都是同一个应用);
  • 2)消息业务将会不断创新演进,需要终端快速跟进和支持,传统的技术研究、标准制定,终端研发,运营商测试等运营商长周期的流程,难以适应 RCS 快速发展;
  • 3)行业客户对 RCS 业务仍不熟悉,开发门槛较高。

另一方面,要培养用户使用短信入口的服务也不是件易事。

5G 时代,是多终端连接的物联网时代,小程序也被视为物联网众多的入口之一,谁都不会想放过这个机遇。

但 5G 消息能否拿回被微信这种IM应用抢走的市场,又或者在新的物联网增量市场分得一杯羹,尚需时日见证。可以肯定的是,对于客户来说,尤其是行业客户,多了一个选择。一个不是腾讯系,不是阿里系,也不是头条系的选择。

7、虽有不确定性,但RCS未来可期

目前,国内运营商的5G消息业务还处于试点大区联调测试阶段。

2020年4月10日,中兴通讯助力中国移动在杭州成功打通了基于GSMA UP2.4标准的5G消息first call,标志着国内5G消息商用进入正式倒计时。

据业内消息,2020年6月份国内就可以推出5G消息的正式商用。国内手机的升级支持,估计需要3个月到1年的时间。

相信随着5G建设的深入,RCS很快会成为大家手机中的标配。

“5G消息”到底会发展成什么样,作为IM开发者和普通用户来说,商业终究不是普通人该考虑的。从功能和体验上来说,多一种选择也未偿不是件好事,我们期待它早日到来!

 

8、最新动态:中国移动已于2020年5月10日上线“5G消息”APP

“5G消息”App是中国移动基于国际RCS标准打造的一款通讯及服务软件,支持发送文本、图片、音视频、地理位置等丰富消息;还可与商户的聊天机器人进行交互,获取7*24小时的智能服务。已于5月10日上线到苹果App store。

 

不幸的是,“5G消息”App上线仅一天就被下架(下架时间为5月11日)。

中国移动回应下架事件时说:因当前一些终端尚未支持5G消息功能,中国移动开发了“5G消息”APP,可以让开发者完成Chatbot(智能聊天机器人)应用开发后,真实体验消息交互服务,吸引广大开发者积极参与5G消息的合作生态构建,并非面向客户商用发布的产品。

中国移动表示:由于前期三家运营商联合发布5G消息白皮书,引发较高舆论关注,为保护“5G消息”名称不被恶意抢占,中国移动近日在应用市场进行上线(指的就是上线“5G消息”App)。因存在一些技术问题,该APP目前临时下线,稍后会重新上线。

在过去数年里,运营商与苹果公司的沟通讨论一直在进行中。目前通过安装App体验的做法,可以帮助苹果公司和苹果手机用户体验和使用5G消息。

9、《“5G消息”白皮书》附件下载

(附件无法上传,请从此链接下载:http://www.52im.net/thread-3001-1-1.html

10、参考资料

[1] 5G消息白皮书

[2] 中国移动率先发布5G消息APP:支持iOS/Android

[3] “5G消息”来了,App小心了!

[4] 中国移动、中国电信、中国联通联合发布《5G消息白皮书》

[5] 5G消息(RCS),到底是什么?

[6] 5G消息来了,它会干掉微信还是变成另一个飞信?

附录:更多IM产品方面的文章

技术往事:微信估值已超5千亿,雷军曾有机会收编张小龙及其Foxmail

QQ和微信凶猛成长的背后:腾讯网络基础架构的这些年

闲话即时通讯:腾讯的成长史本质就是一部QQ成长史

腾讯开发微信花了多少钱?技术难度真这么大?难在哪?

技术往事:史上最全QQ图标变迁过程,追寻IM巨人的演进历史》 

开发往事:深度讲述2010到2015,微信一路风雨的背后》 

开发往事:记录微信3.0版背后的故事(距微信1.0发布9个月时)》 

微信七年回顾:历经多少质疑和差评,才配拥有今天的强大

前创始团队成员分享:盘点微信的前世今生——微信成功的必然和偶然

QQ的成功,远没有你想象的那么顺利和轻松

[技术脑洞] 如果把14亿中国人拉到一个微信群里技术上能实现吗?》 

QQ和微信止步不前,意味着即时通讯社交应用创业的第2春已来?

那些年微信开发过的鸡肋功能,及其带给我们的思考

为什么说即时通讯社交APP创业就是一个坑?

即时通讯创业必读:解密微信的产品定位、创新思维、设计法则等

老罗最新发布了“子弹短信”这款IM,主打熟人社交能否对标微信?

盘点和反思在微信的阴影下艰难求生的移动端IM应用

QQ现状深度剖析:你还认为QQ已经被微信打败了吗?

那些年微信开发过的鸡肋功能,及其带给我们的思考

渐行渐远的人人网:十年亲历者的互联网社交产品复盘和反思

中国互联网社交二十年:全民见证的互联网创业演义

读懂微信:从1.0到7.0版本,一个主流IM社交工具的进化史

王欣回应微信封禁,解释为何取名“马桶MT”

同为IM社交产品中的王者,QQ与微信到底有什么区别

还原真实的腾讯:从最不被看好,到即时通讯巨头的草根创业史

知识科普:IM聊天应用是如何将消息发送给对方的?(非技术篇)

QQ设计团队分享:新版 QQ 8.0 语音消息改版背后的功能设计思路

社交应用教父级人物的张小龙和马化腾的同与不同

技事往事:你知道IM聊天软件中的“对方正在输入…”功能的起源吗?

盘点移动互联网时代的社交产品进化史(上篇):谁主沉浮

盘点移动互联网时代的社交产品进化史(下篇):大浪淘沙

IM热门功能思考:为什么微信里没有消息“已读”功能?

IM热门功能思考:聊天中加入“对方正在输入…”真的好吗?

别做梦了,社交产品哪有那么容易成功

微信那么牛,为什么海外成功的却是抖音?

专访马化腾:首次开谈个人经历、管理心得、技术创新、微信的诞生等

一文读懂微信之父张小龙:失败天才、颠覆者、独裁者、人性操控师

新技术展望:5G消息能取代IM应用?一文读懂5G消息的前世今生!

>> 更多同类文章 ……

欢迎关注我的“即时通讯技术圈”公众号:

(本文同步更新于:http://www.52im.net/thread-3001-1-1.html

posted @ 2020-05-14 11:47 Jack Jiang 阅读(346) | 评论 (0)编辑 收藏

本文引用了后端技术指南针公众号“浅谈RPC那些事儿1”和即时通讯网的“即时通讯新手入门:快速理解RPC技术——基本概念、原理和用途”两篇文章的部分内容。

1、引言

经常有开发者在纠结怎么开发IM集群,虽然真正的使用人数,可能用个人电脑单机都能支撑。

你也许会说,明明不需要用到IM集群,干吗要自找麻烦?答曰:“老板说这个得有!”、“万一产品做成了,用户量达到百万、千万级呢?”,各种回答,反此种种。总之,IM集群就是得整一个(先甭管用不用的上...)。

当然,玩笑归玩笑,真正要做到可投入到生产级别的IM集群系统,难度还是相当大的。必竟IM这种长连接应用相比传统Http这种短连接应用太不标准。

我们以一个典型的IM聊天消息传输为例:

假设存在两个正在聊天的用户(用户A和用户B),当A连接的是IM集群中的IM实例1、B连接的是IM集群中的IM实例2,此时当用户A向用户B发送一条聊天消息时,这条消息应该如何传递呢?

我们梳理一下上面这个例子的消息流转过程:

  • 1)IM聊天消息首先会由用户A发往IM实例1;
  • 2)IM实例1会将此条消息转交给IM实例2;
  • 3)IM实例2会将此条消息最终投递给连接在本实例上的用户B。

如上述流程所示,这就是一个IM集群系统中典型的聊天消息投递过程。

那么,这其中涉及到一个关键步骤:即第2)步中如何实现“IM实例1会将此条消息转交给IM实例2”?

此时,RPC技术出场了!

 

▲ 上图是个典型的分布式IM架构,注意中间的“RPC通信”字样本图引用自《基于Go的马蜂窝旅游网分布式IM系统技术实践

本文将以通俗易懂的白话形式,帮你快速理解IM集群中的关键技术——RPC。

推荐阅读:另一篇RPC基础知识文章也值得一读《即时通讯新手入门:快速理解RPC技术——基本概念、原理和用途》。

本文已同步发布于“即时通讯技术圈”公众号,欢迎关注:

▲ 本文在公众号上的链接是:https://mp.weixin.qq.com/s/0RXTUWHXDmMddsPVWej2Qg

2、相关文章

▼ 以下两篇文章有助于您对RPC和IM集群有个初步的概念:

即时通讯新手入门:快速理解RPC技术——基本概念、原理和用途》(推荐)

即时通讯新手入门:一文读懂什么是Nginx?它能否实现IM的负载均衡?

▼ IM开发干货系列文章(本文是其第24篇):

IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

IM消息送达保证机制实现(二):保证离线消息的可靠投递

如何保证IM实时消息的“时序性”与“一致性”?

IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?

IM群聊消息如此复杂,如何保证不丢不重?

一种Android端IM智能心跳算法的设计与实现探讨(含样例代码)

移动端IM登录时拉取数据如何作到省流量?

通俗易懂:基于集群的移动端IM接入层负载均衡方案分享

浅谈移动端IM的多点登陆和消息漫游原理

IM开发基础知识补课(一):正确理解前置HTTP SSO单点登陆接口的原理

IM开发基础知识补课(二):如何设计大量图片文件的服务端存储架构?

IM开发基础知识补课(三):快速理解服务端数据库读写分离原理及实践建议

IM开发基础知识补课(四):正确理解HTTP短连接中的Cookie、Session和Token

IM群聊消息的已读回执功能该怎么实现?

IM群聊消息究竟是存1份(即扩散读)还是存多份(即扩散写)?

IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列

一个低成本确保IM消息时序的方法探讨

IM开发基础知识补课(六):数据库用NoSQL还是SQL?读这篇就够了!

IM里“附近的人”功能实现原理是什么?如何高效率地实现它?

IM开发基础知识补课(七):主流移动端账号登录方式的原理及设计思路

IM开发基础知识补课(八):史上最通俗,彻底搞懂字符乱码问题的本质

IM的扫码登功能如何实现?一文搞懂主流应用的扫码登陆技术原理

IM要做手机扫码登陆?先看看微信的扫码登录功能技术原理

IM开发基础知识补课(九):想开发IM集群?先搞懂什么是RPC!》(本文)

如果您是IM开发初学者,强烈建议首先阅读《新手入门一篇就够:从零开发移动端IM》。

3、正文概述

限于篇幅原因,本文不会深入展开RPC的底层技术原理,会尽量用通俗白话的方式对概念性的东西进行讲解。

通过本文你将主要了解到以下内容:

  • 1)什么是RPC;
  • 2)为什么需要RPC;
  • 3)RPC的重要组件;
  • 4)常见RPC框架和各自特点。

4、什么是RPC?

RPC 是1984年代由 Andrew D. Birrell & Bruce Jay Nelson 提出的(见二位大佬的论文《Implementing Remote Procedure Calls),所以它并不是最近才有的技术概念。

关于RPC的介绍,正经的资料上大概是这样介绍的:

RPC(Remote Procedure Call)远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。

大白话理解RPC就是:RPC让你用别人家的东西就像自己家的一样。

看得我似懂非懂,于是我不得不问几个问题:

  • 1)为啥要用别人家的东西——请求其他服务);
  • 2)我怎么可以借到别人家的东西——其他服务调用;
  • 3)要是借用的话哪种形式更好——确定一个合适的调用方法);
  • 4)怎么让我用别人东西像自己的一样——屏蔽底层细节透明通信)。

在解答这些问题之前,我们必须达到一个共识问题:RPC只是一种通信模式,和http并不冲突对立,相反http可以作为RPC传输数据的一种协议,把RPC当作一种模式和思想,我们才能更好地理解它。

更严谨的RPC基础知识介绍,请阅读:《即时通讯新手入门:快速理解RPC技术——基本概念、原理和用途》。

5、为什么需要RPC?

以大家最熟悉的电商系统为例,这样规模的分布式系统,需要拆分出用户服务、商品服务、优惠券服务、支付服务、订单服务、物流服务、售后服务等等。这些服务之间都相互调用,这时内部调用最好使用 RPC ,同时每个服务都可以独立部署,独立上线。 

也就说当我们的项目太大,需要解耦服务,扩展性强、部署灵活,这时就要用到 RPC ,这主要是解决了分布式系统中,服务与服务之间的调用问题。

 

▲ 上图中的分布系统内部,就是用RPC实现的本图引用自《从新手到架构师,一篇就够:从100到1000万高并发的架构演进之路

对于IM集群这样的分布式系统来说,不同IM实例间的用户聊天消息,就是通过RPC进行流转的。

6、为什么不直接使用HTTP,而要搞RPC?

在日常业务中我们可以把功能封装成静态库、动态库、sdk、独立服务等,最常见也最方便的还是HTTP这种形式的调用。

HTTP服务把需要提供的服务暴露成接口(也就是通常所说的http rest接口啦),使用方直接按约定的HTTP方法和URI进行数据交互。

我们都知道HTTP协议是应用层协议,是个非常标准的协议,在HTTP协议之下还有网络层、传输层、数据链路层等,一个数据包packet除了净荷payload之外还有很多header,由于标准和通用性的设计目标也使得HTTP一次数据交互真正传输的payload只是其中一部分。

 

HTTP是我们用的最多最熟悉的交互模式,在系统内部各个服务之间接口较少,交互不多的情况下工作得还不错。

但如果在内部系统调用很复杂的前提下,HTTP调用的效率和安全性就不那么理想了。

 

以IM系统为例,单个IM实例的吞吐效率至少可以达到几万甚至数十万QPS,使用HTTP这种短连接(调用时建立socket连接,完成后释放连接)方式显的相当低效(每次调用都要重新经历TCP的3次握手、4次挥手过程),在分布式的情况下势必拉低整个IM集群的吞吐效率。而对于RPC,这种socket长连接方式对于高性能场景来说,效果是显而易见的。

更重要的是面对众多的服务我们需要的不仅仅是一个通信方式,而是一个内部服务的管理系统,这也就是我们今天说的RPC框架。注意:RPC是一种模式策略和框架,并不是单纯的通信协议。

题外话:实际上,HTTP在RPC系统中,并不是个你死我活的关系,必竟HTTP只是个通信协议,而HTTP有某些性能要求不敏感的场景来说,是完全可以作为RPC的具体实现协议之一来使用的。

7、RPC的调用过程是什么样的?

 

▲ 典型的RPC调用过程

如上图所示,一个典型的RPC调用过程是这样(过程序号对应上图中的数字):

  • 1)客户端(client)以本地调用方式调用服务;
  • 2)客户端存根(client stub)接收到调用后,负责将方法、参数等组装成能够进行网络传输的消息体(将消息体对象序列化为二进制);
  • 3)客户端通过 sockets 将消息发送到服务端;
  • 4)服务端存根(server stub)收到消息后进行解码(将消息对象反序列化);
  • 5)服务端存根(server stub)根据解码结果调用本地的服务;
  • 6)本地服务执行并将结果返回给服务端存根(server stub);
  • 7)服务端存根(server stub)将返回结果打包成消息(将结果消息对象序列化);
  • 8)服务端(server)通过 sockets 将消息发送到客户端;
  • 9)客户端存根(client stub)接收到结果消息,并进行解码(将结果消息发序列化);
  • 10)客户端(client)得到最终结果。

RPC的作用,其实就是要把上述2、3、4、7、8、9 这些步骤都封装起来。是不是很神奇?

8、关于HTTP和RPC的一些争议

HTTP和RPC是两个很容易混淆的概念,对于刚开始接触RPC的人来说,通常都会困惑:有HTTP了为什么还要用RPC?

在知乎上看到了这个很有趣的问题:《既然有http请求,为什么还要用rpc?

其中一个大佬的回答感觉很有意思: 

换个角度来说:HTTP 与 RPC 的关系就好比普通话与方言的关系。要进行跨企业服务调用时,往往都是通过 HTTP API,也就是普通话,虽然效率不高,但是通用,没有太多沟通的学习成本。但是在企业内部还是 RPC 更加高效,同一个企业公用一套方言进行高效率的交流,要比通用的 HTTP 协议来交流更加节省资源。整个中国有非常多的方言,正如有很多的企业内部服务各有自己的一套交互协议一样。虽然国家一直在提倡使用普通话交流,但是这么多年过去了,你回一趟家乡探个亲什么的就会发现身边的人还是流行说方言。

如果再深入一点说,普通话本质上也是一种方言,只不过它是官方的方言,使用最为广泛的方言,相比而言其它方言都是小语种,小语种之中也会有几个使用比较广泛比较特色的方言占比也会比较大。这就好比开源 RPC 协议中 Protobuf 和 Thrift 一样,它们两应该是 RPC 协议中使用最为广泛的两个。

总之:RPC是一种编程模式和概念,并不是非常具体的一种技术,实际上和HTTP没有明确的冲突,HTTP可以作为RPC传输协议,原因还是RPCpid际上是一种内部服务框架而不是一个具体的通信协议,它可以涉及服务注册、服务治理、服务发现、熔断机制、负载均衡等。

9、典型的RPC框架

一个典型RPC框架中,包含了服务发现、负载、容错、网络传输、序列化等组件,其中“RPC 协议”就指明了程序如何进行网络传输和序列化。

 

▲ 一个典型的 RPC 架构原理图本图引用自《即时通讯新手入门:快速理解RPC技术——基本概念、原理和用途

 

▲ 著名RPC框架Dubbo的架构图本图引用自《即时通讯新手入门:快速理解RPC技术——基本概念、原理和用途

一个 RPC 最重要的功能模块,就是上图中的”RPC 协议”部分: 

其中的序列化和反序列化的意思是:

  • 1)序列化:将数据结构或对象转换成二进制串的过程;
  • 2)反序列化:将序列化中所生成的二进制串转换成数据结构或者对象的过程。

在网络消息传输中可以基于TCP、UDP、http来实现,各自都有各自的特点。

基于 TCP 实现的 RPC 调用,能够灵活对协议字段进行定制,减少网络开销提高性能,实现更大的吞吐量和并发数,但要关注底层细节,在进行数据解析时更加复杂一些(比如最受欢迎的Protobuf的使用)。

基于 HTTP 实现的 RPC 可以使用 JSON 和 XML 格式的请求或响应数据,解析工具很成熟,在其上进行二次开发会非常便捷和简单。但是 HTTP 是上层协议,所占用的字节数会比使用 TCP 协议传输所占用的字节数更高。

对于其他部分,本文不再展开。

10、市面上常见的RPC框架及其特点

常见 RPC 技术和框架有:

  • 1)应用级的服务框架:阿里的 Dubbo/Dubbox、Google gRPC、Spring Boot/Spring Cloud。
  • 2)远程通信协议:RMI、Socket、SOAP(HTTP XML)、REST(HTTP JSON)。
  • 3)通信框架:MINA 和 Netty。

目前流行的开源 RPC 框架还是比较多的,有阿里巴巴的 Dubbo、Facebook 的 Thrift、Google 的 gRPC、Twitter 的 Finagle 等。

下面重点介绍当前最流行的三种RPC框架主要特点:

  • 1)gRPC:是 Google 公布的开源软件,基于最新的 HTTP 2.0 协议,并支持常见的众多编程语言。RPC 框架是基于 HTTP 协议实现的,底层使用到了 Netty 框架的支持;
  • 2)Thrift:是 Facebook 的开源 RPC 框架,主要是一个跨语言的服务开发框架。用户只要在其之上进行二次开发就行,应用对于底层的 RPC 通讯等都是透明的。不过这个对于用户来说需要学习特定领域语言这个特性,还是有一定成本的;
  • 3)Dubbo:是阿里集团开源的一个极为出名的 RPC 框架,在很多互联网公司和企业应用中广泛使用。协议和序列化框架都可以插拔是极其鲜明的特色。

11、本文小结

小结一下,简单地理解RPC就是:

RPC 就是从一台机器(客户端)上通过参数传递的方式调用另一台机器(服务器)上的一个函数或方法(可以统称为服务)并得到返回的结果。

RPC 会隐藏底层的通讯细节(不需要直接处理Socket通讯或Http通讯)。

RPC 是一个请求响应模型。客户端发起请求,服务器返回响应(类似于Http的工作方式)。

RPC 在使用形式上像调用本地函数(或方法)一样去调用远程的函数(或方法)。

12、参考资料

[1] 什么是 RPC 框架

[2] 谁能用通俗的语言解释一下什么是 RPC 框架?

[3] 浅谈RPC那些事儿[1]

[4] 即时通讯新手入门:快速理解RPC技术——基本概念、原理和用途

[5] 即时通讯新手入门:一文读懂什么是Nginx?它能否实现IM的负载均衡?

附录:有关IM架构设计的文章

浅谈IM系统的架构设计

简述移动端IM开发的那些坑:架构设计、通信协议和客户端

一套海量在线用户的移动端IM架构设计实践分享(含详细图文)

一套原创分布式即时通讯(IM)系统理论架构方案

从零到卓越:京东客服即时通讯系统的技术架构演进历程

蘑菇街即时通讯/IM服务器开发之架构选择

腾讯QQ1.4亿在线用户的技术挑战和架构演进之路PPT

微信后台基于时间序的海量数据冷热分级架构设计实践

微信技术总监谈架构:微信之道——大道至简(演讲全文)

如何解读《微信技术总监谈架构:微信之道——大道至简》

快速裂变:见证微信强大后台架构从0到1的演进历程(一)

17年的实践:腾讯海量产品的技术方法论

移动端IM中大规模群消息的推送如何保证效率、实时性?

现代IM系统中聊天消息的同步和存储方案探讨

IM开发基础知识补课(二):如何设计大量图片文件的服务端存储架构?

IM开发基础知识补课(三):快速理解服务端数据库读写分离原理及实践建议

IM开发基础知识补课(四):正确理解HTTP短连接中的Cookie、Session和Token

WhatsApp技术实践分享:32人工程团队创造的技术神话

微信朋友圈千亿访问量背后的技术挑战和实践总结

王者荣耀2亿用户量的背后:产品定位、技术架构、网络方案等

IM系统的MQ消息中间件选型:Kafka还是RabbitMQ?

腾讯资深架构师干货总结:一文读懂大型分布式系统设计的方方面面

以微博类应用场景为例,总结海量社交系统的架构设计步骤

快速理解高性能HTTP服务端的负载均衡技术原理

子弹短信光鲜的背后:网易云信首席架构师分享亿级IM平台的技术实践

知乎技术分享:从单机到2000万QPS并发的Redis高性能缓存实践之路

IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列

微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

微信技术分享:微信的海量IM聊天消息序列号生成实践(容灾方案篇)

新手入门:零基础理解大型分布式架构的演进历史、技术原理、最佳实践

一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践

阿里技术分享:深度揭秘阿里数据库技术方案的10年变迁史

阿里技术分享:阿里自研金融级数据库OceanBase的艰辛成长之路

社交软件红包技术解密(一):全面解密QQ红包技术方案——架构、技术实现等

社交软件红包技术解密(二):解密微信摇一摇红包从0到1的技术演进

社交软件红包技术解密(三):微信摇一摇红包雨背后的技术细节

社交软件红包技术解密(四):微信红包系统是如何应对高并发的

社交软件红包技术解密(五):微信红包系统是如何实现高可用性的

社交软件红包技术解密(六):微信红包系统的存储层架构演进实践

社交软件红包技术解密(七):支付宝红包的海量高并发技术实践

社交软件红包技术解密(八):全面解密微博红包技术方案

社交软件红包技术解密(九):谈谈手Q红包的功能逻辑、容灾、运维、架构等

社交软件红包技术解密(十):手Q客户端针对2020年春节红包的技术实践

即时通讯新手入门:一文读懂什么是Nginx?它能否实现IM的负载均衡?

即时通讯新手入门:快速理解RPC技术——基本概念、原理和用途

多维度对比5款主流分布式MQ消息队列,妈妈再也不担心我的技术选型了

从游击队到正规军(一):马蜂窝旅游网的IM系统架构演进之路

从游击队到正规军(二):马蜂窝旅游网的IM客户端架构演进和实践总结

IM开发基础知识补课(六):数据库用NoSQL还是SQL?读这篇就够了!

瓜子IM智能客服系统的数据架构设计(整理自现场演讲,有配套PPT)

阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处

从游击队到正规军(三):基于Go的马蜂窝旅游网分布式IM系统技术实践

微信后台基于时间序的新一代海量数据存储架构的设计实践

IM开发基础知识补课(九):想开发IM集群?先搞懂什么是RPC!

>> 更多同类文章 ……

本文已同步发布于“即时通讯技术圈”公众号,欢迎关注:


(本文同步发布于:http://www.52im.net/thread-2996-1-1.html

posted @ 2020-05-09 11:54 Jack Jiang 阅读(292) | 评论 (0)编辑 收藏

     摘要: 本文为开源工程:“github.com/GuoZhaoran/fastIM”的配套文章,原作者:“绘你一世倾城”,现为:猎豹移动php开发工程师,感谢原作者的技术分享。0、引言阅读提示:本文适合有一定网络通信技术基础的IM新手阅读。如果你对网络编程,以及IM的一些理论知识知之甚少,请务必首先阅读:《新手入门一篇就够:从零开发移动端IM》,按需补充相关...  阅读全文

posted @ 2020-04-28 12:05 Jack Jiang 阅读(460) | 评论 (0)编辑 收藏

阿里巴巴技术团队于2020年04月22日发布《Java开发手册v1.6.0-泰山版》。

1、概述

2017年开春之际,阿里诚意献上重磅大礼:《阿里巴巴Java开发手册(规约)》,首次公开阿里官方Java代码规范标准。这套Java统一规范标准将有助于提高行业编码规范化水平,帮助行业人员提高开发质量和效率、大大降低代码维护成本。

《阿里巴巴Java开发手册(规约)》是阿里内部Java工程师所遵循的开发规范,涵盖编程规约、单元测试规约、异常日志规约、MySQL规约、工程规约、安全规约等,这是近万名阿里Java技术精英的经验总结,并经历了多次大规模一线实战检验及完善。这是阿里回馈给Java社区的一份礼物,希望能够帮助企业开发团队在Java开发上更高效、容错、有协作性,提高代码质量,降低项目维护成本。

另外,《作者谈《阿里巴巴Java开发手册(规约)》背后的故事》一文,可以看看作者怎么说。

下载方式:详见文末 “6、历史版及最新版下载地址” !

2、价值意义

《阿里巴巴Java开发手册(规约)》的愿景是码出高效,码出质量。它结合作者的开发经验和架构历程,提炼阿里巴巴集团技术团队的集体编程经验和软件设计智慧,浓缩成为立体的编程规范和最佳实践。众所周知,现代软件行业的高速发展对开发者的综合素质要求越来越高,因为不仅是编程相关的知识点,其他维度的知识点也会影响软件的最终交付质量,比如,数据库的表结构和索引设计缺陷可能带来软件的架构缺陷或性能风险;单元测试的失位导致集成测试困难;没有鉴权的漏洞代码易被黑客攻击等。所以,本手册以开发者为中心视角,划分为编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约七个维度,每个条目下有相应的扩展解释和说明,正例和反例,全面、立体、形象地帮助到开发者的成长和团队代码规约文化的形成。

从严格意义上讲,《阿里巴巴Java开发手册(规约)》超越了Java语言本身,明确作为一名合格开发者应该具备的基本素质,因此本手册适合计算机相关行业的管理者和研发人员、高等院校的计算机专业师生、求职者等阅读,希望成为大家如良师益友般的工作手册、工具字典。

3、最新动态

关于泰山版(v1.6.0):

此版发布于2020年04月22日,此版升级内容包括:

1)发布错误码统一解决方案,详细参考手册的“附表 3”。

2)新增 34 条新规约。如:日期时间的闰年、闰月问题,三目运算的自动拆箱,SQL查询的表别名限定,Collectors 类的 toMap()方法使用注意等。

3)修改描述 90 处。如:阻塞等待锁、建表的小数类型等。

4)完善若干处示例。如:ISNULL 的示例等

4、主要作者

杨冠宝: 

杨冠宝:花名孤尽,取自《笑傲江湖》中风清扬的“独孤九剑,破尽天下武功”之意,是《阿里巴巴Java开发手册》的主要作者。在阿里巴巴集团历任研发、架构师、技术主管等不同的角色,承担过双11、国际化、代码中心等大型项目,有着丰富的一线编程经验,目前是研发协同平台Aone代码中心负责人。乐于分享与总结,在阿里巴巴集团内部大型分享多达30余次,不懈地追求技术创新,勇于挑战技术难度,在大数据、高并发、研发效能领域均有较深的造诣。

2016年3月,孤尽带领约码项目组编写《阿里巴巴Java开发手册(规约)》,码出高效,码出质量,推动阿里系与业界一起进步,让代码变得更舒服,更清澈,更好维护。

5、部分内容截图预览

 
 
 

6、历史版及最新版下载地址

请从此下载:阿里技术结晶:阿里巴巴Java开发手册-v1.6.0-泰山版》[附件下载]

posted @ 2020-04-23 11:44 Jack Jiang 阅读(1033) | 评论 (0)编辑 收藏

本文原始内容由爱奇艺技术产品团队原创分享,本次有修订和改动。

1、引言

由于移动网络的复杂性特点,编写高质量、体验好的具备网络通信能力的移动端应用(尤其是即时通讯这类网络质量高度敏感的应用)有很大的挑战性。

我们平时看到的移动网络主要有如下三个典型特点:

1)移动状态网络信号不稳定,高时延、易抖动丢包、通道狭窄;

2)移动状态网络接入类型和接入点变化频繁;

3)移动状态用户使用高频化、碎片化、非WIFI流量敏感。

(▲ 上述文字,引用自《移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”》)

正是由于上述特点,移动端应用在进行网络数据通信时会面临各种复杂多变的问题。

无论后面的技术有多复杂,但对于普通用户使用APP来说,能顺畅的完成网络请求,是理所当然的事。换句话说,APP网络请求成功率,重要性直接体现在它能直接决定APP服务的可用性,直接影响到数据通信、视频播放、广告展现、支付便捷等服务质量。

本文将以爱奇艺的iOS端APP为例,分享对移动网络请求成功率优化方面的技术实践之路。

本文将同时发布于“即时通讯技术圈”公众号,欢迎关注:

(本文已同步发布于:http://www.52im.net/thread-2981-1-1.html

2、相关文章

现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障

移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”》(* 必读好文

移动端IM开发者必读(二):史上最全移动弱网络优化方法总结

全面了解移动端DNS域名劫持等杂症:技术原理、问题根源、解决方案等

美图App的移动端DNS优化实践:HTTPS请求耗时减小近半

百度APP移动端网络深度优化实践分享(一):DNS优化篇

百度APP移动端网络深度优化实践分享(二):网络连接优化篇

百度APP移动端网络深度优化实践分享(三):移动端弱网优化篇

3、导致移动端网络请求失败的因素

想要优化移动端网络请求成功率,先来了解移动端网络请求全链条可能导致请求失败的环节有哪些。

这些环节往往由以下两类因素导致:

 
 

第一类:不可改善因素:

1)iOS系统对APP的网络访问权限控制、飞行模式或者无网络连接。检测和识别这三种情况,通过适当方式提示用户;

2)路由器故障。

第二类:可以改善因素:

1)蜂窝/Wifi信号的强弱、连接拥堵的假连接状态;

2)DNS故障(比如DNS劫持等);

3)运营商局部节点故障;

4)自有运营负载均衡故障;

5)业务服务器故障:HTTP响应错误,对应APM的HTTP响应错误率;

6)业务逻辑错误:监控子类解析结果,对应APM的解析错误率监控。

对于不可改善因素:目前只能通过网络诊断识别出故障类型,引导用户手动去授权访问网络或者连接可用网络。

其中,如果是路由器故障,可以引导用户重启路由器或者切换4G。通过爱奇艺APP的数据监控,大致可以看到用户无网连接的时长占比有3.8%左右,这说明提供好的无网提示变得十分重要,而从用户使用蜂窝信号的弱信号(0格和1格信号)时长占比有9%左右时长,也可以看出移动端网络环境的复杂性。

 
 

针对可以改善的因素,解决方法可大致分为三类:

1)网络层错误,对应因素1到4。主要体现为超时报错;

2)HTTP响应错误,对应因素5。HTTP状态码为400及以上;

3)解析错误,对应因素6。由基线网络库定义的重载接口进行监控。

为了提高网络请求成功率,首先需要建立监控体系,从而使得基线网络库能够通过网络统计模块向APM投递各种维度的网络请求数据。有了APM的数据统计后,才能有效的发现导致端上网络失败的原因,进而解决问题。

除此之外,由于端上网络请求数据巨大,存储空间的限制使得APM只能采样2%的用户,因此针对重点业务的网络请求(比如首页)则进行了全量采集,从而对成功率的优化实现更客观全面的评估。

4、在基线网络库这一层针对不同业务提供不同的补偿思路

在优化之前,通过APM的归类分析可以得出:请求失败的主要报错是超时(-1001)的占比达到九成,与此同时SSL错误,DNS解析错误占比紧随其后。根据这一数据统计,重试成为最主要的请求成功率优化的措施。

经过不断探索和实践总结,基线网络库针对不同业务需求提供了四种不同的重试手段。

1)IP直连重试,通过配置直连IP数来控制重试次数:

Scheme不变,Host改为直接使用IP(消除域名解析风险)。由于此举需要各个业务线自己提供直连的IP,目前接入的业务主要是登录等强制要求HTTPS连接的业务。

2)超级管道重试,可以配置1~3次重试:

公司自研基于HTTP的网关代理服务(类似于远程charles代理)。Host改为代理IP(消除域名解析风险),Scheme改为HTTP(消除SSL风险,h2降级为HTTP1.1)。由于该措施需要付出流量成本,目前接入的业务都是关键核心业务,比如首页等。

3)HTTP重试,可以配置1~3次重试:

Scheme修改为HTTP(消除SSL风险,h2降级为HTTP1.1),其他不变。鉴于其为普惠性重试手段,目前接入非关键核心的一般业务。

4)原url重试,可以配置1~3次重试:

Scheme和host等都不变,通常意义上理解的重试,单纯的再请求一次。此举目前不是推荐重试手段,由业务方自主决定。

 
 

除了单个重试手段可以重试多次,基础网络库也支持多种重试手段的组合,四种重试手段的优先次序为:IP直连重试 > 超级管道重试 > HTTP重试 > 原URL重试。扣除无网情况,首页推荐页CARD接口成功率通过组合重试在2020第一季度末达到了99.76%。

 

5、其它影响移动端网络请求成功率的因素

除了重试,还有以下因素对网络请求成功率有直接影响。

1)HTTP/2 vs HTTP/1.1:推荐的请求策略是首次请求走H2,当失败重试时走HTTP/1.1:

HTTP/2对HTTP/1.1最大改进是共用一个TCP连接(详见《从HTTP/0.9到HTTP/2:一文读懂HTTP协议的历史演变和设计思路》),其在网络顺畅时,为HTTP/2带来了速度上的优势。但当网络变坏时,TCP包的绝对顺序编号会导致一个包的丢失而堵住后面所有的请求。这样单TCP连接反而扩大了拥堵,增大了请求失败的可能性。

NSURLSession是HTTP协议自适应的,不能控制请求使用HTTP/2或者HTTP/1.1。不过由于业界事实上的标准要求HTTP/2必须是HTTPs的,这样通过将URL Scheme改为HTTP可以间接降级到HTTP/1.1。

2)适当的超时设置是一个重要影响因素:

NSURLSession的超时实际上是TCP的包间超时,并不是整体请求耗时的超时。

 

推荐的超时设置策略是:首次请求的超时可以小一点,而重试的超时应该大一些。

3)接口请求过于密集并发可能降低请求成功率:

比如播放记录的upload接口在加上多次重试后,成功率仍然只有98.2%。APM监控此接口在IPv4环境失败率只有0.47%,而IPv6失败率高达7.07%。通过端上优化请求策略,降低接口的并发密度后,IPv6环境和IPv4环境同时提高到99.85%的成功率。

4)接口数据体积越小,请求成功率越高:

HTTP/2和HTTP/1.1都是基于TCP连接的,接口数据体积越小,需要传输的TCP包越少,传输失败的概率也就降低了。目前爱奇艺APP正在从gzip转向压缩率更高的br(指的是Brotli压缩算法,详见:《启用 Brotli 压缩算法,对比 Gzip 压缩 CDN 流量再减少 20%)。

6、提高鲁棒性并防止故障的优化措施

在经过各种优化措施提高网络成功率后,我们还通过下面几个措施成功的防止线上故障造成的成功率瞬时下降,提高了网络请求的鲁棒性。

1)超级管道本身的鲁棒性:

下面案例显示使用了超级管道重试的接口错误率只有3.95%,而没有使用超级管道重试的接口错误率高达28.96%。这个案例的时间点还没有使用异地容灾IP,在叠加异地容灾IP之后,错误率曲线几乎可以抹平。

 
 

2)HTTP重试和原URL重试在v4v6双栈环境下,优先IPv4:

由于IPv6仍在建设中,有些接口在IPv6的表现弱于IPv4,那么可以指定重试走IPv4。

3)TLS1.3– 1RTT的节省:

TLS1.3将SSL握手2个RTT降为1个RTT,降低了SSL握手失败的概率。iOS12.2开始,NSURLSession支持TLS1.3。只需要服务器升级支持TLS1.3即可,端上无须改动。

4)IP复合连接竞速:

使用TCP连接测速,目的是剔除坏IP,选择最优IP,从而提高请求的成功概率。

经上述措施的持续优化,爱奇艺APP在2020Q1末,扣除无网情况后,业务成功率达到了99.7%,而网络层成功率达到了99.77%。

▲ 业务成功率 = 网络层成功率+HTTP响应成功率+解析成功率

在完成优化后,爱奇艺APP基础网络库的构成如下:

 

如上图所示,基础网络库各模板的功能作用如下:

1)统一网络库:提供一个网络接口层,所有业务接口都对接使用网络接口层;

2)统一网络库:提供一个网络封装层,对接了iOS系统网络层NSURLSession、ASIHTTPRequest(基于CFNetwork)、和公司自研的长连接网关;

3)网络统计模块:将从业务调用开始到回调给业务方的各个环节的耗时及状态值,变成统计数据,上传到APM汇合;

4)网络诊断模块:对关键业务进行诊断,包括dns解析,ping,tcpconnect,trace等工具对具体IP进行分析,分析结果上传到APM汇合;

5)弱网检测模块:通过借鉴Facebook的弱网检测是基于网速拟合的网络等级分级,分为网络情况非常差(2G或者无网)、网络情况较差(3G)、网络情况一般、网络情况较好、网络情况非常好五个等级;

6)HTTPDNS模块:有效的解决了运营商劫持问题;

7)超级管道重试:基于HTTP的网关代理,具有异地容灾代理能力;

8)ipv4/ipv6模块:识别端上是ipv4 only环境、v4/v6双栈还是ipv6 only环境;

9)复合连接模块:可以在server IP缓存池选出最佳IP,手段包括目标IP连接竞速,IP历史请求统计数据排序;

10)网络日志模块:记录了最近发生的失败网络请求详细数据和网络诊断数据。随反馈一并提交,可以便捷的排查线上网络问题。

7、未来的目标与可能的优化措施

为了持续优化网络成功率,下一步目标是扣除无网情况,重点业务成功率达到99.9%。后续考虑的优化措施如下。

1)Multipath:

当Wifi假连接的时可以走蜂窝流量,iOS 7开始支持Multipath特性(详见:《揭开 iOS 7 之 Multipath TCP 的面纱》)。

2)QUIC:

QUIC是基于UDP的,由于运营商对UDP有针对性的丢包,实测QUIC并没有体现出优势。然而,考虑到libcurl在2019已提供完整QUIC能力,NSURLSession不久也会支持QUIC。随着运营商对UDP包的干扰减少,QUIC的优势将得到体现。

如果对QUIC协议感兴趣,可以读一读下面这些文章:

网络编程懒人入门(十):一泡尿的时间,快速读懂QUIC协议

技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解

让互联网更快:新一代QUIC协议在腾讯的技术实践分享

七牛云技术分享:使用QUIC协议实现实时视频直播0卡顿!

3)智能调度并发:

更精准更灵敏的弱网识别,弱网下对关键核心业务进行倾斜。

4)HTTPDNS的push能力:

HTTPDNS打通APM的质量监控体系后,通过push及时下线故障IP。

关于移动端DNS问题上的优化,业内已经有了很多总结,有兴趣可以深入研究:

全面了解移动端DNS域名劫持等杂症:技术原理、问题根源、解决方案等

美图App的移动端DNS优化实践:HTTPS请求耗时减小近半

百度APP移动端网络深度优化实践分享(一):DNS优化篇

移动端网络优化之HTTP请求的DNS优化

附录:更多网络通信方面的技术资料

TCP/IP详解 - 第11章·UDP:用户数据报协议

TCP/IP详解 - 第17章·TCP:传输控制协议

TCP/IP详解 - 第18章·TCP连接的建立与终止

TCP/IP详解 - 第21章·TCP的超时与重传

技术往事:改变世界的TCP/IP协议(珍贵多图、手机慎点)

通俗易懂-深入理解TCP协议(上):理论基础

通俗易懂-深入理解TCP协议(下):RTT、滑动窗口、拥塞处理

理论经典:TCP协议的3次握手与4次挥手过程详解

理论联系实际:Wireshark抓包分析TCP 3次握手、4次挥手过程

计算机网络通讯协议关系图(中文珍藏版)

UDP中一个包的大小最大能多大?

P2P技术详解(一):NAT详解——详细原理、P2P简介

P2P技术详解(二):P2P中的NAT穿越(打洞)方案详解(基本原理篇)

P2P技术详解(三):P2P中的NAT穿越(打洞)方案详解(进阶分析篇)

P2P技术详解(四):P2P技术之STUN、TURN、ICE详解

通俗易懂:快速理解P2P技术中的NAT穿透原理

高性能网络编程(一):单台服务器并发TCP连接数到底可以有多少

高性能网络编程(二):上一个10年,著名的C10K并发连接问题

高性能网络编程(三):下一个10年,是时候考虑C10M并发问题了

高性能网络编程(四):从C10K到C10M高性能网络应用的理论探索

高性能网络编程(五):一文读懂高性能网络编程中的I/O模型

高性能网络编程(六):一文读懂高性能网络编程中的线程模型

Java的BIO和NIO很难懂?用代码实践给你看,再不懂我转行!

不为人知的网络编程(一):浅析TCP协议中的疑难杂症(上篇)

不为人知的网络编程(二):浅析TCP协议中的疑难杂症(下篇)

不为人知的网络编程(三):关闭TCP连接时为什么会TIME_WAIT、CLOSE_WAIT

不为人知的网络编程(四):深入研究分析TCP的异常关闭

不为人知的网络编程(五):UDP的连接性和负载均衡

不为人知的网络编程(六):深入地理解UDP协议并用好它

不为人知的网络编程(七):如何让不可靠的UDP变的可靠?

不为人知的网络编程(八):从数据传输层深度解密HTTP

不为人知的网络编程(九):理论联系实际,全方位深入理解DNS

网络编程懒人入门(一):快速理解网络通信协议(上篇)

网络编程懒人入门(二):快速理解网络通信协议(下篇)

网络编程懒人入门(三):快速理解TCP协议一篇就够

网络编程懒人入门(四):快速理解TCP和UDP的差异

网络编程懒人入门(五):快速理解为什么说UDP有时比TCP更有优势

网络编程懒人入门(六):史上最通俗的集线器、交换机、路由器功能原理入门

网络编程懒人入门(七):深入浅出,全面理解HTTP协议

网络编程懒人入门(八):手把手教你写基于TCP的Socket长连接

网络编程懒人入门(九):通俗讲解,有了IP地址,为何还要用MAC地址?

网络编程懒人入门(十):一泡尿的时间,快速读懂QUIC协议

网络编程懒人入门(十一):一文读懂什么是IPv6

技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解

让互联网更快:新一代QUIC协议在腾讯的技术实践分享

现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障

聊聊iOS中网络编程长连接的那些事

移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”

移动端IM开发者必读(二):史上最全移动弱网络优化方法总结

IPv6技术详解:基本概念、应用现状、技术实践(上篇)

IPv6技术详解:基本概念、应用现状、技术实践(下篇)

从HTTP/0.9到HTTP/2:一文读懂HTTP协议的历史演变和设计思路

脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手

脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

脑残式网络编程入门(三):HTTP协议必知必会的一些知识

脑残式网络编程入门(四):快速理解HTTP/2的服务器推送(Server Push)

脑残式网络编程入门(五):每天都在用的Ping命令,它到底是什么?

脑残式网络编程入门(六):什么是公网IP和内网IP?NAT转换又是什么鬼?

脑残式网络编程入门(七):面视必备,史上最通俗计算机网络分层详解

脑残式网络编程入门(八):你真的了解127.0.0.1和0.0.0.0的区别?

以网游服务端的网络接入层设计为例,理解实时通信的技术挑战

迈向高阶:优秀Android程序员必知必会的网络基础

全面了解移动端DNS域名劫持等杂症:技术原理、问题根源、解决方案等

美图App的移动端DNS优化实践:HTTPS请求耗时减小近半

Android程序员必知必会的网络通信传输层协议——UDP和TCP

IM开发者的零基础通信技术入门(一):通信交换技术的百年发展史(上)

IM开发者的零基础通信技术入门(二):通信交换技术的百年发展史(下)

IM开发者的零基础通信技术入门(三):国人通信方式的百年变迁

IM开发者的零基础通信技术入门(四):手机的演进,史上最全移动终端发展史

IM开发者的零基础通信技术入门(五):1G到5G,30年移动通信技术演进史

IM开发者的零基础通信技术入门(六):移动终端的接头人——“基站”技术

IM开发者的零基础通信技术入门(七):移动终端的千里马——“电磁波”

IM开发者的零基础通信技术入门(八):零基础,史上最强“天线”原理扫盲

IM开发者的零基础通信技术入门(九):无线通信网络的中枢——“核心网”

IM开发者的零基础通信技术入门(十):零基础,史上最强5G技术扫盲

IM开发者的零基础通信技术入门(十一):为什么WiFi信号差?一文即懂!

IM开发者的零基础通信技术入门(十二):上网卡顿?网络掉线?一文即懂!

IM开发者的零基础通信技术入门(十三):为什么手机信号差?一文即懂!

IM开发者的零基础通信技术入门(十四):高铁上无线上网有多难?一文即懂!

IM开发者的零基础通信技术入门(十五):理解定位技术,一篇就够

百度APP移动端网络深度优化实践分享(一):DNS优化篇

百度APP移动端网络深度优化实践分享(二):网络连接优化篇

百度APP移动端网络深度优化实践分享(三):移动端弱网优化篇

技术大牛陈硕的分享:由浅入深,网络编程学习经验干货总结

可能会搞砸你的面试:你知道一个TCP连接上能发起多少个HTTP请求吗?

知乎技术分享:知乎千万级并发的高性能长连接网关技术实践

5G时代已经到来,TCP/IP老矣,尚能饭否?

爱奇艺移动网络优化实践分享:网络请求成功率优化篇(iOS端)

>> 更多同类文章 ……

欢迎关注我的“即时通讯技术圈”公众号:

(本文已同步发布于:http://www.52im.net/thread-2981-1-1.html

posted @ 2020-04-21 14:20 Jack Jiang 阅读(309) | 评论 (0)编辑 收藏

本文同时发布于“即时通讯技术圈”公众号,链接是:https://mp.weixin.qq.com/s/cS5xB2DrjF52rmz6EGVJ6A

本文参考了公众号鲜枣课堂的“IPv6,到底是什么?”一文的部分内容,感谢原作者。

1、引言

现在IPv6的技术应用已经越来越普及了,很多应用都开始支持IPv6。

 

▲ 去年开始,支付宝的官网上就已出现“支持IPv6”标识

对于即时通讯技术(尤其是IM应用)的开发者来说,新产品上架苹果的App Store因IPv6问题被拒的情况,很常见。每次也都能根据网上的资料一一解决,并顺利通过审核。

然而几次下来,到底什么是IPv6,还是有点云里雾里。

那么,IP协议在TCP/IP体系中到底有多重要?看看下图便知(原因清晰版:从此处进入下载)。

 

▲ 红圈处就是IP协议,它几乎是整个TCP/IP协议簇的支撑(图引用自《计算机网络通讯协议关系图》)

总之,IP协议在TCP/IP体系中,是非常重要的一环(可以认为,没它,也就没有了互联网),作为IPv4的下一代协议,了解IPv6非常有必要。而作为即时通讯开发者来说,了解IPv6就显的尤为迫切,说不定某天你的IM就会因为IPv6问题而导致无法通信的局面出现。

本文将用浅显易懂的文字,带你了解到底什么是IPv6。

(本文同步发布于:http://www.52im.net/thread-2979-1-1.html

2、系列文章

本文是系列文章中的第11篇,本系列文章的大纲如下:

网络编程懒人入门(一):快速理解网络通信协议(上篇)

网络编程懒人入门(二):快速理解网络通信协议(下篇)

网络编程懒人入门(三):快速理解TCP协议一篇就够

网络编程懒人入门(四):快速理解TCP和UDP的差异

网络编程懒人入门(五):快速理解为什么说UDP有时比TCP更有优势

网络编程懒人入门(六):史上最通俗的集线器、交换机、路由器功能原理入门

网络编程懒人入门(七):深入浅出,全面理解HTTP协议

网络编程懒人入门(八):手把手教你写基于TCP的Socket长连接

网络编程懒人入门(九):通俗讲解,有了IP地址,为何还要用MAC地址?

网络编程懒人入门(十):一泡尿的时间,快速读懂QUIC协议

网络编程懒人入门(十一):一文读懂什么是IPv6》(本文)

3、复习一下什么是IPv4?

IPv4是Internet Protocol version 4的缩写,中文翻译为互联网通信协议第四版,通常简称为网际协议版本4。

IPv4使用32位(4字节)地址,因此地址空间中只有 4,294,967,296(即2^32) 个地址。

IPv4地址可被写作任何表示一个32位整数值的形式,但为了方便人类阅读和分析,它通常被写作点分十进制的形式,即四个字节被分开用十进制写出,中间用点分隔。

通常IPv4地址的地址格式为 nnn.nnn.nnn.nnn,就像下面这样:

172.16.254.1

下图看起来更清晰一些:

4、IPv6又是什么?

IPv6是Internet Protocol version 6的缩写,中文翻译为互联网通信协议(TCP/IP协议)第6版,通常简称为网际协议版6。IPv6具有比IPv4大得多的编码地址空间,用它来取代IPv4主要是为了解决IPv4地址枯竭问题,同时它也在其他方面对于IPv4有许多改进。

其实,IPv6并不是新技术,从IPv6最早的工作组成立1992年到现在,已过去27年。在互联网技术的发展历程中,IPv6年龄甚至有些太大了。

IPv6的“6”表示的是TCP/IP协议的第六个版本,IPv4的“4”表示的是TCP/IP协议的第四个版本。其实除了这两个版本,当然还有其它版本,TCP/IP协议其实从IPv1开始,到现在IPv10都已经出现了,这些不同版本之间并没有关联,也不是简单IP地址长度的长短。

IPv6地址由八组、每组四位16进制数字组成,每组之间由":"来分隔。

看个简单的例子:

2610:00f8:0c34:67f9:0200:83ff:fe94:4c36,每个“:”前后都是4位16进制的数字,共分隔成8组。

如下图所示: 

 

小知识:如何查看手机或者电脑的网络是否支持IPv6呢?

可以在你手机或者电脑上的浏览器中打开:Ipv6-test.com,就像下图这样: 

5、为什么要使用IPv6?

最主要的原因,就是地址数量不够用了。

IPv4迄今为止已经使用了30多年。最早期的时候,互联网只是设计给美国军方用的,根本没有考虑到它会变得如此庞大,成为全球网络。

尤其是进入21世纪后,随着计算机和智能手机的迅速普及,互联网开始爆发性发展,越来越多的上网设备出现,越来越多的人开始连接互联网。这就意味着,需要越来越多的IP地址。

IPv4的地址总数是2的32次方,也就是约42.9亿个。而全球的网民总数早已超过这个数目。

 

所以说,IPv4地址池接近枯竭,根本无法满足互联网发展的需要。人们迫切需要更高版本的IP协议,更大数量的IP地址池。(有点像固定电话号码升位。)

6、IPv6会带给我们什么?

首先,最重要的一点,就是前面所说的地址池扩容。IPv4的地址池是约42.9亿,IPv6能达到多少呢?

数量如下:

340282366920938463463374607431768211456个…

不用数了,太多了… 简单说,是2的128次方。

这个数量,即使是给地球上每一颗沙子都分配一个IP,也是妥妥够用的。

 

▲ 这图你看懂了吗?嗯,我也没看懂,反正就是很多的样子

这个数量值是怎么得来的呢?还是它的地址位长决定的。

如果以二进制来写,IPv6的地址是128位。不过,这样写显然不太方便(一行都写不下)。所以,通常用十六进制来写,也就缩短成32位(32位会分为8组,每组4位)。 

下面就是一个标准、合法的IPv6地址示例:

2001:0db8:85a3:08d3:1319:8a2e:0370:7344

注意:IPv6的地址是可以简写的,每项数字前导的0可以省略。

例如,下面这个地址:

2001:0DB8:02de:0000:0000:0000:0000:0e13

粉红的“0”就可以省略,变成:

2001: DB8:2de:0:0:0:0:e13

如果有一组或连续几组都是0,那么可以简写成“::”,也就是:

2001: DB8:2de::e13

注意:一个IPv6地址,只能有一个“::”。

为什么?很简单,你看下面这四个地址,如果所有0全都缩写,会变成什么样?

2001:0000:0000:0000:0000:25de:0000:cade

2001: 0000: 0000:0000:25de:0000:0000:cade

2001: 0000: 0000:25de:0000:0000:0000:cade

2001: 0000: 25de:0000:0000:0000:0000:cade

是的,都是2001::25de::cade,冲突了。所以,这个地址是非法的,不允许存在的。

关于IPv6还有很多技术细节,因篇幅原因,不再赘述。

除了地址数量之外,IPv6还有很多优点,例如:

1)IPv6使用更小的路由表。使得路由器转发数据包的速度更快;

2)IPv6增加了增强的组播支持以及对流的控制,对多媒体应用很有利,对服务质量(QoS)控制也很有利;

3)IPv6加入了对自动配置的支持。这是对DHCP协议的改进和扩展,使得网络(尤其是局域网)的管理更加方便和快捷;

4)IPv6具有更高的安全性。用户可以对网络层的数据进行加密并对IP报文进行校验,极大地增强了网络的安全性;

5)IPv6具有更好的扩容能力。如果新的技术或应用需要时,IPV6允许协议进行扩充;

6)IPv6具有更好的头部格式。IPV6使用新的头部格式,就简化和加速了路由选择过程,提高了效率;

……

7、IPv6的优点这么多,为什么之前普及却这么慢?

IPv6优点这么多,为什么它问世已经20年了,还是没有完全替代IPv4呢?这里面的水就很深了。。。说白了,主要还是和利益有关。

7.1 NAT这类技术,让IPv4得以续命

如果按照本世纪初专家们的预测,我们IPv4的地址早已枯竭几万次了。但是,一直挺到现在,大家仍然还在用IPv4,对老百姓来说,并没有因为地址不够而无法上网。

这是为什么呢? 就是因为除了IPv6之外,我们还有一些技术,可以变相地缓解地址不足。

例如NAT(Network Address Translation,网络地址转换)。

NAT是什么意思?当我们在家里或公司上网时,你的电脑肯定有一个类似192.168.0.1的地址,这种地址属于私网地址,不属于公共的互联网地址。

▲ 一个典型的NAT应用场景(图自《IPv6,到底是什么?》)

每一个小的局域网,都会使用一个网段的私网地址,在与外界连接时,再变换成公网地址。这样一来,几十个或几百个电脑,都只需要一个公网地址。

甚至还可以私网套私网,NAT套NAT,一层一层套。这样一来,大大节约了公网IP地址数量。正因为如此,才让我们“续命”到了今天,不至于无法上网。

但是,NAT这种方式也有很多缺点,虽然私网地址访问互联网地址方便,但互联网地址访问私网地址就困难了。很多服务,都会受到限制,你只能通过复杂的设置才能解决,也会影响网络的处理效率。

▲ NAT内网的计算机是不能被外网直接访问的(图自《IPv6,到底是什么?》)

7.2 升级IPv6涉及运营商的利益

物以稀为贵,地址越稀缺,就越值钱。掌握地址的人,就越开心。谁开心?运营商和ISP(互联网服务提供商)。

他们就像是经销商,从上游(互联网域名与号码分配机构,即ICANN)申请到IP地址,再卖给下游用户。稀缺没关系,反正,他一定能赚取更多的差价。

如果大家去找运营商或ISP买带宽,或者租赁云服务,带公共地址的,一定比不带公共地址的贵很多很多。

除了地址可以赚钱之外,如果升级支持IPv6,对运营商和ISP来说,也意味着很大的资金投入。现在新设备基本都是支持的,但毕竟还是有一些老设备,如果在使用寿命到期之前就换,就是亏钱。

所以,运营商和ISP都没有动力去启用IPv6。 

至于设备商或手机电脑厂商,出于提前考虑,早已普遍支持了IPv6,意见并不是很大,也决定不了什么。必竟,提供基础设施服务的运营商们更强势。

8、IPv6未来会怎样

随着5G时代的到来,有了IPv6的加持,万物互联或许会成为现实。对于我等实时通信类软件的开发人员来说,某些场景下,或许再也不需要为“P2P打洞”这种事情烦恼了。 

▲ 5G+IPv6,万物互联不是梦

未来已来,你准备好了吗?

9、参考资料

[1] IPv6入门教程

[2] IPv6,到底是什么?

[3] 关于IPv6的发展史!IPv6的秘密史!

[4] 科普:一文读懂IPv6是什么?

[5] 漫话:全球IPv4地址正式耗尽?到底什么是IPv4和IPv6?

附录:更多网络编程基础知识文章

TCP/IP详解 - 第11章·UDP:用户数据报协议

TCP/IP详解 - 第17章·TCP:传输控制协议

TCP/IP详解 - 第18章·TCP连接的建立与终止

TCP/IP详解 - 第21章·TCP的超时与重传

技术往事:改变世界的TCP/IP协议(珍贵多图、手机慎点)

通俗易懂-深入理解TCP协议(上):理论基础

通俗易懂-深入理解TCP协议(下):RTT、滑动窗口、拥塞处理

理论经典:TCP协议的3次握手与4次挥手过程详解

理论联系实际:Wireshark抓包分析TCP 3次握手、4次挥手过程

计算机网络通讯协议关系图(中文珍藏版)

UDP中一个包的大小最大能多大?

P2P技术详解(一):NAT详解——详细原理、P2P简介

P2P技术详解(二):P2P中的NAT穿越(打洞)方案详解(基本原理篇)

P2P技术详解(三):P2P中的NAT穿越(打洞)方案详解(进阶分析篇)

P2P技术详解(四):P2P技术之STUN、TURN、ICE详解

通俗易懂:快速理解P2P技术中的NAT穿透原理

高性能网络编程(一):单台服务器并发TCP连接数到底可以有多少

高性能网络编程(二):上一个10年,著名的C10K并发连接问题

高性能网络编程(三):下一个10年,是时候考虑C10M并发问题了

高性能网络编程(四):从C10K到C10M高性能网络应用的理论探索

高性能网络编程(五):一文读懂高性能网络编程中的I/O模型

高性能网络编程(六):一文读懂高性能网络编程中的线程模型

Java的BIO和NIO很难懂?用代码实践给你看,再不懂我转行!

不为人知的网络编程(一):浅析TCP协议中的疑难杂症(上篇)

不为人知的网络编程(二):浅析TCP协议中的疑难杂症(下篇)

不为人知的网络编程(三):关闭TCP连接时为什么会TIME_WAIT、CLOSE_WAIT

不为人知的网络编程(四):深入研究分析TCP的异常关闭

不为人知的网络编程(五):UDP的连接性和负载均衡

不为人知的网络编程(六):深入地理解UDP协议并用好它

不为人知的网络编程(七):如何让不可靠的UDP变的可靠?

不为人知的网络编程(八):从数据传输层深度解密HTTP

不为人知的网络编程(九):理论联系实际,全方位深入理解DNS

技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解

让互联网更快:新一代QUIC协议在腾讯的技术实践分享

现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障

聊聊iOS中网络编程长连接的那些事

移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”

移动端IM开发者必读(二):史上最全移动弱网络优化方法总结

IPv6技术详解:基本概念、应用现状、技术实践(上篇)

IPv6技术详解:基本概念、应用现状、技术实践(下篇)

从HTTP/0.9到HTTP/2:一文读懂HTTP协议的历史演变和设计思路

脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手

脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

脑残式网络编程入门(三):HTTP协议必知必会的一些知识

脑残式网络编程入门(四):快速理解HTTP/2的服务器推送(Server Push)

脑残式网络编程入门(五):每天都在用的Ping命令,它到底是什么?

脑残式网络编程入门(六):什么是公网IP和内网IP?NAT转换又是什么鬼?

脑残式网络编程入门(七):面视必备,史上最通俗计算机网络分层详解

脑残式网络编程入门(八):你真的了解127.0.0.1和0.0.0.0的区别?

以网游服务端的网络接入层设计为例,理解实时通信的技术挑战

迈向高阶:优秀Android程序员必知必会的网络基础

全面了解移动端DNS域名劫持等杂症:技术原理、问题根源、解决方案等

美图App的移动端DNS优化实践:HTTPS请求耗时减小近半

Android程序员必知必会的网络通信传输层协议——UDP和TCP

IM开发者的零基础通信技术入门(一):通信交换技术的百年发展史(上)

IM开发者的零基础通信技术入门(二):通信交换技术的百年发展史(下)

IM开发者的零基础通信技术入门(三):国人通信方式的百年变迁

IM开发者的零基础通信技术入门(四):手机的演进,史上最全移动终端发展史

IM开发者的零基础通信技术入门(五):1G到5G,30年移动通信技术演进史

IM开发者的零基础通信技术入门(六):移动终端的接头人——“基站”技术

IM开发者的零基础通信技术入门(七):移动终端的千里马——“电磁波”

IM开发者的零基础通信技术入门(八):零基础,史上最强“天线”原理扫盲

IM开发者的零基础通信技术入门(九):无线通信网络的中枢——“核心网”

IM开发者的零基础通信技术入门(十):零基础,史上最强5G技术扫盲

IM开发者的零基础通信技术入门(十一):为什么WiFi信号差?一文即懂!

IM开发者的零基础通信技术入门(十二):上网卡顿?网络掉线?一文即懂!

IM开发者的零基础通信技术入门(十三):为什么手机信号差?一文即懂!

IM开发者的零基础通信技术入门(十四):高铁上无线上网有多难?一文即懂!

IM开发者的零基础通信技术入门(十五):理解定位技术,一篇就够

百度APP移动端网络深度优化实践分享(一):DNS优化篇

百度APP移动端网络深度优化实践分享(二):网络连接优化篇

百度APP移动端网络深度优化实践分享(三):移动端弱网优化篇

技术大牛陈硕的分享:由浅入深,网络编程学习经验干货总结

可能会搞砸你的面试:你知道一个TCP连接上能发起多少个HTTP请求吗?

知乎技术分享:知乎千万级并发的高性能长连接网关技术实践

5G时代已经到来,TCP/IP老矣,尚能饭否?

>> 更多同类文章 ……

欢迎关注我的“即时通讯技术圈”公众号: 

(本文同步发布于:http://www.52im.net/thread-2979-1-1.html

posted @ 2020-04-17 11:21 Jack Jiang 阅读(389) | 评论 (0)编辑 收藏

本文已同时发布于我的“即时通讯技术圈”公众号。

1、引言

哈罗,大家好,我是Jack Jiang。。。(一股浓浓的自媒体视频旁白味道)。

对于经常看我文章的即时通讯开发者来说,今天要讨论的这个话题,貌似有点不着边际。

是的,自从我整理完《IM开发者的零基础通信技术入门》系列文章之后,对于网络编程的理解,开始有点飘了。

言归正传。现在,5G技术离我们的生活越来越近了,号称网络延迟1ms、下行速度10Gb/s的5G,在这样逆天的网络性能指标下,老骥伏枥的TCP/IP是否仍能Hold的住?带着这个思考,便有了本文的内容。

 

▲ 5G网速有多快?看图感受一下(图自《零基础,史上最强5G技术扫盲》)

(本文已同步发布于:http://www.52im.net/thread-2976-1-1.html

2、学好TCP/IP够用吗?

对于即时通讯技术的开发者,从技术栈来说,一条最普通的聊天消息的送达,肯定要涉及到网络编程技术,而网络编程最核心的也就是TCP/IP协议(准确的说是TCP/IP协议簇,见《TCP/IP详解》),毫无疑问深入的学习TCP/IP协议肯定是非常有必要了。

基本上,对于普通的IM或消息推送系统开发来说,对TCP/IP相关的计算机网络基础比较熟悉的话,完全够用了。

 

▲ 这本书很多人都读过

3、移动网络问题,只能赖我代码烂?

亲手写过即时通讯的网络通信层的同学都很清楚,在移动网络中(我说的移动网络具体指的是运营商的2g/3g/4g/5g这些),因为无线通信的介质和技术实现特殊性,出现了很多传统有线互联网不曾有过的网络通信问题。

就拿IM在移动弱网中出现的各种问题来说,多数开发者都不自信的认为这应该是自已的网络层代码写的不够优秀,是的,很多时候也确实是这样。

我收集整理的下面这几篇资料,就讨论的是这些,有兴趣可以读一下:

现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障

百度APP移动端网络深度优化实践分享(三):移动端弱网优化篇

微信移动端应对弱网络情况的探索和实践PPT [附件下载]

YY直播在移动弱网环境下的深度优化实践分享(视频+PPT)[附件下载]

其实,很少有人会去思考,在TCP/IP协议被发明出来的50年后,对于现代的移动网络来说,是否仍然能工作的好?以弱网问题为例,难道我写的IM总是丢消息、掉线就仅仅是“我”的代码太烂? 

没错,这不仅仅是应用层的代码编写问题,它或许涉及到TCP/IP的设计局限,甚至移动网络的底层设计也并不是最完美的。

下面这两篇文章,对于弱网问题思考,已经深入到运营商的通信技术这一层,强烈建议读一读:

移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”

移动端IM开发者必读(二):史上最全移动弱网络优化方法总结

如果你的认知,已经开始对底层的网络通信技术有所困惑,下面这几篇就是为你准备的:

IM开发者的零基础通信技术入门(六):移动终端的接头人——“基站”技术

IM开发者的零基础通信技术入门(七):移动终端的千里马——“电磁波”

IM开发者的零基础通信技术入门(八):零基础,史上最强“天线”原理扫盲

IM开发者的零基础通信技术入门(九):无线通信网络的中枢——“核心网”

IM开发者的零基础通信技术入门(十):零基础,史上最强5G技术扫盲

IM开发者的零基础通信技术入门(十一):为什么WiFi信号差?一文即懂!

IM开发者的零基础通信技术入门(十二):上网卡顿?网络掉线?一文即懂!

IM开发者的零基础通信技术入门(十三):为什么手机信号差?一文即懂!

IM开发者的零基础通信技术入门(十四):高铁上无线上网有多难?一文即懂!

4、简单复习一下TCP/IP

从字面意义上讲,有人可能会认为 TCP/IP 是指 TCP 和 IP 两种协议。实际生活当中有时也确实就是指这两种协议。

然而在很多情况下,它只是利用 IP 进行通信时所必须用到的协议簇的统称。

具体来说,IP 或 ICMP、TCP 或 UDP、TELNET 或 FTP、以及 HTTP 等都属于 TCP/IP 协议。他们与 TCP 或 IP 的关系紧密,是互联网必不可少的组成部分。TCP/IP 一词泛指这些协议,因此,有时也称 TCP/IP 为网际协议簇。

互联网进行通信时,需要相应的网络协议,TCP/IP 原本就是为使用互联网而开发制定的协议簇。因此,互联网的协议就是 TCP/IP,TCP/IP 就是互联网的协议。 

▲ 上图反映了TCP/IP协议族的关系(图片引用自《计算机网络通讯协议关系图》)

5、TCP/IP或许太老了

对于现代移动网络来说,TCP/IP或许太老了。我们简单了解一下TCP/IP协议的产生过程。

1973年:卡恩与瑟夫开发出了TCP/IP协议中最核心的两个协议:TCP协议和IP协议。

1974年:卡恩与瑟夫正式发表了TCP/IP协议并对其进行了详细的说明。同时,为了验证TCP/IP协议的可用性,使一个数据包由一端发出,在经过近10万km的旅程后到达服务端。在这次传输中,数据包没有丢失一个字节,这充分说明了TCP/IP协议的成功。

1983年:TCP/IP协议正式替代NCP,从此以后TCP/IP成为大部分因特网共同遵守的一种网络规则。

1984年:TCP/IP协议得到美国国防部的肯定,成为多数计算机共同遵守的一个标准。 

是的,你没有看错,TCP/IP协议设计于距今50年前!

 

▲ 罗伯特·卡恩(左者)与文特·瑟夫(右者)(图片引用自《技术往事:改变世界的TCP/IP协议》)

6、TCP/IP原本是为固定网络设计的

虽然TCP/IP自上世纪70年代发明以来,连接了无数的计算机,推动了互联网的蓬勃发展。

但不可回避的现实是,基于TCP/IP的互联网,它的初衷是为固定网络和网络互连而设计,而今天我们已经发展到了移动互联时代。

再往后看,未来5G将面临AR/VR、超高清视频、物联网、车联网等各种应用、用例纷呈,加之网络安全的紧迫性越发凸显,TCP/IP或许难以适应未来。

7、TCP/IP或许并不适合移动网络

7.1 TCP/IP设计之初无法预见高速移动网时代

在TCP/IP刚被设计的年代,即传统固定互联网的公元元年,主机是固定的,用于编址的IP也是固定的,世界是平的。

可是随着应用程序以及芯片技术的活力涌现,设备越来越小,App越来越丰富,当你觉得浑身憋得慌的时候,移动互联网时代来了。

但传统的TCP/IP并不适合移动网络,以TCP/IP协议簇中我们最常用的TCP协议来说,传统的TCP基于TCP/IP协议头字段的五元组,而标识设备的IP地址仅仅标识了设备位置,并没有标识设备本身(实际上不管到了什么年代,IP地址都不应该标识设备本身,它就是标识位置的!问题是,TCP不应该用一个标识位置的元素来标识设备)。

而对于移动互联网来说,一旦移动设备(比如智能手机)换了位置(通信基站切换了),其IP地址也会改变,进而既有的TCP连接将全部中断。

 

▲ 运营商的基站是有覆盖范围的,而且覆盖范围并不大

对于底层的移动网络通信技术有所了解的开发人员或许知道,手机的通信是由基站进行代理的,而基站是固定的。换句话说,当你移动到下一个基站的位置时,手机就得自动切换到新的基站,进而重新进行一系列的跟运营商的无线体系进行连接建立的过程。

这在日常生活中使用并没有什么问题,但在时速达到350公里每小时的复兴号高铁上用手机上网时,这就会导致严重的问题。因为基站的信号覆盖范围有限,在手机移动速度如此之快的情况下,基站的切换也将频繁到让网络工程师们崩溃(有兴趣可以读一下《IM开发者的零基础通信技术入门(十四):高铁上无线上网有多难?一文即懂!》)。

TCP/IP和网络的关系,可以作个有趣的类比。

假设互联网是公路,那么TCP/IP这就是这条公路上的一套交通规则。这套规则在制定时,可能考虑到的只是普通的市场内道路(最多是高速公路使用),而现在的5G时代,就好比时速350公里的高速铁路,试想普通的市内交通规则套用在高速铁路上,那难道不算是灾难吗。

必竟普通的市内交通速度不会很快,各种规则的制定误差和余量可以比较大,但高速铁路上,速度飞快、交通信号控制精确无比的情况下,这套规则,对于开高铁的司机来说,肯定是胆颤心惊。而TCP/IP对于5G来说,就好比这套老的交通规则,用它来驾驭这么快速的5G快车,是不是很疯狂?

 

7.2 TCP/IP与电信网的基因不同

基于TCP/IP的互联网原本是为固定网络和网络互联设计,而运营商的移动网络是为移动性连接而生。互联网的连接是分布式的,而移动通信网络是集中控制的。

这两者的技术基因确实有很大不同,在早期移动网络网络性能较慢的情况下,这两者的结合,矛盾似乎并不突出。

实际上,在传统电信网(就是大家最常用的电话、短信网络)与IT互联网是两拨人各自有玩耍(电信网为代表的就是3GPP标准化组织,互联网为代表的就是IETF标准化组织)。

在那个移动网还不发达的年代,这两拨人各自玩各自的,大家谁也不用鸟谁。

随着人们对移动上网需求越来越旺盛,搞电信网的这拨人只能想办法接入传统的互联网,必竟在当时传统互联网太强势,而移动网的应用场景还在摸索阶段,为了能快速解决移动上网的问题,与是也不好麻烦IETF这拨人,所有痛苦默默承受——虽然TCP/IP在移动网上的实施并不合适,但只能想办法缝缝补补,把移动网的标准制定,往它上面靠。

这就好比,TCP/IP这辆车已经造好了,至于你搞移动网的人,是修一条普通马路(2G)、还是一条高速公司路(3G)、或者是现在的高速铁路(5G),反正你只能将就这辆车。原本应该是什么路上跑什么车,而现在是不管你什么路,只能跑这辆车。反正车子跑不好,不怪车子,怪路。。

好奇葩的逻辑,而这个逻辑就好比是现在的TCP/IP跟移动网的关系。

所以,在5G,甚至未来的6G、7G时代,这种“勉强”的结合,抛必带来网络低效、基础设施成本高昂等问题。

8、移动运营商们已经意识到问题

是的,大佬们已经意识到了问题的严重性,正在着手解决。

2020年4月初,欧洲电信标准协会(ETSI)已成立了一个新的行业规范工作组“Non-IP Networking”(ISG NIN),以解决新服务、尤其是5G服务面临的老式网络协议所存在的问题。

▲ 详细新闻内容《点此查看

该工作组的目标是为5G网络研究开发新的网络协议,以替代TCP/IP。

是的,这些移动运营商已经发现在4G、甚至5G网络中使用的基于TCP/IP的技术存在一些问题。

由于TCP/IP协议最初是为互联网设计,而非为移动通信网络而生,当移动通信网络引入TCP/IP后,增加了移动性、安全性、QoS等功能,这使得网络更复杂,频谱使用效率较低。为了解决这些问题,后续的修补和替代方案又导致了成本、时延和功耗增加。

大佬们终于承认,对于5G的某些高级服务,TCP/IP确实被认为不是最佳的。

9、移动网络未来会怎样?

虽然TCP/IP可能越来越难以适应移动网络的发展,但不可否认,短期内TCP/IP的不可替代性。

必竟,基于TCP/IP的传统互联网所构建的软件和硬件世界(尤其是硬件)并不是一朝一夕的事,而替换掉这些,无论是从成本还是各方利益来说,都是个需要反复权衡和博弈的事。

一个很好的例子是,IPv4和IPv6,虽然谁都知道IPv4的困境,但IPv6喊了这么多年目前想要普及,仍然还比较遥远,要知道IPv6已经喊了10年了。因为这小小的IP地址,牵涉的是互联网从硬到软几乎所有环节,影响之大,无出其右。

对于IM开发者来说,因为移动网络的特殊性,而技术改朝换代也并不鲜见。

比如众所周之的XMPP协议,设计之初也是野心勃勃——“要让上IM就像打开网页一样简单!”。确实,XMPP无论是肉眼可读性,还是数据结构的优雅,都非常优秀,但悲剧的是,设计者们从来没有想过移动网会发展成今天这样,或者说设计者们从未考虑过XMPP在移动网下的使用。于是,后面的故事,大家都很清楚——每个人都在抱怨XMPP臃肿、冗余(是的,这里我收集了一大堆这样的文章),这算个是把优点做成缺点的典型案例了。

或许,未来会有那么一天,移动网络终有属于为自已定制的网络协议标准。而对于搞网络通信的程序员来说,如果这套新的标准让能基于移动网络的代码编写,变的愉快起来,那真是谢天谢地了!

10、参考资料

[1] TCP/IP 已完 ?New IP 之后,又来一个 Non-IP

[2] 5G:再见,TCP/IP

[3] 重新设计TCP/IP协议栈以支持设备移动性

[4] 5G要抛弃TCP/IP?

[5] ETSI LAUNCHES NEW GROUP ON NON-IP NETWORKING ADDRESSING 5G NEW SERVICES

附录:更多网络编程基础资料

TCP/IP详解 - 第11章·UDP:用户数据报协议

TCP/IP详解 - 第17章·TCP:传输控制协议

TCP/IP详解 - 第18章·TCP连接的建立与终止

TCP/IP详解 - 第21章·TCP的超时与重传

技术往事:改变世界的TCP/IP协议(珍贵多图、手机慎点)

通俗易懂-深入理解TCP协议(上):理论基础

通俗易懂-深入理解TCP协议(下):RTT、滑动窗口、拥塞处理

理论经典:TCP协议的3次握手与4次挥手过程详解

理论联系实际:Wireshark抓包分析TCP 3次握手、4次挥手过程

计算机网络通讯协议关系图(中文珍藏版)

UDP中一个包的大小最大能多大?

P2P技术详解(一):NAT详解——详细原理、P2P简介

P2P技术详解(二):P2P中的NAT穿越(打洞)方案详解(基本原理篇)

P2P技术详解(三):P2P中的NAT穿越(打洞)方案详解(进阶分析篇)

P2P技术详解(四):P2P技术之STUN、TURN、ICE详解

通俗易懂:快速理解P2P技术中的NAT穿透原理

高性能网络编程(一):单台服务器并发TCP连接数到底可以有多少

高性能网络编程(二):上一个10年,著名的C10K并发连接问题

高性能网络编程(三):下一个10年,是时候考虑C10M并发问题了

高性能网络编程(四):从C10K到C10M高性能网络应用的理论探索

高性能网络编程(五):一文读懂高性能网络编程中的I/O模型

高性能网络编程(六):一文读懂高性能网络编程中的线程模型

Java的BIO和NIO很难懂?用代码实践给你看,再不懂我转行!

不为人知的网络编程(一):浅析TCP协议中的疑难杂症(上篇)

不为人知的网络编程(二):浅析TCP协议中的疑难杂症(下篇)

不为人知的网络编程(三):关闭TCP连接时为什么会TIME_WAIT、CLOSE_WAIT

不为人知的网络编程(四):深入研究分析TCP的异常关闭

不为人知的网络编程(五):UDP的连接性和负载均衡

不为人知的网络编程(六):深入地理解UDP协议并用好它

不为人知的网络编程(七):如何让不可靠的UDP变的可靠?

不为人知的网络编程(八):从数据传输层深度解密HTTP

不为人知的网络编程(九):理论联系实际,全方位深入理解DNS

网络编程懒人入门(一):快速理解网络通信协议(上篇)

网络编程懒人入门(二):快速理解网络通信协议(下篇)

网络编程懒人入门(三):快速理解TCP协议一篇就够

网络编程懒人入门(四):快速理解TCP和UDP的差异

网络编程懒人入门(五):快速理解为什么说UDP有时比TCP更有优势

网络编程懒人入门(六):史上最通俗的集线器、交换机、路由器功能原理入门

网络编程懒人入门(七):深入浅出,全面理解HTTP协议

网络编程懒人入门(八):手把手教你写基于TCP的Socket长连接

网络编程懒人入门(九):通俗讲解,有了IP地址,为何还要用MAC地址?

网络编程懒人入门(十):一泡尿的时间,快速读懂QUIC协议

技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解

让互联网更快:新一代QUIC协议在腾讯的技术实践分享

现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障

聊聊iOS中网络编程长连接的那些事

移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”

移动端IM开发者必读(二):史上最全移动弱网络优化方法总结

IPv6技术详解:基本概念、应用现状、技术实践(上篇)

IPv6技术详解:基本概念、应用现状、技术实践(下篇)

从HTTP/0.9到HTTP/2:一文读懂HTTP协议的历史演变和设计思路

脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手

脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

脑残式网络编程入门(三):HTTP协议必知必会的一些知识

脑残式网络编程入门(四):快速理解HTTP/2的服务器推送(Server Push)

脑残式网络编程入门(五):每天都在用的Ping命令,它到底是什么?

脑残式网络编程入门(六):什么是公网IP和内网IP?NAT转换又是什么鬼?

脑残式网络编程入门(七):面视必备,史上最通俗计算机网络分层详解

脑残式网络编程入门(八):你真的了解127.0.0.1和0.0.0.0的区别?

以网游服务端的网络接入层设计为例,理解实时通信的技术挑战

迈向高阶:优秀Android程序员必知必会的网络基础

全面了解移动端DNS域名劫持等杂症:技术原理、问题根源、解决方案等

美图App的移动端DNS优化实践:HTTPS请求耗时减小近半

Android程序员必知必会的网络通信传输层协议——UDP和TCP

IM开发者的零基础通信技术入门(一):通信交换技术的百年发展史(上)

IM开发者的零基础通信技术入门(二):通信交换技术的百年发展史(下)

IM开发者的零基础通信技术入门(三):国人通信方式的百年变迁

IM开发者的零基础通信技术入门(四):手机的演进,史上最全移动终端发展史

IM开发者的零基础通信技术入门(五):1G到5G,30年移动通信技术演进史

IM开发者的零基础通信技术入门(六):移动终端的接头人——“基站”技术

IM开发者的零基础通信技术入门(七):移动终端的千里马——“电磁波”

IM开发者的零基础通信技术入门(八):零基础,史上最强“天线”原理扫盲

IM开发者的零基础通信技术入门(九):无线通信网络的中枢——“核心网”

IM开发者的零基础通信技术入门(十):零基础,史上最强5G技术扫盲

IM开发者的零基础通信技术入门(十一):为什么WiFi信号差?一文即懂!

IM开发者的零基础通信技术入门(十二):上网卡顿?网络掉线?一文即懂!

IM开发者的零基础通信技术入门(十三):为什么手机信号差?一文即懂!

IM开发者的零基础通信技术入门(十四):高铁上无线上网有多难?一文即懂!

IM开发者的零基础通信技术入门(十五):理解定位技术,一篇就够

百度APP移动端网络深度优化实践分享(一):DNS优化篇

百度APP移动端网络深度优化实践分享(二):网络连接优化篇

百度APP移动端网络深度优化实践分享(三):移动端弱网优化篇

技术大牛陈硕的分享:由浅入深,网络编程学习经验干货总结

可能会搞砸你的面试:你知道一个TCP连接上能发起多少个HTTP请求吗?

知乎技术分享:知乎千万级并发的高性能长连接网关技术实践

5G时代已经到来,TCP/IP老矣,尚能饭否?

>> 更多同类文章 ……

欢迎关注我的“即时通讯技术圈”公众号: 

(本文已同步发布于:http://www.52im.net/thread-2976-1-1.html

posted @ 2020-04-13 23:41 Jack Jiang 阅读(490) | 评论 (0)编辑 收藏

     摘要: 本文作者腾讯WXG后台开发工程师jeryyzhang,收录时有改动,感谢原作者的分享。1、引言大约3年前,微信技术团队分享了《微信后台基于时间序的海量数据冷热分级架构设计实践》一文,文中总结了微信这种超级IM基于时间序的海量数据存储架构的设计实践,也得以让大家了解了微信后台的架构设计思路。时隔3年,微信再次分享了基于时间序的新一代海量数据存储架构的设计实践(可以认为是《微信后台基于时间序的海量数据...  阅读全文

posted @ 2020-04-09 15:07 Jack Jiang 阅读(312) | 评论 (0)编辑 收藏

     摘要: 一、引言2020年春节早已过去两月有余,回顾本次腾讯手Q春节红包活动的玩法,主要以答题形式结合中国传统文化(成语、诗词、对联、历史等)的方式进行,达到寓教于乐的效果。 ▲ 2020年春节QQ的红包活动对于这种大体量的IM社交应用运营活动,技术上除了前端、后台的大力支撑,对于手Q客户端来说,又是从哪些方面来保证整个红包活动的灵活性、稳定性和用户体验的呢?带着这个问题,我们一起来...  阅读全文

posted @ 2020-04-06 23:41 Jack Jiang 阅读(294) | 评论 (0)编辑 收藏

     摘要: 本文原文由微信客户端高级工程师方秋枋原创发表于WeMobileDev公众号,收录时有修订和加工,感谢作者的无私分享。1、引言作为一个重要业务,微信支付在客户端上面临着各种问题。其中最核心问题就是分平台实现导致的问题:1)iOS 和安卓实现不一致:容易出 Bug、通过沟通保证不了质量;2)扩展性差且无法快速响应业务需求:需求变更迭代周期长、数据上报不全面;3)质量保障体系不完善:缺少业务及设计知识沉...  阅读全文

posted @ 2020-03-25 17:00 Jack Jiang 阅读(414) | 评论 (0)编辑 收藏

     摘要: 1、引言很多人一想到IM应用开发,第一印象就是“长连接”、“socket”、“保活”、“协议”这些关键词,没错,这些确实是IM开发中肯定会涉及的技术范畴。但,当你真正开始编写第一行代码时,最现实的问题实际上是“聊天消息ID该怎么生成?”这个看似微不足道的小事情。说它看似微不足道,...  阅读全文

posted @ 2020-03-19 17:34 Jack Jiang 阅读(368) | 评论 (0)编辑 收藏

本文原文由作者Amazing10原创发布于公众号业余码农,收录时有改动,感谢原作者的技术分享。

1、引言

某天中午,吃完午饭,摊在自己的躺椅上,想趁吃饱喝足的午后时间静静享受独自的静谧。

 
 

干点什么好呢?于是单手操作鼠标打开了一个陌生而隐秘的网站。正开着某个视频起劲。。。

突然浏览器弹出了一个提示:

请使用微信扫码登录账号,继续观看

这...

 
 

但是由于强烈的好奇驱使,迫于无奈,只好选择登录再继续观看。于是熟练的掏出手机,打开微信扫一扫对准上面的二维码,只听见 “叮” 的一声,网页上的二维码放佛活过来了,直接刷新出了本尊的微信头像,同时手机上也弹出登录的提醒。

 
 

心中略微惊叹,但没来得及多想。忙点击手机界面中登录按钮。此时网页刷新,恢复了正常,表示可以继续观看。

上网冲浪的时间总是过得很快,很快就有些疲倦。于是闭上眼睛,脑海中却浮现出了刚刚微信扫描二维码,然后登录网页的场景,心中再次惊叹,并开始思考起其中的原理来。。。

言归正传,本文将以轻松活泼的语言形式,为你分析和讲解微信手机扫码登录的技术原理,希望在你的IM中开发此功能时有所启发。

推荐阅读:另一篇同类文章《IM的扫码登录功能如何实现?一文搞懂主流的扫码登录技术原理》也值得一读。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170[推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

(本文同步发布于:http://www.52im.net/thread-2941-1-1.html

2、IM开发干货系列文章

本文是系列文章中的第23篇,总目录如下:

IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

IM消息送达保证机制实现(二):保证离线消息的可靠投递

如何保证IM实时消息的“时序性”与“一致性”?

IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?

IM群聊消息如此复杂,如何保证不丢不重?

一种Android端IM智能心跳算法的设计与实现探讨(含样例代码)

移动端IM登录时拉取数据如何作到省流量?

通俗易懂:基于集群的移动端IM接入层负载均衡方案分享

浅谈移动端IM的多点登录和消息漫游原理

IM开发基础知识补课(一):正确理解前置HTTP SSO单点登录接口的原理

IM开发基础知识补课(二):如何设计大量图片文件的服务端存储架构?

IM开发基础知识补课(三):快速理解服务端数据库读写分离原理及实践建议

IM开发基础知识补课(四):正确理解HTTP短连接中的Cookie、Session和Token

IM群聊消息的已读回执功能该怎么实现?

IM群聊消息究竟是存1份(即扩散读)还是存多份(即扩散写)?

IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列

一个低成本确保IM消息时序的方法探讨

IM开发基础知识补课(六):数据库用NoSQL还是SQL?读这篇就够了!

IM里“附近的人”功能实现原理是什么?如何高效率地实现它?

IM开发基础知识补课(七):主流移动端账号登录方式的原理及设计思路

IM开发基础知识补课(八):史上最通俗,彻底搞懂字符乱码问题的本质

IM的扫码登功能如何实现?一文搞懂主流应用的扫码登录技术原理

IM要做手机扫码登陆?先看看微信的扫码登录功能技术原理》(本文)

3、原理解析

微信扫码登录现在在日常生活中已经是常见不能再常见的场景之一了,但是要知道微信首次公开这项功能时,却是惊艳众人。移动端与PC端以这样一种巧妙的方式链接在了一起,的确是让人惊叹。

以下是一个典型的微信扫码登录全过程: 

本来想在Web版微信上截图,但扫码登陆后出现了下面的提示(貌似很多人都碰到过): 

好吧,这很微信,反正就是不想让你好好用,用户爱咋咋滴。。。

如上图所示,操作过程如下:

1)第一步:电脑上打开PC端(出现2维码);

2)第二步:拿出手机,扫码2维码;

3)第三步:PC端显示扫码成功;

4)第四步:手机端“确认”登录;

5)第五步:成功登陆PC端。

上述实际操作过程,用户体验相当顺滑,也难怪刚出来那会,能惊艳到很多人。

那么,对于上述操作过程的技术实现原理是什么样的呢?

想起来之前听过的前后端的概念,知道账户的数据信息一般都是放在服务器上,前端负责向后端 “讨要数据” 并显示,后端则是对前端的 “讨要” 做出反应。

这样一来,猜测微信登录的过程可能就是:

1)网页前端向微信后台请求账号数据;

2)微信后台接受网页前端的请求,然后将他的账号数据返回;

3)网页前端接收到了数据后,在浏览器里进行显示。

于是,手脚麻利的画了个示意图:

当我正准备沾沾自喜的时候,突然看到桌面上的手机。咦,如果就只是这么个过程,那手机的作用是啥。于是才开始意识到,问题没这么简单。

好吧,我们城要再深入一点探秘微信扫码登录的过程。

4、过程分析

为了更深入的分析整个过程,我们可以去看看微信网页版,地址是:https://wx.qq.com/

 

笔者看着网页中硕大的二维码陷入了沉思——这个二维码跟手机账号有没有什么对应关系呢?如果没有,那它又是怎么生成的呢?

思考间,于是打开了浏览器的开发者工具。

在网络监控一览找到了这幅二维码,与之对应的链接是:

https://login.weixin.qq.com/qrcode/gaO8cOQweA==

如下图所示:

然后习惯性地,尝试多次刷新页面,发现二维码不断发生变化,链接也不断更改:

https://login.weixin.qq.com/qrcode/AencxgKNFQ==

https://login.weixin.qq.com/qrcode/YcD7f_DxvA==

https://login.weixin.qq.com/qrcode/QblN8lCn2g==

似乎发现了些东西:二维码不断变化,其对应的链接尾的代码也相应变化,并且是随机性的变化。

这也就是说,每一次页面刷新都会随机且唯一地生成一个二维码。这或许可以与手机登录的过程联系起来。

似乎开始明白了,于是再次拿起手机,熟练的使用微信扫描了此时的二维码。

“叮” 的一声,网页上的二维码顿时变成了我帅气的微信头像。这个时候,我才突然意识到,是扫码之后网页才与他的微信账号建立起了联系。

如下图所示: 

也就是说:

1)没有扫码之前,页面上的二维码只是随机生成的且与用户无关的码;

2)而当用户扫码之后,二维码便与用户帐号绑定在了一起。

原来手机扫码的用处是这样!

此时注意到,手机微信上弹出了『微信登录确认』的提醒。这个时候谨慎地点击了下方的登录按钮。

如下图所示: 

随着平滑的动画一闪而过,网页上已经显示出了我的微信账号信息,显示微信账号已经登录。再一次体验这个过程,心中开始思索手机微信在登录过程中所起到的具体作用。

首先需要明白几个过程:

1)进入网页登陆界面,随机生成一个二维码;

2)通过手机扫描二维码,将微信账号与二维码绑定;

3)在手机微信点击登录按钮,授权网页登录微信账号;

4)网页获得的账号信息,将数据显示。

5、原理解释

回顾上述过程,结合最开始的原理猜测,开始思索整个环节,是哪里理解的不对。。。

1)网页的二维码到底从何而来?

2)是谁向微信后台请求了账号数据?

实际上:不同的网站可能都需要通过微信后台进行数据的获取,那么每一个网站必然也存在它的后台来给微信后台发送请求。

这样一来,整个过程就能解释得通了:

1)网站页面刷新,网页后台向微信后台请求授权登录;

2)微信后台返回登录所需二维码;

3)用户通过手机扫描二维码,并在手机上授权登录后,微信后台告知网页后台已授权;

4)网页后台向微信后台请求微信账号数据;

5)微信后台返回账号数据;

6)网页后台接收数据并通过浏览器显示;

6、技术剖析

正如上节所述,想清楚了整个过程后,我们应该对整个过程的技术实现进行进一步的探究。

在微信开发官方文档中,我找到了第三方网站应用微信登录开发指南:

https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html

我将整个过程梳理了一遍,画出了这个图: 

如上图所示,整个技术实现如下。

(1)二维码的获得:

  • 1)用户打开网站后,网站后台根据微信OAuth2.0协议向微信开发平台请求授权登录,并传递事先在微信开发平台中审核通过的AppID和AppSecrect等参数;
  • 2)微信开发平台对AppID等参数进行验证,并向网站后台返回二维码;
  • 3)网站后台将二维码传送至网站前端进行显示。

(2)微信客户端授权登录:

  • 1)用户使用微信客户端扫描二维码并授权登录;
  • 2)微信客户端将二维码特定的uid与微信账号绑定,传送至微信开发平台;
  • 3)微信开发平台验证绑定数据,调用网站后台的回调接口,发送授权临时票据code;

(3)网站后台请求数据:

  • 1)网站后台接收到code,表明微信开发平台同意数据请求;
  • 2)网站后台根据code参数,再加上AppID和AppSecret请求微信开发平台换取access_token;
  • 3)微信开发平台验证参数,并返回access_token;
  • 4)网站后台收到access_token后即可进行参数分析获得用户账号数据。

在上述过程中,有几个参数值得解释一下(来源官方文档):

  • 1)AppID:应用唯一标识,在微信开放平台提交应用审核通过后获得;
  • 2)AppSecret:应用密钥,在微信开放平台提交应用审核通过后获得;
  • 3)code:授权临时票据,第三方通过code进行获取access_token的时候需要用到,code的超时时间为10分钟,一个code只能成功换取一次access_token即失效。code的临时性和一次性保障了微信授权登录的安全性。

整个过程从网站后台向微信开发平台请求授权登录开始,最终目的是为了获得access_token:

access_token:用户授权第三方应用发起接口调用的凭证

在获得了access_token后就可以解析用户的一些基本信息,包括头像、用户名、性别、城市等。这样一来,整个微信扫描登录的过程就完成了。

7、写在最后

研究到这,终于大体上对微信扫码登录的整个过程有了清晰的认知。看起来似乎也不难,开发者只需要在网页后端做好对微信公众平台的接口调用即可实现扫码登录。

伸了伸懒腰,忽然又想到在整个过程中还需要考虑超时的问题。比如二维码超时未扫描、二维码扫描后超时授权、获得access_token后超时等等问题。

我发现一个简单的功能实现起来还是需要考虑许多细节,真的是纸上得来终觉浅呀。于是我下定决心,下次得少上网冲浪了,花点时间搭个服务器先把微信扫码登录过程实现看看。

不过,还得先去在微信开放平台注册开发者帐号,并拥有一个已审核通过的网站应用,并获得相应的AppID和AppSecret才行。

想了想,还是让我先趟一会儿吧。。。

 

附录:更多IM开发相关文章

[1] IM开发热门文章:

新手入门一篇就够:从零开发移动端IM

移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”

移动端IM开发者必读(二):史上最全移动弱网络优化方法总结

从客户端的角度来谈谈移动端IM的消息可靠性和送达机制

现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障

腾讯技术分享:社交网络图片的带宽压缩技术演进之路

小白必读:闲话HTTP短连接中的Session和Token

移动端IM开发需要面对的技术问题

开发IM是自己设计协议用字节流好还是字符流好?

请问有人知道语音留言聊天的主流实现方式吗?

通俗易懂:基于集群的移动端IM接入层负载均衡方案分享

微信对网络影响的技术试验及分析(论文全文)

即时通讯系统的原理、技术和应用(技术论文)

开源IM工程“蘑菇街TeamTalk”的现状:一场有始无终的开源秀

QQ音乐团队分享:Android中的图片压缩技术详解(上篇)

QQ音乐团队分享:Android中的图片压缩技术详解(下篇)

腾讯原创分享(一):如何大幅提升移动网络下手机QQ的图片传输速度和成功率

腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(上篇)

腾讯原创分享(三):如何大幅压缩移动网络下APP的流量消耗(下篇)

如约而至:微信自用的移动端IM网络层跨平台组件库Mars已正式开源

基于社交网络的Yelp是如何实现海量用户图片的无损压缩的?

腾讯技术分享:腾讯是如何大幅降低带宽和网络流量的(图片压缩篇)

腾讯技术分享:腾讯是如何大幅降低带宽和网络流量的(音视频技术篇)

字符编码那点事:快速理解ASCII、Unicode、GBK和UTF-8

全面掌握移动端主流图片格式的特点、性能、调优等

子弹短信光鲜的背后:网易云信首席架构师分享亿级IM平台的技术实践

微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

自已开发IM有那么难吗?手把手教你自撸一个Andriod版简易IM (有源码)

融云技术分享:解密融云IM产品的聊天消息ID生成策略

适合新手:从零开发一个IM服务端(基于Netty,有完整源码)

拿起键盘就是干:跟我一起徒手开发一套分布式IM系统

>> 更多同类文章 …… 

[2] 有关WEB端即时通讯开发:

新手入门贴:史上最全Web端即时通讯技术原理详解

Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE

SSE技术详解:一种全新的HTML5服务器推送事件技术

Comet技术详解:基于HTTP长连接的Web端实时通信技术

新手快速入门:WebSocket简明教程

WebSocket详解(一):初步认识WebSocket技术

WebSocket详解(二):技术原理、代码演示和应用案例

WebSocket详解(三):深入WebSocket通信协议细节

WebSocket详解(四):刨根问底HTTP与WebSocket的关系(上篇)

WebSocket详解(五):刨根问底HTTP与WebSocket的关系(下篇)

WebSocket详解(六):刨根问底WebSocket与Socket的关系

socket.io实现消息推送的一点实践及思路

LinkedIn的Web端即时通讯实践:实现单机几十万条长连接

Web端即时通讯技术的发展与WebSocket、Socket.io的技术实践

Web端即时通讯安全:跨站点WebSocket劫持漏洞详解(含示例代码)

开源框架Pomelo实践:搭建Web端高性能分布式IM聊天服务器

使用WebSocket和SSE技术实现Web端消息推送

详解Web端通信方式的演进:从Ajax、JSONP 到 SSE、Websocket

MobileIMSDK-Web的网络层框架为何使用的是Socket.io而不是Netty?

理论联系实际:从零理解WebSocket的通信原理、协议格式、安全性

微信小程序中如何使用WebSocket实现长连接(含完整源码)

八问WebSocket协议:为你快速解答WebSocket热门疑问

快速了解Electron:新一代基于Web的跨平台桌面技术

一文读懂前端技术演进:盘点Web前端20年的技术变迁史

Web端即时通讯基础知识补课:一文搞懂跨域的所有问题!

>> 更多同类文章 ……

(本文同步发布于:http://www.52im.net/thread-2941-1-1.html

posted @ 2020-03-13 17:15 Jack Jiang 阅读(351) | 评论 (0)编辑 收藏

     摘要: 一、引言对于后端程序员来说,127.0.0.1和0.0.0.0这两个IP地址再熟悉不过了,看起来好像就那么回事,但真正较起真来,这两个IP地址到底有什么作用以及到底有什么不同?貌似谁可以轻松回答,但张嘴却又不知从何说起。。。(这要是面视,估计真会被这搞砸...)本文将系统地总结127.0.0.1和0.0.0.0这两个IP地址的作用,以及它们之间的区别,希望能为你解惑。  * 推...  阅读全文

posted @ 2020-03-03 15:53 Jack Jiang 阅读(677) | 评论 (0)编辑 收藏

     摘要: 1、引言上个月在知乎上发表的由“袁辉辉”分享的关于TIM进程永生方面的文章(即时通讯网重新整理后的标题是:《史上最强Android保活思路:深入剖析腾讯TIM的进程永生技术》),短时间内受到大量关注,可惜在短短的几十个小时后,就在一股神秘力量的干预下被强行删除了。。。 ▲ 该文在知乎上从发布到删除的时间历程(中间省略了N条读者的评论)在《史上最强And...  阅读全文

posted @ 2020-02-26 22:44 Jack Jiang 阅读(472) | 评论 (0)编辑 收藏

本文由马蜂窝技术团队电商交易基础平台研发工程师"Anti Walker"原创分享。

一、引言

即时通讯(IM)功能对于电商平台来说非常重要,特别是旅游电商。

从商品复杂性来看,一个旅游商品可能会包括用户在未来一段时间的衣、食、住、行等方方面面。从消费金额来看,往往单次消费额度较大。对目的地的陌生、在行程中可能的问题,这些因素使用户在购买前、中、后都存在和商家沟通的强烈需求。可以说,一个好用的 IM 可以在一定程度上对企业电商业务的 GMV 起到促进作用。

本文我们将结合马蜂窝旅游电商IM系统的发展历程,单独介绍基于Go重构分布式IM系统过程中的实践和总结(本文相当于《从游击队到正规军(一):马蜂窝旅游网的IM系统架构演进之路》一文的进阶篇),希望可以给有相似问题的朋友一些借鉴。

另外:如果你对Go在高并发系统中的应用感兴趣,即时通讯网的以下两篇也值得一读:

Go语言构建千万级在线的高并发消息推送系统实践(来自360公司)

12306抢票带来的启示:看我如何用Go实现百万QPS的秒杀系统(含源码)

系列文章:

从游击队到正规军(一):马蜂窝旅游网的IM系统架构演进之路

从游击队到正规军(二):马蜂窝旅游网的IM客户端架构演进和实践总结

从游击队到正规军(三):基于Go的马蜂窝旅游网分布式IM系统技术实践》(* 本文

关于马蜂窝旅游网: 

马蜂窝旅游网是中国领先的自由行服务平台,由陈罡和吕刚创立于2006年,从2010年正式开始公司化运营。马蜂窝的景点、餐饮、酒店等点评信息均来自上亿用户的真实分享,每年帮助过亿的旅行者制定自由行方案。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170 [推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

(本文同步发布于:http://www.52im.net/thread-2909-1-1.html

二、相关文章

一套海量在线用户的移动端IM架构设计实践分享(含详细图文)

一套原创分布式即时通讯(IM)系统理论架构方案

从零到卓越:京东客服即时通讯系统的技术架构演进历程

蘑菇街即时通讯/IM服务器开发之架构选择

以微博类应用场景为例,总结海量社交系统的架构设计步骤

一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践

腾讯QQ1.4亿在线用户的技术挑战和架构演进之路PPT

微信技术总监谈架构:微信之道——大道至简(演讲全文)

如何解读《微信技术总监谈架构:微信之道——大道至简》

快速裂变:见证微信强大后台架构从0到1的演进历程(一)

瓜子IM智能客服系统的数据架构设计(整理自现场演讲,有配套PPT)

阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处

三、技术背景和问题

与广义上的即时通讯不同,电商各业务线有其特有业务逻辑,如客服聊天系统的客人分配逻辑、敏感词检测逻辑等,这些往往要耦合进通信流程中。随着接入业务线越来越多,即时通讯服务冗余度会越来越高。同时整个消息链路追溯复杂,服务稳定性很受业务逻辑的影响。

之前我们 IM 应用中的消息推送主要基于轮询技术,消息轮询模块的长连接请求是通过 php-fpm 挂载在阻塞队列上实现。当请求量较大时,如果不能及时释放 php-fpm 进程,对服务器的性能消耗很大。

为了解决这个问题,我们曾用 OpenResty+Lua 的方式进行改造,利用 Lua 协程的方式将整体的 polling 的能力从 PHP 转交到 Lua 处理,释放一部 PHP 的压力。这种方式虽然能提升一部分性能,但 PHP-Lua 的混合异构模式,使系统在使用、升级、调试和维护上都很麻烦,通用性也较差,很多业务场景下还是要依赖 PHP 接口,优化效果并不明显。

为了解决以上问题,我们决定结合电商 IM 的特定背景对 IM 服务进行重构,核心是实现业务逻辑和即时通讯服务的分离。

更多有关马蜂窝旅游网的IM系统架构的演进过程,请详读:《从游击队到正规军(一):马蜂窝旅游网的IM系统架构演进之路》一文,在此不再赘述。

四、基于Go的双层分布式IM架构

4.1、实现目标

1)业务解耦:

将业务逻辑与通信流程剥离,使 IM 服务架构更加清晰,实现与电商 IM 业务逻辑的完全分离,保证服务稳定性。

2)接入方式灵活:

之前新业务接入时,需要在业务服务器上配置 OpenResty 环境及 Lua 协程代码,非常不便,IM 服务的通用性也很差。考虑到现有业务的实际情况,我们希望 IM 系统可以提供 HTTP 和 WebSocket 两种接入方式,供业务方根据不同的场景来灵活使用。

比如已经接入且运行良好的电商定制化团队的待办系统、定制游抢单系统、投诉系统等下行相关的系统等,这些业务没有明显的高并发需求,可以通过 HTTP 方式迅速接入,不需要熟悉稍显复杂的 WebSocket 协议,进而降低不必要的研发成本。

3)架构可扩展:

为了应对业务的持续增长给系统性能带来的挑战,我们考虑用分布式架构来设计即时通讯服务,使系统具有持续扩展及提升的能力。

4.2、语言选择

目前,马蜂窝技术体系主要包括 PHP,Java,Golang,技术栈比较丰富,使业务做选型时可以根据问题场景选择更合适的工具和语言。

结合 IM 具体应用场景,我们选择 Go 的原因包括:

  • 1)运行性能:在性能上,尤其是针对网络通信等 IO 密集型应用场景。Go 系统的性能更接近 C/C++;
  • 2)开发效率:Go 使用起来简单,代码编写效率高,上手也很快,尤其是对于有一定 C++ 基础的开发者,一周就能上手写代码了。

4.3、架构设计

整体架构图如下: 

名词解释:

  • 1)客户:一般指购买商品的用户;
  • 2)商家:提供服务的供应商,商家会有客服人员,提供给客户一个在线咨询的作用;
  • 3)分发模块:即 Dispatcher,提供消息分发的给指定的工作模块的桥接作用;
  • 4)工作模块:即 Worker 服务器,用来提供 WebSocket 服务,是真正工作的一个模块。

架构分层:

  • 1)展示层:提供 HTTP 和 WebSocket 两种接入方式;
  • 2)业务层:负责初始化消息线和业务逻辑处理。如果客户端以 HTTP 方式接入,会以 JSON 格式把消息发送给业务服务器进行消息解码、客服分配、敏感词过滤,然后下发到消息分发模块准备下一步的转换;通过 WebSocket 接入的业务则不需要消息分发,直接以 WebSocket 方式发送至消息处理模块中;
  • 3)服务层:由消息分发和消息处理这两层组成,分别以分布式的方式部署多个 Dispatcher 和 Worker 节点。Dispatcher 负责检索出接收者所在的服务器位置,将消息以 RPC 的方式发送到合适的 Worker 上,再由消息处理模块通过 WebSocket 把消息推送给客户端;
  • 4)数据层:Redis 集群,记录用户身份、连接信息、客户端平台(移动端、网页端、桌面端)等组成的唯一 Key。

4.4、服务流程

步骤一:

如上图右侧所示:

用户客户端与消息处理模块建立 WebSocket 长连接;

通过负载均衡算法,使客户端连接到合适的服务器(消息处理模块的某个 Worker);

连接成功后,记录用户连接信息,包括用户角色(客人或商家)、客户端平台(移动端、网页端、桌面端)等组成唯一 Key,记录到 Redis 集群。

步骤二:

如图左侧所示,当购买商品的用户要给管家发消息的时候,先通过 HTTP 请求把消息发给业务服务器,业务服务端对消息进行业务逻辑处理。

1)该步骤本身是一个 HTTP 请求,所以可以接入各种不同开发语言的客户端。通过 JSON 格式把消息发送给业务服务器,业务服务器先把消息解码,然后拿到这个用户要发送给哪个商家的客服的。

2)如果这个购买者之前没有聊过天,则在业务服务器逻辑里需要有一个分配客服的过程,即建立购买者和商家的客服之间的连接关系。拿到这个客服的 ID,用来做业务消息下发;如果之前已经聊过天,则略过此环节。

3)在业务服务器,消息会异步入数据库。保证消息不会丢失。

步骤三:

业务服务端以 HTTP 请求把消息发送到消息分发模块。这里分发模块的作用是进行中转,最终使服务端的消息下发给指定的商家。

步骤四:

基于 Redis 集群中的用户连接信息,消息分发模块将消息转发到目标用户连接的 WebSocket 服务器(消息处理模块中的某一个 Worker)

1)分发模块通过 RPC 方式把消息转发到目标用户连接的 Worker,RPC 的方式性能更快,而且传输的数据也少,从而节约了服务器的成本。

2)消息透传 Worker 的时候,多种策略保障消息一定会下发到 Worker。

步骤五:

消息处理模块将消息通过 WebSocket 协议推送到客户端。

1)在投递的时候,接收者要有一个 ACK(应答) 信息来回馈给 Worker 服务器,告诉 Worker 服务器,下发的消息接收者已经收到了。

2)如果接收者没有发送这个 ACK 来告诉 Worker 服务器,Worker 服务器会在一定的时间内来重新把这个信息发送给消息接收者。

3)如果投递的信息已经发送给客户端,客户端也收到了,但是因为网络抖动,没有把 ACK 信息发送给服务器,那服务器会重复投递给客户端,这时候客户端就通过投递过来的消息 ID 来去重展示。

以上步骤的数据流转大致如图所示:

4.5、系统完整性设计

4.5.1 可靠性

(1)消息不丢失:

为了避免消息丢失,我们设置了超时重传机制。服务端会在推送给客户端消息后,等待客户端的 ACK,如果客户端没有返回 ACK,服务端会尝试多次推送。

目前默认 18s 为超时时间,重传 3 次不成功,断开连接,重新连接服务器。重新连接后,采用拉取历史消息的机制来保证消息完整。

(2)多端消息同步:

客户端现有 PC 浏览器、Windows 客户端、H5、iOS/Android,系统允许用户多端同时在线,且同一端可以多个状态,这就需要保证多端、多用户、多状态的消息是同步的。

我们用到了 Redis 的 Hash 存储,将用户信息、唯一连接对应值 、连接标识、客户端 IP、服务器标识、角色、渠道等记录下来,这样通过 key(uid) 就能找到一个用户在多个端的连接,通过 key+field 能定位到一条连接。

4.5.2 可用性

上文我们已经说过,因为是双层设计,就涉及到两个 Server 间的通信,同进程内通信用 Channel,非同进程用消息队列或者 RPC。综合性能和对服务器资源利用,我们最终选择 RPC 的方式进行 Server 间通信。

在对基于 Go 的 RPC 进行选行时,我们比较了以下比较主流的技术方案: 

1)Go STDRPC:Go 标准库的 RPC,性能最优,但是没有治理;

2)RPCX:性能优势 2*GRPC + 服务治理;

3)GRPC:跨语言,但性能没有 RPCX 好;

4)TarsGo:跨语言,性能 5*GRPC,缺点是框架较大,整合起来费劲;

5)Dubbo-Go:性能稍逊一筹, 比较适合 Go 和 Java 间通信场景使用。

最后我们选择了 RPCX,因为性能也很好,也有服务的治理。

两个进程之间同样需要通信,这里用到的是 ETCD 实现服务注册发现机制。

当我们新增一个 Worker,如果没有注册中心,就要用到配置文件来管理这些配置信息,这挺麻烦的。而且你新增一个后,需要分发模块立刻发现,不能有延迟。

如果有新的服务,分发模块希望能快速感知到新的服务。利用 Key 的续租机制,如果在一定时间内,没有监听到 Key 有续租动作,则认为这个服务已经挂掉,就会把该服务摘除。

在进行注册中心的选型时,我们主要调研了 ETCDZooKeeperConsul

三者的压测结果参考如下: 

 

结果显示,ETCD 的性能是最好的。另外,ETCD 背靠阿里巴巴,而且属于 Go 生态,我们公司内部的 K8S 集群也在使用。

综合考量后,我们选择使用 ETCD 作为服务注册和发现组件。并且我们使用的是 ETCD 的集群模式,如果一台服务器出现故障,集群其他的服务器仍能正常提供服务。

小结一下:通过保证服务和进程间的正常通讯,及 ETCD 集群模式的设计,保证了 IM 服务整体具有极高的可用性。

4.5.3 扩展性

消息分发模块和消息处理模块都能进行水平扩展。当整体服务负载高时,可以通过增加节点来分担压力,保证消息即时性和服务稳定性。

4.5.4 安全性

处于安全性考虑,我们设置了黑名单机制,可以对单一 uid 或者 ip 进行限制。比如在同一个 uid 下,如果一段时间内建立的连接次数超过设定的阈值,则认为这个 uid 可能存在风险,暂停服务。如果暂停服务期间该 uid 继续发送请求,则限制服务的时间相应延长。

4.6、性能优化和踩过的坑

4.6.1 性能优化

1)JSON 编解码:

开始我们使用官方的 JSON 编解码工具,但由于对性能方面的追求,改为使用滴滴开源的 Json-iterator,使在兼容原生 Golang 的 JSON 编解码工具的同时,效率上有比较明显的提升。

以下是压测对比的参考图: 

2)time.After:

在压测的时候,我们发现内存占用很高,于是使用 Go Tool PProf 分析 Golang 函数内存申请情况,发现有不断创建 time.After 定时器的问题,定位到是心跳协程里面。

原来代码如下: 

优化后的代码为:

优化点在于 for 循环里不要使用 select + time.After 的组合。

3)Map 的使用:

在保存连接信息的时候会用到 Map。因为之前做 TCP Socket 的项目的时候就遇到过一个坑,即 Map 在协程下是不安全的。当多个协程同时对一个 Map 进行读写时,会抛出致命错误:fetal error:concurrent map read and map write,有了这个经验后,我们这里用的是 sync.Map

4.6.2 踩坑经验

1)协程异常:

基于对开发成本和服务稳定性等问题的考虑,我们的 WebSocket 服务基于 Gorilla/WebSocket 框架开发。其中遇到一个问题,就是当读协程发生异常退出时,写协程并没有感知到,结果就是导致读协程已经退出但是写协程还在运行,直到触发异常之后才退出。

这样虽然从表面上看不影响业务逻辑,但是浪费后端资源。在编码时应该注意要在读协程退出后主动通知写协程,这样一个小的优化可以这在高并发下能节省很多资源。

2)心跳设计:

举个例子:之前我们在闲时心跳功能的开发中走了一些弯路。最初在服务器端的心跳发送是定时心跳,但后来在实际业务场景中使用时发现,设计成服务器读空闲时心跳更好。因为用户都在聊天呢,发一个心跳帧,浪费感情也浪费带宽资源。

这时候,建议大家在业务开发过程中如果代码写不下去就暂时不要写了,先结合业务需求用文字梳理下逻辑,可能会发现之后再进行会更顺利。

3)每天分割日志: 

日志模块在起初调研的时候基于性能考虑,确定使用 Uber 开源的 ZAP 库,而且满足业务日志记录的要求。日志库选型很重要,选不好也是影响系统性能和稳定性的。

ZAP 的优点包括:

1)显示代码行号这个需求,ZAP 支持而 Logrus 不支持,这个属于提效的。行号展示对于定位问题很重要;

2)ZAP 相对于 Logrus 更为高效,体现在写 JSON 格式日志时,没有使用反射,而是用内建的 json encoder,通过明确的类型调用,直接拼接字符串,最小化性能开销。

小坑:每天写一个日志文件的功能,目前 ZAP 不支持,需要自己写代码支持,或者请求系统部支持。

五、性能表现

压测 1:

上线生产环境并和业务方对接以及压测,目前定制业务已接通整个流程,写了一个 Client。模拟定期发心跳帧,然后利用 Docker 环境。开启了 50 个容器,每个容器模拟并发起 2 万个连接。这样就是百万连接打到单机的 Server 上。单机内存占用 30G 左右。

压测 2:

同时并发 3000、4000、5000 连接,以及调整发送频率,分别对应上行:60万、80 万、100 万、200 万, 一个 6k 左右的日志结构体。

其中有一半是心跳包 另一半是日志结构体。在不同的压力下的下行延迟数据如下: 

结论:

随着上行的并发变大,延迟控制在 24-66 毫秒之间。所以对于下行业务属于轻微延迟。另外针对 60 万 5k 上行的同时,用另一个脚本模拟开启 50 个协程并发下行 1k 的数据体,延迟是比没有并发下行的时候是有所提高的,延迟提高了 40ms 左右。

六、本文小结

基于 Go 重构的 IM 服务在 WebSocket 的基础上,将业务层设计为配有消息分发模块和消息处理模块的双层架构模式,使业务逻辑的处理前置,保证了即时通讯服务的纯粹性和稳定性;同时消息分发模块的 HTTP 服务方便多种编程语言快速对接,使各业务线能迅速接入即时通讯服务。

最后,我还想为 Go 摇旗呐喊一下。很多人都知道马蜂窝技术体系主要是基于 PHP,有一些核心业务也在向 Java 迁移。与此同时,Go 也在越来越多的项目中发挥作用。现在,云原生理念已经逐渐成为主流趋势之一,我们可以看到在很多构建云原生应用所需要的核心项目中,Go 都是主要的开发语言,比如 Kubernetes,Docker,Istio,ETCD,Prometheus 等,包括第三代开源分布式数据库 TiDB。

所以我们可以把 Go 称为云原生时代的母语。「云原生时代,是开发者最好的时代」,在这股浪潮下,我们越早走进 Go,就可能越早在这个新时代抢占关键赛道。希望更多小伙伴和我们一起,加入到 Go 的开发和学习阵营中来,拓宽自己的技能图谱,拥抱云原生。

附录:更多IM架构设计方面的文章

[1] 有关IM架构设计的文章:

浅谈IM系统的架构设计

简述移动端IM开发的那些坑:架构设计、通信协议和客户端

一套海量在线用户的移动端IM架构设计实践分享(含详细图文)

一套原创分布式即时通讯(IM)系统理论架构方案

从零到卓越:京东客服即时通讯系统的技术架构演进历程

蘑菇街即时通讯/IM服务器开发之架构选择

腾讯QQ1.4亿在线用户的技术挑战和架构演进之路PPT

微信后台基于时间序的海量数据冷热分级架构设计实践

微信技术总监谈架构:微信之道——大道至简(演讲全文)

如何解读《微信技术总监谈架构:微信之道——大道至简》

快速裂变:见证微信强大后台架构从0到1的演进历程(一)

17年的实践:腾讯海量产品的技术方法论

移动端IM中大规模群消息的推送如何保证效率、实时性?

现代IM系统中聊天消息的同步和存储方案探讨

IM开发基础知识补课(二):如何设计大量图片文件的服务端存储架构?

IM开发基础知识补课(三):快速理解服务端数据库读写分离原理及实践建议

IM开发基础知识补课(四):正确理解HTTP短连接中的Cookie、Session和Token

WhatsApp技术实践分享:32人工程团队创造的技术神话

微信朋友圈千亿访问量背后的技术挑战和实践总结

王者荣耀2亿用户量的背后:产品定位、技术架构、网络方案等

IM系统的MQ消息中间件选型:Kafka还是RabbitMQ?

腾讯资深架构师干货总结:一文读懂大型分布式系统设计的方方面面

以微博类应用场景为例,总结海量社交系统的架构设计步骤

快速理解高性能HTTP服务端的负载均衡技术原理

子弹短信光鲜的背后:网易云信首席架构师分享亿级IM平台的技术实践

知乎技术分享:从单机到2000万QPS并发的Redis高性能缓存实践之路

IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列

微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

微信技术分享:微信的海量IM聊天消息序列号生成实践(容灾方案篇)

新手入门:零基础理解大型分布式架构的演进历史、技术原理、最佳实践

一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践

阿里技术分享:深度揭秘阿里数据库技术方案的10年变迁史

阿里技术分享:阿里自研金融级数据库OceanBase的艰辛成长之路

社交软件红包技术解密(一):全面解密QQ红包技术方案——架构、技术实现等

社交软件红包技术解密(二):解密微信摇一摇红包从0到1的技术演进

社交软件红包技术解密(三):微信摇一摇红包雨背后的技术细节

社交软件红包技术解密(四):微信红包系统是如何应对高并发的

社交软件红包技术解密(五):微信红包系统是如何实现高可用性的

社交软件红包技术解密(六):微信红包系统的存储层架构演进实践

社交软件红包技术解密(七):支付宝红包的海量高并发技术实践

社交软件红包技术解密(八):全面解密微博红包技术方案

社交软件红包技术解密(九):谈谈手Q红包的功能逻辑、容灾、运维、架构等

即时通讯新手入门:一文读懂什么是Nginx?它能否实现IM的负载均衡?

即时通讯新手入门:快速理解RPC技术——基本概念、原理和用途

多维度对比5款主流分布式MQ消息队列,妈妈再也不担心我的技术选型了

从游击队到正规军(一):马蜂窝旅游网的IM系统架构演进之路

从游击队到正规军(二):马蜂窝旅游网的IM客户端架构演进和实践总结

IM开发基础知识补课(六):数据库用NoSQL还是SQL?读这篇就够了!

瓜子IM智能客服系统的数据架构设计(整理自现场演讲,有配套PPT)

阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处

>> 更多同类文章 ……

[2] 更多其它架构设计相关文章:

腾讯资深架构师干货总结:一文读懂大型分布式系统设计的方方面面

快速理解高性能HTTP服务端的负载均衡技术原理

子弹短信光鲜的背后:网易云信首席架构师分享亿级IM平台的技术实践

知乎技术分享:从单机到2000万QPS并发的Redis高性能缓存实践之路

新手入门:零基础理解大型分布式架构的演进历史、技术原理、最佳实践

阿里技术分享:深度揭秘阿里数据库技术方案的10年变迁史

阿里技术分享:阿里自研金融级数据库OceanBase的艰辛成长之路

达达O2O后台架构演进实践:从0到4000高并发请求背后的努力

优秀后端架构师必会知识:史上最全MySQL大表优化方案总结

小米技术分享:解密小米抢购系统千万高并发架构的演进和实践

一篇读懂分布式架构下的负载均衡技术:分类、原理、算法、常见方案等

通俗易懂:如何设计能支撑百万并发的数据库架构?

多维度对比5款主流分布式MQ消息队列,妈妈再也不担心我的技术选型了

从新手到架构师,一篇就够:从100到1000万高并发的架构演进之路

美团技术分享:深度解密美团的分布式ID生成算法

12306抢票带来的启示:看我如何用Go实现百万QPS的秒杀系统(含源码)

>> 更多同类文章 ……

(本文同步发布于:http://www.52im.net/thread-2909-1-1.html

posted @ 2020-02-19 16:47 Jack Jiang 阅读(277) | 评论 (0)编辑 收藏

     摘要: 1、引言随着Android系统的不断升级,即时通讯网技术群和社区里的IM和推送开发的程序员们,对于进程保活这件事是越来越悲观,必竟系统对各种保活黑科技的限制越来越多了,想超越系统的挚肘,难度越来越大。但保活这件事就像“激情”之后的余味,总是让人欲罢不能,想放弃又不甘心。那么,除了像上篇《2020年了,Android后台保活还有戏吗?看我如何优雅的实现!》这样的正经白名单方式...  阅读全文

posted @ 2020-01-14 14:33 Jack Jiang 阅读(246) | 评论 (0)编辑 收藏

     摘要: 1、引言扫码登录这个功能,最早应该是微信的PC端开始搞,虽然有点反人类的功能(不扫码也没别的方式登录),但不得不说还是很酷的。下面这张图,不管是IM开发者还是普通用户,应该很熟悉: 于是,搞IM产品的老板和产品经理们,从此又多了一个要抛给程序员们的需求——“为什么微信有扫一扫登录,而我们的没有?”。好吧,每次只要是微信有的功能,IM程序员们...  阅读全文

posted @ 2020-01-08 13:39 Jack Jiang 阅读(118) | 评论 (0)编辑 收藏

     摘要: 本文由腾讯WXG应用研究员breezecheng原创发表于公众号“腾讯技术工程”,原题“微信「扫一扫识物」 的背后技术揭秘”。一、引言现在市面上主流的移动端IM应用于都有“扫一扫”功能,看起来好像也就能扫一扫加好友、加群,但实际上作为一个IM产品的重要信息入口,“扫一扫”功能也可以很强大。▲...  阅读全文

posted @ 2020-01-02 20:54 Jack Jiang 阅读(207) | 评论 (0)编辑 收藏

1、引言

对于移动端IM应用和消息推送应用的开发者来说,Android后台保活这件事是再熟悉不过了。

自从Android P(即Android 8.0)出现以后,Android已经从系统层面将后台保活这条路给堵死了(详见:《Android P正式版即将到来:后台应用保活、消息推送的真正噩梦》),曾今那些层出不穷的保活黑科技能用的也越来越少了(详见:《全面盘点当前Android后台保活方案的真实运行效果(截止2019年前)》。虽然可以自已对接厂商的ROOM级推送通道,但一方面各厂商的推送接口都不一样(而且同一厂商不同的系统版本间也存在推送接口的兼容性问题),很不方便。另一方面要一家家引入各自的推送服务SDK包会让APP变的很大,这让APP的下载变的很不友好。

总之,Android应用的后台保活在某些场景下,还是有持续的需求。除了之前那些耳熟能详的保活黑科技以外,在Android 9.0(甚至Android 10)时代,我们还有哪些保活方法可以用?那么,请跟着本文作者的思路,看看更优雅的后台保活实现方法吧。

(本文同步发布于:http://www.52im.net/thread-2881-1-1.html

 

2、关于作者

网名NanBox:毕业于华中科技大学,现为"悦跑圈APP”高级Android开发工程师。主要负责公司 Android 项目,核心模块的开发。涉及 GPS 定位、地图、图片编辑等功能。独立开发了手表应用项目。 在项目中应入了 Flutter 跨平台开发技术,实现了原生和 Flutter 的混合开发。

本文作者乐于分享,平时会写技术文章并分享在多个平台,是掘金专栏作者的一员,文章总阅读量超过 10 万。在 GitHub 上有多个开源项目,多次在团队内部进行技术分享。是 Android 和 Flutter 官方中文文档译者。

3、相关文章

如果你想详细了解目前Android平台上后台保活技术的挑战,请阅读:

Android P正式版即将到来:后台应用保活、消息推送的真正噩梦》。

如果你想回顾那些曾今出现的Android保活黑科技,以下文章值得好好读读:

全面盘点当前Android后台保活方案的真实运行效果(截止2019年前)

应用保活终极总结(一):Android6.0以下的双进程守护保活实践

应用保活终极总结(二):Android6.0及以上的保活实践(进程防杀篇)

应用保活终极总结(三):Android6.0及以上的保活实践(被杀复活篇)

Android进程保活详解:一篇文章解决你的所有疑问

Android端消息推送总结:实现原理、心跳保活、遇到的问题等

深入的聊聊Android消息推送这件小事

为何基于TCP协议的移动端IM仍然需要心跳保活机制?

微信团队原创分享:Android版微信后台保活实战分享(进程保活篇)

融云技术分享:融云安卓端IM产品的网络链路保活技术实践

4、Android保活现状

我们知道,Android 系统会存在杀后台进程的情况,并且随着系统版本的更新,杀进程的力度还有越来越大的趋势(见:《Android P正式版即将到来:后台应用保活、消息推送的真正噩梦》)。

系统这种做法本身出发点是好的,因为可以节省内存,降低功耗,也避免了一些流氓行为。

但有一部分应用,应用本身的使用场景就需要在后台运行,用户也是愿意让它在后台运行的,比如跑步类应用、一些懒得对接厂商推送通道的IM应用、消息推送资讯类应用等。

一方面流氓软件用各种流氓手段进行保活,另一方面系统加大杀后台的力度,导致我们一些真正需要在后台运行的应用被误杀,苦不堪言。

5、优雅的保活?

为了做到保活,出现了不少「黑科技」,比如 1 个像素的 Activity,播放无声音频,双进程互相守护等(可以读读这个系列:《应用保活终极总结(一):Android6.0以下的双进程守护保活实践》、《应用保活终极总结(二):Android6.0及以上的保活实践(进程防杀篇)》、《应用保活终极总结(三):Android6.0及以上的保活实践(被杀复活篇)》)。

这些做法可以说是很流氓了,甚至破坏了 Android 的生态,好在随着 Android 系统版本的更新,这些非常规的保活手段很多都已失效了。

对于那些确实需要在后台运行的应用,我们如何做到优雅的保活呢?

6、加入后台运行白名单,可以优雅的实现保活

从 Android 6.0 开始,系统为了省电增加了休眠模式,系统待机一段时间后,会杀死后台正在运行的进程。但系统会有一个后台运行白名单,白名单里的应用将不会受到影响,在原生系统下,通过:「设置」 - 「电池」 - 「电池优化」 - 「未优化应用」,可以看到这个白名单。

通常会看到下面这两位: 

下次被产品说「 XXX 都可以保活,为什么我们不行!」的时候,你就知道怎么怼回去了。大厂通过和手机厂商的合作,将自己的应用默认加入到白名单中。如果你在一个能谈成这种合作的大厂,也就不用往下看了。

好在系统还没有抛弃我们,允许我们申请把应用加入白名单。

首先,在 AndroidManifest.xml 文件中配置一下权限:

<uses-permissionandroid:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>

可以通过以下方法,判断我们的应用是否在白名单中:

@RequiresApi(api = Build.VERSION_CODES.M)

private boolean isIgnoringBatteryOptimizations() {

    boolean isIgnoring = false;

    PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);

    if(powerManager != null) {

        isIgnoring = powerManager.isIgnoringBatteryOptimizations(getPackageName());

    }

    return isIgnoring;

}

如果不在白名单中,可以通过以下代码申请加入白名单:

@RequiresApi(api = Build.VERSION_CODES.M)

public void requestIgnoreBatteryOptimizations() {

    try{

        Intent intent = newIntent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);

        intent.setData(Uri.parse("package:"+ getPackageName()));

        startActivity(intent);

    } catch(Exception e) {

        e.printStackTrace();

    }

}

申请时,应用上会出现这样一个窗口:

可以看到,这个系统弹窗会有影响电池续航的提醒,所以如果想让用户点允许,必须要有相关的说明。如果要判断用户是否点击了允许,可以在申请的时候调用 startActivityForResult,在 onActivityResult 里再判断一次是否在白名单中。

7、加入后台运行白名单的多厂商适配方法

7.1 基本说明

Android 开发的一个难点在于,各大手机厂商对原生系统进行了不同的定制,导致我们需要进行不同的适配,后台管理就是一个很好的体现。几乎各个厂商都有自己的后台管理,就算应用加入了后台运行白名单,仍然可能会被厂商自己的后台管理干掉。

如果能把应用加入厂商系统的后台管理白名单,可以进一步降低进程被杀的概率。不同的厂商在不同的地方进行设置,一般是在各自的「手机管家」,但更难的是,就算同一个厂商的系统,不同的版本也可能是在不同地方设置。

最理想的做法是,我们根据不同手机,甚至是不同的系统版本,给用户呈现一个图文操作步骤,并且提供一个按钮,直接跳转到指定页面进行设置。但需要对每个厂商每个版本进行适配,工作量是比较大的。我使用真机测试了大部分主流 Android 厂商的手机后,整理出了部分手机的相关资料。

首先我们可以定义这样两个方法:

/**

 * 跳转到指定应用的首页

 */

private void showActivity(@NonNull String packageName) {

    Intent intent = getPackageManager().getLaunchIntentForPackage(packageName);

    startActivity(intent);

}

 

/**

 * 跳转到指定应用的指定页面

 */

private void showActivity(@NonNull String packageName, @NonNull String activityDir) {

    Intent intent = new Intent();

    intent.setComponent(newComponentName(packageName, activityDir));

    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

    startActivity(intent);

}

以下是部分手机的厂商判断,跳转方法及对应设置步骤,跳转方法不保证在所有版本上都能成功跳转,都需要加 try catch。

7.2 华为

厂商判断:

public boolean isHuawei() {

    if(Build.BRAND == null) {

        return false;

    } else{

        return Build.BRAND.toLowerCase().equals("huawei") || Build.BRAND.toLowerCase().equals("honor");

    }

}

跳转华为手机管家的启动管理页:

private void goHuaweiSetting() {

    try{

        showActivity("com.huawei.systemmanager",

            "com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity");

    } catch(Exception e) {

        showActivity("com.huawei.systemmanager",

            "com.huawei.systemmanager.optimize.bootstart.BootStartActivity");

    }

}

操作步骤:应用启动管理 -> 关闭应用开关 -> 打开允许自启动

7.3 小米

厂商判断:

public static boolean isXiaomi() {

    return Build.BRAND != null&& Build.BRAND.toLowerCase().equals("xiaomi");

}

跳转小米安全中心的自启动管理页面:

private void goXiaomiSetting() {

    showActivity("com.miui.securitycenter",

        "com.miui.permcenter.autostart.AutoStartManagementActivity");

}

操作步骤:授权管理 -> 自启动管理 -> 允许应用自启动

7.4 OPPO

厂商判断:

public static boolean isOPPO() {

    return Build.BRAND != null&& Build.BRAND.toLowerCase().equals("oppo");

}

跳转 OPPO 手机管家:

private void goOPPOSetting() {

    try{

        showActivity("com.coloros.phonemanager");

    } catch(Exception e1) {

        try{

            showActivity("com.oppo.safe");

        } catch(Exception e2) {

            try{

                showActivity("com.coloros.oppoguardelf");

            } catch(Exception e3) {

                showActivity("com.coloros.safecenter");

            }

        }

    }

}

操作步骤:权限隐私 -> 自启动管理 -> 允许应用自启动

7.5 VIVO

厂商判断:

public static boolean isVIVO() {

    return Build.BRAND != null&& Build.BRAND.toLowerCase().equals("vivo");

}

跳转 VIVO 手机管家:

private void goVIVOSetting() {

    showActivity("com.iqoo.secure");

}

操作步骤:权限管理 -> 自启动 -> 允许应用自启动

7.6 魅族

厂商判断:

public static boolean isMeizu() {

    return Build.BRAND != null&& Build.BRAND.toLowerCase().equals("meizu");

}

跳转魅族手机管家:

private void goMeizuSetting() {

    showActivity("com.meizu.safe");

}

操作步骤:权限管理 -> 后台管理 -> 点击应用 -> 允许后台运行

7.7 三星

厂商判断:

public static boolean isSamsung() {

    return Build.BRAND != null&& Build.BRAND.toLowerCase().equals("samsung");

}

跳转三星智能管理器:

private void goSamsungSetting() {

    try{

        showActivity("com.samsung.android.sm_cn");

    } catch(Exception e) {

        showActivity("com.samsung.android.sm");

    }

}

操作步骤:自动运行应用程序 -> 打开应用开关 -> 电池管理 -> 未监视的应用程序 -> 添加应用

7.8 乐视

厂商判断:

public static boolean isLeTV() {

    return Build.BRAND != null&& Build.BRAND.toLowerCase().equals("letv");

}

跳转乐视手机管家:

private void goLetvSetting() {

    showActivity("com.letv.android.letvsafe",

        "com.letv.android.letvsafe.AutobootManageActivity");

}

操作步骤:自启动管理 -> 允许应用自启动

7.9 锤子

厂商判断:

public static boolean isSmartisan() {

    return Build.BRAND != null&& Build.BRAND.toLowerCase().equals("smartisan");

}

跳转手机管理:

private void goSmartisanSetting() {

    showActivity("com.smartisanos.security");

}

操作步骤:权限管理 -> 自启动权限管理 -> 点击应用 -> 允许被系统启动。

8、友商致敬?

在之前做的跑步应用中,我在设置里增加了一个权限设置页面,将上面提到的设置放在这里面。

最近发现友商某咚也跟进了,图 1 是我们做的,图 2 是某咚做的: 

某咚从设计、从我写的不够好的文案,甚至是我从十几台手机上一张一张截下来的图,进行了全方位的致敬。感谢某咚的认可,但最近在某个发布会上听到这么一句话:在致敬的同时,能不能说一句谢谢?

某咚的致敬,一方面说明了目前确实存在进程容易被杀,保活难度大的问题,另一方面也说明了这种引导用户进行白名单设置的手段是有效的。

附录:更多相关技术文章

应用保活终极总结(一):Android6.0以下的双进程守护保活实践

应用保活终极总结(二):Android6.0及以上的保活实践(进程防杀篇)

应用保活终极总结(三):Android6.0及以上的保活实践(被杀复活篇)

Android进程保活详解:一篇文章解决你的所有疑问

Android端消息推送总结:实现原理、心跳保活、遇到的问题等

深入的聊聊Android消息推送这件小事

为何基于TCP协议的移动端IM仍然需要心跳保活机制?

微信团队原创分享:Android版微信后台保活实战分享(进程保活篇)

微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)

移动端IM实践:实现Android版微信的智能心跳机制

移动端IM实践:WhatsApp、Line、微信的心跳策略分析

Android P正式版即将到来:后台应用保活、消息推送的真正噩梦

全面盘点当前Android后台保活方案的真实运行效果(截止2019年前)

一文读懂即时通讯应用中的网络心跳包机制:作用、原理、实现思路等

融云技术分享:融云安卓端IM产品的网络链路保活技术实践

正确理解IM长连接的心跳及重连机制,并动手实现(有完整IM源码)

2020年了,Android后台保活还有戏吗?看我如何优雅的实现!

>> 更多同类文章 ……

(本文同步发布于:http://www.52im.net/thread-2881-1-1.html

posted @ 2019-12-27 14:51 Jack Jiang 阅读(418) | 评论 (0)编辑 收藏

     摘要: 原作者:黄日成,手Q游戏中心后台开发,腾讯高级工程师。从事C++服务后台开发4年多,主要负责手Q游戏中心后台基础系统、复杂业务系统开发,主导过手Q游戏公会、企鹅电竞App-对战系统等项目的后台系统设计,有丰富的后台架构经验。1、引言接本系列的上一篇《P2P技术详解(二):P2P中的NAT穿越(打洞)方案详解(基本原理篇)》,本篇将深入分析各种NAT穿越(打洞)方案的技术实现原理和数据交互过程,希望...  阅读全文

posted @ 2019-12-24 11:25 Jack Jiang 阅读(289) | 评论 (0)编辑 收藏

     摘要: 1、引言岁月真是个养猪场,这几年,人胖了,微信代码也翻了。记得 14 年转岗来微信时,用自己笔记本编译微信工程才十来分钟。如今用公司配的 17 年款 27-inch iMac 编译要接近半小时;偶然间更新完代码,又莫名其妙需要全新编译。在这么低的编译效率下,开发心情受到严重影响。于是年初我向上头请示,优化微信编译效率,上头也同意了。  学习交流:- 即时通讯/推送技术开发交流5...  阅读全文

posted @ 2019-12-19 20:22 Jack Jiang 阅读(136) | 评论 (0)编辑 收藏

     摘要: 1、引言IM等社交应用的开发工作中,乱码问题也很常见,比如:1)IM聊天消息中的Emoji表情为什么发给后端后MySQL数据库里会乱码;2)文件名中带有中文的大文件聊天消息发送后,对方看到的文名是乱码;3)Http rest接口调用时,后端读取到APP端传过来的参数有中文乱码问题;... ...那么,对于乱码这个看似不起眼,但并不是一两话能讲清楚的问题,是很有必要从根源了解字符集和编码原理,知其然...  阅读全文

posted @ 2019-12-17 19:36 Jack Jiang 阅读(175) | 评论 (0)编辑 收藏

1、引言

随着互联网安全意识的普遍提高,对安全要求稍高的应用中,HTTPS的使用是很常见的,甚至在1年前,苹果公司就将使用HTTPS作为APP上架苹果应用市场的先决条件之一(详见:《苹果即将强制实施 ATS,你的APP准备好切换到HTTPS了吗?》)。

所以,无论是即时通讯IM还是其它应用,在网络安全意识增强的今天,很多场景下使用HTTPS是肯定没错的。对于即时通讯IM的开发人员来说,长连接用TLS这没疑问,短连接用HTTPS也没问题,但我想问你一个最基础的面视问题:HTTPS到底用的是对称加密还是非对称加密?

要回答这个问题,显然需要再梳理一下HTTPS的技术原理了,本文将带你了解HTTPS到底用的是对称加密还是非对称加密,以及具体又是怎么使用的。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170 [推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

(本文同步发布于:http://www.52im.net/thread-2866-1-1.html

2、相关文章

➊ 要理解HTTPS,须对HTTP协议有所了解,以下文章可能是您需要的:

网络编程懒人入门(七):深入浅出,全面理解HTTP协议

脑残式网络编程入门(三):HTTP协议必知必会的一些知识

不为人知的网络编程(八):从数据传输层深度解密HTTP

从HTTP/0.9到HTTP/2:一文读懂HTTP协议的历史演变和设计思路

WebSocket详解(四):刨根问底HTTP与WebSocket的关系(上篇)

WebSocket详解(五):刨根问底HTTP与WebSocket的关系(下篇)

可能会搞砸你的面试:你知道一个TCP连接上能发起多少个HTTP请求吗?

➋ 想更好的理解本文有关HTTPS的知识,建议一并阅以下HTTPS的基础文章:

一分钟理解 HTTPS 到底解决了什么问题

即时通讯安全篇(七):如果这样来理解HTTPS,一篇就够了

一篇读懂HTTPS:加密原理、安全逻辑、数字证书等

HTTPS时代已来,打算更新你的HTTP服务了吗?

美图App的移动端DNS优化实践:HTTPS请求耗时减小近半

➌ 本文是IM通讯安全知识系列文章中的第8篇,此系列总目录如下:

即时通讯安全篇(一):正确地理解和使用Android端加密算法

即时通讯安全篇(二):探讨组合加密算法在IM中的应用

即时通讯安全篇(三):常用加解密算法与通讯安全讲解

即时通讯安全篇(四):实例分析Android中密钥硬编码的风险

即时通讯安全篇(五):对称加密技术在Android平台上的应用实践

即时通讯安全篇(六):非对称加密技术的原理与应用实践

即时通讯安全篇(七):如果这样来理解HTTPS原理,一篇就够了

即时通讯安全篇(八):你知道,HTTPS用的是对称加密还是非对称加密?》(本文)

3、HTTPS灵魂拷问

随着 HTTPS 建站的成本下降,现在大部分的网站都已经开始用上 HTTPS 协议。大家都知道 HTTPS 比 HTTP 安全,也听说过与 HTTPS 协议相关的概念有 SSL 、非对称加密、 CA证书等。

但对于以下灵魂三拷问可能就答不上了:

  • 1)为什么用了 HTTPS 就是安全的?
  • 2)HTTPS 的底层原理如何实现?
  • 3)用了 HTTPS 就一定安全吗?

不用担心,本文将在解答“HTTPS到底用的是对称加密还是非对称加密?”的同时层层深入,从原理上把 HTTPS 的安全性讲透,您也将同时理解上述问题。

4、HTTPS 的实现原理

大家可能都听说过 HTTPS 协议之所以是安全的是因为 HTTPS 协议会对传输的数据进行加密,而加密过程是使用了非对称加密实现。但其实:HTTPS 在内容传输的加密上使用的是对称加密,非对称加密只作用在证书验证阶段。

HTTPS的整体过程分为证书验证和数据传输阶段,具体的交互过程如下: 

① 证书验证阶段:

1)浏览器发起 HTTPS 请求;

2)服务端返回 HTTPS 证书;

3)客户端验证证书是否合法,如果不合法则提示告警。

② 数据传输阶段:

1)当证书验证合法后,在本地生成随机数;

2)通过公钥加密随机数,并把加密后的随机数传输到服务端;

3)服务端通过私钥对随机数进行解密;

4)服务端通过客户端传入的随机数构造对称加密算法,对返回结果内容进行加密后传输。

5、为什么数据传输是用对称加密?

首先:非对称加密的加解密效率是非常低的,而 http 的应用场景中通常端与端之间存在大量的交互,非对称加密的效率是无法接受的。

另外:在 HTTPS 的场景中只有服务端保存了私钥,一对公私钥只能实现单向的加解密,所以 HTTPS 中内容传输加密采取的是对称加密,而不是非对称加密。

6、为什么需要 CA 认证机构颁发证书?

HTTP 协议被认为不安全是因为传输过程容易被监听者勾线监听、伪造服务器,而 HTTPS 协议主要解决的便是网络传输的安全性问题。

首先我们假设不存在认证机构,任何人都可以制作证书,这带来的安全风险便是经典的“中间人攻击”问题。

“中间人攻击”的具体过程如下: 

如上图所以,过程原理如下:

  • 1)本地请求被劫持(如DNS劫持等),所有请求均发送到中间人的服务器;
  • 2)中间人服务器返回中间人自己的证书;
  • 3)客户端创建随机数,通过中间人证书的公钥对随机数加密后传送给中间人,然后凭随机数构造对称加密对传输内容进行加密传输;
  • 4)中间人因为拥有客户端的随机数,可以通过对称加密算法进行内容解密;
  • 5)中间人以客户端的请求内容再向正规网站发起请求;
  • 6)因为中间人与服务器的通信过程是合法的,正规网站通过建立的安全通道返回加密后的数据;
  • 7)中间人凭借与正规网站建立的对称加密算法对内容进行解密;
  • 8)中间人通过与客户端建立的对称加密算法对正规内容返回的数据进行加密传输;
  • 9)客户端通过与中间人建立的对称加密算法对返回结果数据进行解密。

由于缺少对证书的验证,所以客户端虽然发起的是 HTTPS 请求,但客户端完全不知道自己的网络已被拦截,传输内容被中间人全部窃取。

7、浏览器是如何确保 CA 证书的合法性?

7.1 证书包含什么信息?

  • 1)颁发机构信息;
  • 2)公钥;
  • 3)公司信息;
  • 4)域名;
  • 5)有效期;
  • 6)指纹;
  • 7)......

7.2 证书的合法性依据是什么?

  • 1)首先:权威机构是要有认证的,不是随便一个机构都有资格颁发证书,不然也不叫做权威机构;
  • 2)另外:证书的可信性基于信任制,权威机构需要对其颁发的证书进行信用背书,只要是权威机构生成的证书,我们就认为是合法的。

所以权威机构会对申请者的信息进行审核,不同等级的权威机构对审核的要求也不一样,于是证书也分为免费的、便宜的和贵的。

7.3 浏览器如何验证证书的合法性?

浏览器发起 HTTPS 请求时,服务器会返回网站的 SSL 证书,浏览器需要对证书做以下验证:

1)验证域名、有效期等信息是否正确:证书上都有包含这些信息,比较容易完成验证;

2)判断证书来源是否合法:每份签发证书都可以根据验证链查找到对应的根证书,操作系统、浏览器会在本地存储权威机构的根证书,利用本地根证书可以对对应机构签发证书完成来源验证(如下图所示): 

3)判断证书是否被篡改:需要与 CA 服务器进行校验;

4)判断证书是否已吊销:通过CRL(Certificate Revocation List 证书注销列表)和 OCSP(Online Certificate Status Protocol 在线证书状态协议)实现,其中 OCSP 可用于第3步中以减少与 CA 服务器的交互,提高验证效率。

以上任意一步都满足的情况下浏览器才认为证书是合法的。

这里插一个我想了很久的但其实答案很简单的问题:

既然证书是公开的,如果要发起中间人攻击,我在官网上下载一份证书作为我的服务器证书,那客户端肯定会认同这个证书是合法的,如何避免这种证书冒用的情况?

其实这就是非加密对称中公私钥的用处,虽然中间人可以得到证书,但私钥是无法获取的,一份公钥是不可能推算出其对应的私钥,中间人即使拿到证书也无法伪装成合法服务端,因为无法对客户端传入的加密数据进行解密。

7.4 只有认证机构可以生成证书吗?

如果需要浏览器不提示安全风险,那只能使用认证机构签发的证书。但浏览器通常只是提示安全风险,并不限制网站不能访问,所以从技术上谁都可以生成证书,只要有证书就可以完成网站的 HTTPS 传输。

例如早期的 12306 采用的便是手动安装私有证书的形式实现 HTTPS 访问: 

8、本地随机数被窃取怎么办?

证书验证是采用非对称加密实现,但是传输过程是采用对称加密,而其中对称加密算法中重要的随机数是由本地生成并且存储于本地的,HTTPS 如何保证随机数不会被窃取?

其实 HTTPS 并不包含对随机数的安全保证,HTTPS 保证的只是传输过程安全,而随机数存储于本地,本地的安全属于另一安全范畴,应对的措施有安装杀毒软件、反木马、浏览器升级修复漏洞等。

9、用了 HTTPS 会被抓包吗?

HTTPS 的数据是加密的,常规下抓包工具代理请求后抓到的包内容是加密状态,无法直接查看。

但是,正如前文所说,浏览器只会提示安全风险,如果用户授权仍然可以继续访问网站,完成请求。因此,只要客户端是我们自己的终端,我们授权的情况下,便可以组建中间人网络,而抓包工具便是作为中间人的代理。通常 HTTPS 抓包工具的使用方法是会生成一个证书,用户需要手动把证书安装到客户端中,然后终端发起的所有请求通过该证书完成与抓包工具的交互,然后抓包工具再转发请求到服务器,最后把服务器返回的结果在控制台输出后再返回给终端,从而完成整个请求的闭环。

既然 HTTPS 不能防抓包,那 HTTPS 有什么意义?

HTTPS 可以防止用户在不知情的情况下通信链路被监听,对于主动授信的抓包操作是不提供防护的,因为这个场景用户是已经对风险知情。要防止被抓包,需要采用应用级的安全防护,例如采用私有的对称加密,同时做好移动端的防反编译加固,防止本地算法被破解。

10、本文小结

以下用简短的Q&A形式进行全文总结。

Q: HTTPS 为什么安全?

A: 因为 HTTPS 保证了传输安全,防止传输过程被监听、防止数据被窃取,可以确认网站的真实性。

Q: HTTPS 的传输过程是怎样的?

A: 客户端发起 HTTPS 请求,服务端返回证书,客户端对证书进行验证,验证通过后本地生成用于改造对称加密算法的随机数,通过证书中的公钥对随机数进行加密传输到服务端,服务端接收后通过私钥解密得到随机数,之后的数据交互通过对称加密算法进行加解密。

Q: 为什么需要证书?

A: 防止”中间人“攻击,同时可以为网站提供身份证明。

Q: 使用 HTTPS 会被抓包吗?

A: 会被抓包,HTTPS 只防止用户在不知情的情况下通信被监听,如果用户主动授信,是可以构建“中间人”网络,代理软件可以对传输内容进行解密。

好了,回归到本文标的问题,我们来总结回顾一下。

Q: HTTPS用的是对称加密还是非对称加密?

Q: HTTPS 在内容传输的加密上使用的是对称加密,非对称加密只作用在证书验证阶段。

顺手 po 一张学习的过程图(点击查看大图):

附录:更多有关IM安全的文章

传输层安全协议SSL/TLS的Java平台实现简介和Demo演示

理论联系实际:一套典型的IM通信协议设计详解(含安全层设计)

微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解

来自阿里OpenIM:打造安全可靠即时通讯服务的技术实践分享

简述实时音视频聊天中端到端加密(E2EE)的工作原理

移动端安全通信的利器——端到端加密(E2EE)技术详解

Web端即时通讯安全:跨站点WebSocket劫持漏洞详解(含示例代码)

通俗易懂:一篇掌握即时通讯的消息传输安全原理

IM开发基础知识补课(四):正确理解HTTP短连接中的Cookie、Session和Token

快速读懂量子通信、量子加密技术

即时通讯安全篇(七):如果这样来理解HTTPS原理,一篇就够了

一分钟理解 HTTPS 到底解决了什么问题

一篇读懂HTTPS:加密原理、安全逻辑、数字证书等

即时通讯安全篇(八):你知道,HTTPS用的是对称加密还是非对称加密?

>> 更多同类文章 ……

(本文同步发布于:http://www.52im.net/thread-2866-1-1.html) 

posted @ 2019-12-10 12:15 Jack Jiang 阅读(170) | 评论 (0)编辑 收藏

1、引言

在即时通讯网经常能看到各种高大上的高并发、分布式、高性能架构设计方面的文章,平时大家参加的众多开发者大会,主题也都是各种高大上的话题——什么5G啦、AI人工智能啦、什么阿里双11分分钟多少万QPS高并发等等。

但实际上,对于普通的开发者(包括IM开发人员)来说,多数公司、多数团队也都是干着默默无闻、平淡无奇的产品开发,并没有那么多高并发、高大上的事情可以做。

就拿一个IM系统来说,无论你的架构设计考虑了多少分布式、高吞吐、高可用,所有这些事情只要落地,那编码的第一件事情就是要实现几乎所有信息系统都要面对的任务——如何设计账号登录功能?

本文将分享几种典型的移动端账号登陆方式的技术原理,以及设计思路,理解后,完全可以快速实施于你的各种应用系统(并不限于IM系统)中。本文阅读对像主要为刚入门的开发人员,请程序老司机们嘴下留情哦。

 

通过本篇文章, 你可以学到:

1)主流账号登陋技术方案细节;

2)相应的表设计;

3)相应的流程设计。

通过本篇文章, 你无法学到:

与其他原理性的文章一样,本篇不涉及具体代码实现细节(对于程序员来说,只要思路搞通,代码咋写都不会太烂,大家应该都有体会)。

学习交流:

- 即时通讯/推送技术开发交流5群:215477170[推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

(本文同步发布于:http://www.52im.net/thread-2863-1-1.html

2、IM开发干货系列文章

本文是系列文章中的第20篇,总目录如下:

IM消息送达保证机制实现(一):保证在线实时消息的可靠投递

IM消息送达保证机制实现(二):保证离线消息的可靠投递

如何保证IM实时消息的“时序性”与“一致性”?

IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?

IM群聊消息如此复杂,如何保证不丢不重?

一种Android端IM智能心跳算法的设计与实现探讨(含样例代码)

移动端IM登录时拉取数据如何作到省流量?

通俗易懂:基于集群的移动端IM接入层负载均衡方案分享

浅谈移动端IM的多点登陆和消息漫游原理

IM开发基础知识补课(一):正确理解前置HTTP SSO单点登陆接口的原理

IM开发基础知识补课(二):如何设计大量图片文件的服务端存储架构?

IM开发基础知识补课(三):快速理解服务端数据库读写分离原理及实践建议

IM开发基础知识补课(四):正确理解HTTP短连接中的Cookie、Session和Token

IM群聊消息的已读回执功能该怎么实现?

IM群聊消息究竟是存1份(即扩散读)还是存多份(即扩散写)?

IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列

一个低成本确保IM消息时序的方法探讨

IM开发基础知识补课(六):数据库用NoSQL还是SQL?读这篇就够了!

IM里“附近的人”功能实现原理是什么?如何高效率地实现它?

IM开发基础知识补课(七):主流移动端账号登录方式的原理及设计思路》(本文)

3、最经典的用户名密码注册登陆方式

一个典型的用户名密码注册登陆功能类似于下面这样:

 

这种账号登陆方式很经典也很常用,先注册、再进行登录,尤其在老一点的CMS系统、网站系统、聊天应用中都能找到这个影子。

它的技术原理流程图如下:

 
 

如上图所示,详细的流程说明如下:

  • 1)前端将用户名、密码发送到服务器,服务器进行常规的判断,判断用户名、密码长度是否满足,用户名是否重复等条件,条件不通过直接返回对应错误码给到前端,这里密码字段,为了防止传输过程中被截胡,建议加密再上传,我们的传输密码默认都是会进行一个md5加密,然后记录到数据库再进行一层加密,就算是脱库也没事,密码不要明文存储。
  • 2)校验通过后,就将用户名密码写入数据库,并进行后面积分发放等操作,这里不展开。
  • 3)现在进行登录,前端将用户名,密码发送给到服务端,服务端首先会校验登录次数是否超过设置的阈值,如果超过只能继续等待被关小黑屋。
  • 4)如果未超过继续登录逻辑,判断用户名、密码是否正确,不正确密码则进行阈值的判断,如果超过则关小黑屋,记住小黑屋必须设置过期时间,要不然就会永久关上了,这个可以用redis的过期来做。
  • 5)登录成功后进行后续的一切后置逻辑,比如加积分。。。等操作。

这种经典的注册登陆方式,具体怎么设计就不在这里赘述了,谁都懂。

4、现今最主流的手机号注册登陆方式

4.1 基本原理

典型的手机号注册登陆功能类似于下图:

 

典型的手机号注册技术原理流程图如下:

 
 

如上图所示,详细的流程说明如下:

  • 1)首先输入手机号:然后发送到服务端,服务端将手机号记录在我们数据库中,然后生成随机验证码,并将手机号和验证码绑定到一个redis里面,然后记录过期时间,这个过期时间一般是10分钟左右,这就是我们一般手机验证码的有效期;
  • 2)手机接收到手机短信后:那么就在界面填写验证码发送服务端,服务端收到验证码后就会在redis里面查询到这个手机号对应的验证码,失败就返回错误码。
  • 3)成功后:就进行登录操作。

这里看起来没有明确的注册登录操作,其实在发送手机号码就可以认为是一个常规的注册,然后后面的验证码输入就是一个登陆操作。

但这种区别于常见的用户名密码注册方式,是没有密码的的。

问: 那我要密码咋办?

答: 在后续产品里面增加一个手机号码密码补录的功能即可,这也是现在很常规的手法,但是现在移动互联网大爆炸时代,密码已经显得不是那么重要了,反正我从来记不住密码,如果手机号码能操作的app,绝对不用密码来操作。

4.2 具体的数据库设计

表结构: 

说明:

这里只是单纯说明需要用到的数据,没有扩展具体场景,这个表结构能够满足上面两个方案的设计。

5、一种辅助的登陆方式:第3方账号登陆

5.1 基本原理

现在很多应用为了降低新用户的使用门槛,都会对接第3方账号进行登陆(比如:用微信号登陆、QQ号登陆、微博账号登陆等)。

这里我以QQ的开放平台登录逻辑为例进行讲解。

某团外卖的QQ账号登陆功能如下图:

 

我们先来一波时序图:

 
 

时序流程详细说明:

  • 1)客户端自己调起登录的界面,进行输入用户名、密码,这里的是第三方的用户名,密码,登录成功后,会返回access_token openid expire_in,这过程会使用到oauth2.0,不过在sdk里面进行内置回调获取了,后面我们会说明我们自身实现的oauth2.0;
  • 2)客户端拿到access_token、openid、login_type(qq、wechat...)请求应用服务器,应用服务器拿到这些数据后就会根据对应的login_type去对应的用户中心进行access_token和openid进行校验。校验不通过则返回对应错误码;
  • 3)校验通过后就会判断本地是否有这个login_type和openid是否存在,不存在则进行获取远程的用户名、头像等基础信息来作为本地基础数据,并且返回code值;
  • 4)如果已经存在,那就是进行登录操作,返回code值;
  • 5)客户端拿到code值后进行token值的换取,这个完全遵照oauth2.0的协议来走的,后续每次请求必须带上token,token值在服务端的时间比较久,因为我们想要做的是那种永不下线的操作,所以每次请求我们都将token过期时间进行累加。

想要深入了解第3方账号登陆,可以读读这两篇:《第三方登录:QQ登录接入指南》、《第三方账号登录功能接入完全流程》。

5.2 具体的数据库设计

表结构:

对于读者的建议,我这里做一下数据库的整理。

 

用户基础表(users):

 

用户验证关联表(user_auth_rel): 

 

本地用户表(user_local_auth):

 

第三方用户表(user_third_auth): 

 

表结说明:

  • 1)users表只是单纯针对我们业务侧的登录,主要是做自身业务的oauth2.0业务;
  • 2)user_local_auth是做自己用户名、密码登录,手机号码登录信息记录;
  • 3)user_third_auth是我们第三方用户体系的数据记录;
  • 4)user_auth_rel是用来关联我们users表与user_local_auth、user_third_auth;
  • 5)整个设计理念就是将自建用户与第三方在存储上区分,这在架构演进上也是合乎情理的,开始用户体系大多自建,而后才是对外接入。

6、本文小结

总的来讲,账号注册登录功能在一般的系统里都是入口功能,一般情况下都不会太复杂。

对于第三方用户的接入技术,也同样比较简单,我文章里设计多一个user_thirds是可以支持足够多的第三方接入,当然一般我们也就两三个登录就好,太多登录方不仅自身维护成本,界面摆盘也不好看不是。

希望大家能够通过以上学习,能够对于账户注册登录有一个比较好的认知,文章里设计方案不包含分表分库、没有服务化,就是简单直接的设计,当然用户量和需要的不一样,在这个基础上还要加很多东西,谢谢大家阅读。

附录:更多IM开发方面的文章

[1] IM开发综合文章:

新手入门一篇就够:从零开发移动端IM

移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”

移动端IM开发者必读(二):史上最全移动弱网络优化方法总结

从客户端的角度来谈谈移动端IM的消息可靠性和送达机制

现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障

腾讯技术分享:社交网络图片的带宽压缩技术演进之路

小白必读:闲话HTTP短连接中的Session和Token

IM开发基础知识补课:正确理解前置HTTP SSO单点登陆接口的原理

移动端IM开发需要面对的技术问题

开发IM是自己设计协议用字节流好还是字符流好?

请问有人知道语音留言聊天的主流实现方式吗?

一个低成本确保IM消息时序的方法探讨

完全自已开发的IM该如何设计“失败重试”机制?

通俗易懂:基于集群的移动端IM接入层负载均衡方案分享

微信对网络影响的技术试验及分析(论文全文)

即时通讯系统的原理、技术和应用(技术论文)

开源IM工程“蘑菇街TeamTalk”的现状:一场有始无终的开源秀

QQ音乐团队分享:Android中的图片压缩技术详解(上篇)

QQ音乐团队分享:Android中的图片压缩技术详解(下篇)

腾讯原创分享(一):如何大幅提升移动网络下手机QQ的图片传输速度和成功率

腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(上篇)

腾讯原创分享(三):如何大幅压缩移动网络下APP的流量消耗(下篇)

如约而至:微信自用的移动端IM网络层跨平台组件库Mars已正式开源

基于社交网络的Yelp是如何实现海量用户图片的无损压缩的?

腾讯技术分享:腾讯是如何大幅降低带宽和网络流量的(图片压缩篇)

腾讯技术分享:腾讯是如何大幅降低带宽和网络流量的(音视频技术篇)

字符编码那点事:快速理解ASCII、Unicode、GBK和UTF-8

全面掌握移动端主流图片格式的特点、性能、调优等

子弹短信光鲜的背后:网易云信首席架构师分享亿级IM平台的技术实践

微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

自已开发IM有那么难吗?手把手教你自撸一个Andriod版简易IM (有源码)

融云技术分享:解密融云IM产品的聊天消息ID生成策略

适合新手:从零开发一个IM服务端(基于Netty,有完整源码)

拿起键盘就是干:跟我一起徒手开发一套分布式IM系统

>> 更多同类文章 …… 

[2] 有关IM架构设计的文章:

浅谈IM系统的架构设计

简述移动端IM开发的那些坑:架构设计、通信协议和客户端

一套海量在线用户的移动端IM架构设计实践分享(含详细图文)

一套原创分布式即时通讯(IM)系统理论架构方案

从零到卓越:京东客服即时通讯系统的技术架构演进历程

蘑菇街即时通讯/IM服务器开发之架构选择

腾讯QQ1.4亿在线用户的技术挑战和架构演进之路PPT

微信后台基于时间序的海量数据冷热分级架构设计实践

微信技术总监谈架构:微信之道——大道至简(演讲全文)

如何解读《微信技术总监谈架构:微信之道——大道至简》

快速裂变:见证微信强大后台架构从0到1的演进历程(一)

17年的实践:腾讯海量产品的技术方法论

移动端IM中大规模群消息的推送如何保证效率、实时性?

现代IM系统中聊天消息的同步和存储方案探讨

IM开发基础知识补课(二):如何设计大量图片文件的服务端存储架构?

IM开发基础知识补课(三):快速理解服务端数据库读写分离原理及实践建议

IM开发基础知识补课(四):正确理解HTTP短连接中的Cookie、Session和Token

WhatsApp技术实践分享:32人工程团队创造的技术神话

微信朋友圈千亿访问量背后的技术挑战和实践总结

王者荣耀2亿用户量的背后:产品定位、技术架构、网络方案等

IM系统的MQ消息中间件选型:Kafka还是RabbitMQ?

腾讯资深架构师干货总结:一文读懂大型分布式系统设计的方方面面

以微博类应用场景为例,总结海量社交系统的架构设计步骤

快速理解高性能HTTP服务端的负载均衡技术原理

子弹短信光鲜的背后:网易云信首席架构师分享亿级IM平台的技术实践

知乎技术分享:从单机到2000万QPS并发的Redis高性能缓存实践之路

IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列

微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

微信技术分享:微信的海量IM聊天消息序列号生成实践(容灾方案篇)

新手入门:零基础理解大型分布式架构的演进历史、技术原理、最佳实践

一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践

阿里技术分享:深度揭秘阿里数据库技术方案的10年变迁史

阿里技术分享:阿里自研金融级数据库OceanBase的艰辛成长之路

社交软件红包技术解密(一):全面解密QQ红包技术方案——架构、技术实现等

社交软件红包技术解密(二):解密微信摇一摇红包从0到1的技术演进

社交软件红包技术解密(三):微信摇一摇红包雨背后的技术细节

社交软件红包技术解密(四):微信红包系统是如何应对高并发的

社交软件红包技术解密(五):微信红包系统是如何实现高可用性的

社交软件红包技术解密(六):微信红包系统的存储层架构演进实践

社交软件红包技术解密(七):支付宝红包的海量高并发技术实践

社交软件红包技术解密(八):全面解密微博红包技术方案

社交软件红包技术解密(九):谈谈手Q红包的功能逻辑、容灾、运维、架构等

即时通讯新手入门:一文读懂什么是Nginx?它能否实现IM的负载均衡?

即时通讯新手入门:快速理解RPC技术——基本概念、原理和用途

多维度对比5款主流分布式MQ消息队列,妈妈再也不担心我的技术选型了

从游击队到正规军(一):马蜂窝旅游网的IM系统架构演进之路

从游击队到正规军(二):马蜂窝旅游网的IM客户端架构演进和实践总结

IM开发基础知识补课(六):数据库用NoSQL还是SQL?读这篇就够了!

瓜子IM智能客服系统的数据架构设计(整理自现场演讲,有配套PPT)

阿里钉钉技术分享:企业级IM王者——钉钉在后端架构上的过人之处

>> 更多同类文章 ……

(本文同步发布于:http://www.52im.net/thread-2863-1-1.html

posted @ 2019-12-07 19:38 Jack Jiang 阅读(132) | 评论 (0)编辑 收藏

1、引言

整个暑假去面试,面试了很多家公司(无论是小厂还是大厂)问到的深度不同,网络原理是面试最容易问到的问题,虽然我们在项目中很少去实践它,但是了解其原理,会让我们背后网络通信是如果工作的,既能在面试官面前体现出你的基础是否扎实,也能对以后深入网络这部分学习有更多的了解。

很多同学面试在准备这部分的时候,都会去背,这部分确实很难掌握,我个人总结的最好的学习网络原理的方法就是不用刻意的去记忆而是完全的结合实际去讲整个原理融会贯通。虽然一开始学习起来很吃力,但是稍微用点心,多看几遍,多问自己为什么,把自己当做是开发网络原理的开发者,面试前的准备只要理清逻辑就足够了,而不是去背这部分内容。

而且这部分相同的知识点面试官有多种提问方式,但是其中很多都是换汤不换药。我记得最多的问的是输入URL,到页面呈现出来,其中经历了什么?这道面试题的背后,涉及到了很多网络原理的知识,我们这篇文章不会全部分享到,而是先把由来和网络层次划分弄清楚,就完成了这篇文章的目的。

(本文同步发布于:http://www.52im.net/thread-2851-1-1.html

相关文章:

网络编程懒人入门(一):快速理解网络通信协议(上篇)》(* 力荐)

网络编程懒人入门(二):快速理解网络通信协议(下篇)》(* 力荐)

网络编程懒人入门(六):史上最通俗的集线器、交换机、路由器功能原理入门

网络编程懒人入门(九):通俗讲解,有了IP地址,为何还要用MAC地址?

学习交流:

- 即时通讯/推送技术开发交流5群:215477170[推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

2、关于作者

小鹿(前端工程师):

微信公众号:小鹿动画学编程

Github地址:https://github.com/luxiangqiang

个人博客:http://luxiangqiang.com/

3、系列文章

本文是系列文章中的第7篇,本系列大纲如下:

脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手

脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

脑残式网络编程入门(三):HTTP协议必知必会的一些知识

脑残式网络编程入门(四):快速理解HTTP/2的服务器推送(Server Push)

脑残式网络编程入门(五):每天都在用的Ping命令,它到底是什么?

脑残式网络编程入门(六):什么是公网IP和内网IP?NAT转换又是什么鬼?

脑残式网络编程入门(七):面视必备,史上最通俗计算机网络分层详解》(本文)

4、为什么要进行网络层次划分?

说到网络层次划分并不陌生,我刚刚接触到网络层次的时候一脸懵逼,这么多层,一层不就行了嘛?层与层之间好多协议,还有各种数据包,第一次我放弃了。

当我从新拾起网络层次的时候,我下定决心从根上理解它。首先弄明白它的原理,那必定要知道它的由来,也就是为什么要进行网络层次划分?这个问题问的好。

假如“小鹿”是网络的开发人员,起初认为计算机与计算机之间的通信只需要一根线就可以完成通信,对没错,但是世界那么大,那么多计算机,距离又远,不但浪费线,还没出现各种线被你偷偷剪断的情况,毋庸置疑,那计算机之间通信就不行了。(后边出来了无线网,虽然其中网关、路由之间也需要连线,但不是让每台计算机两两连接,而是一个区域为单位计算机相互连接通信)

不行,老板说,“小鹿”你给我想法子改,改不出来今晚不能睡觉,“小鹿”仔细想了想,这还是个技术活,需要进行全面的改进,也发现所谓的计算机之间的连线只能传送0、1信号,另一台计算并不知道那么多0、1代表什么,而且“小鹿”又发现不同厂商的生产的计算机既然有连线实现通信也是很麻烦的,干脆定义一套规则吧,无论“某硕”计算机还是“某想”计算机,都必须遵守这套规则,其实所说的这套规则就是我们经常说的“网络协议”。

不是说网络层次的由来吗,怎么讲到网络协议了。咱们继续,通过上面的问题,那个计算机之间通过连线传送0、1信号的问题虽然规定了通信规则,但是除了像0、1这种无意义的信号之外,网络中还存在着其他各种各样的问题,两个计算机之间怎么进行识别?以及怎么才能知道对方的地址?以及不同计算机应用程序怎么知道是给自己传递的数据,还有不同的通信数据格式怎么来规定等等一系列的问题都出来了。

“小鹿”发现,如果各种问题都写成一套协议来规定双方通信的规则,但是呢?万一其中哪些规则通信中出现问题,影响到了其他规则,最常见的就是数据包,一个数据包中如果包含各种各样的协议,不就乱套了。

“小鹿”为了能够把它设计的更好,决定采用分层划分的结构,既能规定不同层的完成的功能,又能实现层与层之间的改动而不相互影响,这就是我们经常听到网络划分层次的好处。

5、网络分层是如何进行分层的?

既然我们决定要分层,那么分为几层才好呢?

起初网络分层是标准的七层,也就是我们所说的 OSI 七层模型。

 

▲ OSI参考模型或七层模型

我们所知道的还有 TCP/IP 四层模型和 TCP/IP 五层模型。这又是怎么出来的,其实所谓的 TCP/IP 四层模型和 TCP/IP 五层模型是以 OSI 七层优化而来,把某些层进行合并了,其实本质上还是相同的,但是我个人最喜欢用五层来解释。

 

▲ 五层模型

6、每一层的作用是什么?

这一部分涉及到每一层的很多协议和知识点,但是我们这一节不具体分享,为什么?我们具体深入之前必须大脑里有个具体的网络分层结构图,先要知道每层是做什么的,层与层之间的关系,然后下一节再深入每层中的每个协议怎么通信的,这样的好处学起来条理清晰,而不至于当时我学习的时候表面还不懂,就深入最后懵逼状态。

6.1 物理层

物理层,顾名思义,用物理手段将电脑连接起来,就像我们上边讲到的计算机之间的物理连线。主要用来传输0、1信号,上边也分析过了,0、1信号毕竟没有任何的现实意义,所有我们用另一层用来规定不同0、1组合的意义是什么。

6.2 数据链路层

下层的物理层既然不能规定不同0、1组合的信号代表什么意义,那么我们在数据链路层规定一套协议,专门的给0、1信号进行分组,以及规定不同的组代表什么意思,从而双方计算机都能够进行识别,这个协议就是“以太网协议”(具体的以太网协议内容下节内容详细讲解)。

但是问题又来了,我们要发送给对方计算机,怎么标识对方以及怎么知道对方的地址呢?

6.2.1)MAC 地址:

我们所说的MAC地址到底的作用是啥?说白了它就是作为网络中计算机设备的唯一标识,从计算机在厂商生产出来就被十六进制的数标识为MAC地址。

既然我们知道了用MAC地址作为标识,那么怎么才能知道我们要进行通信的计算机MAC地址呢?

6.2.2)广播:

这里广播详细的在下一节讲,这一节你只需要知道广播可以帮助我们能够知道对方的 MAC 地址。那么既然知道了MAC地址就可以通信了?没有想得那么简单,广播中还存在两种情况,一种是,在同一子网络下(同一局域网下)的计算机是通过 ARP 协议获取到对方 MAC地址的。不同自网络中(不同局域网)中是交给两个局域网的网关(路由器)去处理的。这里边涉及到很多细节的知识,都会集中到下一节,但是这一节你了解怎么进行标识计算机和怎么获取到MAC地址就可以了。

6.3 网络层

物理层和数据链路层都有自己的事情要做,也就是我们上边所讲到的这些(里边很多细节不在这节多说)。上边两层在我看来可以完成正常通信了,那么网络层出来干啥子?

网络层的由来是因为在数据链路层中我们说说两台计算机之间的通信是分为同一子网络和不同子网络之间,那么问题就来了,怎么判断两台计算机是否在同一子网络(局域网)中?这就是网络层要解决的问题。

6.3.1)IP 协议:

我们通常用到的 IP 地址,就是网络层中的东西,所规定的的协议就是 IP 协议。很多小伙伴问,IP 地址想必也是地址吧,上边都有唯一标识的 MAC 地址了,IP 地址出来是混饭吃的?为了能够让大家更方便的理解 IP 地址和 MAC 地址,我们可以将 IP 地址抽象成一种逻辑上的地址,也就是说 MAC 地址是物理上的地址,就是定死了。IP 地址呢,是动态分配的,不是固定死的。

我们就是通过 IP 地址来判断两个计算机设备是否在同一子网络中的,那么你会问它是怎么判断的,以及 IP 地址谁给他分配的?又是如何分配的等一些列问题,我们不着急,这里只说一下大体的流程,详细会后续写一大篇。

既然我们通过 IP 地址来判断两个计算机是否处于同一局域网中,那么首先要知道对方的 IP 地址吧?DNS 解析想必大家都知道,可以将域名解析为 IP 地址。好了,我们知道两台计算机的 IP 地址了,怎么进行判断是否同一局域网中?

6.3.2)子网掩码:

嘿嘿,又是一个只听说过,但是不知道这个什么作用的一个名词,没事,等我聊完,你就明白是做什么的了。

子网掩码就是用来标识同一局域网中的 IP 地址的信息的?什么信息?IP 地址是由 32 个二进制位组成的,也就是四个十进制(如:255.255.255.000)。

子网掩码也是由 32 个二进制位组成的,但是只能用 0 或 1 来表示,如:11111111.11111111.11111111.00000000。

到底什么意思呢?有 1 的部分表示网络部分,有 0 表示主机部分,这和判断两台计算机是否在同一局域网中有什么关系?没错,是有关系的!两台计算机的 IP 地址分别和子网掩码进行一种运算(AND 运算),如果结果相同,两台计算机就在同一局域网中,否则就不在同一局域网中。

AND 是如何进行运算的,IP 的数据包的组成等问题,不在这里多陈述。

6.4 传输层

好了,如果你认为计算机可以进行通信了,那么“小鹿”恭喜你,你已经基本知道了以上几层划分的作用,但是如果你正在一边打 LOL,一边和朋友在 QQ 聊天,突然,游戏中队友聊天信息出现在了 QQ 窗口中,咦?出现了什么情况?

其实是以上层级还是不够,出现上边的原因就是,两台计算机虽然可以通信了,但是每天计算机运行着好多的程序,谁知道你们传输的信息是属于哪些程序的,怨不得 LOL 的聊天信息跑到了 QQ 窗口中。

想必大家猜到了传输层主要用来干啥滴,是的,传输层的主要功能就是为了能够实现“端口到端口”的通信。计算机上运行的不同程序都会分配不同的端口,所以才能使得数据能够正确的传送给不同的应用程序。

6.4.1)UDP 协议:

加入端口号也需要一套规则,那就是 UDP 协议,但是 UDP协议有个缺点,一旦进行通信,就不知道对方是否接收到数据了,我们再定义一套规则,让其可以和对方进行确认,那么 TCP 出现了。

6.4.2)TCP 协议:

我们通常说 TCP 三次握手和四次挥手,没错,这就是传输层中完成的,TCP 三次握手涉及到的内容贼多,都可以单独写一篇长文,这里不多陈述,知道它是在传输层中完成的以及它的作用是什么,能够认识到它就好了。

6.5 应用层协议

“喂,你发给我的是什么破数据,乱七八糟的,我TM能解析吗?能不能按照我的规定给我传送?“

“好的,下次不敢了”

想必大家已经猜到了应用层的协议,应用层的功能就是规定了应用程序的数据格式。我们经常用得到的电子邮件、HTTP协议、以及FTP数据的格式,就是在应用层定义的。

7、每一层的的功能细节是什么?

前面章节主要分享了网络分层的基本概念,为什么要进行网络分层?又是如何进行分层?每一层的基本功能是什么?而且对于每一层的的功能细节方面,比如数据包的组成以及每层包含的一些协议的使用都没有细说,那么本节将继续分享网络分层每层中协议等深入讲解。(PS:可能里边有的讲解不正确,还请大佬指出改正)

7.1 物理层

物理层里边涉及到最多的是硬件底层的一些内容,没有需要过多了解的内容,我们直接看数据链路层。

7.2 数据链路层

上回讲到数据链路层中规定的“以太网协议”来规定电信号的分组形式,什么是以太网,以太网的数据包是什么样子的?

7.2.1)以太网协议:

以太网规定,每组的电信号就是一个数据包,每个数据包我们可以成为“帧”。每帧的组成是由标头(Head)和数据(Data)组成。

 

那么你会问,标头里有什么信息?Data 数据又会存放写什么?为什么分为两部分?放在一块不好吗?

a)标头:

为什么传输数据会有标头,我们想呀,在传输数据的时候,接收端怎么判断是不是给自己发送的,那么就只取出标头来进行判断。

数据包的标头中通常会存放一些有关数据包的说明、发送者是谁、接受者又是谁等相关识别信息。

标头的长度固定为 18 字节,也就是说,一些标头识别信息的大小不能超过 18 字节。

b)数据:

数据,顾名思义,你要传输给接收端什么数据都会放到数据包中,也就是整个数据包的具体内容,比如文件、字符串之类的。

数据部分的长度最小至少为 46 个字节,最长 1500 字节。我们可能会想到,如果小于 46 字节没啥问题可以存放开,那么大于 1500 字节怎么处理呢?很简单,我们就分成两个包处理(分割),两个包存放不下就分割成三个包…

7.2.2)广播:

上回说到,广播的作用就是用来查找接收端的 MAC 地址,从而进行下一步的数据传输。注意,广播只是一种发送数据的形式,而计算机想要知道另一台计算机的 MAC 地址是通过 ARP 协议解决的,ARP 协议会在讲完 IP 协议后再说,因为它会涉及到 IP 协议的一点内容,现在讲可能会有点乱。

如果你觉的上边稍微有点乱,那怎们稍微屡一下,我们想要发送数据,首先要知道对方的唯一标识(MAC 地址),要想知道对方的 MAC 地址,需要使用 ARP 协议,假设我们通过 ARP 协议拿到了接收方的 MAC 地址。

我们开始发送数据,将发送方的 MAC 地址和接收方的 MAC 地址封装在数据包中,然后发送端向同一子网络中(同一局域网)中的所有计算机发送该数据包,所有的计算机接收到该包之后,就对数据包的头部进行提取,提取出里边封装好的接收端 MAC 地址和自己的 MAC 地址作比对,如果相同,就说明该数据包是给自己发送的,否则,就会丢弃该数据包,这个过程就是广播的过程。

上一篇文章在这个地方留下的一个问题就以上是在同一局域网中,如果不在同一局域网中我们怎么处理?我们平常使用无线网都知道每个无线局域网都会有一个路由器,我们先通过以上的方法将数据发送到路由器,然后路由器转发数据到其他局域网中的计算机。

7.3 网络层

网络层中最重要的一个协议就是 IP 协议,我们一般发送端给服务端发送数据同时要知道两个地址才能准确送达到对方,分别为 IP 地址和 MAC 地址。停!stop! 上边讲到的明明知道对方的 MAC 地址就可以传输数据了,为什么现在需要两个地址呢?你给我说明白,说不明白取关!

上边确实是一个 MAC 地址就可以通信,但是前提是通过 ARP 协议获得的 MAC 地址,而 ARP 协议正是利用的接收端的 IP 地址才获取到接收端的 MAC 地址的,所以这两个地址很重要,那么如果实现的,下边会继续讲。

7.3.1)IP 协议:

IP 的数据包是直接放入到以太网数据包的“数据”部分的,这样做有一个好处就是“上层的变动完全涉及不到下层的结构”。然后数据包就变成这个样子了。

 

IP 数据包也分为标头(Head)和数据(Data)两部分:

  • 1)标头:IP 数据包的标头是 20 ~ 60 字节,主要包括版本、IP 地址等信息;
  • 2)数据:数据的最大长度为 65515 字节。整个 IP 数据包的最大总长度为 65535 字节。主要存放 IP 数据包的具体内容。

问题来了,以太网的数据部分最长为 1500 字节,你把一个长度为 65535 字节的 IP 数据包放到以太网的数据包汇总,不会被撑破吗?你在逗我么?确实是呀,那我们就分割数据包吧,分割成几个以太网数据包分开发送。

7.3.2)AND 运算:

IP 协议上篇文章中最重要的作用就是判断两个设备是否属于同一子网中(同一局域网中)。

将两个IP地址与子网掩码分别进行AND运算(两个数位都为1,运算结果为1,否则为0),然后比较结果是否相同,如果是的话,就表明它们在同一个子网络中,否则就不是。

我们可以通过 DNS 解析知道对方的 IP ,除了判断两个计算机是否在同一局域网中,还有一个作用就是然后通过 ARP 协议获取到对方的 MAC 地址。停!真想让我取关吗?ARP 就 TN 的说了多少遍了,该详细说一下了吧?

7.3.3)ARP 协议:

前提:对方的 IP 地址是已知的,通过 DNS 解析得到。

ARP 协议发出一个数据包,包含在以太网的数据包中(其中包含对方的 IP 地址,对方的 MAC 地址栏是 FF:FF:FF:FF:FF:FF)。子网络中的每台主机都会收到这个包,然后从中取出 IP 地址与自身对比,如果两者相同,都做出回复,向对方报告自己的 MAC 地址,否则就丢弃这个包。

7.4 传输层

传输层主要涉及到两个重要协议,UDP 和 TCP 协议,上篇讲过主要用来确定端口到端口的通信,计算机中不同运行的程序端口号不相同。

"端口"是 0 到 65535 之间的一个整数,正好 16 个二进制位。0 到 1023的端口被系统占用,我们只能选用大于1023 的端口。

7.4.1)UDP 协议:

UDP 协议也分为标头(Head)和数据(Data)两部分:

  • 1)标头:标头的长度为 8 字节。主要存放了发送和接收端口号;
  • 2)数据:数据部分和标头部分的总长度不超过 65535 字节,正好放进一个IP数据包。

前边也讲过,数据包之间是包含关系的,所以 UDP 的数据包是放到 IP 数据包的“数据”部分的,IP 数据包又放在以太网数据包的“数据”部分的。

 

7.4.2)TCP 协议:

TCP 和 UDP 是相同的,上一篇讲了 UDP 和 TCP 的优缺点,TCP 保证了网络的可靠性,TCP 三次握手和四次挥手就是这部分内容。

TCP 的数据包和 UDP 相同嵌入在 IP 协议的“数据”部分,TCP 并没有长度限制,但是为了保证传输效率,肯定要进行限制的,TCP 的数据包的长度一般不会超过 IP 数据包的长度了,保证单个的 TCP 数据包不再进行分割。

7.5 应用层

应用层是最高一层,直接面向用户,它的数据包会放在 TCP 的数据包的“数据”部分,那么整个五层的数据包就会变成一下这样。

 

以上五层中的内容基本讲完了,我是从下到上逐层写的,这篇文章可以让你入门网络五层协议的基本内容了。

8、写在最后

如果本文内容看完,还是有点懵,那怎么办?

可以继续以下两篇文章,它们应该可以让你内力倍增:

网络编程懒人入门(一):快速理解网络通信协议(上篇)

网络编程懒人入门(二):快速理解网络通信协议(下篇)

另外,关于计算机网络协议的分层和关系,可以看看下面两图:

 

* 上述两张图的清晰原图,请见:《计算机网络通讯协议关系图(中文珍藏版)[附件下载]》。

附录:更多网络编程基础资料

TCP/IP详解 - 第11章·UDP:用户数据报协议

TCP/IP详解 - 第17章·TCP:传输控制协议

TCP/IP详解 - 第18章·TCP连接的建立与终止

TCP/IP详解 - 第21章·TCP的超时与重传

技术往事:改变世界的TCP/IP协议(珍贵多图、手机慎点)

通俗易懂-深入理解TCP协议(上):理论基础

通俗易懂-深入理解TCP协议(下):RTT、滑动窗口、拥塞处理

理论经典:TCP协议的3次握手与4次挥手过程详解

理论联系实际:Wireshark抓包分析TCP 3次握手、4次挥手过程

计算机网络通讯协议关系图(中文珍藏版)

UDP中一个包的大小最大能多大?

P2P技术详解(一):NAT详解——详细原理、P2P简介

P2P技术详解(二):P2P中的NAT穿越(打洞)方案详解

P2P技术详解(三):P2P技术之STUN、TURN、ICE详解

通俗易懂:快速理解P2P技术中的NAT穿透原理

高性能网络编程(一):单台服务器并发TCP连接数到底可以有多少

高性能网络编程(二):上一个10年,著名的C10K并发连接问题

高性能网络编程(三):下一个10年,是时候考虑C10M并发问题了

高性能网络编程(四):从C10K到C10M高性能网络应用的理论探索

高性能网络编程(五):一文读懂高性能网络编程中的I/O模型

高性能网络编程(六):一文读懂高性能网络编程中的线程模型

Java的BIO和NIO很难懂?用代码实践给你看,再不懂我转行!

不为人知的网络编程(一):浅析TCP协议中的疑难杂症(上篇)

不为人知的网络编程(二):浅析TCP协议中的疑难杂症(下篇)

不为人知的网络编程(三):关闭TCP连接时为什么会TIME_WAIT、CLOSE_WAIT

不为人知的网络编程(四):深入研究分析TCP的异常关闭

不为人知的网络编程(五):UDP的连接性和负载均衡

不为人知的网络编程(六):深入地理解UDP协议并用好它

不为人知的网络编程(七):如何让不可靠的UDP变的可靠?

不为人知的网络编程(八):从数据传输层深度解密HTTP

不为人知的网络编程(九):理论联系实际,全方位深入理解DNS

网络编程懒人入门(一):快速理解网络通信协议(上篇)

网络编程懒人入门(二):快速理解网络通信协议(下篇)

网络编程懒人入门(三):快速理解TCP协议一篇就够

网络编程懒人入门(四):快速理解TCP和UDP的差异

网络编程懒人入门(五):快速理解为什么说UDP有时比TCP更有优势

网络编程懒人入门(六):史上最通俗的集线器、交换机、路由器功能原理入门

网络编程懒人入门(七):深入浅出,全面理解HTTP协议

网络编程懒人入门(八):手把手教你写基于TCP的Socket长连接

网络编程懒人入门(九):通俗讲解,有了IP地址,为何还要用MAC地址?

网络编程懒人入门(十):一泡尿的时间,快速读懂QUIC协议

技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解

让互联网更快:新一代QUIC协议在腾讯的技术实践分享

现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障

聊聊iOS中网络编程长连接的那些事

移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”

移动端IM开发者必读(二):史上最全移动弱网络优化方法总结

IPv6技术详解:基本概念、应用现状、技术实践(上篇)

IPv6技术详解:基本概念、应用现状、技术实践(下篇)

从HTTP/0.9到HTTP/2:一文读懂HTTP协议的历史演变和设计思路

以网游服务端的网络接入层设计为例,理解实时通信的技术挑战

迈向高阶:优秀Android程序员必知必会的网络基础

全面了解移动端DNS域名劫持等杂症:技术原理、问题根源、解决方案等

美图App的移动端DNS优化实践:HTTPS请求耗时减小近半

Android程序员必知必会的网络通信传输层协议——UDP和TCP

IM开发者的零基础通信技术入门(一):通信交换技术的百年发展史(上)

IM开发者的零基础通信技术入门(二):通信交换技术的百年发展史(下)

IM开发者的零基础通信技术入门(三):国人通信方式的百年变迁

IM开发者的零基础通信技术入门(四):手机的演进,史上最全移动终端发展史

IM开发者的零基础通信技术入门(五):1G到5G,30年移动通信技术演进史

IM开发者的零基础通信技术入门(六):移动终端的接头人——“基站”技术

IM开发者的零基础通信技术入门(七):移动终端的千里马——“电磁波”

IM开发者的零基础通信技术入门(八):零基础,史上最强“天线”原理扫盲

IM开发者的零基础通信技术入门(九):无线通信网络的中枢——“核心网”

IM开发者的零基础通信技术入门(十):零基础,史上最强5G技术扫盲

IM开发者的零基础通信技术入门(十一):为什么WiFi信号差?一文即懂!

IM开发者的零基础通信技术入门(十二):上网卡顿?网络掉线?一文即懂!

IM开发者的零基础通信技术入门(十三):为什么手机信号差?一文即懂!

IM开发者的零基础通信技术入门(十四):高铁上无线上网有多难?一文即懂!

IM开发者的零基础通信技术入门(十五):理解定位技术,一篇就够

百度APP移动端网络深度优化实践分享(一):DNS优化篇

百度APP移动端网络深度优化实践分享(二):网络连接优化篇

百度APP移动端网络深度优化实践分享(三):移动端弱网优化篇

技术大牛陈硕的分享:由浅入深,网络编程学习经验干货总结

可能会搞砸你的面试:你知道一个TCP连接上能发起多少个HTTP请求吗?

知乎技术分享:知乎千万级并发的高性能长连接网关技术实践

>> 更多同类文章 ……

(本文同步发布于:http://www.52im.net/thread-2851-1-1.html

posted @ 2019-12-01 15:59 Jack Jiang 阅读(332) | 评论 (0)编辑 收藏

     摘要: 本文引用了唐小智发表于InfoQ公众号上的“钉钉企业级IM存储架构创新之道”一文的部分内容,收录时有改动,感谢原作者的无私分享。1、引言业界的 IM 产品在功能上同质化较高,而企业级的 IM 产品对于高可用、安全性又有更高的要求,如何打造具备差异化的产品,又在高可用、安全性、数据一致性等方面具备较高的品质,是企业级 IM 产品成功的关键。钉钉在过去短短几年时间里,用户数已破...  阅读全文

posted @ 2019-11-26 15:32 Jack Jiang 阅读(140) | 评论 (0)编辑 收藏

     摘要: 本文原题“从实践角度重新理解BIO和NIO”,原文由Object分享,为了更好的内容表现力,收录时有改动。1、引言这段时间自己在看一些Java中BIO和NIO之类的东西,也看了很多博客,发现各种关于NIO的理论概念说的天花乱坠头头是道,可以说是非常的完整,但是整个看下来之后,发现自己对NIO还是一知半解、一脸蒙逼的状态(请原谅我太笨)。 基于以上原因,就有了写本文...  阅读全文

posted @ 2019-11-22 21:55 Jack Jiang 阅读(621) | 评论 (0)编辑 收藏

     摘要: 1、引言如今我们所处的时代,是移动互联网时代,也可以说是视频时代。从快播到抖音,从“三生三世”到“延禧攻略”,我们的生活,被越来越多的视频元素所影响。  而这一切,离不开视频拍摄技术的不断升级,还有视频制作产业的日益强大。 此外,也离不开通信技术的飞速进步。试想一下,如果还是当年的56K Modem拨号,或者是2G手机,...  阅读全文

posted @ 2019-11-19 11:00 Jack Jiang 阅读(598) | 评论 (0)编辑 收藏

     摘要: 本文引用了饿了么资深开发工程师万汨“Redis 到底是怎么实现“附近的人”这个功能的呢?”一文的内容,感谢原作者的分享,为了提升文章品质,即时通讯收录时有内容补充和修订。1、引言基本上以陌生人社交为主的IM产品里,都会增加“附近的人”、“附近的xxx”这种以LBS(地理位置)为导向的产品特色(微信这个熟...  阅读全文

posted @ 2019-11-12 15:04 Jack Jiang 阅读(503) | 评论 (0)编辑 收藏

1、TCP协议到底怎么了?

现时的互联网应用中,Web平台(准确地说是基于HTTP及其延伸协议的客户端/服务器应用)的数据传输都基于 TCP 协议。

但TCP 协议在创建连接之前需要进行三次握手(如下图 1,更详细原理请见《理论经典:TCP协议的3次握手与4次挥手过程详解》),如果需要提高数据交互的安全性,既增加传输层安全协议(TLS),还会增加更多的更多握手次数(如下图 2)。

 
▲ 图 1 - TCP的三次握手原理图
 
▲ 图 2  - TLS的初始化握手原理图

正如上面两张图里演示的原理,TCP 协议连接建立的成本相对较高。

所以,一般的稳定网络传输都是通过TCP,但是在网络基建本身就已经越来越完善的情况下,TCP设计本身的问题便暴露了出来,特别是在弱网环境下,让我们不得不考虑一些新的可能性。

(本文同步发布于:http://www.52im.net/thread-2816-1-1.html

2、QUIC协议登场

和 TCP 相反,UDP 协议是无连接协议。客户端发出 UDP 数据包后,只能“假设”这个数据包已经被服务端接收。这样的好处是在网络传输层无需对数据包进行确认,但存在的问题就是为了确保数据传输的可靠性,应用层协议需要自己完成包传输情况的确认。

此时,QUIC 协议就登场了。

QUIC 是 Quick UDP Internet Connections 的缩写,谷歌发明的新传输协议。

与 TCP 相比,QUIC 可以减少延迟。

QUIC 协议可以在 1 到 2 个数据包(取决于连接的服务器是新的还是已知的)内,完成连接的创建(包括 TLS)(如下图3所示)。

 

▲ 图 3  - QUIC 协议握手原理图

从表面上看:QUIC 非常类似于在 UDP 上实现的 TCP + TLS + HTTP/2。由于 TCP 是在操作系统内核和中间件固件中实现的,因此对 TCP 进行重大更改几乎是不可能的(TCP 协议栈通常由操作系统实现,如 Linux、Windows 内核或者其他移动设备操作系统。修改 TCP 协议是一项浩大的工程,因为每种设备、系统的实现都需要更新)。但是,由于 QUIC 建立在 UDP 之上,因此没有这种限制。QUIC 可以实现可靠传输,而且相比于 TCP,它的流控功能在用户空间而不在内核空间,那么使用者就不受限于 CUBIC 或是 BBR,而是可以自由选择,甚至根据应用场景自由调整优化。

QUIC 与现有 TCP + TLS + HTTP/2 方案相比,有以下几点主要特征:

1)利用缓存,显著减少连接建立时间;

2)改善拥塞控制,拥塞控制从内核空间到用户空间;

3)没有 head of line 阻塞的多路复用;

4)前向纠错,减少重传;

5)连接平滑迁移,网络状态的变更不会影响连接断线。

 

从图上可以看出,QUIC 底层通过 UDP 协议替代了 TCP,上层只需要一层用于和远程服务器交互的 HTTP/2 API。这是因为 QUIC 协议已经包含了多路复用和连接管理,HTTP API 只需要完成 HTTP 协议的解析即可。

有关QUIC的详解请见:《技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解》。

3、QUIC协议的目标

QUIC 协议的主要目的,是为了整合 TCP 协议的可靠性和 UDP 协议的速度和效率。

一张图看懂QUIC协议的优势:

 

对于 Google 来说优化 TCP 协议是一个长期目标,QUIC 旨在创建几乎等同于 TCP 的独立连接,但有着低延迟,并对类似 SPDY 的多路复用流协议有更好的支持。 如果 QUIC 协议的特性被证明是有效的,这些特性以后可能会被迁移入后续版本的 TCP 和 TLS 协议(它们都有很长的开发周期)。

值得注意的是,虽然理论上来说,如果 QUIC 的特性被证明是有效的,这些特性以后可能会被迁移到后续版本的 TCP 协议中,但鉴于TCP协议长达几十年在互联网通信里的垄断地位,以及这么多年积累下来的沉重历史报复,想要根本性地优化或改进TCP协议,难度相当大(或许,有些事情,只能是想想而已,IPV6还喊了这么多年呢,不是一样没普及。。。)。

4、QUIC协议这么好,可以大规模切换为QUIC吗?

理想和现实总是有一定的差距:虽然经过多年的推广的应用,但QUIC协议目前仍未达到大量普及的阶段,在 IETF上的QUIC 依然还是草稿,并且还存在Google QUIC与IETF QUIC两类不稳定的协定。

而且,QUIC还面临以下挑战:

1)小地方,路由封杀UDP 443端口( 这正是QUIC 部署的端口);

2)UDP包过多,由于QS限定,会被服务商误认为是攻击,UDP包被丢弃;

3)无论是路由器还是防火墙目前对QUIC都还没有做好准备。

5、QUIC协议实践

Chrome 浏览器从 2014 年开始已经实验性的支持了 QUIC 协议。可以通过在 Chrome 浏览器中输入 chrome://net-internals/#quic 查看是否已经支持 QUIC 协议。如果还未支持,可以在 chrome://flags/#enable-quic 中进行开启。

开始 Chrome 浏览器对 QUIC 协议的支持之后,可以在 chrome://net-internals/#quic 中查看到当前浏览器的 QUIC 一些连接。当然目前只有 Google 服务才支持 QUIC 协议(如 YouTube、 Google.com)。

 

Google 在 2015 年的一篇博文中分享了一些关于 QUIC 协议实现的结果,这些优势在诸如 YouTube 的视频服务上更为突出:用户报告通过 QUIC 协议在观看视频的时候可以减少 30% 的重新缓冲时间。

6、我想试试QUIC协议,可以怎么做?

目前支持 QUIC 协议的 web 服务只有 0.9 版本以后的 Caddy 。其他常用 web 服务如 nginx、apache 等都未开始支持。

整个 QUIC 协议比较复杂,想自己完全实现一套对笔者来说还比较困难。

所以先看看开源实现有哪些。

1)Chromium

这个是官方支持的。优点自然很多,Google 官方维护基本没有坑,随时可以跟随 chrome 更新到最新版本。不过编译 Chromium 比较麻烦,它有单独的一套编译工具。暂时不建议考虑这个方案。

2)proto-quic

从 chromium 剥离的一个 QUIC 协议部分,但是其 github 主页已宣布不再支持,仅作实验使用。不建议考虑这个方案。

3)goquic

goquic 封装了 libquic 的 go 语言封装,而 libquic 也是从 chromium 剥离的,好几年不维护了,仅支持到 quic-36, goquic 提供一个反向代理,测试发现由于 QUIC 版本太低,最新 chrome 浏览器已无法支持。不建议考虑这个方案。

4)quic-go

quic-go 是完全用 go 写的 QUIC 协议栈,开发很活跃,已在 Caddy 中使用,MIT 许可,目前看是比较好的方案。

那么,对于中小团队或个人开发者来说,比较推荐的方案是最后一个,即采用 caddy 来部署实现 QUIC。caddy 这个项目本意并不是专门用来实现 QUIC 的,它是用来实现一个免签的 HTTPS web 服务器的(caddy 会自动续签证书)。而QUIC 只是它的一个附属功能(不过现实是——好像用它来实现 QUIC 的人更多)。

从Github的技术趋势来说,有关QUIC的开源资源越来越多,有兴趣可以自已逐一研究研究:https://github.com/search?q=quic

7、本文小结

QUIC 协议开创性的使用了 UDP 协议作为底层传输协议,通过各种方式减少了网络延迟。

虽然目前 QUIC 协议已经运行在一些较大的网站上,但离大范围普及还有较长的一段距离,期待 QUIC 协议规范能够成为终稿,并在除了谷歌浏览器之外的其他浏览器和应用服务器中也能够实现。

8、参考资料

9、系列文章

附录:更多网络编程相关资料推荐

TCP/IP详解 - 第11章·UDP:用户数据报协议

TCP/IP详解 - 第17章·TCP:传输控制协议

TCP/IP详解 - 第18章·TCP连接的建立与终止

TCP/IP详解 - 第21章·TCP的超时与重传

技术往事:改变世界的TCP/IP协议(珍贵多图、手机慎点)

通俗易懂-深入理解TCP协议(上):理论基础

通俗易懂-深入理解TCP协议(下):RTT、滑动窗口、拥塞处理

理论经典:TCP协议的3次握手与4次挥手过程详解

理论联系实际:Wireshark抓包分析TCP 3次握手、4次挥手过程

计算机网络通讯协议关系图(中文珍藏版)

UDP中一个包的大小最大能多大?

P2P技术详解(一):NAT详解——详细原理、P2P简介

P2P技术详解(二):P2P中的NAT穿越(打洞)方案详解

P2P技术详解(三):P2P技术之STUN、TURN、ICE详解

通俗易懂:快速理解P2P技术中的NAT穿透原理

高性能网络编程(一):单台服务器并发TCP连接数到底可以有多少

高性能网络编程(二):上一个10年,著名的C10K并发连接问题

高性能网络编程(三):下一个10年,是时候考虑C10M并发问题了

高性能网络编程(四):从C10K到C10M高性能网络应用的理论探索

高性能网络编程(五):一文读懂高性能网络编程中的I/O模型

高性能网络编程(六):一文读懂高性能网络编程中的线程模型

不为人知的网络编程(一):浅析TCP协议中的疑难杂症(上篇)

不为人知的网络编程(二):浅析TCP协议中的疑难杂症(下篇)

不为人知的网络编程(三):关闭TCP连接时为什么会TIME_WAIT、CLOSE_WAIT

不为人知的网络编程(四):深入研究分析TCP的异常关闭

不为人知的网络编程(五):UDP的连接性和负载均衡

不为人知的网络编程(六):深入地理解UDP协议并用好它

不为人知的网络编程(七):如何让不可靠的UDP变的可靠?

不为人知的网络编程(八):从数据传输层深度解密HTTP

不为人知的网络编程(九):理论联系实际,全方位深入理解DNS

技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解

让互联网更快:新一代QUIC协议在腾讯的技术实践分享

现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障

聊聊iOS中网络编程长连接的那些事

移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”

移动端IM开发者必读(二):史上最全移动弱网络优化方法总结

IPv6技术详解:基本概念、应用现状、技术实践(上篇)

IPv6技术详解:基本概念、应用现状、技术实践(下篇)

从HTTP/0.9到HTTP/2:一文读懂HTTP协议的历史演变和设计思路

脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手

脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

脑残式网络编程入门(三):HTTP协议必知必会的一些知识

脑残式网络编程入门(四):快速理解HTTP/2的服务器推送(Server Push)

脑残式网络编程入门(五):每天都在用的Ping命令,它到底是什么?

脑残式网络编程入门(六):什么是公网IP和内网IP?NAT转换又是什么鬼?

以网游服务端的网络接入层设计为例,理解实时通信的技术挑战

迈向高阶:优秀Android程序员必知必会的网络基础

全面了解移动端DNS域名劫持等杂症:技术原理、问题根源、解决方案等

美图App的移动端DNS优化实践:HTTPS请求耗时减小近半

Android程序员必知必会的网络通信传输层协议——UDP和TCP

IM开发者的零基础通信技术入门(一):通信交换技术的百年发展史(上)

IM开发者的零基础通信技术入门(二):通信交换技术的百年发展史(下)

IM开发者的零基础通信技术入门(三):国人通信方式的百年变迁

IM开发者的零基础通信技术入门(四):手机的演进,史上最全移动终端发展史

IM开发者的零基础通信技术入门(五):1G到5G,30年移动通信技术演进史

IM开发者的零基础通信技术入门(六):移动终端的接头人——“基站”技术

IM开发者的零基础通信技术入门(七):移动终端的千里马——“电磁波”

IM开发者的零基础通信技术入门(八):零基础,史上最强“天线”原理扫盲

IM开发者的零基础通信技术入门(九):无线通信网络的中枢——“核心网”

IM开发者的零基础通信技术入门(十):零基础,史上最强5G技术扫盲

IM开发者的零基础通信技术入门(十一):为什么WiFi信号差?一文即懂!

IM开发者的零基础通信技术入门(十二):上网卡顿?网络掉线?一文即懂!

IM开发者的零基础通信技术入门(十三):为什么手机信号差?一文即懂!

IM开发者的零基础通信技术入门(十四):高铁上无线上网有多难?一文即懂!

IM开发者的零基础通信技术入门(十五):理解定位技术,一篇就够

百度APP移动端网络深度优化实践分享(一):DNS优化篇

百度APP移动端网络深度优化实践分享(二):网络连接优化篇

百度APP移动端网络深度优化实践分享(三):移动端弱网优化篇

技术大牛陈硕的分享:由浅入深,网络编程学习经验干货总结

可能会搞砸你的面试:你知道一个TCP连接上能发起多少个HTTP请求吗?

知乎技术分享:知乎千万级并发的高性能长连接网关技术实践

>> 更多同类文章 ……

(本文同步发布于:http://www.52im.net/thread-2816-1-1.html

posted @ 2019-11-01 14:32 Jack Jiang 阅读(1008) | 评论 (0)编辑 收藏

     摘要: 本文由ITPub根据封宇在【第十届中国系统架构师大会(SACC2018)】现场演讲内容整理而成。1、引言瓜子业务重线下,用户网上看车、预约到店、成交等许多环节都发生在线下。瓜子IM智能客服系统的目的是要把这些线下的活动搬到线上,对线下行为进行追溯,积累相关数据。系统连接用户、客服、电销、销售、AI机器人、业务后台等多个角色及应用,覆盖网上咨询、浏览、预约看车、到店体验、后服、投诉等众多环节,各个角...  阅读全文

posted @ 2019-10-25 15:29 Jack Jiang 阅读(144) | 评论 (0)编辑 收藏

     摘要: 1、引言 说道“心跳”这个词大家都不陌生,当然不是指男女之间的心跳,而是和长连接相关的。顾名思义就是证明是否还活着的依据。 什么场景下需要心跳呢?目前我们接触到的大多是一些基于长连接的应用需要心跳来“保活”。 由于在长连接的场景下,客户端和服务端并不是一直处于通信状态,如果双方长期没有沟通则双方都不清楚对方目前的状态,所以需要发送一段很小的...  阅读全文

posted @ 2019-10-22 10:48 Jack Jiang 阅读(807) | 评论 (0)编辑 收藏

     摘要: 一、引言移动互联网技术改变了旅游的世界,这个领域过去沉重的信息分销成本被大大降低。用户与服务供应商之间、用户与用户之间的沟通路径逐渐打通,沟通的场景也在不断扩展。这促使所有的移动应用开发者都要从用户视角出发,更好地满足用户需求。论坛时代的马蜂窝,用户之间的沟通形式比较单一,主要为单纯的回帖回复等。为了以较小的成本快速满足用户需求,当时采用的是非实时性消息的方案来实现用户之间的消息传递。随着行业和公...  阅读全文

posted @ 2019-10-17 23:14 Jack Jiang 阅读(131) | 评论 (0)编辑 收藏

     摘要: 1、引言老读者应该还记得我在去年国庆节前分享过一篇《技术干货:从零开始,教你设计一个百万级的消息推送系统》,虽然我在文中有贴一些伪代码,依然有些朋友希望能直接分享一些可以运行的源码。好吧,质疑我穷我无话可说(因为是真穷。。),怀疑我撸码的能力那是绝对不行,所以这次准备拉起键盘大干一场——徒手撸套分布式IM出来!^_^!本文记录了我开发的一款面向IM学习者的 IM系统R...  阅读全文

posted @ 2019-10-14 22:49 Jack Jiang 阅读(513) | 评论 (0)编辑 收藏

     摘要: 本文为开源实验性工程:“github.com/GuoZhaoran/spikeSystem”的配套文章,原作者:“绘你一世倾城”,现为:猎豹移动php开发工程师,感谢原作者的技术分享。1、引言Go语言的出现,让开发高性能、高稳定性服务端系统变的容易,与高贵冷艳的Erlang语言不同的是,Go语言简单易学,在高性能服务端架构中的应用越来越广泛。对于即时...  阅读全文

posted @ 2019-10-12 14:46 Jack Jiang 阅读(264) | 评论 (0)编辑 收藏

     摘要: 0、引言站长提示:本文适合IM新手阅读,但最好有一定的网络编程经验,必竟实践性的代码上手就是网络编程。如果你对网络编程,以及IM的一些理论知识知之甚少,请务必首先阅读:《新手入门一篇就够:从零开发移动端IM》,该文为IM小白分类整理了详尽的理论资料,请按需补充相关知识。配套源码:本文写的比较浅显但不太易懂,建议结合代码一起来读,文章配套的完整源码 请从本文文末 “11、完整源...  阅读全文

posted @ 2019-10-09 14:49 Jack Jiang 阅读(2189) | 评论 (0)编辑 收藏

     摘要: 原文来源:51CTO技术栈公众号,本文原题:NoSQL还是SQL?这一篇讲清楚,收录时有修订和改动。1、引言随着互联网大数据时代的到来,越来越多的网站、应用系统都需要支撑大量甚至海量数据存储,同时还伴有高并发、高可用、高可扩展等特性要求。很多时候,传统的关系型数据库在应付这些已经显得力不从心,并暴露了许多难以克服的问题。由此,各种各样的 NoSQL(Not Only SQL)数据库作为传统关系型数...  阅读全文

posted @ 2019-09-26 14:16 Jack Jiang 阅读(177) | 评论 (0)编辑 收藏

     摘要: 本文来自美团技术团队“照东”的分享,原题《Leaf——美团点评分布式ID生成系统》,收录时有勘误、修订并重新排版,感谢原作者的分享。1、引言鉴于IM系统中聊天消息ID生成算法和生成策略的重要性(因为某种意义上来说:聊天消息ID的优劣决定了IM应用层某些功能实现的难易度),所以即时通讯网近期正在着重整理有关IM中的聊天消息ID算法方面的文章,包括微信团...  阅读全文

posted @ 2019-09-23 16:25 Jack Jiang 阅读(190) | 评论 (0)编辑 收藏

     摘要: 本文来自融云技术团队原创分享,原文发布于“融云全球互联网通信云”公众号,原题《如何实现分布式场景下唯一 ID 生成?》,即时通讯网收录时有部分改动。1、引言对于IM应用来说,消息ID(或称序列号)是个看似不起眼,但非常重要的东西之一。消息ID的使用贯穿了IM技术逻辑的方方面面,比如:1)聊天消息的顺序保证;2)聊天消息QoS送达保证机制时的去重;3)特定聊天消息的精确查找和...  阅读全文

posted @ 2019-09-19 17:40 Jack Jiang 阅读(191) | 评论 (0)编辑 收藏

     摘要: 本文来自融云技术团队原创分享,原文发布于“ 融云全球互联网通信云”公众号,原题《IM 即时通讯之链路保活》,即时通讯网收录时有部分改动。1、引言众所周知,IM 即时通讯是一项对即时性要求非常高的技术,而保障消息即时到达的首要条件就是链路存活。那么在复杂的网络环境和国内安卓手机被深度定制化的条件下,如何保障链路存活呢?本文详解了融云安卓端IM产品在基于 TCP 协议实现链路保...  阅读全文

posted @ 2019-09-17 11:15 Jack Jiang 阅读(122) | 评论 (0)编辑 收藏

     摘要: 本文原作者:selfboot,博客地址:selfboot.cn,Github地址:github.com/selfboot,感谢原作者的技术分享。1、引言对于 DNS(Domain Name System) 大家肯定不陌生,不就是用来将一个网站的域名转换为对应的IP吗。当我们发现可以上QQ但不能浏览网页时,我们会想到可能是域名服务器挂掉了;当我们用别人提供的hosts文件浏览到一...  阅读全文

posted @ 2019-09-09 15:41 Jack Jiang 阅读(146) | 评论 (0)编辑 收藏

本文来自知乎官方技术团队的“知乎技术专栏”,感谢原作者faceair的无私分享。

1、引言

实时的响应总是让人兴奋的,就如你在微信里看到对方正在输入,如你在王者峡谷里一呼百应,如你们在直播弹幕里不约而同的 666,它们的背后都离不开长连接技术的加持。

每个互联网公司里几乎都有一套长连接系统,它们被应用在消息提醒、即时通讯、推送、直播弹幕、游戏、共享定位、股票行情等等场景。而当公司发展到一定规模,业务场景变得更复杂后,更有可能是多个业务都需要同时使用长连接系统。

业务间分开设计长连接会导致研发和维护成本陡增、浪费基础设施、增加客户端耗电、无法复用已有经验等等问题。共享长连接系统又需要协调好不同系统间的认证、鉴权、数据隔离、协议拓展、消息送达保证等等需求,迭代过程中协议需要向前兼容,同时因为不同业务的长连接汇聚到一个系统导致容量管理的难度也会增大。

经过了一年多的开发和演进,经过我们服务面向内和外的数个 App、接入十几个需求和形态各异的长连接业务、数百万设备同时在线、突发大规模消息发送等等场景的锤炼,我们提炼出一个长连接系统网关的通用解决方案,解决了多业务共用长连接时遇到的种种问题。

知乎长连接网关致力于业务数据解耦、消息高效分发、解决容量问题,同时提供一定程度的消息可靠性保证。

(本文同步发布于:http://www.52im.net/thread-2737-1-1.html

2、相关文章

3、我们怎么设计通讯协议?

3.1 业务解耦

支撑多业务的长连接网关实际上是同时对接多客户端和多业务后端的,是多对多的关系,他们之间只使用一条长连接通讯。

 

这种多对多的系统在设计时要避免强耦合。业务方逻辑也是会动态调整的,如果将业务的协议和逻辑与网关实现耦合会导致所有的业务都会互相牵连,协议升级和维护都会异常困难。

所以我们尝试使用经典的发布订阅模型来解耦长连接网关跟客户端与业务后端,它们之间只需要约定 Topic 即可自由互相发布订阅消息。传输的消息是纯二进制数据,网关也无需关心业务方的具体协议规范和序列化方式。



3.2 权限控制

我们使用发布订阅解耦了网关与业务方的实现,我们仍然需要控制客户端对 Topic 的发布订阅的权限,避免有意或无意的数据污染或越权访问。

假如讲师正在知乎 Live 的 165218 频道开讲,当客户端进入房间尝试订阅 165218 频道的 Topic 时就需要知乎 Live 的后端判断当前用户是否已经付费。这种情况下的权限实际上是很灵活的,当用户付费以后就能订阅,否则就不能订阅。权限的状态只有知乎 Live 业务后端知晓,网关无法独立作出判断。

所以我们在 ACL 规则中设计了基于回调的鉴权机制,可以配置 Live 相关 Topic 的订阅和发布动作都通过 HTTP 回调给 Live 的后端服务判断。



同时根据我们对内部业务的观察,大部分场景下业务需要的只是一个当前用户的私有 Topic 用来接收服务端下发的通知或消息,这种情况下如果让业务都设计回调接口来判断权限会很繁琐。

所以我们在 ACL 规则中设计了 Topic 模板变量来降低业务方的接入成本,我们给业务方配置允许订阅的 Topic 中包含连接的用户名变量标识,表示只允许用户订阅或发送消息到自己的 Topic。



此时网关可以在不跟业务方通信的情况下,独立快速判断客户端是否有权限订阅或往 Topic 发送消息。

3.3 消息可靠性保证


网关作为消息传输的枢纽,同时对接业务后端和客户端,在转发消息时需要保证消息在传输过程的可靠性。

TCP 只能保证了传输过程中的顺序和可靠性,但遇到 TCP 状态异常、客户端接收逻辑异常或发生了 Crash 等等情况时,传输中的消息就会发生丢失。

为了保证下发或上行的消息被对端正常处理,我们实现了回执和重传的功能。重要业务的消息在客户端收到并正确处理后需要发送回执,而网关内暂时保存客户端未收取的消息,网关会判断客户端的接收情况并尝试再次发送,直到正确收到了客户端的消息回执。



而面对服务端业务的大流量场景,服务端发给网关的每条消息都发送回执的方式效率较低,我们也提供了基于消息队列的接收和发送方式,后面介绍发布订阅实现时再详细阐述。

在设计通讯协议时我们参考了 MQTT 规范(详见《扫盲贴:认识MQTT通信协议》),拓展了认证和鉴权设计,完成了业务消息的隔离与解耦,保证了一定程度的传输可靠性。同时保持了与 MQTT 协议一定程度上兼容,这样便于我们直接使用 MQTT 的各端客户端实现,降低业务方接入成本。

4、我们怎么设计系统架构?

在设计项目整体架构时,我们优先考虑的是:

  • 1)可靠性;
  • 2)水平扩展能力;
  • 3)依赖组件成熟度;
  • 4)简单才值得信赖。


为了保证可靠性,我们没有考虑像传统长连接系统那样将内部数据存储、计算、消息路由等等组件全部集中到一个大的分布式系统中维护,这样增大系统实现和维护的复杂度。我们尝试将这几部分的组件独立出来,将存储、消息路由交给专业的系统完成,让每个组件的功能尽量单一且清晰。

同时我们也需要快速地水平扩展能力。互联网场景下各种营销活动都可能导致连接数陡增,同时发布订阅模型系统中下发消息数会随着 Topic 的订阅者的个数线性增长,此时网关暂存的客户端未接收消息的存储压力也倍增。将各个组件拆开后减少了进程内部状态,我们就可以将服务部署到容器中,利用容器来完成快速而且几乎无限制的水平扩展。

最终设计的系统架构如下图:
 

系统主要由四个主要组件组成:

  • 1)接入层使用 OpenResty 实现,负责连接负载均衡和会话保持;
  • 2)长连接 Broker,部署在容器中,负责协议解析、认证与鉴权、会话、发布订阅等逻辑;
  • 3)Redis 存储,持久化会话数据;
  • 4)Kafka 消息队列,分发消息给 Broker 或业务方。


其中 Kafka 和 Redis 都是业界广泛使用的基础组件,它们在知乎都已平台化和容器化 (详见:《Redis at Zhihu》、《知乎基于 Kubernetes 的 Kafka 平台的设计和实现》),它们也都能完成分钟级快速扩容。

5、我们如何构建长连接网关?

5.1 接入层

OpenResty 是业界使用非常广泛的支持 Lua 的 Nginx 拓展方案,灵活性、稳定性和性能都非常优异,我们在接入层的方案选型上也考虑使用 OpenResty。

接入层是最靠近用户的一侧,在这一层需要完成两件事:

  • 1)负载均衡,保证各长连接 Broker 实例上连接数相对均衡;
  • 2)会话保持,单个客户端每次连接到同一个 Broker,用来提供消息传输可靠性保证。


负载均衡其实有很多算法都能完成,不管是随机还是各种 Hash 算法都能比较好地实现,麻烦一些的是会话保持。

常见的四层负载均衡策略是根据连接来源 IP 进行一致性 Hash,在节点数不变的情况下这样能保证每次都 Hash 到同一个 Broker 中,甚至在节点数稍微改变时也能大概率找到之前连接的节点。

之前我们也使用过来源 IP Hash 的策略,主要有两个缺点:

  • 1)分布不够均匀,部分来源 IP 是大型局域网 NAT 出口,上面的连接数多,导致 Broker 上连接数不均衡;
  • 2)不能准确标识客户端,当移动客户端掉线切换网络就可能无法连接回刚才的 Broker 了。


所以我们考虑七层的负载均衡,根据客户端的唯一标识来进行一致性 Hash,这样随机性更好,同时也能保证在网络切换后也能正确路由。常规的方法是需要完整解析通讯协议,然后按协议的包进行转发,这样实现的成本很高,而且增加了协议解析出错的风险。

最后我们选择利用 Nginx 的 preread 机制实现七层负载均衡,对后面长连接 Broker 的实现的侵入性小,而且接入层的资源开销也小。

Nginx 在接受连接时可以指定预读取连接的数据到 preread buffer 中,我们通过解析 preread buffer 中的客户端发送的第一个报文提取客户端标识,再使用这个客户端标识进行一致性 Hash 就拿到了固定的 Broker。

5.2 发布与订阅

我们引入了业界广泛使用的消息队列 Kafka 来作为内部消息传输的枢纽。

前面提到了一些这么使用的原因:

  • 1)减少长连接 Broker 内部状态,让 Broker 可以无压力扩容;
  • 2)知乎内部已平台化,支持水平扩展。


还有一些原因是:

  • 1)使用消息队列削峰,避免突发性的上行或下行消息压垮系统;
  • 2)业务系统中大量使用 Kafka 传输数据,降低与业务方对接成本。


其中利用消息队列削峰好理解,下面我们看一下怎么利用 Kafka 与业务方更好地完成对接。

5.3 发布

连接 Broker 会根据路由配置将消息发布到 Kafka Topic,同时也会根据订阅配置去消费 Kafka 将消息下发给订阅客户端。

路由规则和订阅规则是分别配置的,那么可能会出现四种情况。

情况一:消息路由到 Kafka Topic,但不消费,适合数据上报的场景,如下图所示。



情况二:消息路由到 Kafka Topic,也被消费,普通的即时通讯场景,如下图所示。



情况三:直接从 Kafka Topic 消费并下发,用于纯下发消息的场景,如下图所示。



情况四:消息路由到一个 Topic,然后从另一个 Topic 消费,用于消息需要过滤或者预处理的场景,如下图所示。



这套路由策略的设计灵活性非常高,可以解决几乎所有的场景的消息路由需求。同时因为发布订阅基于 Kafka,可以保证在处理大规模数据时的消息可靠性。

5.4 订阅

当长连接 Broker 从 Kafka Topic 中消费出消息后会查找本地的订阅关系,然后将消息分发到客户端会话。

我们最开始直接使用 HashMap 存储客户端的订阅关系。当客户端订阅一个 Topic 时我们就将客户端的会话对象放入以 Topic 为 Key 的订阅 Map 中,当反查消息的订阅关系时直接用 Topic 从 Map 上取值就行。

因为这个订阅关系是共享对象,当订阅和取消订阅发生时就会有连接尝试操作这个共享对象。为了避免并发写我们给 HashMap 加了锁,但这个全局锁的冲突非常严重,严重影响性能。

最终我们通过分片细化了锁的粒度,分散了锁的冲突。

本地同时创建数百个 HashMap,当需要在某个 Key 上存取数据前通过 Hash 和取模找到其中一个 HashMap 然后进行操作,这样将全局锁分散到了数百个 HashMap 中,大大降低了操作冲突,也提升了整体的性能。

5.5 会话持久化

当消息被分发给会话 Session 对象后,由 Session 来控制消息的下发。

Session 会判断消息是否是重要 Topic 消息, 是的话将消息标记 QoS 等级为 1,同时将消息存储到 Redis 的未接收消息队列,并将消息下发给客户端。等到客户端对消息的 ACK 后,再将未确认队列中的消息删除。

有一些业界方案是在内存中维护了一个列表,在扩容或缩容时这部分数据没法跟着迁移。也有部分业界方案是在长连接集群中维护了一个分布式内存存储,这样实现起来复杂度也会变高。

我们将未确认消息队列放到了外部持久化存储中,保证了单个 Broker 宕机后,客户端重新上线连接到其他 Broker 也能恢复 Session 数据,减少了扩容和缩容的负担。

5.6 滑动窗口

在发送消息时,每条 QoS 1 的消息需要被经过传输、客户端处理、回传 ACK 才能确认下发完成,路径耗时较长。如果消息量较大,每条消息都等待这么长的确认才能下发下一条,下发通道带宽不能被充分利用。

为了保证发送的效率,我们参考 TCP 的滑动窗口设计了并行发送的机制(详见:《通俗易懂-深入理解TCP协议(下):RTT、滑动窗口、拥塞处理》)。我们设置一定的阈值为发送的滑动窗口,表示通道上可以同时有这么多条消息正在传输和被等待确认。



我们应用层设计的滑动窗口跟 TCP 的滑动窗口实际上还有些差异。

TCP 的滑动窗口内的 IP 报文无法保证顺序到达,而我们的通讯是基于 TCP 的所以我们的滑动窗口内的业务消息是顺序的,只有在连接状态异常、客户端逻辑异常等情况下才可能导致部分窗口内的消息乱序。

因为 TCP 协议保证了消息的接收顺序,所以正常的发送过程中不需要针对单条消息进行重试,只有在客户端重新连接后才对窗口内的未确认消息重新发送。消息的接收端同时会保留窗口大小的缓冲区用来消息去重,保证业务方接收到的消息不会重复。

我们基于 TCP 构建的滑动窗口保证了消息的顺序性同时也极大提升传输的吞吐量。

6、写在最后

知乎长连接网关由基础架构组 (Infra) 开发和维护,主要贡献者是@faceair@安江泽 。

基础架构组负责知乎的流量入口和内部基础设施建设,对外我们奋斗在直面海量流量的的第一战线,对内我们为所有的业务提供坚如磐石的基础设施,用户的每一次访问、每一个请求、内网的每一次调用都与我们的系统息息相关。

附录:更多网络编程相关资料

[1] 网络编程基础资料:
TCP/IP详解 - 第11章·UDP:用户数据报协议
TCP/IP详解 - 第17章·TCP:传输控制协议
TCP/IP详解 - 第18章·TCP连接的建立与终止
TCP/IP详解 - 第21章·TCP的超时与重传
技术往事:改变世界的TCP/IP协议(珍贵多图、手机慎点)
通俗易懂-深入理解TCP协议(上):理论基础
通俗易懂-深入理解TCP协议(下):RTT、滑动窗口、拥塞处理
理论经典:TCP协议的3次握手与4次挥手过程详解
理论联系实际:Wireshark抓包分析TCP 3次握手、4次挥手过程
计算机网络通讯协议关系图(中文珍藏版)
UDP中一个包的大小最大能多大?
P2P技术详解(一):NAT详解——详细原理、P2P简介
P2P技术详解(二):P2P中的NAT穿越(打洞)方案详解
P2P技术详解(三):P2P技术之STUN、TURN、ICE详解
通俗易懂:快速理解P2P技术中的NAT穿透原理
高性能网络编程(一):单台服务器并发TCP连接数到底可以有多少
高性能网络编程(二):上一个10年,著名的C10K并发连接问题
高性能网络编程(三):下一个10年,是时候考虑C10M并发问题了
高性能网络编程(四):从C10K到C10M高性能网络应用的理论探索
高性能网络编程(五):一文读懂高性能网络编程中的I/O模型
高性能网络编程(六):一文读懂高性能网络编程中的线程模型
不为人知的网络编程(一):浅析TCP协议中的疑难杂症(上篇)
不为人知的网络编程(二):浅析TCP协议中的疑难杂症(下篇)
不为人知的网络编程(三):关闭TCP连接时为什么会TIME_WAIT、CLOSE_WAIT
不为人知的网络编程(四):深入研究分析TCP的异常关闭
不为人知的网络编程(五):UDP的连接性和负载均衡
不为人知的网络编程(六):深入地理解UDP协议并用好它
不为人知的网络编程(七):如何让不可靠的UDP变的可靠?
不为人知的网络编程(八):从数据传输层深度解密HTTP
网络编程懒人入门(一):快速理解网络通信协议(上篇)
网络编程懒人入门(二):快速理解网络通信协议(下篇)
网络编程懒人入门(三):快速理解TCP协议一篇就够
网络编程懒人入门(四):快速理解TCP和UDP的差异
网络编程懒人入门(五):快速理解为什么说UDP有时比TCP更有优势
网络编程懒人入门(六):史上最通俗的集线器、交换机、路由器功能原理入门
网络编程懒人入门(七):深入浅出,全面理解HTTP协议
网络编程懒人入门(八):手把手教你写基于TCP的Socket长连接
网络编程懒人入门(九):通俗讲解,有了IP地址,为何还要用MAC地址?
技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解
让互联网更快:新一代QUIC协议在腾讯的技术实践分享
现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障
聊聊iOS中网络编程长连接的那些事
移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”
移动端IM开发者必读(二):史上最全移动弱网络优化方法总结
IPv6技术详解:基本概念、应用现状、技术实践(上篇)
IPv6技术详解:基本概念、应用现状、技术实践(下篇)
从HTTP/0.9到HTTP/2:一文读懂HTTP协议的历史演变和设计思路
脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手
脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?
脑残式网络编程入门(三):HTTP协议必知必会的一些知识
脑残式网络编程入门(四):快速理解HTTP/2的服务器推送(Server Push)
脑残式网络编程入门(五):每天都在用的Ping命令,它到底是什么?
脑残式网络编程入门(六):什么是公网IP和内网IP?NAT转换又是什么鬼?
以网游服务端的网络接入层设计为例,理解实时通信的技术挑战
迈向高阶:优秀Android程序员必知必会的网络基础
全面了解移动端DNS域名劫持等杂症:技术原理、问题根源、解决方案等
美图App的移动端DNS优化实践:HTTPS请求耗时减小近半
Android程序员必知必会的网络通信传输层协议——UDP和TCP
IM开发者的零基础通信技术入门(一):通信交换技术的百年发展史(上)
IM开发者的零基础通信技术入门(二):通信交换技术的百年发展史(下)
IM开发者的零基础通信技术入门(三):国人通信方式的百年变迁
IM开发者的零基础通信技术入门(四):手机的演进,史上最全移动终端发展史
IM开发者的零基础通信技术入门(五):1G到5G,30年移动通信技术演进史
IM开发者的零基础通信技术入门(六):移动终端的接头人——“基站”技术
IM开发者的零基础通信技术入门(七):移动终端的千里马——“电磁波”
IM开发者的零基础通信技术入门(八):零基础,史上最强“天线”原理扫盲
IM开发者的零基础通信技术入门(九):无线通信网络的中枢——“核心网”
IM开发者的零基础通信技术入门(十):零基础,史上最强5G技术扫盲
IM开发者的零基础通信技术入门(十一):为什么WiFi信号差?一文即懂!
IM开发者的零基础通信技术入门(十二):上网卡顿?网络掉线?一文即懂!
IM开发者的零基础通信技术入门(十三):为什么手机信号差?一文即懂!
IM开发者的零基础通信技术入门(十四):高铁上无线上网有多难?一文即懂!
IM开发者的零基础通信技术入门(十五):理解定位技术,一篇就够
百度APP移动端网络深度优化实践分享(一):DNS优化篇
百度APP移动端网络深度优化实践分享(二):网络连接优化篇
百度APP移动端网络深度优化实践分享(三):移动端弱网优化篇
技术大牛陈硕的分享:由浅入深,网络编程学习经验干货总结
可能会搞砸你的面试:你知道一个TCP连接上能发起多少个HTTP请求吗?
知乎技术分享:知乎千万级并发的高性能长连接网关技术实践
>> 更多同类文章 ……

[2] NIO异步网络编程资料:
Java新一代网络编程模型AIO原理及Linux系统AIO介绍
有关“为何选择Netty”的11个疑问及解答
开源NIO框架八卦——到底是先有MINA还是先有Netty?
选Netty还是Mina:深入研究与对比(一)
选Netty还是Mina:深入研究与对比(二)
NIO框架入门(一):服务端基于Netty4的UDP双向通信Demo演示
NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示
NIO框架入门(三):iOS与MINA2、Netty4的跨平台UDP双向通信实战
NIO框架入门(四):Android与MINA2、Netty4的跨平台UDP双向通信实战
Netty 4.x学习(一):ByteBuf详解
Netty 4.x学习(二):Channel和Pipeline详解
Netty 4.x学习(三):线程模型详解
Apache Mina框架高级篇(一):IoFilter详解
Apache Mina框架高级篇(二):IoHandler详解
MINA2 线程原理总结(含简单测试实例)
Apache MINA2.0 开发指南(中文版)[附件下载]
MINA、Netty的源代码(在线阅读版)已整理发布
解决MINA数据传输中TCP的粘包、缺包问题(有源码)
解决Mina中多个同类型Filter实例共存的问题
实践总结:Netty3.x升级Netty4.x遇到的那些坑(线程篇)
实践总结:Netty3.x VS Netty4.x的线程模型
详解Netty的安全性:原理介绍、代码演示(上篇)
详解Netty的安全性:原理介绍、代码演示(下篇)
详解Netty的优雅退出机制和原理
NIO框架详解:Netty的高性能之道
Twitter:如何使用Netty 4来减少JVM的GC开销(译文)
绝对干货:基于Netty实现海量接入的推送服务技术要点
Netty干货分享:京东京麦的生产级TCP网关技术实践总结
新手入门:目前为止最透彻的的Netty高性能原理和框架架构解析
写给初学者:Java高性能NIO框架Netty的学习方法和进阶策略
少啰嗦!一分钟带你读懂Java的NIO和经典IO的区别
史上最强Java NIO入门:担心从入门到放弃的,请读这篇!
手把手教你用Netty实现网络通信程序的心跳机制、断线重连机制
>> 更多同类文章 …

(本文同步发布于:http://www.52im.net/thread-2737-1-1.html

posted @ 2019-09-05 12:04 Jack Jiang 阅读(203) | 评论 (0)编辑 收藏

     摘要: 本文原作者: Wizey,作者博客:http://wenshixin.gitee.io,即时通讯网收录时有改动,感谢原作者的无私分享。1、引言典型的Web端即时通讯技术应用场景,主要有以下两种形式:1)作为完整的即时通讯产品进行应用:比如独立的Web端IM产品;2)作为某个更大系统中的一部分进行应用:比如客服系统(相当于工单系统里嵌入IM技术啦)。对于第一种场景,为了更好的划分功能逻辑,一个完整的...  阅读全文

posted @ 2019-09-02 15:40 Jack Jiang 阅读(279) | 评论 (0)编辑 收藏

     摘要: 本文原文由作者“司徒正美”发布于公众号“前端你别闹”,即时通讯网收录时有改动,感谢原作者的分享。1、引言1990 年,第一个Web浏览器的诞生;1991 年,WWW诞生,这标志着前端技术的开始。在这将近20年的前端发展史中,我们经历了从最早的纯静态页面,到JavaScript跨时代的诞生;从PC端到移动端;从依赖后端到前端可自由打包开发;从早期的网景...  阅读全文

posted @ 2019-08-22 18:05 Jack Jiang 阅读(155) | 评论 (0)编辑 收藏

本文来自网易云信团队的技术分享,原创发表于网易云信公众号,原文链接:mp.weixin.qq.com/s/LT2dASI7QVpcOVxDAsMeVg,收录时有改动。

1、引言

在不了解IM技术的人眼里,群聊是再平常不过的功能而已,万人群聊?应该也不难实现吧?!

确实,从前端功能界面上来看,群聊无非就是个循环向群员发送消息的一对多聊天消息分发模式而已,难在何处?

真实的情况是,群聊是IM系统中的高难度技术点之一。难在哪?难在服务端!从某种角度上说,群聊功能的架构设计和技术实现的品质,可以代表这款IM软件的技术水平。

群聊从后台的技术实现上说,至少有以下难点:

1)如何高效地进行大量群员消息的分发?

2)如何高效地管理群员的在线状态?

3)如何高效地读取群员的在线状态?

4)集群系统中,如何高效地保证群员消息的准确送达?

5)群聊消息该扩散写还是扩散读?

6)如何保证大量群聊消息分发的情况下不影响单聊消息体验?

7)如何应对大群突发事件下的性能负载?

.... ....

目前,市面上主流的IM产品中,微信群是500人上限,QQ群是3000人上限(3000人群是按年付费升级,很贵,不是为一般用户准备的)。一方面,从产品的定义上群成员数量不应过多,另一方面,技术成本也是个不可回避的因素。万人群这种超大规模群的技术难度,更是难已想象。

本文内容是网易云信团队为了响应万人群聊功能需求,在设计实现万人群聊技术方案中总结的技术实践,借此机会分享给各IM开发者同行。

(本文同步发布于:http://www.52im.net/thread-2707-1-1.html

学习交流:

- 即时通讯/推送技术开发交流5群:215477170[推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM

2、概述

随着移动互联网的发展,即时通讯服务被广泛应用到各个行业,客户业务快速发展,传统百人或千人上限的群聊已经无法满足很多业务发展需求,因此网易云信IM推出万人群服务。

万人群场景需要解决以下问题:

1)消息需要按1:9999的比例进行转发投递,按常规消息处理流程将产生大量的子任务,对系统吞吐量的要求极高;

2)在微服务系统架构下,如果不采用一些优化方案,服务以及存储(DB、缓存等)之间的QPS和网络流量将非常高;

3)以群为单位的缓存(如群成员列表)内存存储开销较大(假设一个成员200Byte,万人群约2MB);

4)群成员登录后需要同步群离线消息,智能手机上App前后台切换产生的较多登录同步消息协议,因此需要优化消息同步方案。

为了解决以上问题,万人群技术方案采用了“聚合+分层/组+增量”的设计思路:

3、万人群消息的处理流程

1)按群维护在线群成员信息,主要包含两部分(可以理解为两个缓存集合):

a. 群成员在线信息:即用户在线状态变化(上线、下线)时,更新相应群的在线状态信息(即动态维护群有哪些成员在线);

b. 成员IM长连接信息:即用户新登录时,更新用户的Link信息(即登录所在Link的地址信息,消息转发时根据Link地址路由消息)。

2)IM Server收到群消息后,按群ID将消息路由到“群消息服务”模块;

3)群消息模块检查并预处理消息内容,然后通过“群成员在线状态”服务获取在线成员,完成消息转发的基础工作。为了减少群消息模块和群在线成员服务之间的网络流量,采用了“本地缓存+增量同步”的缓存策略,即本地缓存记录最后更新版本号和时间戳,每次同步群在线成员前先检查缓存版本号是否有变更,若有则按最后更新时间增量同步;

4)通过“群成员在线服务”获取在线群成员的Link链接信息,按Link分组路由消息(分组路由的原因:同一Link上的全部群成员只需要路由一条消息即可)。同样为了减少网络开销,成员Link信息也采用“本地缓存+增量同步”的方案;

5)群消息采用“漫游+历史”的存储方案,漫游的消息存储在分布式缓存中,历史消息异步写入HBase。用户登录后可以通过漫游快速的获取到最新消息,并可以通过拉取历史查看更早的消息。

4、万人群方案本地缓存增量同步策略

抛开群在线状态管理逻辑,群成员在线状态服务可以简单理解为分布式集中缓存。

增量同步技术方案如下:

如上图所示:

1)数据缓存是一个集合,其包含了多个缓存数据项,每一个数据项带有最后更新时间信息;另外缓存还有一个严格递增的版本号;

2)缓存数据变更(新增、修改、删除)后,需要增加版本号;

3)本地线程通过缓存管理读取数据时,管理服务先检查本地版本号和分布式缓存中的版本号是否一致,若不一致则按本地最新时间戳增量同步新数据项,并更新本地的版本号和最后更新时间(为了避免分布式集中缓存中并发写入导致的增量时间戳不可靠问题,增量更新时可以将本地记录的最后更新时间戳向前推移,比如减少20ms);

4)为避免本地多线程并发读取相同数据项导致并发更新本地缓存的问题,可以按缓存数据合并更新请求,即解决并发问题还可以减少网络开销;

5)缓存数据由大量数据项构成,为了避免单个缓存数据太大,可以将数据项中的属性业务场景精简(冷热分离),低频次读写的属性额外缓存。

5、万人群水平扩容方案

万人群采用大量本地缓存的方案解决消息处理性能和网络流量的问题,因此本地存储空间成了方案的瓶颈点。因此我们设计了分组路由的技术方案。

消息按群ID和路由策略定向路由到指定分组(集群)上处理,分组由多个计算节点组成,因此方案上可以做到分组内和分组间的水平扩缩容。

6、作为“云”服务,网易云信是如何实现万人群所需的计算资源的?

由于万人群对计算和存储资源消耗比较高,在实施和运维方案上也有一定的特殊性,为了保证业务的可靠性和稳定性,网易云信是将万人大群的能力,仅提供给专属的云客户(普通公有云客户是无法使用的)。

之所以能从软硬件基础设施上为万人群提供保障,网易云信的IM专有云必须具备以下资源能力:

1)需要专属的独立计算资源:保持计算资源独立,且资源冗余度比公有云高,且需要保证不会受到公有云上其他客户业务的影响;

2)需要专属的独立运维服务:从而根据客户业务场景制定最佳的业务监控、弹性扩容、故障迁移等运维方案。

总之,万人群聊的实现,过硬的技术方案设计和技术实现只是一方面,基础计算设施资源和运维能力也是不可或缺。

所以,从今以后,不要随随便便就喊万人群聊,甚至十万人群聊,这不是想实现就能实现的哦!

附录:更多群聊相关技术文章

快速裂变:见证微信强大后台架构从0到1的演进历程(一)
如何保证IM实时消息的“时序性”与“一致性”?
IM单聊和群聊中的在线状态同步应该用“推”还是“拉”?
IM群聊消息如此复杂,如何保证不丢不重?
微信后台团队:微信后台异步消息队列的优化升级实践分享
移动端IM中大规模群消息的推送如何保证效率、实时性?
现代IM系统中聊天消息的同步和存储方案探讨
关于IM即时通讯群聊消息的乱序问题讨论
IM群聊消息的已读回执功能该怎么实现?
IM群聊消息究竟是存1份(即扩散读)还是存多份(即扩散写)?
一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践
[技术脑洞] 如果把14亿中国人拉到一个微信群里技术上能实现吗?
IM群聊机制,除了循环去发消息还有什么方式?如何优化?
网易云信技术分享:IM中的万人群聊技术方案实践总结
>> 更多同类文章 ……

(本文同步发布于:http://www.52im.net/thread-2707-1-1.html

posted @ 2019-08-14 10:07 Jack Jiang 阅读(144) | 评论 (0)编辑 收藏

     摘要: 本文原文由作者“张小方”原创发布于“高性能服务器开发”微信公众号,原题《心跳包机制设计详解》,即时通讯网收录时有改动。1、引言一般来说,没有真正动手做过网络通信应用的开发者,很难想象即时通讯应用中的心跳机制的作用。但不可否认,作为即时通讯应用,心跳机制是其网络通信技术底层中非常重要的一环,有没有心跳机制、心跳机制的算法实现好坏,都将直接影响即时通讯应...  阅读全文

posted @ 2019-08-08 12:01 Jack Jiang 阅读(247) | 评论 (0)编辑 收藏

     摘要: 本文由原作者松若章原创发布,作者主页:zhihu.com/people/hrsonion/posts,感谢原作者的无私分享。1、引言一道经典的面试题是:从 URL 在浏览器被被输入到页面展现的过程中发生了什么?大多数回答都是说请求响应之后 DOM 怎么被构建,被绘制出来。但是你有没有想过,收到的 HTML 如果包含几十个图片标签,这些图片是以什么方式、什么顺序、建立了多少连接、使用什么协议被下载下...  阅读全文

posted @ 2019-08-02 09:55 Jack Jiang 阅读(196) | 评论 (0)编辑 收藏

     摘要: 本文由百度技术团队“蔡锐”原创发表于“百度App技术”公众号,原题为《百度App网络深度优化系列《三》弱网优化》,感谢原作者的无私分享。一、前言网络优化解决的核心问题有三个,第一是安全问题,我们在《百度APP移动端网络深度优化实践分享(一):DNS优化篇》进行了详细的讲解。第二是速度问题,我们在《百度APP移动端网络深度优化实践分享(二):网络连接优...  阅读全文

posted @ 2019-07-29 10:29 Jack Jiang 阅读(145) | 评论 (0)编辑 收藏

     摘要: 本文引用自马蜂窝公众号,由马蜂窝技术团队原创分享。一、引言今天,越来越多的用户被马蜂窝持续积累的笔记、攻略、嗡嗡等优质的分享内容所吸引,在这里激发了去旅行的热情,同时也拉动了马蜂窝交易的增长。在帮助用户做出旅行决策、完成交易的过程中,IM 系统起到了重要的作用。IM 系统为用户与商家建立了直接沟通的渠道,帮助用户解答购买旅行产品中的问题,既促成了订单交易,也帮用户打消了疑虑,促成用户旅行愿望的实现...  阅读全文

posted @ 2019-07-24 21:44 Jack Jiang 阅读(141) | 评论 (0)编辑 收藏

     摘要: 本文由作者FreddyChen原创分享,为了更好的体现文章价值,引用时有少许改动,感谢原作者。1、写在前面一直想写一篇关于im即时通讯分享的文章,无奈工作太忙,很难抽出时间。今天终于从公司离职了,打算好好休息几天再重新找工作,趁时间空闲,决定静下心来写一篇文章,毕竟从前辈那里学到了很多东西。工作了五年半,这三四年来一直在做社交相关的项目,有直播、即时通讯、短视频分享、社区论坛等产品,深知即时通讯技...  阅读全文

posted @ 2019-07-22 12:48 Jack Jiang 阅读(439) | 评论 (0)编辑 收藏

     摘要: 1、引言本文以设计淘宝网的后台架构为例,介绍从一百个并发到千万级并发情况下服务端的架构的14次演进过程,同时列举出每个演进阶段会遇到的相关技术,让大家对架构的演进有一个整体的认知。文章最后汇总了一些架构设计的原则。(本文同步发布于:http://www.52im.net/thread-2665-1-1.html)2、关于作者huashiou:广东工业大学计算机科学与技术硕士毕业,大数据开发工程师。...  阅读全文

posted @ 2019-07-17 23:57 Jack Jiang 阅读(356) | 评论 (0)编辑 收藏

     摘要: 本文由DCloud 公司创始人王安原创发布于CSDN,原题《小程序技术演进史》,即时通讯网收录时有改动,感谢原作者。1、引言微信的成功,并非特定于某个具体的功能,微信的成功实际上是一大批创新技术和体验的成功合集,这也是它为何如此难此被超越的根本原因。作为微信这个超级社交应用中最为亮眼的技术之一——微信小程序,俨然已成历移动端小程序的代名词,很多人一提起“小程序&...  阅读全文

posted @ 2019-07-04 12:02 Jack Jiang 阅读(160) | 评论 (0)编辑 收藏

     摘要: 本文原题“《NIO 入门》,作者为“Gregory M. Travis”,他是《JDK 1.4 Tutorial》等书籍的作者。1、引言Java NIO是Java 1.4版加入的新特性,虽然Java技术日新月异,但历经10年,NIO依然为Java技术领域里最为重要的基础技术栈,而且依据现实的应用趋势,在可以预见的未来,它仍将继续在Java技术领域占据重要位置。网...  阅读全文

posted @ 2019-06-29 22:17 Jack Jiang 阅读(732) | 评论 (0)编辑 收藏

1、引言

很多初涉网络编程的程序员,在研究Java NIO(即异步IO)和经典IO(也就是常说的阻塞式IO)的API时,很快就会发现一个问题:我什么时候应该使用经典IO,什么时候应该使用NIO?

在本文中,将尝试用简明扼要的文字,阐明Java NIO和经典IO之间的差异、典型用例,以及这些差异如何影响我们的网络编程或数据传输代码的设计和实现的。

本文没有复杂理论,也没有像网上基它文章一样千篇一律的复制粘贴,有的只是接地气的通俗易懂,希望能给你带来帮助。

(本文同步发布于:http://www.52im.net/thread-2635-1-1.html

2、相关文章

3、Java NIO和IO的主要区别

下表总结了Java NIO和IO之间的主要区别。我将在表格后面的部分中详细介绍每个区别。

3.1 Stream Oriented vs. Buffer Oriented

Java NIO和IO之间的第一个重要区别是IO是面向流的,其中NIO是面向缓冲区的。那么,这意味着什么?

面向流的Java IO意味着您可以从流中一次读取一个或多个字节。你对读取的字节做什么取决于你。它们不会缓存在任何地方。此外,您无法在流中的数据中前后移动。如果需要在从流中读取的数据中前后移动,则需要先将其缓存在缓冲区中。

Java NIO的面向缓冲区的方法略有不同。数据被读入缓冲区,稍后处理该缓冲区。你可以根据需要在缓冲区中前后移动。这使你在处理过程中具有更大的灵活性。但是,你还需要检查缓冲区是否包含完整处理所需的所有数据。并且,你需要确保在将更多数据读入缓冲区时,不要覆盖尚未处理的缓冲区中的数据。

3.2 Blocking vs. Non-blocking IO

Java IO的各种流都是blocking的。这意味着,当线程调用read()或write()时,该线程将被阻塞,直到有一些数据要读取,或者数据被完全写入,在此期间,该线程无法执行任何其他操作。

Java NIO的非阻塞模式允许线程请求从通道读取数据,并且只获取当前可用的内容,或者根本没有数据,如果当前没有数据可用。线程可以继续使用其他内容,而不是在数据可供读取之前保持阻塞状态。

非阻塞写入也是如此,线程可以请求将某些数据写入通道,但不要等待它完全写入。然后线程可以继续并在同一时间做其他事情。

线程在IO调用中没有阻塞时花费空闲时间,通常在此期间在其他通道上执行IO。也就是说,单个线程现在可以管理多个输入和输出通道。

4、Selectors

Java NIO的选择器允许单个线程监视多个输入通道。你可以使用选择器注册多个通道,然后使用单个线程“选择”具有可用于处理的输入的通道,或者选择准备写入的通道。这种选择器机制使单个线程可以轻松管理多个通道。

5、NIO和经典IO如何影响应用程序的设计?

选择NIO或IO作为IO工具包可能会影响应用程序设计的以下方面:

1)API调用NIO或IO类;

2)处理数据;

3)用于处理数据的线程数。

5.1 API调用

当然,使用NIO时的API调用看起来与使用IO时不同。这并不奇怪。而不是仅仅从例如InputStream读取字节的数据字节,必须首先将数据读入缓冲区,然后从那里进行处理。

5.2 数据处理

使用纯NIO设计与IO设计时,数据处理也会受到影响。

在IO设计中,您从InputStream或Reader中读取字节的数据字节。想象一下,您正在处理基于行的文本数据流。

例如:

Name: Anna

Age: 25

Email: [url=mailto:anna@mailserver.com]anna@mailserver.com[/url]

Phone: 1234567890

这个文本行流可以像这样处理:

InputStream input = ... ; // get the InputStream from the client socket


BufferedReader reader = newBufferedReader(newInputStreamReader(input));


String nameLine   = reader.readLine();

String ageLine    = reader.readLine();

String emailLine  = reader.readLine();

String phoneLine  = reader.readLine();

注意处理状态是如何,由程序执行的程度决定的。换句话说,一旦第一个reader.readLine()方法返回,您就确定已经读取了整行文本。readLine()会阻塞直到读取整行,这就是原因。您还知道此行包含名称。同样,当第二个readLine()调用返回时,您知道此行包含年龄等。

正如您所看到的,只有当有新数据要读取时,程序才会进行,并且对于每个步骤,您都知道该数据是什么。一旦执行的线程已经超过读取代码中的某个数据片段,该线程就不会在数据中向后移动(通常不会)。

此图中还说明了此原则:

▲ Java IO:从阻塞流中读取数据

NIO的实现看起来会有所不同,这是一个简化的例子:

ByteBuffer buffer = ByteBuffer.allocate(48);

intbytesRead = inChannel.read(buffer);

注意第二行从通道读取字节到ByteBuffer。当该方法调用返回时,您不知道所需的所有数据是否都在缓冲区内。你只知道缓冲区包含一些字节,这使得处理更加困难。

想象一下,在第一次读取(缓冲)调用之后,是否所有读入缓冲区的内容都是半行。例如,“姓名:An”。你能处理这些数据吗?并不是的。在完成任何数据的处理之前,您需要等待至少一整行数据进入缓冲区。

那么你怎么知道缓冲区是否包含足够的数据来处理它?好吧,你没有。找出的唯一方法是查看缓冲区中的数据。结果是,在您知道所有数据是否存在之前,您可能需要多次检查缓冲区中的数据。这既低效又可能在程序设计方面变得混乱。

例如:

ByteBuffer buffer = ByteBuffer.allocate(48);

intbytesRead = inChannel.read(buffer);

while(! bufferFull(bytesRead) ) {

    bytesRead = inChannel.read(buffer);

}

bufferFull()方法必须跟踪读入缓冲区的数据量,并返回true或false,具体取决于缓冲区是否已满。换句话说,如果缓冲区已准备好进行处理,则认为它已满。

bufferFull()方法扫描缓冲区,但必须使缓冲区保持与调用bufferFull()方法之前相同的状态。如果不是,则可能无法在正确的位置读入读入缓冲区的下一个数据。这不是不可能的,但这是另一个需要注意的问题。

如果缓冲区已满,则可以对其进行处理。如果它不满,您可能能够部分处理那里的任何数据,如果这在您的特定情况下是有意义的。在许多情况下,它没有。

这个图中说明了is-data-in-buffer-ready循环:

▲ Java NIO:从通道读取数据,直到所有需要的数据都在缓冲区中

6、什么时候该用NIO?什么时候该用经典IO?

NIO允许您仅使用一个(或几个)线程来管理多个通道(网络连接或文件),但成本是解析数据可能比从阻塞流中读取数据时更复杂。

如果您需要同时管理数千个打开的连接,每个只发送一些数据,例如聊天服务器,在NIO中实现服务器可能是一个优势。同样,如果您需要与其他计算机保持大量开放连接,例如在P2P网络中,使用单个线程来管理所有出站连接可能是一个优势。

此图中说明了这一个线程,多个连接设计:

▲ Java NIO:管理多个连接的单个线程

如果您拥有较少带宽的连接,一次发送大量数据,那么可能最经典的IO服务器实现可能是最合适的。

此图说明了经典的IO服务器设计:

▲ Java IO:经典的IO服务器设计 - 由一个线程处理的一个连接

7、更简化的理解

以众所周之的数据读取过程为例,我们来一个更简化的理解。

对于数据读取,就读取速度来说:CPU > 内存 > 硬盘。

I- 就是从硬盘到内存

O- 就是从内存到硬盘

第一种方式:从硬盘读取数据,然后程序一直等,数据读完后,继续你的操作。这种方式是最简单的,叫阻塞IO(也就是经典IO)。

第二种方式:从硬盘读取数据,然后程序继续向下执行,等数据读取完后,通知当前程序读取完成(对硬件来说叫中断,对程序来说叫回调),然后此程序可以立即处理读取的数据,也可以执行完当前操作后再对读取完的数据进行操作。

8、总而言之

还是以数据读取为例,操作系统是按块Block(块)从硬盘拿数据,就如同一个大脸盆,一下子就放入了一盆水。但是,当 Java 使用的时候,旧的 IO(经典IO)确实基于 流 Stream的,也就是虽然操作系统给我了一脸盆水,但是我得用吸管慢慢喝。

由于经典IO的重重落后理念,于是,NIO 横空出世。。。

附录:更多NIO异步网络编程资料

Java新一代网络编程模型AIO原理及Linux系统AIO介绍
有关“为何选择Netty”的11个疑问及解答
开源NIO框架八卦——到底是先有MINA还是先有Netty?
选Netty还是Mina:深入研究与对比(一)
选Netty还是Mina:深入研究与对比(二)
NIO框架入门(一):服务端基于Netty4的UDP双向通信Demo演示
NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示
NIO框架入门(三):iOS与MINA2、Netty4的跨平台UDP双向通信实战
NIO框架入门(四):Android与MINA2、Netty4的跨平台UDP双向通信实战
Netty 4.x学习(一):ByteBuf详解
Netty 4.x学习(二):Channel和Pipeline详解
Netty 4.x学习(三):线程模型详解
Apache Mina框架高级篇(一):IoFilter详解
Apache Mina框架高级篇(二):IoHandler详解
MINA2 线程原理总结(含简单测试实例)
Apache MINA2.0 开发指南(中文版)[附件下载]
MINA、Netty的源代码(在线阅读版)已整理发布
解决MINA数据传输中TCP的粘包、缺包问题(有源码)
解决Mina中多个同类型Filter实例共存的问题
实践总结:Netty3.x升级Netty4.x遇到的那些坑(线程篇)
实践总结:Netty3.x VS Netty4.x的线程模型
详解Netty的安全性:原理介绍、代码演示(上篇)
详解Netty的安全性:原理介绍、代码演示(下篇)
详解Netty的优雅退出机制和原理
NIO框架详解:Netty的高性能之道
Twitter:如何使用Netty 4来减少JVM的GC开销(译文)
绝对干货:基于Netty实现海量接入的推送服务技术要点
Netty干货分享:京东京麦的生产级TCP网关技术实践总结
新手入门:目前为止最透彻的的Netty高性能原理和框架架构解析
写给初学者:Java高性能NIO框架Netty的学习方法和进阶策略
少啰嗦!一分钟带你读懂Java的NIO和经典IO的区别
>> 更多同类文章 ……

(本文同步发布于:http://www.52im.net/thread-2635-1-1.html

posted @ 2019-06-25 16:32 Jack Jiang 阅读(553) | 评论 (0)编辑 收藏

     摘要: 1、引言对于即时通讯网来说,所有的技术文章和资料都在围绕即时通讯这个技术方向进行整理和分享,这一次也不例外。对于即时通讯系统(包括IM、消息推送系统等)来说,MQ消息中件间是非常常见的基础软件,但市面上种类众多、各有所长的MQ消息中件间产品,该怎么去选择?这是个问题!对于很多经验不足的开发者来说,一个公司内部用的IM聊天系统,总用户量也不过百十来人,动辄就是Kafka、MongoDB,美其名曰为了...  阅读全文

posted @ 2019-06-21 15:01 Jack Jiang 阅读(226) | 评论 (0)编辑 收藏

     摘要: 本文引用了作者“ ConardLi”的《用JS开发跨平台桌面应用,从原理到实践》一文部分内容,原文链接:segmentfault.com/a/1190000019426512,感谢原作者的无私分享。1、引言现在开发IM应用动不动就要求多端——即Android端、iOS端、PC端、Web端等,Android端和iOS端作为两种不同的移动端技术,单独开发...  阅读全文

posted @ 2019-06-14 11:11 Jack Jiang 阅读(160) | 评论 (0)编辑 收藏

     摘要: 本文引用了“蔷薇Nina”的“Nginx 相关介绍(Nginx是什么?能干嘛?)”一文部分内容,感谢作者的无私分享。1、引言Nginx(及其衍生产品)是目前被大量使用的服务端反向代理和负载均衡方案,从某种意义上来讲,Nginx几乎是低成本、高负载Web服务端代名词。如此深入人心的Nginx,很多人也想当然的认为,在IM或消息推送等场景下是否也能使用N...  阅读全文

posted @ 2019-06-07 21:33 Jack Jiang 阅读(151) | 评论 (0)编辑 收藏

     摘要: 1、引言相信看到这个标题,很多人的第一反应就是:对数据库进行分库分表啊!但是实际上,数据库层面的分库分表到底是用来干什么的,其不同的作用如何应对不同的场景,我觉得很多同学可能都没搞清楚。本篇文章我们一起来学习一下,对于一个支撑日活百万用户的高并发系统,数据库架构应该如何设计呢?本文的讨论和分享,将用一个创业公司的发展作为背景引入,方便大家理解。(本文同步发布于:http://www.52im.ne...  阅读全文

posted @ 2019-05-15 14:39 Jack Jiang 阅读(297) | 评论 (0)编辑 收藏

     摘要: 【来源申明】本文原文来自:微信公众号“鲜枣课堂”,官方网站:xzclass.com,原题为:《中国通信的百年沉浮》,本文引用时已征得原作者同意。为了更好的内容呈现,即时通讯网在收录时内容有稍许调整,转载时请注明原文来源信息,请尊重原作者的劳动。1、系列文章引言1.1 适合谁来阅读?本系列文章尽量使用最浅显易懂的文字、图片来组织内容,力求通信技术零基础的人群也能看懂。但个人建...  阅读全文

posted @ 2019-05-05 15:40 Jack Jiang 阅读(194) | 评论 (0)编辑 收藏

     摘要: 1、引言关于“负载均衡”的解释,百度词条里:负载均衡,英文叫Load Balance,意思就是将请求或者数据分摊到多个操作单元上进行执行,共同完成工作任务。负载均衡(Load Balance)建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。负载均衡有两方面的含义:1)首先,大量的并...  阅读全文

posted @ 2019-04-29 14:39 Jack Jiang 阅读(180) | 评论 (0)编辑 收藏

     摘要: 一、引言WebSocket是一种比较新的协议,它是伴随着html5规范而生的,虽然还比较年轻,但大多主流浏览器都已经支持。它使用方面、应用广泛,已经渗透到前后端开发的各种场景中。对http一问一答中二式流程(就是从所周之的“长轮询”技要啦)的不满,催生了支持双向通信的WebSocket诞生。WebSocket是个不太干净协议。本文将从8个常见的疑问入手,为还不了解WebSo...  阅读全文

posted @ 2019-04-25 14:27 Jack Jiang 阅读(179) | 评论 (0)编辑 收藏

     摘要: 本文由百度技术团队“蔡锐”原创发表于“百度App技术”公众号,原题为《百度App网络深度优化系列《二》连接优化》,感谢原作者的无私分享。一、前言在《百度APP移动端网络深度优化实践分享(一):DNS优化篇》里大家了解到网络优化一般会首选优化DNS,而接下来的HTTP协议成为优化的重点,一般优化者会选择协议切换,合并请求,精简数据包大小等手段来对HTT...  阅读全文

posted @ 2019-04-24 16:25 Jack Jiang 阅读(144) | 评论 (0)编辑 收藏

     摘要: 本文由百度技术团队“蔡锐”原创发表于“百度App技术”公众号,原题为《百度App网络深度优化系列《一》DNS优化》,感谢原作者的无私分享。一、前言网络优化是客户端几大技术方向中公认的一个深度领域,所以百度App给大家带来网络深度优化系列文章。本系列文章目录如下:《百度APP移动端网络深度优化实践分享(一):DNS优化篇》(* 本文)《百度APP移动端...  阅读全文

posted @ 2019-04-22 13:51 Jack Jiang 阅读(159) | 评论 (0)编辑 收藏

     摘要: 1、引言我,Scott,一家创业公司的 CTO。从业6年却很少写文章,近一年来接触了几十个刚毕业的前端新人,也面试了100多个前端工程师和Nodejs工程师,对于前端发展的这个职业算是有些感触吧,打算陆续写一些从业经验也好,技术分享也好,对自己前6年的经历做一些文字上的沉淀。此篇文章谨献给工作0 ~ 3年的前端工程师,内容都是我的亲身经历,不精彩但接地气。(本文同步发布于:http://www.5...  阅读全文

posted @ 2019-04-15 11:45 Jack Jiang 阅读(197) | 评论 (0)编辑 收藏

     摘要: 1、引言在文章《理论联系实际:Wireshark抓包分析TCP 3次握手、4次挥手过程》中,我们学会了用wireshark来分析TCP的“三次握手,四次挥手”,非常好用。这就是传说中的锤子,拿着 锤子,看什么都像 钉子!在这本文中,我对将准 HTTP这颗钉子,狠狠地砸下去。。。为了对网络数据包的“流转”有更加深刻的理解,我在docker(远程)上部署...  阅读全文

posted @ 2019-04-13 11:27 Jack Jiang 阅读(162) | 评论 (0)编辑 收藏

Jack Jiang的 Mail: jb2011@163.com, 联系QQ: 413980957, 微信: hellojackjiang