算法基礎——存儲

引入

基礎理論的進步,是推動技術實現重大突破,促使相關領域的技術達成跨越式發展的核心。

在發展日新月異的大數據領域,基礎理論的核心無疑是算法。不管是技術設計,還是工程實踐,都必須仰仗相關算法的支持,才能夠真的落地應用。

下面我們就看看大數據相關領域有哪些核心的算法。

存儲類算法

大數據存儲相關的核心算法,主要是為了高效存儲和管理海量數據,以及提升數據讀寫性能和存儲利用率等。

以下我們來看看大數據領域最經典的存儲類算法:

B樹及其變種(B+樹、B* 樹)

原理

  • B樹:是一種自平衡的多路搜索樹,每個節點可以有多個子節點。它的所有葉子節點都在同一層,并且包含了所有的數據。
  • B+樹:是 B樹的一種變種,它的非葉子節點只存儲索引信息,所有的數據都存儲在葉子節點中,葉子節點之間通過指針相連,形成一個有序鏈表,便于范圍查詢。(最通用)
  • B*樹:在 B+樹的基礎上,對節點的分裂規則進行了優化,提高了空間利用率。

應用場景:廣泛應用于關系型數據庫的索引結構,能夠高效地支持點查詢和范圍查詢。

優點:查詢、插入和刪除操作的時間復雜度都是 O (log n),性能穩定。

缺點:對于大規模數據的寫入操作,可能會導致頻繁的節點分裂和合并,影響性能。

B+樹是一種平衡的、多叉的樹形結構,能夠支持O(logn)的插入和查詢時間復雜度。B+樹的整個結構是有序存儲的,這使得B+樹能夠高效地支持范圍查詢;在空間放大維度,B+樹能夠達到70%的空間利用率。綜上所述,B+樹有較好的綜合性能,在現代的諸多存儲系統中,B+樹索引很常見,例如關系數據庫MySQL的默認存儲引擎InnoDB。

在大數據領域是避免不了使用多線程與高并發場景的,所以需要對B+樹索引進行并發控制。由于B+樹的樹形結構會不斷動態調整,要實現一個正確的多線程B+樹,存在著較大的設計挑戰。

目前來說,實現B+樹的并發,可以采用以下3種機制:

  1. 鎖耦合
    鎖耦合機制是B+樹中應用最為廣泛的一種加鎖方式。鎖耦合機制就是一種節點級別的加鎖方式,但是路徑上的節點的鎖會更早地釋放,同時能保證線程安全。在鎖耦合機制中,每個線程同時最多擁有兩個節點的鎖,分別為父節點和孩子節點。父節點的節點可以在孩子節點的鎖獲取之后釋放,這樣可以充分減少每個節點加鎖和釋放的臨界區大小,從而最大化多線程性能。
  2. 樂觀鎖機制
    采用鎖耦合機制,每個讀/寫線程仍然是互相阻塞的,而樂觀鎖機制則是為了減少寫線程對讀線程的阻塞,并進一步減少加鎖的數量。內部節點除節點內部的鎖字段之外,還額外維護一個寫版本號。每當寫線程對節點完成修改之后,先對寫版本號完成自增操作,隨后釋放寫鎖。每當讀線程訪問一個節點的時候,首先記錄節點版本號,在完成對節點的訪問之后檢測節點版本號是否發生變化,如果節點寫版本號發生變化,讀線程重做對該節點的訪問,否則意味著節點訪問過程中該節點并未發生寫操作,因此讀節點操作成功執行。
  3. 無鎖機制。
    通過無鎖的方式來操作B+樹,提升隨機讀和范圍查詢的性能。它的核心的思想是把B+樹的頁(page)通過page id(PID)映射到map,map的[key,value]變成[PID,page value]?,把直接對page的修改,變成一個修改的操作記錄,加入到“page value”?。所以“page value”可能是一個“base page”?,即page原始的內容,和一串對page修改形成的記錄的鏈表,而在修改記錄鏈表中加入一個修改記錄節點可以很容易變成一個無鎖的方式來實現。另外,對B+樹的split和merge操作也通過類似的原理,把具體的操作細化成好幾個原子操作,避免傳統的加鎖方式。

SkipList(跳表)

原理

  • SkipList 是一種可以用來快速查找數據的數據結構,它基于有序鏈表,并通過在鏈表節點上增加多層索引來提高查找效率。在 SkipList 中,每個節點都可能有多個指針,這些指針指向不同層次的下一個節點,高層的指針可以跳過更多的節點,從而加快查找速度。
  • 構建 SkipList 時,會按照一定的概率隨機決定每個節點在不同層次出現的概率。例如,一個節點可能以 50% 的概率出現在第一層,以 25% 的概率出現在第二層,以 12.5% 的概率出現在第三層,以此類推。這樣就形成了一個類似金字塔形狀的多層結構,使得查找操作可以在對數時間內完成。

應用場景:由于 SkipList 在插入、刪除和查找操作上都具有較高的效率,適合在內存中存儲和操作大量的有序數據,能夠快速地根據分數對元素進行排序和查找;在分布式哈希表(DHT)等分布式數據結構中,SkipList 可以用于實現節點之間的快速路由和數據查找。通過在不同節點上構建 SkipList 結構,可以高效地定位數據所在的節點,提高分布式系統的性能和可擴展性。

優點:SkipList 的插入、刪除和查找操作的平均時間復雜度為 O (log n),與平衡樹(如紅黑樹)等數據結構相當,但 SkipList 的實現相對簡單,代碼復雜度較低,易于理解和維護。而且 SkipList 支持動態擴展和收縮,能夠方便地適應數據量的變化。

缺點:SkipList 的空間復雜度相對較高,因為每個節點可能包含多個指針,需要額外的空間來存儲這些指針。此外,由于 SkipList 的節點層數是隨機生成的,在極端情況下可能會出現查找性能下降的情況,但這種情況發生的概率較低。

跳躍表(SkipList)是一種能高效實現插入、刪除、查找的內存數據結構,這些操作的期望復雜度都是O(logN)。與紅黑樹以及其他的二分查找樹相比,跳躍表的優勢在于實現簡單,而且在并發場景下加鎖粒度更小,從而可以實現更高的并發性。正因為這些優點,跳躍表廣泛使用于KV數據庫中,諸如Redis、LevelDB、HBase都把跳躍表作為一種維護有序數據集合的基礎數據結構。

LSM樹(Log-Structured Merge Tree)

原理:將數據的寫入操作先記錄在內存中(通常是一個有序的數據結構,如跳表),當內存中的數據達到一定閾值后,再批量地將數據寫入磁盤,形成一個有序的數據文件(SSTable,Sorted String Table)。磁盤上的數據會按層級進行組織,不同層級的數據會定期進行合并操作,以減少數據冗余和提高查詢效率。

應用場景:適用于寫多讀少的場景,如日志存儲、時間序列數據存儲等。

優點:寫入性能高,能夠快速處理大量的寫入請求;

缺點:讀取時可能需要合并多個 SSTable,讀取性能相對較低,并且在合并過程中會產生一定的 I/O 開銷。

2000年年初,Google發表了Bigtable的論文,論文中的創新點之一就是它所使用的文件組織方式,即LSM樹。

算法的核心也是基于硬件特性來,才能真正的解決落地的問題。對于磁盤讀寫來說,順序讀寫要遠比隨機讀寫快,LSM樹通過將隨機寫轉化為順序寫,消去隨機的本地更新操作來提高寫入性能,但查詢(包括點查詢和范圍查詢)性能會有一定程度的下降,因為一次查詢操作可能要遍歷磁盤中的許多個不同的SST文件。針對查詢性能問題,在不同應用實現時會有一些優化,比如在HBase中設計了異步的compaction來降低文件個數,來提高讀取性能。

LSM樹本質上和B+樹一樣,是一種磁盤數據的索引結構。但和B+樹不同的是,LSM樹的索引對寫入請求更友好。因為無論是何種寫入請求,LSM樹都會將寫入操作處理為一次順序寫。

LSM樹的索引一般由兩部分組成,一部分是內存部分,一部分是磁盤部分。內存部分一般采用跳躍表來維護一個有序的KeyValue集合。磁盤部分一般由多個內部KeyValue有序的文件組成。

哈希算法(Hash Tables)

原理:通過哈希函數將鍵映射到一個固定大小的數組中,數組中的每個位置稱為一個槽(Slot)。當插入、查找或刪除數據時,先計算鍵的哈希值,然后根據哈希值找到對應的槽。如果發生哈希沖突(即不同的鍵映射到了同一個槽),可以采用開放尋址法、鏈地址法等方法來解決。

應用場景:適用于快速查找和插入的場景,如緩存系統、分布式哈希表(DHT)等。在分布式系統中,一致性哈希算法是一種常用的哈希算法,用于實現數據的均勻分布和節點的動態擴展。

優點:平均查找、插入和刪除操作的時間復雜度為 O (1),性能高效;

缺點:哈希函數的設計比較關鍵,如果哈希函數設計不當,可能會導致哈希沖突頻繁,影響性能。并且哈希表不支持范圍查詢。

哈希表是一種無序的數據結構,它提供了快速的插入操作和查找操作。

一個好的哈希表能夠保證插入和查找的時間復雜度為O(1),即插入和查詢性能與哈希表中的數據量無關。這種設計可以實現高效的寫性能和查詢性能,但是它犧牲了范圍查詢性能。

哈希表結構設計中最關鍵的問題是:

  1. 如何選擇合適的哈希函數;
  2. 如何選擇合適的哈希沖突處理機制。

常見的哈希沖突解決機制有四種:

  1. 鏈地址法。
    在鏈地址法下,哈希表的每個桶由一個鏈表構成。鏈表中存儲的是所有哈希值相同的鍵值對。因此在進行查詢操作時,可以通過遍歷該鏈表查詢對應的鍵值對。
  2. 線性探測法。
    在線性探測法下,哈希表是一個連續的桶數組,對于任意一個哈希鍵,根據哈希函數定位到一個映射位置,插入和查找都基于該地址進行向后探測。當插入一個鍵值時,判斷映射地址是否為空,如果該地址為空,則在映射地址插入鍵值對,否則向后探測直到找到空桶,并將該鍵值對放入該空桶。查詢操作則從映射地址開始向后掃描所有鍵值對,直到找到待查詢鍵值對或者遇到一個空桶。
  3. 雙選擇法。
    雙選擇法采用兩個獨立的哈希函數,對于每個鍵值對,都有兩個可插入的桶。當執行插入的時候,根據兩個哈希函數分別將哈希鍵映射到兩個桶a和b中。根據桶a和桶b的填充度,選擇填充度更低的桶插入鍵值對。同樣,執行查詢操作時,只需要遍歷兩個桶即可定位到查詢鍵值。
  4. 布谷鳥探測法。
    布谷鳥探測法是雙選擇法的一種變種。它同樣采用兩個哈希函數。當執行鍵值對插入時,根據兩個哈希函數分別將哈希鍵映射到兩個桶a和b中。如果桶a和b存在空閑位置,則將鍵值對插入到空閑位置中;否則,隨機挑選一個桶中的鍵值對,將其踢出該桶,并存入待插入鍵值對,被踢出的鍵值對則嘗試插入到其對應的另一個桶中。

采用不同哈希沖突解決方式,在查詢性能、插入性能、哈希表填充度三個維度會有不同的表現,解決哈希沖突的方案也是沒有“銀彈”。

鏈地址法的插入性能更優,并且對于空間的占用是逐漸增長的;線性探測法的填充度可以做到最優,但是這是以犧牲查詢和插入性能為前提的;在查詢性能上,布谷鳥和雙選擇法會比其他方法更優。在實際的鍵值數據庫中,不同的設計會采用不同的哈希函數和哈希沖突解決機制。Redis采用的就是鏈地址法,這使得Redis的空間占用更為緩慢,空間管理也更為靈活。

LRU(Least Recently Used)和 LFU(Least Frequently Used)緩存算法

原理

  • LRU:基于 “最近最少使用” 的原則,當緩存空間滿時,優先淘汰最近最少使用的數據。通常使用雙向鏈表和哈希表來實現,雙向鏈表用于維護數據的訪問順序,哈希表用于快速查找數據。
  • LFU:基于 “最不經常使用” 的原則,當緩存空間滿時,優先淘汰使用頻率最低的數據。可以使用多個鏈表和哈希表來實現,每個鏈表存儲相同使用頻率的數據。

應用場景:常用于緩存系統中,如數據庫緩存、Web 服務器緩存等,以提高數據的訪問速度。

優點

  • LRU:實現簡單,能夠較好地反映數據的訪問局部性。
  • LFU:能夠更好地適應數據的使用頻率。

缺點

  • LRU:對于某些特殊的訪問模式,可能會導致性能下降。
  • LFU:實現相對復雜,并且在數據訪問模式發生變化時,需要一定的時間來調整。

總結

今天提到的都是存儲相關最核心的算法,本文主要是拋磚引玉,后續在分享大數據相關組件底層實現原理時,有涉及到相關算法的時候,我們再深入看看。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/67610.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/67610.shtml
英文地址,請注明出處:http://en.pswp.cn/web/67610.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

正則表達式入門

入門 1、提取文章中所有的英文單詞 //1.先創建一個Pattern對象,模式對象,可以理解成就是一個正則表達式對象 Pattern pattern Pattern.compile("[a-zA-Z]"); //2.創建一個匹配器對象 //理解:就是 matcher匹配器按照p…

分布式架構中的事務管理:需要了解的常見解決方案

前言 在現代互聯網應用中,分布式架構越來越常見。隨著系統規模的擴大,越來越多的業務和數據被分布到不同的服務和數據庫中。雖然分布式架構帶來了諸多優勢,但也引入了一個新的問題:分布式事務。 一、什么是分布式事務&#xff1…

《TCP 網絡編程實戰:開發流程、緩沖區原理、三次握手與四次揮手》

一、 TCP 網絡應用程序開發流程 學習目標 能夠知道TCP客戶端程序的開發流程1. TCP 網絡應用程序開發流程的介紹 TCP 網絡應用程序開發分為: TCP 客戶端程序開發TCP 服務端程序開發說明: 客戶端程序是指運行在用戶設備上的程序 服務端程序是指運行在服務器設備上的程序,專門…

新年新挑戰:如何用LabVIEW開發跨平臺應用

新的一年往往伴隨著各種新的項目需求,而跨平臺應用開發無疑是當前備受矚目的發展趨勢。在眾多開發工具中,LabVIEW 以其獨特的圖形化編程方式和強大的功能,為開發跨平臺應用提供了有效的途徑。本文將深入探討如何運用 LabVIEW 開發能夠在不同操…

C 語言實現計算一年中指定日期是第幾天?題】

引言 在編程的世界里,處理日期和時間相關的問題是非常常見的。比如在日歷應用、任務管理系統、數據分析等場景中,經常需要計算某個日期在一年中是第幾天。本文將詳細介紹如何使用 C 語言來實現這一功能,通過分析代碼的結構、邏輯以及可能存在…

rsync安裝與使用-linux015

使用 rsync 可以非常高效地將文件或目錄從一個服務器傳輸到另一個服務器。 能力: 支持 64 位文件、64 位 inode、64 位時間戳、64 位長整型支持套接字對、符號鏈接、符號鏈接時間、硬鏈接、硬鏈接特殊文件、硬鏈接符號鏈接支持 IPv6、訪問時間(atimes&…

UE5.3 C++ CDO的初步理解

一.UObject UObject是所有對象的基類,往上還有UObjectBaseUtility。 注釋:所有虛幻引擎對象的基類。對象的類型由基于 UClass 類來定義。 這為創建和使用UObject的對象提供了 函數,并且提供了應在子類中重寫的虛函數。 /** * The base cla…

Pandas基礎06(異常值的檢測與過濾/抽樣/常用聚合函數/數據聚合)

Pandas基礎06 異常值的檢測與過濾 在數據分析中,異常值(Outliers)是指與其他數據點顯著不同的值。這些值可能由于數據錄入錯誤、設備故障或極端情況而產生,因此在進行數據分析之前,需要對其進行檢測與過濾。本文將介紹…

【PyTorch】4.張量拼接操作

個人主頁:Icomi 在深度學習蓬勃發展的當下,PyTorch 是不可或缺的工具。它作為強大的深度學習框架,為構建和訓練神經網絡提供了高效且靈活的平臺。神經網絡作為人工智能的核心技術,能夠處理復雜的數據模式。通過 PyTorch&#xff0…

jstat命令詳解

jstat 用于監視虛擬機運行時狀態信息的命令,它可以顯示出虛擬機進程中的類裝載、內存、垃圾收集、JIT 編譯等運行數據。 命令的使用格式如下。 jstat [option] LVMID [interval] [count]各個參數詳解: option:操作參數LVMID:本…

App.Current.Services.GetService<UserView>()無限循環

代碼無線循環 public partial class UserView : UserControl{public UserView(){InitializeComponent();InitData();}private void InitData(){DataContext App.Current.Services.GetService<UserView>();}} } DataContext App.Current.Services.GetService<User…

(動態規劃路徑基礎 最小路徑和)leetcode 64

視頻教程 1.初始化dp數組&#xff0c;初始化邊界 2、從[1行到n-1行][1列到m-1列]依次賦值 #include<vector> #include<algorithm> #include <iostream>using namespace std; int main() {vector<vector<int>> grid { {1,3,1},{1,5,1},{4,2,1}…

松靈機器人 scout ros2 驅動 安裝

必須使用 ubuntu22 必須使用 鏈接的humble版本 #打開can 口 sudo modprobe gs_usbsudo ip link set can0 up type can bitrate 500000sudo ip link set can0 up type can bitrate 500000sudo apt install can-utilscandump can0mkdir -p ~/ros2_ws/srccd ~/ros2_ws/src git cl…

pytorch基于GloVe實現的詞嵌入

PyTorch 實現 GloVe&#xff08;Global Vectors for Word Representation&#xff09; 的完整代碼&#xff0c;使用 中文語料 進行訓練&#xff0c;包括 共現矩陣構建、模型定義、訓練和測試。 1. GloVe 介紹 基于詞的共現信息&#xff08;不像 Word2Vec 使用滑動窗口預測&…

C++ 堆棧分配的區別

這兩種聲明方式有什么區別 1.使用 new 關鍵字動態分配內存 動態分配&#xff1a;使用 new 關鍵字會在堆&#xff08;heap&#xff09;上分配內存&#xff0c;并返回一個指向該內存位置的指針。生命周期&#xff1a;對象的生命周期不會隨著聲明它的作用域結束而結束&#xff0…

深入解析 Linux 內核中的頁面錯誤處理機制

在現代操作系統中,頁面錯誤(Page Fault)是內存管理的重要組成部分。當程序試圖訪問未映射到物理內存的虛擬內存地址時,CPU 會觸發頁面錯誤異常。Linux 內核通過一系列復雜的機制來處理這些異常,確保系統的穩定性和性能。本文將深入解析 Linux 內核中處理頁面錯誤的核心代碼…

MATLAB-Simulink并行仿真示例

一、概述 在進行simulink仿真的過程中常常遇到CPU利用率較低&#xff0c;仿真緩慢的情況&#xff0c;可以借助并行仿真改善這些問題&#xff0c;其核心思想是將參數掃描、蒙特卡洛分析或多工況驗證等任務拆分成多個子任務&#xff0c;利用多核CPU或計算集群的并行計算能力&…

Workbench 中的熱源仿真

探索使用自定義工具對移動熱源進行建模及其在不同行業中的應用。 了解熱源動力學 對移動熱源進行建模為各種工業過程和應用提供了有價值的見解。激光加熱和材料加工使用許多激光束來加熱、焊接或切割材料。盡管在某些情況下&#xff0c;熱源 &#xff08;q&#xff09; 不是通…

I2C基礎知識

引言 這里祝大家新年快樂&#xff01;前面我們介紹了串口通訊協議&#xff0c;現在我們繼續來介紹另一種常見的簡單的串行通訊方式——I2C通訊協議。 一、什么是I2C I2C 通訊協議&#xff08;Inter-Integrated Circuit&#xff09;是由Phiilps公司在上個世紀80年代開發的&#…

深度學習 DAY3:NLP發展史

NLP發展史 NLP發展脈絡簡要梳理如下&#xff1a; (遠古模型&#xff0c;上圖沒有但也可以算NLP&#xff09; 1940 - BOW&#xff08;無序統計模型&#xff09; 1950 - n-gram&#xff08;基于詞序的模型&#xff09; (近代模型&#xff09; 2001 - Neural language models&am…