南大通用数据库-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 整数倍的数值。 |

相关推荐
StayInLove几秒前
G1垃圾回收器日志详解
java·开发语言
TeYiToKu2 分钟前
笔记整理—linux驱动开发部分(9)framebuffer驱动框架
linux·c语言·arm开发·驱动开发·笔记·嵌入式硬件·arm
dsywws5 分钟前
Linux学习笔记之时间日期和查找和解压缩指令
linux·笔记·学习
道法自然04025 分钟前
Ethernet 系列(8)-- 基础学习::ARP
网络·学习·智能路由器
lzhlizihang8 分钟前
【Hive sql 面试题】求出各类型专利top 10申请人,以及对应的专利申请数(难)
大数据·hive·sql·面试题
无尽的大道8 分钟前
Java字符串深度解析:String的实现、常量池与性能优化
java·开发语言·性能优化
互联网打工人no19 分钟前
每日一题——第一百二十四题
c语言
爱吃生蚝的于勒12 分钟前
深入学习指针(5)!!!!!!!!!!!!!!!
c语言·开发语言·数据结构·学习·计算机网络·算法
羊小猪~~15 分钟前
数据结构C语言描述2(图文结合)--有头单链表,无头单链表(两种方法),链表反转、有序链表构建、排序等操作,考研可看
c语言·数据结构·c++·考研·算法·链表·visual studio
binishuaio21 分钟前
Java 第11天 (git版本控制器基础用法)
java·开发语言·git