大数据NoSQL技术之Couchbase Server数据库详解
一.什么是Couchbase Server
大數(shù)據(jù)的NoSQL技術(shù)已發(fā)展成熟,這以MongoDB為代表,但我這里要介紹的是另一種NoSQL技術(shù),叫做Couchbase Server,?近年來在國外發(fā)展迅猛,大有超過MongoDB之勢。Couchbase Server是由早先的CouchDB發(fā)展而來,?繼承了Memcached的技術(shù)特性,?是一個開源的、分布式的、面向文檔(document-oriented)的NoSQL?數(shù)據(jù)庫,?具有許多優(yōu)越核心功能:
二.Couchbase Server 3.02與MongoDB 3.0的對比
據(jù)新動力咨詢公司做的一項
針對Couchbase Server 3.02與MongoDB 3.0的性能測試報告,在相同硬件的類似集群配置(因兩者拓撲架構(gòu)不同,不能做到相同)下,Couchbase在下列4個方面超過MongoDB:
1.并發(fā)Couchbase展示了較好的并發(fā)性,能比MongoDB處理三倍多的并發(fā)用戶
2.吞吐量Couchbase展示了較高的吞吐量,甚至在相同數(shù)量的并發(fā)用戶下,Couchbase Server比MongoDB能提供2.5倍的吞吐量
3.?延遲Couchbase展示了較低的延遲。即使在相同數(shù)量的并發(fā)用戶下,Couchbase能夠提供比MongoDB低4-5倍的延遲
4.?性價比在相同硬件并滿足相同延遲值的要求下,Couchbase Server比mongodb能夠提供2.5倍甚至4.5倍的吞吐量。這樣,Couchbase Server的操作費用將只有
MongoDB的22-44%。
如今許多互聯(lián)網(wǎng)巨頭都遷移到
Couchbase Server上了,如paypal、linkedin、ebay、GE等。
三.如何安裝
下面以windows系統(tǒng)為例:
一 首先,到官網(wǎng)下載安裝包:http://www.couchbase.com/nosql-databases/downloads,?可根據(jù)你的的硬件操作系統(tǒng)選擇所要的安裝包, 這里為方便起見選擇了64位的企業(yè)windows版couchbase-server-enterprise_4.1.0-windows_amd64.exe, 安裝系統(tǒng)最小需要內(nèi)存為 4G,處理
器最小為 4 核處理器; 同時從此網(wǎng)站上再下載一個Java版的應(yīng)用程序包Couchbase-Java-Client-2.2.5.zip, 以便后面開發(fā)應(yīng)用項目之用。
然后點擊這個exe文件開始安裝, 選擇安裝的路徑, 確認安裝所需的最小內(nèi)存大小和處理器個數(shù)完成安裝。
二.?配置
完成安裝之后,直接就會
進入一個管理界面進行配
置。另外,在桌面上,安裝程序默認就會生成一個快捷方式。點擊設(shè)置按鈕,?進入5個設(shè)置步驟:
1.?配置服務(wù)器
設(shè)置磁盤存儲路徑,服務(wù)器主機,是否生成一個新
集群還是加入已有一個集群中。
2.?安裝示例數(shù)據(jù)
安裝系統(tǒng)提供兩個樣品數(shù)據(jù)桶bucket (下面將詳細介紹)?和MapReduce,?可選擇安不安裝
3.?創(chuàng)建默認的
桶(bucket)
設(shè)置桶類型(Couchbase或Memcached)?、每個節(jié)點使用的內(nèi)存大小、備份
、磁盤讀寫同步工作個數(shù)以及沖洗Flush。
4.?通知設(shè)置是否希望收到升級的提示以及產(chǎn)品登記。
5.?配置
服務(wù)器
設(shè)置管理員的口令,?注意帳號名和密碼要區(qū)分大小寫
6.?配置完成之后,進入
監(jiān)控web頁面console。以后可以點擊桌面快捷圖標打開,在此監(jiān)控頁面上就可以看到
服務(wù)器的使用情況并可查看和編輯
數(shù)據(jù)。整個console共有8個Tab頁面:
集群概況
、服務(wù)器節(jié)點
、數(shù)據(jù)桶(bucket)、視圖、索引、跨數(shù)據(jù)中心備份、日志和設(shè)置。
a"集群概況(Cluster Overview)
當(dāng)前時間段上桶的操作
圖和磁盤讀取圖以及服務(wù)器當(dāng)前活動狀況,?見上圖
b:服務(wù)器節(jié)點(Server Nodes)
包括節(jié)點名稱
、活動狀態(tài)、何種服務(wù)、內(nèi)存
使用
、交換使用、CPU
使用、磁盤使用、數(shù)據(jù)項數(shù)(
活躍/備份)?。還可進行添加
服務(wù)器、除去
服務(wù)器、分組服務(wù)器、更換服務(wù)器等操作
c:數(shù)據(jù)桶(Data Buckets)
(bucket)?是一種新概念,?相當(dāng)于關(guān)系型數(shù)據(jù)庫中的Schema,?即
數(shù)據(jù)存儲區(qū)間
。每一個bucket都包含活躍和備份的數(shù)據(jù)集,?并映射到1024個邏輯分區(qū)(Virtual Bucket,?簡稱vBucket),文檔的讀取寫入等操作只與分區(qū)vBuckets打交互。相同的文檔ID,每次都被哈希到相同的分區(qū),?分區(qū)vBucket可以在節(jié)點之間移動(rebalance), vBucket和物理服務(wù)器之間的對應(yīng)關(guān)系被存儲在cluster map中。
在此Tab上, 不僅可以監(jiān)控各個
數(shù)據(jù)桶的使用狀況, 還可創(chuàng)建新的數(shù)據(jù)桶, 建立新文檔, 查看、修改和刪除已有文檔
d:視圖(Views)
視圖是一種可視化的表, 在Couchbase中以兩種格式(設(shè)計和生產(chǎn))文檔存儲在
數(shù)據(jù)桶中, 每張視圖由一名字和一組MapReduce函數(shù)表示。
其必須Map
函數(shù)
描述了怎樣從數(shù)據(jù)桶中提取數(shù)據(jù), 而可選Reduce函數(shù)描述了怎樣聚合其結(jié)果。
在此Tab中, 可以查看視
圖數(shù)據(jù)并可進行過濾排序等操作, 還可創(chuàng)建、刪除和編輯設(shè)計視圖的Java文檔, 并發(fā)布為生產(chǎn)視圖
e:Index(索引)
Couchbase提供有三種用于不同服務(wù)的索引:
·MapReduce
視圖
索引,是線性增加的,?只當(dāng)文檔有變化時才重新索引;
·立體視圖索引, Couchbase使用立體視圖來查詢
地理空間
信息,?一個立體視圖含有地理空間數(shù)據(jù),?基于所記錄的數(shù)據(jù)是否在一給定的多維范圍內(nèi)來
查詢所要信息。他們也用于非幾何多維范圍內(nèi)的查詢,?不像MapReduce視圖
有兩個
函數(shù)map和reduce ,?立體視圖只有一個函數(shù)spatial,?類似于前者函數(shù)map。
全局第二索引(GSI),?使得應(yīng)用以高速度進行快速查詢和
數(shù)據(jù)掃描,?不像視圖索引,?其索引值僅局部每個節(jié)點,?全局第二索引是建立在整個集群上的
f:XDCR(跨數(shù)據(jù)中心備份)
XDCR提供了一種把
數(shù)據(jù)從一個
集群備份到另一個
集群的便利方式,?可把活躍數(shù)據(jù)拷貝到N+1個Couchbase服務(wù)器集群或外部應(yīng)用(如Elastic, Spark, Storm等),?這些集群常用于多個地理分散的災(zāi)難恢復(fù)或為快速傳輸而接近實際用戶,?這種備份可設(shè)為雙向或多向。
在此Tab頁面上,?可以方便創(chuàng)建多個運種
集群,?設(shè)置備份參數(shù)。
g:日志(Log)
Tab記錄了事件
、模塊代碼、服務(wù)器節(jié)點和時間的日志,?可用于診斷Couchbase集群內(nèi)的活動和錯誤。
h:設(shè)置(Setting)
設(shè)置Tab頁面用于設(shè)置你的Couchbase服務(wù)器全局參數(shù),?包括集群配置
、更新通知、自動修復(fù)、報警、自動壓縮、帳號管理、審計和樣品數(shù)據(jù)桶。
三.?開發(fā)實例
當(dāng)安裝并設(shè)置好Couchbase
服務(wù)器
集群(只一臺服務(wù)器也構(gòu)成一個集群)后,?就可以進行應(yīng)用開發(fā)了。將前面下載的Couchbase-Java-Client-2.2.5.zip解壓,?將其中的三個jar包: couchbase-core-io-1.2.5.jar、couchbase-java-client-2.2.5.jar、rxjava-1.0.15.jar加入你所用的IDE庫中。
首先,?你需要做的是連接
集群:
Cluster cluster = CouchbaseCluster.create();
當(dāng)不帶參數(shù)時,?則此連接邏輯上與localhost相連的
集群綁定,?這種做法在開發(fā)
環(huán)境下是可以的,?但在生產(chǎn)環(huán)境下需要指定服務(wù)器節(jié)點,?如下所示:
Cluster cluster = CouchbaseCluster.create("192.168.56.101","192.168.56.102");你不必把集群中每個節(jié)點都列上, 只需幾個種子節(jié)點以便客戶可以建立
起初始連接, 實際連接是當(dāng)調(diào)用openBucket方法時才建立起與數(shù)據(jù)桶的真正連接:
Bucket bucket?=cluster.openBucket();這只是連接缺省的數(shù)據(jù)桶, 并返回Bucket引用。如果你想連接一個不同的數(shù)據(jù)桶, 你需通過console界面預(yù)先創(chuàng)建好一個數(shù)據(jù)桶才可連接, 代碼如下:
Bucket bucket = cluster.openBucket("bucket","password");當(dāng)應(yīng)用關(guān)閉時, 你必須斷開與集群的連接以確保釋放所有資源(如sockets, threads, 等), 下面代碼關(guān)閉客戶:cluster.disconnect();這斷開所有數(shù)據(jù)桶并釋放全部資源。現(xiàn)在有了Bucket引用, 就可以操作JSON文檔了。首先, 生成一個用戶的JsonObject:
JsonObjectuser = JsonObject.empty()
.put("firstname", "Walter")
.put("lastname", "White")
.put("job", "chemistry teacher")
.put("age", 50);
JsonObject的作用非常類似Map, 但被設(shè)計僅用于插入值, 以便存為有效的JSON(包括嵌套對象和數(shù)組), 所生成的結(jié)果文檔類似如下:
{
"firstname":"Walter",
"job":"chemistry teacher",
"age":50,
"lastname":"White"
}
為存儲文檔, 需調(diào)用bucket的upsert方法。由于服務(wù)器上的文檔具有多種特性, 需要給他賦予一個唯一文檔ID, 如walter:
JsonDocument doc = JsonDocument.create("walter", user);
JsonDocument response =
bucket.upsert(doc);
這個Document將自動轉(zhuǎn)換為JSON并存入集群中, 如果這個文檔ID已經(jīng)存在它將被替換。Bucket提供了諸多如插入(insert)、獲取(get) 、刪除(remove) 、關(guān)閉(close)等方法, 為調(diào)用方便, 我把他們寫在一個稱為ConnectionManager類里:package com.couchbase.beersample;import java.util.ArrayList;import java.util.NoSuchElementException;import java.util.concurrent.CountDownLatch;import rx.Observable;import rx.Subscriber;import rx.functions.Action1;import rx.functions.Func1;import com.couchbase.client.java.*;import com.couchbase.client.java.document.JsonDocument;import com.couchbase.client.java.view.AsyncViewResult;import com.couchbase.client.java.view.AsyncViewRow;import com.couchbase.client.java.view.Stale;import com.couchbase.client.java.view.ViewQuery;/** * The ConnectionManager handles connecting, disconnecting and managing of the * Couchbase connection. */public class ConnectionManager { //生成一個靜態(tài)instance private static final ConnectionManager connectionManager = new ConnectionManager(); public static ConnectionManager getInstance() { return connectionManager; }//生成一個靜態(tài)集群 static Cluster cluster = CouchbaseCluster.create(); //打開一個數(shù)據(jù)桶, 這里為beer-sample, 安裝時自動生成的 static Bucket bucket = cluster.openBucket("beer-sample"); //關(guān)閉集群 public static void disconnect() { cluster.disconnect(); } //得到視圖的行集合列表, 這里使用異步獲取方式 public static ArrayList<AsyncViewRow> getView(String designDoc, String view) { final ArrayList<AsyncViewRow> result = new ArrayList<AsyncViewRow>(); final CountDownLatch latch = new CountDownLatch(1); bucket.async().query( ViewQuery.from(designDoc, view).limit(20).stale(Stale.FALSE)) .doOnNext(new Action1<AsyncViewResult>() { @Override public void call(AsyncViewResult viewResult) { if (!viewResult.success()) { System.out.println(viewResult.error()); } } }).flatMap(new Func1<AsyncViewResult, Observable<AsyncViewRow>>() { @Override public Observable<AsyncViewRow> call(AsyncViewResult viewResult) { return viewResult.rows(); } }).subscribe(new Subscriber<AsyncViewRow>() { @Override public void onCompleted() { latch.countDown(); } @Override public void (Throwable throwable) { System.err.println("Whoops: " + throwable.getMessage()); } @Override public void onNext(AsyncViewRow viewRow) { result.add(viewRow); } }); try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } return result; }//獲取一個Json文檔 public static JsonDocument getItem(String id) { JsonDocument response = null; try { response = bucket.get(id); } catch (NoSuchElementException e) { System.out.println("ERROR: No element with message: " + e.getMessage()); e.printStackTrace(); } return response; } //刪除一個Json文檔 public static void deleteItem(String id) { try { bucket.remove(id, PersistTo.MASTER); } catch (NoSuchElementException e){ System.out.println("ERROR: No element with message: " + e.getMessage()); } } //更新一個Json文檔 public static void updateItem(JsonDocument doc) { bucket.upsert(doc); } //關(guān)閉數(shù)據(jù)桶的連接 public static void closeBucket() { bucket.close(); }}為演示目的, 這里舉一個把啤酒beer信息存儲到Couchbase里的應(yīng)用例子, 先要建立一個BeerModel類:package com.couchbase.beersample;public class BeerModel{ private String name, style, deion, category, abv, srm, ibu, upc, brewery, Id = ""; public String getName(){ return name; } public void setName(String name){ this.name = name; } public String getStyle(){ return style; } public void setStyle(String style){ this.style = style; } public String getDeion() { return deion; } public void setDeion(String deion) { this.deion = deion; } public String getCategory() { return category; } public void setCategory(String category) { this.category = category; } public String getAbv() { return abv; } public void setAbv(String abv) { this.abv = abv; } public String getSrm() { return srm; } public void setSrm(String srm) { this.srm = srm; } public String getIbu() { return ibu; } public void setIbu(String ibu) { this.ibu = ibu; } public String getUpc() { return upc; } public void setUpc(String upc) { this.upc = upc; } public String getBrewery() { return brewery; } public void setBrewery(String brewery) { this.brewery = brewery; } public String getId(){ return Id; } public void setId(String id) { this.Id = id; }}再建造一個Main類, 在main函數(shù)里進行測試,package com.couchbase.beersample;import com.couchbase.client.java.document.JsonDocument;import com.couchbase.client.java.document.json.JsonObject;import com.couchbase.client.java.view.AsyncViewRow;import java.util.ArrayList;import rx.functions.Action1;import rx.functions.Func1;/** * * @author Xijian */public class Main { public static void main(String[] args) { BeerModel beerModel = new BeerModel(); beerModel.setId("2"); beerModel.setName("beer2"); beerModel.setStyle("beer2 style"); beerModel.setDeion("beer2 Deion"); beerModel.setAbv("beer2 abv"); beerModel.setIbu("beer2 ibu"); beerModel.setSrm("beer2 srm"); beerModel.setUpc("beer2 upc"); beerModel.setBrewery("beer2 Brewery id"); JsonObject beer = JsonObject.empty() .put("name", beerModel.getName()) .put("style", beerModel.getStyle()) .put("deion", beerModel.getDeion()) .put("abv", beerModel.getAbv()) .put("ibu", beerModel.getIbu()) .put("srm", beerModel.getSrm()) .put("upc", beerModel.getUpc()) .put("brewery", beerModel.getBrewery()) .put("type", "beer"); JsonDocument doc = JsonDocument.create(beerModel.getId(), beer); ConnectionManager.updateItem(doc); beerModel = new BeerModel(); beerModel.setId("3"); beerModel.setName("beer3"); beerModel.setStyle("beer3 style"); beerModel.setDeion("beer3 Deion"); beerModel.setAbv("beer3 abv"); beerModel.setIbu("beer3 ibu"); beerModel.setSrm("beer3 srm"); beerModel.setUpc("beer3 upc"); beerModel.setBrewery("beer3 Brewery id"); beer = JsonObject.empty() .put("name", beerModel.getName()) .put("style", beerModel.getStyle()) .put("deion", beerModel.getDeion()) .put("abv", beerModel.getAbv()) .put("ibu", beerModel.getIbu()) .put("srm", beerModel.getSrm()) .put("upc", beerModel.getUpc()) .put("brewery", beerModel.getBrewery()) .put("type", "beer"); doc = JsonDocument.create(beerModel.getId(), beer); ConnectionManager.updateItem(doc); ArrayList<AsyncViewRow> result = ConnectionManager.getView("beer", "by_name"); System.out.println("size: " + result.size()); doc = ConnectionManager.getItem("2"); System.out.println("name: " + doc.content().getString("name")); }}運行Main類, 將得到如下結(jié)果: size: 2 name: beer2其次, 打開管理員console頁面, 進入Views Tab中, 在頂上一行的>Views>之前的下拉單里選取beer-sample, 然后點擊按鈕Create Development View, 在彈出的窗口中, Design Document Name: 框下填入name,View Name:框下填入by_name, 再點擊Save按鈕存入, 此時View Code的分區(qū)展開, 有兩個窗口, 左邊為Map窗, 內(nèi)含缺省函數(shù), function (doc, meta) { emit(meta.id, null); }右邊為Reduce窗, 缺省為空。修改Map函數(shù)為 function (doc, meta) { if(doc.type && doc.type == "beer") { emit(doc.name, doc.brewery_id + ", " + doc.style); } }Reduce窗不變, 點擊Save按鈕存入。再點擊下面的Show Results則顯示如下視圖結(jié)果:
你還可以過濾這些結(jié)果(需點擊Filter Results箭頭icon), 確定這些結(jié)果正確之后就可以把其發(fā)布到生產(chǎn)環(huán)境上去, 這可通過點Publish按鈕完成。
總結(jié)
以上是生活随笔為你收集整理的大数据NoSQL技术之Couchbase Server数据库详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GTID的常见错误和处理方法
- 下一篇: MySQL 复制夯住排查以及原理探讨