日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

【Redis 开发与运维】总结篇

發布時間:2023/12/10 数据库 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Redis 开发与运维】总结篇 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • Redis 是什么?簡述它的優缺點?
  • Redis 為什么這么快?
  • Redis 相比 memcached 有哪些優勢?
  • 說說 Redis 的數據類型和使用場景
  • 如何通過 Redis 實現分布式鎖
  • 如何使用 Redis 做異步隊列
  • 使用 Pipeline 的好處
  • Redis 過期鍵的刪除策略?
  • Redis 內存淘汰機制?
  • Redis 持久化機制
  • 說說緩存設計中會出現的問題和解決方案
  • 高并發場景下,如何解決數據庫與緩存雙寫的時候數據不一致的情況?
  • Redis 中跳躍表 skiplist 實現原理
  • Redis 為什么用 skiplist 而不用紅黑樹?
  • 假如 Redis 里面有 1 億個key,其中有 10w 個 key 是以某個固定的已知前綴開頭的,如何將它們全部找出來?
  • Redis6.0 為什么要引入多線程?
  • Redis 集群方案應該怎么做?都有哪些方案?
  • 講一講位圖 Bitmap
  • 講一講 HyperLogLog
  • Redis 單線程如何處理那么多的并發客戶端連接?
  • 布隆過濾器的原理
  • 慢查詢場景有哪些?
  • 如何保證 redis/mysql 的一致性?


Redis 是什么?簡述它的優缺點?

  • Redis 本質上是一個 Key-Value 類型的內存數據庫,很像 memcached,整個數據庫統統加載在內存當中進行操作,定期通過異步操作把數據庫數據 flush 到硬盤上進行保存。
  • 因為是純內存操作,Redis 的性能非常出色,每秒可以處理超過 10 萬次讀寫操作,是已知性能最快的 Key-Value DB。
  • Redis 的出色之處不僅僅是性能,Redis 最大的魅力是支持保存多種數據結構,此外單個 value 的最大限制是 1GB,不像 memcached 只能保存 1MB 的數據,因此 Redis 可以用來實現很多有用的功能。
  • Redis 的主要缺點是數據庫容量受到物理內存的限制,不能用作海量數據的高性能讀寫,因此 Redis 適合的場景主要局限在較小數據量的高性能操作和運算上。

Redis 為什么這么快?

  • 純內存訪問,Redis 將所有數據都放在內存中;
  • 采用的是基于非阻塞的 IO 多路復用機制,避免了網絡 IO 上浪費過多時間;
  • 單線程避免了線程切換和競態產生的消耗。

Redis 相比 memcached 有哪些優勢?

  • 數據類型:Redis 支持更豐富的數據類型(支持更復雜的應用場景),Redis 不僅僅支持簡單的 key/value 類型的數據,同時還提供 list,set,zset,hash 等數據結構的存儲。memcache 只支持簡單的數據類型 String。
  • 持久化:Redis 支持數據的持久化,可以將內存中的數據保持在磁盤中,重啟的時候可以再次加載進行使用,而 Memecache 把數據全部存在內存之中。
  • 集群模式:memcached 沒有原生的集群模式,需要依靠客戶端來實現往集群中分片寫入數據;而 Redis 原生支持集群模式。
  • 線程模型:Memcached 是多線程,非阻塞 IO 復用的網絡模型;Redis 使用單線程的多路 IO 復用模型。

說說 Redis 的數據類型和使用場景

Redis 支持五種數據類型:string( 字符串),hash( 哈希),list( 列表),set( 集合)及 zset(sorted set:有序集合)。

  • string:redis 中字符串 value 最大可為 512M。可以用來做一些計數功能的緩存(也是實際工作中最常見的)。常規計數:微博數,粉絲數等。
  • hash:鍵值對集合,是一個字符串類型的 Key 和 Value 的映射表,也就是說其存儲的 Value 是一個鍵值對(Key- Value),hash 特別適合用于存儲對象,后續操作的時候,可以直接僅僅修改這個對象中的某個字段的值。 比如我們可以 hash 數據結構來存儲用戶信息,商品信息等等。
  • list:簡單的字符串列表,按照插入順序排序,可以添加一個元素到列表的頭部(左邊)或者尾部(右邊),Redis list 的實現為一個雙向鏈表,即可以支持反向查找和遍歷,更方便操作,不過帶來了部分額外的內存開銷。可以實現一個簡單消息隊列功能,做基于 redis 的分頁功能等。還可以通過 lrange 命令做(微博、朋友圈)文章列表分頁,就是從某個元素開始讀取多少個元素,可以基于 list 實現高性能分頁。
  • set:是一個字符串類型的無序集合。可以用來進行全局去重等,比如:在微博應用中,可以將一個用戶所有的關注人存在一個集合中,將其所有粉絲存在一個集合,Redis 可以非常方便的實現如共同關注、共同粉絲、共同喜好等功能,這個過程也就是求交集的過程。
  • sorted set:是一個字符串類型的有序集合,給每一個元素一個固定的分數 score 來保持順序。可以用來做排行榜應用或者進行范圍查找等。

我們實際項目中比較常用的是 string、hash。 如果你是 Redis 的高級用戶,還需要加上下面幾種數據結構 HyperLogLog、Geo、Pub/Sub。

如果你說還玩過 Redis Module,像 BloomFilter,RedisSearch,Redis-ML,面試官得眼睛就開始發亮了。

詳情請參考:《【Redis 開發與運維】API 的理解和使用》


如何通過 Redis 實現分布式鎖

分布式鎖需要解決的問題

  • 互斥性
  • 安全性
  • 死鎖
  • 容錯

利用 SETNX key value:如果 key 不存在,則創建并賦值;設置成功,返回 1。設置失敗,返回 0。

問題一:如何解決 SETNX 長期有效的問題

  • EXPIRE key seconds:設置 key 的生存時間,當 key 過期時(生存時間為0),會自動被刪除
  • 缺點:原子性得不到滿足,因為 SETNX 和 EXPIRE 命令是兩個操作不滿足原子性。

答:可以利用:SET key value [EX seconds] [PX milliseconds] [NX|XX]

  • Ex second:設置鍵的過期時間為 second 秒
  • PX milliseconds:設置鍵的過期時間為 millisecond 毫秒
  • NX:只在鍵不存在時,才對鍵進行設置操作
  • XX:只在鍵已經存在時,才對鍵進行設置操作
  • SET 操作成功完成時,返回 OK,否則返回 nil
  • 例如:set lock 12345 ex 10 nx,表示設置了一個 key 為 lock 的鎖,鎖的過期時間為 10 秒

問題二:怎么處理別人把我的鎖釋放(刪除)的問題

  • 因為鎖的釋放無非就是刪除掉,那個 key 嘛,刪了鎖就釋放了。

答:

  • 可以把鎖的值設為用戶 ID,刪除之前比對用戶 ID 和鎖的值是否相等,只有相等才能刪除。
  • 因為判斷鎖相等和刪除鎖是兩個操作,不滿足原子性,于是可以利用 Lua 做到原子性。例如:
/*** 解鎖** @param id* @return*/ public boolean unlock(String id) {String script ="if redis.call('get',KEYS[1]) == ARGV[1] then" +" return redis.call('del',KEYS[1]) " +"else" +" return 0 " +"end";try {String result = jedis.eval(script, Collections.singletonList(LOCK_KEY), Collections.singletonList(id)).toString();return "1".equals(result) ? true : false;} finally {jedis.close();} }

大量的 key 同時過期的注意事項

  • 集中過期,由于清除大量的 key 很耗時,會出現短暫的卡頓現象
  • 解決方案:在設置 key 的過期時間的時候,給每個 key 加上隨機值

問題三:鎖過期時間到了業務沒執行完怎么辦?

  • 默認情況下,加鎖的時間是 30 秒,如果加鎖的業務沒有執行完,那么到 30-10 = 20 秒的時候,就會進行一次續期,把鎖重置成 30 秒,那這個時候可能又有同學問了,那業務的機器萬一宕機了呢?宕機了定時任務跑不了,就續不了期,那自然30秒之后鎖就解開了唄。

如何使用 Redis 做異步隊列

使用 Redis 的 List 作為隊列,RPUSH 生產消息,LPOP 消費消息

  • 缺點:沒有等待隊列里有值就直接消費
  • 彌補:可以通過在應用層引入 Sleep 機制去調用 LPOP 重試

BLPOP key [key ...] timeout:阻塞直到隊列有消息或者超時

  • 缺點:只能供一個消費者消費

pub/sub:主題訂閱者模式

  • 發送者(pub)發送消息,如:publish myTopic hello,表示向 myTopic 發布消息 hello
  • 訂閱者(sub)接收消息,如:subscribe myTopic,表示訂閱 myTopic 的消息
  • 訂閱者可以訂閱任意數量的頻道

    缺點:消息的發布是無狀態的,無法保證可達,消息還是即發即失的

使用 Pipeline 的好處

  • Redis 提供了批量操作命令(例如 mget、mset 等),有效地節約 RTT(Round Trip Time,往返時間)。但大部分命令是不支持批量操作的,例如要執行 n 次 hset 命令,并沒有 mhset 命令存在,需要消耗 n 次 RTT。
  • Pipeline(流水線)機制能改善上面這類問題,它能將一組 Redis 命令進行組裝,通過一次 RTT 傳輸給 Redis,再將這組 Redis 命令的執行結果按順序返回給客戶端。

詳情請參考:Redis 一些超好用的功能特性


Redis 過期鍵的刪除策略?

  • 定時刪除:超時時間到達時,刪除
  • 惰性刪除:再次訪問過期數據時,刪除
  • 定期刪除:每隔一定周期,刪除
  • 對于定時刪除:由于數據庫可能同時接受成千上萬個用戶的訪問,那么可能有大量的 key 需要刪除,如果我們為每一個 key 的超時時間都設置一個定時器,每次超時就進行刪除操作,那么會導致系統性能非常低。
  • 對于惰性刪除:如果一個過期 key 長期沒有被訪問,那么該 key-value 對將會一直存儲在數據庫中,會一直占有內存。而 redis 又是一個基于內存的數據庫,這樣很容易導致內存被耗盡。
  • 對于定期刪除 :redis 難以確定執行刪除操作的時長和頻率
  • 因此 redis 采用惰性刪除和定期刪除相結合的方式,來刪除系統中的過期鍵

Redis 內存淘汰機制?

  • Redis v4.0 前提供 6 種數據淘汰策略:
    • volatile-lru:利用 LRU 算法移除設置過期時間的 key(LRU:最近最少使用,Least Recently Used )
    • volatile-ttl:從已設置過期時間的數據集中挑選將要過期的數據淘汰
    • volatile-random:從已設置過期時間的數據集中任意選擇數據淘汰
    • allkeys-lru:當內存不足以容納新寫入數據時,在鍵空間中,移除最近最少使用的 key(這個是最常用的)
    • allkeys-random:當內存不足以容納新寫入數據時,從數據集中任意選擇數據淘汰
    • no-eviction:禁止驅逐數據,也就是說當內存不足以容納新寫入數據時,新寫入操作會報錯。
  • Redis v4.0 后增加以下 2 種:
    • volatile-lfu:從已設置過期時間的數據集中挑選最不經常使用的數據淘汰(LFU,Least Frequently Used)算法,也就是最頻繁被訪問的數據將來最有可能被訪問到。
    • allkeys-lfu:當內存不足以容納新寫入數據時,在鍵空間中,移除最不經常使用的 key。

Redis 持久化機制

詳情請參考:《【Redis 開發與運維】RDB 和 AOF 數據持久化》


說說緩存設計中會出現的問題和解決方案

詳情請參考:《【Redis 開發與運維】緩存設計》


高并發場景下,如何解決數據庫與緩存雙寫的時候數據不一致的情況?

Redis 中跳躍表 skiplist 實現原理

跳表(skiplist)是一個特殊的鏈表,相比一般的鏈表,有更高的查找效率,其效率可比擬于二叉查找樹。

跳表的性質:

  • 由很多層結構組成
  • 每一層都是一個有序的鏈表
  • 最底層(Level 1)的鏈表包含所有元素
  • 如果一個元素出現在 Level i 的鏈表中,則它在 Level i 之下的鏈表也都會出現
  • 每個節點包含兩個指針,一個指向同一鏈表中的下一個元素,一個指向下面一層的元素。

隨機層數的設計:

  • Redis 使用隨機層數,解決插入、刪除時,時間復雜度重新蛻化成 O(n) 的問題
  • 它不要求上下相鄰兩層鏈表之間的節點個數有嚴格的對應關系,而是為每個節點隨機出一個層數(level)。比如,一個節點隨機出的層數是 3,那么就把它鏈入到第 1 層到第 3 層這三層鏈表中。

隨機層數的計算方式:

  • 執行插入操作時計算隨機數的過程,是一個很關鍵的過程,它對 skiplist 的統計特性有著很重要的影響。這并不是一個普通的服從均勻分布的隨機數,它的計算過程如下:
    • 首先,每個節點肯定都有第 1 層指針(每個節點都在第 1 層鏈表里)。
    • 如果一個節點有第 i 層(i >= 1)指針(即節點已經在第 1 層到第 i 層鏈表中),那么它有第(i + 1)層指針的概率為 p。
    • 節點最大的層數不允許超過一個最大值,記為 MaxLevel。
  • 這個計算隨機層數的偽碼如下所示:
randomLevel()level := 1// random()返回一個[0...1)的隨機數while random() < p and level < MaxLevel dolevel := level + 1return level
  • randomLevel() 的偽碼中包含兩個參數,一個是 p,一個是 MaxLevel。在 Redis 的 skiplist 實現中,這兩個參數的取值為:
p = 1/4 MaxLevel = 32
  • 所以,根據前面 randomLevel() 的偽碼,我們很容易看出,產生越高的節點層數,概率越低。
  • 當 skiplist 中有 n 個節點的時候,它的總層數的概率均值是多少。這個問題直觀上比較好理解。根據節點的層數隨機算法,容易得出:
    • 第 1 層鏈表固定有 n 個節點;
    • 第 2 層鏈表平均有 n*p 個節點;
    • 第 3 層鏈表平均有 n*p*p 個節點;

Redis 為什么用 skiplist 而不用紅黑樹?

  • 插入、刪除、查找以及迭代輸出有序序列這幾個操作,紅黑樹也可以完成,時間復雜度跟跳表是一樣的。但是,按照區間來查找數據這個操作,紅黑樹的效率沒有跳表高,跳表可以做到 O(logn) 的時間復雜度;
  • 比起紅黑樹來說,跳表更容易代碼實現;
  • 跳表更加靈活,它可以通過改變索引構建策略有效平衡執行效率和內存消耗。

假如 Redis 里面有 1 億個key,其中有 10w 個 key 是以某個固定的已知前綴開頭的,如何將它們全部找出來?

使用 keys 指令可以掃出指定模式的 key 列表。

追問:如果這個 redis 正在給線上的業務提供服務, 那使用 keys 指令會有什么問題?

keys 指令會導致線程阻塞一段時間, 線上服務會停頓, 直到指令執行完畢, 服務才能恢復。

可以使用 SCAN cusor [MATCH patten] [COUNT count],每次只返回少量元素

  • 基于游標的迭代器,需要基于上一次的游標延續之前的迭代過程
  • 以 0 作為游標開始一次新的迭代,直到命令返回游標 0 完成一次遍歷,記得將上次返回的游標作為下次 SCAN 的游標
  • 不保證每次執行都返回某個給定數量的元素,只能是大概率符合 count 參數,支持模糊查詢
  • 可能會獲取到重復 key 的問題,需要在客戶端進行去重,比如用 HashSet 接收
  • 如:scan 0 match k1* count 10,表示將鍵為 k1 開頭的從 0 開始的游標數 10 個(10 個以內,不一定是 10 個)返回

Redis6.0 為什么要引入多線程?

  • Redis6.0 的多線程是指,將網絡數據讀寫和協議解析通過多線程的方式來處理,對于命令執行來說,仍然使用單線程操作。也就是說,Redis6.0 的多線程是為了解決其網絡 IO 的瓶頸。

Redis 集群方案應該怎么做?都有哪些方案?

詳情請參考:《【Redis 開發與運維】Redis Cluster 集群》


講一講位圖 Bitmap

詳情請參考:【Redis 開發與運維】小功能大用處


講一講 HyperLogLog

HyperLogLog,它是 LogLog 算法的升級版,作用是能夠提供不精確的去重計數。存在以下的特點:

  • 能夠使用極少的內存來統計巨量的數據,在 Redis 中實現的 HyperLogLog,只需要 12K 內存就能統計 2^64 個數據
  • 計數存在一定的誤差,誤差率整體較低,標準誤差為 0.81%
  • 誤差可以被設置輔助計算因子進行降低

為什么用 HyperLogLog,例如以下場景:

統計 APP 或網頁的一個頁面,每天有多少用戶點擊進入的次數,同一個用戶的反復點擊進入記為 1 次。

這種場景用 HashMap 這種數據結構也可以,但是假設 APP 中日活用戶達到百萬或千萬以上級別的話,采用 HashMap 的做法就會導致程序中占用大量的內存。


Redis 單線程如何處理那么多的并發客戶端連接?

因為 Redis 的線程模型:基于非阻塞的 IO 多路復用機制。多路指的是多個 Socket 連接,復用指的是復用一個線程。

Redis 采用 IO 多路復用機制同時監聽多個 Socket,多個 Socket 會產生不同的事件,不同的事件對應著不同的操作,當這些 Socket 產生了事件,IO 多路復用程序會將這些事件放到一個隊列中,通過這個隊列,以有序、同步、每次一個事件的方式向文件時間分派器中傳送。當事件處理器處理完一個事件后,IO 多路復用程序才會繼續向文件分派器傳送下一個事件。


布隆過濾器的原理

首先需要 k 個 hash 函數,每個函數可以把 key 散列成為 1 個整數;

初始化時,需要一個長度為 n 比特的數組,每個比特位初始化為 0;

某個 key 加入集合時,用 k 個 hash 函數計算出 k 個散列值,并把數組中對應的比特位置為 1;

判斷某個 key 是否在集合時,用 k 個 hash 函數計算出 k 個散列值,并查詢數組中對應的比特位,如果所有的比特位都是 1,則命中,但不一定在集合中,如果存在比特位為 0,則未命中,一定不在集合中。

優點:不需要存儲 key,節省空間

缺點:

  • 算法判斷 key 在集合中時,有一定的概率 key 其實不在集合中
  • 無法刪除

慢查詢場景有哪些?

  • 使用 O(n) 復雜度的命令,比如 keys *
  • 大對象的查詢也有可能造成慢查詢
  • 關于阻塞的原因,請參考:Redis 的噩夢:阻塞

如何保證 redis/mysql 的一致性?


巨人的肩膀:https://github.com/cosen1024/Java-Interview/blob/main/Redis/Redis.md

總結

以上是生活随笔為你收集整理的【Redis 开发与运维】总结篇的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。