写点什么

巧用工具提升无源码系统的性能和稳定性

  • 2020-02-11
  • 本文字数:2999 字

    阅读完需:约 10 分钟

巧用工具提升无源码系统的性能和稳定性

导读:在没有核心系统源码的情况下,修改源码打印耗时的方法无法使用,通过 tcpdump、wireshark、gdb、010 editor、火焰图、ida、数据库抓 sql 耗时语句、oracle ash 报告、loadrunner 等工具找到了服务器 tps 上不去,C 程序进程随机挂掉的问题,并顺利解决,收获颇多。

背景

公司最近新上线一个系统,主要架构如下:


1557385732344055544.png


测试环境系统部署后,出现了两个问题:


1.loadrunner 压测 tps 上不去,压测 java 接口 tps 单机只能到 100 多 tps 就上不去了,耗时从单次访问的 100ms 上升到 110 并发时的 1s 左右。 2. 压测期间 C 服务器 1 经常不定时挂掉。


因为某些原因,该项目 C 相关程序没有源码,只有安装部署文件,为了解决上述两个问题,我们几个同事和重庆同事一块参与问题排查和解决。因为没有源码,中间经历了层层波折,经过一个月努力,终于解决了上述两个问题,整个排查过程学到了很多知识。

用到的分析工具

1.tcpdump,


2.wireshark,


3.gdb,


4.010 editor,


5.火焰图,


6.ida,


7.数据库抓 sql 耗时语句,


8.oracle ash 报告,


9.loadrunner

几句话总结

1.C 程序客户端 socket 长连接调用 C 服务端存在性能瓶颈,通过 tcpdump,wireshark 二进制分析出传输协议后改用 java 调用 C 服务端,单机 tps 提升 1 倍,性能提升 3 倍


2.数据库语句存在 for update 语句导致并发上不去,经过分析从业务上采用 sequence 替换 for update 语句,并通过 010 editor 直接修改二进制 修改 for update 语句相关逻辑为 sequence ,系统具备了扩容服务器 tps 也能同步提升的能力


3.数据库 insert 语句并发情况下存在瓶颈,扩大 oracle redo log 日志大小解决,继续提升 tps40%。


4.程序进程随机挂掉,通过 gdb 分析 core dump 文件,定位到在并发情况下程序中使用的 gethostbyname 有问题,采用临时方法解决。

分析过程

1.第一次瓶颈定位


刚开始排查问题时,loadrunner 压测 java 接口,并发用户从 0 逐渐增加到 110 个的情况下,tps 到 100 左右就不再提升,响应耗时从 100ms 增大到 1s。此时我们的分析重点是谁是当前的主要瓶颈


1557385749084086043.png


再看一遍架构图, 图中 5 个节点都有可能是瓶颈点,数据库此时我们通过数据库 dba 管理权限抓取耗时 sql,没抓取到,先排除数据库问题,java 的我们打印分步耗时日志,定位到 jni 调用 c 客户端耗时占比最大。这时瓶颈点初步定位到 C 客户端,C 服务端 1,C 服务端 2 这三个节点。


因为没有源码,我们采用 tcpdump 抓包分析,在 C 服务器 1 上


tcpdump   -i  eth0  -s  0   -w aa.txt  host  java客户端ip
复制代码


抓出的包用 wireshark 分析


1557385770945013038.png


通过追踪流-TCP 流 分析服务端耗时并没有变的太大,因为 C 客户端和 C 服务端是长连接,多个请求可能会共用一个连接,所以此时分析出的数据可能会不太准,因此我们采用 loadrunner 压测,其它条件不变,一台 C 服务器 1 和两台 C 服务器 1 分别查看耗时变化,


其它条件不变,一台 java 服务器和两台 java 服务器分别查看耗时变化.


最终定位到是 C 客户端的问题。(ps:在 wireshark 的分析数据时还跟秦迪大师弄明白了 tcp 延迟确认)


2.改造 C 客户端


C 客户端和 C 服务端是通过长连接通信的,直接改造 C 代码难度较大,所有我们准备把 C 替换成 java,这就需要分析 C 之间通信传参时候用的什么协议,然后根据这个协议用 java 重写。我们根据之前的经验推测出了编码协议,用 wireshark 分析二进制确认确实是这种编码。


1557385794505066716.png


我们根据这种协议编码采用 java 重写后,同样在 110 并发用户情况下,tps 提升到了 210(提升两倍),耗时降到了 330ms(是原来的三分之一)


3.第二次瓶颈定位。


经过第二步优化后 tps 提升了两倍,但是此时扩容 tomcat,扩容 C 服务器,tps 就维持在 210 左右,不会变高了。因此我们继续进行定位新的瓶颈点。此时找 dba 要到一个实时查看 oracle 耗时 sql 的语句


select
(select b.SQL_TEXT from v$sqlarea b where b.SQL_ID=a.SQL_ID ) sqltxt,
(select c.SQL_FULLTEXT from v$sqlarea c where c.SQL_ID=a.SQL_ID ) sqlfulltxt,
a.username, a.LAST_CALL_ET,a.MACHINE ,a.command, a.EVENT, a.SQL_ID ,a.SID,a.SERIAL#,
'alter system kill session ''' || a.SID ||','||a.SERIAL# ||''';' as killstment
from v$session a
where a.STATUS = 'ACTIVE'
and a.USERNAME not in ('SYS', 'SYSTEM')
order by
a.LAST_CALL_ET desc ,a.username,a.MACHINE ,a.command, a.EVENT, a.SQL_ID ,a.SID;
复制代码


发现有个 for update 的 sql 并发量大的时候部分请求 LAST_CALL_ET 列的值能达到 6 秒,for update 导致了所有请求被串行执行,影响了并发能力。我们经过分析业务逻辑后,用 sequence 暂时替换 for update 语句,但是我们没有源码,没法修改,后来又通过 010 editor 直接修改二进制文件,通过 010 editor 查询找到了 for update 语句,顺利替换。


替换后,4 台 C 服务器 tps 达到了 580,提升了 2.7 倍(580/210),系统初步具备了横向扩展能力


4.第三次瓶颈定位。


经过上一步改造,4 台 C 服务器时系统的 tps 提升了 2.7 倍,但是并没有提升到 4 倍(210*4=840),没有线性提升,说明还是有别的瓶颈,又通过 dba 上边给的 sql 发现 insert 语句偶尔耗时也很长,在 1s 左右,EVENT 等待事件是 IO 事件,DBA 同事给修改了 redo log file 大小(这个是测试环境 Oracle,之前没有优化),从默认的 50M,修改为 1G, tps 提升到了 640 (还没提升到 4 倍,也就是说还有瓶颈,可能还是数据库,但因为数据库暂时没办法抓取到毫秒级的耗时 sql,没再继续追查)


经过这几次性能提升,加上我们测试服务器配置都不高,如果线上服务器性能预估能达到 1000tps,基本满足眼前需求,因此就没再继续进行性能优化。


5.程序进程随机挂掉问题。


压测过程中,C 服务器进程经常随机挂掉,通过 tail -f /var/log/messages 发现生成了 core dump 文件,但是又被系统自动删除了。董建查到了开启 core dupm 文件的方法,如下:


a、ulimit -c


查看是否为 0,如果为 0,表示 coredump 文件设置为 0,需要修改为不限制


ulimit -c unlimited
复制代码


b、修改/etc/abrt/abrt-action-save-package-data.conf


ProcessUnpackaged = yes
复制代码


修改后进程又崩溃时 core dump 文件生成了,进入 core dump 目录进行调试


gdb 脚本路径 coredump


bt 显示堆栈信息


1557385818730041636.png


继续执行如下命令


f 0


1557385940619005067.png


set print pretty on
info local //显示当前函数中的局部变量信息。
复制代码


1557385958240060013.png


通过 p 命令查看里边变量的值


1557385972529098668.png


发现变量 thishost->h_addr_list 的值为 null


我们分析可能是并发请求时有方法不是线程安全的导致这个值为 null,从而引起了进程 crash,继续调试。


在 gdb 中 set logging on 把调试信息输出到文件


1557385988259045673.png


thread apply all bt 输出所有的线程信息。


退出 gdb


grep --color -i clientconnect -C5 gdb.txt
复制代码


1557386019141074009.png


确实有两个线程并发在访问


1557386229214033131.png


通过 ida 工具反编译 so,最终定位到以下语句在并发时有问题,thishost 中的变量可能会被另一个线程在一瞬间初始化为 null。


thishost = gethostbyname((const char *)hostname);
ip = inet_ntoa(*(struct in_addr *)*thishost->h_addr_list);
复制代码


根据我们的项目特点,因为我们没有远程调用,C 服务端 1 和 C 服务端 2 都部署在了同一台服务器上,所以我们通过修改二进制把地址暂时写死成了 127.0.0.1,把 ip = inet_ntoa(*(struct in_addr _)_thishost->h_addr_list);修改成了空指令,重新部署后没再出现系统崩溃的问题。


本文转载自宜信技术学院网站。


原文链接:http://college.creditease.cn/detail/245


2020-02-11 17:43707

评论

发布
暂无评论
发现更多内容

KunlunBase的Fullsync高可用机制简介

KunlunBase昆仑数据库

国产数据库

KunlunBase 0.9.1版本Sysbench性能测试报告

KunlunBase昆仑数据库

国产数据库

ORACLE进阶(十四)转义字符讲解

No Silver Bullet

oracle delete 转义字符 7月月更 TRUNCATE

Pyecharts结合Pandas绘制图表

迷彩

数据分析 数据可视化 7月月更

自助洗车加盟一般多少加盟费?

共享电单车厂家

自助洗车加盟 自助洗车品牌 车白兔自助洗车

KunlunBase功能之insert/update/delete...returning语句

KunlunBase昆仑数据库

国产数据库

小数据量用户场景使用KunlunBase的价值

KunlunBase昆仑数据库

KunlunBase对MySQL私有DML语法的支持

KunlunBase昆仑数据库

国产数据库

商品管理功能越来越丰富,不愧是 Pro 系统!

CRMEB

KunlunBase 指导手册(一)快速安装手册

KunlunBase昆仑数据库

国产数据库

KunlunBase指导手册(二)对等部署最佳实践

KunlunBase昆仑数据库

国产数据库

KunlunBase指导手册(四)从 Oracle 实时同步数据到 KunlunBase

KunlunBase昆仑数据库

国产数据库

什么是“企业级”低代码?成为企业级低代码必须具备的5种能力

优秀

低代码 企业级低代码平台

AITSM:看人工智能如何重塑IT服务管理

云智慧AIOps社区

人工智能 运维 安全 监控 IT管理

Kunlun-Storage vs PostgreSQL OLTP 测试

KunlunBase昆仑数据库

国产数据库

昆仑数据库 MySQL 连接协议简介

KunlunBase昆仑数据库

国产数据库

KunlunBase 读写分离方案

KunlunBase昆仑数据库

美团二面:为什么Redis会有哨兵?

Java全栈架构师

Java redis 程序员 面试 后端

共享自助洗车是车主自己洗吗?

共享电单车厂家

共享自助洗车 自助洗车加盟 车白兔自助洗车

面试官:Linux操作系统里一个进程最多可以创建多少个线程?

Java全栈架构师

程序员 多线程 操作系统 计算机 java面试

心寄开源,合规护航!2022 开放原子全球开源峰会开源合规分论坛即将开幕

kk-OSC

开源 开源峰会 开放原子全球开源峰会 开源合规

SAP Fiori @OData.publish 注解的工作原理解析

汪子熙

SAP Fiori SAP UI5 ui5 7月月更

性能测试中的随机数性能问题探索

FunTester

华为云张修征:将金融作为战略投入的重点行业,助力中国金融机构数字化升级

科技热闻

连续4周上榜的这位开发者,活出了当代大学生该有的样子

OpenI启智社区

深度学习 开源 大学

腾讯一面:内存满了,会发生什么?

程序员小毕

程序员 腾讯 面试 程序人生 计算机

无人自助洗车项目如何?好不好做

共享电单车厂家

自助洗车加盟 车白兔自助洗车 无人自助洗车项目

阿里内网GC面试小册,仅7天Github获赞96.9K

程序知音

Java 阿里巴巴 程序员 后端 JVM

自助洗车更轻松更自在的洗车方式

共享电单车厂家

自助洗车 自助洗车加盟 车白兔自助洗车

A tour of gRPC:04 - gRPC unary call 一元调用

BUG侦探

gRPC RPC protocolBuffer

KunlunBase指导手册(三)数据导入&同步

KunlunBase昆仑数据库

国产数据库

巧用工具提升无源码系统的性能和稳定性_行业深度_杨振、董建_InfoQ精选文章