NOSQL schema建立原則

(1)數據規模php

Bigtable類數據庫系統(HBase,Cassandra等)是爲了解決海量數據規模的存儲須要設計的。這裏說的海量數據規模指的是單個表存儲的數據量是在TB或者PB規模,單個表是由千億行*千億列這樣的規模組成的。提到這個數據規模的問題,不得不說的就是如今在NoSQL市場中,最火的四種NoSQL系統依次是Mongodb,Redis,Cassandra,HBase。咱們知道Cassandra和HBase都是Bigtable類系統,並且都是名門出身(獲得了Facebook,Yahoo,Twitter等的大力支持)。那麼爲何最火的是Mongodb呢?難道是由於HBase不夠優秀麼?我認爲緣由很簡單,畢竟大部分公司的數據規模還達不到Facebook,Yahoo等那麼大,使用Mongodb足以知足他們的需求。Mongodb所提供的Auto-sharding, schema-less等功能,正好解決了這樣數據規模的公司在使用RDBMS過程當中遇到的問題。mysql

(2)數據模型sql

並且Bigtable類數據庫系統的數據模型相對簡單,通常不涉及多表的JOIN操做。在這樣的規模下,傳統的RDBMS應用愈來愈受到限制,維護和升級的成本愈來愈高。並且傳統RDBMS因爲基於share-storage的設計,scale-out的能力不強。把基於share-storage的RDBMS作成分佈式數據庫,須要用戶來開發Proxy層。上述種種問題使得咱們在面對海量數據的時候不得不考慮像Bigtable這樣的NoSQL存儲方案。那麼對於習慣了爲RDBMS設計schema的DBA們來講,遷移到Bigtable類NoSQL系統時的schema設計問題,就須要換一個思路來考慮這個問題了。這篇文章就是介紹在Bigtable類系統中如何設計table的schema,以及隨着數據規模的擴展,一些傳統RDBMS應用向Bigtable系統遷移過程當中須要注意的問題。數據庫

NoSQL數據庫把可擴展性放到了首位,那麼必然會形成必定量的數據冗餘,經過數據冗餘的方式實如今RDBMS中的不一樣表格之間的關係表達。並且在Bigtable類系統中,不會提供SQL類的複雜查詢表達和各類優化功能,僅僅提供海量的數據存儲能力。因此,就像在Facebook的統一消息系統中同樣,不少時候是用一行來存儲一個用戶的全部信息。那麼在Bigtable類系統中,一行所能存儲的數據量就是很是大的。前段時間在微博上有rumor說apple的siri系統後臺是用的HBase,我想若是是真的話,那麼一個用戶的我的助理信息也應該是存在一行裏吧,呵呵。更有意思的是,apple的保密工做作的真好,並且聲東擊西。明明用的是HBase,招聘的時候非說會Cassandra和Mongodb的有加分。。。服務器

在Bigtable類系統schema設計中還須要注意的就是列族特性。由於Bigtable類系統本質上是按照列族存取的,同一個列族裏不一樣列有一個共同點就是數據類型相同。相同的數據類型就會使得數據在磁盤和內存之間IO時的壓縮率很是高,這是全部面向列的存儲系統的共同優點。那麼咱們在考慮一行所要存儲的信息時,就能夠按照各個屬性的數據類型的不一樣存放到相應的列族中。因爲Bigtable是一個稀疏的表格系統,因此可能某一行具有的某一屬性在其餘全部的行裏都不存在,可是這個屬性的數據類型(例如int)的屬性在其餘行基本上確定會存在因此在實際的存儲中,同一列族的屬性是存放到一塊兒的。架構

(3)非規範化app

在NoSQL系統數據建模中,常常提到一個Denormalization的概念,就是非規範化。舉個簡單的例子就是在RDBMS中的Entity和這些Entity之間的關係存儲到NoSQL中的同一個表格中。例如在RDBMS的規範化數據建模中,有兩個表格:Student(StudentID,StudentName,Tutor,CourseID), Course(CourseID,CourseName)。而在Bigtable類NoSQL系統中,只有一個表格Student(StudentID,StudentName,Tutor,CourseID,CourseName)。那麼對於在傳統RDBMS中須要讀取兩個表格的信息,而後JOIN在一塊兒得到或者聚合某些用戶的信息,在NoSQL系統中只須要讀取一次就能夠獲取某些用戶的信息了。less

(4)Row Key異步

Bigtable類系統schema設計須要注意的另一個問題就是Row的自然有序性。Bigtable類系統把Row Key都是解釋成String的,而且按照String的字母順序來組織Row的。因此這一特性就能夠被咱們的schema設計所利用。例如咱們的應用常常須要用到某一屬性的索引或者幾個屬性組合的索引,那麼就能夠用這一屬性或者屬性組合來作Row Key。這一點很是相似於RDBMS中的索引和組合索引,只不過在Bigtable類系統中,這是自然存在的。須要注意的是,在HBase系統中屬性組合做爲Row Key時,須要用特殊的符號將各個單獨的組成部分拼接起來,可是「/」是不能做爲Row Key中不一樣屬性的分割符的,咱們能夠用「_」。分佈式

(5)數據一致性和事務

在數據一致性方面,在傳統的RDBMS系統中,每一列的屬性能夠規範成NOT NULL, UNIQUE或者CHECK等,由RDBMS系統來爲用戶保證數據的一致性需求。在Bigtable類系統中,這一需求在DB層並無保證,而是由用戶層程序來保證的。例如Bigtable類系統是一個大的稀疏的表格,那麼對於表格中若是某個cell爲NULL,那麼在實際物理存儲中是不存儲這個cell的,也就是Bigtable類系統中不保存內容爲NULL的value。因爲開源系統HBase具有行一致性和行原子性,並且通常一行存放一個用戶的信息,因此維護數據一致性的代價相對較小。若是Bigtable類系統的schema設計不佳,形成複雜的數據冗餘,那麼對於應用層來維護數據一致性的代價就很大了。

關於Bigtable類系統的事務支持提及來就很複雜了。簡單的就是HBase已只支持單行的事務,今天據說HBase也開始支持單機多行事務。可是若是打算實現相似於RDBMS的事務特徵,就得結合HBase和Zookeeper了。關於這方面在本文不作詳細討論,後面會專門發文討論Google的關於Percolator和Megastore的paper。這兩篇paper主要討論瞭如何在利用NoSQL系統實現事務,如何打通NoSQL和SQL的。可是就像在Cloud Foundry中Chris說到的同樣,將來的數據庫系統是polyglot persistent storage,不會出現大而全的數據庫一統天下。那麼在Bigtable/HBase上開發愈來愈複雜的feature也得有本身的取捨,試圖打造NoSQL領域的DB通是不現實的。

(6)索引

關於索引是每一個DB系統都須要考慮的問題。從Bigtable的論文中能夠看出其爲每列維護特殊的單列索引,容許建立多列索引。這些索引由Bigtable自動維護,查詢時由Bigtable自動選擇使用哪些索引。這一點和RDBMS就比較接近了。而開源實現的HBase除了自動有序的Row Key做爲索引之外,只提供一個自動維護secondary index。可是查詢時該使用那些索引,得由應用層來決定。關於HBase的secondary index的實現有多種方式,貌似最近還喝coprocessor扯上了關係,能夠參考這個http://kenwublog.com/hbase-secondary-index-and-join。 HBase同時容許建立和使用存儲在文件系統上的Lucene索引。關於HBase和Lucene的結合,能夠參考這裏http://www.infoq.com/articles/LuceneHbase

以上主要是從理論上說明了如何爲Bigtable類系統設計schema。下一篇文章會以一些實例的方式說明這篇文章的內容,其中會涉及到Facebook統一消息系統的例子。

轉自:http://yanbohappy.sinaapp.com/?p=20

上一篇文中從理論上講了如何針對應用需求選擇Bigtable類系統和Bigtable類系統schema設計的原則。這一篇文章舉例說明目前在工業界你們是怎麼作的。一下以Facebook統一消息系統的設計爲例來講明這個問題。

We’re launching a new version of Messages today that combines chat, SMS, email, and Messages into a real-time conversation.

(1)   統一消息系統的規模和應用需求

每月多於350 million的用戶會發送多於 135 billion的person-to-person messages, 120 billion的chat messages。即便這些messages都被限制在160個字符以內,那也意味着21,600,000,000,000 bytes的數據。並且數據是在一直增加的,由於用戶收到消息或者郵件以後通常是不會刪除的。並且統一消息系統所存儲的數據主要有如下兩種類型:一是常常變化的較小的臨時數據集(聊天內容),一是不多被訪問的不斷增長的數據集(郵件,閱讀了收件箱裏的郵件之後就不多去再看它一眼。可是還不能使用archive的方式(相似於磁帶)存儲,由於這些數據必須available all times and with low latency)。同時,對於每一個用戶,咱們須要維護這個用戶的全部消息的逆向索引,由於每一個用戶都想像使用gmail同樣經過關鍵字的形式搜索本身以往的郵件或者聊天記錄。

同時消息系統須要high write throughput。如今的狀況是Facebook Message天天約80億的消息,75億以上的讀和寫操做。高峯時期每分鐘150萬的讀和寫操做,其中約55%的讀和45%的寫操做,每次的寫操做會插入16個記錄。NoSQL系統的Denormalization特性帶來了schema-less的優點,同時因爲同一份信息可能在不一樣的列中冗餘存在,也使得寫的次數增長。

(2)爲何選擇HBase?

在統一消息系統創建之初,對於Infrastructure最重要的就是數據庫的選擇了。 Facebook的Data team面臨的選擇主要有三種:Cassandra, MySQL和HBase。通過在evaluate clusters上的測試,他們最終選擇了HBase。緣由以下:MySQL首先是不能很好的auto sharding的問題,也不能很好的處理長尾數據,並且隨着數據集的不斷增加,更新索引的性能會降低,統計一些變量會變得很慢。而Cassandra的最終一致性模型對於消息系統來講又是很是不靠譜的。Cassandra保證每次讀都能讀到,這個是高可用的,然而讀到的數據卻不保證是最新的數據。若是不是最新的數據,會發生一個read repair process。而HBase在可擴展性和性能不會隨着數據量增加而降低方面擊敗了MySQL,又具有比Cassandra更簡單的一致性模型。(這是否是說明HBase的強一致性、低可用性打敗了Cassandra的最終一致性和高可用性呢?筆者一直認爲Cassandra/Dynamo的思路在設計上很是先進和超前,可是實際系統中應用起來很是麻煩。工業界仍是但願簡單可依賴的東西。) Facebook在HBase上作了一些工做以後,發現HBase的許多feature(例如auto load balance, auto failover, compression support, multiple shards per server等)正好知足這個統一消息系統的需求。HBase底下的HDFS的諸多優勢(replication, end-to-end checksum and automatic rebalance)也很是吸引人,並且Facebook在Hadoop/Hive上面有不少使用經驗。由於在這以前,Facebook的數據倉庫就已經轉到Hadoop平臺上了。

注:這裏不得不說Hadoop/HDFS的replication策略和Cassandra的replication策略的不一樣。Cassandra在某一服務器收到用戶的寫入數據以後,異步的寫到其餘副本服務器上。並且屢次寫操做在不一樣副本的時間前後關係是不能保證一致的。可是HDFS是經過同步的pipeline的方式寫入的,那麼一旦給客戶端返回成功,就能保證全部副本數據的一致性。並且HBase可以保證屢次寫入之間的順序關係,這在消息系統中是很是重要的。由於多條消息的前後到達關係若是混亂,會給用戶帶來麻煩。可是pipeline的複製有個缺點,就是木桶的短板效應,一旦3副本中有一個寫入的速度變慢,就會致使總體pipeline變慢,那麼HBase的寫入吞吐率就會下降。

(3)Facebook Messages後臺存儲系統HBase的schema設計

包括Messages, Chats, Emails, SMS四種消息類型。因爲本文主要討論後臺HBase系統的schema設計問題,關於Facebook統一消息系統的架構和數據流描述詳細請見這篇文章http://blog.huihoo.com/?p=688。歸納起來就是用 HBase 做爲Backend storage infrastructure,每一個用戶數據存儲在 HBase 的單獨一行裏,每一個實體都存儲在本身的HBase列中 ;郵件的大附件是存儲在Facebook本身開發的專用存儲系統 HayStack 中;使用 Apache Lucene 維護反向索引列表。在整個數據流中,用戶的每一個行爲都是經過應用服務器代理用戶完成的。因此整個數據流就是應用服務器與後臺存儲基礎設施之間的互動。針對同一個用戶的不一樣更新可能同時發生,也就是對HBase中一行的操做須要同步,這也是由應用服務器來控制的。也就是說每一個用戶在某一時間段本質上全部的操做都會經過某一臺同步服務器控制的。

這是統一消息系統中Hbase的schema設計圖。從這張圖中能夠看出,一個用戶是Hbase中的一行,包括Metadata Entities, Metadata indexes, Action logs, Keyword search index四個列族。

 

用戶消息系統中的任何更新操做(如發表和刪除消息,標記爲已讀等)會當即append到Action Logs列族中,這稱爲一個action log。一些很小的消息實體也存儲在每一個對應的action log中。這個設計很像Log-Structured File System(http://www.cs.berkeley.edu/~brewer/cs262/LFS.pdf),把每塊數據都append到磁盤,而後維護索引以保持文件總體性和結構。這裏也是經過Metadata indexes列族來維護消息數據的結構。例如咱們要加載未讀郵件列表,那麼先經過Metadata indexes獲取指定tag/time區間的郵件的索引,而後去Metadata Entities中尋找索引對應的實體(好比郵件內容)顯示出來。因此能夠這麼理解,Metadata Entities列族中每一列存放着不一樣的消息實體。

 

Actin log的做用和文件系統或者數據庫中log的做用相似,能夠經過replay action log的方式來構造或者恢復用戶郵箱的當前狀態。經過最後的action log id和Metadata entities, metadata indexes配合來恢復或者更新用戶消息系統的內容。Action log能夠經過批量執行大量的異步寫節省帶寬,提升IO吞吐率。並且action log還能夠被複制到其餘地方以實現數據的備份。

 

Keyword search index列族是爲了用戶經過關鍵字搜索本身消息系統中內容而設計的,維護了一個從keyword到匹配的消息的逆向索引。每一列是一個keyword和存在這個keyword的消息列表。當用戶寫入一個消息是,經過Lucene去解析和轉化它爲一個(keyword,messageID,position)的tuple,而後append到這個Hbase列族中相應關鍵字的列中。這樣全部的消息都被實時索引。關於如何集成Lucene和Hbase,請看這篇文章http://www.infoq.com/cn/articles/LuceneHbase 。

 

(4)Hbase在Facebook的部署狀況

這是Facebook的部署方案:每一個rack裏放20臺server,每一個集羣裏至少5個racks。

據稱Facebook的消息系統的Hbase集羣的規模已經超過了1000臺servers。能夠說是目前那Hbase用做online storage應用的最大規模的集羣了。並且目前在微博上有rumor說Facebook正準備把用戶數據從mysql移到hbase。看來Facebook要全面擁抱Hbase了。

參考文獻:

http://www.facebook.com/note.php?note_id=454991608919

http://dbpedias.com/wiki/HBase:Facebook_Messaging_-_HBase_Comes_of_Age

http://blog.huihoo.com/?p=688

轉自:http://yanbohappy.sinaapp.com/?p=24
相關文章
相關標籤/搜索