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)
較早推出的客戶端,穩定,持久運行。
A simple, asynchronous, single-threaded memcached client written in java. 支持異步,單線程的memcached客戶端,用到了java1.5版本的concurrent和nio,存取速度會高於前者,可是穩定性很差,測試中常 報timeOut等相關異常。
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爲了提升速度,加強擴展性,所要面臨的一部分捨棄。