门窗软件2015版性能提升

Author Avatar
Moon 4月 17, 2018

随着用户数量的日益增长,新格尔的王牌软件——门窗软件2015的网络版越来越卡。这就导致最近售后天天被客户追得团团转,于是我临危受命——门窗软件 2015 版性能提升!
啥都不说了,撸起袖子,就是一个字——干!
大家退后,我要开始装逼了!什么负载均衡、读写分离、内存、缓存统统给我来一套!什么存储过程、联表、子查询统统给我优化掉!整站 Ajax、PHP 内核原理搞起来,内存分配能省则省,都给我当黄金来用!……
啪、啪、啪,观众的烂番茄把我打醒了~好了,该从哪儿下手呢?咱不能凭想当然就优化性能哇,总得来点科学理论指导下实践吧?
病急不能乱投医,我们还是先来给这位“病人”按部就班,进行诊断:

诊断性能瓶颈

Nginx 日志排查

哇,这里有位病人手拿两把锟斤拷,嘴里喊着烫烫烫,让我们来看看他的病情:
通过查询“生态圈”系统,我很快找到了他家软件所在的 web 服务器,由于 log 没有入分析系统,所以我们只能拿 raw log 来分析了。
好在这家客户的 log 是 json 格式的,为了方便分析,随手撸段代码先导入数据库再说!(之后还碰到很多客户是最原始的 nginx log 格式,我用了正则表达式从 log 中提取有用信息)

啧啧,果然这时候有一个请求用了 11.135s 之久!看来病情是真的严重,那就让我们看看他这 3 分钟里到底做了什么“不可告人”的事情,竟让上天如此惩罚他(特别申明:我没有窥私癖……):

什么?!他是个“清白”的人,难道是上天惩罚错了人……那一定是前世的孽缘……
醒醒~回到正题,我们通过分析上面两张图,得出这样的结论:“病人”在查询的时候,数据库并没有写操作,换句话说,数据库并没有锁表或者锁行。这么看来,做读写分离并没什么卵用。
仔细想想也是这么个道理:我们的用户多数是中小企业,规模可能在几人到几十人之间,在办公室里操作电脑的就更少了。而现在的架构,是一家客户一个独立数据库,所以对一个 schema 来说,并发操作的可能性不大,所以发生死锁的情况可以忽略不计。

调取 RDS 监控

上面排除了一种可能,那么到底是什么原因导致这个“病人”呻吟得如此销魂呢?在我们 OP 领导的协助下,我们打开了 RDS 的性能监控(此处弄丢两张图)。
通过观察性能监控,我们发现该“病人”所在的 RDS 内存基本维持在40%左右,但是 CPU 却在那个时间冒上去了!聪明的你,一定猜到了——
是的,他就是个受害者!由于多用户共享了 RDS 服务器,其中只要有一家用户占用了大量资源,自然就会挤压其他用户的资源空间,造成了一群人的卡顿。
事后也证明了我的猜想:2018年4月18日下午,编号 003 的 RDS 在下午 3 - 4 点之间 CPU 飙到了 80% 以上,几乎同时,就有好多客户开始来追售后!

查看 MySQL 的 binlog

那既然找到了问题的原因,那就该找到这个罪魁祸首了。可惜,当我要查看 binlog 的时候,由于某些原因无法查看,只能获取到慢查询日志。
以下的判断会有些不精准:通过对 RDS 慢查询的分析,初步判定,多数是由于打印报表类的请求导致的。但是还不能就此对某家客户判刑。因为每天打报表的客户都不一样,所以慢查询发生的库也不一样,而且罪魁祸首本身也是受害者,虽然要惩罚他,但是也得给他解决问题,是不?

其他可能性 - Qt 外壳

期间也有“病人”是这样的情况:从 nginx log 分析,页面数据已经在 1s 以内发送给了客户端,但是客户端里却显示不出来。这样的问题,看起来就是客户端的原因了。
我也稍微调研了一下,门窗软件一个 tab 页大概占用 2M - 3M 内存,关闭 tab 页会释放内存,但是这么点内存,开上 10 个、8 个的,也不会有什么问题。
好了,这么说,就基本上确定了是 webkit 内核的兼容性问题,对应的方案就是——升级内核或者直接抛弃外壳。

其他可能性 - 网络 ISP

还有一些特殊的“病人”是这样的情况:页面白屏,死活打不开。对于这样的“病人”,我上去就是一个 ping 服务器,结果服务器 ping 不通,本来以为找到原因了,结果 OP 领导告诉我,他对服务器做了防 ping 处理……好吧,领导果然不按套路出牌,我给你个双击 666!
既然做了防 ping,那我直接打开总可以吧?事实证明,换了 360 浏览器还是打不开(当然,前提是打开百度没什么问题),那就基本上可以确定是网络问题了。
我的第一反应是 DNS 劫持,但是通过直接访问 IP 地址,发现依然是打不开网页。
本着“出了问题先从自己身上找原因”的原则,我再次找了领导,领导告诉我机房是没有线路限制的,所以这样基本上就能确定是 ISP 的问题了。我仿佛看到了联通(用户的 ISP )在阴暗的小角落里对着我嘿嘿淫笑……(让你牛逼,劳资掐你网线!)
既然如此,对于这样的用户,我只想说一句:“除了等待,还是等待,等不及就打联通客服吧!”,好在那个用户当时正好快下班了,才没有耽误人家业务,第二天网络就恢复了。(其实我也不想甩锅给联通的, 只是真的是这样啊……希望用户不要觉得是我在甩锅吧!)

结论和方案

通过这次的排查,我总结了门窗软件的几个问题和解决方案:

问题原因 解决方案
RDS 硬件资源竞争,导致大面积用户卡顿 1. 增加 RDS 硬件资源
2. 配置主从数据库,并将打印报表的查询放到只读数据库
外壳 webkit 内核 bug 1. 升级 webkit 内核
2. 抛弃外壳,采用 chrome 浏览器,直接用网页版(独立打印程序 / 迁移 NCReport 到 WEB 打印)
网络原因 1. 排除 DNS 劫持
2. 排除机房线路限制
3. 剩下的就找 ISP 去吧,哥只能帮你到这儿了
代码原因 1. 检查 SQL 语句,有无性能问题
2. 检查 PHP 代码,有无性能问题
(关于 SQL 和 PHP 的优化,就不在本文展开了)

通过以上的问题排查和定位,我也发现了一些缺陷:

  1. Log 缺失。Log 的重要性,对于有经验的程序员来说,不言而喻。我们不光要会查看 nginx / apache 的 log、MySQL 的 binglog,还要注意平时的编程中,也要在关键的地方加上 log。因为这些 log,将会在排查问题的时候,成为我们的“证据”。
  2. 自动化分析工具不完善。我们已经用了阿里云的日志服务,可以对 nginx log 进行统计分析,但是对于 RDS 的 binlog,却显得无能为力,这也是接下来要完善的地方。
  3. 很多 SQL 语句,性能很有问题。看得出来,之前的研发也是动足了脑筋来进行优化。但是连续 join 超过 3 张表、大量使用 SQL 函数和存储过程等,都是卡顿的罪魁祸首。特别是存储过程,根本不利于水平扩展(当然,对于现在一家用户一个数据库来说,也用不着水平扩展)。

从这次的排查情况分析下来看,仅仅从 SQL 语句和 PHP 代码角度进行优化的空间不大,即便是优化了,也收益不大。
因此,接下来优化的重点应该是去外壳和改打印报表,辅以排查问题的工具了。