天天看點

資料庫系統設計概述資料庫系統設計概述

資料庫系統設計概述

世界上隻有兩種開發人員,一種使用資料庫系統的,一種開發資料庫系統的。

資料是系統最重要的資訊。大部分系統都是對資料的管理。應用系統通過資料模型來建構現實世界,通過算法操作對象或資料結構,來改變資料模型的狀态。資料被組織在作業系統檔案中,我們通過資料系統來組織,查詢,搜尋,處理資料。

本文将從資料庫的發展、資料庫的分類、常見資料庫架構,資料庫常見概念和技術等方面探讨這個我們接觸最多的底層系統,并通過穿插不同資料庫的實作原理,來了解資料庫的具體實作。

本文分為五個大章節。探古溯源,從資料庫的誕生,發展,現狀和展望來了解資料庫存在的意義,以及資料庫設計的曆史與現實原因。百家争鳴,本節從不同分類方式,講解一些不同的資料庫系統實作,有助于拓展我們的視野,在技術選型時可以作為參考(底層資料庫系統的選型對整個系統的架構實在太重要了)。承上啟下,本節是整篇文章的中間章節,前兩章以興趣點,純理論展開,在本節中将對前兩章做一個總結,有了前兩章知識,我們已經可以去選擇适合項目需求的資料庫系統,對那些想更深入了解底層存儲的同學也可以選擇自己感興趣的資料庫類型和方案找到相應的實作,進而進入下一步學習。下面兩章将講解更多具體的技術點。知行合一,這一章節将講解資料庫的實作,分析一些資料庫架構,分布式問題和解決方案,透析具體的資料庫常見的技術點。

針對不同興趣,大家可以按需取之,跳過不感興趣的,看想關注的點。

一、探古溯源

疑今者察之古,不知來者視之往。——《管子》

資料庫管理系統允許人員組織,存儲和從計算機檢索資料。在計算機的早期,使用“打孔卡”用于輸入,輸出和資料存儲。打孔卡提供了一種快速的資料輸入和檢索方法。資料庫在計算機的最新發展中起了非常重要的作用。第一批計算機程式是在 1950 年代初期開發的,幾乎完全專注于編碼語言和算法。當時,計算機基本上是大型電腦,資料(名稱,電話号碼)被認為是處理資訊的殘餘物。當計算機開始商業化後,資料的重要性開始越來越被人重視。

資料庫系統設計概述資料庫系統設計概述

timeline of database

題外話:穿越時間——筆者去了解一個東西,總喜歡追根溯源,從時間的起點,或從邏輯的深處開始探索。一個東西的邏輯原點往往是純粹的簡單的,之後随時間發展和廣延的展開會逐漸複雜起來。是以從頭開始了解一個東西,往往更容易了解。比如我們看一個系統的源碼,可以從該系統的 1.0.0 版本開始,可以從這個系統最初想要解決的問題開始。

計算機資料庫始于 1960 年代。此十年中,有兩種流行的資料模型:稱為

CODASYL

的網絡模型和稱為 IMS 的層次模型。

SABER

系統被證明是商業上成功的一種資料庫系統,該系統被 IBM 用來幫助美國航空管理其預訂資料。

1970 年,大神 EF Codd 發表了一篇重要的論文:《?大型共享資料庫的資料關系模型》,提出了使用關系資料庫模型的建議,他的想法改變了人們對資料庫的看法。在他的模型中,資料庫的架構或邏輯組織與實體資訊存儲斷開連接配接,這成為資料庫系統的标準原理。之後 UBC 開發了 Ingres 和在 IBM 開發了 SystemR。Ingres 使用一種稱為

QUEL

的查詢語言,引導而誕生了

Ingres Corp

MS SQL Server

Sybase

PACE

Britton-Lee

之類的系統。另一方面,

System R

使用

SEQUEL

查詢語言,它有助于

SQL / DS

DB2

Allbase

Oracle

Non-Stop SQL

的開發。關系資料庫管理系統(RDBMS)已經成為公認的術語。

1976 年 P. Chen 提出了一個新的資料庫模型,稱為

Entity-Relationship

,即

ER

。該模型使設計人員可以專注于資料應用程式,而不是邏輯表結構。1980 年結構化查詢語言或 SQL 成為标準查詢語言。

RDBM系統

是存儲和處理結構化資料的有效方法。然而,随着網際網路的快速發展,“非結構化”資料(視訊,照片,音樂等)變得更加普遍。非結構化資料既是非關系資料,又是無模式資料,而關系資料庫管理系統根本就沒有設計用于處理此類資料。21 世紀後,

NoSql

模型進入人們的視野,NoSql 的出現是對網際網路以及對更快的速度和對非結構化資料的處理需求的一種回應。一般而言,由于 NoSQL 資料庫的速度和靈活性,它們在某些用例中比關系資料庫更可取的。

NoSQL模型

是非關系型的,并且采用“分布式”資料庫系統。這個非關系系統速度很快,使用臨時組織資料的方法,并且處理大量不同類型的資料。一般而言,NoSQL 相對于 RDBMS 系統有如下優勢:

  • 更高的可擴充性
  • 分布式計算系統
  • 低成本
  • 靈活的架構
  • 可以處理非結構化和半結構化資料
  • 沒有複雜的關系

在資料庫的發展曆程中,雖然隻經曆了短短半個世紀,卻誕生了一批優秀的資料庫系統,

SystemR

Postgresql

Mysql

DB2

Oracle

MongoDB

HBase

Neo4j

Elasticsearch

等等,都在軟體的發展中發揮了重要的。

資料庫系統設計概述資料庫系統設計概述

hitory of database

二、百家争鳴

現在春天來了嘛,一百種花都讓它開放,不要隻讓幾種花開放,還有幾種花不讓它開放,這就叫百花齊放。—— 毛澤東

迄今為止,業界誕生的資料系統數不勝數。如果你打開?DB-Engines 網站,可以看到幾百個功能定位不同的資料庫系統。檢視

DB-Engines

的分類排名,可以看出

DB-Engines

将如此衆多的系統大緻分為以下幾類(?網址):

資料庫系統設計概述資料庫系統設計概述

db engines

Willian Blair 在《Database Software Market:The Long-Awaited Shake-up》一文中以以下次元為資料庫系統做了一個細緻的分類:關系型/非關系型、操作型/分析型。

資料庫系統設計概述資料庫系統設計概述

databases

上圖中的縱軸分類為

Relational Database

(關系型資料庫,RDBMS)和

Nonrelational Database

(非關系型資料庫,NoSQL),橫軸的分類為 Operational(操作型,即 OLTP)和 Analytical(分析型,即 OLAP)。

非關系型的分類是一個比較籠統的劃分,主要是針對傳統關系型來區分的,與傳統關系型系統模型不一緻的都劃分到了非關系型中。

非關系型(NoSQL)可以再進一步劃分:Key-Value 型、列存儲型、文檔型、圖資料庫等。

  • 文檔存儲:MongoDB、Elasticsearch、Amazon DocumentDB、Azure Cosmos DB 等。
  • Key-Value 存儲:Redis Labs、Oracle Berkeley DB、Amazon DynamoDB、Aerospike、LevelDB 等。
  • 圖資料庫:Neo4j 等。
  • 時序資料庫:InfluxDB、Timescale 等。
  • WideCloumn:DataStax、Cassandra、Apache HBase 和 Bigtable 等。
資料庫系統設計概述資料庫系統設計概述

database type

關系模型

關系型模型是大多數開發人員接觸最早,接觸最多的資料庫模型。它基于集合理論,是最經典的資料庫模式。關系型資料庫采用行和列的二維表來模組化資料。它适合于提前知道資料模型,并且資料模型比較固定,發生變化比較小,對查詢比較靈活的場景,你隻需要将資料以行和列的方式存儲,在查詢的時候以不同的需要組合資料。關系型不适合資料層次較多,記錄與記錄之間關聯較多的場景,這種場景往往造成查詢複雜度上升,查詢性能下降。

關系型資料庫主要用于大多數商業資料處理,其大多數是事務處理(如 ERP 系統、銀行交易、航空公司訂票、銷售系統、金融财務管理系統等)和批處理場景(如客戶發票、工資單、報告等)。

20 世紀 70 年代至今,關系型資料庫經久不衰,其簡潔的資料模型和經典的 SQL 查詢語句支撐了目前大部分網際網路系統,線上論壇、社交網絡、電子商務等等,各式各樣的系統背後,都隐藏着一個強大的關系資料庫。

關系型資料庫用的比較多的除了

Oracle

Sql Server

等商業資料庫外,就是

Mysql 了

,另外本人比較喜歡和推崇是

Postgresql

,被稱為世界上功能最強大的開源資料庫。

分析的世界

聯機分析處理(Online analytical processing),簡稱OLAP,OLAP 是相對與傳統的OLTP(聯機事務處理,Online Transaction Processing)系統而言的,OLTP 是傳統的關系型資料庫的主要應用,側重于基本的、日常的互動式的事務處理,例如銀行交易。OLAP 是資料倉庫系統的主要應用,支援複雜的分析操作,側重分析決策支援,并且提供直覺易懂的查詢結果。OLAP 工具讓使用者能夠從多個角度互動地分析多元資料。OLAP 由三個基本的分析操作組成:上卷(roll-up)、鑽取(drill-down)、切片(slicing)和切塊(dicing)。上卷涉及可以在一個或多個次元中累積和計算的資料的聚合。

OLAP 利于大資料量,資料更新少,經常使用大量資料做聚合統計的場景。OLTP 适合資料量小,頻繁操作更新資料的場景。

OLAP 主要應用于商業智能、風控分析、智能報表等業務場景。

分析和事務是兩個世界。在分析需求不大的時候,很多團隊直接使用業務事務資料庫做分析使用,這隻能支援小資料量、分析需求變化不大,弱分析的場景。真正的資料分析場景,往往使用單獨的

資料倉庫

。在不影響業務庫的情況下,實時或周期批量地從中提取資料,轉換成對分析友好的資料模式,執行必要的清理和轉換,然後加載到資料倉庫中。将資料導入倉庫的過程稱為

提取-轉換-加載

(Extract-Transform-Load, ETL)。

資料庫系統設計概述資料庫系統設計概述

ETL

OLTP和OLAP沒有明确的邊界,它們的一些典型特性如下所示:

OLTP OLAP
使用者 操作人員,底層管理人員 決策人員,進階管理人員
功能 日常操作處理 分析決策
DB 設計 面向應用 面向主題
資料 目前的,新的,細節的,二維的,分立的 曆史的,聚集的,多元內建的,統一的
存取 讀寫數十上百條資料 讀百萬級資料
讀特征 基于鍵,傳回少量資料 基于大量資料彙總
寫特征 随機通路,低延遲 批量或資料流
DB 大小 100MB~~GB 100GB~~TB
時間要求 實時性 對時間的要求不嚴格
主要應用 資料庫 資料倉庫

業界有許多優秀的開源的 OLAP 系統,比如:

  • Druid:Metamarkets 公司開發的一個用于大資料實時處理的開源分布式系統。目前已經成為 Apache 的開源項目。?官網 ?了解
  • Kylin:Apache Kylin™ 是一個開源的、分布式的分析型資料倉庫,提供 Hadoop/Spark 之上的 SQL 查詢接口及多元分析(OLAP)能力以支援超大規模資料,最初由 eBay 開發并貢獻至開源社群。它能在亞秒内查詢巨大的表。?官網
  • Presto:Presto 是一個對 PB 級資料運作互動式分析的開源分布式 SQL 查詢引擎。?官網
  • ClickHouse:ClickHouse 是由号稱“俄羅斯 Google”的 Yandex 開發的一個列存儲的 OLAP 系統。?官網

列式存儲

傳統 OLTP 資料庫通常采用

行式存儲

。以下圖為例,所有的列依次排列構成一行,以行為機關存儲,再配合以 B+ 樹或 SS-Table 作為索引,就能快速通過主鍵找到相應的行資料。

資料庫系統設計概述資料庫系統設計概述

row-format

行存儲适用于 OLTP 場景,OLTP 的大多數操作都是以實體(Entity)為機關,即對每條記錄的增删改查,是以将一行資料在實體上放在相鄰的位置更利于操作,也更利于特定的優化。

在 OLAP 場景中,極少單獨操作單條記錄的情況。OLAP 分析往往針對大量的資料集,在大量的資料集的基礎上對特定的列做分組、過濾、聚合操作。是以在實體上将每列資料放在相鄰的位置。

資料庫系統設計概述資料庫系統設計概述

column-format

這樣如果針對某一列做分析聚合,隻需要找到相應列的檔案,或資料塊的位置,比如,要計算上圖資料的平均 Age,隻需要擷取 Age 列的資料集即可。但是,面向行的存儲引擎仍然需要将所有行從磁盤加載到記憶體中、解析它們,并過濾出不符合所需條件的行。這可能需要很長的時間。

基于列模式的存儲,天然就會具備以下幾個優點:

  • 自動索引

    因為基于列存儲,是以每一列本身就相當于索引。是以在做一些需要索引的操作時,就不需要額外的資料結構來為此列建立合适的索引。

  • 利于資料壓縮

    利于壓縮有兩個原因。一來你會發現大部分列資料基數其實是重複的,拿上面的資料來說,因為同一個 author 會發表多篇部落格,是以 author 列出現的所有值的基數肯定是小于部落格數量的,是以在 author 列的存儲上其實是不需要存儲部落格數量這麼大的資料量的;二來相同的列資料類型一緻,這樣利于資料結構填充的優化和壓縮,而且對于數字列這種資料類型可以采取更多有利的算法去壓縮存儲。

列式存儲的概念其實很早就有,隻是應時代所需,列式存儲在近幾年才火熱起來,一時湧現了很多優秀的列式存儲資料庫,甚至很多之前的行存儲系統,也有了列式存儲的能力。

  • Hbase:一個分布式的、面向列的開源資料庫,該技術來源于 Fay Chang 所撰寫的 Google 論文《Bigtable:一個結構化資料的[分布式存儲系統]》。HBase 不同于一般的關系資料庫,它是一個适合于非結構化資料存儲的資料庫。另一個不同的是 HBase 基于列的而不是基于行的模式。
  • Cassandra:它最初由 Facebook 開發,用于改善電子郵件系統的搜尋性能的簡單格式資料,集 Google BigTable 的資料模型與

    Amazon Dynamo

    的完全分布式架構于一身。Facebook 于 2008 将

    Cassandra

    開源,此後,由于

    Cassandra

    良好的可擴充性其被許多知名網站所采用,成為了一種流行的分布式結構化資料存儲方案。
  • 其中上一章節提到的很多 OLAP 資料庫大多數是面向列式存儲的。如

    Druid

    ClickHouse

    等。

檢索不再高深

曾幾何時,全文檢索是一個多麼高深的技術,雖然如 Google 這樣的全網搜尋引擎背後的搜尋算法和技術依然不是輕易就可以實作的。但現在大大小小的各種 App,網站的搜尋功能的背後技術基本被一個強大的開源系統輕松就可以實作了。這個系統就是

Elasticsearch

,一個基于

Lucence

的分布式實時全文檢索資料庫。

倫敦的較高價的電梯大廈内,Shay Banon 正在忙着尋找工作,而他的妻子正在藍帶 (Le Cordon Bleu) 烹饪學校學習廚藝。在空閑時間,他開始編寫搜尋引擎來幫助妻子管理越來越豐富的菜單。

他的首個疊代版本叫做 Compass。第二個疊代版本就是 Elasticsearch(基于 Apache Lucene 開發)。他将 Elasticsearch 作為開源産品釋出給公衆,并建立了 #elasticsearch IRC 通道,剩下來就是靜待使用者出現了。

公衆反響十分強烈。使用者自然而然地就喜歡上了這一軟體。由于使用量急速攀升,此軟體開始有了自己的社群,并引起了人們的高度關注,尤其引發了 Steven Schuurman、Uri Boness 和 Simon Willnauer 的濃厚興趣。他們四人最終共同組建了一家搜尋公司。

一個程式員為幫助妻子管理菜單開發的搜尋工具最終稱為一個強大的全文檢索資料庫。看來,面向對象依然是程式員創作的強大靈感源泉之一。

資料庫系統設計概述資料庫系統設計概述

revert-index

将非結構化資料中的一部分資訊提取出來,重新組織,使其變得有一定結構,然後對此有一定結構的資料進行搜尋,進而達到搜尋相對較快的目的。這部分從非結構化資料中提取出的然後重新組織的資訊,稱之索引。将這些索引與文檔建立映射關聯,通過索引檢索出對應的文檔資料,這種詞彙到文檔的映射被稱之為反向索引。先建立索引,再對索引進行搜尋的過程就叫全文檢索。

提到全文檢索,不得不提到的一個技術就是 Lucene,Lucene 是 apache 下的一個開放源代碼的全文檢索引擎工具包。提供了完整的查詢引擎和索引引擎,部分文本分析引擎。

Elastisearch 就是基于 Lucene 的一個分布式開源全文檢索資料庫。它提供了一個分布式多使用者能力的全文搜尋引擎,基于 RESTful web 接口。Elasticsearch 是用 Java 開發的,并作為 Apache 許可條款下的開放源碼釋出,是目前流行的企業級搜尋引擎。設計用于雲計算中,能夠達到實時搜尋,穩定,可靠,快速,安裝使用友善。許多系統的搜尋功能背後,其實就是一個強大的 Elastisearch 服務,Elasticsearch 也常由于日志檢索,資料分析場景。

K-V 緩存霸主

在整個計算機系統中磁盤和網絡是最慢的部分,一個系統中最重要的東西就是資料,而目前系統中的資料最終都存儲在磁盤上。是以目前磁盤緩慢的讀寫速度和人民對系統響應資料和系統高并發之間的沖突,就是目前系統需要解決的主要沖突。将透徹了,所有的系統優化都是在緩解這個沖突。

為提供系統響應資料和并發能力,一個最常見的手段就是緩存。在計算機系統中,CPU,記憶體,磁盤,網絡的通路效率差着不同的數量級,為緩解這種數量級帶來的通路效率問題,最常見的手段就是緩存。CPU 和記憶體之間有緩存,稱之為 CPU 高效緩沖;記憶體和磁盤之間也自帶緩存。

資料庫系統設計概述資料庫系統設計概述

cache

在分布式系統中,資料庫通路的壓力,我們常常使用分布式緩存系統來解決。

Redis 是一個高性能的 key-value 資料庫。它支援存儲的 value 類型相對更多,包括 string(字元串)、list(連結清單)、set(集合)、zset(sorted set --有序集合)和 hash(哈希類型)。Redis 支援緩存過期時間,原子操作,資料持久化,支援叢集模式。

  • K-V 緩存:将資料 K-V 化并緩存在 Redis 中,進而提高資料的通路效率,減小資料庫的通路壓力,這種常見的系統優化政策。
  • 分布式鎖:分布式鎖,就是一個全局的臨界資源,通過對這個臨界資源的獨占達到一種全局鎖的功能,任何全局共享資源都可以實作分布式鎖的功能,甚至 MySql,分布式檔案系統。基于 Redis 的分布式鎖,是常見的一種實作。
  • Pub\Sub:釋出訂閱的管道功能本不應該是一個分布式緩存系統的功能,但 Redis 實作了這一部分功能,在一些簡單的釋出訂閱場景下也可以很好的工作。
  • 布隆過濾器:通過一個 bit 的 0 或 1 來表示 key 是否存在,通過 bit 集合來表示一組資料,這就是簡單的布隆過濾器的實作。相對與用類似 Hash 的方式來存儲 key 映射 boolean 值的方式,布隆過濾器可以節省大量的空間。Redis 就有布隆過濾器的實作。布隆過濾器常用來對大量資料做 True Or Flase 的判斷,比如緩存是否存在,比如大量使用者是否有權限。
  • HyperLogLog:HyperLogLog 是用來快速計算基數的。基數,即不重複元素的個數(類似 SQL 的 count distinct)。
  • 工具:介紹一些好用的 Java 技術棧的相關工具。?Jetcache,阿裡開源的一個基于注解的緩存架構。?Redisson,一個強大的 Redis Java 用戶端工具。

小而精

通常我們使用的資料庫系統大多是 Client-Server 模式的,即資料庫服務作為一個常駐程序運作在 Server 端,應用程式通過 TCP/IP 協定通路資料庫系統。還有一種嵌入式的資料庫,可以運作在本機中,這種資料庫嵌入到應用程式中,随應用程式啟動,資料存儲在本地磁盤中。這種資料庫是輕量的,一般占用記憶體少,代碼精簡。

  • ?SQLite:遵守 ACID,實作了大多數 SQL 标準,支援 SQL 文法。支援 JDBC。
  • ?H2:一個 Java 編寫的關系型資料庫,它可以被嵌入 Java 應用程式中使用,或者作為一個單獨的資料庫伺服器運作。Spring Boot 内置的資料庫。
  • Berkeley DB:一個高效的嵌入式資料庫和鍵-值資料庫程式設計庫。
  • ?LevelDB:是 Google 開源的持久化 KV 單機資料庫,具有很高的随機寫,順序讀/寫性能,LevelDB 應用了 LSM(Log Structured Merge) 政策。另一個 Facebook 基于 levelDB 開發的 RocksDB,也是一個高性能的 key-value 型内嵌式存儲引擎。LevelDB 或 RocksDB 常常被當作存儲引擎使用。比如強大的時間序列資料庫 Influxdb 早期底層存儲引擎就是用于的 LevelDB;RocksDB 是流式計算架構 Flink 的 Checkpoint 的底層存儲引擎;著名的分布式 Actor 架構 Akka 也使用 RocksDB 作為預設的 checkpint 存儲。由于其強大的順序讀寫能力,也常常用來做 WAL(write-ahead-log)日志存儲引擎。

這些小而精的嵌入式資料庫,除了用在一些小型裝置上,如手機用戶端等。也常常被用于很多自研資料庫系統的存儲引擎。這些自研的資料庫系統,以上面那些嵌入式資料庫作為存儲引擎,在上面實作自己特有功能,進而實作一個特殊的資料庫系統,比如擴充分布式功能,基于其現實一個分布式存儲系統;比如基于 LevelDB 等實作磁盤隊列,和分布式隊列;比如基于其存儲特殊的模型的資料,如時間序列資料庫;比如基于其實作本地記錄檔記錄和重試送出,實作最終一緻性的分布式事務解決方案。

三、承上啟下

前幾章我們已經了解了資料庫系統的發展,也從不同角度了解了資料庫系統的不同分類,并且了解到了許多不同功能場景的資料庫系統。為我們如何選擇資料庫系統已經增添了一份基礎知識。我們應該如何選擇一個适合的存儲方案呢?

原則

  1. 選擇是基于需求确定的。是以必須明确需求場景,然後按需求場景選擇适合的存儲方案。
  2. 沒有調查就沒有發言權。方案調研就是一個調查過程,需要先了解不同資料庫的基本特性,才能選擇合适的存儲方案。

基本場景

和前章資料庫系統的分類很相似。其實上面資料庫系統的分類一方面就是基于不同的使用場景才設計的,進而有不同實作的資料庫系統,進而有針對不同場景的特殊優化,進而逐漸形成了不同場景的特殊模型。

事務性,如 Mysql 這些是最常見的事務性系統使用的存儲方案,滿足 ACID,使用簡單。支援千萬級别資料級别的讀寫。分析性,适合 BI,資料報表、資料監控等資料服務系統。文檔型,适合高度可變的資料模型,當你事先不知道你的資料看起來究竟像什麼樣子,文檔型是一個不錯的選擇,文檔型也适合點查詢多餘集合查詢的場景。圖資料庫,圖資料庫是一種很特殊的,新興的資料庫類型,它側重于分析解釋資料之間的互相關系而不是資料值本身,它适合推薦引擎、權限通路控制和地理資料等場景。時序性,時序性資料庫在資料分析,時序資料展示,監控領域使用比較多,它适合對大量時間型資料查詢、過濾、組合、聚合分析等。K-V 型,緩存和固定 View 模式的資料展示,K-V 型的需要按查詢組合好存儲起來,這樣查詢時按 key 擷取即可。

讀寫

  • 是否需要寫事務
  • 順序讀寫還是随機讀寫
  • 偏點查詢還是大量資料集分析查詢
  • 資料結構變化大,還是查詢結構變化大

資料量

資料量,需要考慮資料的數量,也需要考慮資料數量的增長速度,這樣就需要考慮資料庫的量級承載能力以及水準擴充能力。

資料用途

對臨時資料和重要的業務資料的存儲可以采用相對側重點不一緻的方案。對資料的一緻性要求的強弱也會影響資料存儲系統的選型。對資料事務的要求,對資料儲存時間的選擇也會不一樣。

可靠性

資料的可靠性即保證資料的可用的能力,可靠性與成本一般是權衡的一體兩面,需要對資料可用性的要求選用不同的存儲架構。

可擴充性

可擴充性表現在資料使用的可擴充和系統本身的可擴充上。

可維護性

  • 可運維性:友善營運團隊來保持系統平穩運作。
  • 簡單性:簡化系統複雜性,使新工程師能夠輕松了解系統。
  • 可演化性:後續工程師能夠輕松地對系統進行改進,并根據需求變化将其适配到非典型場景,也稱為可延伸性、易于修改性或可塑性。

學習和了解資料底層存儲,除了可以搭建良好的存儲架構是提供思路上的幫助,也可以讓我們學習到很多平時純業務開發接觸不多的底層技術實作。對底層技術的了解和掌握,又可以反過來讓我們更加了解我們的整個業務系統,對系統的合理性優化做出重要的選擇。也可以幫助我們實作自己的系統。

開源資料庫系統的良好的分布式架構,優秀的網絡通信,性能強勁的記憶體和磁盤通路優化以及更多經典的資料接口和算法都是值得我們學習和借鑒的。

四、知行合一

知是行的主意,行是知的工夫;知是行之始,行是知之成。—— 王陽明

這一章節将簡單講解一些資料庫系統的常見技術點。

系統架構

Master-Slave

Master-slave 架構可以說是最常用的資料存儲架構,關系型資料庫如:mysql,postgreSql,oracle,Nosql 諸如:MongoDb,消息隊列如:Kafka,RabbitMQ 等都使用了這種架構。

資料庫系統設計概述資料庫系統設計概述

master_slave

在整個系統中,Master 承擔寫任務,Slave 通過複制 Master 的資料保證與 Master 資料的一緻性。Master 和 Slave 都可以承擔讀任務。Master 架構解決了資料的高可用問題(Slave 存儲了資料副本),也擴充了資料讀并發能力(多 Slave 同時通過讀請求)。

在 Master-Slave 架構中,單 Master 如果出現故障,就會導緻這個資料庫系統不可用,這時就可以采用 Master-Master 架構,系統中同時存在多個 Master 節點,但是,多個 Mater 節點并不同時提供寫服務,同時隻會存在一個可寫的 Master,另一個 Master 作為備機存在,隻有當其他 Master 不可用時才會被選舉稱為 Master 節點提供寫服務,作為備機的 Master 是可以提供讀服務的。這種架構的隻解決了單 Master 節點的高可用問題,并沒有解決單 Master 負載過大的問題,這裡之是以隻有一個 Master 提供寫服務,是為了保證寫資料的一緻性問題。

資料一緻性

我們将同一份資料在不同資料節點上的存儲稱之為副本。隻要系統中資料存在多個副本,就會有資料一緻性問題。如何保證資料多副本的一緻性,一直以來都是分布式系統的最大挑戰。多節點資料同步,一般采用複制方式,從節點複制主節點的資料,多節點之間互相複制等等,但無論采用哪種方式,都無法避免不一緻的情況。

資料一緻性可以分為最終一緻性和強一緻性。強一緻性模型能夠允許你的單服務程式移植到分布式節點叢集上并且不會發生任何錯誤。強一緻性往往通過犧牲系統可用性來達到,在寫入資料時,如無法保證多副本一緻,則失敗。最終一緻性模型中,當停止改變數值的一段不确定的時間後,所有的複制集将會最終保持一緻。這表明,在這段時間之前,資料副本在某種情形下是不一緻的,但資料最終會達到一緻,最終一緻性意味着“收斂”,即預期所有的副本最終會收斂到相同的值。

在資料收斂過程中,為保證最終資料的一緻性性,還有許多問題需要解決。如系統間的時序問題,原子送出問題,共識問題。

CAP 理論

**定理:**一個分布式系統不可能同時滿足 consistency、availability、partition tolerance 這三個基本需求,最多同時滿足兩個。

  • consistency 一緻性:所有節點同一時刻看到相同資料
  • availability 可用性:節點失敗不阻止影響正在運作的節點的工作
  • partition tolerance 分區容錯:即使出現資訊丢失或網絡、節點失敗,系統也能繼續運作(通過複制)
資料庫系統設計概述資料庫系統設計概述

cap

這三種性質進行倆倆組合,可以得到下面三種情況:

  • CA:完全嚴格的仲裁協定,例如 2PC(兩階段送出協定,第一階段投票,第二階段事物送出)
  • CP:不完全(多數)仲裁協定,例如 Paxos、Raft
  • AP:使用沖突解決的協定,例如 Dynamo、Gossip

CA 和 CP 系統設計遵循的都是強一緻性理論。不同的是 CA 系統不能容忍節點發生故障。CP 系統能夠容忍 2f+1 個節點中有 f 個節點發生失敗。

分區

資料庫系統設計概述資料庫系統設計概述

p_r_mini

上面說副本隻能保證資料的可用性。為提高大量資料集的讀寫能力,我們可以将資料拆分成不同的分區分開處理,這種技術稱之為分片。

分片,即将資料集分割成互相獨立的小資料集,減少因資料集增長而帶來對單個節點的壓力。資料分片有以下好處:

  • 提高性能:限制分區中資料量的大小,降低資料壓力
  • 提高可用性:資料之間互相獨立,不同分區之間失敗互不影響,允許失敗節點的存在

分區自然也會帶來一些問題,首先需要考慮的就是

如何分區的問題

  • 基于關鍵字區間:将資料按關鍵字劃分為不同區間,将相同區間的資料寫入同一個節點。比如使用者資料 id 分布在[1-1000000]之間,需将資料分布到 10 個節點上,可以将資料劃分成十個區間:
  • **關鍵字哈希分區:**通過 Hash 算法計算分區号,将資料寫入相應分區号的分區中。

資料分區帶來的

負載傾斜

熱點

問題:由于資料的不确定性,資料關鍵字計算出來的分區存儲可能集中在某幾個區間内,這樣就可能導緻某些節點資料明顯多餘其他節點,這種資料集中于某個節點的情況就是資料熱點。由于資料熱點的出現,整個系統的負載将傾斜到這些節點上,造成分區間的負載不均衡,這就是負載傾斜問題。

去中心化:Dynamo

Dynamo 是 Amazon 的一個分布式存儲。Amazon 發表了一篇論文 ?Dynamo: Amazon’s Highly Available Key-value Store 講解 Dynamo 架構,使得 Dynamo 稱為許多資料存儲系統借鑒的架構。

Dynamo 基于一些衆所周知的技術實作了可擴充性和高可用性:

  • 資料通過

    一緻性哈希

    算法進行分區和複制(partitioned and replicated)
  • 通過

    對象版本化

    (object versioning)實作一緻性
  • 副本之間的一緻性由一種

    仲裁的技術

    (quorum-like technique)和一個去中心化的

    副本同步協定

    (replica synchroni protocol)來保證
  • 基于 gossip 協定進行分布式故障檢測和成員檢測(membership)協定管理節點

Dynamo 是一個完全去中心化的系統。

資料庫系統設計概述資料庫系統設計概述

no_master

向 Dynamo 添加或移除存儲節點不需要人工 partition(調整哈希節點)或 redistribution(在節點之間重新平衡資料分布)

Dynamo 采用最終一緻性方案。

生産級别的存儲系統的架構是很複雜的。除了最終存儲資料的元件之外,系統還要針對以下方面制定可擴充和健壯的解決方案:負載均衡、成員管理(membership)、故障檢測、故障恢複、副本同步、過載處理(overload handling)、狀态轉移、并發和任務排程、請求 marshalling、請求路由(routing)、系統監控和告警,以及配置管理。

下表總結了 Dynamo 使用的這些技術及每項技術的好處。

資料庫系統設計概述資料庫系統設計概述

table-1

Partition
  • 技術:

    一緻性哈希

  • 好處:增量可擴充性
寫高可用
  • 技術:讀時協調(解決沖突)的

    向量時鐘

    (vector clocks with reconciliation during reads)
  • 好處:version size 和更新頻率(update rates)解耦
短時故障處理
  • 技術:寬松的選舉和 hinted handoff(移交給其他節點處理,附帶提示資訊)
  • 好處:部分副本不可用時,仍然可以提供高可用性和持久性
持久(permanent)故障恢複
  • 技術:基于

    Merkle tree

    的逆熵(anti-entropy)
  • 好處:背景同步版本不一緻的副本
成員管理和故障檢測
  • 技術:基于

    Gossip

    的成員管理協定和故障檢測
  • 好處:保持了架構的對稱性,無需一個中心元件(centralized registry)來存儲成員和節點狀态等資訊

分布式資料庫 Cassandra 就是 Dynamo 的典型實作。

有主架構:Bigtable

Bigtable 是 google 開源的資料庫系統。Bigtable 是典型的有主架構。

Bigtable 主要由三個元件構成:

  1. 一個用戶端庫,會連結到每個用戶端
  2. 一個 master server
  3. 多個 tablet server

master 負責:

  1. 将 tablet 配置設定給 tablet server
  2. 檢測 tablet server 的過期(expiration)及新加(addition)事件
  3. 平衡 tablet server 負載
  4. 垃圾回收(GC)
  5. 處理 schema 變動,例如 table 和 column family 的建立

BigTable 的 Master 隻負責中繼資料的管理,Table Server 負載自身管理的 Table 的讀寫功能,用戶端隻想 Master 同步中繼資料,資料不經過 Master 節點,直接和 Table Server 通信。是以,BigTable 中 Master 節點的負載很低。

有主架構中,Master 承擔的能力也會不一緻,比如在下圖架構中,Master 隻承擔 Coordinate 功能,管理中繼資料和 Node 節點,Client 擷取 Mata Data,直接和相應的資料節點通信。

資料庫系統設計概述資料庫系統設計概述

master_worker1

在下面架構中,Client 不直接和 Data Node 節點通信,而是和 Master 通信,Master 更加相關中繼資料将請求轉發給對應的 Data Node:

資料庫系統設計概述資料庫系統設計概述

master_work2

Coordinate-Worker

架構是很多分布式資料庫采用的架構,有興趣的同學可以看看筆者之前講解的 ?《Druid 的架構設計》

索引

資料庫系統的索引,就是用來提高資料檢索效率的。資料庫系統的資料記錄存儲在磁盤中,如果沒有索引,要從磁盤中檢索相應的記錄,就需要掃描所有的資料段,這種 O(N) 的通路效率和全磁盤的掃描自然不可能在真正的資料庫系統中使用。為提高資料檢索能力,資料庫系統引入索引技術,為磁盤上的資料記錄做一個索引結構,這些索引放在記憶體中,或按塊存儲在磁盤上(但隻需要少數幾次磁盤讀取就可以讀入記憶體中),這樣檢索一個資料先從記憶體索引中查找到對應的 Key 或磁盤位置,然後從磁盤中讀取記錄。

這裡索引做了兩個事情:

  • 将大量磁盤檢索變成記憶體檢索
  • 通過特定的資料結構可以提高記憶體檢索的效率,改變 O(N) 這種低效率的檢索

HASH 索引

資料庫系統設計概述資料庫系統設計概述

hash_index

HASH 即哈希表,類似 Java 的 HashMap 資料結構,Key-Value 格式。假設我們在記憶體内維護一個 HashMap Index,key 為資料的鍵,Value 是資料在磁盤的存儲偏移量。

  • 擷取資料時,先從記憶體 Map 擷取對應資料的磁盤 offset,然後讀取磁盤的資料。
  • 寫資料時,先将資料追加寫入磁盤,然後更新記憶體 HashMap Index。

Hash 索引聽起來過于簡單,但确實是一種可行的索引方法。Hash 索引簡單高效,查詢性能 O(1),更新也高效,當時也有明顯的缺點,比如:

  • 需要将整個哈希表放入記憶體,這對于大資料量來說記憶體耗費将不可承受的。
  • 隻能進行精确查詢。
  • 不能實作範圍查詢。

B-Tree 索引

B-trees

索引始見于 1970 年,經受了長久的時間考驗,時至今日,它仍然時幾乎所有關系資料庫中的标準索引實作,許多非關系型資料庫也經常使用。

了解

B-trees

索引先從二叉搜尋樹開始。二叉搜尋樹是一種特殊的二叉樹,它滿足以下條件:

  • 左子樹小于父節點
  • 右子樹大于父節點
資料庫系統設計概述資料庫系統設計概述

BST

上圖是一個搜尋二叉樹,如果我要查找 208 這個 key:

  • 先從根節點開始,即 136。比較 208 > 136,下一步應該從根節點的右子樹查找
  • 398 > 208,繼續搜尋 398 的左子樹
  • 250 > 208,繼續搜尋 250 的左子樹
  • 200 < 208,繼續搜尋 200 的右子樹。
  • 200 的右子樹并不存在,是以資料中沒有 208,查找結束

讓我們再查找 40:

  • 從根節點 136 開始,136 > 40,繼續搜尋左子樹
  • 80 > 40,繼續搜尋左子樹
  • 40 = 40,節點存在,從節點中擷取資料 id,然後可以更加資料 id 查找對應的資料

在索引結構中,樹的每個

Node

包含一個 key 值,一個資料指針(或資料 id、磁盤 offset 等)

二叉搜尋樹的時間複雜度是

log(N)

,這是一個不錯的結果。

二叉搜尋樹依舊隻能擷取特定的值,如果我需要進行範圍查找,即查找兩個數之間的所有資料,就需要去周遊樹中的每一個節點,去判斷節點是否在此範圍内,這種情況下,時間複雜度又下降到了

O(N)

。是以我們需要改進上面的資料結構,現代大多數資料庫都才有一種改進的二叉搜尋樹—— B+Tree。

資料庫系統設計概述資料庫系統設計概述

B+tree

B+Tree 在二叉搜尋樹的基礎上添加如下特征:

  • 僅僅在葉子節點存儲索引資訊(關聯表資料的資訊)
  • 其餘節點僅僅用于查找到最終的葉子節點(葉子節點包含了所有的 key)

在 B+Tree 中,每個 Key 會存在兩個 Node,所有中間節點隻用于輔助檢索最終正确的葉子節點(葉子節點才包含關聯資料的資訊)。

讓我們嘗試從上面的 B+Tree 中搜尋出[40, 100]之間的節點:

  • 采用和二叉搜尋樹一樣的方式,我們隻需要搜尋 40 這個節點(或搜尋出最接近 40 的節點,當 40 的節點不存在時)
  • 然後在葉子節點連結清單中往下追溯,知道超過 100

假設樹中共有 N 個節點,追溯了 M 個葉子節點,那麼可以得出,此次搜尋的時間複雜度是:

log(N) + M

。相對于之前的

O(N)

的二叉搜尋樹有以下好處:

  • 不需要讀取整棵樹,這樣可以減少讀取磁盤的次數(索引資料一般按頁存儲在磁盤上)
  • 大多數情況下 M (約等于檢索範圍)會遠小于整個資料量 N,是以這裡的

    O(M)

    時間複雜度大多數情況下遠小于

    O(N)

*任何事情都是雙面的。*B+Tree 索引帶來的檢索優勢,必然會有其他方面的損失。這主要展現在删除資料時。因為葉子節點類似于連結清單結構,删除一個節點需要從 header 開始周遊,時間複雜度是 O(N)。

B+Tree 索引具有比較好的檢索性能,為了減少磁盤通路次數,大多數索引系統的 B+tree 都隻有 3- 4 層,是以 B+Tree 索引能夠承載的節點數是有限的。B+Tree 在更新節點是需要

自排序

自平衡

,這需要額外的性能消耗,B+Tree 的插入和删除時間複雜度是

O(log(N))

。這就是為什麼在使用資料庫時不建議索引字段都添加索引,而是充分考慮具體情況,在需要的字段上添加索引,否則索引太多會影響表的

insert\update\delete

操作性能。

LSM

B+Tree 是基于頁的索引引擎,B+Tree 的資料存儲本身是無序的,其建立索引的思想是在記憶體中維護一個 key 與資料磁盤位置的對應關系,并保證這個記憶體資料結構有序。有一種基于檔案的存儲引擎,它将資料劃分成檔案段,并保證資料在磁盤檔案段中有序,是以,這種存儲引擎并不需要在記憶體中維護所有資料的順序表,隻需要在記憶體中維護一個稀疏的索引結構,每次從記憶體索引中搜尋到的資料并不是具體到每條資料,而是一個檔案段(或檔案塊),然後将這些有序的資料讀入記憶體,再按序擷取具體的資料。(如何保證寫入資料有序?)

LSM(Log-Structured Merge-Tree),就是這樣一種索引結構。LSM 的架構如所示:

資料庫系統設計概述資料庫系統設計概述

lsm

SSTable: LSM 的磁盤檔案,稱作

SSTable(Sorted String Table)

。望文得意,LSM 存儲在磁盤中的檔案,資料也是按 Key 排序存儲的,這樣就可以解決上面講到的資料量大了之後無法将資料全部索引到記憶體中的問題。如果磁盤檔案也是有序的,那麼記憶體索引可以采取”稀疏索引“(Sparse Index),可以每一段記錄一個索引,将資料邏輯上分成多個

block

,稀疏索引隻需要記錄每個

block

的偏移量,每條資料通過周遊

block

實作。這樣索引量将大大減小。

Memtable: LSM 的記憶體結構叫做

Memtable

Memtable

是一個有序結構,同樣可以采用樹結構,可以用

跳表

。LSM 寫資料時,隻需要寫入記憶體中的

Memtable

,當

Memtable

到達一定量之後,會異步刷入磁盤,就是上面的

SSTable

Immutable Memtable: 在資料從記憶體

Memtable

刷入

SSTable

時,為避免讀寫鎖導緻的性能問題,LSM 會在記憶體中 copy 一份

immutable Memtable

表,顧名思義,這個資料結構不可改變,新寫入的資料隻會寫入新的

Memtable

immutable Memtable

供刷盤線程讀取,查詢資料的請求也可以通路這個資料結構,這樣如果資料在記憶體中,就不需要通路磁盤,可以提供資料查詢的效率。

WAL: write ahead log,預寫日志,關于 WAL,可以參考我之前的文章?《你常聽說的 WAL 到底是什麼》。在 LSM 中,在資料刷入磁盤前,為防止異常導緻資料丢失,LSM 會先将資料寫入 WAL,然後寫入 SSTable,系統重新開機時,LSM 會從 WAL 中回溯 SSTable,當寫完一個 SSTable 時,LSM 會清理掉過期的 WAL 日志,防止 WAL 過量。

LSM 如何寫入資料:

  1. 寫入

    WAL

  2. 寫入

    Memtable

  3. Memtable

    達到門檻值時,複制

    Imutable Memtable

  4. 異步刷入磁盤

LSM 如何删除資料: 為保證順序寫磁盤,LSM 不會去直接删除資料,而是通過寫一條 delete 辨別來表示資料被删除,資料隻有在被 Compact 時才會被真正删除。

LSM 如何讀取資料: LSM 讀取資料将從

memtable

imutable

sstable

依次讀取,直到讀取到資料或讀完所有層次的資料結構傳回無資料。是以當資料不存在時,需要依次讀取各層檔案。LSM 可以通過引入

布隆過濾器

來先判斷一個資料是否存在,避免無效的掃檔案。

密集索引(dense index) 和 稀疏索引(spare index):密集索引為每條資料對應一個索引記錄,稀疏索引一般隻索引資料塊或檔案,是跳躍式的。是以稀疏索引比密集索引更節省空間。

壓縮

資料壓縮對資料庫系統中 I/O 性能的影響相當明顯,它可以減少磁盤空間使用、降低帶寬使用和提高吞吐量。資料庫系統中的資料存儲、索引存儲、資料轉換、資料備份和網絡通信都會用到相應的壓縮技術。當将資料庫壓縮引入實時資料庫時。壓縮算法必須提供高壓縮比才能實作高資料存儲,壓縮算法必須足夠快,才能在實時資料庫中實作實時記錄和查詢功能。

壓縮過程一般由兩個獨立的部分組成,

模組化

編碼

。模組化定義輸入流中不同符号的特征。模型存儲有關符号在資料中出現的頻率的資訊,即符号機率。編碼是壓縮過程的第二部分,它根據模型提供的機率為不同符号建立一組代碼,進而産生資料的壓縮版本。将更頻繁地出現的符号與較短的代碼詞和較長的稀有符号互換。資料的均勻性會影響大多數壓縮算法的壓縮比,但對壓縮速度沒有任何影響。是以,為了達到更好的壓縮性能,壓縮算法是專門為資料的每個部分設計的,是以不同的壓縮算法對不同類型的,不同量級和不同組合的資料的壓縮效果是不一緻的。也是以大多數支援資料壓縮的資料庫系統都會提供多種不同的壓縮算法讓使用者根據自身資料情況自由選擇。

壓縮算法可以分為以下兩大類:

  • 有損壓縮:有損壓縮會重構原始資料。是以讀取的壓縮後的資料是不完整的。這種壓縮方式通常用在音頻、視訊等流檔案的壓縮中。
  • 無損壓縮:無損壓縮不影響壓縮資料的原始值。通常使用在文本,數字等資料的壓縮中。

壓縮應該考慮什麼問題:

  • 大小:壓縮後的檔案大小,即壓縮比。當使用壓縮時,本就是為了降低資料大小,是以壓縮算法的壓縮比是首要考慮的問題。
  • 速度:壓縮速度會影響資料的讀寫效率,這對實時系統來說尤為重要,速度和大小是 trade-off 的兩面,必須充分考慮具體的使用場景。
  • **資源:**壓縮節省了磁盤和寬帶,但是會增加 CPU 和壓縮時的記憶體使用。是以壓縮時的資源耗損情況也需要考慮。

下面列舉一些常見的壓縮算法或方法(Gzip、Bzip2、LZMA、XZ、LZ4、LZO),并做相應的對比:

測試條件:

  • Intel Core i5 CPU 750 at 2.67GHz
  • 8GB of DDR3 memory
  • tmpfs as ram disk
  • Linux kernel 3.3.2, gentoo amd64
  • CFLAGS: -pipe -O2 -g -floop-block -floop-interchange -fgraphite
  • bzip2-1.0.6-r3, xz-utils-5.0.3, gzip-1.4

檔案壓縮對比結果(原資料: 445M):

資料庫系統設計概述資料庫系統設計概述

c-c

壓縮比對比:

資料庫系統設計概述資料庫系統設計概述

c-r

壓縮耗時對比:

資料庫系統設計概述資料庫系統設計概述

各大資料庫系統多多少少都會用到壓縮技術來降低資料存儲空間,來提高系統性能,以下列舉一些資料庫系統使用到的壓縮技術:

  • Google 在 BigTable 和 MapReduce 中使用 Snappy 壓縮資料和網絡傳輸。
  • SQL Server 使用 XPRESS 算法壓縮備份資料。
  • Oracle 使用自實作的 Oracle Advanced Compression 算法壓縮資料。
  • MySQL 使用 LZ77 算法壓縮 InnoDB 的表。
  • Kafka 同時支援 gzip 和 snappy 和 lz4 算法,并對預設的 lz4 做了特定的優化。
  • Druid 使用 lz4 壓縮資料。

數值壓縮:delta-of-delta

數值壓縮經常用于壓縮列式存儲的數字列。前面我們講到過,列式存儲将每列的資料存儲在相鄰的位置。這樣的存儲結構利于壓縮資料,下面我們講一下在許多列式存儲中使用的 Delta 數值壓縮技術。

![delta of delta](https://magebyte.oss-cn-shenzhen.aliyuncs.com/databases/delta of delta.png)

如圖所示,假設有 6 個原始數值(73、300、302、332、343、372)。在未壓縮之前,每個數值占用 4 個位元組,6 * 4 = 24 共占用 24 個位元組。Delta 壓縮算法不存儲原始的數值,而是先确定一個數字(一般取第一個數值),後面的數值是相對于第一個數值的內插補點,如圖第二行所示得到的資料集為(73、227、3、30、11、29)。因為最大的內插補點是 227,是以隻需要一個 byte 就可以表示,是以之前需要使用 4 個位元組存儲的每個數值,現在隻需要使用 1 個位元組。為了儲存對應的內插補點相關元描述資訊,需要額外的 1 位元組儲存這些資訊,上圖還将資料分塊存儲,是以最終需要的位元組數是 7 個。這樣相對于原始的 24 位元組節約了将近 3 倍的空間。

其實上圖就是 Elasticsearch 底層使用 Lucence 的原理。

delta-of-delta 适用于數值類型資料的壓縮,且對資料量大并且資料集中的資料壓縮才有效果。如果資料集比較小,且比較稀疏,資料的最大內插補點已經和資料值可以表示的最大值相差不大,那麼壓縮的意思便存在。

讀寫

資料存儲系統就是一個與磁盤和網絡打交道的系統,是以資料存儲系統在這方面的優化可謂精益求精,比如

異步IO

緩沖批量讀寫

append寫資料

按磁盤頁讀寫資料

預讀資料

磁盤記憶體映射技術

等等。

異步

與異步 IO 對應的是同步 IO,即每進行一次 IO 操作,需要等待此次操作結束才能繼續接下來的操作,這樣在大量并發請求情況下,IO 的效率将會大大降低,磁盤 IO 和網絡 IO 在并發量大的情況下采用異步 IO 可以明顯提供效率。

Mysql 的 InnoDB 也采用 AIO 提高效率,InnoDB1.1.x 之前,AIO 的實作通過 InnoDB 存儲引擎中的代碼來模拟實作,從 InnoDB1.1.x 開始,提供了核心級别的 AIO 支援,稱為 Native AIO。在 InnoDB 存儲引擎中,read ahead 方式的讀取都是通過 AIO 完成,髒頁的重新整理,即磁盤的寫入操作則全部由 AIO 完成。

在 Kafka 中,Broker 的資料磁盤落地,都是采用的 Java NIO 的方式處理的,這是 Java 的異步 IO 的實作,Java NIO 可以提供資料寫入的并發性能。

緩沖

緩沖技術是為了協調吞吐速度相差很大的裝置之間資料傳送而采用的技術。

資料庫系統設計概述資料庫系統設計概述

buffer

在資料到達與離去速度不比對的地方,就應該使用緩沖技術。緩沖技術好比是一個水庫,如果上遊來的水太多,下遊來不及排走,水庫就起到“緩沖”作用,先讓水在水庫中停一些時候,等下遊能繼續排水,再把水送往下遊。

将緩沖和批量發送結合,可以提高資料在在網絡和磁盤中的寫入速率。在資料寫入網絡或磁盤時,先設定一個緩沖池,當資料達到一定的數量或緩沖時間逾時時,在将資料批量發送出去,可以減少請求并發,也可以減少請求額外資料帶來的帶寬和磁盤消耗。

在 Mysql 中,Innodb 在多個地方使用緩沖來提升寫入性能。比如插入緩沖,将多個插入請求合并到一個操作中,這樣可以将之前的一些非順序寫入變成相對的順序寫入,以提高寫入效率。另一方面也可以按磁盤實體頁寫入資料,這樣充分利用了磁盤的寫入特性。

在 Elastisearch 和 Kafka 的用戶端中,都采用了緩沖批量寫入的功能來減少寫入并發情況。

磁盤

在磁盤的讀寫優化上,經常可以看到以下技術:

  • 按磁盤頁讀寫資料:磁盤讀寫的機關是

    。為了減少讀寫資料時磁盤通路頻率,資料庫系統通常都按頁讀寫資料。
  • 預讀資料:一些資料庫系統認為使用者通路了一部分資料,那麼在它相鄰的放的資料下次被通路的可能性也很大,是以會預先讀取多個頁的資料。
  • 磁盤記憶體映射(MMP):即盤扇區映射到程序的虛拟記憶體空間的過程。MMP 讀寫資料時跨過了頁緩存,減少了資料的拷貝次數;實作了使用者空間和核心空間的高效互動方式;可以緩解系統記憶體不足的壓力。

本文對各種技術淺嘗辄止,其實每一個技術點都可以深入講解,感興趣的同學請持續關注我們後期的文章。

參考:

《Designing Data-Intensive Applications》

《Database Software Market:The Long-Awaited Shake-up》

《Distributed systems for fun and profit》

《How does a relational database work》

《七周七資料庫》

《Mysql 技術内幕——InnoDB 存儲引擎》

《資料庫系統概念》

《Dynamo: Amazon's Highly Available Key-value Store》

http://arthurchiao.art/blog/amazon-dynamo-zh/

https://zhuanlan.zhihu.com/p/35622907

https://baike.baidu.com/

https://hbase.apache.org/

https://zh.wikipedia.org/

https://clickhouse.tech/

https://druid.apache.org/

https://www.elastic.co/