標籤:
Redis 在新浪微博中的應用
Redis簡介
1. 支援5種資料結構
支援strings, hashes, lists, sets, sorted sets
string是很好的儲存方式,用來做計數儲存。sets用於建立索引庫非常棒;
2. K-V 儲存 vs K-V 緩衝
新浪微博目前使用的98%都是持久化的應用,2%的是緩衝,用到了600+伺服器
Redis中持久化的應用和非持久化的方式不會差別很大:
非持久化的為8-9萬tps,那麼持久化在7-8萬tps左右;
當使用持久化時,需要考慮到持久化和寫效能的配比,也就是要考慮redis使用的記憶體大小和硬碟寫的速率的比例計算;
3. 社區活躍
Redis目前有3萬多行代碼, 代碼寫的精簡,有很多巧妙的實現,作者有技術潔癖
Redis的社區活躍度很高,這是衡量開源軟體品質的重要指標,開源軟體的初期一般都沒有商業技術服務支援,如果沒有活躍社區做支撐,一旦發生問題都無處求救;
Redis基本原理
redis持久化(aof) append online file:
寫log(aof), 到一定程度再和記憶體合并. 追加再追加, 順序寫磁碟, 對效能影響非常小
1. 單一實例單進程
Redis使用的是單進程,所以在配置時,一個執行個體只會用到一個CPU;
在配置時,如果需要讓CPU使用率最大化,可以配置Redis執行個體數對應CPU數, Redis執行個體數對應連接埠數(8核Cpu, 8個執行個體, 8個連接埠), 以提高並發:
單機測試時, 單條資料在200位元組, 測試的結果為8~9萬tps;
2. Replication
過程: 資料寫到master-->master儲存到slave的rdb中-->slave載入rdb到記憶體。
儲存點(save point): 當網路中斷了, 連上之後, 繼續傳.
Master-slave下第一次同步是全傳,後面是增量同步處理;、
3. 資料一致性
長期運行後多個結點之間存在不一致的可能性;
開發兩個工具程式:
1.對於資料量大的資料,會周期性的全量檢查;
2.即時的檢查增量資料,是否具有一致性;
對於主庫未及時同步從庫導致的不一致,稱之為延時問題;
對於一致性要求不是那麼嚴格的情境,我們只需要要保證最終一致性即可;
對於延時問題,需要根據業務情境特點分析,從應用程式層面增加策略來解決這個問題;
例如:
1.新註冊的使用者,必須先查詢主庫;
2.註冊成功之後,需要等待3s之後跳轉,後台此時就是在做資料同步。
新浪Redis使用曆程
2009年, 使用memcache(用於非持久化內容), memcacheDB(用於持久化+計數),
memcacheDB是新浪在memcache的基礎上,使用BerkeleyDB作為資料持久化的儲存實現;
1. 面臨的問題
- 資料結構(Data Structure)需求越來越多, 但memcache中沒有, 影響開發效率
- 效能需求, 隨著讀操作的量的上升需要解決,經曆的過程有:
資料庫讀寫分離(M/S)-->資料庫使用多個Slave-->增加Cache (memcache)-->轉到Redis
- 解決寫的問題:
水平分割,對錶的拆分,將有的使用者放在這個表,有的使用者放在另外一個表;
可靠性需求
Cache的"雪崩"問題讓人糾結
Cache面臨著快速恢複的挑戰
開發成本需求
Cache和DB的一致性維護成本越來越高(先清理DB, 再清理緩衝, 不行啊, 太慢了!)
開發需要跟上不斷湧入的產品需求
硬體成本最貴的就是資料庫層面的機器,基本上比前端的機器要貴幾倍,主要是IO密集型,很耗硬體;
維護性複雜
一致性維護成本越來越高;
BerkeleyDB使用B樹,會一直寫新的,內部不會有檔案重新組織;這樣會導致檔案越來越大;大的時候需要進行檔案歸檔,歸檔的操作要定期做;
這樣,就需要有一定的down time;
基於以上考慮, 選擇了Redis
2. 尋找開源軟體的方式及評判標準
- 對於開源軟體,首先看其能做什麼,但更多的需要關注它不能做什麼,它會有什麼問題?
- 上升到一定規模後,可能會出現什麼問題,是否能接受?
- google code上, 國外論壇找材料(國內比國外技術水平滯後5年)
- 觀察作者個人的代碼水平
Redis應用情境
1. 業務使用方式
- hash sets: 關注列表, 粉絲列表, 雙向關注列表(key-value(field), 排序)
- string(counter): 微博數, 粉絲數, ...(避免了select count(*) from ...)
- sort sets(自動排序): TopN, 熱門微博等, 自動排序
- lists(queue): push/sub提醒,...
上述四種, 從精細化控制方面,hash sets和string(counter)推薦使用, sort sets和lists(queue)不推薦使用
還可通過二次開發,進行精簡。比如: 儲存字元改為儲存整形, 16億資料, 只需要16G記憶體
儲存類型儲存在3種以內,建議不要超過3種;
將memcache +myaql 替換為Redis:
Redis作為儲存並提供查詢,後台不再使用mysql,解決資料多份之間的一致性問題;
2. 對大資料表的儲存
(eg:140字微博的儲存)
一個庫就存唯一性id和140個字;
另一個庫存id和使用者名稱,發布日期、點擊數等資訊,用來計算、排序等,等計算出最後需要展示的資料時再到第一個庫中提取微博內容;
改進的3個步驟:
1)發現現有系統存在問題;
2)發現了新東西, 怎麼看怎麼好, 全面轉向新東西;
3)理性迴歸, 判斷哪些適合新東西, 哪些不適合, 不合適的回遷到老系統
3. 一些技巧
- 很多應用, 可以承受資料庫連接失敗, 但不能承受處理慢
- 一份資料, 多份索引(針對不同的查詢情境)
- 解決IO瓶頸的唯一途徑: 用記憶體
- 在資料量變化不大的情況下,優先選用Redis
遇到的問題及解決辦法
(注意: 都是量特別大時候會出現的, 量小了怎麼都好說)
1.Problem: Replication中斷後, 重發-->網路突發流量
Solution: 重寫Replication代碼, rdb+aof(滾動)
2.Problem: 容量問題
Solution: 容量規劃和M/S的sharding功能(share nothing, 抽象出來的資料對象之間的關聯資料很小)
增加一些配置, 分流, 比如: 1,2,3,4, 機器1處理%2=1的, 機器2處理%2=0的.
低於記憶體的1/2使用量, 否則就擴容(建議Redis執行個體使用的資料,最大不要超過記憶體的80%)
我們線上96G/128G記憶體伺服器不建議單一實例容量大於20/30G。
微博應用中單表資料最高的有2T的資料,不過應用起來已經有些力不從心;
每個的連接埠不要超過20G;測試磁碟做save所需要的時間,需要多長時間能夠全部寫入;記憶體越大,寫的時間也就越長;
單一實例記憶體容量較大後,直接帶來的問題就是故障恢複或者Rebuild從庫的時候時間較長,對於普通硬碟的載入速度而言,我們的經驗一般是redis載入1G需要1分鐘;(載入的速度依賴於資料量的大小和資料的複雜度)
Redis rewrite aof和save rdb時,將會帶來非常大且長的系統壓力,並佔用額外記憶體,很可能導致系統記憶體不足等嚴重影響效能的線上故障。
reblance: 現有資料按照上述配置重新分發。
後面使用中介層,路由HA;
註:目前官方也正在做這個事,Redis Cluster,解決HA問題;
3. Problem: bgsave or bgwriteaof的冰晶問題
Solution: 磁碟效能規劃和限制寫入的速度, 比如: 規定磁碟以200M/s的速度寫入, 細水長流, 即使到來大量資料. 但是要注意寫入速度要滿足兩個客觀限制:
符合磁碟速度
符合時間限制(保證在高峰到來之前, 就得寫完)
4.Problem: 營運問題
1)Inner Crontab: 把Crontab遷移到Redis內部, 減少遷移時候的壓力
本機多連接埠避免同時做 - 能做到
同一業務多連接埠(分布在多機上), 避免同時做 - 做不到
2)動態升級: 先載入.so檔案, 再管理配置, 切換到新代碼上(Config set命令)
把對redis改進的東西都打包成lib.so檔案,這樣能夠支援動態升級
自己改的時候要考慮社區的升級。當社區有新的版本,有很好用的新功能時,要能很容易的與我們改進後的版本很好的merge;
升級的前提條件: 模組化, 以模組為單位升級
載入時間取決於兩個方面: 資料大小, 資料結構複雜度. 一般, 40G資料耗時40分鐘
分布式系統的兩個核心問題: A.路由問題 B.HA問題
3)危險命令的處理: 比如: fresh all刪除全部資料, 得進行控制
營運不能只講資料備份,還得考慮資料恢複所需要的時間;
增加許可權認證(管理員才有許可權)eg:flashall 許可權認證,得有密碼才能做;
當然,高速資料互動一般都不會在每次都進行許可權認證,通用的處理策略是第一次認證,後期都不用再認證;
控制hash策略(沒有key, 就找不到value; 不知道hash策略, 就無法得到key)
4)Config Dump:
記憶體中的配置項動態修改過, 按照一定策略寫入到磁碟中(Redis已支援)
5)bgsave帶來aof寫入很慢:
fdatasync在做bgsave時, 不做sync aof(會有資料出入)
6)成本問題: (22T記憶體, 有10T用來計數)
Redisscounter(16億資料佔用16G記憶體) - 全部變為整型儲存, 其餘(字串等)全不要
Redis+SSD(counterService計數服務)
順序自增, table按照順序寫, 寫滿10個table就自動落地(到SSD)
儲存分級: 記憶體配置問題, 10K和100K寫到一塊, 會有片段. Sina已經最佳化到浪費只佔5%以內(已經很好了!)
5.Problem: 分布式問題
1.Config Server: 命名空間, 特別大的告訴訪問, 都不適合用代理, 因為代理降低速度, 但是, Sina用了(單機多連接埠, Redis Cluster, sentinel)
Config Server放到Zookeeper上
最前面是命名服務,後面跟的是無狀態的twmemproxy(twitter的改進的,用C寫的) ,後面才是redis;
2.twmemproxy
應用不必關心串連失敗, 由代理負責重連
把Hash演算法放到代理商
代理後邊的升級, 前端不關心, 解決了HA的問題
無狀態, 多台代理無所謂
3.AS --> Proxy -->Redis
4.Sina的Redis都是單機版, 而Redis-Cluster互動過於複雜,沒有使用
做HA的話,一定要配合監控來做,如果掛了之後,後續該如何做;
並不是追求單機效能,而是叢集的輸送量,從而可以支援無線擴充;
經驗總結
- 提前做好資料量的規劃, 減少sharding(互連網公司一般以年為單位)
- 只存精細化資料(記憶體很金貴!)
- 儲存使用者維度資料
對象維度資料要有生命週期
特別是資料量特別大的時候,就很有必要來進行劃分了;
- 暴露服務的常見過程: IP-->負載平衡-->網域名稱-->命名服務(一張表: 名字+資源(IP+連接埠))
- 對於硬體消耗,IO、網路和CPU相比,Redis最消耗的是CPU,複雜的資料類型必定帶來CPU消耗;
- 新浪微博回應時間逾時目前設定為5s;(返回很慢的記錄key,需記錄下來分析,慢日誌);
- 備份的資料要定期要跑一下生產的資料;用來檢查備份資料的有效性;
- slave掛多了肯定會對master造成比較的影響;新浪微博目前使用的M/S是一拖一,主要用來做容災;
同步時,是fork出一個單獨進程來和slave進行同步;不會佔用查詢的進程;
- 升級到2.6.30以後的linux核心;
在2.6.30以上對非強制中斷的問題處理的很好,效能提升效果明顯,差不多有15%到30%的差距;
- redis不用讀寫分離,每個請求都是單線程,為什麼要進行讀寫分離。
Redis 在新浪微博中的應用