關系型數據庫尚能飯否?NoSQL、NewSQL誰能接棒?
數據的積累是當今各行各業巨頭的企業財富,數據庫則是數據存儲的重要途徑。在大數據和微服務大行其道的今天,傳統的關系型數據庫也將迎來變革。云原生的數據庫架構受到越來越多的關注,所以我想和大家一起來聊聊云原生數據架構。本文作為上篇,會先對當下各類數據庫發展現狀進行分析。
一、關系型數據庫尚能飯否?
關系型數據庫出現至今的幾十年時間里,一直是數據庫領域的佼佼者。下圖是全球較為權威的DB-Engines的統計排名,排名主要依據Google以及Bing搜索引擎的關鍵字搜索數量、從業人數信息、職位搜索量、Stack Overflow上提問關注數量等:

DB-Engines 2018年6月公布的數據庫排名
截止至2018年6月,排名前6位的數據庫,僅有排名第5的MongoDB是文檔型數據庫,其余全部是關系型數據庫,且前3位所占有的比重遠遠領先于其后的其他數據庫。
1、優勢
關系型數據庫在經過大數據、NoSQL以及NewSQL等技術革新的輪番轟炸之后依然堅挺,與其固有的優勢密不可分。它的優勢主要體現在對開發人員、運維人員以及系統本身這3個方面的影響。
開發優勢
對于開發人員來說,關系型數據庫的首要優勢是面向SQL。
SQL是關系型數據庫的結構化查詢語言,雖然不同的關系型數據庫有不同的SQL方言,但基于ANSI標準的SQL是大部分關系型數據庫都支持的。且SQL是面向數據庫的訪問語言,可以非常方便的對數據庫進行增、刪、改、查以及授權和管理。SQL的查詢靈活度非常高,可以十分便捷的在聯機事務處理(OLTP)與聯機分析處理(OLAP)之間轉換。
此外,SQL是應用開發工程師所必須掌握的一門編程語言,流行度非常廣泛,招聘到一個完全不會寫SQL的應用開發程序員的概率非常小。因此,SQL極大降低了開發人員招聘的成本。
除了SQL語言本身,各種開發語言對關系型數據庫的支持也十分完善。以Java舉例:JDBC是Java語言訪問數據庫的標準接口,各個關系型數據庫廠商均提供了實現JDBC接口的驅動程序。使用Java語言開發的工程師無需感知不同關系型數據庫間的差異,只要根據JDBC接口編程即可。
由于面向關系的數據庫存儲與面向對象的Java程序不易一一對應,產生了很多對象關系映射(ORM)框架用于簡化關系對象模型的阻抗不匹配,如JPA及其官方實現Hibernate、MyBatis、Jooq等,進一步簡化了應用工程師的日常開發工作。ORM框架大多是采用JDBC封裝,對各個關系型數據庫的兼容性非常高。
運維優勢
關系型數據庫由于存在時間長久,針對每一種常見的關系型數據庫,都能較容易地招聘到相應的數據庫管理員(DBA),以保證關系型數據庫的穩定性、安全性、完整性以及性能,同時保證監控和分析關系型數據庫的系統瓶頸以及設計的合理性。
成熟的關系型數據庫都有自己完善的生態圈,用于保證高可用、數據備份、性能監測分析等成熟的配套工具。規模較大的企業及重要業務系統一般都需要專門的DBA進行運維工作。
系統優勢
只有時間才是檢驗技術的成熟與穩定的標準。關系型數據庫經歷了幾十年的考驗,已經有超大規模的使用,其存儲引擎已經十分成熟。基于MVCC的數據庫引擎在性能和正確性上做到了很好的平衡,并且通過B+tree索引大幅提升了查詢的效率。面對數據這樣的關鍵節點,謹慎的選用關系型數據庫是架構師們的***方案。
基于ACID的事務是關系型數據庫帶給應用系統的又一強力保障。ACID指數據庫事務能夠正確執行的四個基本要素的首字母縮寫。它包括原子性、一致性、隔離性和持久性。只有支持事務的數據庫才能***限度的保證數據的正確性和完整性:
- 原子性(Atomicity)。位于同一事務中的所有操作,要么全部完成(提交),要么全部不完成(回滾),不能停滯在某個中間環節。如果事務在執行過程中發生錯誤,數據將會恢復到事務開始前的狀態。
- 一致性(Consistency)。非只讀的事務應封裝數據庫的狀態從一個一致狀態轉變為另一個一致狀態。一致狀態是指數據庫中的數據應滿足完整性約束,并且事務的中間狀態不應在事務之外被感知。
- 隔離性(Isolation)。多事務并發執行時,不應相互影響其他事務,就像只有這一個操作在并行的被數據庫執行一樣。
- 持久性(Durability)。事務完成后,該事務對數據庫的所有更改將持久的保存在數據庫中。
在編程中使用事務也并非難事,各類如Spring之類的開發框架已經在面向切面(AOP)層面將其做的十分簡單和優雅了。
2、不足
關系型數據庫的性能和訪問承載能力,在面向單一數據節點的企業級應用時代是無可挑剔的。但在訪問量和數據量急劇膨脹的今天,關系型數據庫已經很難再像以前那樣成為如此巨大規模系統的底層支撐,甚至成為了應用系統的瓶頸所在。
關系型數據庫主要有以下三處不足:
- 單節點并發訪問量受限。在服務任意擴容和拆分的同時,由于數據庫中存儲的數據是有狀態的,因此很難像服務一樣任意拆分和擴容。單一的數據庫節點承載大量的服務節點的查詢和更新請求,這并非一個對等的架構部署模式。
- 單節點數據承載量受限。單一數據庫節點對數據的承載能力是有限的。數據量越大,用于查詢數據所創建的索引的深度就越深。索引深度決定IO訪問的次數,索引深度越深,查找越慢。
- 分布式事務性能衰退嚴重。將數據庫拆分之后,需要使用分布式事務代替本地事務。基于XA的分布式事務采用兩階段提交,在準備階段即鎖定資源,直至整個事務結束。在系統并發度增加時,性能會急劇衰退。
綜上所述,關系型數據庫的不足,歸根結底是設計初衷導致的。它并非分布式的產物,對分布式系統的天生不友好,導致它很難適應互聯網的架構模型。面對可以隨時彈性擴容的無狀態服務,關系型數據庫已經略顯笨重。
二、未達預期的NoSQL
隨著關系型數據庫的不足之處暴露得越來越明顯,NoSQL的出現成為了有益補充。不過NoSQL并非為了取代關系型數據庫,而是指Not Only SQL,提供了在SQL之外的另一種選擇。
NoSQL有很多種分類,大致包括鍵值數據庫、文檔數據庫、列族數據庫以及圖數據庫等,用于解決各異的場景。
1、鍵值數據庫
鍵值數據庫的代表是Redis。它在很多場景下都作為緩存使用,但Redis也同樣提供落盤功能。面對通過主鍵查詢的場景,Redis的效率非常高,但對于內容的查詢,則無能為力。
Redis提供了集群的能力,可以將數據分散至不同的節點,有效的分散了單一節點的訪問量瓶頸。如果在內存中無法加載Redis的全部數據而導致落盤,Redis的性能將有所下降,因此在數據量較大的情況下,將Redis的數據根據主鍵進行分片是不錯的解決方案。
Redis通過MULTI、EXEC、DISCARD以及WATCH命令提供事務功能。Redis事務提供一次性的、按順序的、且不可中斷的執行命令的機制。但即使事務中的部分命令執行失敗也無法回滾,因此Redis的事務與數據庫領域中的事務并非是一一對應的關系。
2、文檔數據庫
文檔數據庫的代表是MongoDB。文檔模型與面向對象的數據表達方式更加接近,它擁有自由度極高的Schema模型,可以方便的與JSON數據映射。
文檔數據庫的設計理念與關系型數據庫完全不同,它沒有靜態定義的表結構,而是可以靈活在文檔中隨意增減屬性以及嵌入子文檔和數組。因此面向文檔數據庫設計應用程序,應是以對象本身為主,而不是優先考慮數據庫表結構如何定義。這種設計使得開發工程師在修改程序邏輯時十分方便,無需考慮數據庫表結構的變更導致的鎖表等問題。
MongoDB的查詢維度十分靈活,可以根據需要查找的內容建立索引以提升效率。此外,MongoDB在分布式的表現上也遠強于關系型數據庫,它可以將數據自動分片,并且能夠透明化分片之間的負載均衡和失效轉移。它還內置GridFS,支持大數據集的存儲。
但是MongoDB無法像關系型數據庫那樣支持ACID事務,而是使用最終一致性事務,因此不建議將MongoDB用于非常關鍵的如訂單、交易、賬務等業務系統,而是用于論壇等對數據事務要求級別低一些的業務系統中。
3、列族數據庫
列族數據庫的代表是位于Hadoop大數據體系中的HBase。它是專門用于處理海量數據的分布式數據庫。
HBase通過行主鍵和列族來確定一條記錄,每個列族中的屬性是不固定的,這一點與文檔數據庫類似。HBase同樣能夠自動切分數據,使得數據存儲自動具有水平擴展的能力。HBase的數據存儲在HDFS這樣的分布式文件系統中,對于海量數據的支持是***的。
HBase采用LSM Tree (Log-Structured Merge-Tree)。它將對數據的更改放在內存中,達到指定的閾值后再將更改歸并后批量寫入磁盤,將單個寫操作轉換為批量寫操作,幅大提升寫入速度。但在讀取數據時,HBase則需要分別查找內存和磁盤中的數據,對性能產生一定影響。因此Hbase更加適合寫多讀少的應用。另外,Hbase同樣不支持ACID事務,并且只能通過行鍵來查詢數據。
圖數據庫是用于處理圖關系的數據庫,用于特殊場景,因此這里便不再介紹。
總的來說,NoSQL數據庫的種類繁多,分別適合用于不同的場景。我們通過下表簡單對比一下前文介紹的三種類型NoSQL數據庫:

雖然各種NoSQL的使用場景有很大差別,但它們大多很好地支持了分布式數據庫所需要的分片和數據遷移等功能,在海量數據和大并發的支持方面,強于傳統的關系型數據庫。
NoSQL數據庫雖然可以提供良好的擴展性和靈活性,但它們的不足卻是十分明顯的:
不同的NoSQL數據庫都有自己的查詢語言,相比于SQL,制定應用程序標準接口難上加難。并且NoSQL也無法提供ACID的事務的操作,因此很多企業無法放心的將NoSQL應用于核心業務系統中。
正如NoSQL的定義所說,它們僅僅是基于SQL的關系型數據庫的有益補充,而非關系型數據庫的替代者。
三、冉冉升起的NewSQL
由于SQL和ACID事務實在太過于深入人心,而分布式數據庫的需求又***的旺盛,因此另一種數據庫,NewSQL就應運而生了。
NewSQL是對各種具有分布式可擴展的數據庫的簡稱,它繼承了NoSQL對海量數據的處理能力,同時還保持了傳統關系型數據庫對SQL和ACID事務的支持。NewSQL的關注重點在于混合式(Hybrid)數據庫,它們更傾向于找尋不再區分OLTP與OLAP查詢的多模式數據庫架設方案。
在2016年,Andrew Pavlo與Matthew Aslett發布了一篇論文:《What’s Really New with NewSQL?》,在文章他們將NewSQL劃分為3個大類:新架構(New Architecture)、透明化分片中間件(Transparent Sharding Middleware)和云數據庫(Database-as-a-Service)。
論文參考鏈接:
https://db.cs.cmu.edu/papers/2016/pavlo-newsql-sigmodrec2016.pdf
1、新架構
這一類NewSQL是全新的面向分布式的架構設計的數據庫系統。
它們一般使用share-nothing的架構,支持多節點并發控制、高度容錯的自動化數據副本復制、流控以及分布式查詢處理等特征。
由于它們是天生面向分布式多節點而設計的系統,因此對于查詢優化和節點間的通信協議等處理的更加出色。舉例來說,NewSQL的數據庫的多數據節點間可以直接通信,而無需依賴中心節點。
除了Google的Spanner,其他類似的數據庫都需要自行管理數據在磁盤和內存中的存儲與分布。這意味著該類型的數據庫系統負責將查詢發送到數據節點,而不是將數據復制到請求節點以減少網絡傳輸。
由于采用了全新的架構設計和存儲引擎,并未充分經過時間驗證,所以企業的技術選型者們格外的謹慎。同時,又因為有運維新一代NewSQL經驗的工程師數量也較少,所以相比于關系型數據庫,當前的使用者還相對小眾。很多企業目前都會嘗試跟進全新架構的NewSQL,但尚未遷移核心系統。
最典型的新架構類型的產品是Google的Spanner以及國產數據庫TiDB。
2、透明化分片中間件
透明化分片數據庫中間件允許應用將數據分片寫入多數據節點,但數據節點仍然采用面向單數據節點的關系型數據庫。透明化分片中間件使用中心組件用來路由數據操作請求、協調事務、管理數據分布及復制數據副本。整個集群對外是一個邏輯實例,應用往往無需改動即可平滑使用。
透明化分片數據庫中間件的核心優勢是兼容性,它可以成本較低地在系統現有的單機關系型數據庫與分片中間件之間切換,而無需開發者做任何代碼上的改動。它們旨在充分合理地在分布式的場景下利用傳統關系型數據庫的計算和存儲能力,而并非實現一個全新的關系型數據庫。
這樣既可利用傳統關系型數據庫的穩定性和兼容性,又可在其基礎之上增加分布式場景的處理。在原有基礎上增量而非顛覆是這類NewSQL產品的核心理念。由于開源及流行度的原因,基于MySQL協議的數據庫中間件是最為普遍的。
由于基于單數據節點的傳統關系型數據庫是面向磁盤設計的,對于基于內存的存儲管理及并發控制,不如重新設計的面向分布式的新架構NewSQL那樣,能夠更加高效的利用。另外,SQL解析、查詢計劃優化等工作在中間件和數據庫中將會重復工作,使得整體運行效率略遜于全新設計的NewSQL。
在國內的大中型互聯網公司中,這類NewSQL十分流行,每個公司都基本有自己的數據庫中間件。但由于和公司內部的業務系統耦合較重,成熟的開源產品較少,我們之后將討論到的Sharding-Sphere生態圈中的Sharding-Proxy即屬于這類NewSQL產品。
3、云數據庫
***一種類型的NewSQL,是由云計算公司所提供的云數據庫產品。云數據庫的使用方無需自行維護數據庫及其硬件,而是全部數據托管至云平臺所提供的服務。使用方通過數據庫的URL連接至云端數據庫,并通過API或操作儀表盤去操作和監控系統即可。
云數據庫使用成本***,工程師完全無需考慮數據庫的任何細節問題。對中小型公司來說是理想的解決方案,但對于擁有巨大數據體量的公司來說,采用前兩種NewSQL的開源或自研方案更加合適。
亞馬遜所提供的Aurora即為這類NewSQL的典型應用。
總的來看,NewSQL雖然尚未成熟,但確是面向未來的正確嘗試。三種類型NewSQL數據庫的關注點各不相同,新架構類型數據庫的關注點是徹底的革新;透明化分片數據庫中間件的關注點是增量;而云數據庫則更加關注屏蔽用戶使用細節。
雖然不同類型各有千秋,但它們的核心功能是類似的。無論哪一種NewSQL,混合式(Hybrid)數據庫將是未來的發展方向,當OLTP與OLAP不再區分,將會極大地降低開發成本。
至此,我們就基本理清了當下各類數據庫發展現狀,下一篇文章我會詳細說明面向云原生的數據庫的核心功能特征。有相關思考的同學也歡迎留言交流。