redis
redis是什麼?
- 內存數據庫,一切數據操作都在內存中進行,所以速度很快,常被用來做緩存,消息隊列,分佈式鎖。
- 具有高效的數據結構,String、list、hash、set、zset,bitmaps、hyperloglog、geo、stream。
- redis還支持事務、持久化、多種集羣方式、發佈訂閱模型、內存淘汰機制等等。
redis和memached有什麼區別?
相同:
- 都是基於內存的數據庫、速度很快、可以做緩存。
- 都有過期策略。
不同:
- redis具有多種高效的數據結構。而memcached只支持最簡單的key-value模式
- redis又有持久化的功能,可以將數據存在硬盤,等待下一次重啓恢復數據,而memcached不支持,內存一斷電數據便會消失。
- redis具有事務、持久化、發佈訂閱模型等
- redis原生支持集羣,而memcached沒有原生的集羣模式。
redis基本數據類型
String:底層是簡單動態數組
List:壓縮鏈表(單個小於64B個數小於512)+雙向循環鏈表
Hash:壓縮鏈表(單個小於64 個數小於512 +Hash表
Set:有序數組 +Hash表
Zset 壓縮列表 + 跳錶
Hyperloglog
GEO
Stream
redis 線程模型
redis 單線程是指:
關閉文件、AOF刷盤、釋放內存會創建線程執行
redis 過期刪除策略(expire)
過期key都會存在過期字典中。
1.惰性刪除:比如說一個key設置了過期時間,那麼下一次使用的時候先判斷它又沒有過期,過期就把它刪除了。這樣的話對CPU比較友好,將刪除操作分散在各個時間段。
2.定期刪除:固定一個時間,抽取一批數據,刪除過期的Key。如果在抽取的數據中,過期的key佔25%以上,會重新再抽一批進行執行。
redis的話,採用的是定期刪除+惰性刪除。
但是,這樣還會漏掉許多過期的key,會出現OOM,所以還要使用數據淘汰策略。
redis數據的淘汰策略
MYSQL裏有2000W數據,redis只存20W數據,如何保證redis中數據都是熱點數據?
0.no-eviction:禁止驅逐數據,數據滿了,再存會拋出錯誤
1.volatile-random: 從已設置過期時間中隨意挑
2.volatile-ttl :從已經設置過期時間中挑將要過期的
3.voiatile-lru(最近最少使用):從過期中選擇最近最少使用
4.volatile-lfu:挑選最不經常使用的
5.allkeys-random:從數據集任意挑選
6.allkeys-lru:當內存不足時候,挑最近最少使用的(最常用)
7.allkeys-lfu:當內存不足時,挑選最不經常使用的key
bigkey
如果說一個key對應的value的內存過大,就可以看作bigkey,bigkey不僅佔內存,還對redis的性能有較大的影響。
String 大於10kb
list、set、hash、zset 大於500個
如果發現?
- 使用 --bigkeys
- 分析RDB文件找出bigkey 使用redis-rdb-tools工具
- 使用scan掃描
如何刪除?
- 分批刪除
- 異步刪除,unlink,將key放入異步線程
redis事務
- MULTI 開啓事務
- 命令執行入隊
- EXEC 執行事務
redis 事務不支持回滾,生產環境不可能出錯。
redis 事務
redis 提供了一種將多個命令打包的功能,然後再按照順序執行打包的所有命令,並且不會被中途打斷。
所以它滿足原子性。
redis 爲什麼這麼塊?
- 首先它是一個內存數據庫,內存數據庫的數據操作很快。大部分操作在內存中未完成。
- 它具有高效的數據結構,比如zset的跳錶就加快了查詢的速度。
- 執行數據操作命令是單線程的,這樣就省去了許多關於事務的操作
- 它使用了I/O 多路複用,根據文件事件分發器,來處理請求
redis 持久化
-
AOF
-
RDB
-
AOF+RDB
-
AOF:是指redis每次執行完一條命令後,將命令寫入AOF文件中。(速度快,最多丟失少量數據)
AOF寫回硬盤有:Always,EverySec,No
AOF過大會觸發AOF的重寫:創建子線程,將Redis數據庫中數據,轉換爲一條條命令。將新數據暫時存在AOF重寫緩衝區中,等線程執行完畢,將緩衝區數據寫入AOF文件。 -
RDB:指的是某一時刻,內存的快照,讀寫恢復快,但是備份週期長。(save、bgsave(後臺運行))
-
混合持久化:前半段RDB(速度快)+後半段AOF(完整)
Redis 四種部署方式
- 單機模式
- 主從複製
- 哨兵模式
- 集羣模式
集羣腦裂的問題?
集羣腦裂是什麼? 就是主節點暫時網絡異常,哨兵發現主節點掛了,那麼選舉新的主節點。
主節點與客戶端正常,與從節點失聯,主節點照常寫入。
舊的主節點成從節點,刪除數據進行全量同步,數據發生丟失。
解決:
寫數據最少同步slave數:min-slave-to-write:1
服務器的延遲值:min-slaves
redis做緩存
緩存雪崩
緩存雪崩,就是大量緩存再同一時間過期,導致請求打在數據庫上。
解決方式:
- 緩存不要同一時間過期,分散在一個時間段內。
- 緩存不過期
緩存擊穿
就是一個熱點key突然過期,很多人同時請求這一個key
解決方法:熱點Key不過期。
緩存穿透
顧名思義,把緩存穿透了,請求打在數據庫上了,原來直接查緩存,就返回,現在發現緩存中沒有,就會去數據庫查。
當一些數據庫中肯定沒有的key,緩存中當然也肯定沒有。
當大量無效key請求發生時,就會將請求打在數據庫,導致數據庫崩潰。
解決方法:
- 將所有有效key 放在布隆過濾器裏面,先查過濾器,過濾器沒有的,直接返回。
- 提前判斷key是不是合法的狀態
緩存更新策略(先刪緩存,再更新數據庫:旁路緩存)
redis 延時隊列:使用zset value爲過期時間,進行輪詢
redis做購物車?
怎麼防止客戶端連續點擊?
防重Token令牌:
下游傳遞唯一序列號如何實現冪等性?
所謂請求序列號,其實就是每次向服務端請求時候附帶一個短時間內唯一不重複的序列號,該序列號可以是一個有序 ID,也可以是一個訂單號,一般由下游生成,在調用上游服務端接口時附加該序列號和用於認證的 ID。
當上遊服務器收到請求信息後拿取該 序列號 和下游 認證ID 進行組合,形成用於操作 Redis 的 Key,然後到 Redis 中查詢是否存在對應的 Key 的鍵值對,根據其結果:
如果存在,就說明已經對該下游的該序列號的請求進行了業務處理,這時可以直接響應重複請求的錯誤信息。
如果不存在,就以該 Key 作爲 Redis 的鍵,以下游關鍵信息作爲存儲的值(例如下游商傳遞的一些業務邏輯信息),將該鍵值對存儲到 Redis 中 ,然後再正常執行對應的業務邏輯即可。
適用操作
- 插入操作
- 更新操作
- 刪除操作
使用限制
要求第三方傳遞唯一序列號;
需要使用第三方組件 Redis 進行數據效驗;
主要流程
- 下游服務生成分佈式 ID 作爲序列號,然後執行請求調用上游接口,並附帶唯一序列號與請求的認證憑據ID。
- 上游服務進行安全效驗,檢測下游傳遞的參數中是否存在序列號和憑據ID。
- 上游服務到 Redis 中檢測是否存在對應的序列號與認證ID組成的 Key,如果存在就拋出重複執行的異常信息,然後響應下游對應的錯誤信息。如果不存在就以該序列號和認證ID組合作爲 Key,以下游關鍵信息作爲 Value,進而存儲到 Redis 中,然後正常執行接來來的業務邏輯。
“ 上面步驟中插入數據到 Redis 一定要設置過期時間。這樣能保證在這個時間範圍內,如果重複調用接口,則能夠進行判斷識別。如果不設置過期時間,很可能導致數據無限量的存入 Redis,致使 Redis 不能正常工作。
Redis冪等性
- 用戶id+任務id
Redis設計排行榜
@PostMapping("/add/{name}/{score}")
void addUser(@PathVariable("name") String name, @PathVariable("score") Integer score) {
redisUtil.zadd("user:ranking", score, name);
}
@PostMapping("/top10")
Set<String> show(){
Set<String> zrevrange = redisUtil.zrevrange("user:ranking", 0, 10);
return zrevrange;
}