簡體   English   中英

實時寫入磁盤

[英]real-time writes to disk

我有一個線程需要將數據從內存緩沖區寫入磁盤數千次。 我對每次寫入需要多長時間有一些要求,因為需要清除緩沖區以供單獨的線程再次寫入。

我已經用 dd 測試了磁盤。 我沒有在其上使用任何文件系統並直接寫入磁盤(使用直接標志打開它)。 我能夠以 32K 的塊大小獲得大約 100 MB/s 的速度。

在我的應用程序中,我注意到我無法以接近這個速度將數據寫入磁盤。 所以我調查了正在發生的事情,我發現有些寫入需要很長時間。 我的代碼塊看起來像(順便說一下,這是在 C 中):

last = get_timestamp();
write();
now = get_timestamp();
if (longest_write < now - last)
  longest_write = now - last;

最后我打印出最長的寫入。 我發現對於 32K 緩沖區,我看到最長的寫入速度約為 47 毫秒。 這太長了,無法滿足我的應用程序的要求。 我認為這不能完全歸因於磁盤的旋轉延遲。 任何想法發生了什么以及我可以做些什么來獲得更穩定的寫入速度? 謝謝

編輯:我實際上使用了我在上面聲明的類型的多個緩沖區並將它們之間的條帶化到多個磁盤。 我的問題的一種解決方案是增加緩沖區的數量以分攤長寫入的成本。 但是,我希望將用於緩沖的內存量保持在盡可能小,以避免弄臟產生寫入緩沖區的數據的線程的緩存。 我的問題應該僅限於處理將小塊寫入磁盤的延遲差異以及如何減少它。

我假設您使用的是連接到標准計算機中內置磁盤控制器的 ATA 或 SATA 驅動器。 這是一個有效的假設,還是您使用了任何不同尋常的東西(硬件 RAID 控制器、SCSI 驅動器、外部驅動器等)?

作為一名在工作中進行大量磁盤 I/O 性能測試的工程師,我會說這聽起來很像您的寫入被緩存在某處。 您的“高延遲”I/O 是該緩存最終被刷新的結果。 即使沒有文件系統,I/O 操作也可以緩存在 I/O 控制器或磁盤本身中。

為了更好地了解正在發生的事情,不僅要記錄最大延遲,還要記錄平均延遲。 考慮記錄最多 10-15 個延遲樣本,以便更好地了解這些高延遲樣本的(不)頻率。 此外,扔掉測試前兩三秒記錄的數據,然后開始數據記錄。 在磁盤測試開始時可能會出現高延遲 I/O 操作,但這些操作並不代表磁盤的真實性能(可能是由於磁盤必須加速到全速、磁頭必須執行大的初始搜索,正在刷新磁盤寫入緩存等)。

如果您想對磁盤 I/O 性能進行基准測試,我建議您使用IOMeter之類的工具,而不是使用dd或滾動您自己的工具。 IOMeter 可以輕松查看更改 I/O 大小、對齊方式等的差異,此外它還跟蹤許多有用的統計信息。

要求 I/O 操作在一定時間內發生是一件冒險的事情。 一方面,系統上的其他應用程序可以與您競爭磁盤訪問或 CPU 時間,幾乎不可能預測它們對您的 I/O 速度的確切影響。 您的磁盤可能會遇到壞塊,在這種情況下,它必須在處理 I/O 之前做一些額外的工作來重新映射受影響的扇區。 這引入了不可預測的延遲。 您也無法控制操作系統、驅動程序和磁盤控制器正在做什么。 由於各種不可預見的原因,您的 I/O 請求可能會在這些層之一中得到備份。

如果您對 I/O 時間有嚴格限制的唯一原因是因為您的緩沖區被重用,請考慮更改您的算法。 嘗試使用循環緩沖區,以便您可以在寫入數據時將數據刷新出來。 如果您發現填充它的速度比刷新它的速度快,則可以限制緩沖區的使用。 或者,您也可以創建多個緩沖區並在它們之間循環。 當一個緩沖區填滿時,將該緩沖區寫入磁盤並切換到下一個緩沖區。 即使第一個緩沖區仍在寫入,您也可以寫入新緩沖區。

回復評論:你不能真正“讓內核讓開”,它是系統中的最低級別,你必須通過一個或另一個程度。 您可以為您的磁盤控制器構建自定義版本的驅動程序(前提是它是開源的)並構建一個“高優先級”I/O 路徑供您的應用程序使用。 您仍然受磁盤控制器固件和驅動器本身的固件/硬件的支配,您不一定能預測或做任何事情。

傳統上,硬盤驅動器在執行大型順序 I/O 操作時性能最佳。 驅動程序、設備固件和操作系統 I/O 子系統會考慮到這一點,並嘗試將較小的 I/O 請求組合在一起,以便它們只需要向驅動器生成單個大型 I/O 請求。 如果您一次只刷新 32K,那么您的寫入可能會在某個級別緩存、合並並一次性發送到驅動器。 通過阻止這種合並,您應該減少 I/O 延遲“尖峰”的數量並看到更統一的磁盤訪問時間。 但是,與您通常看到的中等時間相比,這些訪問時間將更接近“尖峰”中看到的大時間。 延遲峰值對應於未與任何其他請求合並的 I/O 請求,因此必須吸收磁盤查找的全部開銷。 請求合並是有原因的; 通過捆綁請求,您可以通過多個命令分攤驅動器查找操作的開銷。 擊敗合並會導致執行比平時更多的搜索操作,從而使 I/O 速度整體變慢。 這是一種權衡:您以偶爾出現異常的高延遲操作為代價來減少平均 I/O 延遲。 然而,這是一個有益的權衡,因為與禁用合並相關的平均延遲增加幾乎總是比擁有更一致的訪問時間是一個優勢更不利。

我還假設您已經嘗試調整線程優先級,並且這不是您的高帶寬生產者線程因 CPU 時間而耗盡緩沖區刷新線程的情況。 你確認了嗎?

您說您不想打擾也在系統上運行的高帶寬線程。 您是否實際測試了各種輸出緩沖區大小/數量並測量了它們對另一個線程的影響? 如果是這樣,請分享您測量的一些結果,以便我們在集思廣益時可以使用更多信息。

考慮到大多數機器擁有的內存量,從 32K 緩沖區移動到通過 4 個 32K 緩沖區循環的系統是內存使用量的一個相當無關緊要的跳躍。 在具有 1GB 內存的系統上,緩沖區大小的增加僅代表系統內存的 0.0092%。 嘗試使用交替/旋轉緩沖區系統(為簡單起見,從 2 開始)並測量對高帶寬線程的影響。 我敢打賭,額外的 32K 內存不會對另一個線程產生任何明顯的影響。 這不應該是“弄臟了生產者線程的緩存”。 如果您經常使用這些內存區域,則應始終將它們標記為“正在使用”,並且永遠不應將其換出物理內存。 被刷新的緩沖區必須保留在物理內存中才能讓 DMA 工作,第二個緩沖區將在內存中,因為您的生產者線程當前正在寫入它。 事實,使用一個額外的緩沖會減少可用物理內存的生產線(雖然只是非常輕微)的總量,但如果你正在運行需要高帶寬和低延遲,然后應用程序,你會設計你的系統,它有超過 32K 的內存可供備用。

不是通過試圖強制硬件和低級軟件執行特定的性能測量來解決問題,更簡單的解決方案是調整您的軟件以適應硬件。 如果您測量最大寫入延遲為 1 秒(為了獲得更好的整數),請編寫您的程序,以使刷新到磁盤的緩沖區在至少 2.5-3 秒內不需要重新使用。 這樣,您就可以涵蓋最壞的情況,並提供安全余量,以防發生真正意外的情況。 如果您使用的系統在 3-4 個輸出緩沖區之間循環,則不必擔心在緩沖區被刷新之前重新使用緩沖區。 您將無法過於密切地控制硬件,並且如果您已經在寫入原始卷(無文件系統),那么您和您可以操縱或消除的硬件之間就沒有太多東西了。 如果您的程序設計不靈活並且您看到不可接受的延遲峰值,您可以隨時嘗試更快的驅動器。 固態驅動器不必“尋求”執行 I/O 操作,因此您應該看到相當統一的硬件 I/O 延遲。

只要你使用O_DIRECT | O_SYNC O_DIRECT | O_SYNC ,您可以使用ioprio_set()來設置進程/線程的 IO 調度優先級(盡管手冊頁說“進程”,但我相信您可以傳遞gettid()給出的 TID)。

如果您設置了實時 IO 類,那么您的 IO 將始終首先訪問磁盤 - 聽起來這就是您想要的。

我有一個線程需要將數據從內存緩沖區寫入磁盤數千次。

我已經用 dd 測試了磁盤。 我沒有在其上使用任何文件系統並直接寫入磁盤(使用直接標志打開它)。 我能夠以 32K 的塊大小獲得大約 100 MB/s 的速度。

dd的塊大小與文件系統塊大小對齊。 我猜你的日志文件不是。

另外,您的應用程序可能不僅會寫入日志文件,還會執行其他一些文件操作。 或者您的應用程序並不孤單使用磁盤。

通常,磁盤 I/O 沒有針對延遲進行優化,而是針對吞吐量進行了優化。 高延遲很正常 - 網絡文件系統的延遲更高。

在我的應用程序中,我注意到我無法以接近這個速度將數據寫入磁盤。 所以我調查了正在發生的事情,我發現有些寫入需要很長時間。

一些寫入需要更長的時間,因為在某個時間點之后,您將寫入隊列飽和,而操作系統最終決定將數據實際刷新到磁盤。 默認情況下,I/O 隊列配置得非常短:以避免由於崩潰而導致過度緩沖和信息丟失。

注意:如果您想查看實際速度,請嘗試在打開文件時設置O_DSYNC標志。

如果您的塊確實對齊,您可以嘗試使用O_DIRECT標志,因為這將消除 Linux 磁盤緩存級別上的爭用(與其他應用程序)。 寫入將以磁盤的實際速度工作。

使用dd 100MB/s - 沒有任何同步 - 是一個高度綜合的基准測試,因為您永遠不知道數據已經真正到達磁盤。 嘗試將conv=dsync添加到dd的命令行。

還嘗試使用更大的塊大小。 32K還是小。 幾年前,當我測試順序 I/O 和隨機 I/O 時,IIRC 128K 大小是最佳的。

我看到最長的寫入速度約為 47 毫秒。

“實時”!=“快速”。 如果我將最大響應時間定義為 50 毫秒,並且您的應用始終在 50 毫秒內響應(47 < 50),那么您的應用將被歸類為實時。

我認為這不能完全歸因於磁盤的旋轉延遲。 任何想法發生了什么以及我可以做些什么來獲得更穩定的寫入速度?

我認為您無法避免write()延遲。 延遲是磁盤 I/O 的繼承屬性。 您無法避免它們 - 您必須期待並處理它們。

我只能想到以下選項:使用兩個緩沖區。 第一個將由write() ,第二個 - 用於存儲來自線程的新傳入數據。 write()完成時,切換緩沖區,如果有東西要寫,就開始寫。 這樣,線程總是有一個緩沖區可以將信息放入其中。 如果線程生成信息的速度比 write() 可以寫入的速度快,則仍可能發生溢出。 在這種情況下,動態添加更多緩沖區(最多達到某個限制)可能會有所幫助。

否則,只有當您的應用程序是磁盤的唯一用戶時,您才能實現(旋轉)磁盤 I/O 的某種實時性。 (實時應用程序的舊規則適用:只能有一個。) O_DIRECT以某種方式幫助從等式中消除操作系統本身的影響。 (盡管由於文件擴展名的塊分配,您仍然會以偶爾延遲的形式存在文件系統的開銷。在 Linux 下,它工作得非常快,但仍然可以通過提前預分配整個文件來避免,例如通過寫入零。 ) 如果時間真的很重要,請考慮為這項工作購買專用磁盤。 SSD 具有出色的吞吐量,並且不會受到搜索的影響。

您是寫入新文件還是覆蓋同一個文件?

與 dd 的最大區別可能是尋道時間,dd 正在流式傳輸到一個連續的(主要是)塊列表,如果您正在編寫大量小文件,則頭部可能會在整個驅動器上尋找以分配它們。

解決問題的最好方法可能是取消在特定時間寫入日志的要求。 您能否使用一組緩沖區,以便在新日志數據到達另一個緩沖區時寫入(或至少發送到驅動器的緩沖區)一個緩沖區?

linux 不會直接向磁盤寫入任何內容,它將使用虛擬內存,然后內核線程調用 pdflush 會將這些數據寫入磁盤,可以通過 sysctl -w "" 控制 pdflush 的行為

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM