key-value緩存和存儲系統通常用於互聯網產品的開發中,作爲後端磁盤存儲系統的緩存,或記錄和處理龐大的用戶日誌。Redis是一個高性能的key-value存儲系統,可以存儲多種數據類型,如string, hash, list, set, bitmap, hyperloglog等。Redis的數據緩存在內存中,極大地提高了數據庫的讀寫效率。
表1爲Redis一些基本操作的時間複雜度,可以看出,Redis操作效率會隨着數據集的增加而明顯降低。因此,當數據集較爲龐大時,需要從單位操作時間和內存利用率方面對數據庫進行優化。下面介紹一種運用y-Fast tries優化Redis整數集操作的方法。
表1 Redis數據操作的時間複雜度
Operation |
Redis |
Insert |
O(n) |
Search |
O(logn) |
Remove |
O(n) |
數據結構介紹:
1. x-Fast Tires
x-Fast Tires(圖1)是一個用於存儲整數的線索二叉樹,線索二叉樹具有快速查找前驅和後繼節點的特點。在該數據結構中,有效數值均存儲在葉子節點中,葉子節點由一個雙向鏈表連接。樹中每一層的節點單獨存儲於一個hash表中,樹的空間複雜度爲O(nlog(U)).
圖1 x-Fast Tries結構示意圖(From Stanford PPT)
x-Fast Tries的深度爲log(U),由於每層的節點都存儲在hash表中,因而判斷一個節點是否處於某一層中只需O(1)的時間。爲了尋找到這個節點,可以在樹上跨層做二分查找,因爲樹的深度爲log(U),所以查找的時間複雜度爲O(loglog(U))。依此,可以分析出x-FastTries節點操作的時間複雜度:
表2 x-Fast Tires時間複雜度
Operation |
Time |
Operation |
Time |
insert(x) |
O(log(U)) |
is-empty() |
O(1) |
search(x) |
O(1) |
remove(x) |
O(log(U)) |
succ(x) |
O(loglog(U)) |
prev(x) |
O(loglog(U)) |
max() |
O(1) |
min() |
O(1) |
由上表可以看出,insert和remove操作的效率還比較低,因此引入了y-Fast Tries.
2. y-Fast Tries
Y-Fast Tries是Willard, DanE提出的一種tries,由x-Fast Tires和平衡二叉搜索樹節點集組合而成(圖2)。它有一個突出的特點,即能夠在loglog(U)時間內完成數據庫的多種操作(表3),U爲整數空間的size. 當U=2^64時,loglog(U)=6,這意味着在一個64位機上,Y-Fast tries可以在6步之內完成所有操作。並且,該數據結構可以在空間複雜度爲O(n)情況下完成所有操作。
圖2 y-Fast Tries結構示意圖 (From wikipedia)
表3 y-Fast Tires時間複雜度
Operation |
Time |
Operation |
Time |
insert(x) |
O(loglog(U)) |
is-empty() |
O(1) |
search(x) |
O(loglog(U)) |
remove(x) |
O(loglog(U)) |
succ(x) |
O(loglog(U)) |
prev(x) |
O(loglog(U)) |
max() |
O(1) |
min() |
O(1) |
假設每個搜索二叉樹有O(log(U))個元素,樹中所有定義在有序字典上的操作均可在O(loglog(U))完成。應用時,要確保每個搜索二叉樹的節點數在1/2 log(U)~ 2 log(U)之間,當小於這個數值時,合併鄰居節點,大於時,則產生分裂。y-Fast Tires的設計直覺是先利用x-Fast Tries定位子樹,然後在子樹上的進一步數據操作可以保證在O(loglog(U))時間內完成。
在空間複雜度上,每個搜索二叉樹有O(log(U))個元素,x-Fast Tries中有O(n/log(U))個元素,因此總的空間複雜度爲O(n/log(U)·log(U))= O(n).
優化結果:
1. 測試平臺
CPU: 16 x Intel(R) Xeon(R) CPU E5-2670 0 @2.60GHz
Memory: 140GB
Kernel: Linux-3.14.3
2. 測試結果
在原始Redis和y-Fast Tries優化後的數據庫中,整數集單次操作耗時如下圖,
操作耗時爲採用log尺度統計,可以看出,Y-Fast Tries優化後的操作效率明顯高於原始Redis的效率,在remove操作中效果最爲顯著。
Redis:
Y-Fast Tries: