標籤:
2011 年,當初選擇 Redis 作為主要的記憶體資料存放區,主要吸引我的是它提供多樣的基礎資料結構可以很方便的實現業務需求。另一方面又比較擔心它的效能是否足以支撐,畢竟當時 Redis 還屬於比較新的開源產品。但 Redis 官網宣稱其是提供多資料結構的高效能儲存,我們對其還是抱有幻想的。
幻想
要瞭解 Redis 的效能,我們先看看官方的基準效能測試資料,心裡有個底。
測試前提Redis version 2.4.2Using the TCP loopbackPayload size = 256 bytes 測試結果SET: 198412.69/sGET: 198019.80/s
這個資料剛一看覺得有點超出預期了,不過看了測試前提是規避了網路開銷的,Client 和 Server 全在本機。而真實的使用情境肯定是需要走網路的,而且使用的用戶端庫也是不同的。不過這個官方參考資料當時讓我們對 Redis 的效能還是抱有很大的期待的。
另外官方文檔中也提到,在區域網路環境下只要傳輸的包不超過一個 MTU (乙太網路下大約 1500 bytes),那麼對於 10、100、1000 bytes 不同包大小的處理吞吐能力實際結果差不多。關於輸送量與資料大小的關係可見下面官方網站提供的。
驗證
基於我們真實的使用情境,我們搭建了效能驗證環境,作了一個驗證測試,如下(資料來自同事 @kusix 當年的測試報告,感謝)。
測試前提Redis version 2.4.1Jmeter version 2.4Network 1000MbPayload size = 100 bytes 測試結果SET: 32643.4/sGET: 32478.8/s
在實驗環境下得到的測試資料給人的感覺和官方差了蠻多,這裡面因為有網路和用戶端庫綜合的影響所以沒有實際的橫向比較意義。這個實驗環境實測資料只對我們真實的生產環境具有指導參考作用。在實驗環境的測試,單 Redis 執行個體運行穩定,單核 CPU 利用率在 70% ~ 80% 之間波動。除了測試 100 bytes 的包,還測了 1k、10k 和 100k 不同大小的包,如所示:
誠然,1k 基本是 Redis 效能的一個拐點,這一點從看趨勢是和官方圖的一致。
現實
基於實驗室測試資料和實際業務量,現實中採用了 Redis 分區來承擔更大的輸送量。一個單一 Redis 分區一天的 ops 波動在 20k~30k 之間,單核 CPU 利用率在 40% ~ 80% 之間波動,如。
這與當初實驗室環境的測試結果接近,而目前生產環境使用的 Redis 版本已升級到 2.8 了。如果業務量峰值繼續增高,看起來單個 Redis 分區還有大約 20% 的餘量就到單一實例極限了。那麼可行的辦法就是繼續增加分區的數量來分攤單個分區的壓力,前提是能夠很容易的增加分區而不影響業務系統。這才是使用 Redis 面臨的真正殘酷現實考驗。
殘酷
Redis 是個好東西,提供了很多好用的功能,而且大部分實現的都還既可靠又高效(主從複製除外)。所以一開始我們犯了一個天真的用法錯誤:把所有不同類型的資料都放在了一組 Redis 叢集中。
- 長生命週期的使用者狀態資料
- 臨時快取資料
- 後台統計用的流水資料
導致的問題就是當你想擴分區的時候,用戶端 Hash 映射就變了,這是要遷移資料的。而所有資料放在一組 Redis 裡,要把它們分開就麻煩了,每個 Redis 執行個體裡面都是千萬級的 key。
而另外一個問題是單個 Redis 的效能上限帶來的瓶頸問題。由於 CPU 的單核頻率都發展到了瓶頸,都在往多核發展,一個 PC Server 一般 24或32 核。但 Redis 的單線程設計機制只能利用一個核,導致單核 CPU 的最大處理能力就是 Redis 單一實例處理能力的天花板了。
舉個具體的案例,新功能上線又有點不放心,於是做了個開關放在 Redis,所有應用可以很方便的共用。通過讀取 Redis 中的開關 key 來判斷是否啟用某個功能,對每個請求做判斷。這裡的問題是什嗎?這個 key 只能放在一個執行個體上,而所有的流量進入都要去這個 Redis GET 一下,導致該分區執行個體壓力山大。而它的極限在我們的環境上不過 4 萬 OPS,這個天花板其實並不高。
總結
認識清楚了現實的殘酷性,瞭解了你所在環境 Redis 的真實效能指標,區分清幻想和現實。我們才能真正考慮好如何合理的利用 Redis 的多功能特性,並有效規避的它的弱項,再給出一些 Redis 的使用建議:
-根據資料性質把 Redis 叢集分類;我的經驗是分三類:cache、buffer 和 db
- cache:臨時快取資料,加分區擴容容易,一般無持久化需要。
- buffer:用作緩衝區,平滑後端資料庫的寫操作,根據資料重要性可能有持久化需求。
- db:替代資料庫的用法,有持久化需求。
- 規避在單一實例上放熱點 key。
- 同一系統下的不同子應用或服務使用的 Redis 也要隔離開
另外,有一種觀點認為用作緩衝 Memcache 更合適,這裡可以獨立分析下其中的優劣取捨吧。Memcache 是設計為多線程的,所以在多核機器上單一實例對 CPU 的利用更有效,所以它的效能天花板也更高。(見)要達到同樣的效果,對於一個 32 核機器,你可能需要部署 32 個 Redis 執行個體,對營運也是一種負擔。
除此,Redis 還有個 10k 問題,當快取資料大於 10k(用作靜態頁面的緩衝,就可能超過這個大小)延遲會明顯增加,這也是單線程機制帶來的問題。如果你的應用業務量離 Redis 的效能天花板還比較遠而且也沒有 10k 需求,那麼用 Redis 作緩衝也是合理的,可以讓應用減少多依賴一種外部技術棧。最後,搞清楚現階段你的應用到底需要什麼,是多樣的資料結構和功能、更好的擴充能力還是更敏感的效能需求,然後再來選擇合適的工具吧。別只看到個基準測試的效能資料,就歡呼雀躍起來了。
額外扯點其他的,Redis 的作者 @antirez 對自己的產品和技術那是相當自信。一有人批評 Redis 的問題,他都是要跳出來在自己的 blog 裡加以回應和說明的。比如有人說 Redis 功能多容易使用但也容易誤用,作者就跑出來解釋我設計是針對每種不同情境的,你用的不對怪我咯,怪我咯。有人說緩衝情境 Memcache 比 Redis 更合適,作者也專門寫了篇文章來說明,大概就是 Memcache 有的 Redis 都有,它沒有的我還有。當然最後也承認多線程是沒有的,但正在思考為 Redis I/O 增加線程,每個 Client 一個線程獨立處理,就像 Memcache 一樣,已經等不及要去開發與測試了,封住所以批評者的嘴。
Redis 這些年不斷的增加新功能和最佳化改進,讓它變得更靈活情境適應性更多的同時,也讓我們在使用時需要更細緻的思考,不是它有什麼我就用什麼,而是你需要什麼你就選擇什麼。
這篇先到這,後面還會再寫寫關於 Redis 擴充方面的主題。
參考
[1] antirez. Redis Documentation.
[2] antirez. Clarifications about Redis and Memcached.
[3] antirez. Lazy Redis is better Redis.
[4] antirez. On Redis, Memcached, Speed, Benchmarks and The Toilet.
[5] antirez. An update on the Memcached/Redis benchmark.
[6] dormando. Redis VS Memcached (slightly better bench).
[7] Mike Perham. Storing Data with Redis.
[8] 溫柔一刀. Redis 常見的效能問題和解決方案.
http://www.cnblogs.com/mindwind/p/5067905.html
Redis 的效能幻想與殘酷現實(轉)