0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

简单了解TCP中设计的短连接和长连接

西西 来源:Kirito的技术分享 作者:kiritomoe 2019-02-01 10:46 次阅读

1 前言

可能很多 Java 程序员对 TCP 的理解只有一个三次握手,四次挥手的认识,我觉得这样的原因主要在于 TCP 协议本身稍微有点抽象(相比较于应用层的 HTTP 协议);其次,非框架开发者不太需要接触到 TCP 的一些细节。其实我个人对 TCP 的很多细节也并没有完全理解,这篇文章主要针对微信交流群里有人提出的长连接,心跳的问题,做一个统一的整理。

在 Java 中,使用 TCP 通信,大概率会涉及到 Socket、Netty,本文会借用它们的一些 API 和设置参数来辅助介绍。

2 长连接与短连接

TCP 本身并没有长短连接的区别,长短与否,完全取决于我们怎么用它。

短连接:每次通信时,创建 Socket;一次通信结束,调用 socket.close()。这就是一般意义上的短连接,短连接的好处是管理起来比较简单,存在的连接都是可用的连接,不需要额外的控制手段。

长连接:每次通信完毕后,不会关闭连接,这样就可以做到连接的复用。长连接的好处便是省去了创建连接的耗时。

短连接和长连接的优势,分别是对方的劣势。想要图简单,不追求高性能,使用短连接合适,这样我们就不需要操心连接状态的管理;想要追求性能,使用长连接,我们就需要担心各种问题:比如端对端连接的维护,连接的保活。

长连接还常常被用来做数据的推送,我们大多数时候对通信的认知还是 request/response 模型,但 TCP 双工通信的性质决定了它还可以被用来做双向通信。在长连接之下,可以很方便的实现 push 模型。

短连接没有太多东西可以讲,所以下文我们将目光聚焦在长连接的一些问题上。纯讲理论未免有些过于单调,所以下文我借助 Dubbo 这个 RPC 框架的一些实践来展开 TCP 的相关讨论。

3 服务治理框架中的长连接

前面已经提到过,追求性能的时候,必然会选择使用长连接,所以借助 Dubbo 可以很好的来理解 TCP。我们开启两个 Dubbo 应用,一个 server 负责监听本地 20880(众所周知,这是 Dubbo 协议默认的端口),一个 client 负责循环发送请求。执行 lsof-i:20880 命令可以查看端口的相关使用情况:

简单了解TCP中设计的短连接和长连接

*:20880(LISTEN) 说明了 Dubbo 正在监听本地的 20880 端口,处理发送到本地 20880 端口的请求。

后两条信息说明请求的发送情况,验证了 TCP 是一个双向的通信过程,由于我是在同一个机器开启了两个 Dubbo 应用,所以你能够看到是本地的 53078 端口与 20880 端口在通信。我们并没有手动设置 53078 这个客户端端口,他是随机的,但也阐释了一个道理:即使是发送请求的一方,也需要占用一个端口。

稍微说一下 FD 这个参数,他代表了文件句柄,每新增一条连接都会占用新的文件句柄,如果你在使用 TCP 通信的过程中出现了 open too many files 的异常,那就应该检查一下,你是不是创建了太多的连接,而没有关闭。细心的读者也会联想到长连接的另一个好处,那就是会占用较少的文件句柄。

4 长连接的维护

因为客户端请求的服务可能分布在多个服务器上,客户端端自然需要跟对端创建多条长连接,使用长连接,我们遇到的第一个问题就是要如何维护长连接。

//客户端 public class NettyHandler extends SimpleChannelHandler {

private final Map《String, Channel》 channels = new ConcurrentHashMap《String, Channel》();// 《ip:port, channel》

} //服务端

public class NettyServer extends AbstractServer implements Server {

private Map《String, Channel》 channels;// 《ip:port, channel》

}

在 Dubbo 中,客户端和服务端都使用 ip:port 维护了端对端的长连接,Channel 便是对连接的抽象。我们主要关注 NettyHandler 中的长连接,服务端同时维护一个长连接的集合是 Dubbo 的设计,我们将在后面提到。

5 连接的保活

这个话题就有的聊了,会牵扯到比较多的知识点。首先需要明确一点,为什么需要连接的报活?当双方已经建立了连接,但因为网络问题,链路不通,这样长连接就不能使用了。需要明确的一点是,通过 netstat,lsof 等指令查看到连接的状态处于 ESTABLISHED 状态并不是一件非常靠谱的事,因为连接可能已死,但没有被系统感知到,更不用提假死这种疑难杂症了。如果保证长连接可用是一件技术活。

6 连接的保活:KeepAlive

首先想到的是 TCP 中的 KeepAlive 机制。KeepAlive 并不是 TCP 协议的一部分,但是大多数操作系统都实现了这个机制。KeepAlive 机制开启后,在一定时间内(一般时间为 7200s,参数 tcp_keepalive_time)在链路上没有数据传送的情况下,TCP 层将发送相应的KeepAlive探针以确定连接可用性,探测失败后重试 10(参数 tcp_keepalive_probes)次,每次间隔时间 75s(参数 tcp_keepalive_intvl),所有探测失败后,才认为当前连接已经不可用。

在 Netty 中开启 KeepAlive

bootstrap.option(ChannelOption.TCP_NODELAY,true)

Linux 操作系统中设置 KeepAlive 相关参数,修改 /etc/sysctl.conf 文件:

net.ipv4.tcp_keepalive_time=90 net.ipv4.tcp_keepalive_intvl=15 net.ipv4.tcp_keepalive_probes=2

KeepAlive 机制是在网络层面保证了连接的可用性,但站在应用框架层面我们认为这还不够。主要体现在两个方面:

KeepAlive 的开关是在应用层开启的,但是具体参数(如重试测试,重试间隔时间)的设置却是操作系统级别的,位于操作系统的 /etc/sysctl.conf 配置中,这对于应用来说不够灵活。

KeepAlive 的保活机制只在链路空闲的情况下才会起到作用,假如此时有数据发送,且物理链路已经不通,操作系统这边的链路状态还是 ESTABLISHED,这时会发生什么?自然会走 TCP 重传机制,要知道默认的 TCP 超时重传,指数退避算法也是一个相当长的过程。

KeepAlive 本身是面向网络的,并不是面向于应用的,当连接不可用时,可能是由于应用本身 GC 问题,系统 load 高等情况,但网络仍然是通的,此时,应用已经失去了活性,所以连接自然应该认为是不可用的。

看来,应用层面的连接保活还是必须要做的。

7 连接的保活:应用层心跳

终于点题了,文题中提到的心跳便是一个本文想要重点强调的另一个 TCP 相关的知识点。上一节我们已经解释过了,网络层面的 KeepAlive 不足以支撑应用级别的连接可用性,本节就来聊聊应用层的心跳机制是实现连接保活的。

如何理解应用层的心跳?简单来说,就是客户端会开启一个定时任务,定时对已经建立连接的对端应用发送请求(这里的请求是特殊的心跳请求),服务端则需要特殊处理该请求,返回响应。如果心跳持续多次没有收到响应,客户端会认为连接不可用,主动断开连接。不同的服务治理框架对心跳,建连,断连,拉黑的机制有不同的策略,但大多数的服务治理框架都会在应用层做心跳,Dubbo 也不例外。

8 应用层心跳的设计细节

以 Dubbo 为例,支持应用层的心跳,客户端和服务端都会开启一个 HeartBeatTask,客户端在 HeaderExchangeClient 中开启,服务端将在 HeaderExchangeServer 开启。文章开头埋了一个坑:Dubbo 为什么在服务端同时维护 Map

// HeartBeatTask if (channel instanceof Client) {

((Client) channel).reconnect();

} else { channel.close();

}

熟悉其他 RPC 框架的同学会发现,不同框架的心跳机制真的是差距非常大。心跳设计还跟连接创建,重连机制,黑名单连接相关,还需要具体框架具体分析。

除了定时任务的设计,还需要在协议层面支持心跳。最简单的例子可以参考 nginx 的健康检查,而针对 Dubbo 协议,自然也需要做心跳的支持,如果将心跳请求识别为正常流量,会造成服务端的压力问题,干扰限流等诸多问题。

简单了解TCP中设计的短连接和长连接

其中 Flag 代表了 Dubbo 协议的标志位,一共 8 个地址位。低四位用来表示消息体数据用的序列化工具的类型(默认 hessian),高四位中,第一位为1表示是 request 请求,第二位为 1 表示双向传输(即有返回response),第三位为 1 表示是心跳事件。

心跳请求应当和普通请求区别对待。

9 注意和 HTTP 的 KeepAlive 区别对待

HTTP 协议的 KeepAlive 意图在于连接复用,同一个连接上串行方式传递请求-响应数据

TCP 的 KeepAlive 机制意图在于保活、心跳,检测连接错误。

这压根是两个概念。

10 KeepAlive 常见异常

启用 TCP KeepAlive 的应用程序,一般可以捕获到下面几种类型错误

ETIMEOUT 超时错误,在发送一个探测保护包经过 (tcpkeepalivetime + tcpkeepaliveintvl * tcpkeepaliveprobes)时间后仍然没有接收到 ACK 确认情况下触发的异常,套接字被关闭 java java.io.IOException:Connectiontimedout

EHOSTUNREACH host unreachable(主机不可达)错误,这个应该是 ICMP 汇报给上层应用的。 java java.io.IOException:Noroute to host

链接被重置,终端可能崩溃死机重启之后,接收到来自服务器的报文,然物是人非,前朝往事,只能报以无奈重置宣告之。 java java.io.IOException:Connectionresetbypeer

11 总结

有三种使用 KeepAlive 的实践方案:

1.默认情况下使用 KeepAlive 周期为 2 个小时,如不选择更改,属于误用范畴,造成资源浪费:内核会为每一个连接都打开一个保活计时器,N 个连接会打开 N 个保活计时器。 优势很明显:

TCP 协议层面保活探测机制,系统内核完全替上层应用自动给做好了

内核层面计时器相比上层应用,更为高效

上层应用只需要处理数据收发、连接异常通知即可

数据包将更为紧凑

2.关闭 TCP 的 KeepAlive,完全使用应用层心跳保活机制。由应用掌管心跳,更灵活可控,比如可以在应用级别设置心跳周期,适配私有协议。

3.业务心跳 + TCP KeepAlive 一起使用,互相作为补充,但 TCP 保活探测周期和应用的心跳周期要协调,以互补方可,不能够差距过大,否则将达不到设想的效果。

各个框架的设计都有所不同,例如 Dubbo 使用的是方案三,但阿里内部的 HSF 框架则没有设置 TCP 的 KeepAlive,仅仅由应用心跳保活。和心跳策略一样,这和框架整体的设计相关

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • JAVA
    +关注

    关注

    19

    文章

    2904

    浏览量

    102998
  • API
    API
    +关注

    关注

    2

    文章

    1383

    浏览量

    60994
  • TCP
    TCP
    +关注

    关注

    8

    文章

    1272

    浏览量

    78303
收藏 人收藏

    评论

    相关推荐

    如何标识一个TCP连接

    tcp应用中,server事先在某个固定端口监听,client主动发起连接,经过三路握手后建立tcp连接。那么对单机,其最大并发tcp
    的头像 发表于 10-10 10:33 2403次阅读

    TCP握手连接和断开连接

    TCP握手连接和断开连接
    发表于 07-31 15:02

    TCP/IP协议连接指南

    中扮演什么角色了。文章目录ESP32 单片机学习笔记 - 07 - TCP连接一、例程实践1)建立TCP客户端 - tcp_client2)总结二、
    发表于 02-17 07:45

    大神告诉你TCP建立连接为什么是三次握手

    所谓三次握手(Three-Way Handshake)即建立TCP连接,是指建立一个TCP连接时,需要客户端和服务端总共发送3个包以确认连接
    的头像 发表于 04-16 11:43 9991次阅读
    大神告诉你<b class='flag-5'>TCP</b>建立<b class='flag-5'>连接</b>为什么是三次握手

    TCP, ISO- on- TCP, UDP连接

    TSEND“ & „TRCV “ 发送和接收数据(TCP 和ISO - on- TCP)„TUSEND“ & „TURCV“ 发送和接收数据(UDP) 自动连接管理的通讯块( 仅用于S7- 1200)
    的头像 发表于 06-12 15:11 4453次阅读
    <b class='flag-5'>TCP</b>, ISO- on- <b class='flag-5'>TCP</b>, UDP<b class='flag-5'>连接</b>

    TCP面向连接的虚电路是怎么实现的

    电子发烧友网站提供《TCP面向连接的虚电路是怎么实现的.pdf》资料免费下载
    发表于 11-26 17:31 16次下载
    <b class='flag-5'>TCP</b>面向<b class='flag-5'>连接</b>的虚电路是怎么实现的

    字节一面:HTTP长连接TCP连接有区别?

    由于 HTTP 是基于 TCP 传输协议实现的,客户端与服务端要进行 HTTP 通信前,需要先建立 TCP 连接,然后客户端发送 HTTP 请求,服务端收到后就返回响应,至此「请求-应答」的模式就完成了,随后就会释放
    的头像 发表于 12-02 14:00 744次阅读

    什么是Socket连接?Socket与TCP连接的关系

    主机 A 的应用程序必须通过 Socket 建立连接才能与主机B的应用程序通信,而建立 Socket 连接需要底层 TCP/IP 协议来建立 TCP
    发表于 03-31 15:10 747次阅读

    什么是Socket连接?与TCP连接有什么关系?

    什么是Socket连接?它与TCP连接有什么关系? 计算机网络是我们日常生活中不可或缺的一部分,而Socket连接则是网络通信中必不可少的一种机制。Socket是应用层与
    的头像 发表于 05-23 11:43 412次阅读

    基于软件定义无线电的实时频谱分析仪设备连接方法(一)简单2端口TCP/IP连接

    虹科实时频谱分析仪HK-R5550支持简单2端口TCP/IP连接和使用HiSLIP进行连接两种不同的设备连接方法。
    的头像 发表于 12-22 09:16 664次阅读
    基于软件定义无线电的实时频谱分析仪设备<b class='flag-5'>连接</b>方法(一)<b class='flag-5'>简单</b>2端口<b class='flag-5'>TCP</b>/IP<b class='flag-5'>连接</b>

    什么是Socket连接?它与TCP连接有什么关系?

    计算机网络是我们日常生活中不可或缺的一部分,而Socket连接则是网络通信中必不可少的一种机制。在本篇文章中,我们将通过简单易懂、生动形象的语言,向大家介绍Socket连接及其重要性
    的头像 发表于 03-06 11:00 816次阅读
    什么是Socket<b class='flag-5'>连接</b>?它与<b class='flag-5'>TCP</b><b class='flag-5'>连接</b>有什么关系?

    【干货】什么是Socket连接?它与TCP连接有什么关系?

    计算机网络是我们日常生活中不可或缺的一部分,而Socket连接则是网络通信中必不可少的一种机制。在本篇文章中,我们将通过简单易懂、生动形象的语言,向大家介绍Socket连接及其重要性
    的头像 发表于 04-09 10:39 804次阅读
    【干货】什么是Socket<b class='flag-5'>连接</b>?它与<b class='flag-5'>TCP</b><b class='flag-5'>连接</b>有什么关系?

    TCP通信过程中的长连接与短连接是什么?

    当面试官问你:TCP 通信过程中的长连接与短连接是什么?
    的头像 发表于 08-08 11:30 542次阅读
    <b class='flag-5'>TCP</b>通信过程中的长<b class='flag-5'>连接</b>与短<b class='flag-5'>连接</b>是什么?

    TCP连接的建立与中止

    常重要的 。 TCP 连接的建立可以简单地称为三次握手,而连接的中止则可以称为四次挥手。 建立连接 TC
    的头像 发表于 10-08 16:52 459次阅读

    TCP的长连接和短连接

    TCP在真正开始进行数据传输之前,Server 和 Client 之间必须建立一个连接。当数据传输完成后,双方不再需要这个连接时,就可以释放这个连接
    的头像 发表于 11-13 10:46 524次阅读