在修改大文件時存檔大文件的最無副作用的方法
我正在關註一個在 Red Hat 伺服器上的日誌文件中生成大量數據(每天大約 5G)的應用程序。這個過程在一周中執行 24 小時,因此文件沒有被修改的那一天是沒有意義的,儘管在午夜添加到它的資訊並不是特別重要,所以如果我輸了也沒關係讓我們說一個在此期間幾秒鐘的數據。
為了每天對日誌文件進行“安全”存檔,我創建了一個腳本,該腳本在清晨的某個時間點執行以下操作:
- 將文件複製到本地文件夾
- 截斷“活動”文件
- tar+壓縮副本
- 將副本的 tar.gz 移動到我們的存檔空間
這是腳本本身,以防出現明顯問題:
DF=$(date +"%Y%m%d_%H%M%S") TARGET="fixdata-logs-$DF" cp -r ./fixdata/logs $TARGET #Truncate the original log file find ./fixdata/logs -name '*.log' -exec sh -c 'cat /dev/null >| {}' \; #Zip the log files tar -zcvf $TARGET.tar.gz $TARGET #Delete the labelled copy rm -rf $TARGET #Archive files older tha 3 days find . -type f -mtime +3 -name \*.gz -exec mv {} $ARCHIVE_DIR \;
(我知道一些數據可能會失去,但這個腳本執行的時間是幾秒鐘的數據失去並不重要。)
問題是,在此期間,應用程序經常報告與系統資源相關的錯誤。例如,其隊列的心跳監視器經常無法產生正常的心跳。很明顯,這個 copy->tar.gz->move 過程對伺服器 IO 造成的影響足以影響應用程序的行為。
如何減少此腳本的影響?完成時間並不重要——如果解決方案需要更長的時間但不會導致應用程序錯誤,那麼這比快速解決方案更可取。還有其他我應該考慮的方法嗎?
為了完整起見,我考慮了以下但有疑問:
- 直接跳過複製部分和tar:但是我擔心如果文件在忙時被修改,tar會出現問題。
- 先複製到存檔文件夾,然後再 tar - 如果壓縮是在不同的磁碟上完成的,那麼 IO 影響會更小嗎?我擔心我們使用的存檔空間不適合進行壓縮等輸入/輸出磁碟操作,因為我認為它不是傳統的隨機存取磁碟。我也不確定複製到不同的物理磁碟是否不會讓事情變得更糟,因為我原以為作業系統有一些聰明的方法來製作本地副本,而無需物理讀取文件中的所有字節。不幸的是,我的 *nix 技能在這裡沒有幫助。
- 等到週末:不幸的是,伺服器上的磁碟空間不足以包含歸檔前一周的數據。當然我可以要求增加它,但首先我想看看是否有更理智的解決方案。
您可以通過不執行複制+截斷來顯著減少 I/O 負載。相反,重命名文件,然後,如果程序保持日誌文件描述符處於打開狀態,則執行所需的任何操作以使其回收其日誌描述符(通常發送 a
HUP
是這樣做的規範方式)。如果該程序還沒有該功能,則對其進行修補以使其具有。通過這樣做,您將不會有在同一介質上複製的 I/O 成本(這是同時讀+寫),然後是截斷(這可能是也可能不是顯著的負載,具體取決於您的文件系統) ,然後讀取到 tar/compress 和寫入載入以製作存檔。
重命名日誌文件後,您可以隨意壓縮/壓縮/壓縮。為了進一步減少 I/O 負載,請考慮將 tar/compress 的寫入端直接寫入存檔儲存——雖然您的存檔儲存可能不是典型的隨機訪問設備,但它仍然需要直接的動態壓縮的數據(即使 S3 也可以使用正確的 CLI 工具來做到這一點)。
與上述正交的另一件事是使用
ionice
. 通過以 as 執行程序ionice -c 3 <command>
,您將程序的 I/O 優先級降低為“僅空閒”——也就是說,如果系統上還有其他任何東西想要執行 I/O,您的程序將被撞到。這是一個好主意,但如果你有一個繁重的 I/O 系統,它可能會讓你陷入困境(你的程序可能需要aaaaaages才能完成,因為它很少獲得 I/O 時間)。如果您已經在執行大量不必要的 I/O,則將其設置為“僅空閒”優先級會使問題變得更糟。我也非常懷疑,僅空閒調度並沒有完全按照它所說的那樣進行。當“僅空閒”程序執行時,與“僅空閒”程序未執行時相比,我看到其他(“盡力而為”計劃的)程序的性能略有下降。我懷疑這是因為當程序在“僅空閒”程序正在進行 I/O 操作時請求 I/O 時,在“盡力而為”之前完成 I/O 之前會有延遲程序的 I/O 操作可以開始。也就是說,它仍然比“僅空閒”程序以“盡力而為”優先級執行要好得多,但這並不是乍看之下的奇妙修復。