當環境變數使進程加速 40 倍時

今天我們想談談 Sherlock 系統的一些最新更新[這是史丹佛大學的一個高效能集群 - 大約。 trans.],這顯著加快了列出具有大量條目的目錄中的檔案的速度。

與普通文章不同,這更多的是內部人士的報告,介紹我們如何定期開發 Sherlock,以使其為用戶保持最佳運行狀態。 我們希望將來發表更多這樣的文章。

列出許多文件需要時間

這一切都始於用戶的技術支援問題。 他報告了執行的問題 ls 在包含超過 15 個條目的目錄中需要幾分鐘 $SCRATCH [暫存檔案目錄 - 約。 車道]。

一個目錄中的數千個檔案通常會對檔案系統造成負擔,絕對不建議這樣做。 用戶知道這一點並承認這不好,但提到在他的筆記型電腦上列出的速度比 Sherlock 快 1000 倍。 當然,這傷害了我們。 所以我們看得更深入。

因為ls看起來不錯

我們研究了它的實際作用 ls 列出目錄時,以及為什麼該過程需要這麼長時間。 在大多數現代發行版上 ls 預設情況下它運行為 ls --color=auto,因為每個人都喜歡這些顏色。

但美麗的色彩是有代價的:對於每個文件 ls 必須取得有關文件類型、其權限、標誌、擴充屬性等的信息,以便選擇適當的顏色。

解決這個問題的一個簡單方法是完全停用 ls 中的顏色,但想像一下使用者的憤怒。 在任何情況下都不應該取消顏色輸出,我們不是怪物。

所以我們看得更深入。 ls 透過環境變數的顏色條目 LS_COLORS,設定為 dircolors(1) 基於設定檔 dir_colors(5)。 是的, 可執行檔讀取設定檔以建立環境變量,然後 ls 使用該環境變量 (如果你不了解文件 (do),然後是 dir_colors 會起作用的, 儘管一切)。

讓我們仔細看看

為了確定哪種配色方案導致速度變慢,我們創建了一個實驗環境:

$ mkdir $SCRATCH/dont
$ touch $SCRATCH/dont/{1..10000} # don't try this at home!
$ time ls --color=always $SCRATCH/dont | wc -l
10000

real    0m12.758s
user    0m0.104s
sys     0m0.699s

12,7 個檔案需要 10 秒,不太好。

順便說一句,我們需要一個標誌 --color=always: 雖然他轉向 ls --color=autols 偵測何時未連接到終端(例如透過管道或使用輸出重定向)並停用著色(如果設定為) auto。 聰明的傢伙。

那麼什麼需要這麼長時間呢? 我們看著 strace:

$ strace -c ls --color=always $SCRATCH/dont | wc -l
10000
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 44.21    0.186617          19     10000           lstat
 42.60    0.179807          18     10000     10000 getxattr
 12.19    0.051438           5     10000           capget
  0.71    0.003002          38        80           getdents
  0.07    0.000305          10        30           mmap
  0.05    0.000217          12        18           mprotect
  0.03    0.000135          14        10           read
  0.03    0.000123          11        11           open
  0.02    0.000082           6        14           close
[...]

哇:10 通電話 lstat(), 10 通通話 getxattr() (全部失敗,因為我們的環境沒有 ls 正在尋找的屬性),10 次調用 capget().

當然,這可以優化。

能力屬性? 沒有

遵循建議 10年前的bug,我們嘗試停用屬性檢查 能力:

$ eval $(dircolors -b | sed s/ca=[^:]*:/ca=:/)
$ time strace -c ls --color=always $SCRATCH/dont | wc -l
10000
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 98.95    0.423443          42     10000           lstat
  0.78    0.003353          42        80           getdents
  0.04    0.000188          10        18           mprotect
  0.04    0.000181           6        30           mmap
  0.02    0.000085           9        10           read
  0.02    0.000084          28         3           mremap
  0.02    0.000077           7        11           open
  0.02    0.000066           5        14           close
[...]
------ ----------- ----------- --------- --------- ----------------
100.00    0.427920                 10221         6 total

real    0m8.160s
user    0m0.115s
sys     0m0.961s

哇,高達8秒的加速! 我們擺脫了所有那些昂貴的電話 getxattr()和挑戰 capget() 也消失了,太好了。

但仍然有這些煩人的電話 lstat(), 雖然…

你需要多少朵花?

因此,我們仔細觀察了 LS_COLORS.

首先我們簡單地禁用這個變數:

$ echo $LS_COLORS
rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:
$ unset LS_COLORS
$ echo $LS_COLORS

$  time ls --color=always $SCRATCH/dont | wc -l
10000

real    0m13.037s
user    0m0.077s
sys     0m1.092s

什麼!?! 還有13秒嗎?

事實證明,當環境變量 LS_COLORS 只有一個元素未定義或缺失 <type>=color:,它預設使用內建資料庫並且仍然使用顏色。 因此,如果您想要停用某種文件類型的著色,則需要使用以下命令覆蓋它 <type>=:<type> 00 在文件中 DIR_COLORS.

經過大量的試驗和錯誤,我們將搜尋範圍縮小到:

EXEC 00
SETUID 00
SETGID 00
CAPABILITY 00

寫成

LS_COLORS='ex=00:su=00:sg=00:ca=00:'

這意味著:不要按屬性為文件著色。 能力,但是一點一點 setuid/setgid,也不由 可執行標誌.

我們加快速度 ls

如果您不執行任何這些檢查,則調用 lstat() 消失了,現在是完全不同的事了:

$ export LS_COLORS='ex=00:su=00:sg=00:ca=00:'
$ time strace -c ls --color=always $SCRATCH/dont | wc -l
10000
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 63.02    0.002865          36        80           getdents
  8.10    0.000368          12        30           mmap
  5.72    0.000260          14        18           mprotect
  3.72    0.000169          15        11           open
  2.79    0.000127          13        10           read
[...]
------ ----------- ----------- --------- --------- ----------------
100.00    0.004546                   221         6 total

real    0m0.337s
user    0m0.032s
sys     0m0.029s

0,3秒列出10個文件的列表,創紀錄。

設定夏洛克

從預設設定的 13 秒到微調後的 0,3 秒 LS_COLORS 意味著由於不存在而產生 40 倍的加速度 setuid / setgid 和彩色可執行檔。 沒有那麼大的損失。

當然,現在這是在 Sherlock 中為每個用戶配置的。

但如果你想恢復顏色,你可以簡單地恢復到預設:

$ unset LS_COLORS

但在有很多文件的目錄上,一定要在運行時煮咖啡 ls.

來源: www.habr.com

添加評論