NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

跨进程通信,到底用长连接还是短连接

  • 2018-11-19
  • 本文字数:3962 字

    阅读完需:约 13 分钟

跨进程通信,到底用长连接还是短连接

一个完整的软件系统大多数情况下是由多个进程共同协作进行的,哪怕它们在同一台服务器上。所以,进程之间如何进行高效的通信至关重要。


单个应用程序+单个数据库这套基础开发套餐我相信每个人都经历过,甚至在初期它们还有可能部署在同一台服务器上。既然应用程序和数据库分属于两个不同的进程,所以这个问题本质上还是两个进程之间的通信问题。


两个进程之间如果要通信,很显然必须要建立一个连接,通过它来相互传输数据。原则上,如果两个进程在同一台服务器上,有很多种方式可以进行相互通信。不过在分布式系统中,不同的进程很多时候被部署在不同的服务器上。所以我们这次只聊基于 TCP/IP 的通信方式,因为对大家来说这是最普遍会用到的方式,不管是应用程序间的远程调用(RPC)还是应用程序与数据库间的调用(DAL),皆是如此。

通过套接字(socket)建立连接

socket 与 TCP/IP 之间是唇齿相依般的关系,联系紧密,先来看下维基百科对 socket 的定义。


socket 是计算机网络中用于在节点内发送或接收数据的内部端点。具体来说,它是网络软件(协议栈)中这个端点的一种表示,包含通信协议、目标地址、状态等,是系统资源的一种形式。


它在网络中所处的位置大致就是下面的黑色部分,应用层与传输层之间。



其中的传输层就是 TCP/IP 所在的地方,而你平时通过代码编写的应用程序大多属于应用层范畴,socket 在这里起到就是连接应用层与传输层的作用。


socket 的诞生是为了应用程序能够更方便的将数据经由传输层来传输,所以它本质上就是对 TCP/IP 的运用进行了一层封装,然后应用程序直接调用 socket API 即可进行通信。那么它是如何工作的呢?它分为 2 个部分,服务端需要建立 socket 来监听指定的地址,然后等待客户端来连接。而客户端则需要建立 socket 并与服务端的 socket 地址进行连接。



这图展示的就是建立 TCP/IP 连接的过程,经典的叫法为“三次握手”的过程。顾名思义,这个过程中来回产生了三次网络通信。


接下来的数据传输过程就简单很多,发送数据就是客户端往服务端通信,服务端处理完之后的数据返回则相反。



值得注意的是,传输的过程涉及到数据 Copy,不过这些 Copy 是必不可少的。其中的发送缓冲区和接收缓冲区就是套接字缓存(socket buffer)。



连接使用完之后需要关闭,不过 TCP/IP 连接关闭过程比创建更复杂一些,次数多了一次,这就是经典的“四次握手”过程。


简单总结一下 socket。socket 是进程间数据传输的媒介,为了保证连接的可靠,你需要特别注意建立连接和关闭连接的过程。为了确保准确、完整的数据传输,客户端和服务端来回进行了多次网络通信才得以完成连接的创建和关闭,这同时也是你在运用一个连接时所花费的额外成本。


基于 socket 我们可以选择建立长连接或者短连接,在实际运用中两者都有可能被用到。

长连接和短连接的区别

先带你来认识一下它俩的区别。


长连接意味着进行一次数据传输后,不关闭连接,长期保持连通状态。如果两个应用程序之间有新的数据需要传输,则直接复用这个连接,无需再建立一个新的连接。就像下图这样。



它的优势是在多次通信中可以省去连接建立和关闭连接的开销,并且从总体上来看,进行多次数据传输的总耗时更少。缺点是需要花费额外的精力来保持这个连接一直是可用的,因为网络抖动、服务器故障等都会导致这个连接不可用,甚至是由于防火墙的原因。所以,一般我们会通过下面这几种方式来做“保活”工作,确保连接在被使用的时候是可用状态:


  1. 利用 TCP 自身的保活(Keepalive)机制来实现,保活机制会定时发送探测报文来识别对方是否可达。一般的默认定时间隔是 2 小时,你可以根据自己的需要在操作系统层面去调整这个间隔,不管是 Linux 还是 Windows 系统。

  2. 上层应用主动的定时发送一个小数据包作为“心跳”,探测是否能成功送达到另外一端。 保活功能大多数情况下用于服务端探测客户端的场景,一旦识别客户端不可达,则断开连接,缓解服务端压力。


提前多说一句,如果在做了高可用的分布式系统场景中运用长连接会更麻烦一些。因为高可用必然包含自动故障转移、故障隔离等机制。这恰恰导致了一旦发生故障,客户端需要及时发现哪些连接已处于不可用状态,并进行相应的重连,包括重新做负载均衡等工作。


了解完了长连接,那么短连接就很容易理解了。短连接意味着每一次的数据传输都需要建立一个新的连接,用完再马上关闭它。下次再用的时候重新建立一个新的连接,如此反复。



它的优势是由于每次使用的连接都是新建的,所以基本上只要能够建立连接,数据就大概率能送达到对方。并且哪怕这次传输出现异常也不用担心影响后续新的数据传输,因为届时又是一个新的连接。缺点是每个连接都需要经过三次握手和四次握手的过程,耗时大大增加。


另外,短连接还有一个致命的缺点。我们回到前面提到的维基百科对 socket 的定义,其中说到 socket 包含通信协议、目标地址、状态等。实际当你在基于 socket 进行开发的时候,这些包含的具体资源主要就是这 5 个:源 IP、源端口、目的 IP、目的端口、协议,有个专业的叫法称之为“五元组”。在一台计算机上只要这五元组的值不重复,那么连接就可以被建立。然而一台计算机最多只能开启 65535 个端口,如果现在两个进程之间需要通信,作为服务端的 IP 和端口必然是固定的,因此单个客户端理论上最多只能与服务端同时建立 65535 个 socket 连接。如果除去操作系统和其它进程所占用的端口,实际还会更少。所以,一旦使用不当,在很短的时间内建立了大量连接,端口很容易被占用完。这不但会导致自身无法正常工作,还会影响到同一台计算机上的其它进程。


我猜你在项目中大多数情况使用的是短连接的方式,因为这对我们编程来说可以少考虑很多问题,潜在的这些缺点可能是你没有遇到或者意识到而已。存在必有其价值,接下去我们根据实际的案例让你清楚知道如何来选择它们。

长连接和短连接的选择

我想你肯定见过一些监控或者实时报价类系统,比如股票软件,它需要在几秒之内刷新最新的价格。像这种场景中同时包含了需要运用长连接的三个主要因素:高频、服务端主动推送和有状态


  • 高频的原因我想你根据前面的内容也明白了,因为频次越高的话,使用短连接带来的建立连接和关闭连接的总开销越大。

  • 而服务端主动推送也需要长连接的原因是,由于服务端往往是“中心化”的,一般都是 1 个服务端为多个客户端提供服务。所以,如果使用短连接的方式,那么在客户端未主动连接到服务端的情况下,服务端并不知道需要往哪些客户端去推送数据,这是原因之一。所以此时,长连接成为了一个很好的选择。另外一个原因是,哪怕客户端通过定时的短连接轮询方式进行主动连接,除了增加了额外的建立连接和关闭连接的开销外,还可能遇到通信完成后结果数据并未发生变化,做了无用功。

  • 成熟股票软件的服务端,为了支撑更多的用户以及做高可用,必然部署了多台。但是这个业务场景,用户无法容忍由于多个服务端之间数据同步的误差导致他在客户端看到的价格刷新产生“回退”现象。所以,只能尽量保持一直连接在同一台服务器上,才能避免这个情况。这种场景被称之为“有状态”,也可以理解为是“串行”的,因为多次请求的前后需要保持“连续性”。


短连接则更适用于诸如阅读类软件的场景中,例如,很多时候用户点开一篇文章后需要花一些时间进行阅读,这个时间有长有短,并且直到用户下一次操作之前都没有数据传输发生。这个场景中包含了运用短连接的两个主要因素:低频、无状态


  • 因为低频,所以更能容忍建立连接和关闭连接的开销。

  • 用户的下一次点击往往跳转到了其它文章,并且新打开的与当前文章并不需要具有“连续性”,所以这种场景我们称之为“无状态”的。另外,理论上同一时刻打开几篇文章也不会存在什么不妥。


通过这两个案例我们可以总结出一个决定何时运用长连接和短连接的最佳实践。


长连接适用于:两个进程之间需要高频通信并且具备服务端主动推送或者有状态(需串行)两者之一的场景,否则并不是必选项。


短连接适用于:两个进程之间通信频率较低,或者属于无状态(可并行)的场景,否则并不是必选项。


其它情况就根据所需的侧重点来,比如侧重性能就长连接,侧重编码的便捷性就选择短连接。

总结

至此,相信你应该清楚了长连接和短连接在跨进程通信中该如何选择,而且还对通过 socket 建立 TCP 连接有了一定的认识。你在实际的工作中可能遇到的场景千奇百怪,只需要保持先识别所处场景的特点,再基于这些特点来作出选择的习惯,必然至少是个不错的决策。


不过有时候我们可能需要一个中庸的方案来作为默认选择,因为很多场景中的请求并不是平稳的,甚至波动会较大,而且可能同时存在有状态和无状态的场景,此时如果单方面的选择长连接或者短连接都会产生较多的资源浪费。那么我们可以通过增加一些复杂度来实现一个能够综合长连接和短连接各自优点的方案:建立多个长连接,每次数据传输的时候独占使用,用完之后放回,再给后续使用。这种方案被称之为“连接池”。例如,很多的数据库访问框架都内置了连接池机制,因为作为底层框架的它不知道会被使用到何种场景的系统中,所以提供了这个选项。


连接池的运作流程大致如下图。除了上面所说的,独占使用,用完放回之外,一般都会在应用程序启动时预先建立好指定数据量的连接,以更好应对冷启动后请求数快速上升带来的资源竞争问题,这个数量一般称之为最小连接数。另外,如果新的请求进来时,所有已建立的连接都在使用中,但是连接数的上限未达到指定数量,可以再建立新的长连接来使用,用完依旧放回到空闲池,相当于把连接池扩大了,这个上限数量一般称之为最大连接数。



不知道大家对长连接和短连接的运用有什么样的经验和认识呢?欢迎在下方评论区留言,我们一起讨论。



延伸阅读:分布式系统系列文章

第一篇:《拨云见日看什么是分布式系统?》


第二篇:《详解分布式系统本质:“分治”和“冗余”》


第三篇:《别忽视分布式系统这六大“暗流”》


2018-11-19 15:055008

评论 3 条评论

发布
用户头像
分布式系统中,后端微服务之间,使用长连接,还是短连接,比较合适?本文看下来是否使用长连接比较合适,请博主帮解答一下
2019-04-12 09:21
回复
用户头像
还有个浏览器普遍做法,限制性链接; 限制了最长持续时间(5m, 5h and so on)和收发次数的长连接。 兼具两者有点又能根据需要灵活配置。
2018-12-06 21:00
回复
用户头像
『需要经过三次握手和四次握手的过程』
应该是四次挥手吧。
2018-11-22 10:19
回复
没有更多了
发现更多内容

软件开发中的字符编码问题的思考

行者孙

c++ 软件开发 签约计划第二季 字符编码

使用 JavaScript 给微信用户发送消息

Jerry Wang

微信 sdk 28天写作 Web JS SDK 12月日更

React进阶(四):路由介绍

No Silver Bullet

React 路由 12月日更

初识腾讯移动通讯 TPNS~

阿策小和尚

28天写作 Android 小菜鸟 12月日更

Java反射机制获取运行时类的完整结构

编程江湖

JAVA开发

聊聊前端工程师如果做职业规划

全栈潇晨

职业规划 前端开发

面试官:说说react的渲染过程

全栈潇晨

React

设计模式【6.1】-- 初探适配器模式

秦怀杂货店

Java 设计模式

C++如何写出异常安全的代码

行者孙

c++ 异常 错误处理 签约计划第二季

在中国如何打造一个有生命力的开源项目?

Jianmu

DevOps 持续集成 CI/CD 开源社区 持续部署

阿里巴巴、埃森哲、德勤三方圆桌对话——《与数字化先锋共绘创新蓝图》

大咖说

阿里巴巴 大咖说 数字经济 数智化

音视频学习--X264码率控制--前瞻

Fenngton

音视频 H264 视频编解码 签约计划第二季

给弟弟的信第12封|阅读对一个人有多重要

大菠萝

28天写作

❤️使用 HTML、CSS 和 JS 创建在线音乐播放器(免费送完整源码)❤️

海拥(haiyong.site)

响应式 大前端 28天写作 签约计划第二季 12月日更

Linux学习方法《Linux一学就会》:网络管理技术

侠盗安全

Linux linux运维 运维工程师 云计算架构师

JavaMoney规范(JSR 354)与对应实现解读

vivo互联网技术

Java、 API 虚拟化 虚拟货币

龙蜥社区一周动态 | 12.06-12.10

OpenAnolis小助手

龙蜥社区

C++中的pimpl惯用法

行者孙

c++ 签约计划第二季 pimpl 惯用法

react源码解析9.diff算法

buchila11

React

react源码解析10.commit阶段

buchila11

React

今年双12,《代码随想录》冲榜TOP1

博文视点Broadview

dart系列之:安全看我,dart中的安全特性null safety

程序那些事

flutter dart 程序那些事 12月日更 flutter 调试工具

Vue之全局事件总线和消息订阅与发布

编程江湖

前端开发

OPPO云VPC网络实践

安第斯智能云

云计算 SDN架构 智能网卡vpc

推倒重来的觉悟

FunTester

单元测试 Mockito powermock spock FunTester

0 基础学习 Flutter~(mini 进阶版)

阿策小和尚

Flutter 小菜 0 基础学习 Flutter 内容合集 签约计划第二季

大数据开发技术NN和2NN工作机制

编程江湖

大数据

使用 scipy.fft 进行Fourier Transform:Python 信号处理

华为云开发者联盟

Python 音频 信号处理 傅立叶变换 Fourier transform

【LeetCode】保持城市天际线Java题解

Albert

算法 LeetCode 12月日更

设计模式【6.2】-- 再聊聊适配器模式

秦怀杂货店

Java 设计模式 适配器模式

技术分享| Linux高并发踩过的坑及性能优化

anyRTC开发者

Linux 音视频 高并发 服务器 高并发优化

跨进程通信,到底用长连接还是短连接_软件工程_张帆_InfoQ精选文章