Java page cache回寫機(jī)制案例詳解
JAVA寫文件的基本流程
在不使用堆外內(nèi)存的情況下,java在寫文件時(shí),先將字節(jié)寫入JVM的堆內(nèi)內(nèi)存中;然后調(diào)用jvm的寫文件函數(shù),將字節(jié)寫入jvm的堆外內(nèi)存中,jvm再調(diào)用系統(tǒng)內(nèi)核的寫文件函數(shù),將字節(jié)寫入內(nèi)核的heap中;然后內(nèi)核將字節(jié)寫入page cache中,將page cache狀態(tài)改為dirty,根據(jù)page cache的回寫機(jī)制在合適的時(shí)機(jī)將字節(jié)寫入磁盤。
page cache 自動(dòng)回寫機(jī)制
page cache的回寫時(shí)機(jī)由系統(tǒng)配置/etc/sysctl.conf 中的幾個(gè)參數(shù)決定,分別是:
- dirty_background_bytes
默認(rèn)值:0 表示不啟用
當(dāng)臟頁所占的內(nèi)存大小超過dirty_background_bytes時(shí),內(nèi)核的pdflush線程會(huì)從后臺(tái)開始回寫臟頁,不會(huì)影響應(yīng)用程序的后序IO操作。
- dirty_background_ratio
默認(rèn)值 :10
參數(shù)意義:當(dāng)臟頁所占的百分比(相對(duì)于所有可用內(nèi)存,即空閑內(nèi)存頁+可回收內(nèi)存頁)達(dá)到dirty_background_ratio時(shí)內(nèi)核的pdflush線程從后臺(tái)開始回寫臟頁,不會(huì)影響應(yīng)用程序的后序IO操作。增大會(huì)使用更多內(nèi)存用于緩沖,可以提高系統(tǒng)的讀寫性能。當(dāng)需要持續(xù)、恒定的寫入場合時(shí),應(yīng)該降低該數(shù)值。
注意:dirty_background_bytes參數(shù)和dirty_background_ratio參數(shù)是相對(duì)的,只能指定其中一個(gè)。當(dāng)其中一個(gè)參數(shù)文件被寫入時(shí),會(huì)立即開始計(jì)算臟頁限制,并且會(huì)將另一個(gè)參數(shù)的值清零。
- dirty_bytes
默認(rèn)值:0 表示不啟用
當(dāng)臟頁所占的內(nèi)存數(shù)量達(dá)到dirty_bytes時(shí),內(nèi)核將臟頁中的數(shù)據(jù)刷入磁盤并阻塞后序的IO操作。
注意:dirty_bytes參數(shù)和dirty_ratio參數(shù)是相對(duì)的,只能指定其中一個(gè)。當(dāng)其中一個(gè)參數(shù)文件被寫入時(shí),會(huì)立即開始計(jì)算臟頁限制,并且會(huì)將另一個(gè)參數(shù)的值清零
- dirty_ratio
默認(rèn)值:20
參數(shù)意義:當(dāng)臟頁所占的百分比(相對(duì)于所有可用內(nèi)存,即空閑內(nèi)存頁+可回收內(nèi)存頁)達(dá)到dirty_ratio時(shí),內(nèi)核將臟頁中的數(shù)據(jù)刷入磁盤并阻塞后序的IO操作。
- dirty_background_ratio與dirty_ratio比較
dirty_ratio是屬于強(qiáng)制性的回寫,也就是說當(dāng)一個(gè)內(nèi)存區(qū)的臟頁達(dá)到這個(gè)比例時(shí)就會(huì)觸發(fā)內(nèi)核內(nèi)存管理把臟頁強(qiáng)制回寫的流程,但dirty_background_ratio是屬于軟性的行為,因?yàn)檫@是透過pdflush內(nèi)核線程進(jìn)行的流程,可以在后臺(tái)執(zhí)行對(duì)這些臟頁面回寫,并不會(huì)因此影響到當(dāng)下正在執(zhí)行中的過程。 所以看Linux內(nèi)核中預(yù)設(shè)的比例是臟頁達(dá)到5%的比例時(shí)就會(huì)先透過pdflush內(nèi)核線程進(jìn)行回寫,當(dāng)臟頁達(dá)到10%比例時(shí),就等于是一個(gè)很嚴(yán)重的狀況,此時(shí)就會(huì)在平衡臟頁面流程中觸發(fā)強(qiáng)制的回寫,讓系統(tǒng)可以回復(fù)到原本預(yù)設(shè)合理的狀態(tài)。
- dirty_expire_centisecs
默認(rèn)值:3000
參數(shù)意義:用來指定臟數(shù)據(jù)能存活的時(shí)間。指定的值是按100算做一秒計(jì)算。只有當(dāng)超過這個(gè)值后,才會(huì)被內(nèi)核進(jìn)程pdflush寫到磁盤。
- dirty_writeback_centisecs
默認(rèn)值:500
參數(shù)意義:pdflush回寫的頻率,每次的喚醒的間隔,是以數(shù)字100算做1秒。如果將這項(xiàng)值設(shè)為500就相當(dāng)5秒喚醒pdflush進(jìn)程。如果將這項(xiàng)值設(shè)為0就表示完全禁止定期回寫數(shù)據(jù)。
- drop_caches
向/proc/sys/vm/drop_caches文件中寫入數(shù)值可以使內(nèi)核釋放page cache,dentries和inodes緩存所占的內(nèi)存。
只釋放pagecache:
echo 1 > /proc/sys/vm/drop_caches
只釋放dentries和inodes緩存:
echo 2 > /proc/sys/vm/drop_caches
釋放pagecache、dentries和inodes緩存:
echo 3 > /proc/sys/vm/drop_caches
這個(gè)操作不是破壞性操作,臟的對(duì)象(比如臟頁)不會(huì)被釋放,因此要首先運(yùn)行sync命令。
注:這個(gè)只能是手動(dòng)釋放
測試
采用javaBIO不斷向一個(gè)文件寫入數(shù)據(jù),通過pcstat觀察page cache的大小。文件初始狀態(tài):
[root@node01 ~]# ll test.txt && pcstat test.txt -rw-r--r--. 1 root root 0 Aug 1 19:58 test.txt +----------+----------------+------------+-----------+---------+ | Name | Size (bytes) | Pages | Cached | Percent | |----------+----------------+------------+-----------+---------| | test.txt | 0 | 0 | 0 | NaN | +----------+----------------+------------+-----------+---------+
dirty_background_bytes測試
將臟頁閾值設(shè)置為10MB,臟頁存活時(shí)間設(shè)置為5000s,當(dāng)臟頁大小不足10MB時(shí),絕對(duì)不會(huì)被刷入磁盤,當(dāng)臟頁大小超過10MB,但是存活時(shí)間不超過5000s時(shí),滿足dirty_background_bytes的條件,被刷入磁盤。
#修改系統(tǒng)配置 [root@node01 ~]# vi /etc/sysctl.conf ... #便于測試,設(shè)為10485760 10mb vm.dirty_background_bytes = 10485760 #便于測試,設(shè)為104857600 100mb vm.dirty_bytes = 104857600 #便于測試,設(shè)為500000 5000s vm.dirty_writeback_centisecs = 500000 #便于測試,設(shè)為30000 5min vm.dirty_expire_centisecs = 30000 #加載系統(tǒng)配置 [root@node01 ~]# sysctl -p
當(dāng)page cache大小超過10mb前,停止寫入,關(guān)閉電源,重啟設(shè)備。
關(guān)機(jī)前page cache狀態(tài)及文件大小。
[root@node01 ~]# ll -h test.txt && pcstat test.txt -rw-r--r--. 1 root root 1.7K Aug 1 20:20 test.txt +----------+----------------+------------+-----------+---------+ | Name | Size (bytes) | Pages | Cached | Percent | |----------+----------------+------------+-----------+---------| | test.txt | 1660 | 1 | 1 | 100.000 | +----------+----------------+------------+-----------+---------+
掐斷電源,重啟。(注意,這里不能按正常流程重啟電源)
重啟后page cache狀態(tài)及文件大小。
[root@node01 ~]# ll -h test.txt && pcstat test.txt -rw-r--r--. 1 root root 0 Aug 1 20:20 test.txt +----------+----------------+------------+-----------+---------+ | Name | Size (bytes) | Pages | Cached | Percent | |----------+----------------+------------+-----------+---------| | test.txt | 0 | 0 | 0 | NaN | +----------+----------------+------------+-----------+---------+
之前寫入的數(shù)據(jù)全部丟失,由于沒有達(dá)到后臺(tái)自動(dòng)刷入磁盤的閾值(dirty_background_bytes),page cache內(nèi)的數(shù)據(jù)丟失。
當(dāng)page cache大小超過10mb后,停止寫入,關(guān)閉電源,重啟設(shè)備。
關(guān)機(jī)前page cache狀態(tài)及文件大小。
[root@node01 ~]# ll -h test.txt && pcstat test.txt -rw-r--r--. 1 root root 37M Aug 1 20:26 test.txt +----------+----------------+------------+-----------+---------+ | Name | Size (bytes) | Pages | Cached | Percent | |----------+----------------+------------+-----------+---------| | test.txt | 37985420 | 9274 | 9274 | 100.000 | +----------+----------------+------------+-----------+---------+
掐斷電源,重啟。(注意,這里不能按正常流程重啟電源)
重啟后page cache狀態(tài)及文件大小。
[root@node01 ~]# ll -h test.txt && pcstat test.txt -rw-r--r--. 1 root root 30M Aug 1 20:26 test.txt +----------+----------------+------------+-----------+---------+ | Name | Size (bytes) | Pages | Cached | Percent | |----------+----------------+------------+-----------+---------| | test.txt | 31035392 | 7577 | 0 | 000.000 | +----------+----------------+------------+-----------+---------+
之前寫入的數(shù)據(jù)部分丟失,每次達(dá)到后臺(tái)自動(dòng)刷入磁盤的閾值(dirty_background_bytes)時(shí)內(nèi)核都會(huì)進(jìn)行一次刷入操作,而沒有達(dá)到閾值的部分就會(huì)丟失。關(guān)機(jī)前37M,關(guān)機(jī)后30M,自動(dòng)刷入閾值設(shè)置為10M,37-10=7M,這7M數(shù)據(jù)沒有被刷入磁盤,重啟后丟失。
dirty_expire_centisecs測試
將臟頁閾值設(shè)置為100MB,檢測頻率設(shè)置為1s,臟頁存活時(shí)間設(shè)置為15s。這樣可以達(dá)到這樣一個(gè)測試目的,當(dāng)我的page cache大小未到達(dá)100MB時(shí),由于超過了存活時(shí)間15s,檢測的又很及時(shí),幾乎可以被全部刷入磁盤。為什么說幾乎呢?因?yàn)椴还茉趺礃?,靠檢測頻率自動(dòng)刷入機(jī)制終究會(huì)丟失檢測真空期的數(shù)據(jù)。臟頁在每次刷入磁盤后重寫前都是干凈的狀態(tài)。
#修改系統(tǒng)配置 [root@node01 ~]# vi /etc/sysctl.conf ... #便于測試,設(shè)為104857600 100mb vm.dirty_background_bytes = 104857600 #便于測試,設(shè)為104857600 100mb vm.dirty_bytes = 104857600 #便于測試,設(shè)為1500 15s vm.dirty_writeback_centisecs = 1500 #便于測試,設(shè)為100 1s vm.dirty_expire_centisecs = 100 #加載系統(tǒng)配置 [root@node01 ~]# sysctl -p
當(dāng)page cache大小超過100mb前,停止寫入,未超過15s,關(guān)閉電源,重啟設(shè)備。
關(guān)機(jī)前page cache狀態(tài)及文件大小。
-rw-r--r--. 1 root root 150 Aug 1 20:44 test.txt +----------+----------------+------------+-----------+---------+ | Name | Size (bytes) | Pages | Cached | Percent | |----------+----------------+------------+-----------+---------| | test.txt | 150 | 1 | 1 | 100.000 | +----------+----------------+------------+-----------+---------+
掐斷電源,重啟。(注意,這里不能按正常流程重啟電源)
重啟后page cache狀態(tài)及文件大小。
[root@node01 ~]# ll -h test.txt && pcstat test.txt -rw-r--r--. 1 root root 0 Aug 1 20:44 test.txt +----------+----------------+------------+-----------+---------+ | Name | Size (bytes) | Pages | Cached | Percent | |----------+----------------+------------+-----------+---------| | test.txt | 0 | 0 | 0 | NaN | +----------+----------------+------------+-----------+---------+
之前寫入的數(shù)據(jù)全部丟失,由于沒有超過臟頁存活時(shí)間,page cache內(nèi)的數(shù)據(jù)丟失。
當(dāng)page cache存活超過15s后,關(guān)閉電源,重啟設(shè)備。
關(guān)機(jī)前page cache狀態(tài)及文件大小。
[root@node01 ~]# ll -h test.txt && pcstat test.txt -rw-r--r--. 1 root root 1.7K Aug 1 20:48 test.txt +----------+----------------+------------+-----------+---------+ | Name | Size (bytes) | Pages | Cached | Percent | |----------+----------------+------------+-----------+---------| | test.txt | 1680 | 1 | 1 | 100.000 | +----------+----------------+------------+-----------+---------+
掐斷電源,重啟。(注意,這里不能按正常流程重啟電源)
重啟后page cache狀態(tài)及文件大小。
[root@node01 ~]# ll -h test.txt && pcstat test.txt -rw-r--r--. 1 root root 1.7K Aug 1 20:48 test.txt +----------+----------------+------------+-----------+---------+ | Name | Size (bytes) | Pages | Cached | Percent | |----------+----------------+------------+-----------+---------| | test.txt | 1680 | 1 | 1 | 100.000 | +----------+----------------+------------+-----------+---------+
超過15s且被檢測到的數(shù)據(jù)全部保留
dirty_writeback_centisecs測試
將臟頁閾值設(shè)置為100MB,檢測頻率設(shè)置為15s,臟頁存活時(shí)間設(shè)置為1s。這樣可以達(dá)到這樣一個(gè)測試目的,當(dāng)我的page cache大小未到達(dá)100MB時(shí),且超過了存活時(shí)間1s,由于檢測的不及時(shí),導(dǎo)致超過存活時(shí)間的數(shù)據(jù)還是沒有被刷入磁盤。
#修改系統(tǒng)配置 [root@node01 ~]# vi /etc/sysctl.conf ... #便于測試,設(shè)為104857600 100mb vm.dirty_background_bytes = 104857600 #便于測試,設(shè)為104857600 100mb vm.dirty_bytes = 104857600 #便于測試,設(shè)為100 1s vm.dirty_writeback_centisecs = 100 #便于測試,設(shè)為1500 15s vm.dirty_expire_centisecs = 1500 #加載系統(tǒng)配置 [root@node01 ~]# sysctl -p
當(dāng)page cache大小超過100mb前,停止寫入,未超過15s,關(guān)閉電源,重啟設(shè)備。
關(guān)機(jī)前page cache狀態(tài)及文件大小。
[root@node01 ~]# ll -h test.txt && pcstat test.txt -rw-r--r--. 1 root root 550 Aug 1 21:02 test.txt +----------+----------------+------------+-----------+---------+ | Name | Size (bytes) | Pages | Cached | Percent | |----------+----------------+------------+-----------+---------| | test.txt | 550 | 1 | 1 | 100.000 | +----------+----------------+------------+-----------+---------+
掐斷電源,重啟。(注意,這里不能按正常流程重啟電源)
重啟后page cache狀態(tài)及文件大小。
[root@node01 ~]# ll -h test.txt && pcstat test.txt -rw-r--r--. 1 root root 0 Aug 1 21:04 test.txt +----------+----------------+------------+-----------+---------+ | Name | Size (bytes) | Pages | Cached | Percent | |----------+----------------+------------+-----------+---------| | test.txt | 0 | 0 | 0 | NaN | +----------+----------------+------------+-----------+---------+
之前寫入的數(shù)據(jù)全部丟失,雖然超過臟頁存活時(shí)間,但是沒有到檢測時(shí)間,page cache內(nèi)的數(shù)據(jù)丟失。
到此這篇關(guān)于Java page cache回寫機(jī)制案例詳解的文章就介紹到這了,更多相關(guān)Java page cache回寫機(jī)制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java使用easypoi快速導(dǎo)入導(dǎo)出的實(shí)現(xiàn)
這篇文章主要介紹了實(shí)現(xiàn)Java使用easypoi快速導(dǎo)入導(dǎo)出的實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-03-03IDEA配置MAVEN本地倉庫的實(shí)現(xiàn)步驟
本文主要介紹了IDEA配置MAVEN本地倉庫的實(shí)現(xiàn)步驟,將詳細(xì)介紹如何配置Maven環(huán)境變量,Maven配置文件,可以輕松地設(shè)置和配置MAVEN本地倉庫,以便在IDEA中享受更高效的開發(fā)體驗(yàn)2023-08-08IDEA 2021版新建Maven、TomCat工程的詳細(xì)教程
這篇文章主要介紹了IDEA 2021版新建Maven、TomCat工程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04導(dǎo)入maven項(xiàng)目各個(gè)注解均報(bào)錯(cuò)的解決方案
這篇文章主要介紹了導(dǎo)入maven項(xiàng)目各個(gè)注解均報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12創(chuàng)建SpringBoot工程并集成Mybatis的方法
這篇文章主要介紹了創(chuàng)建SpringBoot工程并集成Mybatis,需要的朋友可以參考下2018-06-06java?JVM-clinit指令實(shí)現(xiàn)原理面試精講
這篇文章主要介紹了java?JVM-clinit指令實(shí)現(xiàn)原理面試精講,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10