解决磁盘io紧张的一种临时方法

有些时候可能会碰到一个场景是临时磁盘的io比较紧张,但不会紧张太久,例如在搞活动,做大促什么的时候,这种时候如果出现磁盘io紧张的话,可能会大幅度影响系统的性能,如果机器的内存是充足的话,有一个临时的办法可以用下。

Java在写文件的时候,如果没有强制调用FileChannel.force或FileDescriptor.sync的话,文件内容是不一定会被写到磁盘上的,所以有些同学可能会看到一些用java写的存储类的产品,例如HBase之类的,会强制调用上面的方法确保数据的安全性,而其他多数的java应用在写文件的时候是不会去调用上面的方法的。

在不调用上面的方法的情况下,os会先将写入的文件内容放入内存,当放入内存的数据量大于一定的阈值或刷新的间隔时间到了的话,会开始将内存中的数据写入磁盘,这样的好处非常明显,一方面提升了平时的写入速度,另一方面将很多随机写转为了顺序写,对于有raid卡,并且开启了raid卡cache的,这个时候会再挡一层,会再次降低文件io的消耗。

linux主要通过以下几个参数来控制上面的行为:
vm.dirty_background_ratio
控制内存占用的阈值,这个是一个比例,但计算起来很折腾,是机器上free(包括cached)的内存的比例,而不是物理机,所以如果想更准确的控制的话,可以用下面的参数。
vm.dirty_background_bytes
控制内存占用的阈值,但是具体的数值。
vm.dirty_ratio
控制内存最多占用的比例,这个是物理内存,如果到达了这个比例,将会阻塞住所有的写动作,先把内存中所有的数据刷入磁盘,可以看到这个参数很关键,设置不好的话会导致应用的性能疯狂下降。
vm.dirty_bytes
控制内存最多占用的阈值,具体的字节数。
vm.dirty_writeback_centisecs
控制每隔多久把内存里的数据往磁盘里刷,默认是5s。
vm.dirty_expire_centisecs
控制在往磁盘刷的时候,刷放在内存超过多久的数据,默认是30s,按照上面的默认值每隔5s刷一次,所以其实就是每次刷全部的数据。

在这个机制的基础上,如物理内存是比较充足的,那么其实可以在搞活动等的时候临时调整下参数,给dirty这块区域更多的内存,同时将writeback的时间间隔拉长,如果能够做到空闲的物理内存支撑过搞活动的高峰时间那就完美了,那样的话在那个时候即使写文件动作很多,性能也是相当高的,这个方法需要值得注意的是,当dirty区域内存很大,而且很久才writeback一次,所以在writeback的那段时间会比较耗io,但通常是还好的,因为那个时候很多都会是顺序写。

不过除了上面的参数外,要真正的做到io性能提升,在ext3文件系统的情况下,还需要调整mount分区的写日志数据的方式(具体可以参见这篇文章),默认通常是ordered的方式(可通过cat /proc/mounts来确认),需要修改为writeback方式,这样可以避免ext3日志写造成的io紧张问题,前提是丢了的情况下也可以接受,但这个地方不太好操作的是要修改data的方式,需要remount,在ext3里就意味着要先停掉这个分区所有的写,在ext4里则可以直接动态执行。

ps: 好久没写文章了,还好取消订阅的不多,:),后面计划写一个系列的文章:“JAVA程序员也应该了解的系统知识”,主要是希望能够把Java代码和系统知识结合起来,除了写代码外,还应该知道例如cpu、内存、磁盘、网络等和程序的关系到底是什么。

=============================
欢迎关注微信公众号:hellojavacases

关于此微信号:
分享Java问题排查的Case、Java业界的动态和新技术、Java的一些小知识点Test,以及和大家一起讨论一些Java问题或场景,这里只有Java细节的分享,没有大道理、大架构和大框架。

公众号上发布的消息都存放在http://hellojava.info上。

《解决磁盘io紧张的一种临时方法》有1个想法

发表评论

电子邮件地址不会被公开。 必填项已用*标注


*