1. 程式人生 > >Redis-基礎和應用篇

Redis-基礎和應用篇

> 2020,到新公司這一年多以來,更新文章和總結知識的習慣被丟掉了。我覆盤了下自己,原因不是公司技術氛圍不好,也不是每天業務需求太多,其根本原因還是---惰性。作為我們技術人隨著年齡的增長,精力也會被生活中許多瑣碎的事情分散,但我們不應該忘記當初寫下第一行程式碼時的初衷。我們一定要明白持之以恆、長遠規劃、階段性覆盤的重要性。2021新的一年,新的心態,新的目標,GO! GO! GO!!! > 本文是讀錢文品《Redis深度歷險》的讀書筆記 ## 一、redis應用 1、記錄帖子點贊數、評論數和點選數(hash) 2、記錄使用者的帖子ID列表,便於快速顯示使用者的帖子列表(zset) 3、記錄帖子的標題、摘要、作者和封面資訊,使用者列表頁展示(hash) 4、記錄帖子的點贊使用者ID列表,評論ID列表,用於顯示和去重計數(hash) 5、快取近期熱帖內容(帖子內容的空間佔用比較大),減少資料庫壓力(hash) 6、記錄帖子的相關文章ID,根據內容推薦相關帖子(list) 7、如果帖子ID是整數自增的,可以使用redis來分配帖子ID(計數器) 8、收藏集和帖子之間的關係(zset) 9、記錄熱榜帖子ID列表、總熱榜和分類熱榜(zset) 10、快取使用者行為歷史,過濾惡意行為(zset、hash) 11、保證同一使用者不會中獎兩次(set) ## 二、redis資料結構 > string(字串)、list(列表)、hash(字典)、set(集合)、zset(有序集合) ### 1. string(字串) 其內部字串是一個動態字串,類似於ArrayList的動態擴容。以此減少頻繁分配記憶體的開銷。字串長度小於1M時,成倍擴容;大於1M時,只增加1M;最大長度512M。 #### 使用場景: 快取使用者登入資訊。token作為key,使用者資訊使用JSON序列化成字串,獲取時再反序列化。 #### 常用命令 ``` set name value #存值 get name #取值 exists name #判斷 del name mset name1 name2 value1 value2 #批量取 mget name1 name2 ..... #批量取 expire name m秒 #m秒後過期 setex name m秒 value #存值,並且設定過期時間 setnx name value #存值,如果name已經存在,就返回0 set name 1 #設定為整數 incr name #還可以自增 incrby name 整數 #加 ``` ### 2. list(列表) 類似於LinkedList。插入刪除塊,查詢慢。 #### 使用場景 常用於非同步佇列實現(先進先出) #### 常用命令 ``` rpush name value1 value2... #入隊 llen name #佇列長度 lpop name #出隊 value1 ``` ### 3. hash(字典) 類似於HashMap #### 使用場景 可以對儲存結構中每個欄位單獨儲存。過期時間是針對真個hash物件,而不是單獨的子key. #### 常用命令 ``` hset key filed1 value1 hset key filed2 value2 #存 hget key filed1 #取 ``` ### 4. set(集合) sadd, smembers, scard ### 5. zset(有序集合) zadd, zrange,zrank, zrem,zcard ## 三、HyperLogLog - 場景:估數、精確度要求不高場景(統計網站的PV 和UV) - 命令 pfadd、pfcount、pfmerge - 記憶體佔用比set小,有一定的誤差 ## 四、布隆過濾器 - 原理:布隆過濾器是一個BIT陣列 - 場景:資訊推薦去重(微博推薦重新整理時過濾已經看過的資訊),垃圾郵件過濾、爬蟲系統過濾已爬內容、解決快取穿透問題 - 布隆過濾器可以判斷某個資料一定不存在,但是無法判斷一定存在(不精確的SET) - 佔用記憶體極少,並且插入和查詢速度都足夠快。 - 缺點,無法刪除資料;隨著資料的增加,誤判率會增加 - Redisson 實現 ## 五、Reids6種淘汰策略 - volatile-lru:從設定了過期時間的資料集中,選擇最近最久未使用的資料釋放; - allkeys-lru:從資料集中(包括設定過期時間以及未設定過期時間的資料集中),選擇最近最久未使用的資料釋放; - volatile-random:從設定了過期時間的資料集中,隨機選擇一個數據進行釋放; - allkeys-random:從資料集中(包括了設定過期時間以及未設定過期時間)隨機選擇一個數據進行入釋放; - volatile-ttl:從設定了過期時間的資料集中,選擇馬上就要過期的資料進行釋放操作; - noeviction:不刪除任意資料(但redis還會根據引用計數器進行釋放),這時如果記憶體不夠時,會直接返回錯誤。 > 預設策略是noeviction > 推薦使用的策略是volatile-lru > 通過maxmemory-samples配置樣本數量,預設為5 快取淘汰演算法(LFU、LRU、ARC、FIFO、MRU) ## 六、Redis 持久化方案: - RDB 預設方式 (RDB持久化即通過建立快照的方式進行持久化,儲存某個時間點的全量資料。) - AOF (Append-Only-File持久化即記錄所有變更資料庫狀態的指令,以append的形式追加儲存到AOF檔案中) - 如果Redis只是用來做快取伺服器,比如資料庫查詢資料後快取,那可以不用考慮持久化,因為快取服務失效還能再從資料庫獲取恢復。 ## 七、快取和資料庫資料一致性(併發競爭問題) - 延時雙刪策略(在寫庫前、後進行redis.del,並且設定合理的延時時間。) - 讀取binlog分析 ,利用訊息佇列(rabbitmq、kafka), 推送更新各臺的redis快取資料 ## 八、快取穿透 - 現象:使用者大量併發請求的資料(key)對應的資料在redis和資料庫中都不存在,導致儘管資料不存在但還是每次都會進行查DB。 - 解決方案:從快取取不到的資料,在資料庫中也沒有取到,這時也可以將key-value對寫為key-null ## 九、快取擊穿 - 現象:快取擊穿是指快取中沒有但資料庫中有的資料(一般是快取時間到期),這時由於併發使用者特別多,同時讀快取沒讀到資料,又同時去資料庫去取資料,引起資料庫壓力瞬間增大,造成過大壓力。 - 解決方案: 1.設定熱點資料永遠不過期 2.介面限流與熔斷,降級 3.加互斥鎖 4.布隆過濾器 ## 十、快取雪崩 - 現象:大量key同一時間點失效,同時又有大量請求打進來,導致流量直接打在DB上,造成DB不可用。 - 解決方案: 1.設定key永不失效(熱點資料); 2.設定key快取失效時候儘可能錯開; 3.使用多級快取機制,比如同時使用redsi和memcache快取,請求->redis->memcache->db; 4.購買第三方可靠性高的Redis雲伺服器; ## 十一、Redis熱點key處理 ### 1 熱點key發現 - 監控熱key(抓包程式抓redis監聽埠的資料,抓到資料後往kafka裡丟。接下來,flink流式計算系統消費kafka裡的資料,進行資料統計即可) - 通知系統做處理 ### 2 解決方案 - 本地快取(利用ehcache或HashMap將發現的熱key載入到jvm,熱key直接走jvm查詢) - 叢集(把這個熱key,在多個redis上都存一份) - 阿里雲Redis已經在核心層面解決熱點key問題 ### 3. 熱key的危害 - 流量集中,達到物理網絡卡上限。 - 請求過多,快取分片服務被打垮。 - DB 擊穿,引起業務雪崩。 ## 十二、拒絕大KEY - 叢集環境,大key會導致資料遷移卡頓 - 如果被刪除時,記憶體一次性回收,也會卡頓 - 擴容時,會一次性申請更大的記憶體,也會卡頓 - 注意:如果Redis記憶體起伏較大,很有可能是大key導致,這時需要定位大key並優化 - 定位大key可以使用scan、或者redis-cli指令完成 ## 十三、Redis是單執行緒的,但Redis為什麼這麼快 - 1、基於記憶體 - 2、資料結構和操作簡單 - 3、多路I/O複用模型(非阻塞IO) - 4、單執行緒避免了不必要的上下文切換和競爭條件 ## 十四、漏斗限流 分散式限流:redis-cell 單機:Google的guava包提供了RateLimiter類 限流的常見演算法有以下三種: 1.時間視窗演算法 2.漏桶演算法 3.令牌演算法 ## 十五、GEO - Redis通過GeoHash演算法實現附近的人查詢功能; - 內部資料結構是zset,通過score還原就可以得到原始座標; - 叢集環境中單個key對應的資料不宜超過1M,如果超過需要按相應業務規則拆分降低key的資料大小。 ## 十六、scan - 通過遊標分步進行,相比於keys,不會阻塞執行緒 - 提供limit引數可以控制返回結