緩存係列文章–無底洞問題
一、背景
1. 什麼是緩存無底洞問題:
2. 緩存無底洞產生的原因:
鍵值數據庫或者緩存係統,由於通常采用hash函數將key映射到對應的實例,造成key的分布與業務無關,但是由於數據量、訪問量的需求,需要使用分布式後(無論是客戶端一致性哈性、redis-cluster、codis),批量操作比如批量獲取多個key(例如redis的mget操作),通常需要從不同實例獲取key值,相比於單機批量操作隻涉及到一次網絡操作,分布式批量操作會涉及到多次網絡io。
3. 無底洞問題帶來的危害:
(1) 客戶端一次批量操作會涉及多次網絡操作,也就意味著批量操作會隨著實例的增多,耗時會不斷增大。
(2) 服務端網絡連接次數變多,對實例的性能也有一定影響。
4. 結論:
用一句通俗的話總結:更多的機器不代表更多的性能,所謂“無底洞”就是說投入越多不一定產出越多。
分布式又是不可以避免的,因為我們的網站訪問量和數據量越來越大,一個實例根本坑不住,所以如何高效的在分布式緩存和存儲批量獲取數據是一個難點。
二、哈希存儲與順序存儲
在分布式存儲產品中,哈希存儲與順序存儲是兩種重要的數據存儲和分布方式,這兩種方式不同也直接決定了批量獲取數據的不同,所以這裏需要對這兩種數據的分布式方式進行簡要說明:
1. hash分布:
hash分布應用於大部分key-value係統中,例如memcache, redis-cluster, twemproxy,即使像mysql在分庫分表時候,也經常會用user%100這樣的方式。
hash分布的主要作用是將key均勻的分布到各個機器,所以它的一個特點就是數據分散度較高,實現方式通常是hash(key)得到的整數再和分布式節點的某台機器做映射,以redis-cluster為例子:
問題:和業務沒什麼關係,不支持範圍查詢。
2. 順序分布
3. 兩種分布方式的比較:
分布方式 | 特點 | 典型產品 |
哈希分布 | 1. 數據分散度高2.鍵值分布與業務無關3.無法順序訪問
4.支持批量操作 |
一致性哈希memcacheredisCluster其他緩存產品 |
順序分布 | 1.數據分散度易傾斜2.鍵值分布與業務相關3.可以順序訪問
4.支持批量操作 |
BigTableHbase |
三、分布式緩存/存儲四種Mget解決方案
1. IO的優化思路:
(1) 命令本身的效率:例如sql優化,命令優化
(2) 網絡次數:減少通信次數
(3) 降低接入成本:長連/連接池,NIO等。
(4) IO訪問合並:O(n)到O(1)過程:批量接口(mget),
2. 如果隻考慮減少網絡次數的話,mget會有如下模型:
3. 四種解決方案:
(1).串行mget
將Mget操作(n個key)拆分為逐次執行N次get操作, 很明顯這種操作時間複雜度較高,它的操作時間=n次網絡時間+n次命令時間,網絡次數是n,很顯然這種方案不是最優的,但是足夠簡單。
(2). 串行IO
將Mget操作(n個key),利用已知的hash函數算出key對應的節點,這樣就可以得到一個這樣的關係:Map<node, somekeys>,也就是每個節點對應的一些keys
它的操作時間=node次網絡時間+n次命令時間,網絡次數是node的個數,很明顯這種方案比第一種要好很多,但是如果節點數足夠多,還是有一定的性能問題。
(3). 並行IO
此方案是將方案(2)中的最後一步,改為多線程執行,網絡次數雖然還是nodes.size(),但網絡時間變為o(1),但是這種方案會增加編程的複雜度。
它的操作時間=1次網絡時間+n次命令時間
(4). hash-tag實現。
第二節提到過,由於hash函數會造成key隨機分配到各個節點,那麼有沒有一種方法能夠強製一些key到指定節點到指定的節點呢?
redis提供了這樣的功能,叫做hash-tag。什麼意思呢?假如我們現在使用的是redis-cluster(10個redis節點組成),我們現在有1000個k-v,那麼按照hash函數(crc16)規則,這1000個key會被打散到10個節點上,那麼時間複雜度還是上述(1)~(3)
那麼我們能不能像使用單機redis一樣,一次IO將所有的key取出來呢?hash-tag提供了這樣的功能,如果將上述的key改為如下,也就是用大括號括起來相同的內容,那麼這些key就會到指定的一個節點上。
例如:
user1,user2,user3......user1000 {user}1,{user}2,{user}3.......{user}1000
例如下圖:它的操作時間=1次網絡時間+n次命令時間
3. 四種批量操作解決方案對比:
方案 | 優點 | 缺點 | 網絡IO |
串行mget | 1.編程簡單2.少量keys,性能滿足要求 | 大量keys請求延遲嚴重 | o(keys) |
串行IO | 1.編程簡單2.少量節點,性能滿足要求 | 大量node延遲嚴重 | o(nodes) |
並行IO | 1.利用並行特性2.延遲取決於最慢的節點 | 1.編程複雜2.超時定位較難 | o(max_slow(node)) |
hash tags | 性能最高 | 1.tag-key業務維護成本較高2.tag分布容易出現數據傾斜 | o(1) |
四、總結和建議
無底洞問題對資源和性能有一定影響,但是其實大部分係統不需要考慮這個問題,因為
1. 99%公司的數據和流量無法和facebook相比。
2. redis/memcache的分布式集群通常來講是按照項目組做隔離的,以我們經驗來看一般不會超過50對主從。
所以這裏隻是提供了一種優化的思路,開闊一下視野。
五、參考文獻
- Facebook’s Memcached Multiget Hole: More machines != More Capacity
- Multiget的無底洞問題
- 再說memcache的multiget hole(無底洞)
一、背景
1. 什麼是緩存無底洞問題:
2. 緩存無底洞產生的原因:
鍵值數據庫或者緩存係統,由於通常采用hash函數將key映射到對應的實例,造成key的分布與業務無關,但是由於數據量、訪問量的需求,需要使用分布式後(無論是客戶端一致性哈性、redis-cluster、codis),批量操作比如批量獲取多個key(例如redis的mget操作),通常需要從不同實例獲取key值,相比於單機批量操作隻涉及到一次網絡操作,分布式批量操作會涉及到多次網絡io。
3. 無底洞問題帶來的危害:
(1) 客戶端一次批量操作會涉及多次網絡操作,也就意味著批量操作會隨著實例的增多,耗時會不斷增大。
(2) 服務端網絡連接次數變多,對實例的性能也有一定影響。
4. 結論:
用一句通俗的話總結:更多的機器不代表更多的性能,所謂“無底洞”就是說投入越多不一定產出越多。
分布式又是不可以避免的,因為我們的網站訪問量和數據量越來越大,一個實例根本坑不住,所以如何高效的在分布式緩存和存儲批量獲取數據是一個難點。
二、哈希存儲與順序存儲
在分布式存儲產品中,哈希存儲與順序存儲是兩種重要的數據存儲和分布方式,這兩種方式不同也直接決定了批量獲取數據的不同,所以這裏需要對這兩種數據的分布式方式進行簡要說明:
1. hash分布:
hash分布應用於大部分key-value係統中,例如memcache, redis-cluster, twemproxy,即使像mysql在分庫分表時候,也經常會用user%100這樣的方式。
hash分布的主要作用是將key均勻的分布到各個機器,所以它的一個特點就是數據分散度較高,實現方式通常是hash(key)得到的整數再和分布式節點的某台機器做映射,以redis-cluster為例子:
問題:和業務沒什麼關係,不支持範圍查詢。
2. 順序分布
3. 兩種分布方式的比較:
分布方式 | 特點 | 典型產品 |
哈希分布 | 1. 數據分散度高2.鍵值分布與業務無關3.無法順序訪問
4.支持批量操作 |
一致性哈希memcacheredisCluster其他緩存產品 |
順序分布 | 1.數據分散度易傾斜2.鍵值分布與業務相關3.可以順序訪問
4.支持批量操作 |
BigTableHbase |
三、分布式緩存/存儲四種Mget解決方案
1. IO的優化思路:
(1) 命令本身的效率:例如sql優化,命令優化
(2) 網絡次數:減少通信次數
(3) 降低接入成本:長連/連接池,NIO等。
(4) IO訪問合並:O(n)到O(1)過程:批量接口(mget),
2. 如果隻考慮減少網絡次數的話,mget會有如下模型:
3. 四種解決方案:
(1).串行mget
將Mget操作(n個key)拆分為逐次執行N次get操作, 很明顯這種操作時間複雜度較高,它的操作時間=n次網絡時間+n次命令時間,網絡次數是n,很顯然這種方案不是最優的,但是足夠簡單。
(2). 串行IO
將Mget操作(n個key),利用已知的hash函數算出key對應的節點,這樣就可以得到一個這樣的關係:Map<node, somekeys>,也就是每個節點對應的一些keys
它的操作時間=node次網絡時間+n次命令時間,網絡次數是node的個數,很明顯這種方案比第一種要好很多,但是如果節點數足夠多,還是有一定的性能問題。
(3). 並行IO
此方案是將方案(2)中的最後一步,改為多線程執行,網絡次數雖然還是nodes.size(),但網絡時間變為o(1),但是這種方案會增加編程的複雜度。
它的操作時間=1次網絡時間+n次命令時間
(4). hash-tag實現。
第二節提到過,由於hash函數會造成key隨機分配到各個節點,那麼有沒有一種方法能夠強製一些key到指定節點到指定的節點呢?
redis提供了這樣的功能,叫做hash-tag。什麼意思呢?假如我們現在使用的是redis-cluster(10個redis節點組成),我們現在有1000個k-v,那麼按照hash函數(crc16)規則,這1000個key會被打散到10個節點上,那麼時間複雜度還是上述(1)~(3)
那麼我們能不能像使用單機redis一樣,一次IO將所有的key取出來呢?hash-tag提供了這樣的功能,如果將上述的key改為如下,也就是用大括號括起來相同的內容,那麼這些key就會到指定的一個節點上。
例如:
user1,user2,user3......user1000 {user}1,{user}2,{user}3.......{user}1000
例如下圖:它的操作時間=1次網絡時間+n次命令時間
3. 四種批量操作解決方案對比:
方案 | 優點 | 缺點 | 網絡IO |
串行mget | 1.編程簡單2.少量keys,性能滿足要求 | 大量keys請求延遲嚴重 | o(keys) |
串行IO | 1.編程簡單2.少量節點,性能滿足要求 | 大量node延遲嚴重 | o(nodes) |
並行IO | 1.利用並行特性2.延遲取決於最慢的節點 | 1.編程複雜2.超時定位較難 | o(max_slow(node)) |
hash tags | 性能最高 | 1.tag-key業務維護成本較高2.tag分布容易出現數據傾斜 | o(1) |
四、總結和建議
無底洞問題對資源和性能有一定影響,但是其實大部分係統不需要考慮這個問題,因為
1. 99%公司的數據和流量無法和facebook相比。
2. redis/memcache的分布式集群通常來講是按照項目組做隔離的,以我們經驗來看一般不會超過50對主從。
所以這裏隻是提供了一種優化的思路,開闊一下視野。
五、參考文獻
- Facebook’s Memcached Multiget Hole: More machines != More Capacity
- Multiget的無底洞問題
- 再說memcache的multiget hole(無底洞)
一、背景
1. 什麼是緩存無底洞問題:
2. 緩存無底洞產生的原因:
鍵值數據庫或者緩存係統,由於通常采用hash函數將key映射到對應的實例,造成key的分布與業務無關,但是由於數據量、訪問量的需求,需要使用分布式後(無論是客戶端一致性哈性、redis-cluster、codis),批量操作比如批量獲取多個key(例如redis的mget操作),通常需要從不同實例獲取key值,相比於單機批量操作隻涉及到一次網絡操作,分布式批量操作會涉及到多次網絡io。
3. 無底洞問題帶來的危害:
(1) 客戶端一次批量操作會涉及多次網絡操作,也就意味著批量操作會隨著實例的增多,耗時會不斷增大。
(2) 服務端網絡連接次數變多,對實例的性能也有一定影響。
4. 結論:
用一句通俗的話總結:更多的機器不代表更多的性能,所謂“無底洞”就是說投入越多不一定產出越多。
分布式又是不可以避免的,因為我們的網站訪問量和數據量越來越大,一個實例根本坑不住,所以如何高效的在分布式緩存和存儲批量獲取數據是一個難點。
二、哈希存儲與順序存儲
在分布式存儲產品中,哈希存儲與順序存儲是兩種重要的數據存儲和分布方式,這兩種方式不同也直接決定了批量獲取數據的不同,所以這裏需要對這兩種數據的分布式方式進行簡要說明:
1. hash分布:
hash分布應用於大部分key-value係統中,例如memcache, redis-cluster, twemproxy,即使像mysql在分庫分表時候,也經常會用user%100這樣的方式。
hash分布的主要作用是將key均勻的分布到各個機器,所以它的一個特點就是數據分散度較高,實現方式通常是hash(key)得到的整數再和分布式節點的某台機器做映射,以redis-cluster為例子:
問題:和業務沒什麼關係,不支持範圍查詢。
2. 順序分布
3. 兩種分布方式的比較:
分布方式 | 特點 | 典型產品 |
哈希分布 | 1. 數據分散度高2.鍵值分布與業務無關3.無法順序訪問
4.支持批量操作 |
一致性哈希memcacheredisCluster其他緩存產品 |
順序分布 | 1.數據分散度易傾斜2.鍵值分布與業務相關3.可以順序訪問
4.支持批量操作 |
BigTableHbase |
三、分布式緩存/存儲四種Mget解決方案
1. IO的優化思路:
(1) 命令本身的效率:例如sql優化,命令優化
(2) 網絡次數:減少通信次數
(3) 降低接入成本:長連/連接池,NIO等。
(4) IO訪問合並:O(n)到O(1)過程:批量接口(mget),
2. 如果隻考慮減少網絡次數的話,mget會有如下模型:
3. 四種解決方案:
(1).串行mget
將Mget操作(n個key)拆分為逐次執行N次get操作, 很明顯這種操作時間複雜度較高,它的操作時間=n次網絡時間+n次命令時間,網絡次數是n,很顯然這種方案不是最優的,但是足夠簡單。
(2). 串行IO
將Mget操作(n個key),利用已知的hash函數算出key對應的節點,這樣就可以得到一個這樣的關係:Map<node, somekeys>,也就是每個節點對應的一些keys
它的操作時間=node次網絡時間+n次命令時間,網絡次數是node的個數,很明顯這種方案比第一種要好很多,但是如果節點數足夠多,還是有一定的性能問題。
(3). 並行IO
此方案是將方案(2)中的最後一步,改為多線程執行,網絡次數雖然還是nodes.size(),但網絡時間變為o(1),但是這種方案會增加編程的複雜度。
它的操作時間=1次網絡時間+n次命令時間
(4). hash-tag實現。
第二節提到過,由於hash函數會造成key隨機分配到各個節點,那麼有沒有一種方法能夠強製一些key到指定節點到指定的節點呢?
redis提供了這樣的功能,叫做hash-tag。什麼意思呢?假如我們現在使用的是redis-cluster(10個redis節點組成),我們現在有1000個k-v,那麼按照hash函數(crc16)規則,這1000個key會被打散到10個節點上,那麼時間複雜度還是上述(1)~(3)
那麼我們能不能像使用單機redis一樣,一次IO將所有的key取出來呢?hash-tag提供了這樣的功能,如果將上述的key改為如下,也就是用大括號括起來相同的內容,那麼這些key就會到指定的一個節點上。
例如:
user1,user2,user3......user1000 {user}1,{user}2,{user}3.......{user}1000
例如下圖:它的操作時間=1次網絡時間+n次命令時間
3. 四種批量操作解決方案對比:
方案 | 優點 | 缺點 | 網絡IO |
串行mget | 1.編程簡單2.少量keys,性能滿足要求 | 大量keys請求延遲嚴重 | o(keys) |
串行IO | 1.編程簡單2.少量節點,性能滿足要求 | 大量node延遲嚴重 | o(nodes) |
並行IO | 1.利用並行特性2.延遲取決於最慢的節點 | 1.編程複雜2.超時定位較難 | o(max_slow(node)) |
hash tags | 性能最高 | 1.tag-key業務維護成本較高2.tag分布容易出現數據傾斜 | o(1) |
四、總結和建議
無底洞問題對資源和性能有一定影響,但是其實大部分係統不需要考慮這個問題,因為
1. 99%公司的數據和流量無法和facebook相比。
2. redis/memcache的分布式集群通常來講是按照項目組做隔離的,以我們經驗來看一般不會超過50對主從。
所以這裏隻是提供了一種優化的思路,開闊一下視野。
五、參考文獻
- Facebook’s Memcached Multiget Hole: More machines != More Capacity
- Multiget的無底洞問題
- 再說memcache的multiget hole(無底洞)
最後更新:2017-05-19 17:33:56
上一篇:
Apache Velocity開發者指南–導讀
下一篇:
《Redis官方教程》-Redis安全
ibatis調用Oracle中的存儲過程和function
網絡編程中Nagle算法和Delayed ACK的測試
使用HttpURLConnection下載文件時出現 java.io.FileNotFoundException徹底解決辦法
是電商,還是“電傷”
物聯網的大趨勢下,智慧醫療成熱點
文本分析40年政府工作報告 發現了這些關鍵詞
android 狀態欄(StatusBar)
華棲雲與阿裏雲首推“雲上電視台”,可實現內容雲端一站式製作
智慧醫療大數據應用實現個人化精準醫療
HTAP數據庫 PostgreSQL 場景與性能測試之 31 - (OLTP) 高吞吐數據進出(堆存、行掃、無需索引) - 閱後即焚(讀寫大吞吐並測)