热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:警惕!四层七层负载乱用,Javalettuce连接池故障一例

本文由编程笔记#小编为大家整理,主要介绍了警惕!四层七层负载乱用,Javalettuce连接池故障一例相关的知识,希望对你有一定的参考价值。
本文由编程笔记#小编为大家整理,主要介绍了警惕!四层七层负载乱用,Java lettuce连接池故障一例相关的知识,希望对你有一定的参考价值。









01




写在之前







负载均衡

负载均衡建立在现有网络结构之上,它提供一种廉价、有效、透明的方法,扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。(百科)

































四层负载 七层负载
概念 IP+Port实现的负载均衡、不涉及具体协议、工作在TCP层、只转发你的流量,不关注流量内容是什么,只转发即可 七层是应用层、带协议的才能称为七层,它是基于应用层协议的信息进行转发,七层负载均衡也称为“内容交换”,主要是通过报文中具有真正意义的应用层内容,再加实现负载均衡的设备设置的服务器选择方式 ,决定最终选择哪台上游内容服务器;最常见的是http协议,
实现方式 使用三层的IP与四层的端口,来决定哪些流量做负载均衡,对需要做负载的流量进行NAT处理或直连路由或ip隧道的方式 ,把流量转发至上游服务器、并记录这个TCP或者UDP流量是由哪台上游服务器处理,后续这个连接的所有流量都同样转发到同一台服务器处理; 七层是在四层基础之上存在的,它在在四层的基础上结合应用层协议的特性进行负载,比如一个http服务,除了根据三层的IP+四层的端口来辨别哪些流量需要处理,还能基于七层的URI、浏览器类别、COOKIE、语言等信息来决定负载均衡;
工具选择 LVS、nginx、HAProxy、F5等 Nginx、HAProxy、Squid、F5等
利弊 简单、直接转发,不需要太多复杂配置,安全性相对7层差一些; 更智能化(例如根据用户请求内容区分图片服务器或者对文本进行压缩等),对客户端请求和服务器端的响应可以做修改(header信息、超时配置等),提高应用系统的灵活性;安全方面可以定制一些策略如waf、还有SYN Flood攻击,四层负载会直接到上游服务器,而七层的这些SYN攻击,到负载均衡就截止,不会影响到上游服务器,提高一些安全性;

工作场景中,根据公司业务需要自行选择使用哪种负载均衡即可,一般情况下http应用使用七层负载较多,其它七层应用协议如mysql协议、redis协议等都不建议使用七层负载均衡,因为七层均衡设备或软件很少会实现这种专有协议的负载算法。


五层协议模型

目的是熟悉协议工作在哪一层,数据承载形式是什么,redis协议是7层应用层协议,7层负载均衡设备是否就能实现所有七层协议呢?一般情况下不能,这里的redis是应用层协议,属于专用私有协议,但7层负载均衡如果实现了redis协议,就可以做7层负载,但如果没有实现也能类似HTTP一样用7层负载,强烈不建议这样的用法,因为会出现各种奇葩问题,建议使用4层负载就好了。



































五层模型 常见协议 数据表现形式
应用层 HTTP、FTP、Telnet、SNMP、DNS、SMTP、TFTP以及mysql、redis、grpc专有协议等都属于应用层协议  消息(message)
传输层 有连接安全的TCP,无连接不安全UDP TCP的叫做Segment(数据段)UDP的叫做数据报(Datagram)
网络层 ICMP、IP、BGP、IGMP、RIP、OSPF等协议 数据包(Packet)
数据链路层 ARP、RARP、PPP、MTU等协议  数据帧(Frame)
物理机 EEE802,IEEE802.11等协议 二进制位

除了上面的数据承载形式外,还有一种叫数据单元(data unit)的数据,常用的数据单元有服务数据单元(SDU)、协议数据单元(PDU);SDU是在同一机器上的两层之间传送信息,而PDU是发送机器上每层的信息发送到接收机器上的相应层(同等层间交流用的)。


F5 基础知识

F5是硬件负载均衡器,分LTM和GTM,配置中均有几个重要参数:Node(节点)、Pool(资源池)、和Virtual Server(虚拟服务器)。



在配置F5的过程中Virtual Server是核心,通过配置它,可以关联到Pool、Node、并且为VS分配一个IP,这里简单说下配置VS时的类型有哪些,这些也是F5的负载均衡类型,VS的Type有Performance L4、Standard VS、Forwarding IP 和 Fast Http,这里重点介绍下4层与7层负载均衡,其它两种不做多过介绍。


Performance L4类型的Virtual Server,是我们常说的四层负载均衡,也是一般企业都会选择的类型,因为它对应用系统的影响小、转发快、不改变TCP中的任何参数、直接转发。



Forwarding IP类型的 Virtual Server 它主要用在内外网路由功能上面,如果要使用路由功能,需要单独开启,这里不过多介绍。








02




问题排查







问题解决后图示

警惕!四层、七层负载乱用,Java lettuce连接池故障一例

问题描述

最近升级 codis proxy 时,发现升级完成后,Java 程序无法连接 Codis 的现象,线上大面积报警,没有办法只能重启下Java程序,服务正常;访问方式是Java 程序访问F5 VS IP,然后由 VS IP 负载到 Codis Proxy,这个问题不解决,影响后续 Codis Proxy升级。


信息收集

1. 网络反馈 F5 VS 配置未变更过;

2. Java程序也未发版,使用 lettuce连接池通过F5 VS 去访问 Codis 服务 ;

3. 升级 codis proxy 即 codis proxy重启过;

4. RD 同学反馈连接 codis异常,建议重启试下;

5. 重启后正常,把出问题的 Java 程序全部重启,业务恢复;

6. 其实这个时间回滚 codis proxy 代码也不能解决这个问题,必须 重启Java 程序(一般是谁升级了,就回滚谁,百分之八九十可以解决,很可惜此时回滚codis proxy 代码是无法解决)。


怀疑猜想

1. codis proxy 新代码导致,但中间件同学反馈,Java 程序重启之后正常,说明codis proxy 升级后的程序没有问题;

2. Java 使用的 lettuce 客户端套件问题; 

3. Java 程序异常,日志显示如下:

警惕!四层、七层负载乱用,Java lettuce连接池故障一例



[2020-02-28 10:21:52.180] [http-nio-8080-exec-5] ERROR [b9c9e148e24f478aba6d75cf93a21f0d] [] [] [] c.j.fsinnerapi.app.provider.common.exception.handler.GlobalExceptionHandler - occur error:
org.springframework.data.redis.connection.PoolException: Returned connection io.lettuce.core.StatefulRedisConnectionImpl@4afe9497 was either previously returned or does not belong to this connection provider

大意是先前链接已经返回,或者是不属于此连接提供者,说明先前的链接已经失效了,抛出异常了。

肯定是codis proxy 升级重启过程中导致问题,但问题原因究竟是什么呢?不可能因为升级codis proxy,把所有应用全部重启一次吧,陷入僵局,现在抓包分析吧。

抓包分析

java程序服务器端

警惕!四层、七层负载乱用,Java lettuce连接池故障一例

三次握手是成功的,在Push数据时,被reset掉了,这里的reset是谁发出来的呢,根据TTL可以判定是F5。


F5与Java程序端

警惕!四层、七层负载乱用,Java lettuce连接池故障一例

F5与Java程序之间的数据包,与Java程序端的一致,但这里的TTL是255,自身发出的RST。

F5到Codis proxy数据包与codis-proxy自己的数据包,均没有tcp.port == 6701的数据包,根据TTL的判定,应该是七层RESET,原因是如果七层代理有设计RESET功能,并且在无法连接后端程序的时候,发送RESET应用层响应包给客户端,那就认为是七层RESET,如果没有,而只是机械转发后端TCP层的包给客户端,就是四层RESET。从这里发现这个F5的 VS 竟然是七层负载均衡;


排查过程异常的曲折,当时抓包的时候,在重启完proxy后,立即停止了抓包,就出现类似上面的数据包;继续实验,让Java程序直接连 Codis proxy时,重启Codis proxy,Java程序丢几个包后,很快就能重新获取连接,继续访问codis并操作,RD 认为是F5的问题,F5同学目前也不确认问题原因,从这里可以得出Java 程序通过4层直连codis proxy,codis proxy重启时,Java程序丢几个包后,即可直接继续访问,无需重启;


从上面两个方面可以发现,F5 VS使用的七层负载,直连相当对4层,直接让F5同学修改VS配置,修改成4层转发,Codis Proxy 重启,Java 程序丢几个包后正常,到此问题找到了一个解决办法。


到底是什么原因造成的这种现象呢?Codis Proxy程序不升级,F5 VS 使用的七层负载(使用七层负载,暂不说是否合理),Java 程序能正常访问,为什么Codis Proxy 重启后,Java 程序收到一些RESET后,再连F5 VS 就不成功了呢?RD反馈是RESET,这句话看着没有什么太大的问题,其实里面隐藏着一个问题,RESET是什么时候发的,怎么判定 Java程序收到 Reset(Codis Proxy重启过程中)后又重新发起过连接呢?通过再次抓包分析(重启后多抓一段时间的数据包),确实论证了一个问题点,Codis Proxy重启正常后,Java 程序没有再发起连接请求,不重试了,Java 客户端放弃“治疗”,出现上面的 Java 异常错误。到这里基本上可以判断,应该是 Java 客户端使用 lettuce 连接池问题。


入手点是 lettuce 连接池源码,思路是七层负载时,VS IP:9100一直是通的,即使Pool池中所有NodeIP:Port都down了,也不影响IP:9100,客户端依然可以连接,四层负载(直连时)VS  IP:9100是随Codis  Proxy 端口存在而存在,重启时Java 客户端可以感知到IP:9100的存在与否。


问题本质原因

应用系统基于SpringBoot2.x版本开发,并配合使用Spring官方推荐的Lettuce作为Redis连接池套件。


Lettuce开发者认为,Redis单线程效率较高,而在项目实际开发过程中,仅阻塞或事务性操作对Redis的连接时长要求较高,所以Lettuce连接管理单元在默认情况下仅开启一个本地链接供多个LettuceConnector使用,也就是说,在默认情况下,即使你配置了连接池,实际上使用的也仅仅是一个物理连接,且默认情况下Lettuce不会校验该链接的可靠性(是否被关闭、是否可以ping通),所以链接永不释放。


Lettuce通过两种链接方式进行访问redis服务





















独享链接 共享链接
多线程分别持有独立的连接(每个线程单独建立Socket) 多线程共享同一个链接
每个操作都会开启和关闭对应的连接 连接永不关闭,且默认情况下不进行可靠性校验
默认情况下,阻塞性、事务性操作会强制开启一个独占链接 默认情况下,非阻塞性、非事务性操作都只能使用共享连接进行操作

private boolean validateConnection = false;
private boolean shareNativeConnection = true;

由于使用了默认参数配置即共享链接,它只开启一个NativeConnection 实际上仅开启了一个连接。

七层负载时F5 VS IP:9100是通的,Codis Proxy重启时,不影响F5 VS IP:9100的连通性,Java程序无法感知到Codis Proxy重启了,它一直认为服务是正常的,但Codis Proxy 重启导致LettuceConnectionFactory.SharedConnection(共享链接模式下)的validateConnection方法在校验时失败,就会重复调用connectionProvider.release(connection),即出现上面的异常日志,并没有重试再去连接,而一直异常状态;

四层负载时F5 VS IP:9100 随Codis Proxy重启,而Java的Lettuce 可以感知到,连接被关闭;




















参数 四层负载 七层负载
validateConnection = false;
shareNativeConnection = true;(默认)
共享链接方式正常访问 共享链接方式不可以正常访问,报异常错误
validateConnection = false;
shareNativeConnection = false;
独享链接方式正常访问 独享链接方式正常访问


各位RD同学可读下源码分析一下,这里给一个网上分析链接:https://segmentfault.com/a/1190000016417906








03




总结







此问题有两种解决方案,一是七层负载修改成四层(这里由于是F5,支持这种应用层协议使用Standard 类型可以使用,Nginx无法使用七层代理这种非标准应用层协议,4层stream 可以),另一种修改Java使用lettuce连接池参数,禁止lettuce作者推荐的共享式,使用独立链接方式,连接池默认5个连接,使用完成,再重新创建。(由于我是运维,lettuce 源码读的不是精,如有错误,可以指点出来,在这里谢谢你)


郑重声明下非标准的应用层协议,一律推荐使用4层负载,不能使用七层负载,类似MySQL、Redis协议等,原因:Redis是应用层协议,但不能使用7层负载,一是因为负载转换器不可能实现这种私有的协议,二是因为这样一来会造成很多意想不到的错误,并且大部分七层反向代理服务器(软件)不支持这种操作,只有像F5这种硬件设备才支持。


附件 F5 四层负载配置图示

警惕!四层、七层负载乱用,Java lettuce连接池故障一例


附件 F5 七层负载配置图示

警惕!四层、七层负载乱用,Java lettuce连接池故障一例







您的关注是写作的动力

往期故障分享




往期K8S分享




推荐阅读
  • 服务器部署中的安全策略实践与优化
    服务器部署中的安全策略实践与优化 ... [详细]
  • 技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统
    技术分享:使用 Flask、AngularJS 和 Jinja2 构建高效前后端交互系统 ... [详细]
  • 在《Linux高性能服务器编程》一书中,第3.2节深入探讨了TCP报头的结构与功能。TCP报头是每个TCP数据段中不可或缺的部分,它不仅包含了源端口和目的端口的信息,还负责管理TCP连接的状态和控制。本节内容详尽地解析了TCP报头的各项字段及其作用,为读者提供了深入理解TCP协议的基础。 ... [详细]
  • 在Linux系统中,网络配置是至关重要的任务之一。本文详细解析了Firewalld和Netfilter机制,并探讨了iptables的应用。通过使用`ip addr show`命令来查看网卡IP地址(需要安装`iproute`包),当网卡未分配IP地址或处于关闭状态时,可以通过`ip link set`命令进行配置和激活。此外,文章还介绍了如何利用Firewalld和iptables实现网络流量控制和安全策略管理,为系统管理员提供了实用的操作指南。 ... [详细]
  • 小王详解:内部网络中最易理解的NAT原理剖析,挑战你的认知极限
    小王详解:内部网络中最易理解的NAT原理剖析,挑战你的认知极限 ... [详细]
  • 本文详细介绍了在 CentOS 7 系统中配置 fstab 文件以实现开机自动挂载 NFS 共享目录的方法,并解决了常见的配置失败问题。 ... [详细]
  • 本文介绍了如何利用HTTP隧道技术在受限网络环境中绕过IDS和防火墙等安全设备,实现RDP端口的暴力破解攻击。文章详细描述了部署过程、攻击实施及流量分析,旨在提升网络安全意识。 ... [详细]
  • 本文介绍了如何利用 `matplotlib` 库中的 `FuncAnimation` 类将 Python 中的动态图像保存为视频文件。通过详细解释 `FuncAnimation` 类的参数和方法,文章提供了多种实用技巧,帮助用户高效地生成高质量的动态图像视频。此外,还探讨了不同视频编码器的选择及其对输出文件质量的影响,为读者提供了全面的技术指导。 ... [详细]
  • 在CentOS 7环境中安装配置Redis及使用Redis Desktop Manager连接时的注意事项与技巧
    在 CentOS 7 环境中安装和配置 Redis 时,需要注意一些关键步骤和最佳实践。本文详细介绍了从安装 Redis 到配置其基本参数的全过程,并提供了使用 Redis Desktop Manager 连接 Redis 服务器的技巧和注意事项。此外,还探讨了如何优化性能和确保数据安全,帮助用户在生产环境中高效地管理和使用 Redis。 ... [详细]
  • 在对WordPress Duplicator插件0.4.4版本的安全评估中,发现其存在跨站脚本(XSS)攻击漏洞。此漏洞可能被利用进行恶意操作,建议用户及时更新至最新版本以确保系统安全。测试方法仅限于安全研究和教学目的,使用时需自行承担风险。漏洞编号:HTB23162。 ... [详细]
  • 负载均衡基础概念与技术解析
    随着互联网应用的不断扩展,用户流量激增,业务复杂度显著提升,单一服务器已难以应对日益增长的负载需求。负载均衡技术应运而生,通过将请求合理分配到多个服务器,有效提高系统的可用性和响应速度。本文将深入探讨负载均衡的基本概念和技术原理,分析其在现代互联网架构中的重要性及应用场景。 ... [详细]
  • java大数据量调优(超赞值得收藏)
    从总体上来看,对于大型网站,比如门户网站,在面对大量用户访问、高并发请求方面,基本的解决方案集中在这样几个环节: ... [详细]
  • LVS–基础–02–常用命令1、帮助命令ipvsadm--help2、添加虚拟服务器2.1、语法ipvsadm-A[-t|u|f][vip_addr:port][-s:指定算 ... [详细]
  • MFC控件——ListCtrl控件[翻译]
    元旦发帖,首先祝大家元旦快乐!声明:1、本文为翻译文章,水平有限,错误之处,烦请指正(china ... [详细]
  • 护墙_搭建LVS负载均衡NAT和DR模式
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了搭建LVS负载均衡NAT和DR模式相关的知识,希望对你有一定的参考价值。 ... [详细]
author-avatar
想挽回的-谎言
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有