問題:
使用vdbench進行單層100w目錄,每個目錄30個檔案,共3000w檔案讀寫時,在建立檔案得時候IO會出現斷斷續續得情況。
分析過程:
1、 nfs抓包分析
使用vdbench建立一個檔案得流程eg: vdb_f0398.file:
Lookup call -> lookup reply ->create call ->create reply ->write call ->write reply
2、 當vdbench IO歸0時,觀察儲存端狀態
1) read IO特別大,write IO為0
看4標識
2) zfs arc到了limit點為,arc_prune數值增加,意味著頻繁得回收arc,但arc大小為變化
看上圖1是設定的arc_meta_limit,2是已經使用的arc_meta空間,一般觸發回收時會高出limit限制幾百M,3是回收次數。其在arc_meta使用觸發回收時短時間內多次回收呼叫,但是回收的arc空間很少,之後不再回收,導致arc一直是full的狀態。
3) arc相關引數變化
沒有釋放arc
看圖5標識,此處為有寫IO時,此時為readdir執行完了一次後,在對應的目錄下建立了30個檔案(vdbech配置的)。
4) 使用perf分析程式變化情況
發現程式lz4_decompress_zfs 程式變化比較明顯
5) 通過dump_stack列印lz4的呼叫棧:
從列印情況看兩個可疑點,出問題的時候zfs_readdir 和 reconnect_path被不停的呼叫
6) 從這兩個地方分析是否存在問題
1》 zfs_readdir其dump_stack情況
分析內部程式碼,列印事件發現:
會發現while執行的次數和時間會隨著目錄數的增加線性增長,100w目錄查詢一次一般會超過10s(8s-180s,當時應該受到arc回收影響,沒出現IO歸零時不會呼叫到此函式)
2》 reconnect_path情況
出現問題時,exportfs引數沒有收到期望的具體vdb.1_6795.dir目錄名,而是根目錄/(注意此處設定nfsd thread數為1,預設是32,會進行32次根目錄的呼叫,其造成阻塞的概率增大,並耗時非常長)
由此觸發了zfs_readdir
此處引出問題,為什麼引數會是根目錄????
7) 當arc快取開始執行回收操作時,出現問題
而多次回收記憶體並未釋放多少,前面圖示可以看出。
8) 由上聯合起來分析彙總:
當arc使用接近限制閾值的時候,觸發回收操作,而回收操作只回收一點,但將原來的目錄快取破壞掉,使用新建立的檔案後設資料來填充arc,大量的arc快取無法釋放。導致當伺服器端nfs執行 lookup確定要建立的檔案是否合法時,觸發了reconnect_path->zfs_readdir等操作,來進行所有目錄的重新匹配,而此時arc已經滿了無法快取,導致接下來的每次lookup都要執行一遍readdir。
此處引出問題,為什麼快取釋放不了???
3、 由上分析,猜測伺服器vdbench快取了inode,dentry等資訊
通過在跑vdbench IO時,觀察伺服器記憶體使用情況發現,隨著建立資料夾和檔案,記憶體使用明顯
嘗試在儲存端arc接近快取閾值時,清除伺服器的快取,主要是dentry、inode資訊。多次測試發現問題不再重現。Arc可以正常釋放,並且釋放速度較快。
4、 綜上確定問題出現vdbenc IO,在建立資料夾和檔案的時候會影響zfs ARC快取釋放,引出問題:
1) vdbench 在沒有建立完檔案之前會維護這些link?
2) Nfs客戶端做的快取?
3) 此現象對其他公司nas產品是否一樣?
4) 需要儲存端解決此問題?如何解決?
5、arc小於2G回收會出問題這個大概率是之前的因素影響,還在分析程式碼並測試中~~。測試了一次1.5G的在伺服器端正常釋放快取後,沒啥問題。