分享 vivo 互联网技术干货与沙龙活动,推荐最新行业动态与热门会议。
分类: 大数据
2020-08-24 10:34:39
本文首发于 vivo互联网技术 微信公众号
链接:
作者:Yang Yijun
本文主要描述Linux Page Cache优化的背景、Page Cache的基本概念、列举之前针对Kafka的 IO 性能瓶颈采取的一些解决方案、如何进行Page Cache相关参数调整以及性能优化前后效果对比。
当业务快速增长,每天需要处理万亿记录级数据量时。在读写数据方面,Kafka 集群的压力将变得巨大,而磁盘 IO 成为了 Kafka 集群最大的性能瓶颈。
当出现入流量突增或者出流量突增情况,磁盘 IO 持续处于被打满状态,导致无法处理新的读写请求,甚至造成部分broker节点雪崩而影响集群的稳定。
如下图所示,磁盘 IO 被持续打满:
这严重的影响了集群的稳定,从而影响业务的稳定运行。对此,我们做出了一些针对性的优化方案:
以上只是列举了几点主要的优化方案,还有一些其他的内容这里不再赘述。本文我们主要来讲解一下 Linux操作系统的Page Cache参数调优。
Page Cache是针对文件系统的缓存,通过将磁盘中的文件数据缓存到内存中,从而减少磁盘I/O操作提高性能。
对磁盘的数据进行缓存从而提高性能主要是基于两个因素:
文件读写流程如下所示:
当内核发起一个读请求时(例如进程发起read()请求),首先会检查请求的数据是否缓存到了Page Cache中。
如果有,那么直接从内存中读取,不需要访问磁盘,这被称为cache命中(cache hit);
如果cache中没有请求的数据,即cache未命中(cache miss),就必须从磁盘中读取数据。然后内核将读取的数据缓存到cache中,这样后续的读请求就可以命中cache了。
page可以只缓存一个文件部分的内容,不需要把整个文件都缓存进来。
当内核发起一个写请求时(例如进程发起write()请求),同样是直接往cache中写入,后备存储中的内容不会直接更新(当服务器出现断电关机时,存在数据丢失风险)。
内核会将被写入的page标记为dirty,并将其加入dirty list中。内核会周期性地将dirty list中的page写回到磁盘上,从而使磁盘上的数据和内存中缓存的数据一致。
当满足以下两个条件之一将触发脏数据刷新到磁盘操作:
我们如何查看缓存命中率呢?在这里我们可以借助一个缓存命中率查看工具 cachestat。
执行脚本:echo 1 > /proc/sys/vm/drop_caches 这里可能需要等待一会,因为有应用程序正在写数据。
回收前:
回收后:
缓存回收后,正常情况下,buff/cache应该是0的,我这里之所以不为0是因为有数据正在不停的写入。
备注:不同硬件配置的服务器可能效果不同,所以,具体的参数值设置需要考虑自己集群硬件配置。
考虑的因素主要包括:CPU核数、内存大小、硬盘类型、网络带宽等。
执行命令 sysctl -a|grep dirty
1
2
3
4
5
6
|
vm.dirty_background_bytes = 0 # 和参数vm.dirty_background_ratio实现相同功能,但两个参数只会有其中一个生效,表示脏页大小达到多少字节后开始触发刷磁盘
vm.dirty_background_ratio = 10
vm.dirty_bytes = 0 # 和参数vm.dirty_ratio实现相同功能,但两个参数只会有其中一个生效,表示脏页达到多少字节后停止接收写请求,开始触发刷磁盘
vm.dirty_ratio = 20
vm.dirty_expire_centisecs = 3000 #这里表示30秒(时间单位:厘秒)
vm.dirty_writeback_centisecs = 500 #这里表示5秒(时间单位:厘秒)
|
后一个问题对写负载很高的应用会产生很大影响。
当cached中缓存当数据占总内存的比例达到这个参数设定的值时将触发刷磁盘操作。
把这个参数适当调小,这样可以把原来一个大的IO刷盘操作变为多个小的IO刷盘操作,从而把IO写峰值削平。
对于内存很大和磁盘性能比较差的服务器,应该把这个值设置的小一点。
1
2
3
4
5
6
7
8
9
10
11
12
|
#设置方法1:
sysctl -w vm.dirty_background_ratio=1(临时生效,重启服务器后失效)
#设置方法2(永久生效):
echo vm.dirty_background_ratio=1 >> /etc/sysctl.conf
sysctl -p /etc/sysctl.conf
#设置方法3(永久生效):
#当然你还可以在/etc/sysctl.d/目录下创建一个自己的参数优化文件,把系统优化参数进行归类存放,然后设置生效,如:
touch /etc/sysctl.d/kafka-optimization.conf
echo vm.dirty_background_ratio=1 >> /etc/sysctl.d/kafka-optimization.conf
sysctl --system
|
对于写压力特别大的,建议把这个参数适当调大;对于写压力小的可以适当调小;如果cached的数据所占比例(这里是占总内存的比例)超过这个设置,
系统会停止所有的应用层的IO写操作,等待刷完数据后恢复IO。所以万一触发了系统的这个操作,对于用户来说影响非常大的。
这个参数会和参数vm.dirty_background_ratio一起来作用,一个表示大小比例,一个表示时间;即满足其中任何一个的条件都达到刷盘的条件。
为什么要这么设计呢?我们来试想一下以下场景:
结合以上情况,所以添加了一个数据过期时间参数。当数据量没有达到阀值,但是达到了我们设定的过期时间,同样可以实现数据刷盘。
这样可以有效的解决上述存在的问题,其实这种设计在绝大部分框架中都有。
理论上调小这个参数,可以提高刷磁盘的频率,从而尽快把脏数据刷新到磁盘上。但一定要保证间隔时间内一定可以让数据刷盘完成。
禁用swap空间,设置vm.swappiness=0
从下图可以看出,优化前写入流量出现大量突刺,波动非常大,优化后写入流量更加平滑。
(2)磁盘IO UTIL对比
从下图可以看出,优化前IO出现大量突刺,波动非常大,优化后IO更加平滑。
(3)网络入流量对比
从下图可以看出,优化前后对网络入流量并无影响。
这里不同机型,不同硬件配置可能最终优化效果也不一样,但是参数变化的趋势应该是一致的。