Redis 的性能幻想與殘酷現實


2011 年,當初選擇 Redis 作為主要的內存數據存儲,主要吸引我的是它提供多樣的基礎數據結構可以很方便的實現業務需求。另一方面又比較擔心它的性能是否足以支撐,畢竟當時 Redis 還屬於比較新的開源產品。但 Redis 官網宣稱其是提供多數據結構的高性能存儲,我們對其還是抱有幻想的。

幻想

要了解 Redis 的性能,我們先看看官方的基准性能測試數據,心里有個底。

測試前提
Redis version 2.4.2
Using the TCP loopback
Payload size = 256 bytes  
測試結果
SET: 198412.69/s
GET: 198019.80/s

這個數據剛一看覺得有點超出預期了,不過看了測試前提是規避了網絡開銷的,Client 和 Server 全在本機。而真實的使用場景肯定是需要走網絡的,而且使用的客戶端庫也是不同的。不過這個官方參考數據當時讓我們對 Redis 的性能還是抱有很大的期待的。

另外官方文檔中也提到,在局域網環境下只要傳輸的包不超過一個 MTU (以太網下大約 1500 bytes),那么對於 10、100、1000 bytes 不同包大小的處理吞吐能力實際結果差不多。關於吞吐量與數據大小的關系可見下面官方網站提供的示意圖。

驗證

基於我們真實的使用場景,我們搭建了性能驗證環境,作了一個驗證測試,如下(數據來自同事 @kusix 當年的測試報告,感謝)。

測試前提
Redis version 2.4.1
Jmeter version 2.4
Network 1000Mb
Payload size = 100 bytes  
測試結果
SET: 32643.4/s
GET: 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 常見的性能問題和解決方法.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM