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)

12、登錄時獲取短信驗證碼限速(string)

13、分布式系統,緩存用戶登錄信息

二、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 整數   #加
  • setex : 如果 key 已經存在, SETEX 命令將覆寫舊值
  • setnx : 若給定的 key 已經存在,則 SETNX 不做任何動作。

2. list(列表)

類似於LinkedList 雙向鏈表。插入刪除塊,查詢慢。

使用場景

  • lpush 、lpop 棧(stack)
  • lpush 、rpop 隊列(queue)
  • lpush 、brpop 消息隊列

常用命令

blpop key timeout # 移出並獲取列表的第一個元素, 如果列表沒有元素會阻塞列表直到等待超時返回nil或發現可彈出元素為止。

lpush key value1...value #先進后出,將一個或多個元素插入到列表頭部。 如果 key 不存在,一個空列表會被創建並執行 LPUSH 操作。 當 key 存在但不是列表類型時,返回一個錯誤。

rpush key value1...value... #先進先出,在列表的尾部插入一個或多個元素

llen key #隊列長度

lpop key  # 移除並返回列表第一個元素

rpop key # 移除並返回列表最后一個元素

lrange key start end # 根據索引獲取區間元素

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),Redis使用epoll作為I/O多路復用技術的實現,再加上Redis自身的事件處理模型將epoll中的連接、讀寫、關閉都轉換為事件,不在網絡I/O上浪費過多的時間,
  • 4、單線程避免了不必要的上下文切換和競爭條件

Redis是單線程來處理命令的,所以一條命令從客戶端達到服務端不會立刻被執行,所有命令都會進入一個隊列中,然后逐個被執行。

十四、漏斗限流

分布式限流:redis-cell

單機:Google的guava包提供了RateLimiter類

限流的常見算法有以下三種:
1.時間窗口算法
2.漏桶算法
3.令牌算法

十五、GEO

  • Redis通過GeoHash算法實現附近的人查詢功能;
  • 內部數據結構是zset,通過score還原就可以得到原始坐標;
  • 集群環境中單個key對應的數據不宜超過1M,如果超過需要按相應業務規則拆分降低key的數據大小。

十六、scan

  • 通過游標分步進行,相比於keys,不會阻塞線程
  • 提供limit參數可以控制返回結果條數


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM