轉一下新浪使用redis的心得

xz43發表於2015-10-12
使用初衷
從2010年上半年起,我們就開始嘗試使用Redis,主要出於以下幾方面的考慮:
效能比MySQL好。因為業務的發展對效能的需求越來越強烈。
豐富的資料型別。在速度就是市場的互聯網時代,快速開發是一個不變的需求。
Cache當機讓人糾結,Redis有半持久化和持久化兩種方式,能從某種程度上解決這個問題,以減少Cache當機帶來的雪崩效應。
在部分業務場景中,使用MySQL+Memcached存在一致性問題,若使用Redis替代,能降低整體架構複雜度。

完善過程
在開始應用Redis時,規模比較小,資料量也很小,沒有遇到太多的問題。而隨著資料量的增加,遇到了很多問題。總結一句話就是,當資料量變大時,以前不是問題的問題都變成了問題。

Master/Slave同步問題
首先遇到的是Master/Slave的同步問題。它的原理是Slave做了Slaveof之後,向Master傳送一個Sync,Master把記憶體的資料Dump出來,形成rdb檔案,然後傳到Slave,Slave把這個檔案載入到記憶體,完成之後Master向Slave傳送新資料包。
在網路出現問題時,比如瞬斷,會導致Master裡的資料全部重傳。對單個埠來說,如果資料量小,那麼這個影響不大,而如果資料量比較大的話,則會導致網路瞬間流量暴增,同時在同步時Slave做不了讀操作。我們對其進行了修改,加入Position的概念來解決這個問題,確保在網路出現問題時不會重傳所有資料,只重傳斷開時後面的資料。

aof的定期歸檔問題
Redis預設產生的aof檔案需要手工做 bgrewrite-aof,這個操作產生的lock會對寫產生一定的影響。因此,我們最開始用指令碼在凌晨業務低峰時進行這個操作。而隨著數量的增加,lock的時間越來越不能被業務接受。我們對原始碼進行了修改,將bgrewriteaof放到Redis內部去實現,在配置檔案內製定執行時間,讓這個操作自動執行,並且不會導致寫產生的lock問題。
同時,我們還將aof設計得與MySQL的binlog類似,設定每個aof的大小,在達到一定值時,會自動產生一個新的aof。

Mytrigger和MytriggerQ的設計
業務有這樣的需求:應用按使用者維度寫入資料,統計使用者的記錄數(如關注數、粉絲數)時,需要從資料庫中執行count(*)操作。在InnoDB中執行這個相對較慢,而增加Cache方案又滿足不了業務對實時性的要求。因此,我們開發了Mytrigger元件來讀取MySQL的binlog,然後透過業務邏輯轉化寫入Redis。

例如,MySQL中存每條記錄,Redis中存按使用者維度的記錄總和。這樣實現之後,應用從MySQL中讀取資料,從Redis裡讀取記錄條數,MySQL的壓力降低很多,同時計數讀取效能提高了很多。
如果應用是資料的寫入方,那麼它需要將資料寫入資料庫,同時需要把這些新增或變更通知給另一個應用,另一個應用獲得這些新增或更新後開始做自己的業務邏輯處理。
剛開始,我們採用了寫資料庫的同時再寫一份MemcacheQ的方法,後來更換為MytriggerQ讀取MySQL的binlog,將讀取到的資料轉化為隊列。需要了解資料變化的業務透過讀取這個MytriggerQ服務來獲取資料的變化。這樣,應用只用寫一次,簡化了應用架構的複雜度。

容量設計
在申請使用Redis之前,我們會對業務進行評估。透過填寫預計容量和效能需求表格,我們能算出Redis佔用的記憶體量,確保單個埠的資料量不高於機器記憶體的三分之一。
當前,我們使用的是96GB的記憶體型機型,每個埠最終容量控制在30GB以下。當業務需求的容量超過機器最大記憶體時,採用的拆分方式是Hash到多個埠,透過基準測試得出在容量允許的情況下,一臺機器部署2個例項、4個例項或8個例項的最大效能,預留20%的容量用於增長,根據業務指標計算出需要的資源數。

使用了Redis自身的過期策略之後,發現存入Redis的資料有可能出現即使還有大量記憶體沒有使用,Redis還會讓key過期去釋放記憶體,或者記憶體不足時key還沒有過期的問題。
對於過期的資料,我們採用清理和滾動兩種方式。清理容易出現記憶體碎片;滾動即建兩組埠,同時寫兩組埠。比如要保留3個月的資料,那麼每個埠保留6個月的資料,兩個同時寫,使用奇數埠,在第4個月時,把讀寫切換到偶數埠,同時清理奇數埠裡的資料,但使用這種方式帶來了很高的維護成本。

應用場景
做Cache還是做Storage是我們一直在思考的問題。Redis有持久化和半持久化兩種方式,但即使這樣,所有Redis的資料都在記憶體中。大資料量儲存時,資料型別的優勢將越來越不明顯。
當資料量小時,可以不用做過多考慮,因為一切都不是問題,可以利用其豐富的資料型別帶來業務的快速開發和上線;資料量總量和增加量都相對可控,資料比較精細可以使用Redis做儲存。例如,使用者維度的計數就用Redis來做Storage。但對於物件維度,如微博維度的資料使用Redis做Cache。

有些業務的容量增長過快,與之前的預計有出入,且所有的資料都在記憶體中,沒有冷熱區分(降低儲存最好的辦法就是分級儲存),我們就將這部分不再適合放在 Redis的業務使用新的方案代替。例如把它替換成MySQL+Memcached的方式。因為每次做滾動切換的方案運維成本和硬體成本投入都很高,所以可使用HandlerSocket來替換。例如,前6個月的資料放在Redis中,之後的資料放到MySQL中,在減少切換的同時也能降低運維成本。

未來的計劃
隨著機器規模的不斷增加,可用性和自動化需求越來越強烈,目前我們正在結合ZooKeeper設計Redis的自動切換,同時提高Redis自動化維護需求。我們會開發一個高速資料訪問框架和管理系統,將故障切換、資料拆分邏輯和自動資料遷移放到裡面,實現其應用的產品化。希望走過的這些路對大家在使用 Redis的過程中有所幫助。

作者楊海朝,新浪首席DBA,在大規模高併發、海量訪問方面有豐富的管理經驗。熱衷於整體架構、資料庫設計、效能最佳化、分散式部署方案和高可用性方面的研究。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/9399028/viewspace-1813818/,如需轉載,請註明出處,否則將追究法律責任。

相關文章