1. 程式人生 > >系統技術非業餘研究 » BufferedIO和DirectIO混用導致的髒頁回寫問題

系統技術非業餘研究 » BufferedIO和DirectIO混用導致的髒頁回寫問題

今天曲山同學在線上問道:

我測試發現,如果cp一個檔案,然後direct io讀這個檔案,會消耗很長時間。
我猜測dio不能用page cache,而這個檔案cp以後都在cache裡面,要強制刷到磁碟,才能讀?
我cp這個檔案很大,超過256M

由於資料檔案預設是用bufferedio方式開啟的,也就是說它的資料是先緩衝在pagecache裡面的,寫入的資料會導致大量的髒頁,而且這部分資料如果核心記憶體不緊張的話,是一直放在記憶體裡面的的。我們知道directio是直接旁路掉pagecache直接發起裝置IO的,也就是說在發起IO之前要保證資料是先落地到介質去,所以如果檔案比較大的話,這個時間會比較長。從

pagecahce的回寫行為我們可以知道,只要髒頁的數量不超過總記憶體的10%, 我們的機器有4G的記憶體,所以2個100M的檔案總共才200M,不會導致writeback發生,我們可以很順利的觀察到這個現象。

有了上面的分析,下面我們來重現下這個問題。以下是我的步驟:

$ uname -a
Linux rds064075.sqa.cm4 2.6.32-131.21.1.tb477.el6.x86_64 #1 SMP Thu Feb 23 14:24:55 CST 2012 x86_64 x86_64 x86_64 GNU/Linux
$ sudo sysctl vm.drop_caches=3
vm.drop_caches = 3
$ free -m && cat /proc/meminfo |grep -i dirty && time dd if=/dev/urandom of=test.dat count=6144 bs=16384 && free -m && cat /proc/meminfo |grep -i dirty && time dd if=test.dat of=/dev/null count=6144 bs=16384 && free -m && cat /proc/meminfo |grep -i dirty && time dd if=test.dat of=/dev/null count=6144 bs=16384  iflag=direct && free -m && cat /proc/meminfo |grep -i dirty
$ free -m && cat /proc/meminfo |grep -i dirty && time dd if=/dev/urandom of=test.dat count=6144 bs=16384 && free -m && cat /proc/meminfo |grep -i dirty && time dd if=test.dat of=/dev/null count=6144 bs=16384 && free -m && cat /proc/meminfo |grep -i dirty && time dd if=test.dat of=/dev/null count=6144 bs=16384  iflag=direct && free -m && cat /proc/meminfo |grep -i dirty
             total       used       free     shared    buffers     cached
Mem:         48262      22800      25461          0          3         42
-/+ buffers/cache:      22755      25507
Swap:         2047       2047          0
Dirty:               344 kB
6144+0 records in
6144+0 records out
100663296 bytes (101 MB) copied, 15.2308 s, 6.6 MB/s

real	0m15.249s
user	0m0.001s
sys	0m15.228s
             total       used       free     shared    buffers     cached
Mem:         48262      22912      25350          0          3        139
-/+ buffers/cache:      22768      25493
Swap:         2047       2047          0
Dirty:             98556 kB
6144+0 records in
6144+0 records out
100663296 bytes (101 MB) copied, 0.028041 s, 3.6 GB/s

real	0m0.029s
user	0m0.000s
sys	0m0.029s
             total       used       free     shared    buffers     cached
Mem:         48262      22912      25350          0          3        139
-/+ buffers/cache:      22768      25493
Swap:         2047       2047          0
Dirty:             98556 kB
6144+0 records in
6144+0 records out
100663296 bytes (101 MB) copied, 0.466601 s, 216 MB/s

real	0m0.468s
user	0m0.002s
sys	0m0.101s
             total       used       free     shared    buffers     cached
Mem:         48262      22906      25356          0          3        140
-/+ buffers/cache:      22762      25500
Swap:         2047       2047          0
Dirty:               896 kB

從上面的實驗,我們可以看出來我們的檔案是101MB左右,髒頁用了98544KB記憶體,在direct方式讀後,檔案佔用的髒頁被清洗掉了,髒頁變成了80K, 但是這塊資料還是留在了pagecache(140-39), 符合我們的預期。

接著我們從原始碼角度來分析下這個現象,我們知道VFS檔案的讀是從generic_file_aio_read發起的,而不管具體的檔案系統是什麼。
在文卿和三百的幫助下,我們不費吹灰之力就找到了原始碼位置,偷懶的方式如下:

$ stap -L 'kernel.function("generic_file_aio_read")' 
kernel.function("[email protected]
/filemap.c:1331") $iocb:struct kiocb* $iov:struct iovec const* $nr_segs:long unsigned int $pos:loff_t $count:size_t

準備好emacs,我們來看下讀程式碼的實現:
mm/filemap.c:1331

/**
 * generic_file_aio_read - generic filesystem read routine
 * @iocb:       kernel I/O control block
 * @iov:        io vector request
 * @nr_segs:    number of segments in the iovec
 * @pos:        current file position
 *
 * This is the "read()" routine for all filesystems
 * that can use the page cache directly.
 */
ssize_t
generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
                unsigned long nr_segs, loff_t pos)
{
        /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
        if (filp->f_flags & O_DIRECT) {
                loff_t size;
                struct address_space *mapping;
                struct inode *inode;

                mapping = filp->f_mapping;
                inode = mapping->host;
                if (!count)
                        goto out; /* skip atime */
                size = i_size_read(inode);
                if (pos < size) {
                        retval = filemap_write_and_wait_range(mapping, pos,
                                        pos + iov_length(iov, nr_segs) - 1);
                        if (!retval) {
                                retval = mapping->a_ops->direct_IO(READ,
iocb,
                                                        iov, pos, nr_segs);
                        }
                        if (retval > 0) {
                                *ppos = pos + retval;
                                count -= retval;
                        }

                        /*
                         * Btrfs can have a short DIO read if we encounter
                         * compressed extents, so if there was an error,
or if
                         * we've already read everything we wanted to, or if
                         * there was a short read because we hit EOF, go
ahead
                         * and return.  Otherwise fallthrough to
buffered io for
                         * the rest of the read.
                         */
                        if (retval < 0 || !count || *ppos >= size) {
                                file_accessed(filp);
                                goto out;
                        }
                }
        }

原始碼很清楚的說:在directio方式下開啟的檔案,先要透過filemap_write_and_wait_range回寫資料,才開始後面的IO讀流程。
最後一步驟,我們再用stap來確認下我們之前的實驗:

$ cat dwb.stp
global i;
probe kernel.function("filemap_write_and_wait_range") {
if (execname() != "dd") next;
print_backtrace();
println("===");
if (i++>2) exit();
}

$ sudo stap dwb.stp 
 0xffffffff8110e200 : filemap_write_and_wait_range+0x0/0x90 [kernel]
 0xffffffff8110f278 : generic_file_aio_read+0x498/0x870 [kernel]
 0xffffffff8117323a : do_sync_read+0xfa/0x140 [kernel]
 0xffffffff81173c65 : vfs_read+0xb5/0x1a0 [kernel]
 0xffffffff81173da1 : sys_read+0x51/0x90 [kernel]
 0xffffffff8100b172 : system_call_fastpath+0x16/0x1b [kernel]
===
 0xffffffff8110e200 : filemap_write_and_wait_range+0x0/0x90 [kernel]
 0xffffffff811acbc8 : __blockdev_direct_IO+0x228/0xc40 [kernel]
 0xffffffffa008a24a
===
 0xffffffff8110e200 : filemap_write_and_wait_range+0x0/0x90 [kernel]
 0xffffffff8110f278 : generic_file_aio_read+0x498/0x870 [kernel]
 0xffffffff8117323a : do_sync_read+0xfa/0x140 [kernel]
 0xffffffff81173c65 : vfs_read+0xb5/0x1a0 [kernel]
 0xffffffff81173da1 : sys_read+0x51/0x90 [kernel]
 0xffffffff8100b172 : system_call_fastpath+0x16/0x1b [kernel]
===
 0xffffffff8110e200 : filemap_write_and_wait_range+0x0/0x90 [kernel]
 0xffffffff811acbc8 : __blockdev_direct_IO+0x228/0xc40 [kernel]
 0xffffffffa008a24a
===

filemap_write_and_wait_range的呼叫棧很清晰的暴露了一切!

小結:檔案系統比較複雜,最好不要混用bufferedio和directio!
祝玩得開心!

Post Footer automatically generated by wp-posturl plugin for wordpress.

相關推薦

系統技術業餘研究 » BufferedIODirectIO混用導致問題

今天曲山同學在線上問道: 我測試發現,如果cp一個檔案,然後direct io讀這個檔案,會消耗很長時間。 我猜測dio不能用page cache,而這個檔案cp以後都在cache裡面,要強制刷到磁碟,才能讀? 我cp這個檔案很大,超過256M 由於資料檔案預設是用bufferedio方式開啟的

系統技術業餘研究 » Flashcache新新增驅逐空閒引數

我在之前的博文提過Flashcache的cache是以set為單位管理的,每個set預設2M。 當單個set裡面的髒頁數量超過dirty_thresh_pct的時候,就會啟動背景工作佇列來把超過設定的髒頁回寫到後備磁碟去。 這裡有別的同學對flashcache設計文件的翻譯. 參看dirty_th

系統技術業餘研究 » Erlangport通訊的資料格式

erlang內建的port非常強大,是erlang通往外面世界的通道,所以port和erlang程式的通訊的資料格式影響了通訊的效率,和穩定性。我們在選擇格式的時候, 會優先考慮到erlang的特性和port程式編寫語言的特點,選出一種2者都容易處理的格式。 通訊通常有2種,基於行的文字和2進位制

系統技術業餘研究 » ftrace它的前端工具trace

最近在調查lockless的ring_buffer的時候,發現了ftrace. ftrace是 Linux 核心中提供的一種除錯工具。使用 ftrace 可以對核心中發生的事情進行跟蹤,這在除錯 bug 或者分析核心時非常有用. ftrace在2.6.28-rc2以後的Linux核心都支援

系統技術業餘研究 » rebarcommon_test使用實踐疑惑澄清

rebar is an Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. rebar is a self-contained Erla

系統技術業餘研究 » Erlang節點重啟導致的incarnation問題

今天晚上mingchaoyan同學在線上問以下這個問題: 152489 =ERROR REPORT==== 2013-06-28 19:57:53 === 152490 Discarding message {send,<<19 bytes>>} from <0.8

系統技術業餘研究 » Linux下如何知道檔案被那個程序

晚上朔海同學問: 一個檔案正在被程序寫 我想檢視這個程序 檔案一直在增大 找不到誰在寫 使用lsof也沒找到 這個問題挺有普遍性的,解決方法應該很多,這裡我給大家提個比較直觀的方法。 linux下每個檔案都會在某個塊裝置上存放,當然也都有相應的inode, 那麼透過vfs.write我們就可以知道

系統技術業餘研究 » 新的工作研究方向

和大家更新下: 做了將近8年資料庫後,我的工作和研究方向將會延伸到虛擬化和計算相關的雲服務,希望能夠和大家一起進步,Happy New Year! 預祝大家玩得開心! Post Footer automatically generated by wp-posturl plugin for w

系統技術業餘研究 » 如何檢視節點的可用控制代碼數目已用控制代碼數

很多同學在使用erlang的過程中, 碰到了很奇怪的問題, 後來查明都是檔案控制代碼不夠用了, 因為系統預設的是每個程序1024. 所以我們有必要在程式執行的時候, 瞭解這些資訊, 以便診斷和預警. 下面的這個程式就演示了這個如何檢視節點的可用控制代碼數目和已用控制代碼數的功能. 首先確保你已經安

系統技術業餘研究 » oprofile抓不到取樣資料問題解決方法

最近有同學反映在某些新機器上做效能調優的時候, oprofile 有時抓不到資料,我之前也遇到這個情況,很是無語,今天特地驗證了下。 # 我們的作業系統和機器配置大概是這樣的: $sudo aspersa/summary # Aspersa System Summary Report ##

系統技術業餘研究 » Erlang match_spec引擎介紹應用

match_spec是什麼呢? A “match specification” (match_spec) is an Erlang term describing a small “program” that will try to match something (either the para

系統技術業餘研究 » Erlang虛擬機器基礎設施dtrace探測點介紹使用

最新的Erlang虛擬機器(R15B01)很大的一個改進就是加入了對dtrace探測點的支援了, 具體參見這裡, 主要目標是方便在生產實踐中定位複雜的效能問題。 目前Erlang的虛擬機器的探測點支援Linux的systemtap和freebsd的dtrace,我們剛好能夠享受的到。 作者Scot

系統技術業餘研究 » Erlang 網路密集型伺服器的瓶頸解決思路

最近我們的Erlang IO密集型的伺服器程式要做細緻的效能提升,從每秒40萬包處理提升到60萬目標,需要對程序和IO排程器的原理很熟悉,並且對行為進行微調,花了不少時間參閱了相關的文件和程式碼。 其中最有價值的二篇文章是: 1. Characterizing the Scalability of

系統技術業餘研究 » gen_tcp:send的深度解刨使用指南(初稿)

在大家的印象中, gen_tcp:send是個很樸素的函式, 一呼叫資料就喀嚓喀嚓到了對端. 這是個很大的誤解, Erlang的otp文件寫的很不清楚. 而且這個功能對於大部分的網路程式是至關重要的, 它的使用對否極大了影響了應用的效能. 我聽到很多同學在抱怨erlang的效能低或者出了很奇怪的問

系統技術業餘研究 » 計算機各系統元件的吞吐量延遲 看圖不說話

這個圖挺好的,就是比較粗線條,有些東西不太完整/準確,比如現有的USB實際上是480M/12M和1.5M三種速率(暫不算3.0和無線的) 另:幫樓主補充一下這類資料的意義:如果對各種匯流排的速率和IOPS如果沒有概念和預估,寫程式時就只能Compile & Pray了。 Reply:O

系統技術業餘研究 » 如何在TILEPro64多核心板卡上編譯執行Erlang

美國Tilera公司的眾核伺服器,單顆核心包含64顆CPU。硬體架構圖: 卡長這樣的: Erlang已經可以在這款CPU上成功執行,我們可以參考Ulf Wiger在Multicore ☺ Message-passing Concurrency 文件中關於Erlang在Tilera上的效能圖

系統技術業餘研究 » erlang的profile工具原理優缺點

erlang的tools application下包含了一系列的profile工具, 包括 eprof cprof fprof, 具體的使用可以參看文件和<< erlang effective guide>>. 我這裡要說的是他們的工作原理。 這些模組的核心都是根據erla

系統技術業餘研究 » 轉:CPU密集型計算 erlangC 大比拼

原文地址:http://pseudelia.wordpress.com/2009/08/23/erlang-native-code-benchmark/ Normalerweise compiliert Erlang Bytecode (heißt das so in Erlang?). Das

系統技術業餘研究 » 區域性性原理在計算機分散式系統中的應用課程PPT

這個課程最主要focus在資料的區域性性原理,從硬體到作業系統到應用程式這樣的順序過來的,對於我們提高核心系統軟體的效能非常有啟發意義. 課件下載點選這裡 修正:由於原連結已經不存在了,特地在這裡放了一份。 以下是教程的介紹: 課程簡介 ___________________________

系統技術業餘研究 » erlang高階原理應用PPT

公司培訓用的 湊合看吧 主要講erlang系統的特點,分佈叢集以及mnesia的使用, 從比較高的角度來看erlang, 讓你有了大體觀. Post Footer automatically generated by wp-posturl plugin for wordpress. No