2011 年,當初選擇 Redis 做爲主要的內存數據存儲,主要吸引個人是它提供多樣的基礎數據結構能夠很方便的實現業務需求。另外一方面又比較擔憂它的性能是否足以支撐,畢竟當時 Redis 還屬於比較新的開源產品。但 Redis 官網宣稱其是提供多數據結構的高性能存儲,咱們對其仍是抱有幻想的。html
要了解 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),那麼對於 十、100、1000 bytes 不一樣包大小的處理吞吐能力實際結果差很少。關於吞吐量與數據大小的關係可見下面官方網站提供的示意圖。segmentfault
基於咱們真實的使用場景,咱們搭建了性能驗證環境,做了一個驗證測試,以下(數據來自同事 @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 常見的性能問題和解決方法.
寫點程序世間的文字,畫點生活瞬間的畫兒。
微信公衆號「瞬息之間」,碰見了不妨就關注看看。