緩存的不當使用案例分析

1、背景 redis

      最近一朋友作社區重構,社區主要功能有發帖、回帖、查看帖子詳情,詳情頁按不一樣條件展現回帖(除了預先定義的順序外,可能每一個用戶看到的順序都不同,組合超過100個),大概的效果以下: sql

之前用的是開源的代碼,存儲用的是Mysql,系統也過於臃腫,稍微有點流量系統響應就很慢,因此準備重構。數據庫

重構後的方案以下後端

一、存儲仍是Mysql;緩存

二、爲了提升訪問速度,引入MongoDB做爲緩存(爲何不用Redis,由於MongoDB多線程,可擴充性好,而且支持較複雜的查詢) 多線程

Mysql數據表大概以下:
image.png運維

    上述表格是通過簡化版的內容。spa

    存儲方面,Mysql存了全量的帖子和帖子回覆,MongoDB也存了全量的帖子和帖子回覆,之因此這麼設計是由於讓用戶帖子詳情頁不用訪問數據庫,提升訪問速度。線程

     那爲何只保存在MongoDB裏呢,由於MongoDB不支持多表事務,社區的場景插入回覆,還有其它邏輯須要處理,因此須要藉助Mysql的InnoDB的事務機制保證數據的一致性。設計

    重構後訪問帖子詳情頁順序以下:

    一、根據帖子id從MongoDB獲取帖子詳情信息,包括標題、內容及發帖時間和發帖人,若是讀取不到,直接報錯;

    二、根據帖子id及當前條件從MongoDB獲取帖子回覆信息,一樣讀取不到也報錯。

     爲何不按分頁將每一個帖子按頁緩存回覆呢,由於前面說了整個詳情頁展現條件很是複雜,能夠倒序排,也可升序排,還能夠只看做者,有的回覆還有權限,若是所有緩存帖子回覆列表,則緩存的數據量很是的大。

2、問題分析

      通過分析,這樣的設計帶來幾個問題:

     一、系統設計比較複雜,由於要保證數據在Mysql、MongoDB中一致,須要作不少的代碼進行數據覈對、檢查;

     二、系統可用性差,由於帖子詳情頁所有讀取的是MongoDB,因此若是MongoDB掛了,則整個系統也就掛了,特別是MongoDB對於運維團隊還不是特別熟悉的狀況下。

    有什麼更好的方案呢,回到緩存的本質,關於緩存的使用有很多模式,通常來講對緩存不要強依賴,即緩存掛了,整個系統不要掛,讓系統打到後端存儲而且更新緩存,這樣還有最後一道防線,而在這個案例中,將MongoDB當存儲用了,而且同時使用兩個存儲。

     若是當緩存用,怎麼解決帖子詳情頁多種組合條件的致使緩存數據太大的問題?其實對於社區這樣的場景,主要佔內存的是回覆的內容,只要保證帖子回覆內容只緩存一份就能夠了。

    改進後帖子詳情頁邏輯以下:

    一、根據帖子id從 MongoDB中獲取帖子詳情信息,若是獲取不到,則從Mysql中獲取,而且寫回到MongoDB中;

    二、根據帖子id從MongoDB中獲取當頁須要展現的帖子回覆id,讀取不到再從Mysql回源,並寫回到MongoDB中;根據上面獲取的回覆id再從MongoDB中獲取回覆的詳情,一樣若是獲取不到則從Mysql回源,而且寫入到MongoDB中。

    固然在添加、更新回覆後,也須要更新相應的回覆內容,這樣就保證了帖子回覆只緩存一份,不會形成緩存的數據量過大的問題。還有很是重要的一點,整個系統沒有對緩存強依賴,即便MongoDB掛了,系統還會從Mysql讀取數據。最後系統的代碼也變得很是簡潔。

    固然這裏還有不少細節須要注意,像如何避免同一時間大量的回源Mysql的問題,這些業內已經有標準的方案,就不在此展開討論了。

3、案例總結

一、系統設計越簡單越好;

二、不要強依賴緩存;

廣告聯盟設計踩坑

從一次線上故障來看redis刪除機制

全球智能DNS解析實踐

相關文章
相關標籤/搜索