隨着大數據時代的到來,越來越多的網站、應用系統需要支撐海量數據存儲,高並發、高可用、高可擴展性等特性要求。
- 傳統的關系型數據庫在應付這些已經顯得力不從心,並暴露了許多難以克服的問題。
由此,各種各樣的 NoSQL(Not Only SQL)數據庫作為傳統關系型數據的一個有力補充得到迅猛發展。
本文將分析傳統數據庫存在的一些問題,以及幾大類 NoSQL 如何解決這些問題,希望給大家提供一些在不同業務場景下存儲技術選型方面的參考。
傳統數據庫的缺點
傳統的數據庫有如下幾個缺點:
- 大數據場景下 I/O 較高,因為數據是按行存儲,即使只針對其中某一列進行運算,關系型數據庫也會將整行數據從存儲設備中讀入內存,導致 I/O 較高。
- 存儲的是行記錄,無法存儲數據結構。
- 表結構 Schema 擴展不方便,如要修改表結構,需要執行 DDL(data definition language),語句修改,修改期間會導致鎖表,部分服務不可用。
- 全文搜索功能較弱,關系型數據庫下只能夠進行子字符串的匹配查詢,當表的數據逐漸變大的時候,like 查詢的匹配會非常慢,即使在有索引的情況下。況且關系型數據庫也不應該對文本字段進行索引。
- 存儲和處理復雜關系型數據功能較弱,許多應用程序需要了解和導航高度連接數據之間的關系,才能啟用社交應用程序、推薦引擎、欺詐檢測、知識圖譜、生命科學和 IT/網絡等用例。
然而傳統的關系數據庫並不善於處理數據點之間的關系。它們的表格數據模型和嚴格的模式使它們很難添加新的或不同種類的關聯信息。
NoSQL 解決方案
NoSQL,泛指非關系型的數據庫,可以理解為 SQL 的一個有力補充。
在 NoSQL 許多方面性能大大優於非關系型數據庫的同時,往往也伴隨一些特性的缺失,比較常見的是事務庫事務功能的缺失。
數據庫事務正確執行的四個基本要素 ACID 如下:
下面介紹 5 大類 NoSQL 數據針對傳統關系型數據庫的缺點和提供的解決方案:
列式數據庫
列式數據庫是以列相關存儲架構進行數據存儲的數據庫,主要適合於批量數據處理和即時查詢。
相對應的是行式數據庫,數據以行相關的存儲體系架構進行空間分配,主要適合於小批量的數據處理,常用於聯機事務型數據處理。
基於列式數據庫的列列存儲特性,可以解決某些特定場景下關系型數據庫 I/O 較高的問題。
基本原理
傳統關系型數據庫是按照行來存儲數據庫,稱為“行式數據庫”,而列式數據庫是按照列來存儲數據。
將表放入存儲系統中有兩種方法,而我們絕大部分是采用行存儲的。行存儲法是將各行放入連續的物理位置,這很像傳統的記錄和文件系統。
列存儲法是將數據按照列存儲到數據庫中,與行存儲類似。下圖是兩種存儲方法的圖形化解釋:
常見列式數據庫
HBase:是一個開源的非關系型分布式數據庫(NoSQL),它參考了谷歌的 BigTable 建模,實現的編程語言為 Java。
它是 Apache 軟件基金會的 Hadoop 項目的一部分,運行於 HDFS 文件系統之上,為 Hadoop 提供類似於 BigTable 規模的服務。因此,它可以容錯地存儲海量稀疏的數據。
BigTable:是一種壓縮的、高性能的、高可擴展性的,基於 Google 文件系統(Google File System,GFS)的數據存儲系統,用於存儲大規模結構化數據,適用於雲端計算。
相關特性
優點如下:
高效的儲存空間利用率:列式數據庫由於其針對不同列的數據特征而發明的不同算法使其往往有比行式數據庫高的多的壓縮率。
普通的行式數據庫一般壓縮率在 3:1 到 5:1 左右,而列式數據庫的壓縮率一般在 8:1 到 30:1 左右。
比較常見的,通過字典表壓縮數據: 下面中才是那張表本來的樣子。經過字典表進行數據壓縮后,表中的字符串才都變成數字了。
正因為每個字符串在字典表里只出現一次了,所以達到了壓縮的目的(有點像規范化和非規范化 Normalize 和 Denomalize)。
查詢效率高:讀取多條數據的同一列效率高,因為這些列都是存儲在一起的,一次磁盤操作可以把數據的指定列全部讀取到內存中。
下圖通過一條查詢的執行過程說明列式存儲(以及數據壓縮)的優點。
執行步驟如下:
- 去字典表里找到字符串對應數字(只進行一次字符串比較)。
- 用數字去列表里匹配,匹配上的位置設為 1。
- 把不同列的匹配結果進行位運算得到符合所有條件的記錄下標。
- 使用這個下標組裝出最終的結果集。
列式數據庫還適合做聚合操作,適合大量的數據而不是小數據。
缺點如下:
- 不適合掃描小量數據。
- 不適合隨機的更新。
- 不適合做含有刪除和更新的實時操作。
- 單行的數據是 ACID 的,多行的事務時,不支持事務的正常回滾,支持 I(Isolation)隔離性(事務串行提交),D(Durability)持久性,不能保證 A(Atomicity)原子性, C(Consistency)一致性。
使用場景
以 HBase 為例說明:
- 大數據量(100s TB級數據),且有快速隨機訪問的需求。
- 寫密集型應用,每天寫入量巨大,而相對讀數量較小的應用,比如 IM 的歷史消息,游戲的日志等等。
- 不需要復雜查詢條件來查詢數據的應用,HBase 只支持基於 rowkey 的查詢,對於 HBase 來說,單條記錄或者小范圍的查詢是可以接受的。
大范圍的查詢由於分布式的原因,可能在性能上有點影響,HBase 不適用於有 join,多級索引,表關系復雜的數據模型。
- 對性能和可靠性要求非常高的應用,由於 HBase 本身沒有單點故障,可用性非常高。
- 數據量較大,而且增長量無法預估的應用,需要進行優雅的數據擴展的 HBase 支持在線擴展,即使在一段時間內數據量呈井噴式增長,也可以通過 HBase 橫向擴展來滿足功能。
- 存儲結構化和半結構化的數據。
K-V 數據庫
指的是使用鍵值(key-value)存儲的數據庫,其數據按照鍵值對的形式進行組織、索引和存儲。
K-V 存儲非常適合不涉及過多數據關系業務關系的數據,同時能有效減少讀寫磁盤的次數,比 SQL 數據庫存儲擁有更好的讀寫性能,能夠解決關系型數據庫無法存儲數據結構的問題。
常見 K-V 數據庫
Redis:是一個使用 ANSI C 編寫的開源、支持網絡、基於內存、可選持久性的鍵值對存儲數據庫。
從 2015 年 6 月開始,Redis 的開發由 Redis Labs 贊助,而 2013 年 5 月至 2015 年 6 月期間,其開發由 Pivotal 贊助。
在 2013 年 5 月之前,其開發由 VMware 贊助。根據月度排行網站 DB-Engines.com 的數據顯示,Redis 是最流行的鍵值對存儲數據庫。
Cassandra:Apache Cassandra(社區內一般簡稱為C*)是一套開源分布式 NoSQL 數據庫系統。
它最初由 Facebook 開發,用於儲存收件箱等簡單格式數據,集 Google BigTable 的數據模型與 Amazon Dynamo 的完全分布式架構於一身。
Facebook 於 2008 將 Cassandra 開源,此后,由於 Cassandra 良好的可擴展性和性能。
它被 Apple,Comcas,Instagram,Spotify,eBay,Rackspace,Netflix 等知名網站所采用,成為了一種流行的分布式結構化數據存儲方案。
LevelDB:是一個由 Google 公司所研發的鍵/值對(Key/Value Pair)嵌入式數據庫管理系統編程庫, 以開源的 BSD 許可證發布。
相關特性
以 Redis 為例,K-V 數據庫優點如下:
- 性能極高:Redis 能支持超過 10W 的 TPS。
- 豐富的數據類型:Redis 支持包括 String,Hash,List,Set,Sorted Set,Bitmap 和 Hyperloglog。
- 豐富的特性:Redis 還支持 publish/subscribe,通知,key 過期等等特性。
缺點如下:
- 針對 ACID,Redis 事務不能支持原子性和持久性(A 和 D),只支持隔離性和一致性(I 和 C) 。
特別說明一下,這里所說的無法保證原子性,是針對 Redis 的事務操作,因為事務是不支持回滾(roll back),而因為 Redis 的單線程模型,Redis 的普通操作是原子性的。
大部分業務不需要嚴格遵循 ACID 原則,例如游戲實時排行榜,粉絲關注等場景,即使部分數據持久化失敗,其實業務影響也非常小。因此在設計方案時,需要根據業務特征和要求來做選擇。
使用場景
適用場景:
- 儲存用戶信息(比如會話)、配置文件、參數、購物車等等。這些信息一般都和 ID(鍵)掛鈎。
不適用場景:
- 需要通過值來查詢,而不是鍵來查詢。Key-Value 數據庫中根本沒有通過值查詢的途徑。
- 需要儲存數據之間的關系。在 Key-Value 數據庫中不能通過兩個或以上的鍵來關聯數據。
- 需要事務的支持。在 Key-Value 數據庫中故障產生時不可以進行回滾。
文檔數據庫
文檔數據庫(也稱為文檔型數據庫)是旨在將半結構化數據存儲為文檔的一種數據庫。文檔數據庫通常以 JSON 或 XML 格式存儲數據。
由於文檔數據庫的 no-schema 特性,可以存儲和讀取任意數據。
由於使用的數據格式是 JSON 或者 BSON,因為 JSON 數據是自描述的,無需在使用前定義字段,讀取一個 JSON 中不存在的字段也不會導致 SQL 那樣的語法錯誤,可以解決關系型數據庫表結構 Schema 擴展不方便的問題。
常見文檔數據庫
MongoDB:是一種面向文檔的數據庫管理系統,由 C++ 撰寫而成,以此來解決應用程序開發社區中的大量現實問題。2007 年 10 月,MongoDB 由 10gen 團隊所發展。2009 年 2 月首度推出。
CouchDB:Apache CouchDB 是一個開源數據庫,專注於易用性和成為"完全擁抱 Web 的數據庫"。
它是一個使用 JSON 作為存儲格式,JavaScript 作為查詢語言,MapReduce 和 HTTP 作為 API 的 NoSQL 數據庫。
其中一個顯著的功能就是多主復制。CouchDB 的第一個版本發布在 2005 年,在 2008 年成為了 Apache 的項目。
相關特性
以 MongoDB 為例進行說明,文檔數據庫優點如下:
- 新增字段簡單,無需像關系型數據庫一樣先執行 DDL 語句修改表結構,程序代碼直接讀寫即可。
- 容易兼容歷史數據,對於歷史數據,即使沒有新增的字段,也不會導致錯誤,只會返回空值,此時代碼兼容處理即可。
- 容易存儲復雜數據,JSON 是一種強大的描述語言,能夠描述復雜的數據結構。
相比傳統關系型數據庫,文檔數據庫的缺點主要是對多條數據記錄的事務支持較弱,具體體現如下:
- Atomicity(原子性),僅支持單行/文檔級原子性,不支持多行、多文檔、多語句原子性。
- Solation(隔離性),隔離級別僅支持已提交讀(Read committed)級別,可能導致不可重復讀,幻讀的問題。
- 不支持復雜查詢,例如 join 查詢,如果需要 join 查詢,需要多次操作數據庫。
MongonDB 還支持多文檔事務的 Consistency(一致性)和 Durability(持久性),雖然官方宣布 MongoDB 將在 4.0 版本中正式推出多文檔 ACID 事務支持,最后落地情況還有待見證。
使用場景
適用場景:
- 數據量很大或者未來會變得很大。
- 表結構不明確,且字段在不斷增加,例如內容管理系統,信息管理系統。
不適用場景:
- 在不同的文檔上需要添加事務。Document-Oriented 數據庫並不支持文檔間的事務。
- 多個文檔之間需要復雜查詢,例如 join。
全文搜索引擎
傳統關系型數據庫主要通過索引來達到快速查詢的目的,在全文搜索的業務下,索引也無能為力,主要體現在:
- 全文搜索的條件可以隨意排列組合,如果通過索引來滿足,則索引的數量非常多。
- 全文搜索的模糊匹配方式,索引無法滿足,只能用 like 查詢,而 like 查詢是整表掃描,效率非常低。
而全文搜索引擎的出現,正是解決關系型數據庫全文搜索功能較弱的問題。
基本原理
全文搜索引擎的技術原理稱為“倒排索引”(inverted index),是一種索引方法,其基本原理是建立單詞到文檔的索引。與之相對的是“正排索引”,其基本原理是建立文檔到單詞的索引。
現在有如下文檔集合:
正排索引得到索引如下:
由上可見,正排索引適用於根據文檔名稱查詢文檔內容。簡單的倒排索引如下:
帶有單詞頻率信息的倒排索引如下:
由上可見,倒排索引適用於根據關鍵詞來查詢文檔內容。
常見全文搜索引擎
Elasticsearch:是一個基於 Lucene 的搜索引擎。它提供了一個分布式,多租戶,能夠全文搜索與發動機 HTTP Web 界面和無架構 JSON 文件。
Elasticsearch 是用 Java 開發的,並根據 Apache License 的條款作為開源發布。
根據 DB-Engines 排名,Elasticsearch 是最受歡迎的企業搜索引擎,后面是基於 Lucene 的 Apache Solr。
Solr:是 Apache Lucene 項目的開源企業搜索平台。其主要功能包括全文檢索、命中標示、分面搜索、動態聚類、數據庫集成,以及富文本(如 Word、PDF)的處理。Solr 是高度可擴展的,並提供了分布式搜索和索引復制。
相關特性
以 Elasticsearch 為例,全文搜索引擎優點如下:
- 查詢效率高,對海量數據進行近實時的處理。
- 可擴展性,基於集群環境可以方便橫向擴展,可以承載 PB 級數據。
- 高可用,Elasticsearch 集群彈性,他們將發現新的或失敗的節點,重組和重新平衡數據,確保數據是安全的和可訪問的。
缺點如下:
- ACID 支持不足,單一文檔的數據是 ACID 的,包含多個文檔的事務時不支持事務的正常回滾,支持 I(Isolation)隔離性(基於樂觀鎖機制的),D(Durability)持久性,不支持 A(Atomicity)原子性,C(Consistency)一致性。
- 對類似數據庫中通過外鍵的復雜的多表關聯操作支持較弱。
- 讀寫有一定延時,寫入的數據,最快 1s 中能被檢索到。
- 更新性能較低,底層實現是先刪數據,再插入新數據。
- 內存占用大,因為 Lucene 將索引部分加載到內存中。
使用場景
適用場景如下:
- 分布式的搜索引擎和數據分析引擎。
- 全文檢索,結構化檢索,數據分析。
- 對海量數據進行近實時的處理,可以將海量數據分散到多台服務器上去存儲和檢索。
不適用場景如下:
- 數據需要頻繁更新。
- 需要復雜關聯查詢。
圖形數據庫
圖形數據庫應用圖形理論存儲實體之間的關系信息。最常見例子就是社會網絡中人與人之間的關系。
關系型數據庫用於存儲“關系型”數據的效果並不好,其查詢復雜、緩慢、超出預期。
而圖形數據庫的獨特設計恰恰彌補了這個缺陷,解決關系型數據庫存儲和處理復雜關系型數據功能較弱的問題。
常見圖形數據庫
Neo4j:是由 Neo4j,Inc. 開發的圖形數據庫管理系統。由其開發人員描述為具有原生圖存儲和處理的符合 ACID 的事務數據庫,根據 DB-Engines 排名,Neo4j 是最流行的圖形數據庫。
ArangoDB:是由 triAGENS GmbH 開發的原生多模型數據庫系統。數據庫系統支持三個重要的數據模型(鍵/值,文檔,圖形),其中包含一個數據庫核心和統一查詢語言 AQL(ArangoDB 查詢語言)。
查詢語言是聲明性的,允許在單個查詢中組合不同的數據訪問模式。ArangoDB 是一個 NoSQL 數據庫系統,但 AQL 在很多方面與 SQL 類似。
Titan:是一個可擴展的圖形數據庫,針對存儲和查詢包含分布在多機群集中的數百億個頂點和邊緣的圖形進行了優化。
Titan 是一個事務性數據庫,可以支持數千個並發用戶實時執行復雜的圖形遍歷。
相關特性
以 Neo4j 為例,Neo4j 使用數據結構中圖(graph)的概念來進行建模。Neo4j 中兩個最基本的概念是節點和邊。
節點表示實體,邊則表示實體之間的關系。節點和邊都可以有自己的屬性。不同實體通過各種不同的關系關聯起來,形成復雜的對象圖。
針對關系數據,兩種數據庫的存儲結構不同:
Neo4j 中,存儲節點時使用了“index-free adjacency”,即每個節點都有指向其鄰居節點的指針,可以讓我們在 O(1) 的時間內找到鄰居節點。
另外,按照官方的說法,在 Neo4j 中邊是最重要的,即“first-class entities”,所以單獨存儲,這有利於在圖遍歷的時候提高速度,也可以很方便地以任何方向進行遍歷。
優點如下:
- 高性能表現,圖的遍歷是圖數據結構所具有的獨特算法,即從一個節點開始,根據其連接的關系,可以快速和方便地找出它的鄰近節點。
這種查找數據的方法並不受數據量的大小所影響,因為鄰近查詢始終查找的是有限的局部數據,不會對整個數據庫進行搜索。
- 設計的靈活性,數據結構的自然伸展特性及其非結構化的數據格式,讓圖數據庫設計可以具有很大的伸縮性和靈活性。
因為隨着需求的變化而增加的節點、關系及其屬性並不會影響到原來數據的正常使用。
- 開發的敏捷性,直觀明了的數據模型,從需求的討論開始,到程序開發和實現,以及最終保存在數據庫中的樣子,它的模樣似乎沒有什么變化,甚至可以說本來就是一模一樣的。
- 完全支持 ACID,不像別的 NoSQL 數據庫,Neo4j 還具有完全事務管理特性,完全支持 ACID 事務管理。
缺點如下:
- 具有支持節點,關系和屬性的數量的限制。
- 不支持拆分。
使用場景
適用場景如下:
- 在一些關系性強的數據中,例如社交網絡。
- 推薦引擎。如果我們將數據以圖的形式表現,那么將會非常有益於推薦的制定。
不適用場景如下:
- 記錄大量基於事件的數據(例如日志條目或傳感器數據)。
- 對大規模分布式數據進行處理,類似於 Hadoop。
- 適合於保存在關系型數據庫中的結構化數據。
- 二進制數據存儲。
總結
關系型數據庫和 NoSQL 數據庫的選型,往往需要考慮幾個指標:
- 數據量
- 並發量
- 實時性
- 一致性要求
- 讀寫分布和類型
- 安全性
- 運維成本
常見軟件系統數據庫選型參考如下:
- 內部使用的管理型系統,如運營系統,數據量少,並發量小,首選考慮關系型。
- 大流量系統,如電商單品頁,后台考慮選關系型,前台考慮選內存型。
- 日志型系統,原始數據考慮選列式,日志搜索考慮選倒排索引。
- 搜索型系統,例如站內搜索,非通用搜索,如商品搜索,后台考慮選關系型,前台考慮選倒排索引。
- 事務型系統,如庫存,交易,記賬,考慮選關系型+緩存+一致性型協議。
- 離線計算,如大量數據分析,考慮選列式或者關系型也可以。
- 實時計算,如實時監控,可以考慮選內存型或者列式數據庫。
在設計實踐中,我們要基於需求、業務驅動架構,無論選用 RDB/NoSQL/DRDB,一定是以需求為導向,最終數據存儲方案必然是各種權衡的綜合性設計。
參考資料:
- 從0開始學架構 —— Alibaba 李運華
- NoSQL漫談
- 圖形數據庫 Neo4j 開發實戰
- 大數據時代的 9 大Key-Value存儲數據庫
- 事務—— Redis官方文檔
- MongoDB是如何實現事務的ACID?
- MySQL臟讀、虛讀、幻讀
- 全面梳理關系型數據庫和 NoSQL 的使用情景
- 淺析列式數據庫的特點
- 一分鍾搞懂列式與行式數據庫
- HBase 基本概念
- NoSQL Databases, why we should use, and which one we should choose
- 傳統關系數據庫與分布式數據庫知識點
==============================
1NoSQL的誕生原因
隨着互聯網快速發展,各種類型的應用層出不窮,所以導致在這個雲計算的時代,對技術提出了更多的需求,主要體現在下面這四個方面:
-
低延遲的讀寫速度:應用快速地反應能極大地提升用戶的滿意度;
原因:當數據量達到一定規模時,由於關系型數據庫的系統邏輯非常復雜,使得其非常容易發生死鎖等的並發問題,所以導致其讀寫速度下滑非常嚴重;
-
支撐海量的數據和流量:對於搜索這樣大型應用而言,需要利用PB級別的數據和能應對百萬級的流量;
原因:有限的支撐容量:現有關系型解決方案還無法支撐Google這樣海量的數據存儲
-
大規模集群的管理:系統管理員希望分布式應用能更簡單的部署和管理;
原因:由於存在類似Join這樣多表查詢機制,使得數據庫在擴展方面很艱難;
-
龐大運營成本的考量:IT經理們希望在硬件成本、軟件成本和人力成本能夠有大幅度地降低;
原因:企業級數據庫的License價格很驚人,並且隨着系統的規模,而不斷上升;
業界為了解決上面提到的幾個需求,推出了多款新類型的數據庫,並且由於它們在設計上和傳統的NoSQL數據庫相比有很大的不同,所以被統稱為 “NoSQL”系列數據庫。總的來說,在設計上,它們非常關注對數據高並發地讀寫和對海量數據的存儲等,與關系型數據庫相比,它們在架構和數據模型方量面 做了“減法”,而在擴展和並發等方面做了“加法”。現在主流的NoSQL數據庫有BigTable、HBase、Cassandra、SimpleDB、 CouchDB、MongoDB和Redis等
2為何要使用NoSQL數據庫?
-
NoSQL具有靈活的數據模型,可以處理非結構化/半結構化的大數據
現在,我們可以通過Facebook、D&B等第三方輕松獲得與訪問數據,如個人用戶信息、地理位置數據、社交圖譜、用戶產生的內容、機器日志數 據以及傳感器生成的數據等。對這些數據的使用正在快速改變着通信、購物、廣告、娛樂以及關系管理的特質。沒有使用這些數據的應用很快就會被用戶所遺忘。開 發者希望使用非常靈活的數據庫,能夠輕松容納新的數據類型,並且不會被第三方數據提供商內容結構的變化所累。很多新數據都是非結構化或是半結構化的,因此開發者還需要能夠高效存儲這種數據的數據庫。但遺憾的是,關系型數據庫所使用的定義嚴格、基於模式的方式是無法快速容納新的數據類型的,對於非結構化或是 半結構化的數據更是無能為力。NoSQL提供的數據模型則能很好地滿足這種需求。很多應用都會從這種非結構化數據模型中獲益,比如說CRM、ERP、 BPM等等,他們可以通過這種靈活性存儲數據而無需修改表或是創建更多的列。這些數據庫也非常適合於創建原型或是快速應用,因為這種靈活性使得新特性的開 發變得非常容易。
-
NoSQL很容易實現可伸縮性(向上擴展與水平擴展)
如果有很多用戶在頻繁且並發地使用你的應用,那么你就需要考慮可伸縮的數據庫技術而非傳統的RDBMS了。對於關系型技術來說,很多應用開發者會發現動態 的可伸縮性是難以實現的,這時就應該考慮切換到NoSQL數據庫上。對於雲應用來說,關系型數據庫一開始是普遍的選擇。然而,在使用過程中卻遇到了越來越 多的問題,原因就在於他們是中心化的,向上擴展而非水平擴展的。這使得他們不適合於那些需要簡單且動態可伸縮性的應用。NoSQL數據庫從一開始就是分布 式、水平擴展的,因此非常適合於互聯網應用分布式的特性。
在三層互聯網架構的Web/應用層上,多年來向上擴展已經成為默認的擴展方式了。隨着應用使用人數的激增,我們需要添加更多的服務器,性能則是通過負載均 衡來實現的,這時的代價與用戶數量成線性比例關系。在NoSQL數據庫之前,數據庫層的默認擴展方式就是向上擴展。為了支持更多的並發用戶以及存儲更多的 數據,你需要越來越好的服務器,更好的CPU、更多的內存、更大的磁盤來維護所有表。然而,好的服務器意味着更加復雜、私有、並且也更加昂貴。這與 Web/應用層所使用的便宜的硬件形成了鮮明的對比。
-
動態模式
關系型數據庫需要在添加數據前先定義好模式。比如說,你需要存儲客戶的電話號碼、姓名、地址、城市與州等信息,SQL數據庫需要提前知曉你要存的是什么。 這對於敏捷開發模式來說是場災難,因為每次完成新特性時,數據庫的模式通常都需要改變。因此,如果在開發過程中想將客戶喜歡的條目加到數據庫中,那就得向 表中添加這一列才行,然后要做的就是將整個數據庫遷移到新的模式上。
-
自動分片
由於是結構化的,關系型數據庫通常會垂直擴展,單台服務器要持有整個數據庫來確保可靠性與數據的持續可用性。這樣做的代價就是非常昂貴、擴展受到限制,並 且數據庫基礎設施會成為失敗點。這個問題的解決方案就是水平擴展,添加服務器而不是為單台服務器增加更多的能力。NoSQL數據庫通常都支持自動分片,這 意味着他們本質上就會自動在多台服務器上分發數據,應用甚至都不知道這些事情。數據與查詢負載會自動在多台服務器上做到平衡,當某台服務器當機時,它能快 速且透明地被替換掉。
-
復制
大多數NoSQL數據庫也支持自動復制,這意味着你可以獲得高可用性與災備恢復功能。從開發者的角度來看,存儲環境本質上是虛擬化的。
3NoSQL優缺點
在優勢方面,主要體現在下面這三點:
-
簡單的擴展:典型例子是Cassandra,由於其架構是類似於經典的P2P,所以能通過輕松地添加新的節點來擴展這個集群;
-
快速的讀寫:主要例子有Redis,由於其邏輯簡單,而且純內存操作,使得其性能非常出色,單節點每秒可以處理超過10萬次讀寫操作;
-
低廉的成本:這是大多數分布式數據庫共有的特點,因為主要都是開源軟件,沒有昂貴的License成本;
但瑕不掩瑜,NoSQL數據庫還存在着很多的不足,常見主要有下面這幾個:
-
不提供對SQL的支持:如果不支持SQL這樣的工業標准,將會對用戶產生一定的學習和應用遷移成本;
-
支持的特性不夠豐富:現有產品所提供的功能都比較有限,大多數NoSQL數據庫都不支持事務,也不像MS SQL Server和Oracle那樣能提供各種附加功能,比如BI和報表等;
-
現有產品的不夠成熟:大多數產品都還處於初創期,和關系型數據庫幾十年的完善不可同日而語;
上面NoSQL產品的優缺點都是些比較共通的,在實際情況下,每個產品都會根據自己所遵從的數據模型和CAP理念而有所不同。
4適合場景
NoSQL數據庫正在成為數據庫領域的重要力量。如果使用恰當,那么它會帶來很多好處。然而,企業應該非常小心並注意到這些數據庫的限制與問題。
NoSQL這兩年越來越熱,尤其是大型互聯網公司非常熱衷這門技術。根據筆者的經驗,並不是任何場景,NoSQL都要優於關系型數據庫。下面我們來具體聊聊,什么時候使用NoSQL比較給力:
1) 數據庫表schema經常變化
比如在線商城,維護產品的屬性經常要增加字段,這就意味着ORMapping層的代碼和配置要改,如果該表的數據量過百萬,新增字段會帶來額外開銷(重建索引等)。NoSQL應用在這種場景,可以極大提升DB的可伸縮性,開發人員可以將更多的精力放在業務層。
2)數據庫表字段是復雜數據類型
對於復雜數據類型,比如SQL Sever提供了可擴展性的支持,像xml類型的字段。很多用過的同學應該知道,該字段不管是查詢還是更改,效率非常一般。主要原因是是DB層對xml字 段很難建高效索引,應用層又要做從字符流到dom的解析轉換。NoSQL以json方式存儲,提供了原生態的支持,在效率方便遠遠高於傳統關系型數據庫。
3)高並發數據庫請求
此類應用常見於web2.0的網站,很多應用對於數據一致性要求很低,而關系型數據庫的事務以及大表join反而成了”性能殺手”。在高並發情況 下,sql與no-sql的性能對比由於環境和角度不同一直是存在爭議的,並不是說在任何場景,no-sql總是會比sql快。有篇article和大家 分享下,http://artur.ejsmont.org/blog/content/insert-performance-comparison-of-nosql-vs-sql-servers
4)海量數據的分布式存儲
海量數據的存儲如果選用大型商用數據,如Oracle,那么整個解決方案的成本是非常高的,要花很多錢在軟硬件上。NoSQL分布式存儲,可以部署在廉價的硬件上,是一個性價比非常高的解決方案。Mongo的auto-sharding已經運用到了生產環境。http://www.mongodb.org/display/DOCS/Sharding
並不是說NoSQL可以解決一切問題,像ERP系統、BI系統,在大部分情況還是推薦使用傳統關系型數據庫。主要的原因是此類系統的業務模型復雜,使用NoSQL將導致系統的維護成本增加。
5選擇SQL還是NoSQL
上面說明了為什么要使用NoSQL。接下來我們看下如何把NoSQL引入到我們的項目中,我們到底要不要把NoSQL引入到項目中。
在過去,我們只需要學習和使用一種數據庫技術,就能做幾乎所有的數據庫應用開發。因為成熟穩定的關系數據庫產品並不是很多,而供你選擇的免費版本就 更加少了,所以互聯網領域基本上都選擇了免費的MySQL數據庫。在高速發展的WEB2.0時代,我們發現關系數據庫在性能、擴展性、數據的快速備份和恢 復、滿足需求的易用性上並不總是能很好的滿足我們的需要,我們越來越趨向於根據業務場景選擇合適的數據庫,以及進行多種數據庫的融合運用。幾年前的一篇文 章《One Size Fits All - An Idea Whose Time Has Come and Gone》就已經闡述了這個觀點。
當我們在討論是否要使用NoSQL的時候,你還需要理解NoSQL也是分很多種類的,在NoSQL百花齊放的今天,NoSQL的正確選擇比選擇關系數據庫還具有挑戰性。雖然NoSQL的使用很簡單,但是選擇卻是個麻煩事,這也正是很多人在觀望的一個原因。
6NoSQL的分類
NoSQL僅僅是一個概念,NoSQL數據庫根據數據的存儲模型和特點分為很多種類。
以上NoSQL數據庫類型的划分並不是絕對,只是從存儲模型上來進行的大體划分。它們之間沒有絕對的分界,也有交差的情況,比如Tokyo Cabinet / Tyrant的Table類型存儲,就可以理解為是文檔型存儲,Berkeley DB XML數據庫是基於Berkeley DB之上開發的。
7選擇和使用建議
雖然09年出現了比較激進的文章《關系數據庫已死》,但是我們心里都清楚,關系數據庫其實還活得好好的,你還不能不用關系數據庫。但是也說明了一個事實,關系數據庫在處理WEB2.0數據的時候,的確已經出現了瓶頸。
那么我們到底是用NoSQL還是關系數據庫呢?我想我們沒有必要來進行一個絕對的回答。我們需要根據我們的應用場景來決定我們到底用什么。
如果關系數據庫在你的應用場景中,完全能夠很好的工作,而你又是非常善於使用和維護關系數據庫的,那么我覺得你完全沒有必要遷移到NoSQL上面, 除非你是個喜歡折騰的人。如果你是在金融,電信等以數據為王的關鍵領域,目前使用的是Oracle數據庫來提供高可靠性的,除非遇到特別大的瓶頸,不然也 別貿然嘗試NoSQL。
然而,在WEB2.0的網站中,關系數據庫大部分都出現了瓶頸。在磁盤IO、數據庫可擴展上都花費了開發人員相當多的精力來優化,比如做分表分庫 (database sharding)、主從復制、異構復制等等,然而,這些工作需要的技術能力越來越高,也越來越具有挑戰性。如果你正在經歷這些場合,那么我覺得你應該嘗 試一下NoSQL了。
一、選擇合適的NoSQL
如此多類型的NoSQL,而每種類型的NoSQL又有很多,到底選擇什么類型的NoSQL來作為我們的存儲呢?這並不是一個很好回答的問題,影響我們選擇 的因素有很多,而選擇也可能有多種,隨着業務場景,需求的變更可能選擇又會變化。我們常常需要根據如下情況考慮:
1.數據結構特點。包括結構化、半結構化、字段是否可能變更、是否有大文本字段、數據字段是否可能變化。
2.寫入特點。包括insert比例、update比例、是否經常更新數據的某一個小字段、原子更新需求。
3.查詢特點。包括查詢的條件、查詢熱點的范圍。比如用戶信息的查詢,可能就是隨機的,而新聞的查詢就是按照時間,越新的越頻繁。
二、NoSQL和關系數據庫結合
其實NoSQL數據庫僅僅是關系數據庫在某些方面(性能,擴展)的一個彌補,單從功能上講,NoSQL的幾乎所有的功能,在關系數據庫上都能夠滿足,所以選擇NoSQL的原因並不在功能上。
所以,我們一般會把NoSQL和關系數據庫進行結合使用,各取所長,需要使用關系特性的時候我們使用關系數據庫,需要使用NoSQL特性的時候我們使用NoSQL數據庫,各得其所。
舉個簡單的例子吧,比如用戶評論的存儲,評論大概有主鍵id、評論的對象aid、評論內容content、用戶uid等字段。我們能確定的是評論內 容content肯定不會在數據庫中用where content=’’查詢,評論內容也是一個大文本字段。那么我們可以把 主鍵id、評論對象aid、用戶id存儲在數據庫,評論內容存儲在NoSQL,這樣數據庫就節省了存儲content占用的磁盤空間,從而節省大量IO, 對content也更容易做Cache。
//從MySQL中查詢出評論主鍵id列表 commentIds=DB.query(“SELECT id FROM comments where aid=’評論對象id’ LIMIT 0,20”); //根據主鍵id列表,從NoSQL取回評論實體數據 CommentsList=NoSQL.get(commentIds);NoSQL代替MySQL
在某些應用場合,比如一些配置的關系鍵值映射存儲、用戶名和密碼的存儲、Session會話存儲等等,用NoSQL完全可以替代MySQL存儲。不但具有更高的性能,而且開發也更加方便。
三、NoSQL作為緩存服務器
MySQL+Memcached的架構中,我們處處都要精心設計我們的緩存,包括過期時間的設計、緩存的實時性設計、緩存內存大小評估、緩存命中率等等。
NoSQL數據庫一般都具有非常高的性能,在大多數場景下面,你不必再考慮在代碼層為NoSQL構建一層Memcached緩存。NoSQL數據本身在Cache上已經做了相當多的優化工作。
Memcached這類內存緩存服務器緩存的數據大小受限於內存大小,如果用NoSQL來代替Memcached來緩存數據庫的話,就可以不再受限於內存大小。雖然可能有少量的磁盤IO讀寫,可能比Memcached慢一點,但是完全可以用來緩存數據庫的查詢操作。