应用反应业务慢, 怀疑是数据库问题, 应用DEBUG日志看到事务执行时间为 800+ms
业务SQL为简单SQL语句, 相关表均有主键, 数据量也不大.
作为DBA, 首先要排除数据库问题.
1. 使用如下SQL, 查询执行时间长的会话
select * from information_schema.processlist where command !='Sleep' and TIME > 0 and INFO is not NULL;
发现没有....
2. 解析binlog寻找大事务.
脚本可以参考之前写的那个: https://cloud.tencent.com/developer/article/2387420 都是1s 以内.... binlog记录的时间戳是秒级别的(取整) 而且看不到select语句... 注意: gtid_event的时间是事务提交时间. 所以可以选择取第一个table_map_event时间为事务开始时间.
3. 抓包
本来准备开general log的, 但是看不到返回包的时间..
所以写个脚本抓包吧. 脚本可以参考之前的审计脚本
我这里就使用之前的压测工具来模拟业务SQL
使用如下命令开启抓包. 脚本见文末
python monitor_trx.py 3314 > /tmp/t20240221_trx.xlsx
使用如下命令开始压测/模拟
python benchmysqlByddcw.py benchmysqlByddcw.yaml
然后将抓包出来的数据放入到excel中打开,
计算一个事务开始, 到收到服务端回包的时间: 0.029779911041259766 大概29ms
与我们的压测结果的平均延迟吻合.
如果这个值很小, 但客户端看到的很大, 就大概率是网络问题, 或者应用问题
4. 应用服务器ping数据库服务器
使用ping命令查看延迟. 如果延迟也很小的话, 那就是应用的问题了. 就是应用去排除.
5. 应用排查
检查业务逻辑, 是否存在非数据库等待. (比如IO等待)
应用访问慢的问题, 得一点点排查.
基本上就是那么几个信息, CPU, 内存, IO, 网络. 通常OLTP不存在CPU问题, IO/网络问题 多一些. 反正就是一步步排查.
抓包脚本参考如下: (不支持SSL流量, 应用一般也不会使用SSL连接数据库)
#!/usr/bin/env python3
#write by ddcw @https://github.com/ddcw
import socket,struct
import time
import sys,os
def mmysql_pak(port):
s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0800))
try:
while True:
packet = s.recvfrom(65565)[0] #(bytes, address)
ip_header = struct.unpack('!BBHHHBBH4s4s', packet[14:34]) #IP PRO
source_ip,dest_ip = socket.inet_ntoa(ip_header[8]),socket.inet_ntoa(ip_header[9])
iph_length = (ip_header[0] & 0xF) * 4
if ip_header[6] == socket.IPPROTO_TCP: #ONLY FOR TCP
tcp_header = struct.unpack('!HHLLBBHHH', packet[14+iph_length:14+iph_length+20]) #TCP PRO
source_port,dest_port = tcp_header[0],tcp_header[1]
tcp_length = (tcp_header[4] >> 4) * 4
data_offset = 14 + iph_length + tcp_length
data = packet[data_offset:]
if dest_port == port and data:
print(f"C2S\t{source_ip}:{source_port}<-->{dest_ip}:{dest_port}\t{time.time()}\t{struct.unpack('<B',data[3:4])[0]}\t{data[5:30]}")
if source_port == port and data:
print(f"S2C\t{dest_ip}:{dest_port}<-->{source_ip}:{source_port}\t{time.time()}\t{struct.unpack('<B',data[3:4])[0]}\t{data[5:17]}")
except KeyboardInterrupt:
pass
finally:
s.close()
if __name__ == "__main__":
if len(sys.argv) == 2:
port = int(sys.argv[1])
elif len(sys.argv) == 1:
port = 3314
else:
print(f"python3 {sys.argv[0]} PORT")
sys.exit(1)
print("TYPE\tHOST\tTIMESTAMP(s)\tSEQ\tCOMMAND/PACK")
mmysql_pak(port)
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。