作者:京東零售 劉慧卿
一 資料庫發展史
起初,資料的管理方式是檔案系統,資料儲存在檔案中,資料管理和維護都由程式設計師完成。後來發展出樹形結構和網狀結構的資料庫,但都存在著難以擴充套件和維護的問題。直到七十年代,關聯式資料庫理論的提出,以表格形式組織資料,資料之間存在關聯關係,具有了良好的結構化和規範化特性,成為主流資料庫型別。
先來看一張資料庫發展史圖鑑:
隨之高併發大資料時代的來臨,資料庫按照各種應用場景進行了更細粒度的拆分和演進,資料庫細分領域的典型代表:
型別 | 產品代表 | 適用場景 |
---|---|---|
層次資料庫(NDB) | IMS/IDMS | 以樹形結構組織資料,資料之間存在父子關係,查詢速度快,但難以擴充套件和維護 |
關係型資料庫(RDBMS) | Oracle/MySQL | 事務的一致性需求場景 |
鍵值資料庫(KVDB) | Redis/Memcached | 針對高效能併發讀寫場景 |
文件資料庫(DDB) | MongoDB/CouchDB | 針對海量複雜資料訪問場景 |
圖資料庫(GDB) | Neo4j | 以點、邊為基礎儲存單元,高效儲存、查詢圖資料場景 |
時序資料庫(TSDB) | InfluxDB/OpenTSDB | 針對時序資料的持久化和多維度的聚合查詢等場景 |
物件資料庫(ODB) | Db4O | 支援完整的物件導向(OO)概念和控制機制,目前使用場景較少 |
搜尋引擎(SE) | ElasticSearch/Solr | 適合於以搜尋為主的業務場景 |
列資料庫(WCDB) | HBase/ClickHouse | 分散式儲存的海量資料儲存和查詢場景 |
XML資料庫(NXD) | MarkLogic | 支援對XML格式文件進行儲存和查詢等操作場景 |
內容倉庫(CDB) | Jackrabbit | 大規模高效能的內容倉庫 |
二 資料庫名詞概念
RDBS
1970年的6月,IBM 公司的研究員埃德加·考特 (Edgar Frank Codd) 發表了那篇著名的《大型共享資料庫資料的關係模型》(A Relational Model of Data for Large Shared Data Banks)的論文,拉開了關係型資料庫(Relational DataBase Server)軟體革命的序幕(之前是層次模型和網狀模型資料庫為主)。直到現在,關係型資料庫在基礎軟體應用領域仍是最主要的資料儲存方式之一。
關係型資料庫建立在關係型資料模型的基礎上,是藉助於集合代數等數學概念和方法來處理資料的資料庫。在關係型資料庫中,實體以及實體間的聯絡均由單一的結構型別來表示,這種邏輯結構是一張二維表。關係型資料庫以行和列的形式儲存資料,這一系列的行和列被稱為表,一組表組成了資料庫。
NoSQL
NoSQL(Not Only SQL) 資料庫也即非關係型資料庫,它是在大資料的時代背景下產生的,它可以處理分散式、規模龐大、型別不確定、完整性沒有保證的“雜亂”資料,這是傳統的關係型資料庫遠遠不能勝任的。NoSQL資料庫並沒有一個統一的模型,是以犧牲事務機制和強一致性機制,來獲取更好的分散式部署和橫向擴充套件能力,使其在不同的應用場景下,對特定業務資料具有更強的處理效能。常用資料模型示例如下:
型別 | 產品代表 | 應用場景 | 資料模型 | 優缺點 |
---|---|---|---|---|
鍵值資料庫 | Redis/Memcached | 內容快取,如會話,配置檔案等; 頻繁讀寫,擁有簡單資料模型的應用; | 鍵值對,透過雜湊表來實現 | 優點: 擴充套件性和靈活性好,效能高; 缺點: 資料無結構化,只能透過鍵來查詢 |
列簇資料庫 | HBase/ClickHouse | 分散式資料儲存管理 | 以列簇儲存,將同一列存在一起 | 優點: 簡單,擴充套件性強,查詢速度快 缺點: 功能侷限,不支援事務的強一致性 |
文件資料庫 | MongoDB/CouchDB | Web應用,儲存面向文件或半結構化資料 | 鍵值對,value是JSON結構文件 | 優點: 資料結構靈活 缺點: 缺乏統一查詢語法 |
圖形資料庫 | Neo4j/InfoGrid | 社交網路,應用監控,推薦系統等專注構建關係圖譜 | 圖結構 | 優點: 支援複雜的圖形演算法 缺點: 複雜性高,支援資料規模有限 |
NewSQL
NewSQL 是一類新的關係型資料庫, 是各種新的可擴充套件和高效能的資料庫的簡稱。它不僅具有 NoSQL 資料庫對海量資料的儲存管理能力,同時還保留了傳統資料庫支援的 ACID 和 SQL 特性,典型代表有TiDB和OceanBase。
OLTP
聯機事務處理過程(On-Line Transaction Processing):也稱為面向交易的處理過程,其基本特徵是前臺接收的使用者資料可以立即傳送到計算中心進行處理,並在很短的時間內給出處理結果,是對使用者操作快速響應的方式之一。
OLAP
聯機分析處理(On-Line Analytical Processing)是一種面向資料分析的處理過程,它使分析人員能夠迅速、一致、互動地從各個方面觀察資訊,以達到深入理解資料的目的。它具有FASMI(Fast Analysis of Shared Multidimensional Information),即共享多維資訊的快速分析的特徵。
關於OLTP和OLAP的區別,借用一張表格對比如下:
HTAP
HTAP (Hybrid Transactional/Analytical Processing) 混合型資料庫基於新的計算儲存框架,能夠同時支撐OLTP和OLAP場景,避免傳統架構中大量資料互動造成的資源浪費和衝突。
三 領域資料庫
列式資料庫
傳統的以行形式儲存的資料主要滿足OLTP應用,列形式儲存的資料主要滿足以查詢為主的OLAP應用。在列式資料庫中,資料按列儲存,而每個列中的資料型別相同。這種儲存方式使列式資料庫能夠更高效地處理大量的資料,特別是需要進行大規模的資料分析和處理時(如金融、醫療、電信、能源、物流等行業)。
兩種儲存結構的區別如下圖:
列式資料庫的主要優點:
•更高的壓縮比率:由於每個列中的資料型別相同,列式資料庫可以使用更高效的壓縮演算法來壓縮資料(壓縮比可達到5~20倍),從而減少儲存空間的使用。
•更快的查詢速度:列式資料庫可以只讀取需要的列,而不需要讀取整行資料,從而加快查詢速度。
•更好的擴充套件性:列式資料庫可以更容易地進行水平擴充套件,即增加更多的節點和伺服器來處理更大規模的資料。
•更好的資料分析支援:由於列式資料庫可以處理大規模的資料,它可以支援更復雜的資料分析和處理操作,例如資料探勘、機器學習等。
列式資料庫的主要缺點:
•更慢的寫入速度:由於資料是按列儲存,每次寫入都需要寫入整個列,而不是單個行,因此寫入速度可能較慢。
•更復雜的資料模型:由於資料是按列儲存,資料模型可能比行式資料庫更復雜,需要更多的設計和開發工作。
列式資料庫的應用場景:
•金融:金融行業的交易資料和市場資料,例如股票價格、外匯匯率、利率等。列式資料庫可以更快速地處理這些資料,並且支援更復雜的資料分析和處理操作,例如風險管理、投資分析等。
•醫療:醫療行業的病歷資料、醫療影像和實驗資料等。列式資料庫可以更高效地儲存和處理這些資料,並且支援更復雜的醫學研究和分析操作。
•電信:電信行業的使用者資料和通訊資料,例如電話記錄、簡訊記錄、網路流量等。列式資料庫可以更快速地處理這些資料,並且支援更復雜的使用者行為分析和網路最佳化操作。
•能源:能源行業的感測器資料、監測資料和生產資料等。列式資料庫可以更高效地儲存和處理這些資料,並且支援更復雜的能源管理和控制操作。
•物流:物流行業的運輸資料、庫存資料和訂單資料等。列式資料庫可以更快速地處理這些資料,並且支援更復雜的物流管理和最佳化操作。
總之,列式資料庫是一種高效處理大規模資料的資料庫管理系統,但需要權衡寫入速度、資料模型複雜度和成本等因素。 隨著傳統關係型資料庫與新興的分散式資料庫不斷的發展,列式儲存與行式儲存會不斷融合,資料庫系統呈現雙模式資料存放方式。
時序資料庫
時序資料庫全稱為時間序列資料庫 ( Time Series Database),用於儲存和管理時間序列資料的專業化資料庫,是最佳化用於攝取、處理和儲存時間戳資料的資料庫。其跟常規的關聯式資料庫SQL相比,最大的區別在於:時序資料庫是以時間為索引的規律性時間間隔記錄的資料庫。
時序資料庫在物聯網和網際網路應用程式監控(APM)等場景應用比較多,以監控資料採集來舉例,如果資料監控資料採集時間間隔是1s,那一個監控項每天會產生86400個資料點,若有10000個監控項,則一天就會產生864000000個資料點。在物聯網場景下,這個數字會更大,整個資料的規模,是TB甚至是PB級的。
時序資料庫發展史:
當下最常見的Kubernetes容器管理系統中,通常會搭配普羅米修斯(Prometheus)進行監控,Prometheus就是一套開源的監控&報警&時間序列資料庫的組合。
圖資料庫
圖資料庫(Graph Database)是基於圖論實現的一種新型NoSQL資料庫。它的資料儲存結構和資料的查詢方式都是以圖論為基礎的。圖論中圖的基本元素為節點和邊,在圖資料庫中對應的就是節點和關係。
圖資料庫在反欺詐多維關聯分析場景,社交網路圖譜,企業關係圖譜等場景中可以做一些非常複雜的關係查詢。這是由於圖資料結構表現的是實體聯絡本身,它表現了現實世界中事物聯絡的本質,它的聯絡在節點建立時就已經建立,所以在查詢中能以快捷的路徑返回關聯資料,從而表現出非常高效的查詢效能。
目前市面上較為流行的圖資料庫產品有以下幾種:
與傳統的關聯式資料庫相比,圖資料庫具有以下優點:
1.更快的查詢速度:圖資料庫可以快速遍歷圖資料,找到節點之間的關聯和路徑,因此查詢速度更快。
2.更好的擴充套件性:圖資料庫可以輕鬆地擴充套件到大規模的資料集,因為它們可以分散式儲存和處理資料。
3.更好的資料視覺化:圖資料庫可以將資料視覺化為圖形,使使用者更容易理解和分析資料。
4.更好的資料一致性:圖資料庫可以確保資料的一致性,因為它們可以在節點和邊之間建立強制性的關係。
四 資料結構設計
前面簡單介紹了資料庫相關的基礎知識,下面再介紹幾種我們常見的資料結構設計相關的應用實踐:拉鍊表,位運算和環形佇列。
4.1 拉鍊表
拉鍊表是一種資料倉儲中常用的資料模型,用於記錄維度資料的變化歷史。我們以一個人員變動的場景舉例,假設有一個員工資訊表,其中包含了員工的姓名、工號、職位、部門、入職時間等資訊。如果需要記錄員工的變動情況,就可以使用拉鍊表來實現。
首先,在員工資訊表的基礎上新增兩個欄位:生效時間和失效時間。當員工資訊發生變動時,不再新增一條記錄,而是修改原有記錄的失效時間,同時新增一條新的記錄。如下表所示:
姓名 | 工號 | 職位 | 部門 | 入職時間 | 生效時間 | 失效時間 |
---|---|---|---|---|---|---|
張三 | 001 | 經理 | 技術 | 2010-01-01 | 2010-01-01 | 2012-12-31 |
張三 | 001 | 總監 | 技術 | 2013-01-01 | 2013-01-01 | 2015-12-31 |
張三 | 001 | 總經理 | 技術 | 2016-01-01 | 2016-01-01 | 9999-12-31 |
這裡的生效時間指的是該記錄生效的時間,失效時間指的是該記錄失效的時間。例如,張三最初是技術部經理,生效時間為入職時間,失效時間為2012年底,之後晉升為技術部總監,生效時間為2013年初,失效時間為2015年底,最後又晉升為技術部總經理,生效時間為2016年初,失效時間為9999年底。
透過這種方式,可以記錄員工變動的歷史資訊,並能夠方便地查詢某個時間點的員工資訊。例如,如果需要查詢張三在2014年的職位和部門資訊,只需查詢生效時間小於2014年且失效時間大於2014年的記錄即可。
拉鍊表通常包括以下幾個欄位:
1.主鍵:唯一標識每個記錄的欄位,通常是一個或多個列的組合。
2.生效時間:記錄的生效時間,即該記錄開始生效的時間。
3.失效時間:記錄的失效時間,即該記錄失效的時間。
4.版本號:記錄的版本號,用於標識該記錄的版本。
5.其他維度屬性:記錄的其他維度屬性,如客戶名、產品名、員工名等。
當一個記錄的維度屬性發生變化時,不再新增一條記錄,而是修改原有記錄的失效時間,同時新增一條新的記錄。新記錄的生效時間為變化的時間,失效時間為9999年底。這樣就能夠記錄每個維度屬性的歷史變化資訊,同時保證查詢時能夠正確獲取某個時間點的維度屬性資訊。
拉鍊表與傳統的流水錶相比,它們的主要區別在於:
1.資料結構不同:流水錶是一張只有新增和更新操作的表,每次更新都會新增一條記錄,記錄中包含了所有的歷史資訊。而拉鍊表則是一張有新增、更新和刪除操作的表,每個記錄都有一個生效時間段和失效時間段,記錄的歷史資訊透過時間段的變化來體現。
2.查詢方式不同:流水錶的查詢方式是基於時間點的查詢,即查詢某個時間點的記錄資訊。而拉鍊表的查詢方式是基於時間段的查詢,即查詢某個時間段內的記錄資訊。
3.儲存空間不同:由於流水錶需要記錄所有歷史資訊,所以儲存空間相對較大。而拉鍊表只記錄生效時間段和失效時間段,所以儲存空間相對較小。
4.資料更新方式不同:流水錶只有新增和更新操作,每次更新都會新增一條記錄,不會對原有記錄進行修改。而拉鍊表有新增、更新和刪除操作,每次更新會修改原有記錄的失效時間,同時新增一條新的記錄。
4.2 巧用位運算
藉助於計算機位運算的特性,可以巧妙的解決某些特定問題,使實現更加優雅,節省儲存空間的同時,也可以提高執行效率,典型應用場景:壓縮儲存、點陣圖索引、資料加密、圖形處理和狀態判斷等,下面介紹幾個典型案例。
4.2.1 位運算
•使用位運算實現開關和多選項疊加(資源許可權)等應用場景。一個int型別有32個位,理論上可以表示32個開關狀態或業務選項;以使用者每個月的簽到場景舉例:用一個int欄位來表示使用者一個月的簽到情況,0表示未簽到,1表示簽到。想知道某一天是否簽到,則只需要判斷對應的位元位上是否為1。計算一個月累計簽到了多少次,只需要統計有多少個位元位為1就可以了。這種設計巧妙的資料儲存結構在後面的點陣圖(BitMap)中,還會進行更為詳細的介紹。
•使用位運算實現業務優先順序計算:
public abstract class PriorityManager {
// 定義業務優先順序常量
public static final int PRIORITY_LOW = 1; // 二進位制:001
public static final int PRIORITY_NORMAL = 2; // 二進位制:010
public static final int PRIORITY_HIGH = 4; // 二進位制:100
// 定義使用者許可權常量
public static final int PERMISSION_READ = 1; // 二進位制:001
public static final int PERMISSION_WRITE = 2; // 二進位制:010
public static final int PERMISSION_DELETE = 4;// 二進位制:100
// 定義使用者許可權和業務優先順序的組合值
public static final int PERMISSION_LOW_PRIORITY = PRIORITY_LOW | PERMISSION_READ; // 二進位制:001 | 001 = 001
public static final int PERMISSION_NORMAL_PRIORITY = PRIORITY_NORMAL | PERMISSION_READ | PERMISSION_WRITE; // 二進位制:010 | 001 | 010 = 011
public static final int PERMISSION_HIGH_PRIORITY = PRIORITY_HIGH | PERMISSION_READ | PERMISSION_WRITE | PERMISSION_DELETE; // 二進位制:100 | 001 | 010 | 100 = 111
// 判斷使用者許可權是否滿足業務優先順序要求
public static boolean checkPermission(int permission, int priority) {
return (permission & priority) == priority;
}
}
•其它使用位運算的典型場景:HashMap中的佇列長度的設計和執行緒池ThreadPoolExcutor中使用AtomicInteger欄位ctl,儲存當前執行緒池狀態和執行緒數量(高3位表示當前執行緒的狀態,低29位表示執行緒的數量)。
4.2.2 BitMap
點陣圖(BitMap)是一種常用的資料結構,在索引,資料壓縮等方面有廣泛應用。基本思想就是用一個bit位來標記某個元素對應的Value,而Key即是該元素。由於採用了Bit為單位來儲存資料,因此可以大大節省儲存空間,是少有的既能保證儲存空間又能保證查詢速度的資料結構(而不必空間換時間)。
舉個例子,假設有這樣一個需求:在20億個隨機整數中找出某個數m是否存在其中,並假設32位作業系統,4G記憶體,在Java中,int佔4位元組,1位元組=8位(1 byte = 8 bit)。
•如果每個數字用int儲存,那就是20億個int,因而佔用的空間約為 (2000000000*4/1024/1024/1024)≈7.45G
•如果按位儲存就不一樣了,20億個數就是20億位,佔用空間約為 (2000000000/8/1024/1024/1024)≈0.233G
儲存空間可以壓縮節省31倍!那麼它是如何透過二進位制位實現數字標記的呢? 其原理是用每個二進位制位(下標)表示一個真實數字,0表示不存在,1表示存在,這樣我們可以很容易表示{1,2,4,6}這幾個數:
計算機記憶體分配的最小單位是位元組,也就是8位,那如果要表示{12,13,15}怎麼辦呢?可以另申請一個位元組b[1]:
透過一個二維陣列來實現位數疊加,1個int佔32位,那麼我們只需要申請一個int陣列長度為 int index[1+N/32] 即可儲存,其中N表示要儲存的這些數中的最大值:
index[0]:可以表示0~31
index[1]:可以表示32~63
index[2]:可以表示64~95
以此類推...如此一來,給定任意整數M,那麼M/32就得到下標,M%32就知道它在此下標的哪個位置。
BitMap資料結構通常用於以下場景:
1.壓縮儲存大量布林值:BitMap可以有效地壓縮大量的布林值,從而減少記憶體的使用;
2.快速判斷一個元素是否存在:BitMap可以快速地判斷一個元素是否存在,只需要查詢對應的位即可;
3.去重:BitMap可以用於去重操作,將元素作為索引,將對應的位設定為1,重複元素只會對應同一個位,從而實現去重;
4.排序:BitMap可以用於排序,將元素作為索引,將對應的位設定為1,然後按照索引順序遍歷位陣列,即可得到有序的元素序列;
5.ElasticSearch和Solr等搜尋引擎中,在設計搜尋剪枝時,需要儲存已經搜尋過的歷史資訊,可以使用點陣圖減小歷史資訊資料所佔空間;
4.2.3 布隆過濾器
點陣圖(Bitmap)這種資料儲存結構,如果資料量大到一定程度,比如64bit型別的資料,簡單算一下儲存空間就知道,海量硬體資源要求,已經不太現實了:
所以另一個著名的工業實現——布隆過濾器(Bloom Filter) 出現了。如果說BitMap對於每一個可能的整型值,透過直接定址的方式進行對映,相當於使用了一個雜湊函式,那布隆過濾器就是引入了k ( k > 1 )個相互獨立的雜湊函式,保證在給定的空間和誤判率情況下,完成元素判重的過程。下圖中是k = 3 時的布隆過濾器:
布隆過濾器的內部依賴於雜湊演算法,當檢測某一條資料是否見過時,有一定機率出現假陽性(False Positive),但一定不會出現假陰性(False Negative)。也就是說,當 布隆過濾器認為一條資料出現過,那麼該條資料很可能出現過;但如果布隆過濾器認為一條資料沒出現過,那麼該條資料一定沒出現過。布隆過濾器透過引入一定錯誤率,使得海量資料判重在可以接受的記憶體代價中得以實現。
上圖中,x,y,z經由雜湊函式對映將各自在Bitmap中的3個位置置為1,當w出現時,僅當3個標誌位都為1時,才表示w在集合中。圖中所示的情況,布隆過濾器將判定w不在集合中。
常見實現
•Java中Guava工具包中實現;
•Redis 4.0開始以外掛形式提供布隆過濾器功能;
適用場景
•網頁爬蟲對URL的去重,避免爬去相同的URL地址,比如Chrome瀏覽器就是使用了一個布隆過濾器識別惡意連結;
•垃圾郵件過濾,從數十億個垃圾郵件列表中判斷某郵箱是否是殺垃圾郵箱;
•解決資料庫快取擊穿,駭客攻擊伺服器時,會構建大量不存在於快取中的key向伺服器發起請求,在資料量足夠大的時候,頻繁的資料庫查詢會導致掛機;
•谷歌Bigtable、Apache HBase、Apache Cassandra和PostgreSQL使用布隆過濾器來減少對不存在的行或列的磁碟查詢;
•秒殺系統,檢視使用者是否重複購買;
4.3 環形佇列
環形佇列是一種用於表示一個固定尺寸、頭尾相連的資料結構,很適合快取資料流。在通訊開發(Socket,TCP/IP,RPC開發),在核心的程式間通訊(IPC),影片音訊播放等各種場景中,都有其身影。日常開發過程中使用的Dubbo、Netty、Akka、Quartz、ZooKeeper 、Kafka等各種中介軟體,也都有環形佇列的思想。下面介紹兩種常用的環形資料結構:Hash環和時間輪。
4.3.1 一致性Hash環
先來看一下,典型Hash演算法結構如下:
以上圖Hash策略為例,當節點數N發生變化的時候 之前所有的 hash對映幾乎全部失效,如果叢集是無狀態的服務,倒是沒什麼事情,但是如果是分散式快取這種場景,就會導致比較嚴重的問題。比如 Key1原本是路由到Node1上,命中快取的Value1資料。但是當N節點變化後,Key1可能就路由到了Node2節點,這就產生了快取資料無法命中的問題。而無論是機器故障還是快取擴容,都會導致節點數的變化。
如何解決上面場景的問題呢?就是接下來介紹的一致性Hash演算法。
一致性雜湊將整個雜湊值空間組織成一個虛擬的圓環,假設某雜湊函式H的值空間為0-2^32-1(即雜湊值是一個32位無符號整型),所有的輸入值都被對映到 0-2^32-1 之間,組成一個圓環。整個雜湊空間環如下:
路由資料的過程如下:將資料key使用相同的函式Hash計算出雜湊值,並確定此資料在環上的位置,從此位置沿環順時針“行走”,遇到的第一個節點就是其應該定位到的伺服器。如果某個節點的伺服器故障,其影響範圍也不再是所有叢集,而是限定在故障節點與其上游節點的部分割槽域。
當某個節點當機後,原本屬於它的請求都會被重新hash對映到下游節點,會突然造成下游節點壓力過大有可能也會造成下游節點當機,從而容易形成雪崩,為此引入了虛擬節點來解決這個問題。
根據Node節點生成很多的虛擬節點分佈在圓環上,,一個真實節點對映對應多個虛擬節點。這樣當某個節點掛了後原本屬於它的請求,會被均衡的分佈到其他節點上降低了產生雪崩的情況,也解決了物理節點數少,導致請求分佈不均的問題。
帶有虛擬節點的Hash環:
一致性Hash演算法由於均衡性,永續性的對映特點被廣泛應用於負載均衡領域,比如nginx、dubbo等內部都有一致性hash的實現。
4.3.2 時間輪分片
時間輪(TimeWheel)是一種實現延遲功能(定時器)的精妙的演算法,可以實現高效的延時佇列。以Kafka中的時間輪實現方案為例,它是一個儲存定時任務的環形佇列,底層採用陣列實現,陣列中的每個元素可以存放一個定時任務列表(TimerTaskList)。TimerTaskList是一個環形的雙向連結串列,連結串列中的每一項表示的都是定時任務項(TimerTaskEntry),其中封裝了真正的定時任務TimerTask。
透過上圖可以發現,時間輪演算法不再任務佇列作為資料結構,輪詢執行緒不再負責遍歷所有任務,而是僅僅遍歷時間刻度。時間輪演算法好比指標不斷在時鐘上旋轉、遍歷,如果一個發現某一時刻上有任務(任務佇列),那麼就會將任務佇列上的所有任務都執行一遍。
假設相鄰bucket到期時間的間隔為bucket=1s,從0s開始計時,1s後到期的定時任務掛在bucket=1下,2s後到期的定時任務掛在bucket=2下,當檢查到時間過去了1s時,bucket=1下所有節點執行超時動作,當時間到了2s時,bucket=2下所有節點執行超時動作。時間輪使用一個錶盤指標(pointer),用來表示時間輪當前指標跳動的次數,可以用tickDuration * (pointer + 1)來表示下一次到期的任務,需要處理此bucket所對應的 TimeWheel中的所有任務。
時間輪的優點
1.任務的新增與移除,都是O(1)級的複雜度;
2.只需要有一個執行緒去推進時間輪,不會佔用大量的資源;
3.與其他任務排程模式相比,CPU的負載和資源浪費減少;
適用場景
時間輪是為解決高效排程任務而產生的排程模型。在週期性定時任務,延時任務,通知任務等場景都可以發揮效用。
五 總結
本文針對資料儲存相關名詞概念進行了解釋,重點介紹了資料庫技術的發展史。為了豐富文章的可讀性以及實用性,又從資料結構設計層面進行了部分技術實戰能力的外延擴充套件,闡述了拉鍊表,位運算,環形佇列等相關資料結構在軟體開發領域的應用,希望本文給你帶來收穫。
注:本文個別圖片來自網際網路