[原创]TCP的backlog导致的HBase访问超时问题排查(续)

本文涉及的产品
传统型负载均衡 CLB,每月750个小时 15LCU
应用型负载均衡 ALB,每月750个小时 15LCU
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: 接前一篇文章 TCP的backlog导致的HBase超时问题 https://yq.aliyun.com/articles/117801?spm=5176.8091938.0.0.kypXIC ##问题场景 ![1.jpg](http://ata2-img.cn-hangzhou.img-pub.aliyun-inc.com/9fda470aa6727587b15909e9a0

接前一篇文章
TCP的backlog导致的HBase超时问题
https://yq.aliyun.com/articles/117801?spm=5176.8091938.0.0.kypXIC

问题场景

1.jpg

如上图所示,用户业务服务器(ApplicationServer)上面发起HTTP GET/PUT请求,经过SLB到达后端服务器(HBase-Rest-Server), 一般请求链路耗时大概100ms左右,但是会有一定的概率出现耗时很长(超过3s)。

业务方提出问题:

1.为什么slb到ecs连接多
2.为什么过slb后耗时多了2s多

排查分析过程

  1. 首先查询slb http层访问日志, 发现有很多超过3秒的访问请求,包括put 和get方法, 其记录表明slb 访问业务ECS得到处理结果时间较长, 可以判断出耗时较长的原因可能是在后端网络或ECS服务处理上.因为业务ECS HBase并没有记录每条访问请求的处理时间,所以不能排除服务本身处理的耗时.
    另外分析日志还存在有与业务ECS 5秒不能建立连接成功请求, 这一般可能是后端服务不稳定或服务器没做优化会出现此情况
  2. 网络同事查看业务ECS 发现有TCP: time wait bucket table overflow内核日志提示, 证明业务ECS没有做TIME_WAIT内核参数的优化;
  3. 网络同事抓包后发现有一些syn报文重传情况,从网络同事处拿到报文后分别用(tcp.analysis.retransmission), (tcp.flags.syn==1)&&(tcp.analysis.retransmission)过滤发现5分钟内有3329条syn报文的重传,且重传时间都是3秒.

2.png

备注:

linux 2.6.32 内核 TCP_TIMEOUT_INIT 3秒是syn报文第一次重传默认规定时间

linux 3.10内核 TCP_TIMEOUT_INIT 1秒是syn报文第一次重传默认规定时间.

到此问题比较明确是TCP建立连接失败, 不断重传SYN报文引起延时, 为了证明让在业务ECS上用nstat以下命令查看一下建立连接失败的统计和建立连接队列是否存在溢出.

3.png

果然发现执行结果TcpAttemptFails 偶尔非0, TcpExtListenOverflows有10多的值出现.

关于连接数量的分析:

查看用户slb实例前端流量与连接状态图,可知每秒平均259条新建连接

4.png

业务服务器两台, 从上边nstat输出观察可知每台每秒约100-130条TcpPassiveOpens连接,两台的和值与前端连接数量符合.

问题解决建议

给出业务ECS端建立连接失败优化调整建议:
net.ipv4.tcp_max_syn_backlog = 16384 原默认值1024

net.core.somaxconn = 65535 原默认值128

服务器程序中listen backlog = 8191

tw参数:
net.ipv4.tcp_tw_reuse改成1

net.ipv4.tcp_max_tw_buckets增加一倍,改为10000

tcp_fin_timeout 调低吧 15秒

但调整后还是发现有耗时3秒的情况, 随后调查HBase服务发现jetty默认backlog 50, 没有做修改, 修改后耗时较长现象消除.

下边属于上述参数内核代码部分分析

建立连接半连接与全连接队列

内核参数somaxconn,sysctl_max_syn_backlog 和listen backlog参数之间的关系分析

要搞清楚内核中与建立连接有关tcp_max_syn_backlog,somaxconn两个参数的作用,需要细化说明tcp建立连接阶段两个队列的含义:
linux内核中用struct request_sock_queue -> struct listen_sock->struct request_sock结构存储当前正在请求建立连接的sock,称作半连接状态(用syn_backlog表示)。request_sock有个成员变量指针指向对应的struct sock。struct request_sock_queue中rskq_accept_head和rskq_accept_tail分别指向已经建立完连接的request_sock,称作全连接状态(用backlog表示),这些sock都是完成了三次握手等待程序调用accept接受连接。半连接队列在内核中的具体的变量是:
inet_csk(sk)->icsk_accept_queue-> listen_opt
使用了以下两个变量维护半连接队列长度:

已使用队列长度 inet_csk(sk)->icsk_accept_queue->qlen
最大队列长度限制 icsk_accept_queue->listen_opt->max_qlen_log (即长度限制2^ max_qlen_log)

全连接队列在内核中的表示:

request_sock_queue结构中使用rskq_accept_head和rskq_accept_tail维护了全连接队列。inet_csk(sk)->icsk_accept_queue->rskq_accept_head
inet_csk(sk)->icsk_accept_queue->rskq_accept_tail

使用了以下两个变量维护全连接队列长度

unsigned short sk_ack_backlog;    //(全连接队列)可接受连接队列,使用过程中队列的计数
unsigned short sk_max_ack_backlog;    //(全连接队列)最大的可接受连接队列,默认值是listen时设置的backlog参数

服务器端程序通过listen函数设置监听端口 backlog参数,内核理论上将允许该端口最大同时接收2*backlog参数个并发连接“请求”(不含已被应用程序接管的连接)——分别存放在 syn_backlog 和 backlog 队列——每个队列的最大长度为backlog值(为什么是最大还取决于内核参数稍后解释)。syn_backlog 队列存储 SYN_ACK 状态的连接,backlog 则存储 ESTABLISHED 状态但尚未被应用程序接管的连接。accept系统调用时将从全连接backlog队列的rskq_accept_head取出head节点req请求,并从此队列中移除,具体的实现可以参考内核中的tcp_check_req()函数,此函数调用完成后也将握手完成后的连接放入了ehash散列表,就与连接阶段的两个队列没有关系了。

内核参数somaxconn,sysctl_max_syn_backlog 和listen backlog参数之间的关系分析
这部分的分析有兴趣的可以查看内核中SYSCALL_DEFINE2(listen, int, fd, int, backlog)和reqsk_queue_alloc()函数的实现。

listen()参数backlog,内核参数somaxconn, 内核参数tcp_max_syn_backlog中最小值加1后,向上扩展为2整数次幂后 做为半连接队列的长度。代码的实现如下:

if ((unsigned)backlog > somaxconn)//listen调用的backlog大于somaxconn则取两者之小值
    backlog = somaxconn;
nr_table_entries = min_t(u32, backlog, sysctl_max_syn_backlog);//取与max_syn_backlog之最小值
nr_table_entries = max_t(u32, nr_table_entries, 8);// nr_table_entries小于8时取为8
nr_table_entries = roundup_pow_of_two(nr_table_entries + 1); //roundup_pow_of_two - round the given value up to nearest power of two 作用是:计算出最接近2的n次方并且大于size的值即向上扩展为2整数次幂
最终nr_table_entries的值就是半连接队列的长度。

listen()参数backlog,内核参数somaxconn取二者的最小值做为全连接队列的长度。

if ((unsigned)backlog > somaxconn)//listen调用的backlog大于somaxconn则取两者之小值backlog = somaxconn;
sk->sk_max_ack_backlog = backlog;
相关实践学习
lindorm多模间数据无缝流转
展现了Lindorm多模融合能力——用kafka API写入,无缝流转在各引擎内进行数据存储和计算的实验。
云数据库HBase版使用教程
  相关的阿里云产品:云数据库 HBase 版 面向大数据领域的一站式NoSQL服务,100%兼容开源HBase并深度扩展,支持海量数据下的实时存储、高并发吞吐、轻SQL分析、全文检索、时序时空查询等能力,是风控、推荐、广告、物联网、车联网、Feeds流、数据大屏等场景首选数据库,是为淘宝、支付宝、菜鸟等众多阿里核心业务提供关键支撑的数据库。 了解产品详情: https://cn.aliyun.com/product/hbase   ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
4月前
|
DataWorks 数据管理 大数据
DataWorks操作报错合集之在连接HBase时出现超时问题,该怎么解决
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
|
6月前
|
分布式计算 分布式数据库 API
Spark与HBase的集成与数据访问
Spark与HBase的集成与数据访问
|
6月前
|
存储 分布式计算 Hadoop
HBase的数据访问是如何进行的?
HBase的数据访问是如何进行的?
75 0
|
存储 分布式计算 安全
javaapi 访问 hbase
javaapi 访问 hbase
142 0
|
监控 分布式数据库 Hbase
《HBase in Practise 性能、监控和问题排查》电子版地址
HBase in Practise: 性能、监控和问题排查
118 0
《HBase in Practise 性能、监控和问题排查》电子版地址
|
缓存 网络协议 算法
计算机网络学习26:TCP/UDP对比区别、TCP流量控制、拥塞控制、超时重传时间的选择、可靠传输的实现
UDP: User Datagram Protocol 用户数据报协议 TCP: Transmission Control Protocol 传输控制协议 同时这里指的连接是指逻辑连接,而不是物理连接。
计算机网络学习26:TCP/UDP对比区别、TCP流量控制、拥塞控制、超时重传时间的选择、可靠传输的实现
|
算法 Java 大数据
访问HBase经常出现报错:ServerNotRunningYetException: Server xxx.xxx.xxx is not running yet
访问HBase经常出现报错:ServerNotRunningYetException: Server xxx.xxx.xxx is not running yet
|
XML 弹性计算 Shell
HBase Shell 访问|学习笔记
快速学习 HBase Shell 访问
|
分布式计算 Java Hadoop
HBase集群搭建记录 | 云计算[CentOS8] | Maven项目访问HBase(下)
step3. 使用eclipse打开maven项目并配置 step4. 项目访问HBase
210 0
HBase集群搭建记录 | 云计算[CentOS8] | Maven项目访问HBase(下)
|
Java Linux 分布式数据库
HBase集群搭建记录 | 云计算[CentOS7] | Maven项目访问HBase(上)
写在前面 step1 Maven的下载与配置 1. 下载解压 2. 环境变量设置 3. 查看安装 4. 设置阿里云镜像[加速jar包下载] step2 Maven项目的创建 1.创建项目 2. 编译项目 3.测试项目 4.打包项目 5.安装项目
188 0
HBase集群搭建记录 | 云计算[CentOS7] | Maven项目访问HBase(上)