存儲與索引------《Designing Data-Intensive Applications》讀書筆記3

来源:https://www.cnblogs.com/happenlee/archive/2017/12/26/8118267.html
-Advertisement-
Play Games

在上一篇的筆記之中,我們討論了數據模型和查詢語言。在第三章之中我們來聊一聊不同的數據引擎內部是如何實現存儲和檢索的,以及不同設計之間的折中與妥協。 1.鍵值對資料庫 鍵值對資料庫是資料庫形式之中最簡單的一種模式,我們可以把它簡化的實現為下麵兩個函數: 底層存儲格式也十分簡單:一個文本文件,其中每行包 ...


在上一篇的筆記之中,我們討論了數據模型和查詢語言。在第三章之中我們來聊一聊不同的數據引擎內部是如何實現存儲和檢索的,以及不同設計之間的折中與妥協。

1.鍵值對資料庫

鍵值對資料庫是資料庫形式之中最簡單的一種模式,我們可以把它簡化的實現為下麵兩個函數:
通過兩個Shell函數就可以實現簡易的鍵值對資料庫
底層存儲格式也十分簡單:一個文本文件,其中每行包含一個鍵值對,用逗號分隔(類似於CSV文件,忽略轉義問題)。每一次調用 db_set 會追加鍵值對到文件的末尾,如果你更新的一個鍵值對的舊版本不會覆蓋之前的鍵值對,但是 db_get會利用 tail -n 1 in 語句讀取最新的鍵值對。但是真正的資料庫需要處理更多的問題(例如併發控制、回收磁碟空間、使日誌不能永久增長、處理錯誤和部分寫的問題),但基本設計思路和原則是相同的。

但是,db_get 在性能上表現的很糟糕,每一次需要查找一個key,db_get 會掃描整個資料庫文件來查找Key。在演算法定義之中,查找的時間複雜度是O(n)。為了有效地查找資料庫中某個特定鍵的值,我們需要一個不同的數據結構:索引

2.索引

索引是從原始數據派生出來的附加結構。在添加和刪除索引時,不會影響數據存儲的內容,它只會影響查詢的性能。但是維護額外的結構會導致開銷,尤其是寫操作。任何類型的索引都會減慢寫速度,因為每次寫入數據時也需要更新索引。
在存儲系統的有一個重要的權衡:精心挑選的索引加快了讀取的速度,但是每個索引都會減慢寫入速度。由於這個原因,資料庫通常不會預設索引所有內容,但要求應用程式開發人員或資料庫管理員手動地選擇索引,可以選擇使應用程式受益最大的索引,而不需要引入更多的開銷。

  • 哈希索引
    這裡我們通過哈希索引來分析一下上文提及的那個簡易的鍵值資料庫。最簡單的索引策略是:保持一個記憶體的哈希映射,其中每一個鍵都映射到數據文件中的位元組偏移量,通過偏移量可以找到該值的位置,如下圖所示:
    記憶體哈希映射索引
    每當向文件追加一個新的鍵值對時,也會同時更新哈希映射以反映剛纔寫入的數據的偏移量(這既可以用於插入新的鍵值對,也可以用於更新現有的鍵值對)。在查找值時,使用哈希映射查找數據文件中的偏移量,查找該位置並讀取該值。
    那麼我們如何避免最終耗盡磁碟空間呢?一個好的解決方案是,我們可以對這些文件執行壓縮,如下圖所示。壓縮意味著在文件中扔掉重覆的鍵,並且只保留每個鍵的最新更新。
    文件的壓實操作.png
    合併和壓縮可以由後臺線程完成,並且在進行合併和壓縮操作時,我們仍然可以使用舊的文件繼續正常地服務讀寫請求。在合併過程完成後,我們將讀取請求轉換為使用新合併的文件,然後舊的文件可以簡單地刪除。
    缺點
    (1)哈希索引嚴重依賴於記憶體,所以如果Key的數量龐大,需要匹配足夠的記憶體空間。
    (2)範圍查詢效率不高,每查找一個值都需要一次鍵值對映射。
  • SSTable
    由哈希索引我們可以引申出更加高效的索引結構:SSTable(Sorted String Table),SSTable要求鍵值對序列按照鍵來排序。乍一看,這個要求似乎破壞了順序寫的性能,但是它大大提高了維護數據以及索引結構的效率。
    • 合併文件既簡單又高效,使用簡單的歸併排序演算法。
      使用歸併排序合併SSTable
      • 不再需要保留所有鍵在記憶體中的索引,只需要保留部分鍵的索引,利用鍵在SSTable之中有序的特點。
        只需要保留部分鍵的索引
      • 可以進行分組壓縮,每個索引可以指向壓縮塊的起始點,來節省存儲空間與減少I/O帶寬的使用。

但是,如何讓我們寫入的鍵值對有序呢?這個問題在記憶體之中並不是什麼難事,如紅黑樹AVL樹這些數據結構,可以按任何順序插入鍵,並按排序順序讀取它們。所以我們在使用SSTable時,會維護一個MemTable的數據結構在記憶體之中,當MemTable達到閥值時,我們將MemTable作為一個新的SSTable序列化到磁碟之上。同時利用後臺線程,不斷壓縮刪除舊的SSTable,來維護一個可迴圈運行的存儲系統。由於兩次寫入一次是在記憶體,一次磁碟寫入是連續的(append日誌),因此SSTable可以支持非常高的寫入吞吐量。

許多資料庫都是採用這樣的思路來高效的處理數據,如CassandraHBaseLevelDBBitcask等。Lucene的全文搜索的使用ElasticsearchSolr索引引擎,也採用了類似的方法來存儲它的詞典,當然,全文索引比鍵值索引複雜得多,但基於一個類似的想法:給定搜索查詢中的一個詞,查找提及該詞的所有文檔(Web頁面、產品描述等)。這同樣是一個鍵值結構實現的,其中鍵是一個詞,而這個值是包含該詞的所有文檔的ID列表。

  • B樹索引
    這個索引結構大家應該非常熟悉了,在關係型資料庫(如:MySQL,Oracle)與非關係型資料庫(如:MongoDB)之中都大量應用。B樹也把鍵值對進行了排序,它既允許高效的值查詢也允許高效的範圍查詢。
    哈希索引結構將數據分解成可變大小的段,通常是幾個兆位元組或更多的大小。而相比之下,樹型索引將數據分成固定大小的塊或頁,通常為4KB大小(有時更大),每次讀或寫都基於頁的大小。這種設計更接近於底層硬體,因為磁碟也是按固定大小的頁來排列的。B樹索引保證了:N個鍵總是有深度的O(log n)樹,大多數數據都可以放入到一個三或四層的B樹之中,(一個4頁的四級樹,分支繫數為500,可以存儲256TB)。下圖展示了我們怎麼樣使用B樹來查找“251”這個鍵:
    利用B樹索引的存儲結構
    基本寫的操作是覆蓋舊數據的數據頁,重寫不會改變頁的位置;即,當頁被覆蓋時,對該頁的所有引用都保持不變。這與SSTable這樣的哈希索引結構形成鮮明對比,它有附加操作,但從不修改文件。
    而B樹索引的併發控制相對複雜,當多個線程會對樹進行訪問時,需要通過用鎖存器(輕量級鎖)保護樹的數據結構來完成。(這裡也可以用Copy on Write來快照隔離)而哈希索引結構的壓縮,合併則不會影響查詢,寫入等操作。

  • 一些優缺點的探討

    (1)順序寫入通常比隨機寫入快得多,所以SSTable通常的寫入性能是相對優秀的。
    (2)由於SSTable壓縮與清理的線程存在,通常會有較低的存儲開銷。但是壓縮和清理磁碟的過程之中會與正常的請求服務產生磁碟競爭,導致吞吐量的下降。
    (3)由於SSTable會存在同一個鍵值的多個副本,對於實現事務等對於一致性要求更高的場景,樹型索引會表現的更加出色。

3.小結

樹型索引在資料庫架構是非常根深蒂固的,對於很多的工作負載提供始終如一的良好性能。而以SSTable為代表的哈希索引也越來越受歡迎。確定哪種類型的存儲引擎更適合應用場景,並沒有一個簡單易用的規則,因此需要我們對業務邏輯有更深層次的理解。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • AngularJS集合數據遍歷顯示 ...
  • 1 2 3 4 5 AngularJS雙向數據綁定 6 7 8 9 10 11 12 13 14 15 16 hello,{{n... ...
  • AngularJS基於MVC的複雜操作案例 ...
  • 數據圖形化控制項(PC):echarts複製到剪切板控制項(PC):ZeroClipboard、clipboard.js日曆插件(PC):datePicker上傳文件插件(PC):Uploadify、localresizeimg、消息提醒插件(PC):messager圖片分屏載入(PC/MOBILE): ...
  • 在剛開始學JAVA經常會被一些聽上去高大上的術語所迷惑,比如:OOP,封裝,繼承,多態。 這些都是基於對象操作的,而理解了對象,對這三大特性就會好理解許多。 經常會聽說一些人說什麼:"萬物皆對象"。 這話沒錯,世界上所有存在的不存在的事物都可以是對象,你就是上帝的上帝。 我在初學JAVA時也對面向對 ...
  • 1、安裝ruby相關依賴 1.1線上安裝 1.2離線安裝腳本 上傳離線壓縮包,解壓,運行install.sh腳本即可 2、配置運行6個redis服務 2.1先創建3個目錄 2.2創建配置文件(總共7個,1公6私) 將該文件發送到Windows桌面進行重命名,修改 先將redis.conf重命名為re ...
  • 簡介 通過 Erlang 的分散式特性(通過 magic cookie 認證節點)進行 RabbitMQ 集群,各 RabbitMQ 服務為對等節點,即每個節點都提供服務給客戶端連接,進行消息發送與接收。這些節點通過 RabbitMQ HA 隊列(鏡像隊列)進行消息隊列結構複製。本方案中搭建 3 個 ...
  • 本隨筆接上一篇: "工廠方法模式的一些思考(java語法表示)" 那就給factory進行"依賴註入"吧 業務邏輯應該跟非業務邏輯分開,對上面的代碼進行提煉函數重構 可以看到代碼清晰了很多,而且我們獲得了一個特性,那就是業務邏輯對類型不在乎。等等,如果去掉工廠方法模式又怎樣?似乎我們也能得到這個特性 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...