在NFS(Network File System)文件系統中通過read、copy_file_range等系統調用讀取文件時,與同場景下的Alibaba Cloud Linux 2相比,可能會存在明顯的性能退化情況。本文介紹在Alibaba Cloud Linux 3系統的ECS實例中,在NFS文件系統下讀取文件時性能不符合預期的問題原因及解決方案。
問題描述
問題表現
在Alibaba Cloud Linux 3系統的NFS文件系統中讀取文件時性能不符合預期,典型表現如下:
使用read、copy_file_range等系統調用從NFS文件系統中讀取大文件時,耗時較久。
使用
dd
命令從NFS掛載點的文件中讀取數據時,Alibaba Cloud Linux 3比Alibaba Cloud Linux 2用時多。例如:dd if=<nfs_mntpoint>/<testfile> of=/dev/null bs=1M
說明該示例命令表示從NFS掛載點的testfile文件中讀取數據,并將其發送到/dev/null設備中。運行完畢后,
dd
會輸出一些信息,包括讀取的總字節數以及操作耗費的時間,用來計算讀取數據的速率,可以評估NFS文件系統的性能表現。
影響范圍
該問題主要在以下ECS實例中存在:
鏡像:aliyun_3_x64_20G_alibase_20210415.vhd及之后的所有鏡像版本。
內核:5.10.23-4.al8.x86_64及之后的所有內核版本。
文件系統:掛載NFS文件系統,讀取位于掛載點目錄下的文件。
問題原因
在上游Linux內核中,read_ahead_kb
表示塊設備的預讀窗口大小的參數。預讀(read-ahead)是一個性能優化技術,它允許系統預測接下來可能被讀取的數據并提前加載到內存中,這樣當這部分數據被請求時,就可以直接從內存中讀取,而不必等待磁盤I/O操作,從而降低延遲并提高數據讀取效率。
在Linux內核5.4版本之前,NFS文件系統的預讀量通常會基于掛載時設置的
rsize
參數(即每次NFS讀請求的大小)。默認情況下,NFS的預讀窗口read_ahead_kb
大小被設置為rsize
參數的15倍。Alibaba Cloud Linux 2的內核版本是4.19,默認的rsize
參數大小為1,024 KB,即read_ahead_kb
大小為15,360 KB。然而,在Linux內核5.4版本中引入了一個提交(index : kernel/git/torvalds/linux.git),隨后
read_ahead_kb
的值不再基于rsize
參數,而是與VM_READAHEAD_PAGES
參數相關。Alibaba Cloud Linux 3的內核版本是5.10,默認的read_ahead_kb
大小為128 KB。
所以,Alibaba Cloud Linux 3相比于Alibaba Cloud Linux 2的讀取文件性能有所下降。因此Alibaba Cloud Linux 3需要重新評估和調整預讀窗口大小,以優化文件的讀取效率。
在NFS文件系統中,較大的預讀窗口可能會提高大型文件連續讀取的性能,但如果窗口太大,也可能導致不必要的數據被加載到內存中,尤其是在隨機讀取的場景中。因此建議您根據實際的業務場景,仔細評估實際的工作負載,調整read_ahead_kb
參數值以確保找到最佳的預讀窗口大小。
解決方案
您可以選擇以下任意一種方式修改read_ahead_kb
參數來設置預讀值。
通過echo
命令修改(單個文件系統修改)
查看NFS系統目標設備當前的預讀參數。
cat /sys/class/bdi/$(mountpoint -d <nfs_mountpoint>)/read_ahead_kb
其中
<nfs_mountpoint>
需替換為實際的NFS掛載點路徑,可以通過cat /proc/self/mountinfo
命令獲取。適當調大NFS文件系統所對應設備的預讀參數。
sudo sh -c 'echo <num> > /sys/class/bdi/<major>:<minor>/read_ahead_kb'
您需要根據實際環境替換以下參數:
<num>
:需要設置的預讀窗口大小(單位KB)。<major>:<minor>
:NFS文件系統的主要和次要設備號,可以通過sudo mountpoint -d <nfs_mountpoint>
命令獲取。
例如:
sudo sh -c 'echo 15360 > /sys/class/bdi/0:422/read_ahead_kb'
說明如果您掛載了多個NFS文件系統,需要重復執行命令修改每一個設備的預讀參數。
通過udev機制自動修改(多個文件系統修改)
您也可以利用udev機制,添加udev規則,為所有已掛載的設備手動觸發一次udev事件,使其觸發udev規則檢查并自動修改預讀參數,也可以使后續新掛載的文件卷自動修改其預讀參數。操作步驟如下:
udev(用戶空間設備管理器)是Linux內核的一個子系統,負責設備節點的管理和自動化。udev機制的核心組件是udev守護進程,它運行于用戶空間,并與內核通過uevent機制進行通信。
打開并編輯NFS的udev rules配置文件(位于
/etc/udev/rules.d/
目錄)。如果不存在udev rules配置文件,請先自行創建。例如:sudo vim /etc/udev/rules.d/99-nfs.rules
在打開的文件中,添加udev規則,以自動修改預讀參數。
該示例表示將
read_ahead_kb
的值設置為15,360 KB,您可以根據需要修改預讀參數。SUBSYSTEM=="bdi", ACTION=="add", PROGRAM="/bin/awk -v bdi=$kernel 'BEGIN{ret=1} {if ($4 == bdi) {ret=0}} END{exit ret}' /proc/fs/nfsfs/volumes", ATTR{read_ahead_kb}="15360"
保存并關閉文件。
重新加載udev規則,使新增規則生效。
sudo udevadm control --reload
為所有已經掛載的設備手動觸發一次udev事件,將已掛載設備的
read_ahead_kb
值一并修改。sudo udevadm trigger -c add -s bdi
通過修改NFS的配置文件(2.3.3-57.0.1.al8.1及之后版本的多個文件系統修改)
如果您的Alibaba Cloud Linux 3的NFS文件系統版本是nfs-utils-2.3.3-57.0.1.al8.1及之后的版本(可以通過rpm -qa | grep nfs-utils
命令查詢 ),可以通過修改NFS的配置文件來修改read_ahead_kb
參數(位于 /etc/nfs.conf
目錄 )。
打開并編輯NFS的配置文件。
sudo vim /etc/nfs.conf
修改默認預讀值,然后保存并關閉文件。
[nfsrahead] nfs=15000 nfs4=16000
請根據實際掛載的NFS文件系統版本(nfs/nfsv4)修改對應參數值。
nfs
表示NFS文件系統協議版本是3;nfs4
表示NFS文件系統協議版本是4,您可以通過mount -v | grep nfs
命令查詢。對于已掛載的NFS文件系統,需要手動卸載后重新掛載使配置生效。
sudo umount <nfs_mountpoint> sudo mount -t nfs -o vers=<NFS協議版本> <NFS服務器地址> <nfs_mountpoint>