最近经常发现zabbix的dashbord的最近20个问题以及系统状态的刷新偶尔会多几秒延时,圈圈转啊转,让人很不爽,于是决定折腾一下。
最开始着手的就是数据库。
系统参数调整
最初的时候我把postgre中的fsync关闭,并且将数据最为庞大的各个history和trends的分区改成了unlogged模式。效果非常明显。
那么下一步就是对一些常规的系统参数进行精细调整,毕竟很多都是简单有效的方法。
文件系统调整
之前不知道看过哪个评测报告,说对于随机读写,ext3是要超过ext4的。虽然不知道真假,但是还是秉着宁可信其有的方式使用了的ext3分区。
对于文件系统最常见的优化就是关闭atime模式和设置更快的日志模式。
开启atime功能意味着在读取数据的时候也会造成inode的刷新,而inode的刷新也会带来文件系统日志的变更。而atime一般来说是没多大作用,关闭atime也不会出现什么不良反应,属于首先开刀的地方。
其次是日志模式。默认的ordered方式即使先写用户数据再写元数据的模式,也就是和windows一样。当然也有更慢的更安全的journal模式和更快却没那么安全的writeback模式。我的做法是把history和trends单独的表空间采取writeback模式,也算是一种折中。当然也可以完全关闭日志,不过这就太过分了。
再次是关闭jdb barrier。按照ext3 manpage的说法:
|
|
jdb barrier确保日志的提交顺序。如果磁盘的有电源的,可以关闭以提高性能。
对于使用阵列存储的我来说,这个应该不必担心,关闭即可。
另外,文件系统的块大小应该也是会存在影响的。因为数据库的页面以8K为基本单位,而文件系统默认以4K为基本单位。按照直觉的,应该是修改成一致性应该会好一些。不过没亲测过,就暂缓调整了。
内核调整
对于数据库来讲,内存的调整应该是最为主要的。
为了防止页面换出,我直接禁用了交换分区。把后台的pdflush脏页回写频度调高以优化可能的fsync造成的性能影响。实际上,我应该先用strace统计一下。这个地方可以mark一下,有空再试。
对于postgre文档中建议的共享内存段以及信号量的调整,我现在没看到有什么问题,就没去调整。
最后,我将postgre的shard buffer的内存页面大小修改成2M的大页面。理论上讲,减少页面的数量能增加TLB的命中率,更高效的利用cpu缓存。对于数据库这种需要大块分配内存的应用来讲是有利的。
我的数据库内存是16G,按照官方文档中建议的方法将postgre共享内存设置成所有内存的1/4。也就是4G,其他部分用作操作系统的透明文件缓存。因为还有一些零碎的内存,所以整体需要的大页面数量,会比4G更多一些。
官方文档中的建议的方法是取master进程统计的vm峰值, 即:
再除以页面大小,即:
得到的值就是nr_hugepages的值。
另外,官方文档还建议关闭操作系统的透明大页面功能。并将postgre的大页面设置成on,这样就可以让postgre独享大页面了。
我做了一个systemd一次性启动服务来实现这个需求。虽然直接用rc.local的方式更为简单,但是systemd不建议继续使用rc.local,就按照新标准来吧。
|
|
|
|
表索引调整
把基础环境调整后,开始进入正题。调整具体的功能还是要从最直接的地方开刀。也就是找到两个功能卡的对应的表和sql。
表很容易猜,而sql除了查找php的源代码,其实还有更简单的方法。
在postgre中,可以使用pg_stat_statements插件,对sql的执行情况进行统计。把统计视图中调用次数最多的10个sql拉出来看看,就能查到是哪个sql有问题了。
|
|
果然,排名第一的就是events表。语句模板为
最慢的执行时间为7051ms,简直弱爆了。
这张表的eventid为主键,有个默认的btree索引,但是是非聚集的。
因为可以想象的是,这个搜索的条件带有明显的聚集特性。因此,把整个表改成按照eventid进行聚集索引,是个不错的主意。为了验证这个结论,我在测试服务器上插入了1000w的模拟数据并且用pgbench进行测试,1000w行的数据在集中搜索100行数据的情况下聚集索引大概快了20%,效果还是挺明显的。
postgre中的聚集索引创建方法为
注意运行完cluster后要使用analyze进行重新统计,否则规划器会生成非常差劲的执行计划。
另外,需要定期运行cluster命令以更新聚集索引。
尾声
一番折腾,不知道是不是心理作用,感觉似乎快了一些。下一步可以折腾一下php。也许可以换个php 7试试看。