写点什么

用 tcpdump 分析 Java 客户端的 prepare 行为

作者: pepezzzz 原文来源:https://tidb.net/blog/856d4cf6

一、背景

有实际的生产案例中,经常会出现应用开发等数据库用户认为的数据库行为和数据库的实际行为不一致的情况,这时通过网络抓包分析就是非常有效的方案。


本文用 tcpdump 和 wireshark 工具来复现和分析 Java 客户端的 prepare 操作在不同配置下与数据库交互过程中的不同行为。

二、操作过程

  • JAVA DEMO 代码

  • 数据库环境初始化

  • 开始抓包并使用 -w 保存为文件,执行结束后使用 ctrl-c 退出。


在本例中,客户端 IP 固定为 host 172.16.201.85 ,数据库服务端端口固定为 port 4500,两者结合组成监听条件。


[root@vm172-16-201-122 ~]# sudo tcpdump -i eth0  host 172.16.201.85 and port 4500 -w 85_4500_3tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes^C47 packets captured55 packets received by filter0 packets dropped by kernel
复制代码


  • 为防止抓包无内容,可以再开一个窗口同时将 -w 换成 -vv 查看实时信息输出。

  • 启用 Java 代码

  • 使用 wireshark 分析结果


wireshare 打开文件后,选择 4500 即 数据库的端口的通讯条目,右键选择 decode as …



将 4500 端口的通讯都解析为 mysql 协议,MySQL 协议内容转变为可见。



同时,可以用 tcpdump 查询语句 mysql.query contains “ 关键字 ”,查询关键 SQL 语句所在的位置。


三、分析结果

开启客户端句柄缓存

开启 useServerPrepStmts = true 后同时配置 cachePrepStmts = true,这会让客户端缓存预处理语句。


config.setJdbcUrl("jdbc:mysql://172.16.201.122:4500/test?characterEncoding=utf8&useSSL=false&useServerPrepStmts=true&cachePrepStmts=true&prepStmtCacheSqlLimit=10000&prepStmtCacheSize=1000&useConfigs=maxPerformance&rewriteBatchedStatements=true");
复制代码


每次的执行过程是 Prepare statement + 多次 Execute statement。


  • Prepare


客户端发送 prepare 语句请求



返回客户端 prepare 语句句柄和参数定义



  • {Execute statement}*10


后续过程客户端发送语句句柄和参数



返回客户端 Execute 语句结果


关闭客户端句柄缓存

useServerPrepStmts = true 能让服务端执行预处理语句,但默认情况下客户端每次执行完后会 close 预处理语句,并不会复用。


删除 &cachePrepStmts=true&prepStmtCacheSqlLimit=10000&prepStmtCacheSize=1000&useConfigs=maxPerformance


注意:需要一并删除 useConfigs=maxPerformance,它会配置多个参数,其中也包括 cachePrepStmts = true。


config.setJdbcUrl("jdbc:mysql://172.16.201.122:4500/test?characterEncoding=utf8&useSSL=false&useServerPrepStmts=true&rewriteBatchedStatements=true");
复制代码


每次的执行过程是 Prepare statement + Execute statement + Close statement。


  • Prepare statement



  • Execute statement



  • Close statement


服务端行为对比

对比以上两种交互方式的数据库服务端监控与抓包分析的现象一致。


第一时间段 07:42 ,开启客户端缓存。第二时间段 07:45 ,关闭客户端缓存。


Prepare 阶段 第二时间段数量高



Execute 阶段 两个时间段数量一致



Close 阶段 第二时间段数量高



第二阶段未能使用 plan cache (默认情况下 plan cache 在执行 close 后会释放)



可用的改善方法:服务端启用 tidb_ignore_prepared_cache_close_stmt 保留缓存。


启用后会忽略关闭 Prepared Statement 的指令,包括 Binary 协议的 COM_STMT_CLOSE 信号和文本协议的 DEALLOCATE PREPARE 语句都会被忽略。


下图中,第一次未启用 tidb_ignore_prepared_cache_close_stmt,第二次已启用。启用后,能实现在收到 close 后,下一条 SQL 仍能够命中服务端缓存。


TiDB 内部基于 SQL 语句的文本计算 hash 值,在没有客户端句柄的情况下,通过匹配 hash 命中 Plan Cache。代码位置如:https://github.com/pingcap/tidb/blob/67edd7d8f73de399bd72490d449d1dede1ee637b/pkg/planner/core/plan_cache_utils.go#L261


关闭服务端缓存

一旦使用 useServerPrepStmts=false(无论客户端是否缓存句柄),客户端就会关闭使用 plan cache 的行为,所有语句使用 Query 接口。


config.setJdbcUrl("jdbc:mysql://172.16.201.122:4500/test?characterEncoding=utf8&useSSL=false&useServerPrepStmts=false");
复制代码


  • Query statement



  • 服务端行为


使用 Query 无 plancache


四、总结

Java 的行为结果如下表:



同时可以参考文档: https://docs.pingcap.com/zh/tidb/stable/dev-guide-connection-parameters/


某 JAVA 应用的交易压测测试成绩:



通过本例,可以看出 tcpdump + wireshark 的过程可以有效地找出预期不一致时,实际双方是怎么交互的,对于故障分析有非常大的帮助。


发布于: 刚刚阅读数: 1
用户头像

TiDB 社区官网:https://tidb.net/ 2021-12-15 加入

TiDB 社区干货传送门是由 TiDB 社区中布道师组委会自发组织的 TiDB 社区优质内容对外宣布的栏目,旨在加深 TiDBer 之间的交流和学习。一起构建有爱、互助、共创共建的 TiDB 社区 https://tidb.net/

评论

发布
暂无评论
用 tcpdump 分析 Java 客户端的 prepare 行为_性能调优_TiDB 社区干货传送门_InfoQ写作社区