NoSQL架構實踐(二)——以NoSQL為主
前面一篇《NoSQL架構實踐(一)——以NoSQL為輔》主要介紹了以NoSQL為輔助的架構,這種架構實施起來比較簡單,易于理解,由于其中也使用了傳統的關系數據庫,讓開發者更容易控制NoSQL帶來的風險。接下來我們繼續深入下去,換另外一個角度,“以NoSQL為主”來架構系統。
(三)純NoSQL架構
只使用NoSQL作為數據存儲。
圖 4-純NoSQL架構
在一些數據結構、查詢關系非常簡單的系統中,我們可以只使用NoSQL即可以解決存儲問題。這樣不但可以提高性能,還非常易于擴展。手機鳳凰網的前端展示系統就使用了這種方案。
在一些數據庫結構經常變化,數據結構不定的系統中,就非常適合使用NoSQL來存儲。比如監控系統中的監控信息的存儲,可能每種類型的監控信息都不太一樣。這樣可以避免經常對MySQL進行表結構調整,增加字段帶來的性能問題。
這種架構的缺點就是數據直接存儲在NoSQL中,不能做關系數據庫的復雜查詢,如果由于需求變更,需要進行某些查詢,可能無法滿足,所以采用這種架構的時候需要確認未來是否會進行復雜關系查詢以及如何應對。
非常幸運的是,有些NoSQL數據庫已經具有部分關系數據庫的關系查詢特性,他們的功能介于key-value和關系數據庫之間,卻具有key-value數據庫的性能,基本能滿足絕大部分web 2.0網站的查詢需求。比如:
MongoDB就帶有關系查詢的功能,能解決常用的關系查詢,所以也是一種非常不錯的選擇。下面是一些MongoDB的資料:
- 《視覺中國的NoSQL之路:從MySQL到MongoDB》
- 《Choosing a non-relational database; why we migrated from MySQL to MongoDB》
- 最近的一次Mongo Beijing 開發者聚會也有一部分資料。
雖然Foursquare使用MongoDB的宕機事件的出現使人對MongoDB的自動Shard提出了質疑,但是毫無疑問,MongoDB在NoSQL中,是一個優秀的數據庫,其單機性能和功能確實是非常吸引人的。由于上面的例子有詳細的介紹,本文就不做MongoDB的使用介紹。
Tokyo Tyrant數據庫帶有一個名為table的存儲類型,可以對存儲的數據進行關系查詢和檢索。一個table庫類似于MySQL中的一個表。下面我們看一個小演示:
我們要存儲一批用戶信息,用戶信息包含用戶名(name),年齡(age),email,最后訪問時間(lastvisit),地區(area)。下面為寫入的演示代碼:
$tt = new TokyoTyrantTable ( "127.0.0.1", 1978 );
$tt->vanish ();//清空
$id = $tt->genUid ();//獲取一個自增id
//put方法提供數據寫入。 put ( string $key , array $columns );
$tt->put ( $id, array ("id" => $id, "name" => "zhangsan", "age" => 27, "email" => "zhangsan@gmail.com", "lastvisit" =>strtotime ( "2011-3-5 12:30:00" ), "area" => "北京" ) );
$id = $tt->genUid ();
$tt->put ( $id, array ("id" => $id, "name" => "lisi", "age" => 25, "email" => "lisi@126.com", "lastvisit" => strtotime( "2011-3-3 14:40:44" ), "area" => "北京" ) );
$id = $tt->genUid ();
$tt->put ( $id, array ("id" => $id, "name" => "laowang", "age" => 37, "email" => "laowang@yahoo.com", "lastvisit" =>strtotime ( "2011-3-5 08:30:12" ), "area" => "成都" ) );
$id = $tt->genUid ();
$tt->put ( $id, array ("id" => $id, "name" => "tom", "age" => 21, "email" => "tom@hotmail.com", "lastvisit" =>strtotime ( "2010-12-10 13:12:13" ), "area" => "天津" ) );
$id = $tt->genUid ();
$tt->put ( $id, array ("id" => $id, "name" => "jack", "age" => 21, "email" => "jack@gmail.com", "lastvisit" =>strtotime ( "2011-02-24 20:12:55" ), "area" => "天津" ) );
//循環打印數據庫的所有數據庫
$it = $tt->getIterator ();
foreach ( $it as $k => $v ) {
print_r ( $v );
}
?>
比如我們需要查詢年齡為21歲的所有用戶:
$tt = new TokyoTyrantTable ( "127.0.0.1", 1978 );
$query = $tt->getQuery ();
//查詢年齡為21歲的用戶
$query->addCond ( “age”, TokyoTyrant::RDBQC_NUMEQ, “21” );
print_r ( $query->search () );
?>
查詢所有在2011年3月5日之后登陸的用戶:
$tt = new TokyoTyrantTable ( "127.0.0.1", 1978 );
$query = $tt->getQuery ();
$query->addCond ( “lastvisit”, TokyoTyrant::RDBQC_NUMGE, strtotime ( "2011-3-5 00:00:00" ) );
print_r ( $query->search () );
?>
從上面的示例代碼可以看出,使用起來是非常簡單的,甚至比SQL語句還要簡單。Tokyo Tyrant的表類型存儲還提供了給字段建立普通索引和倒排全文索引,大大增強了其檢索功能和檢索的性能。
所以,完全用NoSQL來構建部分系統,是完全可能的。配合部分帶有關系查詢功能的NoSQL,在開發上比MySQL數據庫更加快速和高效。
(四)以NoSQL為數據源的架構
數據直接寫入NoSQL,再通過NoSQL同步協議復制到其他存儲。根據應用的邏輯來決定去相應的存儲獲取數據。
圖 5 -以NoSQL為數據源
純NoSQL的架構雖然結構簡單,易于開發,但是在應付需求的變更、穩定性和可靠性上,總是給開發人員一種風險難于控制的感覺。為了降低風險,系統的功能不局限在NoSQL的簡單功能上,我們可以使用以NoSQL為數據源的架構。
在這種架構中,應用程序只負責把數據直接寫入到NoSQL數據庫就OK,然后通過NoSQL的復制協議,把NoSQL數據的每次寫入,更新,刪除操作都復制到MySQL數據庫中。同 時,也可以通過復制協議把數據同步復制到全文檢索實現強大的檢索功能。在海量數據下面,我們也可以根據不同的規則,把數據同步復制到設計好的分表分庫的 MySQL中。這種架構:
- 非常靈活。可以非常方便的在線上系統運行過程中進行數據的調整,比如調整分庫分表的規則、要添加一種新的存儲類型等等。
- 操作簡單。只需要寫入NoSQL數據庫源,應用程序就不用管了。需要增加存儲類型或者調整存儲規則的時候,只需要增加同步的數據存儲,調整同步規則即可,無需更改應用程序的代碼。
- 性能高。數據的寫入和更新直接操作NoSQL,實現了寫的高性能。而通過同步協議,把數據復制到各種適合查詢類型的存儲中(按照業務邏輯區分不同的存儲),能實現查詢的高性能,不像以前MySQL一種數據庫就全包了。或者就一個表負責跟這個表相關的所有的查詢,現在可以把一個表的數據復制到各種存儲,讓各種存儲用自己的長處來對外服務。
- 易擴展。開發人員只需要關心寫入NoSQL數據庫。數據的擴展可以方便的在后端由復制協議根據規則來完成。
這種架構需要考慮數據復制的延遲問題,這跟使用MySQL的master-salve模式的延遲問題是一樣的,解決方法也一樣。
在這種以NoSQL為數據源的架構中,最核心的就是NoSQL數據庫的復制功能的實現。而當前的幾乎所有的NoSQL都沒有提供比較易于使用的復制接口來完成這種架構,對NoSQL進行復制協議的二次開發,需要更高的技術水平,所以這種架構看起來很好,但是卻不是非常容易實現的。我的開源項目PHPBuffer中有個實現TokyoTyrant復制的例子,雖然是PHP版本的,但是很容易就可以翻譯成其他語言。通過這個例子的代碼,可以實現從Tokyo Tyrant實時的復制數據到其他系統中。
總結
以NoSQL為主的架構應該算是對NoSQL的一種深度應用,整個系統的架構以及代碼都不是很復雜,但是卻需要一定的NoSQL使用經驗才行。
參考鏈接:
- 新浪微博NoSQL微群:http://q.t.sina.com.cn/127870
- 我的新浪微博:http://t.sina.com.cn/sunli1223
- Tokyo Cabinet官方站點: http://1978th.net/tokyocabinet/