Jack Jiang

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

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 阅读(113) | 评论 (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 阅读(103) | 评论 (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 阅读(92) | 评论 (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 阅读(106) | 评论 (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 阅读(82) | 评论 (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 阅读(137) | 评论 (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 阅读(94) | 评论 (0)编辑 收藏

     摘要: 本文由vivo技术团队Yang Kun分享,原题“electron 应用开发优秀实践”,即时通讯网有修订。1、引言在上篇《Electron初体验(快速开始、跨进程通信、打包、踩坑等)》的分享中,我们已经对Electron跨端框架的开发有了大概的了解。本篇将基于vivo技术团队的技术实践,详细阐述了vivo在使用Electron进行跨端桌面开发时的技术栈选型考量,同时分享了在...  阅读全文

posted @ 2022-10-08 10:16 Jack Jiang 阅读(149) | 评论 (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 阅读(106) | 评论 (0)编辑 收藏

     摘要: 本文由蘑菇街前端技术团队分享,原题“Electron 从零到一”,有修订和改动。1、引言在上篇《快速了解新一代跨平台桌面技术——Electron》,我们已经对Electron跨端框架有了基本的认识。本篇将带你简单上手Electron框架开发跨平台桌面端,内容包括一个快速开始例子、跨进程通信原理、打包和分发、以及一些典型的技术踩坑等。希望能带给你启发。...  阅读全文

posted @ 2022-09-22 11:10 Jack Jiang 阅读(184) | 评论 (0)编辑 收藏

仅列出标题
共49页: First 上一页 15 16 17 18 19 20 21 22 23 下一页 Last 
Jack Jiang的 Mail: jb2011@163.com, 联系QQ: 413980957, 微信: hellojackjiang