Redis計數在新浪微博的應用
微博業務的迅速發展,對基礎架構層面的要求也越來越高。新浪作為國內最早使用 redis,并且是國內最大的 redis 使用者,在 redis 的使用上,也在逐步優化和提高。
作為微博中一項重要的數據,計數類業務在微博業務中占的比重和重要性逐步提高。計數結果的準確度直接影響用戶體驗,并且很容易引起用戶的投訴。在計數業務上,在不斷的優化和改進中,我們主要經歷了以下三個階段:
初級階段
從 2010 年開始,使用 redis-2.0 版本。在最初業務數據比較少的時候,表現相當不錯。但隨著數據量和請求量的不斷增加,一些問題逐漸暴露出來。
-
主從同步問題
首先遇到的是主從的同步問題。它的原理是當 master 接收到 slave 的同步請求后,把內存的數據 fork 出一個子進程 dump 出來,形成 rdb 文件,然后傳到 slave,slave 再把這個文件加載到內存,之后的增量更新由 master 在執行完每條修改命令后立即同步給 slave。 在網絡出現問題時,比如瞬斷,會導致 slave 里的數據全部重傳。對單個端口來說,如果數據量小,那么這個影響不大,而如果數據量比較大的話,就會導致網絡流量暴增,同時 slave 在加載 rdb 時無法響應任何請求。
-
持久化問題
計數業務中多數使用 redis 作為存儲,因此都開啟了 aof,并配置為每秒做一次 fsync 操作將寫操作刷新到磁盤。隨著 aof 的增長,需要定期 rewrite。Rewrite 的機制和生成 rdb 的過程類似,都是 fork 出一個子進程來完成的,子進程對于磁盤的持續寫入會導致父進程的 fsync 操作阻塞,造成大量請求超時。
-
版本升級問題
由于 redis 在使用初期 bug 較多,版本迭代頻繁,而版本升級需要關閉 redis 進程并重新加載 aof。對于大量使用 redis 的微博業務來講,這樣的升級成本也越來越難以承受。
-
內存使用問題
2. 0 版本的 redis,在內存使用上相對比較粗放,對于計數這樣一個簡單的 key-value,占用的內存達到 100 字節以上,存在比較多的優化空間。
進階階段
針對 redis 使用初期存在的問題,我們逐個進行了改進。主從復制參考 mysql 的同步方式,使用 rdb+aof 結合的方式,解決了網絡瞬斷引起的重傳問題,同時限制子進程做后臺 dump 時對磁盤的寫入,期間暫停主進程的 fsync 操作,解決了慢請求的問題。
針對計數業務,我們開發了專用的版本 redisscounter,單個 key-value 占用的內存 key 的長度加 4 個字節的 value,將內存的使用量降低到原來的1/4 以下。通過預先分配內存數組和 double hash 技術,消除了 redis 中 hash 表的大量指針開銷。
對于版本升級的問題,我們將 redis 的核心處理邏輯封裝到動態庫,內存中的數據保存在全局變量里,通過外部程序來調用動態庫里的相應函數來讀寫數據。版本升級時只需要替換成新的動態庫文件即 可,無須重新載入數據。通過這樣的方式,版本升級只需執行一條指令,即可在毫秒級別完成代碼的升級,同時對客戶端請求無任何影響。
有了上面的改進后,新版本開始大量應用,多數業務都可以作為完整的存儲替代以前的 mysql+memcached 組合。對于微博的評論數和轉發數,由于微博條目不斷增加,無法保存全量數據,因此采用 mysql+redisscounter 組合的方式,mysql 保存全量數據,使用兩組 redisscounter 保存最近幾個月的熱數據,通過定期滾動兩組 redisscounter 里的數據來清理冷數據。
高級階段
隨著微博的發展,針對單條微博的計數也不斷增加,從原來的評論數、轉發數,又增加了表態數,2013 年還上線了閱讀數。Redisscounter 不能很好的解決這類擴展問題,同時上面的 mysql+redisscounter 的滾動方式也過于復雜,定期的滾動操作很容易出現問題。針對這類問題,我們再度做出改進,將 key 由原先的字符串改成微博 id,同時對于每條微博的評論轉發等計數,我們統計發現,絕大多數微博的計數都可以用 10~15 個 bit 來保存,因此可以將多個計數保存到一個 4 字節的 value 里,過大的計數值在內存中另外開辟一塊空間來保存。這樣通過一條 get 命令即可獲取該微博的所有計數。同時針對微博業務的特點,越老的微博被訪問的次數就會越少,在內存使用多個數組保存不同范圍的微博,內存不足時將最老的一 組微博 dump 到 ssd 上,內部自動實現的滾動可以保證熱微博全部在內存里。對于落到 ssd 上的老數據的訪問,通過異步的 io 線程來讀寫,經過這樣的改進后,去掉了原先的 mysql 存儲,降低了業務開發成本和運維成本。
從 redis 在計數業務上的發展經歷可以看出,技術的進步是由業務的需求推動的。隨著業務的發展,還會遇到更多新的挑戰。希望我們走過的這些改進之路對于讀者在使用 redis 的過程中能有所幫助。
<span id="shareA4" class="fl"> </span> </div>