Redis經驗談

文/楊海朝

新浪作爲全世界最大的Redis用戶,在開發和運維方面有非常多的經驗。本文作者來自新浪,希望能爲業界提供一些親身經歷,讓大家少走彎路。

使用初衷

從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,在大規模高併發、海量訪問方面有豐富的管理經驗。熱衷於整體架構、數據庫設計、性能優化、分佈式部署方案和高可用性方面的研究。


http://www.programmer.com.cn/14577/


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章