Jack Jiang

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

2021年2月2日

     摘要: 本文作者芋艿,原题“使用 Netty 实现 IM 聊天贼简单”,本底价有修订和改动。一、本文引言上篇《跟着源码学IM(七):手把手教你用WebSocket打造Web端IM聊天》中,我们使用 WebSocket 实现了一个简单的 IM 功能,支持身份认证、私聊消息、群聊消息。然后就有人发私信,希望使用纯 Netty 实现一个类似的功能,因此就有了本文。注:源码请从同步链接附件...  阅读全文

posted @ 2021-04-12 15:43 Jack Jiang 阅读(73) | 评论 (0)编辑 收藏

     摘要: 本文作者芋艿,原题“芋道 Spring Boot WebSocket 入门”,本次有修订和改动。一、引言WebSocket如今在Web端即时通讯技术应用里使用广泛,不仅用于传统PC端的网页里,也被很多移动端开发者用于基于HTML5的混合APP里。对于想要在基于Web的应用里添加IM、推送等实时通信功能,WebSocket几乎是必须要掌握的技术。本文将基于Tomcat和Spr...  阅读全文

posted @ 2021-04-06 22:05 Jack Jiang 阅读(79) | 评论 (0)编辑 收藏

     摘要: 本文原作者Chank,原题“如何设计一个亿级消息量的 IM 系统”,为了提升内容质量,本次有修订和改动。1、写有前面本文将在亿级消息量、分布式IM系统这个技术前提下,分析和总结实现这套系统所需要掌握的知识点,内容没有高深的技术概念,尽量做到新手老手皆能读懂。本文不会给出一套通用的IM方案,也不会评判某种架构的好坏,而是讨论设计IM系统的常见难题跟业界的解决方案。因为也没有所...  阅读全文

posted @ 2021-03-29 22:36 Jack Jiang 阅读(96) | 评论 (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 阅读(81) | 评论 (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 阅读(189) | 评论 (0)编辑 收藏

     摘要: 本文由微信开发团队工程师“ kellyliang”原创发表于“微信后台团队”公众号,收录时有修订和改动。1、引言随着直播和类直播场景在微信内的增长,这些业务对临时消息(在线状态时的实时消息)通道的需求日益增长,直播聊天室组件应运而生。直播聊天室组件是一个基于房间的临时消息信道,主要提供消息收发、在线状态统计等功能。本文将回顾微信直播聊天室单房间海量用...  阅读全文

posted @ 2021-03-06 17:08 Jack Jiang 阅读(165) | 评论 (0)编辑 收藏

     摘要: 本文引用了“一文读懂什么是进程、线程、协程”一文的主要内容,感谢原作者的无私分享。1、系列文章引言1.1 文章目的作为即时通讯技术的开发者来说,高性能、高并发相关的技术概念早就了然与胸,什么线程池、零拷贝、多路复用、事件驱动、epoll等等名词信手拈来,又或许你对具有这些技术特征的技术框架比如:Java的Netty、Php的workman、Go的gnet等熟练掌握。但真正到...  阅读全文

posted @ 2021-03-03 13:02 Jack Jiang 阅读(134) | 评论 (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 阅读(133) | 评论 (0)编辑 收藏

     摘要: 本文原题“如果让你来设计网络”,由闪客sun分享,转载请联系作者。1、引言网络编程能力对于即时通讯技术开发者来说是基本功,而计算机网络又是网络编程的理论根基,因而深刻准确地理解计算机网络知识显然能夯实你的即时通讯应用的实践品质。本文风格类似于52im社区里的《网络编程懒人入门》、《脑残式网络编程入门》两个系列,但通俗又不失内涵,简洁又不简陋,非常适合对计算机网络知识有向往但...  阅读全文

posted @ 2021-02-02 15:24 Jack Jiang 阅读(118) | 评论 (0)编辑 收藏

Jack Jiang的 Mail: jb2011@163.com, 联系QQ: 413980957, 微信: hellojackjiang