共計 6598 個字符,預計需要花費 17 分鐘才能閱讀完成。
本篇內(nèi)容主要講解“怎么快速掌握 Redis 數(shù)據(jù)庫”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓丸趣 TV 小編來帶大家學習“怎么快速掌握 Redis 數(shù)據(jù)庫”吧!
Redis 基本數(shù)據(jù)類型
1. 字符串:redis 沒有直接使用 C 語言傳統(tǒng)的字符串表示,而是自己實現(xiàn)的叫做簡單動態(tài)字符串 SDS 的抽象類型。C 語言的字符串不記錄自身的長度信息,而 SDS 則保存了長度信息,這樣將獲取字符串長度的時間由 O(N)降低到了 O(1),同時可以避免緩沖區(qū)溢出和減少修改字符串長度時所需的內(nèi)存重分配次數(shù)。
2. 鏈表 linkedlist:redis 鏈表是一個雙向無環(huán)鏈表結(jié)構(gòu),很多發(fā)布訂閱、慢查詢、監(jiān)視器功能都是使用到了鏈表來實現(xiàn),每個鏈表的節(jié)點由一個 listNode 結(jié)構(gòu)來表示,每個節(jié)點都有指向前置節(jié)點和后置節(jié)點的指針,同時表頭節(jié)點的前置和后置節(jié)點都指向 NULL。
3. 字典 hashtable:用于保存鍵值對的抽象數(shù)據(jù)結(jié)構(gòu)。redis 使用 hash 表作為底層實現(xiàn),每個字典帶有兩個 hash 表,供平時使用和 rehash 時使用,hash 表使用鏈地址法來解決鍵沖突,被分配到同一個索引位置的多個鍵值對會形成一個單向鏈表,在對 hash 表進行擴容或者縮容的時候,為了服務的可用性,rehash 的過程不是一次性完成的,而是漸進式的。
4. 跳躍表 skiplist:跳躍表是有序集合的底層實現(xiàn)之一,redis 中在實現(xiàn)有序集合鍵和集群節(jié)點的內(nèi)部結(jié)構(gòu)中都是用到了跳躍表。redis 跳躍表由 zskiplist 和 zskiplistNode 組成,zskiplist 用于保存跳躍表信息(表頭、表尾節(jié)點、長度等),zskiplistNode 用于表示表跳躍節(jié)點,每個跳躍表的層高都是 1 -32 的隨機數(shù),在同一個跳躍表中,多個節(jié)點可以包含相同的分值,但是每個節(jié)點的成員對象必須是唯一的,節(jié)點按照分值大小排序,如果分值相同,則按照成員對象的大小排序。
5. 整數(shù)集合 intset:用于保存整數(shù)值的集合抽象數(shù)據(jù)結(jié)構(gòu),不會出現(xiàn)重復元素,底層實現(xiàn)為數(shù)組。
6. 壓縮列表 ziplist:壓縮列表是為節(jié)約內(nèi)存而開發(fā)的順序性數(shù)據(jù)結(jié)構(gòu),他可以包含多個節(jié)點,每個節(jié)點可以保存一個字節(jié)數(shù)組或者整數(shù)值。
基于這些基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu),redis 封裝了自己的對象系統(tǒng),包含字符串對象 string、列表對象 list、哈希對象 hash、集合對象 set、有序集合對象 zset,每種對象都用到了至少一種基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu)。
redis 通過 encoding 屬性設置對象的編碼形式來提升靈活性和效率,基于不同的場景 redis 會自動做出優(yōu)化。不同對象的編碼如下:
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS 技術(shù)社區(qū)
字符串對象 string:int 整數(shù)、embstr 編碼的簡單動態(tài)字符串、raw 簡單動態(tài)字符串
列表對象 list:ziplist、linkedlist
哈希對象 hash:ziplist、hashtable
集合對象 set:intset、hashtable
有序集合對象 zset:ziplist、skiplist
Redis 為什么快呢?
redis 的速度非常的快,單機的 redis 就可以支撐每秒 10 幾萬的并發(fā),相對于 mysql 來說,性能是 mysql 的幾十倍。速度快的原因主要有幾點:
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS 技術(shù)社區(qū)
完全基于內(nèi)存操作
C 語言實現(xiàn),優(yōu)化過的數(shù)據(jù)結(jié)構(gòu),基于幾種基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu),redis 做了大量的優(yōu)化,性能極高
使用單線程,無上下文的切換成本
基于非阻塞的 IO 多路復用機制
那為什么 Redis6.0 之后又改用多線程呢?
redis 使用多線程并非是完全摒棄單線程,redis 還是使用單線程模型來處理客戶端的請求,只是使用多線程來處理數(shù)據(jù)的讀寫和協(xié)議解析,執(zhí)行命令還是使用單線程。
這樣做的目的是因為 redis 的性能瓶頸在于網(wǎng)絡 IO 而非 CPU,使用多線程能提升 IO 讀寫的效率,從而整體提高 redis 的性能。
知道什么是熱 key 嗎?熱 key 問題怎么解決?
所謂熱 key 問題就是,突然有幾十萬的請求去訪問 redis 上的某個特定 key,那么這樣會造成流量過于集中,達到物理網(wǎng)卡上限,從而導致這臺 redis 的服務器宕機引發(fā)雪崩。
針對熱 key 的解決方案:
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS 技術(shù)社區(qū)
提前把熱 key 打散到不同的服務器,降低壓力
加入二級緩存,提前加載熱 key 數(shù)據(jù)到內(nèi)存中,如果 redis 宕機,走內(nèi)存查詢
什么是緩存擊穿、緩存穿透、緩存雪崩?
緩存擊穿
緩存擊穿的概念就是單個 key 并發(fā)訪問過高,過期時導致所有請求直接打到 db 上,這個和熱 key 的問題比較類似,只是說的點在于過期導致請求全部打到 DB 上而已。
解決方案:
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS 技術(shù)社區(qū)
加鎖更新,比如請求查詢 A,發(fā)現(xiàn)緩存中沒有,對 A 這個 key 加鎖,同時去數(shù)據(jù)庫查詢數(shù)據(jù),寫入緩存,再返回給用戶,這樣后面的請求就可以從緩存中拿到數(shù)據(jù)了。
將過期時間組合寫在 value 中,通過異步的方式不斷的刷新過期時間,防止此類現(xiàn)象。
https://tva
緩存穿透
緩存穿透是指查詢不存在緩存中的數(shù)據(jù),每次請求都會打到 DB,就像緩存不存在一樣。
針對這個問題,加一層布隆過濾器。布隆過濾器的原理是在你存入數(shù)據(jù)的時候,會通過散列函數(shù)將它映射為一個位數(shù)組中的 K 個點,同時把他們置為 1。
這樣當用戶再次來查詢 A,而 A 在布隆過濾器值為 0,直接返回,就不會產(chǎn)生擊穿請求打到 DB 了。
顯然,使用布隆過濾器之后會有一個問題就是誤判,因為它本身是一個數(shù)組,可能會有多個值落到同一個位置,那么理論上來說只要我們的數(shù)組長度夠長,誤判的概率就會越低,這種問題就根據(jù)實際情況來就好了。
緩存雪崩
當某一時刻發(fā)生大規(guī)模的緩存失效的情況,比如你的緩存服務宕機了,會有大量的請求進來直接打到 DB 上,這樣可能導致整個系統(tǒng)的崩潰,稱為雪崩。雪崩和擊穿、熱 key 的問題不太一樣的是,他是指大規(guī)模的緩存都過期失效了。
針對雪崩幾個解決方案:
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS 技術(shù)社區(qū)
針對不同 key 設置不同的過期時間,避免同時過期
限流,如果 redis 宕機,可以限流,避免同時刻大量請求打崩 DB
二級緩存,同熱 key 的方案。
Redis 的過期策略有哪些?
redis 主要有 2 種過期刪除策略
惰性刪除
惰性刪除指的是當我們查詢 key 的時候才對 key 進行檢測,如果已經(jīng)達到過期時間,則刪除。顯然,他有一個缺點就是如果這些過期的 key 沒有被訪問,那么他就一直無法被刪除,而且一直占用內(nèi)存。
定期刪除
定期刪除指的是 redis 每隔一段時間對數(shù)據(jù)庫做一次檢查,刪除里面的過期 key。由于不可能對所有 key 去做輪詢來刪除,所以 redis 會每次隨機取一些 key 去做檢查和刪除。
那么定期 + 惰性都沒有刪除過期的 key 怎么辦?
假設 redis 每次定期隨機查詢 key 的時候沒有刪掉,這些 key 也沒有做查詢的話,就會導致這些 key 一直保存在 redis 里面無法被刪除,這時候就會走到 redis 的內(nèi)存淘汰機制。
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS 技術(shù)社區(qū)
volatile-lru:從已設置過期時間的 key 中,移出最近最少使用的 key 進行淘汰
volatile-ttl:從已設置過期時間的 key 中,移出將要過期的 key
volatile-random:從已設置過期時間的 key 中隨機選擇 key 淘汰
allkeys-lru:從 key 中選擇最近最少使用的進行淘汰
allkeys-random:從 key 中隨機選擇 key 進行淘汰
noeviction:當內(nèi)存達到閾值的時候,新寫入操作報錯
持久化方式有哪些?有什么區(qū)別?
redis 持久化方案分為 RDB 和 AOF 兩種。
RDB
RDB 持久化可以手動執(zhí)行也可以根據(jù)配置定期執(zhí)行,它的作用是將某個時間點上的數(shù)據(jù)庫狀態(tài)保存到 RDB 文件中,RDB 文件是一個壓縮的二進制文件,通過它可以還原某個時刻數(shù)據(jù)庫的狀態(tài)。由于 RDB 文件是保存在硬盤上的,所以即使 redis 崩潰或者退出,只要 RDB 文件存在,就可以用它來恢復還原數(shù)據(jù)庫的狀態(tài)。
可以通過 SAVE 或者 BGSAVE 來生成 RDB 文件。
SAVE 命令會阻塞 redis 進程,直到 RDB 文件生成完畢,在進程阻塞期間,redis 不能處理任何命令請求,這顯然是不合適的。
BGSAVE 則是會 fork 出一個子進程,然后由子進程去負責生成 RDB 文件,父進程還可以繼續(xù)處理命令請求,不會阻塞進程。
AOF
AOF 和 RDB 不同,AOF 是通過保存 redis 服務器所執(zhí)行的寫命令來記錄數(shù)據(jù)庫狀態(tài)的。
AOF 通過追加、寫入、同步三個步驟來實現(xiàn)持久化機制。
當 AOF 持久化處于激活狀態(tài),服務器執(zhí)行完寫命令之后,寫命令將會被追加 append 到 aof_buf 緩沖區(qū)的末尾
在服務器每結(jié)束一個事件循環(huán)之前,將會調(diào)用 flushAppendOnlyFile 函數(shù)決定是否要將 aof_buf 的內(nèi)容保存到 AOF 文件中,可以通過配置 appendfsync 來決定。
always ##aof_buf 內(nèi)容寫入并同步到 AOF 文件 everysec ##將 aof_buf 中內(nèi)容寫入到 AOF 文件,如果上次同步 AOF 文件時間距離現(xiàn)在超過 1 秒,則再次對 AOF 文件進行同步 no ## 將 aof_buf 內(nèi)容寫入 AOF 文件,但是并不對 AOF 文件進行同步,同步時間由操作系統(tǒng)決定
如果不設置,默認選項將會是 everysec,因為 always 來說雖然最安全(只會丟失一次事件循環(huán)的寫命令),但是性能較差,而 everysec 模式只不過會可能丟失 1 秒鐘的數(shù)據(jù),而 no 模式的效率和 everysec 相仿,但是會丟失上次同步 AOF 文件之后的所有寫命令數(shù)據(jù)。
怎么實現(xiàn) Redis 的高可用?
要想實現(xiàn)高可用,一臺機器肯定是不夠的,而 redis 要保證高可用,有 2 個可選方案。
主從架構(gòu)
主從模式是最簡單的實現(xiàn)高可用的方案,核心就是主從同步。主從同步的原理如下:
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS 技術(shù)社區(qū)
slave 發(fā)送 sync 命令到 master
master 收到 sync 之后,執(zhí)行 bgsave,生成 RDB 全量文件
master 把 slave 的寫命令記錄到緩存
bgsave 執(zhí)行完畢之后,發(fā)送 RDB 文件到 slave,slave 執(zhí)行
master 發(fā)送緩存中的寫命令到 slave,slave 執(zhí)行
這里我寫的這個命令是 sync,但是在 redis2.8 版本之后已經(jīng)使用 psync 來替代 sync 了,原因是 sync 命令非常消耗系統(tǒng)資源,而 psync 的效率更高。
哨兵
基于主從方案的缺點還是很明顯的,假設 master 宕機,那么就不能寫入數(shù)據(jù),那么 slave 也就失去了作用,整個架構(gòu)就不可用了,除非你手動切換,主要原因就是因為沒有自動故障轉(zhuǎn)移機制。而哨兵 (sentinel) 的功能比單純的主從架構(gòu)全面的多了,它具備自動故障轉(zhuǎn)移、集群監(jiān)控、消息通知等功能。
哨兵可以同時監(jiān)視多個主從服務器,并且在被監(jiān)視的 master 下線時,自動將某個 slave 提升為 master,然后由新的 master 繼續(xù)接收命令。整個過程如下:
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS 技術(shù)社區(qū)
初始化 sentinel,將普通的 redis 代碼替換成 sentinel 專用代碼
初始化 masters 字典和服務器信息,服務器信息主要保存 ip:port,并記錄實例的地址和 ID
創(chuàng)建和 master 的兩個連接,命令連接和訂閱連接,并且訂閱 sentinel:hello 頻道
每隔 10 秒向 master 發(fā)送 info 命令,獲取 master 和它下面所有 slave 的當前信息
當發(fā)現(xiàn) master 有新的 slave 之后,sentinel 和新的 slave 同樣建立兩個連接,同時每個 10 秒發(fā)送 info 命令,更新 master 信息
sentinel 每隔 1 秒向所有服務器發(fā)送 ping 命令,如果某臺服務器在配置的響應時間內(nèi)連續(xù)返回無效回復,將會被標記為下線狀態(tài)
選舉出領(lǐng)頭 sentinel,領(lǐng)頭 sentinel 需要半數(shù)以上的 sentinel 同意
領(lǐng)頭 sentinel 從已下線的的 master 所有 slave 中挑選一個,將其轉(zhuǎn)換為 master
讓所有的 slave 改為從新的 master 復制數(shù)據(jù)
將原來的 master 設置為新的 master 的從服務器,當原來 master 重新回復連接時,就變成了新 master 的從服務器
sentinel 會每隔 1 秒向所有實例(包括主從服務器和其他 sentinel)發(fā)送 ping 命令,并且根據(jù)回復判斷是否已經(jīng)下線,這種方式叫做主觀下線。當判斷為主觀下線時,就會向其他監(jiān)視的 sentinel 詢問,如果超過半數(shù)的投票認為已經(jīng)是下線狀態(tài),則會標記為客觀下線狀態(tài),同時觸發(fā)故障轉(zhuǎn)移。
能說說 redis 集群的原理嗎?
如果說依靠哨兵可以實現(xiàn) redis 的高可用,如果還想在支持高并發(fā)同時容納海量的數(shù)據(jù),那就需要 redis 集群。redis 集群是 redis 提供的分布式數(shù)據(jù)存儲方案,集群通過數(shù)據(jù)分片 sharding 來進行數(shù)據(jù)的共享,同時提供復制和故障轉(zhuǎn)移的功能。
節(jié)點
一個 redis 集群由多個節(jié)點 node 組成,而多個 node 之間通過 cluster meet 命令來進行連接,節(jié)點的握手過程:
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS 技術(shù)社區(qū)
節(jié)點 A 收到客戶端的 cluster meet 命令
A 根據(jù)收到的 IP 地址和端口號,向 B 發(fā)送一條 meet 消息
節(jié)點 B 收到 meet 消息返回 pong
A 知道 B 收到了 meet 消息,返回一條 ping 消息,握手成功
最后,節(jié)點 A 將會通過 gossip 協(xié)議把節(jié)點 B 的信息傳播給集群中的其他節(jié)點,其他節(jié)點也將和 B 進行握手
槽 slot
redis 通過集群分片的形式來保存數(shù)據(jù),整個集群數(shù)據(jù)庫被分為 16384 個 slot,集群中的每個節(jié)點可以處理 0 -16384 個 slot,當數(shù)據(jù)庫 16384 個 slot 都有節(jié)點在處理時,集群處于上線狀態(tài),反之只要有一個 slot 沒有得到處理都會處理下線狀態(tài)。通過 cluster addslots 命令可以將 slot 指派給對應節(jié)點處理。
slot 是一個位數(shù)組,數(shù)組的長度是 16384/8=2048,而數(shù)組的每一位用 1 表示被節(jié)點處理,0 表示不處理,如圖所示的話表示 A 節(jié)點處理 0 - 7 的 slot。
當客戶端向節(jié)點發(fā)送命令,如果剛好找到 slot 屬于當前節(jié)點,那么節(jié)點就執(zhí)行命令,反之,則會返回一個 MOVED 命令到客戶端指引客戶端轉(zhuǎn)向正確的節(jié)點。(MOVED 過程是自動的)
如果增加或者移出節(jié)點,對于 slot 的重新分配也是非常方便的,redis 提供了工具幫助實現(xiàn) slot 的遷移,整個過程是完全在線的,不需要停止服務。
故障轉(zhuǎn)移
如果節(jié)點 A 向節(jié)點 B 發(fā)送 ping 消息,節(jié)點 B 沒有在規(guī)定的時間內(nèi)響應 pong,那么節(jié)點 A 會標記節(jié)點 B 為 pfail 疑似下線狀態(tài),同時把 B 的狀態(tài)通過消息的形式發(fā)送給其他節(jié)點,如果超過半數(shù)以上的節(jié)點都標記 B 為 pfail 狀態(tài),B 就會被標記為 fail 下線狀態(tài),此時將會發(fā)生故障轉(zhuǎn)移,優(yōu)先從復制數(shù)據(jù)較多的從節(jié)點選擇一個成為主節(jié)點,并且接管下線節(jié)點的 slot,整個過程和哨兵非常類似,都是基于 Raft 協(xié)議做選舉。
了解 Redis 事務機制嗎?
redis 通過 MULTI、EXEC、WATCH 等命令來實現(xiàn)事務機制,事務執(zhí)行過程將一系列多個命令按照順序一次性執(zhí)行,并且在執(zhí)行期間,事務不會被中斷,也不會去執(zhí)行客戶端的其他請求,直到所有命令執(zhí)行完畢。事務的執(zhí)行過程如下:
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS 技術(shù)社區(qū)
服務端收到客戶端請求,事務以 MULTI 開始
如果客戶端正處于事務狀態(tài),則會把事務放入隊列同時返回給客戶端 QUEUED,反之則直接執(zhí)行這個命令
當收到客戶端 EXEC 命令時,WATCH 命令監(jiān)視整個事務中的 key 是否有被修改,如果有則返回空回復到客戶端表示失敗,否則 redis 會遍歷整個事務隊列,執(zhí)行隊列中保存的所有命令,最后返回結(jié)果給客戶端
WATCH 的機制本身是一個 CAS 的機制,被監(jiān)視的 key 會被保存到一個鏈表中,如果某個 key 被修改,那么 REDIS_DIRTY_CAS 標志將會被打開,這時服務器會拒絕執(zhí)行事務。
到此,相信大家對“怎么快速掌握 Redis 數(shù)據(jù)庫”有了更深的了解,不妨來實際操作一番吧!這里是丸趣 TV 網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學習!