國內外三個不同領域巨頭分享的Redis實戰經驗及使用場景
隨著應用對高效能需求的增加,NoSQL逐漸在各大名企的系統架構中生根發芽。這裡我們將為大家分享社交巨頭新浪微博、傳媒巨頭Viacom及圖片分享領域佼佼者Pinterest帶來的Redis實踐,首先我們看新浪微博 @啟盼cobain的Redis實戰經驗分享:
新浪微博:史上最大的Redis叢集
Tape is Dead,Disk is Tape,Flash is Disk,RAM Locality is King. — Jim Gray
Redis不是比較成熟的memcache或者Mysql的替代品,是對於大型網際網路類應用在架構上很好的補充。現在有越來越多的應用也在紛紛基於Redis做架構的改造。首先簡單公佈一下Redis平臺實際情況:
- 2200+億 commands/day 5000億Read/day 500億Write/day
- 18TB+ Memory
- 500+ Servers in 6 IDC 2000+instances
應該是國內外比較大的Redis使用平臺,今天主要從應用角度談談Redis服務平臺。
Redis使用場景
1.Counting(計數)
可以預見的是,有很多同學認為把計數全部存在記憶體中成本非常高,我在這裡用個圖表來表達下我的觀點:
很多情況大家都會設想純使用記憶體的方案會很有很高成本,但實際情況往往會有一些不一樣:
- COST,對於有一定吞吐需求的應用來說,肯定會單獨申請DB、Cache資源,很多擔心DB寫入效能的同學還會主動將DB更新記入非同步佇列,而這三塊的資源的利用率一般都不會太高。資源算下來,你驚異的發現:反而純記憶體的方案會更精簡!
- KISS原則,這對於開發是非常友好的,我只需要建立一套連線池,不用擔心資料一致性的維護,不用維護非同步佇列。
- Cache穿透風險,如果後端使用DB,肯定不會提供很高的吞吐能力,cache宕機如果沒有妥善處理,那就悲劇了。
- 大多數的起始儲存需求,容量較小。
2.Reverse cache(反向cache)
面對微博常常出現的熱點,如最近出現了較為火爆的短鏈,短時間有數以萬計的人點選、跳轉,而這裡會常常湧現一些需求,比如我們向快速在跳轉時判定使用者等級,是否有一些賬號繫結,性別愛好什麼的,已給其展示不同的內容或者資訊。
普通採用memcache+Mysql的解決方案,當呼叫id合法的情況下,可支撐較大的吞吐。但當呼叫id不可控,有較多垃圾使用者呼叫時,由於memcache未有命中,會大量的穿透至Mysql伺服器,瞬間造成連線數瘋長,整體吞吐量降低,響應時間變慢。
這裡我們可以用redis記錄全量的使用者判定資訊,如string key:uid int:type,做一次反向的cache,當用戶在redis快速獲取自己等級等資訊後,再去Mc+Mysql層去獲取全量資訊。如圖:
當然這也不是最優化的場景,如用Redis做bloomfilter,可能更加省用記憶體。
3.Top 10 list
產品運營總會讓你展示最近、最熱、點選率最高、活躍度最高等等條件的top list。很多更新較頻繁的列表如果使用MC+MySQL維護的話快取失效的可能性會比較大,鑑於佔用記憶體較小的情況,使用Redis做儲存也是相當不錯的。
4.Last Index
使用者最近訪問記錄也是redis list的很好應用場景,lpush lpop自動過期老的登陸記錄,對於開發來說還是非常友好的。
5.Relation List/Message Queue
這裡把兩個功能放在最後,因為這兩個功能在現實問題當中遇到了一些困難,但在一定階段也確實解決了我們很多的問題,故在這裡只做說明。
Message Queue就是通過list的lpop及lpush介面進行佇列的寫入和消費,由於本身效能較好也能解決大部分問題。
6.Fast transaction with Lua
Redis 的Lua的功能擴充套件實際給Redis帶來了更多的應用場景,你可以編寫若干command組合作為一個小型的非阻塞事務或者更新邏輯,如:在收到message推送時,同時1.給自己的增加一個未讀的對話 2.給自己的私信增加一個未讀訊息 3.最後給傳送人回執一個完成推送訊息,這一層邏輯完全可以在Redis Server端實現。
但是,需要注意的是Redis會將lua script的全部內容記錄在aof和傳送給slave,這也將是對磁碟,網絡卡一個不小的開銷。
7.Instead of Memcache
- 很多測試和應用均已證明,
- 在效能方面Redis並沒有落後memcache多少,而單執行緒的模型給Redis反而帶來了很強的擴充套件性。
- 在很多場景下,Redis對同一份資料的記憶體開銷是小於memcache的slab分配的。
- Redis提供的資料同步功能,其實是對cache的一個強有力功能擴充套件。
Redis使用的重要點
1.rdb/aof Backup!
我們線上的Redis 95%以上是承擔後端儲存功能的,我們不僅用作cache,而更為一種k-v儲存,他完全替代了後端的儲存服務(MySQL),故其資料是非常重要的,如果出現數據汙染和丟失,誤操作等情況,將是難以恢復的。所以備份是非常必要的!為此,我們有共享的hdfs資源作為我們的備份池,希望能隨時可以還原業務所需資料。
2.Small item & Small instance!
由於Redis單執行緒(嚴格意義上不是單執行緒,但認為對request的處理是單執行緒的)的模型,大的資料結構list,sorted set,hash set的批量處理就意味著其他請求的等待,故使用Redis的複雜資料結構一定要控制其單key-struct的大小。
另外,Redis單例項的記憶體容量也應該有嚴格的限制。單例項記憶體容量較大後,直接帶來的問題就是故障恢復或者Rebuild從庫的時候時間較長,而更糟糕的是,Redis rewrite aof和save rdb時,將會帶來非常大且長的系統壓力,並佔用額外記憶體,很可能導致系統記憶體不足等嚴重影響效能的線上故障。我們線上96G/128G記憶體伺服器不建議單例項容量大於20/30G。
3.Been Available!
業界資料和使用比較多的是Redis sentinel(哨兵)
2000行C實現了伺服器狀態檢測,自動故障轉移等功能。
但由於自身實際架構往往會複雜,或者考慮的角度比較多,為此 @許琦eryk和我一同做了hypnos專案。
hypnos是神話中的睡神,字面意思也是希望我們工程師無需在休息時間處理任何故障。:-)
其工作原理示意如下:
Talk is cheap, show me your code! 稍後將單獨寫篇部落格細緻講下Hypnos的實現。
4.In Memory or not?
發現一種情況,開發在溝通後端資源設計的時候,常常因為習慣使用和錯誤瞭解產品定位等原因,而忽視了對真實使用使用者的評估。也許這是一份歷史資料,只有最近一天的資料才有人進行訪問,而把歷史資料的容量和最近一天請求量都拋給記憶體類的儲存現實是非常不合理的。
所以當你在究竟使用什麼樣的資料結構儲存的時候,請務必先進行成本衡量,有多少資料是需要儲存在記憶體中的?有多少資料是對使用者真正有意義的。因為這其實對後端資源的設計是至關重要的,1G的資料容量和1T的資料容量對於設計思路是完全不一樣的
Plans in future?
1.slave sync改造
全部改造線上master-slave資料同步機制,這一點我們借鑑了MySQL Replication的思路,使用rdb+aof+pos作為資料同步的依據,這裡簡要說明為什麼官方提供的psync沒有很好的滿足我們的需求:
假設A有兩個從庫B及C,及 A `— B&C,這時我們發現master A伺服器有宕機隱患需要重啟或者A節點直接宕機,需要切換B為新的主庫,如果A、B、C不共享rdb及aof資訊,C在作為B的從庫時,仍會清除自身資料,因為C節點只記錄了和A節點的同步狀況。
故我們需要有一種將A`–B&C 結構切換切換為A`–B`–C結構的同步機制,psync雖然支援斷點續傳,但仍無法支援master故障的平滑切換。
實際上我們已經在我們定製的Redis計數服務上使用瞭如上功能的同步,效果非常好,解決了運維負擔,但仍需向所有Redis服務推廣,如果可能我們也會向官方Redis提出相關sync slave的改進。
2.更適合redis的name-system Or proxy
細心的同學發現我們除了使用DNS作為命名系統,也在zookeeper中有一份記錄,為什麼不讓使用者直接訪問一個系統,zk或者DNS選擇其一呢?
其實還是很簡單,命名系統是個非常重要的元件,而dns是一套比較完善的命名系統,我們為此做了很多改進和試錯,zk的實現還是相對複雜,我們還沒有較強的把控粒度。我們也在思考用什麼做命名系統更符合我們需求。
3.後端資料儲存
大記憶體的使用肯定是一個重要的成本優化方向,flash盤及分散式的儲存也在我們未來計劃之中。(原文連結: Largest Redis Clusters Ever)