我們在 Sublight 上用 PostgreSQL 寫入:1 台主機,1 天,1TB

最近我告訴你如何使用標準食譜 提高 SQL 讀取查詢的效能 來自 PostgreSQL 資料庫。 今天我們就來談談如何 錄音可以更有效地進行 在資料庫中,無需在配置中使用任何「扭曲」 - 只需正確組織資料流即可。

我們在 Sublight 上用 PostgreSQL 寫入:1 台主機,1 天,1TB

#1. 切片

一篇關於如何以及為何值得組織的文章 「理論上」應用分區 已經有了,這裡我們將討論在我們的範圍內應用一些方法的實踐 數百台 PostgreSQL 伺服器的監控服務.

「那些年的事…」

最初,和任何MVP 一樣,我們的專案在相當輕的負載下開始- 只​​對最關鍵的十台伺服器進行監控,所有表都相對緊湊......但隨著時間的推移,監控的主機數量越來越多,我們再次嘗試用其中一個做某事 表大小為 1.5TB,我們意識到雖然可以繼續這樣生活,但是很不方便。

那個時代幾乎就像史詩般的時代,不同版本的 PostgreSQL 9.x 是相關的,因此所有分區都必須「手動」完成 - 透過 表繼承和觸發器 動態路由 EXECUTE.

我們在 Sublight 上用 PostgreSQL 寫入:1 台主機,1 天,1TB
事實證明,最終的解決方案足夠通用,可以轉換為所有表:

  • 聲明了一個空的“header”父表,它描述了所有 必要的索引和觸發器.
  • 從客戶端的角度來看的記錄是在「根」表中進行的,並且內部使用 路由觸發 BEFORE INSERT 該記錄被“物理”插入到所需的部分。 如果還沒有這樣的事情,我們就會捕獲一個異常並且...
  • … 透過使用 CREATE TABLE ... (LIKE ... INCLUDING ...) 根據父表的範本創建 對所需日期有限制的部分這樣當檢索資料時,僅在其中執行讀取。

PG10:第一次嘗試

但從歷史上看,透過繼承進行分區並不適合處理活動寫入流或大量子分區。 例如,您可以回憶一下用於選擇所需部分的演算法 二次複雜度,它適用於 100 多個部分,您自己了解如何...

在PG10中,透過實施支援大大優化了這種情況 本機分區。 因此,我們在遷移儲存後立即嘗試立即應用,但是...

仔細閱讀手冊後發現,此版本中的本機分區表是:

  • 不支援索引描述
  • 不支援觸發器
  • 不能成為任何人的“後代”
  • 不支持 INSERT ... ON CONFLICT
  • 無法自動生成節

額頭被耙子狠狠地敲了一下,我們意識到如果不修改應用程式就不可能做到這一點,因此將進一步的研究推遲了六個月。

PG10:第二次機會

於是,我們開始一一解決出現的問題:

  1. 因為觸發器和 ON CONFLICT 我們發現我們仍然到處需要它們,所以我們做了一個中間階段來解決它們 代理表.
  2. 擺脫“路由” 在觸發器中 - 也就是說,從 EXECUTE.
  3. 他們分別拿出來 包含所有索引的範本表因此它們甚至不存在於代理表中。

我們在 Sublight 上用 PostgreSQL 寫入:1 台主機,1 天,1TB
最後,在這一切之後,我們對主表進行了原生分區。 新部分的創建仍然取決於應用程式的良心。

「鋸」字典

就像任何分析系統一樣,我們也有 “事實”與“刪減” (字典)。 在我們的案例中,他們以此身分行事,例如, 模板體 類似的慢查詢或查詢本身的文字。

「事實」已經按天劃分很長時間了,所以我們平靜地刪除了過時的部分,它們並沒有打擾我們(日誌!)。 但是字典有問題...

並不是說有很多,但大約 100TB 的「事實」產生了 2.5TB 的字典。 您無法方便地從這樣的表中刪除任何內容,也無法在足夠的時間內壓縮它,並且寫入它的速度逐漸變慢。

就像一本字典......其中,每個條目應該只出現一次......這是正確的,但是!......沒有人阻止我們擁有 每天都有一本單獨的字典! 是的,這帶來了一定的冗餘,但它允許:

  • 寫/讀速度更快 由於截面尺寸較小
  • 消耗更少的記憶體 透過使用更緊湊的索引
  • 儲存較少的數據 由於能夠快速刪除過時的

由於採取了一系列複雜的措施 CPU 負載降低約 30%,磁碟負載降低約 50%:

我們在 Sublight 上用 PostgreSQL 寫入:1 台主機,1 天,1TB
同時,我們繼續將完全相同的內容寫入資料庫,只是負載較少。

#2. 資料庫演化與重構

所以我們決定了我們所擁有的 每天都有自己的部分 與數據。 實際上, CHECK (dt = '2018-10-12'::date) — 並且有一個分區鍵和一筆記錄落入特定部分的條件。

由於我們服務中的所有報告都是在特定日期的背景下建立的,因此自「非分區時間」以來它們的索引都是所有類型 (伺服器, 日期,計劃模板), (伺服器, 日期,計劃節點), (日期,錯誤類別,伺服器),...

但現在他們住在每個區域 你的副本 每個這樣的索引......以及在每個部分中 日期是一個常數……事實證明,現在我們在每個這樣的索引中 只要輸入一個常數 作為欄位之一,這會增加其數量和搜尋時間,但不會帶來任何結果。 他們把耙子留給了自己,哎呀......

我們在 Sublight 上用 PostgreSQL 寫入:1 台主機,1 天,1TB
優化的方向很明顯—簡單 從所有索引中刪除日期字段 在分區表上。 考慮到我們的數量,收益約為 1TB/週!

現在讓我們注意,這個太字節仍然必須以某種方式記錄。 也就是說,我們也 磁碟現在應該加載更少! 這張圖清楚地顯示了我們花了一周時間進行清潔所獲得的效果:

我們在 Sublight 上用 PostgreSQL 寫入:1 台主機,1 天,1TB

#3。 「分散」高峰負荷

負載系統的一大麻煩是 冗餘同步 一些不需要它的操作。 有時“因為他們沒有註意到”,有時“這樣更容易”,但遲早你必須擺脫它。

讓我們放大上一張圖片,看看我們有一個磁碟 雙振幅負載下的“泵浦” 相鄰樣本之間的差異,顯然「統計上」不應發生如此數量的操作:

我們在 Sublight 上用 PostgreSQL 寫入:1 台主機,1 天,1TB

這是很容易實現的。 我們已經開始監控 近1000台伺服器,每個都由一個單獨的邏輯線程處理,每個線程都會以一定的頻率重置要發送到資料庫的累積訊息,如下所示:

setInterval(sendToDB, interval)

這裡的問題恰恰在於: 所有執行緒幾乎同時啟動,因此他們的發送時間幾乎總是「恰到好處」地一致。 哎呀#2...

幸運的是,這很容易解決, 新增「隨機」助跑 按時間:

setInterval(sendToDB, interval * (1 + 0.1 * (Math.random() - 0.5)))

#4。 我們緩存我們需要的東西

第三個傳統的高負載問題是 無緩存 他在哪 可以 成為。

例如,我們可以根據計劃節點進行分析(所有這些 Seq Scan on users),但立即認為它們在很大程度上是相同的 - 他們忘記了。

不,當然,沒有任何內容再次寫入資料庫,這會切斷觸發器 INSERT ... ON CONFLICT DO NOTHING。 但這些數據仍然到達資料庫,而且沒有必要 閱讀以檢查衝突 得做。 哎呀#3...

啟用快取之前/之後傳送到資料庫的記錄數差異很明顯:

我們在 Sublight 上用 PostgreSQL 寫入:1 台主機,1 天,1TB

這是隨之而來的儲存負載下降:

我們在 Sublight 上用 PostgreSQL 寫入:1 台主機,1 天,1TB

在總

「每天太字節」聽起來很可怕。 如果你做的一切都是對的,那麼這只是 2^40 位元組/86400 秒 = ~12.5MB/s連桌面 IDE 螺絲也能固定。 🙂

但說實話,即使白天的負載「傾斜」十倍,您也可以輕鬆滿足現代 SSD 的功能。

我們在 Sublight 上用 PostgreSQL 寫入:1 台主機,1 天,1TB

來源: www.habr.com

添加評論