「NOSQL」 雜談

引言:

 nosql 的興起和革命,在我看來已經開始逐漸影響到了傳統的sql的地位,可是僅僅是影響而已,取代是不太可能的。javascript

 

 


 

正文:

兩年前,一個偶然的機會開始接觸到 nosql ( mongodb )。用來做數據挖掘的存儲容器,第一次接觸到nosql,真的被它驚豔到了。鄙人受到傳統的SQL的思惟定勢,甚至一時間難以接受。java

mongodb是一個非關係型文檔數據庫,很是適合文檔類型的數據的存儲,查詢也十分方便,支持動態的橫向和縱向的數據擴展。愛不釋手。下個用幾行shell來展現一下mongodb的魅力mysql

 

 

show dbs;

//無則會建立
use mydb;


show collections;


//新建集合,至關於mysql中的表
db.createCollection('mycollection');

//插入數據.
db.mycollection.insert({'username':'chenqimiao','age':23})

db.mycollection.insert({'username':'cqm','age':23,'sex':'男'})

//查詢
db.mycollection.find({"age":23});

 

 

類比mysql的話,最大的區別可能在於表結構或者說集合結構的定義了,mysql的列是預約義的,而mongodb是在插入數據的時候才肯定這條數據的列。redis

 

因此mongodb能夠支持動態擴展列,在mongo中可能不叫列,要叫做域(field)吧。算法

 

 


 

 

後來花了一點時間瞭解了一下 HBase , Habase   誕生於 Hadoop的子項目,受大數據的遺傳。單表能夠很是的大,一樣Habase也是基於列的。sql

 

 

印象中HBase 中有一個很是特別的特性,HBase 的數據覆蓋,並非實際的覆蓋。HBase 有一個時間維度的概念,全部的數據都是基於這個維度進行存儲的,mongodb

簡單點說,一樣的key  可能在HBase 中存在兩個value。它是怎麼作到的?由於它給每一條記錄都偷偷記錄了一個timestamp,每次你去覆蓋鍵值對的時候,你覺得你已經刪除了舊值,替換成了新shell

值,而實際上只是再添加了一條記錄而已,兩條記錄共存在一個時間維度上。每次get(key)默認取最新的一個value,僅此而已。數據庫

 

你還能夠手動設置失效時間TTL,這樣每個值就會有一個有效期,過了有效期都值是不能get出來了,可是值仍是存儲在HBase中並未丟失。緩存

 

 

 

 


 

 

 

再後來接觸到了 redis ,相信你們對這個都至關的熟悉,基於內存的緩存數據庫,簡單的set()  get()就能夠了緩存一些常用到的值,以前我也專門介紹過 redis的安裝,shell命令,多實例部署,讀寫分離,主從複製,哨兵 等等問題。

 

 

 

當數據超過必定量 , redis會把數據swap到文件中去,若是使用到swap中的文件的值,redis會把文件在swap到內存中,進行讀寫,十分智能。支持的數據類型也比較多 ,除了k-v 還有hset ,hash  ,zset等等

 

 

 

 

 


 

 

 

最近在作在線課堂,用到了 Memcache ,這個東西基本和redis的使用場景類似,基於內存的nosql。可是支持的數據類型只有k-v的形式。這是不一樣於redis的一點。

其二的話, Memcache 不支持文件持久化。

其三, memcache 的多實例,是基於客戶端的,這個比較有意思要好好聊一聊了,象咱們日常接觸的mysql,redis,多實例同步基本是讀寫分離,主從複製,主機寫,從機讀,這樣的模式。能夠說是基於服務端的多實例方案。可是 memcache 有點好玩了,它的多實例之間不進行同步,那它是怎麼作到負載均衡的時候保證數據的完整性呢?

 

說到這裏,我想先介紹一下memcache的主流的客戶端程序(JAVA)

  • 官方提供的基於傳統阻塞io由Greg Whalin維護的客戶端  

     較早推出的客戶端,穩定,持久運行。

 

  • Dustin Sallings實現的基於java nio的Spymemcached  

    A simple, asynchronous, single-threaded memcached client written in java. 支持異步,單線程的memcached客戶端,用到了java1.5版本的concurrent和nio,存取速度會高於前者,可是穩定性很差,測試中常 報timeOut等相關異常。   

  • XMemcache

           Memcached一樣是基於java nio的客戶端,java nio相比於傳統阻塞io模型來講,有效率高(特別在高併發下)和資源耗費相對較少的優勢。傳統阻塞IO爲了提升效率,須要建立必定數量的鏈接造成鏈接 池,而nio僅須要一個鏈接便可(固然,nio也是能夠作池化處理),相對來講減小了線程建立和切換的開銷,這一點在高併發下特別明顯。所以 XMemcached與Spymemcached在性能都很是優秀,在某些方面(存儲的數據比較小的狀況下)Xmemcached比 Spymemcached的表現更爲優秀,具體能夠看這個Java Memcached Clients Benchmark。 

 

 

根據上面的介紹,大概能夠了解到,官方提供的是阻塞的客戶端,要利用線程池來實現併發,可是官方提供的包還有一個很是致命的問題,不提供 CAS 的同步功能。

什麼是 CAS ?

瞭解過java下面的 java.util.concurrent.atomic; 下面的類的同窗應該知道, CAS (check and swap),這是一種樂觀鎖的實現,程序陷入一個循環,獲得舊值,執行CAS方法,傳入舊值,新值,若舊值未發生變化 ,則用舊值,換出新值。

while(true){
    
     Object oldValue = atomicObject.get("key1") ;

     Object newValue = new Object();
  
     Object value  =   checkAndSwap("key1",oldValue,newValue) ;


     if(value!=null&&oldValue.equals(value))  

           break;
     
}

 

 

解釋完 CAS ,回到剛纔的問題,爲何沒有實現 CAS ,是官方包一個致命的弱點,明白了 CAS 原理的同窗,應該發現其實它就是一個同步的手段,那爲何不能使用 syncronized 的。那是由於數據併發發生在不一樣項目裏面,沒有辦法給多個項目以前共用一個 syncronized 。這個時候只能利用memcache提供的鎖,利用 CAS 做爲同步手段。

慶幸spyMemcache和xmemcache都提供了 CAS 的操做。

 

那麼問題來了,剛剛最先提出的問題如何解答?( CAS 多實例同步問題。)其實啊memcache根本不須要進行多實例同步,它的多實例是依賴於客戶端程序實現的。

好比spymemcache:

 para.memcache.server=192.168.202.121:11211,192.168.202.121:11210 配置兩個server便可。其他的操做和操做一個memcache是一摸同樣的,客戶端會根據Hash散列算法( HashMap 的實現算法)將鍵值對放到對應的 memcache 中,因爲算法一致性,因此存取雙方都能得知鍵值在哪個 memcache 中。這樣就實現了多實例了。

 

 另外spymemcache客戶端還有一個比較厲害的地方,它能直接將java對象序列化,做爲k-v中的v,get(k)的時候自動反序列化成對象,無需直接操做JSONObject,固然前提是對象實現

 Serializable 接口,並給定一個 serialVersionUID 。redis也能夠直接存儲二進制文件,可是官方提供的客戶端程序,並無封裝好序列化和反序列化,須要本身實現。


 

 

說了這麼多nosql,好像傳統sql無用武之地通常。其實傳統的sql纔是最穩定的,適用面積最廣,最安全,而且提供了事務回滾,保證數據一致性,這是nosql爲了提升速度,加強擴展性,所要面臨的一部分捨棄。

相關文章
相關標籤/搜索