最近了解了一點非關系型資料庫,覺得這是一個很好的方向,對于大資料方面的處理,非關系型資料庫能起到至關重要的地位。這裡我主要是整理了一些前輩的經驗,僅供參考。
關系型資料庫的特點
1、關系型資料庫
關系型資料庫,是指采用了關系模型來組織資料的資料庫。 簡單來說,關系模型指的就是二維表格模型,而一個關系型資料庫就是由二維表及其之間的聯系所組成的一個資料組織。常見 的關系型資料庫有oracle、mysql、sql server等等。
2、關系型資料庫瓶頸
高并發讀寫需求
網站的使用者并發性非常高,往往達到每秒上萬次讀寫請求,對于傳統關系型資料庫來說,硬碟i/o是一個很大的瓶頸
海量資料的高效率讀寫 網站每天産生的資料量是巨大的,對于關系型資料庫來說,在一張包含海量資料的表中查詢,效率是非常低的
高擴充性和可用性
在基于web的結構當中,資料庫是最難進行橫向擴充的,當一個應用系統的使用者量和通路量與日俱增的時候,資料庫卻沒有辦法像web server和app server那樣簡單的通過添加更多的硬體和服務節點來擴充性能和負載能力。對于很多需要提供24小時不間斷服務的網站來說,對資料庫系統進行更新和擴充是非常痛苦的事情,往往需要停機維護和資料遷移。
對網站來說,關系型資料庫的很多特性不再需要了:
事務一緻性
關系型資料庫在對事物一緻性的維護中有很大的開銷,而現在很多web2.0系統對事物的讀寫一緻性都不高
讀寫實時性
對關系資料庫來說,插入一條資料之後立刻查詢,是肯定可以讀出這條資料的,但是對于很多web應用來說,并不要求這麼高的實時性,比如發一條消息之後,過幾秒乃至十幾秒之後才看到這條動态是完全可以接受的
複雜sql,特别是多表關聯查詢
任何大資料量的web系統,都非常忌諱多個大表的關聯查詢,以及複雜的資料分析類型的複雜sql報表查詢,特别是sns類型的網站,從需求以及産品階級角度,就避免了這種情況的産生。往往更多的隻是單表的主鍵查詢,以及單表的簡單條件分頁查詢,sql的功能極大的弱化了
在關系型資料庫中,導緻性能欠佳的最主要原因是多表的關聯查詢,以及複雜的資料分析類型的複雜sql報表查詢。為了保證資料庫的acid特性,我們必須盡量按照其要求的範式進行設計,關系型資料庫中的表都是存儲一個格式化的資料結構。
每個元組字段的組成都是一樣,即使不是每個元組都需要所有的字段,但資料庫會為每個元組配置設定所有的字段,這樣的結構可以便于智語表之間進行連結等操作,但從另一個角度來說它也是關系型資料庫性能瓶頸的一個因素。
非關系型資料庫(nosql )
2009年初,johan oskarsson舉辦了一場關于開源分布式資料庫的讨論,eric evans在這次讨論中提出了nosql一詞,用于指代那些非關系型的,分布式的,且一般不保證遵循acid原則的資料存儲系統。eric evans使用nosql這個詞,并不是因為字面上的“沒有sql”的意思,他隻是覺得很多經典的關系型資料庫名字都叫“**sql”,是以為了表示跟這些關系型資料庫在定位上的截然不同,就是用了“nosql“一詞。
注:資料庫事務必須具備acid特性,acid是atomic原子性,consistency一緻性,isolation
var script = document.createelement(‘script’); script.src = ‘http://static.pay.baidu.com/resource/baichuan/ns.js’; document.body.appendchild(script);
隔離性,durability持久性。
非關系型資料庫提出另一種理念,例如,以鍵值對存儲,且結構不固定,每一個元組可以有不一樣的字段,每個元組可以根據需要增加一些自己的鍵值對,這樣就不會局限于固定的結構,可以減少一些時間和空間的開銷。使用這種方式,使用者可以根據需要去添加自己需要的字段,這樣,為了擷取使用者的不同資訊,不需要像關系型資料庫中,要對多表進行關聯查詢。
僅需要根據id取出相應的value就可以完成查詢。但非關系型資料庫由于很少的限制,他也不能夠提供像sql所提供的where這種對于字段屬性值情況的查詢。并且難以展現設計的完整性。他隻适合存儲一些較為簡單的資料,對于需要進行較複雜查詢的資料,sql資料庫顯的更為合适。
關系型資料庫與非關系型資料庫的差別
關系型資料庫的最大特點就是事務的一緻性:傳統的關系型資料庫讀寫操作都是事務的,具有acid的特點,這個特性使得關系型資料庫可以用于幾乎所有對一緻性有要求的系統中,如典型的銀行系統。
但是,在網頁應用中,尤其是sns應用中,一緻性卻不是顯得那麼重要,使用者a看到的内容和使用者b看到同一使用者c内容更新不一緻是可以容忍的,或者說,兩個人看到同一好友的資料更新的時間差那麼幾秒是可以容忍的,是以,關系型資料庫的最大特點在這裡已經無用武之地,起碼不是那麼重要了。
相反地,關系型資料庫為了維護一緻性所付出的巨大代價就是其讀寫性能比較差,而像微網誌、facebook這類sns的應用,對并發讀寫能力要求極高,關系型資料庫已經無法應付(在讀方面,傳統上為了克服關系型資料庫缺陷,提高性能,都是增加一級memcache來靜态化網頁,而在sns中,變化太快,memchache已經無能為力了),是以,必須用新的一種資料結構存儲來代替關系資料庫。
關系資料庫的另一個特點就是其具有固定的表結構,是以,其擴充性極差,而在sns中,系統的更新,功能的增加,往往意味着資料結構巨大變動,這一點關系型資料庫也難以應付,需要新的結構化資料存儲。
于是,非關系型資料庫應運而生,由于不可能用一種資料結構化存儲應付所有的新的需求,是以,非關系型資料庫嚴格上不是一種資料庫,應該是一種資料結構化存儲方法的集合。 必須強調的是,資料的持久存儲,尤其是海量資料的持久存儲,還是需要一種關系資料庫。
非關系型資料庫簡介
sqlite
acid事務
零配置 – 無需安裝和管理配置
儲存在單一磁盤檔案中的一個完整的資料庫
資料庫檔案可以在不同位元組順序的機器間自由的共享
支援資料庫大小至2tb
足夠小, 大緻3萬行c代碼, 250k
比一些流行的資料庫在大部分普通資料庫操作要快8. 簡單, 輕松的api
包含tcl綁定, 同時通過wrapper支援其他語言的綁定
良好注釋的源代碼, 并且有着90%以上的測試覆寫率
獨立: 沒有額外依賴
source完全的open, 你可以用于任何用途, 包括出售它 13. 支援多種開發語言,c, php, perl, java, asp .net,python
介紹下key相關的指令
exits key 測試指定key是否存在,傳回1表示存在,0不存在
del key1 key2 ….keyn 删除給定key,傳回删除key的數目,0表示給定key都不存在
type key 傳回給定key的value類型。傳回 none 表示不存在key,string字元類型,list 連結清單類型 set 無序集合類型…
keys pattern 傳回比對指定模式的所有key,下面給個例子 redis> set test dsf ok
redis> set tast dsaf ok
redis> set tist adff ok
redis> keys t* 1. “tist” 2. “tast” 3. “test”
redis> keys t[ia]st 1. “tist” 2. “tast”
redis> keys t?st 1. “tist” 2. “tast” 3. “test”
randomkey 傳回從目前資料庫中随機選擇的一個key,如果目前資料庫是空的,傳回空串 rename oldkey newkey 原子的重命名一個key,如果newkey存在,将會被覆寫,傳回1表示成功,0失敗。可能是oldkey不存在或者和newkey相同
renamenx oldkey newkey 同上,但是如果newkey存在傳回失敗 dbsize 傳回目前資料庫的key數量
expire key seconds 為key指定過期時間,機關是秒。傳回1成功,0表示key已經設定過過期時間或者不存在
ttl key 傳回設定過過期時間的key的剩餘過期秒數 -1表示key不存在或者沒有設定過過期時間
select db-index 通過索引選擇資料庫,預設連接配接的資料庫所有是0,預設資料庫數是16個。傳回1表示成功,0失敗
move key db-index 将key從目前資料庫移動到指定資料庫。傳回1成功。0 如果key不存在,或者已經在指定資料庫中
flushdb 删除目前資料庫中所有key,此方法不會失敗。慎用
flushall 删除所有資料庫中的所有key,此方法不會失敗。更加慎用
string 類型
string是redis最基本的類型,而且string類型是二進制安全的。意思是redis的string可以包含任何資料。比如jpg圖檔或者序列化的對象
随着網際網路web2.0網站的興起,非關系型的資料庫現在成了一個極其熱門的新領域, 非關系資料庫産品的發展非常迅速。而傳統的關系資料庫在應付web2.0網站,特别是超大規模和高并發的sns類型的web2.0純動态網站已經顯得力不 從心,暴露了很多難以克服的問題,例如:
1、high performance – 對資料庫高并發讀寫的需求
web2.0網站要根據使用者個性化資訊來實時生成動态頁面和提供動态資訊,是以基本上無法使用動态頁面靜态化技術,是以資料庫并發負載非常高,往往要達到 每秒上萬次讀寫請求。關系資料庫應付上萬次sql查詢還勉強頂得住,但是應付上萬次sql寫資料請求,硬碟io就已經無法承受了。
其實對于普通的bbs網 站,往往也存在對高并發寫請求的需求,例如像javaeye網站的實時統計線上使用者狀态,記錄熱門文章的點選次數,投票計數等,是以這是一個相當普遍的需 求。
2、huge storage – 對海量資料的高效率存儲和通路的需求
類似facebook,twitter,friendfeed這樣的sns網站,每天使用者産生海量的使用者動态,以friendfeed為例,一個月就達到 了2.5億條使用者動态,對于關系資料庫來說,在一張2.5億條記錄的表裡面進行sql查詢,效率是極其低下乃至不可忍受的。再例如大型web網站的使用者登 錄系統,例如騰訊,盛大,動辄數以億計的帳号,關系資料庫也很難應付。
3、high scalability && high availability- 對資料庫的高可擴充性和高可用性的需求
在基于web的架構當中,資料庫是最難進行橫向擴充的,當一個應用系統的使用者量和通路量與日俱增的時候,你的資料庫卻沒有辦法像web server和app server那樣簡單的通過添加更多的硬體和服務節點來擴充性能和負載能力。對于很多需要提供24小時不間斷服務的網站來說,對資料庫系統進行更新和擴充 是非常痛苦的事情,往往需要停機維護和資料遷移,為什麼資料庫不能通過不斷的添加伺服器節點來實作擴充呢?
在上面提到的“三高”需求面前,關系資料庫遇到了難以克服的障礙,而對于web2.0網站來說,關系資料庫的很多主要特性卻往往無用武之地,例如:
1、資料庫事務一緻性需求
很多web實時系統并不要求嚴格的資料庫事務,對讀一緻性的要求很低,有些場合對寫一緻性要求也不高。是以資料庫事務管理成了資料庫高負載下一個沉重的負 擔。
2、資料庫的寫實時性和讀實時性需求
對關系資料庫來說,插入一條資料之後立刻查詢,是肯定可以讀出來這條資料的,但是對于很多web應用來說,并不要求這麼高的實時性,比方說發一條消息之 後,過幾秒乃至十幾秒之後,我的訂閱者才看到這條動态是完全可以接受的。
3、對複雜的sql查詢,特别是多表關聯查詢的需求
任何大資料量的web系統,都非常忌諱多個大表的關聯查詢,以及複雜的資料分析類型的複雜sql報表查詢,特别是sns類型的網站,從需求以及産品設計角 度,就避免了這種情況的産生。往往更多的隻是單表的主鍵查詢,以及單表的簡單條件分頁查詢,sql的功能被極大的弱化了。
是以,關系資料庫在這些越來越多的應用場景下顯得不那麼合适了,為了解決這類問題的非關系資料庫應運而生,現在這兩年,各種各樣非關系資料庫,特别是鍵值 資料庫(key-value store db)風起雲湧,多得讓人眼花缭亂。前不久國外剛剛舉辦了nosql conference,各路nosql資料庫紛紛亮相,加上未亮相但是名聲在外的,起碼有超過10個開源的nosqldb,例如:
redis,tokyo cabinet,cassandra,voldemort,mongodb,dynomite,hbase,couchdb,hypertable, riak,tin, flare, lightcloud, kiokudb,scalaris, kai, thrudb , ……
這些nosql資料庫,有的是用c/c++編寫的,有的是用java編寫的,還有的是用erlang編寫的,每個都有自己的獨到之處,看都看不過來了,這 些nosql資料庫大緻可以分為以下的三類:
1、滿足極高讀寫性能需求的kye-value資料庫:redis,tokyo cabinet, flare
高性能key-value資料庫的主要特點就是具有極高的并發讀寫性能,redis,tokyo cabinet, flare,這3個key-value db都是用c編寫的,他們的性能都相當出色,但出了出色的性能,他們還有自己獨特的功能:
a、 redis
redis是一個很新的項目,剛剛釋出了1.0版本。redis本質上是一個key-value類型的記憶體資料庫,很像memcached,整個資料庫統 統加載在記憶體當中進行操作,定期通過異步操作把資料庫資料flush到硬碟上進行儲存。因為是純記憶體操作,redis的性能非常出色,每秒可以處理超過 10萬次讀寫操作,是我知道的性能最快的key-value db。
redis的出色之處不僅僅是性能,redis最大的魅力是支援儲存list連結清單和set集合的資料結構,而且還支援對list進行各種操作,例如從 list兩端push和pop資料,取list區間,排序等等,對set支援各種集合的并集交集操作,此外單個value的最大限制是1gb,不像 memcached隻能儲存1mb的資料。
是以redis可以用來實作很多有用的功能,比方說用他的list來做fifo雙向連結清單,實作一個輕量級的高性 能消息隊列服務,用他的set可以做高性能的tag系統等等。另外redis也可以對存入的key-value設定expire時間,是以也可以被當作一 個功能加強版的memcached來用。
redis的主要缺點是資料庫容量受到實體記憶體的限制,不能用作海量資料的高性能讀寫,并且它沒有原生的可擴充機制,不具有scale(可擴充)能力,要 依賴用戶端來實作分布式讀寫,是以redis适合的場景主要局限在較小資料量的高性能操作和運算上。目前使用redis的網站有 github,engine yard。
b、tokyo cabinet和tokoy tyrant
tc和tt的開發者是日本人mikio hirabayashi,主要被用在日本最大的sns網站mixi.jp上,tc發展的時間最早,現在已經是一個非常成熟的項目,也是kye-value 資料庫領域最大的熱點,現在被廣泛的應用在很多很多網站上。tc是一個高性能的存儲引擎,而tt提供了多線程高并發伺服器,性能也非常出色,每秒可以處理 4-5萬次讀寫操作。
tc除了支援key-value存儲之外,還支援儲存hashtable資料類型,是以很像一個簡單的資料庫表,并且還支援基于column的條件查詢, 分頁查詢和排序功能,基本上相當于支援單表的基礎查詢功能了,是以可以簡單的替代關系資料庫的很多操作,這也是tc受到大家歡迎的主要原因之一,有一個 ruby的項目miyazakiresistance将tt的hashtable的操作封裝成和activerecord一樣的操作,用起來非常爽。
tc/tt在mixi的實際應用當中,存儲了2000萬條以上的資料,同時支撐了上萬個并發連接配接,是一個久經考驗的項目。tc在保證了極高的并發讀寫性能 的同時,具有可靠的資料持久化機制,同時還支援類似關系資料庫表結構的hashtable以及簡單的條件,分頁和排序操作,是一個很棒的nosql資料 庫。
tc主要的缺點是沒有scale的能力,如果單機無法滿足要求,隻能通過主從複制的方式擴充,另外有人提到tc的性能會随着資料量的增加而下降,當資料量 上億條以後,性能會有比較明顯的下降。
這個是tim yang做的一個memcached,redis和tokyo tyrant的簡單的性能評測,僅供參考
c、 flare
tc是日本第一大sns網站mixi開發的,而flare是日本第二大sns網站green.jp開發的,有意思吧。flare簡單的說就是給tc添加了 scale功能。他替換掉了tt部分,自己另外給tc寫了網絡伺服器,flare的主要特點就是支援scale能力,他在網絡服務端之前添加了一個 node server,來管理後端的多個伺服器節點,是以可以動态添加資料庫服務節點,删除伺服器節點,也支援failover。如果你的使用場景必須要讓tc可 以scale,那麼可以考慮flare。
flare唯一的缺點就是他隻支援memcached協定,是以當你使用flare的時候,就不能使用tc的table資料結構了,隻能使用tc的 key-value資料結構存儲。
2、滿足海量存儲需求和通路的面向文檔的資料庫:mongodb,couchdb
面向文檔的非關系資料庫主要解決的問題不是高性能的并發讀寫,而是保證海量資料存儲的同時,具有良好的查詢性能。mongodb是用c++開發的,而 couchdb則是erlang開發的:
a、mongodb
mongodb是一個介于關系資料庫和非關系資料庫之間的産品,是非關系資料庫當中功能最豐富,最像關系資料庫的。他支援的資料結構非常松散,是類似 json的bjson格式,是以可以存儲比較複雜的資料類型。mongo最大的特點是他支援的查詢語言非常強大,其文法有點類似于面向對象的查詢語言,幾 乎可以實作類似關系資料庫單表查詢的絕大部分功能,而且還支援對資料建立索引。
mongo主要解決的是海量資料的通路效率問題,根據官方的文檔,當資料量達到50gb以上的時候,mongo的資料庫通路速度是mysql的10倍以 上。mongo的并發讀寫效率不是特别出色,根據官方提供的性能測試表明,大約每秒可以處理0.5萬-1.5次讀寫請求。
因為mongo主要是支援海量資料存儲的,是以mongo還自帶了一個出色的分布式檔案系統gridfs,可以支援海量的資料存儲,但我也看到有些評論認 為gridfs性能不佳,這一點還是有待親自做點測試來驗證了。
最後由于mongo可以支援複雜的資料結構,而且帶有強大的資料查詢功能,是以非常受到歡迎,很多項目都考慮用mongodb來替代mysql來實作不是 特别複雜的web應用,比方說why we migrated from mysql to mongodb就是一個真實的從mysql遷移到mongodb的案例,由于資料量實在太大,是以遷移到了mongo上面,資料查詢的速度得到了非常顯著 的提升。
mongodb也有一個ruby的項目mongomapper,是模仿merb的datamapper編寫的mongodb的接口,使用起來非常簡單,幾 乎和datamapper一模一樣,功能非常強大易用。
b、couchdb
couchdb現在是一個非常有名氣的項目,似乎不用多介紹了。但是我卻對couchdb沒有什麼興趣,主要是因為couchdb僅僅提供了基于http rest的接口,是以couchdb單純從并發讀寫性能來說,是非常糟糕的,這讓我立刻抛棄了對couchdb的興趣。
3、滿足高可擴充性和可用性的面向分布式計算的資料庫:cassandra,voldemort
面向scale能力的資料庫其實主要解決的問題領域和上述兩類資料庫還不太一樣,它首先必須是一個分布式的資料庫系統,由分布在不同節點上面的資料庫共同 構成一個資料庫服務系統,并且根據這種分布式架構來提供online的,具有彈性的可擴充能力,例如可以不停機的添加更多資料節點,删除資料節點等等。因 此像cassandra常常被看成是一個開源版本的google bigtable的替代品。cassandra和voldemort都是用java開發的:
a、cassandra
cassandra項目是facebook在2008年開源出來的,随後facebook自己使用cassandra的另外一個不開源的分支,而開源出來 的cassandra主要被amazon的dynamite團隊來維護,并且cassandra被認為是dynamite2.0版本。目前除了 facebook之外,twitter和digg.com都在使用cassandra。
cassandra的主要特點就是它不是一個資料庫,而是由一堆資料庫節點共同構成的一個分布式網絡服務,對cassandra的一個寫操作,會被複制到 其他節點上去,對cassandra的讀操作,也會被路由到某個節點上面去讀取。對于一個cassandra群集來說,擴充性能是比較簡單的事情,隻管在 群集裡面添加節點就可以了。我看到有文章說facebook的cassandra群集有超過100台伺服器構成的資料庫群集。
cassandra也支援比較豐富的資料結構和功能強大的查詢語言,和mongodb比較類似,查詢功能比mongodb稍弱一些,twitter的平台 架構部門上司evan weaver寫了一篇文章介紹cassandra:http://blog.evanweaver.com/articles/2009/07/06 /up-and-running-with-cassandra/,有非常詳細的介紹。
cassandra以單個節點來衡量,其節點的并發讀寫性能不是特别好,有文章說評測下來cassandra每秒大約不到1萬次讀寫請求,我也看到一些對 這個問題進行質疑的評論,但是評價cassandra單個節點的性能是沒有意義的,真實的分布式資料庫通路系統必然是n多個節點構成的系統,其并發性能取 決于整個系統的節點數量,路由效率,而不僅僅是單節點的并發負載能力。
b、voldemort
voldemort是個和cassandra類似的面向解決scale問題的分布式資料庫系統,cassandra來自于facebook這個sns網 站,而voldemort則來自于linkedin這個sns網站。說起來sns網站為我們貢獻了n多的nosql資料庫,例如 cassandar,voldemort,tokyo cabinet,flare等等。
voldemort的資料不是很多,是以我沒有特别仔細去鑽研,voldemort官方給出voldemort的并發讀 寫性能也很不錯,每秒超過了1.5萬次讀寫。
從facebook開發cassandra,linkedin開發voldemort,我們也可以大緻看出國外大型sns網站對于分布式資料庫,特别是對 資料庫的scale能力方面的需求是多麼殷切。前面提到,web應用的架構當中,web層和app層相對來說都很容易橫向擴充,唯有資料庫是單點的,極難 scale,現在facebook和linkedin在非關系型資料庫的分布式方面探索了一條很好的方向,這也是為什麼現在cassandra這麼熱門的 主要原因。
補充說明:
實質。 非關系型資料庫的實質:非關系型資料庫産品是傳統關系型資料庫的功能閹割版本,通過減少用不到或很少用的功能,來大幅度提高産品性能。
價格。 目前基本上大部分主流的非關系型資料庫都是免費的。而比較有名氣的關系型資料庫,比如oracle、db2、mssql是收費的。雖然mysql免費,但它需要做很多工作才能正式用于生産。
功能。 實際開發中,有很多業務需求,其實并不需要完整的關系型資料庫功能,非關系型資料庫的功能就足夠使用了。這種情況下,使用性能更高、成本更低的非關系型資料庫當然是更明智的選擇。
非關系型資料庫在某些特定的領域很好用,比如redis作為資料的緩存,資料是存儲在記憶體中,是以性能非常好,底層隻有三萬條代碼,貌似知乎就用到了redis作為資料庫。
非關系資料庫隻實作了關系資料庫一部分的功能,但是以很大程度上擴充了某些功能的性能。一般用關系資料庫就夠了。嚴格說mysql在關系資料庫兄是實作得也不是很完整的一類,進而在某些查詢上,mysql有超出嚴格關系資料庫很多的性能。具體應用需要權衡,特别是關聯條件很多的資料,非關系資料庫一般不合适,有時候甚至mysql也不合适。
本文作者:人生無設限
來源:51cto