什么?-你的服务竟然被探活搞死了?

Java面试笔试面经、Java技术每天学习一点

Java面试

关注不迷路

作者:haolujun

来源:https://www.cnblogs.com/haolujun

背景

今年开发了好多服务,着实踩了不少的坑。这不,分分钟就被探活搞的死去活來。这里我把这些经验分享给大家,避免大家再继续犯这种错误。

通用tcp探活原理

其实,探活原理特别简单,只要稍懂计算机网络就能够理解。

  • 检测端 发起tcp三次握手,建立新连接,连接建立成功代表服务活着,建立失败代表服务死了,之后发送rst包主动断开连接。

  • 被检测端 接受检测端发送的三次握手手建立连接,当接收到检测端的rst包后,被检测端断开连接,释放资源。

但是假如rst包丢失了,会发生什么样的情况呢?我们以thrift为例讲述一下之后所发生的事情,如下图所示。

经过三次握手后,服务端已经建立一个新的数据连接,并把连接丢给工作线程。服务端的工作线程监听连接,并准备接收请求(毕竟,任何一个thrift服务都是先接收请求数据,之后进行计算,最后返回响应数据,所以当新连接建立后,thrift默认首先读取连接上的数据)。

检测端建立连接成功后,认为下游服务还活着,所以立刻发送rst包(检测端认为这个rst包一定会到达被检测服务),并且释放连接资源。

但是如果网络状态不好,rst包丢失,那么服务端(被检测端)的工作线程就会无限制的hang在读取连接数据上(因为检测端已经单方面认为连接断开,不会写任何数据,所以服务端也读不到任何数据)。如果多丢几个rst包,那可以预期无论你有多少thrift工作线程,都将会hang死。

此时真正调用服务的客户端的请求也无限制的hang住,因为这些请求得不到thrift工作线程的处理。

最最可怕的是:由于探活只是单纯的建立连接而并不发送或者接受额外数据,并且thrift服务有单独的线程进行accept,这导致了连接建立每次都成功,但实际上服务已经没有了计算能力。

最后的结局就是:整个系统流量突然降低,下游接收不到请求(以为是上游调用的锅),上游发出的请求得不到响应(认为是下游服务的锅),并且没有报警短信发出(以为是运维的锅),对排查问题造成很大的困扰。

出现这种问题时有一个非常明显的现象:即使在系统流量为0的情况下,服务端也会不断有新连接建立并处于Establish状态(这是因为周期性的探活导致的),并且服务端日志不滚动,客户端请求无响应。如果你的系统有这种情况,那么多半和探活有关。

我当时遇到的情况比较糟糕,因为之前一段时间rst丢包率特别低,平均几天丢一个rst包,所以服务hang死造成的影响并不大,只要抽空重新启动服务即可。可是突然某一天,单台服务的rst丢包数达到了秒级:隔几秒丢一个rst包,导致我的服务短时间内全部hang死。

HTTP探活原理

在实际工作中,对于HTTP服务的探活通常也采取TCP探活原理,毕竟HTTP建立在TCP服务之上,所以TCP探活同样适用于HTTP服务。很多HTTP服务实现原理和thrift大同小异,所以当TCP探活的rst包丢失后,HTTP服务同样会hang在读取连接数据。

为了避免rst包丢失,HTTP服务通常使用HTTP探活请求:探测端对被探测端发送特定的HTTP请求,并且验证被探测端的响应数据是否符合预期。如果rst包丢失,服务端连接最差的情况下会处于TIME_WAIT状态,经过2倍超时时间后服务端会主动关闭连接释放资源,这样服务端的工作线程不会长时间的被占用,相比于用TCP探活要好的多。HTTP探活原理如下图所示。

此时rst包虽然丢失,但是由于探测使用的HTTP请求,那么整个请求的交互就会完成(探测端会等待服务端的响应数据,所以能够确保服务端能够完成这个响应),服务端发送完响应数据后会主动关闭连接,发送FIN包(一般的HTTP服务框架默认都会这么做),服务端连接处于TIME_WAIT状态,经过一段时间后连接释放,不会长时间占用服务端资源。

对于HTTP服务,我们需要提供一个不耗费cpu和内存的调用接口,这个接口只是为了满足HTTP探活请求调用,如果探活接口死了,可以认为这个服务也死了。

如何确保不被探活搞死?

我们不能保证网络时时刻刻正常rst包不丢失,所以我们只能改造服务使得其更健壮。
正确解决方案如下:

  • 服务端加入读超时时间。当rst包丢失导致服务端线程hang在读取上,超过一定时间后服务端线程会主动断开连接,释放资源,从而确保服务端线程能够服务于其它请求。

  • 客户端请求服务端加入超时限制并进行重试。当一个服务hang死,导致连接其上的客户端也hang住后,超过一段时间后,客户端主动断开连接并且尝试请求其它可用服务。

现在我们清楚探活问题的来龙去脉,那么我想问:你的服务加入超时时间了么?你的服务会被探活搞死么?

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用[1]提供的链接,我了解到MyBatis是一个Java持久层框架,它可以帮助开发人员将SQL语句与Java代码进行解耦,提供了一种简单且灵活的方式来访问数据库。MyBatis的主要特点包括动态SQL、自动映射、缓存机制等。 关于Java接口探活框架,根据引用的描述,我们需要提供一个不耗费CPU和内存的调用接口,这个接口只是为了满足HTTP探活请求调用。为了确保不被探活,可以考虑以下几种方法: 1. 使用轻量级的框架:选择一个轻量级的框架来实现接口探活,例如Spring Boot。Spring Boot提供了快速构建独立的、生产级别的Spring应用程序的能力,可以通过简单的配置和注解来实现接口探活。 2. 优化接口实现:确保接口实现代码的逻辑简单且高效,避免不必要的计算和资源消耗。可以通过合理的设计和优化算法来提高接口的性能。 3. 使用缓存:对于频繁被调用的接口,可以考虑使用缓存来减少对数据库或其他资源的访问。通过缓存可以提高接口的响应速度,减少对系统资源的消耗。 4. 异步处理:对于耗时的操作,可以考虑使用异步处理来提高接口的并发能力。通过将耗时的操作放入异步任务中,可以释放主线程的资源,提高接口的吞吐量。 5. 监控和调优:定期监控接口的性能指标,例如响应时间、并发数等,及时发现并解决性能瓶颈。可以使用一些监控工具和性能分析工具来帮助定位和解决问题。 这些方法可以帮助确保接口探活框架不会耗费过多的CPU和内存资源,从而避免被探活
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值