天天看點

redis緩存設計-Redis(七)

作者:後端從入門到精通

上篇文章介紹了redisCluster。

一、高并發緩存應對政策

緩存穿透

正常情況下,使用者通路某條資料,第一次從資料庫擷取,後面會set進緩存,從緩存擷取。緩存穿透指的是資料庫沒有這個值,當大量請求時,會經過緩存在資料庫不斷查詢,資料庫負擔不斷增加。這種情況下可能是業務代碼異常,也可能是黑客利用不存在的key不斷攻擊資料庫(是以redis不光可以提高性能,還可以利用減輕資料庫壓力防止黑客攻擊)。那這種情況如何解決呢?

可以增加業務代碼邏輯,當這個值不存在,則set空值到緩存,給這個空值一個過期時間。

還有一種方式使用bigMap布隆過濾器,在業務代碼上先對資料進行一次過濾器過濾,對于不存在的資料,布隆過濾器可以先過濾掉。

緩存擊穿

當系統中redis的key大量一起過期,導緻同一時間高并發一起請求這些key,全部打到資料庫伺服器上,這時候導緻資料庫當機怎麼解決呢?

設定redis過期随機過期時間,并且提供一個過期時間基數。

緩存雪崩

整個redis伺服器直接當機導緻不可用,這時候 必須通過我們前面說的叢集保證redis高可用,以及預估高峰流量,做限流預案,用隊列削峰,服務降級。比如用hystrix服務降級元件,kafka隊列等。

二、熱點緩存key重建

當key是一個熱點,比如雙11某部手機大降價,高并發同時都通路這個key,于是全部一起通路到資料庫,這時候怎麼解決呢,用redission分布式鎖來保證隻有一個請求通路到資料庫,其他的從緩存沖擷取。(順便一提redission分布式鎖源碼裡通過lua腳本通路redis,保證事務和原子性)

三、資料庫緩存雙寫不一緻設計

線程1:set資料庫10,删除緩存

線程2:set資料庫6,删除緩存

線程3:get資料庫10,set緩存10

當線程3和線程2并行執行:

第一步:線程3擷取10,線程2set資料庫6,删除緩存

第二步:線程3set緩存10

這時候實際資料庫存入的是6,但是緩存存入的是10。

導緻了資料庫和緩存不一緻。這時候如何解決呢?

1、這種情況下肯定高并發導緻的,如果并發量很小,或者是個人的資料壓根不用考慮這種問題。

2、就算并發量很高,但是對資料庫一緻性要去不高,比如商品名稱,設定一個過期時間,等讀的時候更新就好。

3、如果不能容忍不一緻,則使用分布式鎖,保證排隊,讓并發變為串行。分布式讀寫鎖,相當于讀讀或者讀寫的時候按順序排隊,讀讀的時候不需要排隊。

4、引入阿裡新的開源中間件canal來監聽binlog日志來修改資料。

(延遲雙删也是一種解決政策,在删除緩存的時候,sleep 50ms再删一次。但這種情況不推薦,這種小機率事件而讓所有請求都停頓)

針對讀多寫少的情況,加入緩存提高性能,針對寫多讀少并且不能容忍不一緻性的情況,就沒必要使用緩存,可以直接操作資料庫,沒必要為了提高性能,而增加很多複雜的設計。

四、鍵值設計

1、key設計

1)以業務名(或者資料庫名)為字首,防止key沖突,冒号分割。

(微服務的情況下,加上服務名稱)

2)統一在一個檔案下管理,防止重複定義。

3)簡潔性:在加字首的情況下必須保證簡介,犧牲可讀性也是可以的。

4)特殊符号不可以:換行空格單雙引号不可以出現。

2、Value設計

Bigkey針對value的,絕對不能放大key,前面強調過很多次。在redis一個字元串最大512mb,哈希,set,zest,list可以存儲大約40億元素。實際情況下我們一般認為:

1)字元串:超過10kb就是bigkey。

2)非字元串:則以個數為機關,一般不要超過5000。

3)非字元串不要使用del進行删除,使用hscan,sscan,zscan方式漸進删除,同時要注意bigkey過期時間,因為過期會觸發del,造成阻塞。

3、bigkey危害

1)redis阻塞。

2)網絡阻塞:Bigkey意味着産生網絡流量較大,假設一個bigkey是1mb,用戶端每秒通路1000,那麼每秒産生1000mb流量,對于普通千兆網絡伺服器(按位元組每秒128mb/s)直接當機。

(千兆網卡為什麼是128mb/s,因為需要除以8,按位元組計算)

3)過期删除:在redis4.0版本設定lazyfree-lazy-expir yes,改為異步删除,如果沒有配置,則bigkey過期會造成阻塞。

4、bigkey産生

正常都是程式設計不當,

1)社交類,大v粉絲太多,比是bigkey。

2)統計類,按天存儲某項功能使用者集合,使用者多也是bigkey。

3)緩存,當我們從資料庫查詢資料,序列化放入緩存是否放入很多不想幹的資料。

如何優化呢?

可以拆分,通過哈希取模拆分更小子產品,進行二次存儲。

如果實在不可以避免,必須要bigkey,那麼隻可以在操作的時候不要hgetall,用hmget,删除的時候也要漸進式删除。

5、選擇合适資料類型

Set user:1:name ky

Set user:1:age 20

可以改為哈希

Hmset user:1 name ky age 20

繼續閱讀