南大通用数据库-Gbase-8a-学习-43-SQL长时间处于Writing to net状态排查

目录

一、问题截图

二、排查思路

[1、Gbase8a SQL有几种状态](#1、Gbase8a SQL有几种状态)

2、问题导致原因猜想

3、观察服务端(集群端)网络情况

4、观察客户端网络情况

5、排查客户端程序处理数据慢

5.1、send

(1)声明

(2)作用

(3)参数

(4)返回值

(5)阻塞条件

5.2、recv

(1)声明

(2)作用

(3)参数

(4)返回值

(5)阻塞条件

5.3、优化思路

6、查看计算节点

7、gccli执行SQL

8、调整参数max_allowed_packet


一、问题截图

今天我发现一个有趣的现象,用户执行一条长达17287秒(差不多5小时)的SQL,这个SQL并没有特别复杂,我用红箭头指出了特殊点:

1、SQL处于Writing to net状态。(这个状态持续了4个多小时)

2、查询的是INFORMATION_SCHEMA.COLUMNS系统表。

3、没有加过滤条件。

二、排查思路

1、Gbase8a SQL有几种状态

|----------------------------------------------|-----------------------|
| 状态 | 含义 |
| init | 表示SQL进入准备执行阶段,开始执行计划。 |
| deleting from main table/updating main table | 准备对主表进行删除或更新操作。 |
| end/query endSQL | SQL到达结束状态,准备清理资源。 |
| Creating tmp table | 查询过程中,正在创建临时表。 |
| Sending data | 读取数据向发起段发送查询结果。 |
| closing tables | 关闭打开的表。 |
| Evaluating | 执行计划评估。 |
| Executing by step | 执行计划中的每一步。 |
| Preparing metadata | 取得本查询所涉及表的可用节点信息。 |
| Sending task to gnodes | 发送任务给数据节点。 |
| Clear tmp tables | 查询完成,开始清理临时表。 |
| Writing to Net | 向客户端发送数据包。 |
| checking permissions | 检查权限。 |
| commit | 提交数据。 |
| killed | 被杀死。 |
| logging slow query | 审计日志在保存慢SQL信息。 |
| Rolling back | 数据回滚。 |

2、问题导致原因猜想

我们看到了Writing to Net的意思是向客户端发送数据包,会不会是网络的问题导致。我们可以提出一下几个猜想。

|------------|---------|
| 猜想 | 是否为问题原因 |
| 服务端网络负载高 | 未验证 |
| 客户端网络负载高 | 未验证 |
| 客户端程序处理数据慢 | 未验证 |

3、观察服务端(集群端)网络情况

Writing to Net的意思是向客户端发送数据包。会不会是网络负载较高,我这边是万兆网卡,理论可以达到10000Mbit/s,1Mbit(兆位) = 0.125Mb(兆字节),也就是1250Mb/s,nmon观察网络情况在33Mb/s上下浮动,排除是服务端网络问题。

|------------|---------|
| 猜想 | 是否为问题原因 |
| 服务端网络负载高 | 否 |
| 客户端网络负载高 | 未验证 |
| 客户端程序处理数据慢 | 未验证 |

4、观察客户端网络情况

客户端服务器我这边没有权限,只能建议客户帮忙排查了,哈哈哈。

|------------|----------------|
| 猜想 | 是否为问题原因 |
| 服务端网络负载高 | 否 |
| 客户端网络负载高 | 权限问题,建议客户帮忙验证。 |
| 客户端程序处理数据慢 | 未验证 |

5、排查客户端程序处理数据慢

为什么我会有这样的想法呢,最近在学习网络编程相关的知识,会不会客户端程序处理逻辑有关,相关概念可以参考之前的博客《Unix环境高级编程-学习-05-TCP/IP协议与套接字》,服务端send数据,客户端recv数据,我们来简单介绍一下这两个函数,以及他们的阻塞条件。

5.1、send

(1)声明
cpp 复制代码
ssize_t send(int __fd, const void *__buf, size_t __n, int __flags)
(2)作用

向套接字__fd所指向的地址发送缓冲区__buf中长度为__n的数据。

(3)参数

|---------|-----------------|
| 参数名 | 描述 |
| __fd | 套接字文件描述符。 |
| __buf | 缓冲区。 |
| __n | 发送的数据长度。 |
| __flags | 标志,这个在具体在其他篇幅讲。 |

(4)返回值

|----|-----------|
| 名称 | 描述 |
| 成功 | 返回发送的字节数。 |
| 失败 | -1 |

(5)阻塞条件

当要发送的消息长度大于套接字当前可用缓冲区时, send将阻塞。

5.2、recv

(1)声明
cpp 复制代码
ssize_t recv(int __fd, void *__buf, size_t __n, int __flags);
(2)作用

从套接字__fd接收长度为__n的数据放入缓冲区__buf中。

(3)参数

|---------|-----------------|
| 参数名 | 描述 |
| __fd | 套接字文件描述符。 |
| __buf | 缓冲区。 |
| __n | 接收的数据长度。 |
| __flags | 标志,这个在具体在其他篇幅讲。 |

(4)返回值

|----|-----------|
| 名称 | 描述 |
| 成功 | 返回接收的字节数。 |
| 失败 | -1 |

(5)阻塞条件

recv函数会一直阻塞到接收缓冲区里有一个字节或一个完整的UDP数据报为止。

5.3、优化思路

我们平时一般的开发思路是单进程单线程从缓冲区中接收到数据,开始处理数据,处理完发送消息给服务端我收到消息,发送端再发数据,如果处理数据时间较长,是不是可能会出现类似状况呢。

如果需要改进,我的思路是开启两个线程,一个线程用于接收数据并将数据放入一个队列中,放入之后和客户端说我收到数据了,另一个线程从队列中拿数据进行处理,这样就不会一直等待。

6、查看计算节点

之前查看了一下计算节点,发现没有类似任务,刚开始还觉得这是都算完了,后来想了想,计算节点就不会有这个任务,因为管理节点和计算节点的DDL是同步的,只需要在拿到任务的管理节点计算即可。也不是个别计算节点慢导致的。

7、gccli执行SQL

我们可以用Gbase8a自带的客户端工具gccli放到本地来执行SQL,gccli具体使用方法可以参考之前的博客《南大通用数据库-Gbase-8a-学习-32-gccli客户端》,这样可以屏蔽网络的问题。

我手动执行了一下,差不多两分钟左右,gccli没有额外的数据处理过程,只是将数据fetch出来进行展示,上面程序处理慢的问题概率又大了几分。

|------------|----------------|
| 猜想 | 是否为问题原因 |
| 服务端网络负载高 | 否 |
| 客户端网络负载高 | 权限问题,建议客户帮忙验证。 |
| 客户端程序处理数据慢 | 有一定可能。 |

8、调整参数max_allowed_packet

参数适当调大后,效果不明显,已经调回原值。

|------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 说明 | 通信时最大的包长度。即服务器和客户端通讯时,发送和接收的数据包或字符串的最大长度。 |
| 默认值 | 64 * 1024 * 1024(单位:字节) |
| 最小值 | 1024(单位:字节) |
| 最大值 | 4L*1024L*1024L*1024L(单位:字节) |
| 详细介绍 | 1、设定单个报文或任何中间字符串(intermediate string)的最大长度,单位是字节。 2、报文消息缓冲由 net_buffer_length 参数进行设定,一般情况下,数据包的通讯缓冲区初始化为 8K字节 。 但其最终可以按需增长至max_allowed_packet 参数设定的大小。 3、这个参数值一般不需要设置的太大。较小的通讯缓冲区设置值可以捕获大的数据包,而那些大的数据包通常是由于异常引起的。 4、此参数的默认值较小,在使用了 BLOB 列或长字符串的场景中,应该增大其值至能容纳最大 BLOB 数据的长度。协议本身限定此值最大为 1G,参数只接受 1024 整数倍的数值,非 1024 的整数倍将会被自动圆整至离其最近的1024 整数倍的数值。 |

相关推荐
Forest_HAHA33 分钟前
<8>-MySQL复合查询
数据库·mysql
Chef_Chen34 分钟前
从0开始学习R语言--Day22--km曲线
学习
march of Time41 分钟前
图数据库介绍及应用,go和Java使用图数据库
java·数据库·golang
委婉待续43 分钟前
Qt的学习(三)
开发语言·qt·学习
白总Server1 小时前
Golang实现分布式Masscan任务调度系统
java·运维·服务器·开发语言·分布式·后端·golang
大博bs1 小时前
使用HashMap或者List模拟数据库插入和查询数据
数据库·list
leo03081 小时前
新一代python管理工具--uv
开发语言·python·uv
袋鼠云数栈1 小时前
从SQL Server到分布式大数据平台:重构企业数据架构
大数据·分布式·sql·重构·数据库架构
熊猫钓鱼>_>1 小时前
Python小工具开发实战:从零构建自动化文件管理器的心得与体悟
开发语言·python·自动化
lb29171 小时前
关于golang热加载安装,实时响应
开发语言·后端·golang·热加载