Tape is Dead,Disk is Tape,Flash is Disk,RAM Locality is King. — Jim Grayhtml
Redis不是比較成熟的Memcache或者Mysql的替代品,是對於大型互聯網類應用在架構上很好的補充。如今有愈來愈多的應用也在紛紛基於Redis作架構的改造。linux
能夠簡單公佈一下Redis平臺實際狀況redis
2200+億 commands/day 5000億Read/day 500億Write/daysql
18TB+ Memory後端
500+ Servers in 6 IDC 2000+instances緩存
應該是國內外比較大的Redis使用平臺,今天主要從應用角度談談Redis服務平臺。服務器
計數的應用在另一篇文章裏較詳細的描述,計數場景的優化 http://www.xdata.me/?p=262 這裏就不坳述了。數據結構
能夠預見的是,有不少同窗認爲把計數所有存在內存中成本很是高,我在這裏用個圖表來表示下個人觀點:架構
不少狀況你們都會設想純使用內存的方案會頗有很高成本,但實際狀況每每會有一些不同:運維
1.COST,對於有必定吞吐需求的應用來講,確定會單獨申請DB、Cache資源,不少擔憂DB寫入性能的同窗還會主動將DB更新記入異步隊列,而這三塊的資源的利用率通常都不會過高。資源算下來,你驚異的發現:反而純內存的方案會更精簡!
2.KISS原則,這對於開發是很是友好的,我只須要創建一套鏈接池,不用擔憂數據一致性的維護,不用維護異步隊列。
3.Cache穿透風險,若是後端使用DB,確定不會提供很高的吞吐能力,cache宕機若是沒有妥善處理,那就悲劇了。
4.大多數的起始存儲需求,容量較小。
面對微博經常出現的熱點,如最近出現了較爲火爆的短鏈,短期有數以萬記的人點擊、跳轉,而這裏會經常涌現一些需求,好比咱們向快速在跳轉時斷定用戶等級,是否有一些帳號綁定,性別愛好什麼的,已給其展現不一樣的內容或者信息。
普通採用Memcache+Mysql的解決方案,當調用id合法的狀況下,可支撐較大的吞吐。但當調用id不可控,有較多垃圾用戶調用時,因爲memcache未有命中,會大量的穿透至Mysql服務器,瞬間形成鏈接數瘋長,總體吞吐量下降,響應時間變慢。
這裏咱們能夠用redis記錄全量的用戶斷定信息,如string key:uid int:type,作一次反向的cache,當用戶在redis快速獲取本身等級等信息後,再去Mc+Mysql層去獲取全量信息。如圖:
固然這也不是最優化的場景,如用Redis作bloomfilter,可能更加省用內存。
產品運營總會讓你展現最近、最熱、點擊率最高、活躍度最高等等條件的top list。不少更新較頻繁的列表若是使用MC+MySQL維護的話緩存失效的可能性會比較大,鑑於佔用內存較小的狀況,使用Redis作存儲也是至關不錯的。
用戶最近訪問記錄也是redis list的很好應用場景,lpush lpop自動過時老的登錄記錄,對於開發來講仍是很是友好的。
這裏把兩個功能放在最後,由於這兩個功能在現實問題當中遇到了一些困難,但在必定階段也確實解決了咱們不少的問題,故在這裏只作說明。
Pinterest使用Redis存儲社交graph信息:
http://blog.gopivotal.com/case-studies-2/using-redis-at-pinterest-for-billions-of-relationships
Message Queue就是經過list的lpop及lpush接口進行隊列的寫入和消費,因爲自己性能較好也能解決大部分問題。
Redis 的Lua的功能擴展實際給Redis帶來了更多的應用場景,你能夠編寫若干command組合做爲一個小型的非阻塞事務或者更新邏輯,如:在收到 message推送時,同時1.給本身的增長一個未讀的對話 2.給本身的私信增長一個未讀消息 3.最後給發送人回執一個完成推送消息,這一層邏輯徹底能夠在Redis Server端實現。
可是,須要注意的是Redis會將lua script的所有內容記錄在aof和傳送給slave,這也將是對磁盤,網卡一個不小的開銷。
不少測試和應用均已證實,
1.在性能方面Redis並無落後Memcache多少,而單線程的模型給Redis反而帶來了很強的擴展性。
2.在不少場景下,Redis對同一份數據的內存開銷是小於Memcache的slab分配的。
3.Redis提供的數據同步功能,實際上是對cache的一個強有力功能擴展。
咱們線上的Redis 95%以上是承擔後端存儲功能的,咱們不只用做cache,而更爲一種k-v存儲,他徹底替代了後端的存儲服務(MySQL),故其數據是很是重要的,如 果出現數據污染和丟失,誤操做等狀況,將是難以恢復的。因此備份是很是必要的!爲此,咱們有共享的hdfs資源做爲咱們的備份池,但願能隨時能夠還原業務 所需數據。
因爲Redis單線程(嚴格意義上不是單線程,但認爲對request的處理是單線程的)的模型,大的數據結構list,sorted set,hash set的批量處理就意爲着其餘請求的等待,故使用Redis的複雜數據結構必定要控制其單key-struct的大小。
另外,Redis單實例的內存容量也應該有嚴格的限制。單實例內存容量較大後,直接帶來的問題就是故障恢復或者Rebuild從庫的時候時間較長, 而更糟糕的是,Redis rewrite aof和save rdb時,將會帶來很是大且長的系統壓力,並佔用額外內存,極可能致使系統內存不足等嚴重影響性能的線上故障。咱們線上96G/128G內存服務器不建議 單實例容量大於20/30G。
業界資料和使用比較多的是Redis sentinel(哨兵)
http://www.huangz.me/en/latest/storage/redis_code_analysis/sentinel.html
http://qiita.com/wellflat/items/8935016fdee25d4866d9
2000行C實現了服務器狀態檢測,自動故障轉移等功能。
但因爲自身實際架構每每會複雜,或者考慮的角度比較多,爲此@許琦eryk 和我一同作了hypnos項目。
hypnos是神話中的睡神,字面意思也是但願咱們工程師無需在休息時間處理任何故障。:-)
其工做原理示意以下:
Talk is cheap, show me your code! 稍後將單獨寫篇博客細緻講下Hypnos的實現。
發現一種狀況,開發在溝通後端資源設計的時候,經常由於習慣使用和錯誤瞭解產品定位等緣由,而忽視了對真實使用用戶的評估。也許這是一份歷史數據,只有最近一天的數據纔有人進行訪問,而把歷史數據的容量和最近一天請求量都拋給內存類的存儲現實是很是不合理的。
因此當你在究竟使用什麼樣的數據結構存儲的時候,請務必先進行成本衡量,有多少數據是須要存儲在內存中的?有多少數據是對用戶真正有意義的。由於這其實對後端資源的設計是相當重要的,1G的數據容量和1T的數據容量對於設計思路是徹底不同的
所有改造線上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的改進。
細心的同窗發現咱們除了使用DNS做爲命名系統,也在zookeeper中有一份記錄,爲何不讓用戶直接訪問一個系統,zk或者DNS選擇其一呢?
其實仍是很簡單,命名系統是個很是重要的組件,而dns是一套比較完善的命名系統,咱們爲此作了不少改進和試錯,zk的實現仍是相對複雜,咱們尚未較強的把控粒度。咱們也在思考用什麼作命名系統更符合咱們需求。
大內存的使用確定是一個重要的成本優化方向,flash盤及分佈式的存儲也在咱們將來計劃之中。