RavenDB 3.0 新特性:索引后端
RavenDB 索引絕對不是簡單的對 key/value 進行存儲, 其功能要強大的多. 就像3.0版本的其他特性一樣, 是汗水與智慧的結晶。本文我主要介紹索引在后端都有哪些變動, 使它變得更快, 更穩定, 性能更好。 至于那些用戶能看得到的新特性, 會在下一篇文章中提到。
內存中的索引. 歷史一次又一次地證明, 只有從硬盤著手, 我們才能跟系統優化工具說再見。 為了提高創建新索引的數據讀寫速度, 2.5版本中開始引入只在內存中創建新索引的新概念. 而在3.0中, 這一功能得到了進一步完善. 索引數據由原來的頻繁地對硬盤讀寫, 改為存進內存緩沖區. 只有在一些特殊情況下(如:內存不足等), 才會將索引數據寫入硬盤.
通過這種方式, 可以大量減少讀寫索引數據的時間, 以及維護和優化硬盤的時間. 擺脫這些束縛, 即使在高負荷的情況下, 也能保持極好的性能. 而在日常使用中, 負荷的偶爾波動也不會導致硬盤出現問題.
異步刪除索引. RavenDB 中的索引包含兩部分, 實際數據跟元數據. 一般情況下, 元數據的要比實際數據少. 但是對于 map/reduce 索引來說, 情況剛好相反, 因為它的元數據包含了許多中間步驟相關的數據. 如果你在大規模數據庫中使用LoadDocument, 我們還需要維護文檔的引用,這需要大量的存儲空間. 結果導致在 RavenDB 2.5 中刪除索引的過程變得極其緩慢.
到了 RavenDB 3.0, 隨著異步刪除索引的出現, 你可迅速刪除索引. 表面上看, 索引被刪除了, 其實刪掉的是索引名稱, 其他清理工作則留給后臺異步處理. 別擔心如果你需要中途重啟數據庫, 那么在數據庫啟動后, 那些未完成的清理工作仍然會在后臺繼續. 這種異步刪除方式使維護和刪除包含大量數據的索引變得相當簡便.
用 id 代替名稱. 為了打破索引跟名稱之間1:1的關聯, 我們在內部結構中使用數值型的 id 代表索引. 這種做法給我們帶來不少壓力, 因為我們必須把舊的索引(old index Users/Search: 正在被刪除的索引) 跟新的索引(new Users/Search index: 正在創建中的索引)區分開來.
好的一面是, 我們使用的內部結構通常都能高效的處理索引操作. 讀寫操作和壓縮磁盤使用空間的速度得到了很大的提高.
索引跟任務交替執行. 任務這個詞對于 RavenDB來說, 基本上指清理索引數據. 如: 清理那些已經被刪除的索引記錄, 或者是對已經發生改變的引用文檔重新索引. 在 2.5 版本中, 這些任務會排成長隊, 在隊列表中等待執行, 導致許多索引任務沒有及時執行. 例如:每天都有一大堆刪除索引的任務在隊列中排隊等待, 每執行一個這樣的任務又很耗時間. 在 3.0 中, 我們做了些調整, 索引跟任務的執行交替進行, 不管隊列排的多滿, 都不會對索引帶來太大影響.
大文檔索引. RavenDB 對文檔大小沒有限制, 這對用戶來說是好事, 但是如果 RavenDB 要對這些文檔索引, 那就亞歷山大了. 假如我們要對一大堆文檔進行索引. 那么我們會加大每一批索引的數量. 隨著系統跟文檔變得越來越大, 問題就開始出現了. 許多文檔在索引更新后會變得變原來的文件要大的多. 比方說, 每一批處理 128K 個文檔, 每個文檔 250Kb, 那就意味著每一批要索引 31GB 的文檔.
這么大的數據要從磁盤讀出來, 需要一定的時間, 這還不包括對內存的讀寫時間.而用戶通常都會對大數據件壓縮處理. 這會導致問題變得更加嚴重. 因為 RavenDB只會讀取文檔在磁盤上的文件大小, 也就是壓縮以后的文件大小. 結果可想而知. 在 3.0 中, 對這個問題采我們采取了一些預防措施. 首先是計算在內容中的文檔大小,同時也能更好的限制每次批量操作內存的數量。
被I/O限制的批量索引. RavenDB的一個核心方案是在云服務器上運行. 但實際上, 我們的客戶所用的服務器各式各樣. 從i2.8xlarge EC2 (32 核, 244GB 內存, 8 x 800 GB SSD 硬盤) 到 A0 Azure (共享的 CPU, 768 MB 內存, 硬盤無力吐槽, 淚奔) 都有. 由于我們實際只使用了服務器上1/4左右的可用資源. 客戶老是抱怨為什么沒有把剩下的資源也用上. 問題是他們用來計算可用資源的算法跟 RavenDB 的不一樣, 性能方面沒什么可抱怨的, 就把火發在 RavenDB 沒有“有效”利用資源上.
看起來很搞笑, 其實不然. 低端的云服務器速度慢, 性能差. 尤其是I/O 的傳輸速率相當慢. 如果你在這樣一臺服務器上給一個已經在使用中的數據庫創建索引, 你會發現大部分的時間都是用來等I/O操作. 久而久之, 這個問題就會越來越嚴重. RavenDB一開始會從硬盤讀取少量數據進行批量索引(比如花個半秒鐘從硬盤上讀出數據). 然后下一批, 再下一批, 就這樣一批接一批的處理. 當 RavenDB 發現要處理的數據太多了, 它就會增加每一批處理的數量. 結果導致等待數據從硬盤讀出來的時間變得越來越久. 在網管看來, RavenDB 基本上就是卡死在那, 什么都沒做.
在 RavenDB 3.0 中, 我們不再糾結I/O的速度問題. 先從硬盤讀取一部分數據, 如果在一段合理的時間段內依然無法讀取足夠的數據, 那我們會先將已讀到的數據索引, 與此同時把讀取數據的任務放到后臺繼續執行. 等到索引執行完后, 又可以對后臺讀取出來的那部分數據進行索引. 這樣做可以很大程度上提高性能. (客戶能看到索引跟讀寫操作在同事進行, 不會埋怨我們的軟件無所事事)
總結 – 基本上這幾個新特性都是在后臺運行, 用戶在前臺是看不到變化的. 但是他們能協調合作, 給大家帶來更好的用戶體驗.
本文地址:http://www.oschina.net/translate/what-new-ravendb-30-indexing
原文地址:http://java.dzone.com/articles/what-new-ravendb-30-indexing