couchDB小全
前段時間研究過一陣子,留下點記錄吧。
簡介
couchDB是這兩年很受geek追捧的數據庫,作者曾是lotus開發人員。與傳統的關系型數據庫不同,它號稱自己是文檔數據庫。所謂文檔數據庫,并不是說它只能存儲文本,事實上因為它是一種schemal-less的概念。用過關系型數據庫的同學都知道,數據表里定義的每一個字段都定義為一種類型:無論是int,char,datetime。但couchDB的字段只有三個:文檔ID、文檔版本號和內容。
內容字段可以看到是一個text類型的文本,里面可以隨意定義數據,而不用關注數據類型,但數據必須以json的形式表示并存放。例如一個表述用戶的文檔可以表示為:[_id:1001,_rev:1-32443289, {'name':'wentrue','location':'beijing'}]。couchDB的底層是erlang語言,以RESTfulAPI的格式提供服務,couchDB所有的讀寫能力都可以通過簡單的調用它的HTTP請求來實現。正因為采用那么一種統一且簡潔的服務接口,可以很方便地開發各種語言的客戶端,以方便不同程序員的使用。
couchDB的文檔不多,基本上主體都在它網站的overview和wiki了。這里按照我的理解組織一遍,不敢冒”大全“之名,借”小全“一用尚可。以下以幾個關鍵詞為標簽簡要敘述。
優點:
couchDB的主要特點在于易用性及并發性。后者我的認識主要是來自erlang,因為erlang是以易并行實現而著稱的,我自己并沒有測試過。但對于易用性我是有著深刻體會。只要一搭好服務,你不但擁有了一個聽任你調遣的數據服務端,還擁有一個簡潔webserver,如果你是在本地部署的,在瀏覽器上訪問http://localhost:5984/_utils/,你就可以看到一個管理與查詢的后臺,在那個后臺,你基本能實現用其它客戶端能實現的所有事情。也就是說,即便你不懂編程語言,你可以在這個管理平臺自由發揮,當然如果你懂一些javascript,那你就可以把couchDB玩轉了。
這個易用性意味著什么?讓我們作個假設,你是一個網站開發人員,你有大量的數據需要存儲,但你又不想跟復雜的后臺邏輯打交道,或許你還不想過多地進行后臺維護,那么用couchDB,你可以直接用js調用數據,然后結合html+css把數據展現出來,再通過js把數據寫回去,這就實現了一個簡單的內容發布系統,沒有任何后臺架構。實際上已經有很多用couchDB實現的網站。
技術概述:
couchDB的底層是一個B-tree的存儲結構,為提高效率,所有的數據的插入或更新都是直接在樹的葉子節點添加,不刪除舊節點,通過版本號來確定最新的數據--版本號還能用來解決并發寫的沖突。所以數據文件會越來越大,可以在適當地時間運行compact過程或replication過程,會刪除舊文件,使得數據文件得到壓縮。
與mysql的對比(是什么原因促使我把眼光暫時離開mysql):
1、couchDB的屬性可以靈活增刪,要增加一個新屬性只需要往數據字段多寫入一個屬性即可。mysql在數據量大了之后,再增刪字段會比較耗費時間,在線操作更是讓人難以忍受的(視數據量大小有可能要鎖表幾十分鐘到一天);
2、文檔間屬性的不一致,如有些記錄可能有A屬性而有一些沒有,用mysql則只能把沒有該屬性的用戶的值置為0或空,影響存儲與查詢;
3、查詢效率,經常會需要對某個字段進行查詢,得到某個滿足條件的子集,用mysql要對每個字段的查詢都達到高效只能采用對該字段建索引的辦法,使得索引文件變大,如果新增字段又要新建索引,建立索引也是一個鎖表又冗長的過程。couchDB應用map-reduce的方法使得計算量可以分散(注意:跟google的那個不太一樣,這里的map-reduce實際上還是在一臺機器完成,且沒有發現多個進程,沒有看到線程個數的配置,這是我感到最難解的,難道還是單線程流水處理的?),雖然也是像沒有建索引的mysql一樣需要掃全表,但可以對常用的一些查詢建立永久索引,索引是隨數據的增長增量更新的,減少查詢時間。
當然,強大的mysql也有類似的解決方案,且看friendfeed的schema-less mysql方案。
數據格式:
couchDB以json格式存儲數據,返回的數據也默認為json格式,這對于前端的javascript處理是非常方便的。然而如果你用其它的語言,比如python,獲取回來的數據量很大,用simplejson包去把這個龐大的json字符串解釋為dict,這就有點費時間了。解決方法之一是升級你的simplejson到最新版本,這樣速度可以提升幾倍,或者你用cjson,這樣格式轉換的時間就基本可以忽略不計。但cjson的接口與處理跟simplejson有點不太一樣,如果你用couchdb-python作為客戶端,需要對客戶端代碼作修改。另一個方法是要求服務端直接返回list格式的數據,然后直接在python解釋,避過了json解釋一關,速度應該保證。list格式請求的API可以看這里。
緩存:
應該是有緩存的,因為同樣的查詢,第二次再查時會比第一次快不少,在couchDB的數據目錄也能看到查詢生成的臨時文件。不過我估計主要的數據還是在硬盤,因為couchDB服務占內存不多,數據不太可能都在里面,而且依據第二次查詢的速度來看,不像是直接從內存取出來的,倒像是從硬盤現成拿數據的速度。
更新機制(如何保持數據一致性):
上面說到couchDB每個文檔有三個字段,其中_rev代表該文檔的版本號,數據每更新一次,文檔的版本號也會更新一次。這個版本號對于保持數據一致性有很重大的作用。上面談到couchDB把所有的屬性忽略schema都統一放在一個字段里,那么當有兩個程序同時修改這個字段時,就有可能造成先寫入的數據被后寫入的數據覆蓋的現象,導致數據不一致。
couchDB利用版本號來解決這個問題,當有程序需要修改一條數據時,它必須先把這個數據的版本號讀出來,寫入的時候,連版本號一并寫入,此時couchDB會檢查該版本號是否與原數據的一致,如果一致則寫入,如果不一致,則說明數據在該程序讀出后已經被修改過,couchDB會寫入不成功,返回一個沖突的信號,待客戶端程序處理。
分布式:
現在couchDB(<1.0)并沒有內置分布式處理機制。所以,官網中提倡的分布式并保持數據一致性的解決方法是:你設置一個寫的couchDB服務,然后把這份數據用replication過程同步拷貝到其它的機器,作為讀服務。這樣的分布式聽起來有點傻,但確實就是如此。所以,信息的一致性其實是難以保證的,也即是說,你剛在網站上發布了一個信息,刷新之后可能并不會馬上就能看到它。不知道將來couchDB的開發者會不會就這方面進行努力,至少現在看到的計劃是還沒有包含更多的分布式支持。
穩定性:
在網上的介紹中,穩定性是作為它的一個feature來介紹的,但我在gentoo上直接用portage裝的couchDB0.9服務一周之內莫名其妙地消失了三次,且在日志里沒有留下任何蜘絲馬跡。所以我對此持保留態度。
python客戶端:
因為提供了簡易的RESTful接口,為couchDB寫各種語言的客戶端可就容易多了,這里列出了大量的客戶端。python客戶端主要有couchdb-python和couchdbkit,我試驗中主要是使用了前者,使用中的問題是json的解釋效率。如果使用python自帶的simplejson或json(>2.5)模塊來解釋,碰上一個大的字符串或dict,你就只能痛苦地等待了。我最初就是以為couchDB極慢,誰想其實是json解釋占了大部分的時間。要解決這個問題,可以裝cjson,很快,但需要對couchdb-python的源代碼作改動;另一個選擇是升級simplejson到最新版,速度會有極大的提升。
couchDB要做什么(它的能與不能):
即使解決了json解釋的問題,純粹歸究到couchDB的問題時,你可不能對它的大數據量讀寫抱有太大的信心,畢竟它設計的初衷是前臺的并發應用,并不是要讓你一次讀出或更新幾百萬條數據。我的試驗結果是,讀200W的數據(每條記錄并不大),第一次查詢大概幾分鐘,第二次一分鐘左右,更新200W條記錄,你需要等待大于20分鐘。
所以,目前為止,如果你要作后臺批量讀寫,并且不能忍受這個速率,它可不是一個最好的選擇。同時在你更新數據的過程中,數據文件的體積會逐漸變大,因為數據都是追加到文件末尾的,舊數據并沒有刪除,所以用couchDB必須預備較大的硬盤空間,并且要定時運行compact或replication過程,通過壓縮或拷貝來清除舊數據。
前景:
這兩年couchDB備受追捧,社區非常活躍,通常社區的活躍程度是影響一個開源軟件成敗的關鍵因素。couchDB吸引人的關鍵之處當然在于它提出了一些對web數據存儲與索引的很好的方案,如果把關系型數據庫看作是一批有固定格式的電子表格的集合,那么文檔型數據庫就是一批各色各樣的文檔的集合。相對于關系型數據庫而言,文檔數據庫顯然更適合用于多樣而靈活的web數據。而couchDB的簡易入門,體系的簡單化,又很符合geeks追求簡潔的夠用的想法。couchDB的宣傳中說它“like a pornstar”也是挺傳神的。所以我比較看好他的發展,看到1.0穩定版會是個什么樣子吧,這注定是一個跟web聯系緊密的數據庫。
我個人比較企盼它能在分布式處理方面有更多的改進,還有就是服務的配置、查詢的效率,都是有待提高的。至于大數據量的處理,我不太難期待,因為看來它應該是個網站前臺的產品,而不太適合用于后臺的分析。
參考文檔
1、couchDB官方網站:http://couchdb.apache.org/
2、couchDB wiki:http://wiki.apache.org/couchdb/
3、couchDB上手指南:http://erlang-china.org/study/couchdb-guide.html
轉載請保留本文原始鏈接:http://www.wentrue.net/blog/?p=255