计算机硬件中CPU、内存、磁盘是最主要的三大部分,其中,CPU发展到今天,执行速度最快,而内存相对CPU而言,就慢多了,CPU执行的指令是从内存取出的,计算的结果也要写回内存,但内存的响应速度如果跟不上CPU的话,CPU只能无所事事的等待了。这样一来,再快的CPU也发挥不了效率。
同理,内存中的数据也要回写到磁盘的,相对于机械硬盘HDD,内存的速度可快多了。这就又出现了问题,磁盘的低速读写速度,相比内存条的二进制电压变化速度,那就是蒸汽机和火箭速度的差别。这样巨大差异,即使内存读写速度再快,还是要被磁盘的低速读写拖后腿。
所谓Cache,就是“为了弥补高速设备和低速设备之间的矛盾”而设立的一个中间层。因为在现实里经常出现高速设备要和低速设备打交道,结果被低速设备拖后腿的情况。
buffer,它存在的目的适用于速度快的设备往速度慢的设备输出东西。例如内存的数据要写到磁盘,cpu寄存器里的数据写到内存。缓冲(buffers)是根据磁盘的读写设计的,它把分散的写操作集中进行,减少磁盘碎片和硬盘的反复寻道,从而提高系统性能。
cache (page cache)缓存具体文件内容;
buff (buff cache)缓存块设备内容
总结:
1)、cached是cpu与内存间的,buffer是内存与磁盘间的,都是为了解决速度不对等的问题。
2)缓存(cached)是把读取过的数据保存起来,重新读取时若命中(找到需要的数据)就不要去读硬盘了,若没有命中就读硬盘。
3)、buffer是即将要被写入磁盘的,而cache是被从磁盘中读出来的
4)、在应用场景上,buffer是由各种进程分配的,被用在如输入队列等方面。
下面我们结合cpu、内存、磁盘IO来看一下这种读、写缓存模型,如图所示:
从图中可以看出,有读、写两条线。磁盘数据会被读取到Page cache进行缓存,程序要读取数据的时候,可以直接从Page cache读取,这是读取数据的一条线路。 此外,当page cache的数据需要刷新时,page cache中的数据会交给buffer cache,而Buffer cache中的所有数据都会定时刷新到磁盘。这些写入数据的另一条线。
Linux是最大限度的将物理内存映射到缓存,待需要使用内存的时候,可以以最快的速度获取内存并使用,在available和buff/cache两列值的对比,可以看出,available是在buff/cache基础上减去了shared以及buffer内存损耗剩下的内存资源,这部分内存资源可以留给应用程序使用。所以查看内存是否充足,只需要关注available一列即可。
要优化page cache,需要关注两个操作系统参数:
vm.dirty_background_ratio:这个参数指定了当文件系统缓存脏页(Page Cache中的数据称为脏页数据)数量达到系统内存百分之多少时(默认10%)就会触发pdflush/flush/kdmflush等后台回写进程运行,将一定缓存的脏页异步地刷入磁盘。增减这个值是最主要的调优手段。
vm.dirty_ratio:这个参数则指定了当文件系统缓存脏页数量达到系统内存百分之多少时(默认20%),系统不得不开始处理缓存脏页(因为此时脏页数量已经比较多,为了避免数据丢失需要将一定脏页刷入磁盘);在此过程中很多应用进程可能会因为系统刷新内存数据到磁盘而发生IO阻塞。
这两个系统参数对应的文件为:
vm.dirty_background_ratio:/proc/sys/vm/dirty_background_ratio vm.dirty_ratio:/proc/sys/vm/dirty_ratio |
作为通用优化设置,建议将vm.dirty_background_ratio设置为5%,vm.dirty_ratio设置为10%。具体的设置根据不同环境,需要进行测试、再测试。
linux提供了几个参数,用来释放cache,具体如下:
要释放page cache,可执行如下命令:
echo 1 > /proc/sys/vm/drop_caches |
要释放文件节点(inodes)缓存和目录项缓存(dentries),大部分缓存数据都是用的page cache,执行如下命令:
echo 2 > /proc/sys/vm/drop_caches |
要释放page cache、dentries和inodes缓存,执行如下命令:
echo 3 > /proc/sys/vm/drop_caches |
建议在执行 清理cache 时前,先执行sync 将缓存数据刷到磁盘,以防丢失脏缓存数据
创建交换空间所需的交换文件是一个普通的文件,但是,创建交换文件与创建普通文件不同,必须通过dd命令来完成,同时这个文件必须位于本地硬盘上。
[root@localhost ~]# dd if=/dev/zero of=/data/swapfile bs=1024 count=65536 |
要使用swap,首先要激活swap,通过mkswap命令指定作为交换空间的设备或者文件
[root@localhost ~]#mkswap /data/swapfile |
最后,通过swapon命令激活swap:
[root@localhost ~]#/usr/sbin/swapon /data/swapfile |
swappiness的值的大小对如何使用swap分区是有着很大的联系的。swappiness=0的时候表示最大限度使用物理内存,然后才是 swap空间,swappiness=100的时候表示积极的使用swap分区。
[root@slave034 ~]# cat /proc/sys/vm/swappiness 60 |
默认值为60,意思是说,系统的物理内存在使用到100-60=40%的时候,就可以开始使用交换分区了。此参数设置了使用交换分区的可能性大小。在/etc/sysctl.conf文件中修改,加上如下内容:
vm.swappiness=10 |
然后执行命令,永久生效。:
sysctl -p |
为了查看及使用上的方便,内核参数文件通常会按照相关性进行分类存储于不同的目录甚至子目录中,主要有如下几类:
/proc/sys/net是跟网络相关的内核参数
/proc/sys/kernel是跟内核相关的内核参数
/proc/sys/vm是跟内存相关的内核参数
/proc/sys/fs是跟文件系统相关的内核参数
此外,/sys下主要存放硬件设备的驱动程序信息,可以通过/sys/block优化磁盘I/O。
推荐使用sysctl命令修改内核参数,因为它会修改前检查数据一致性,(建议使用sysctl 命令修改内核参数,而非echo) 例如:
[root@centos7 kernel]# sysctl kernel.msgmnb kernel.msgmnb = 32768 [root@centos7 kernel]# sysctl -w kernel.msgmnb=40960 kernel.msgmnb = 40960 [root@centos7 kernel]# sysctl kernel.msgmnb kernel.msgmnb = 40960 |
这样只是临时生效,如果想做永久修改,就应该编辑/etc/sysctl.conf文件,在此文件中添加如下内容:
kernel.msgmnb = 40960 |
然后,执行如下命令,立刻生效
[root@centos7 kernel]# sysctl -p |
/proc/sys/net/ipv4/tcp_syn_retries
此参数表示对于一个新建连接,内核要发送多少个SYN连接请求才决定放弃,此值不应该大于255,默认值是5,建议设置为2,
echo 2 > /proc/sys/net/ipv4/tcp_syn_retries |
/proc/sys/net/ipv4/tcp_syncookies
此参数表示开启SYN Cookies。当出现SYN等待队列溢出时,启用cookies来处理,可防范少量SYN攻击,默认为0,表示关闭,建议打开。
echo 1 >/proc/sys/net/ipv4/ tcp_syncookies |
/proc/sys/net/ipv4/tcp_max_syn_backlog
此参数表示设置SYN队列最大长度,默认为1024,建议加大队列长度为8192,可以容纳更多等待连接的网络连接数。
/proc/sys/net/ipv4/tcp_synack_retries
net.ipv4.tcp_synack_retries用来降低服务器SYN+ACK报文重试次数(默认是5次),尽快释放等待资源。
/proc/sys/net/ipv4/ tcp_tw_recycle
此参数表示开启TCP连接中TIME-WAIT sockets的快速回收,默认为0,表示关闭,普通web服务器建议设置为1,开启。
/proc/sys/net/ipv4/tcp_tw_reuse
此参数表示开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接,因为重用连接,比重新建立新连接要便宜得多。此值默认为0,表示关闭,建议启用。启用该resuse的同时,必须同时启用快速回收recycle
/proc/sys/net/ipv4/tcp_fin_timeout
此参数表示处于TIME_WAIT状态的连接在回收前必须等待的最小时间。改小它可以加快回收。普通web服务器建议设置为15.
/proc/sys/net/core/netdev_max_backlog
此参数用来设每个网络接口接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目。默认为1000。修改此参数可以优化网络设备接收队列,建议设置为3000
/proc/sys/kernel/panic
此参数用来设置如果发生“内核严重错误(kernel panic)”,则内核在重新引导之前等待的时间(以秒为单位)。默认值为0,表示在发生内核严重错误时将禁止重新引导,建议设置为1,也就是内核故障后1秒后自动重启。
/proc/sys/kernel/pid_max
此参数用来设置Linux下进程数量的最大值,默认是32768,正常情况下是够用的,当我们跑重量任务时,会不够用,最终导致内存无法分配的错误,所以可以适当增加。
/proc/sys/kernel/core_pattern
此参数用来设置core文件保存位置或文件名,只有文件名时,则保存在应用程序运行的目录下。配置方法:echo "core.%e.%p" >/proc/sys/kernel/core_pattern,其中%e表示程序名, %p表示进程id。
/proc/sys/vm/dirty_background_ratio
这个参数指定了当文件系统缓存脏数据数量达到系统内存百分之多少时(如10%)就会触发pdflush/flush/kdmflush等后台回写进程运行,将一定缓存的脏页异步地刷入磁盘;例如,服务器内存32G,那么有3.2G的内存可以用来缓存脏数据,超过3.2G的话就pdflush/flush/kdmflush进程就会来清理它。
/proc/sys/vm/dirty_ratio
这个参数指定了当文件系统缓存脏数据数量达到系统内存百分之多少时(如15%),系统不得不开始处理缓存脏页(因为此时脏数据数量已经比较多,为了避免数据丢失需要将一定脏数据刷入磁盘);如果触发了这个设置,那么新的IO请求将会被阻挡,直到脏数据被写进磁盘。这是造成IO卡顿的重要原因,但这也是保证内存中不会存在过量脏数据的保护机制。
/proc/sys/vm/dirty_expire_centisecs
该文件表示如果脏数据在内存中驻留时间超过该值,pdflush进程在下一次将把这些数据写回磁盘。这个参数声明Linux内核写缓冲区里面的数据多“旧”了之后,pdflush进程就开始考虑写到磁盘中去。单位是1/100秒。缺省是 3000,也就是30秒的数据就算旧了,将会刷新磁盘。对于特别重载的写操作来说,这个值适当缩小也是好的,但也不能缩小太多,因为缩小太多也会导致IO提高太快。
/proc/sys/vm/dirty_writeback_centisecs
这个参数控制内核的脏数据刷新进程pdflush的运行间隔。单位是1/100秒。缺省数值是500,也就是5秒。如果我们的系统是持续地写入动作,那么建议降低这个数值比较好,这样可以把尖峰的写操作削平成多次写操作,相反,如果我们的系统是短期地尖峰式的写操作,并且写入数据不大(几十M/次)且内存又比较富裕,那么应该增大此数值
/proc/sys/vm/min_free_kbytes
该文件表示强制Linux VM最低保留多少空闲内存(Kbytes)
/proc/sys/vm/panic_on_oom
此参数表示内存不够时内核是否直接panic(恐慌), 默认为0,表示当内存耗尽时,内核会触发OOM killer杀掉最耗内存的进程。如果设置为1表示在OOM时系统会panic(恐慌)
/proc/sys/fs/file-max
该参数指定了可以分配的文件句柄的最大数目。如果用户得到的错误消息声明由于打开文件数已经达到了最大值,从而他们不能打开更多文件,则可能需要增加该值。设置方法为:
echo "10485750">/proc/sys/fs/file-max |
/proc/sys/fs/inotify/max_user_watches
表示注册监听目录的数量限制,如果不设置,当遇到大量文件的时候就会出现too many open files错误,
max_user_watches 值根据同步文件数量进行设置
(1)、磁盘队列长度优化
磁盘对列长度优化(提升磁盘吞吐量),缺点:牺牲内存,如果内存充足,建议优化,否则需要先做压力测试
在LINUX系统中,如果有大量读请求,默认的请求队列或许应付不过来,我们可以动态调整请求队列数来提高效率,默认的请求队列数存放在/sys/block/sda/queue/nr_requests 文件中.查看磁盘的默认请求队列:
[root@hdpserver2 ~]#cat /sys/block/xvda/queue/nr_requests 128 |
这里修改为1024,可执行如下操作:
[root@hdpserver2 ~]#echo 1024 > /sys/block/xvda/queue/nr_requests |
(2)、预读扇区数优化
预读是提高磁盘性能的有效手段,目前对顺序读比较有效,预读参数为/sys/block/sde/queue/read_ahead_kb,其中,sde为对应的磁盘,根据环境,需要修改为对应的磁盘标识。查看磁盘默认预读配置,可执行如下命令:
[root@hdpserver2 elk]# cat /sys/block/sde/queue/read_ahead_kb 128 |
或者执行如下命令查看:
[root@hdpserver2 elk]# blockdev --getra /dev/sde 256 |
上面两个输出有差异,这是因为blockdev输出的是多少个扇区,所以实际的字节是除以2,也就是128kb。要修改read_ahead_kb为256kb,可以执行如下命令:
[root@hdpserver2 elk]# blockdev --setra 512 /dev/sde |
这里设置扇区为512,实际是读256个字节。
(3)、调整I/O调度算法
I/O调度算法再各个进程竞争磁盘I/O的时候担当了裁判的角色.他要求请求的次序和时机做最优化的处理,以求得尽可能最好的整体I/O性能.其实所有的IO优化只有二点,合并和排序。
如何选择合适的调度算法呢,需要结合实际应用场景来定,这里说下一些优化经验:
deadline调度算法通过降低性能而获得更短的等待时间,它使用轮询的调度器,简洁小巧,提供了最小的读取延迟和尚佳的吞吐量,特别适合于读取较多的环境(比如数据库服务,web服务)。
NOOP调度算法适用于SSD盘,有RAID卡,做了RAID的磁盘阵列环境。
CFQ调度算法是对所有因素都做了折中而尽量获得公平性,使用QoS策略为所有任务分配等量的带宽,避免进程被饿死并实现了较低的延迟,可以认为是上述两种调度器的折中.适用于有大量进程的多用户系统,例如桌面多任务及多媒体应用。
RHEL7/Centos7环境中,可以针对每块磁盘制定I/O调度算法,修改完毕立刻生效,比如:
[root@hdpserver2 elk]#cat /sys/block/sde/queue/scheduler noop [deadline] cfq |
修改为cfq
[root@hdpserver2 elk]# echo 'cfq'>/sys/block/sde/queue/scheduler |
查看是否生效
[root@hdpserver2 elk]# cat /sys/block/sde/queue/scheduler noop deadline [cfq] |
(4)、固态硬盘(SSD)优化
TRIM是固体硬盘的一个功能,要查看SSD磁盘是否支持TRIM,可以使用lsblk命令来检测:
[root@localhost hadoop]# lsblk -D /dev/sdb NAME DISC-ALN DISC-GRAN DISC-MAX DISC-ZERO sdb 0 512B 4G 1 └─sdb1 0 512B 4G 1 |
如果输出中,DISC-GRAN和DISC-MAX列非0, 表示该SSD磁盘支持TRIM功能。
Linux文件系统中, 只有ext4、xfs文件系统支持TRIM。要如何启用TRIM功能,可以在文件系统挂载过程中启用,例如:
mount -t ext4 -o discard /dev/sda2 /mnt |
(1)、xfs文件系统格式化时参数优化
对于xfs文件系统,可以在进行格式化的时候添加一些优化参数,这些参数可以大幅度提升xfs的性能。例如:
[root@server1 home]#mkfs.xfs -d agcount=4 -l size=128m,lazy-count=1,version=2 /dev/diska1 |
-l size=128m :注意是小写的m,不是大写的。默认值的是10m,修改这个参数成128m,可以显著的提高xfs文件系统删除文件的速度,当然还有其它,如拷贝文件的速度。 这个参数需要大内存的支持,内存太少的机器不能设置这么高
-d agcount=4 :默认值是根据容量自动设置的。可以设置成1/2/4/16等等,这个参数可以调节对CPU的占用率,值越小,占用率越低.
lazy-count:该值可以是0或1。如果lazy-count=1,则不会修改超级块,可以显著提高性能
设置后可以减少10%左右的内存占用,性能也提高了,效果非常不错。
(2)、ext4文件系统优化
禁用日志功能可以在创建ext4文件系统时就指定:
[root@localhost ext4]# mkfs.ext4 -O ^has_journal /dev/sda7 [root@localhost ext4]# dumpe2fs /dev/sda7 | grep 'Filesystem features' | grep 'has_journal' |
或动态(即在ext4文件系统已经创建后)指定,比如关闭日志功能:
[root@localhost ext4]# tune2fs -O ^has_journal /dev/sda7 [root@localhost ext4]# dumpe2fs /dev/sda7 | grep 'Filesystem features' | grep 'has_journal' |
打开日志功能:
[root@localhost ~]# tune2fs -O has_journal /dev/sda7 |
(3)、ext4文件系统挂载参数优化
ext4文件系统中分两部分存储,一部分是文件的元数据块,另一部分是数据块。metadata和data的操作日志journal也是分开管理的。我们可以让ext4记录metadata的journal,而不记录data的journal。这就是ext4文件系统三种日志模式提供的功能,三种日志模式分别是journal、ordered、writeback。
何使用writeback模式呢,其实只需要在mount分区时,加上writeback选项即可,例如:
[root@localhost ~]# mount -t ext4 -o data=writeback /dev/sda7 /mnt |
这样,/dev/sda7分区的文件系统日志模式就变成了writeback,文件系统性能会提高不少。