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使用的內存大小和硬盤寫的速率的比例計算;mysql

3. 社區活躍

Redis目前有3萬多行代碼, 代碼寫的精簡,有不少巧妙的實現,做者有技術潔癖 
Redis的社區活躍度很高,這是衡量開源軟件質量的重要指標,開源軟件的初期通常都沒有商業技術服務支持,若是沒有活躍社區作支撐,一旦發生問題都無處求救;linux

Redis基本原理

redis持久化(aof) append online file: 
寫log(aof), 到必定程度再和內存合併. 追加再追加, 順序寫磁盤, 對性能影響很是小redis

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下第一次同步是全傳,後面是增量同步;、sql

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不用讀寫分離,每一個請求都是單線程,爲何要進行讀寫分離。

相關文章
相關標籤/搜索