溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Redis 的原理和作用是什么

發(fā)布時(shí)間:2021-06-18 16:58:29 來源:億速云 閱讀:299 作者:chen 欄目:編程語言

這篇文章主要介紹“Redis 的原理和作用是什么”,在日常操作中,相信很多人在Redis 的原理和作用是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Redis 的原理和作用是什么”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

一、Redis 基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)

1. String
Redis 里的字符串是動態(tài)字符串,會根據(jù)實(shí)際情況動態(tài)調(diào)整。類似于 Go 里面的切片-slice,如果長度不夠則自動擴(kuò)容。至于如何擴(kuò)容,方法大致如下:當(dāng) length 小于 1M 的時(shí)候,擴(kuò)容規(guī)則將目前的字符串翻倍;如果 length 大于 1M 的話,則每次只會擴(kuò)容 1M,直到達(dá)到 512M。

Redis 的原理和作用是什么

2. List
Redis 里的 List 是一個鏈表,由于鏈表本身插入和刪除比較塊,但是查詢的效率比較低,所以常常被用做異步隊(duì)列。Redis 里的 List 設(shè)計(jì)非常牛,當(dāng)數(shù)據(jù)量比較小的時(shí)候,數(shù)據(jù)結(jié)構(gòu)是壓縮鏈表,而當(dāng)數(shù)據(jù)量比較多的時(shí)候就成為了快速鏈表。

可運(yùn)用的場景:在業(yè)務(wù)中異步隊(duì)列使用 rpush/lpush 操作隊(duì)列,使用 lpop 和 rpop 出隊(duì)列,具體結(jié)構(gòu)如下圖所示:

Redis 的原理和作用是什么

3. Set

Redis 中的 set 是一個無序 Map,由于 Go 中沒有 set 結(jié)構(gòu),所以這里只能類比 Java 中的 HashSet 概念。Redis 的 set 底層也是一個 Map 結(jié)構(gòu),不同于 Java 的是:alue 是一個 NULL。由于 set 的特性,它可以用于去重邏輯,這一點(diǎn)在 Java 中也經(jīng)常使用。

可運(yùn)用場景:活動抽獎去重。

4. Hash

Redis 中的字典類型大家不陌生,也許其他語言都有這種結(jié)構(gòu)(python,Java,Go), hash 的擴(kuò)容 rehash 過程和 Go 里面的設(shè)計(jì)頗有類似,也就是維護(hù)了兩個 hash 結(jié)構(gòu),如果需要擴(kuò)容的時(shí)候,就把新的數(shù)據(jù)寫入新字典中,然后后端起一個線程來逐步遷移,總體上來說就是采用了空間換時(shí)間的思想。

可運(yùn)用場景:記錄業(yè)務(wù)中的不同用戶/不同商品/不同場景的信息:如某個用戶的名稱,或者用戶的歷史行為。

Redis 的原理和作用是什么

5. Zset
Redis 中的 zset 是一個比較特殊的數(shù)據(jù)結(jié)構(gòu)(跳躍列表),也就是我們了解到的跳表,底層由于 set 的特性保證了 value 唯一,同時(shí)也給了 value 一個得分,所謂的有序其實(shí)就是根據(jù)這個得分來排序。至于跳躍表如何插入,其實(shí)內(nèi)部采用了一個隨機(jī)策略:L0:100%-L2:50%-L3:25%-....Ln:(n-1)value/2%。

可運(yùn)用場景:榜單,總榜,熱榜。

Redis 的原理和作用是什么

二、Redis 進(jìn)階使用

1. 布隆過濾器

Redis 在 4.0 以后支持布隆過濾(準(zhǔn)確的來說是支持了布隆過濾器的插件),給 Redis 提供了強(qiáng)大的去重功能。在業(yè)務(wù)中,我們可能需要查詢數(shù)據(jù)庫判斷歷史數(shù)據(jù)是否存在,如果數(shù)據(jù)庫的并發(fā)能力有限,這個時(shí)候我們可以采用 Redis 的 set 做去重。如果緩存的數(shù)據(jù)過大,這個時(shí)候就需要遍歷所有緩存數(shù)據(jù),另外如果我們的歷史數(shù)據(jù)緩存寫不下了,終究要去查詢數(shù)據(jù)庫,這個時(shí)候就可以使用布隆過濾器。

當(dāng)然布隆過濾器精確度不是 100% 準(zhǔn)確(如果對數(shù)據(jù)準(zhǔn)確度要求很高的話,這里不建議使用),因?yàn)閷τ诖嬖诘臄?shù)據(jù)也許這個值不一定存在,當(dāng)然如果不存在,那肯定 100% 不存在了。

(1)命令使用

bf.add #添加元素bf.exists #判斷元素是否存在bf.madd #批量添加bf.mexists #批量判斷是否存在

(2)原理

Redis 的原理和作用是什么

布隆過濾的組成可以當(dāng)作一個位數(shù)組和幾個計(jì)算結(jié)果比較均勻的 hash 函數(shù),每次添加 key 的時(shí)候,會把 key 通過多次 hash 來計(jì)算所得到的位置,如果當(dāng)前位置不是 0 則表示存在??梢钥吹?,這樣的計(jì)算存在一定誤差,這也正是它的不準(zhǔn)確性問題的由來。

2. 分布式鎖

大家對分布式鎖也許也不會陌生,現(xiàn)在市面上主流的實(shí)現(xiàn)分布鎖的技術(shù)有 ZK 和 Redis;下文為大家簡單介紹一下 Redis 如何實(shí)現(xiàn)分布式鎖。

命令

setnx lock:mutex ture #加鎖del  lock:mutex #刪除鎖

實(shí)現(xiàn)分布式鎖的核心就是:請求的時(shí)候 Set 這個 key,如果其他請求設(shè)置失敗的時(shí)候,即拿不到鎖。但是存在一個問題:如果業(yè)務(wù) panic 或者忘記調(diào)用 del 的話,就會產(chǎn)生死鎖,這個時(shí)候大家很容易能想到:我們可以 expire 一個過期時(shí)間,這樣就可以保證請求不會一直獨(dú)占鎖且無法釋放鎖的邏輯了。

但是假設(shè)業(yè)務(wù)存在這樣一種情況:A 請求在獲取鎖后處理邏輯,由于邏輯過長,這個時(shí)候鎖到期釋放了,A 這個時(shí)候剛剛處理完成,而 B 又去改了這個數(shù)據(jù),這就存在一個鎖失效的問題。解決這種問題參考 CAS 的方式,對鎖設(shè)置一個隨機(jī)數(shù),可以理解為版本號,如果釋放的時(shí)候版本號不一致,則表示數(shù)字已經(jīng)在釋放那一刻改掉了。

三、深入原理

1. IO模型

Redis 是單線程模型(這里的單線程指的是 IO 和鍵值對的讀寫是一個線程完成的),當(dāng)然如果嚴(yán)謹(jǐn)?shù)膩碚f還是可以理解為是多線程,不過這樣的多線程不過是在數(shù)據(jù)備份的時(shí)候會 fork 一個子進(jìn)程對數(shù)據(jù)進(jìn)行從磁盤讀取數(shù)據(jù)并組裝 RDB,然后同步給 slaver 節(jié)點(diǎn)的操作,當(dāng)然包括備份和持久化也都是通過另外起線程完成的,所以我們可以把 Redis 認(rèn)作為一個單線程模型。

那么問題來了,為什么單線程的模型能這么快?原因很簡單,因?yàn)?Redis 本身就是在內(nèi)存中運(yùn)算,而對于上游的客戶端請求,采用了多路復(fù)用的原理。Redis 會給每一個客戶端套接字都關(guān)聯(lián)一個指令隊(duì)列,客戶端的指令隊(duì)列通過隊(duì)列排隊(duì)來進(jìn)行順序處理,同時(shí) Reids 給每一個客戶端的套件字關(guān)聯(lián)一個響應(yīng)隊(duì)列,Redis 服務(wù)器通過響應(yīng)隊(duì)列來將指令的接口返回給客戶端。

Redis 的原理和作用是什么

2. 通信協(xié)議

Redis 采用了 Gossip 協(xié)議作為通信協(xié)議。Gossip 是一種傳播消息的方式,可以類比為瘟疫或者流感的傳播方式,使用 Gossip 協(xié)議的有:Redis Cluster、Consul、Apache Cassandra 等。Gossip 協(xié)議類似病毒擴(kuò)散的方式,將信息傳播到其他的節(jié)點(diǎn),這種協(xié)議效率很高,只需要廣播到附近節(jié)點(diǎn),然后被廣播的節(jié)點(diǎn)繼續(xù)做同樣的操作即可。當(dāng)然這種協(xié)議也有一個弊端就是:會存在浪費(fèi),哪怕一個節(jié)點(diǎn)之前被通知到了,下次被廣播后仍然會重復(fù)轉(zhuǎn)發(fā)。

Redis 的原理和作用是什么

3. 持久化

(1)RDB

RDB 是對當(dāng)前 Redis 的存儲數(shù)據(jù)進(jìn)行一次快照(具體原理和如何做,限于篇幅這里不做過多復(fù)述了)。

(2)AOF

日志只記錄 Redis 對內(nèi)存修改的指令記錄,Redis 提供了一個 bgrewriteaif 的指令對 AOF 進(jìn)行壓縮。原理就是:開辟一個子進(jìn)程對內(nèi)存進(jìn)行遍歷后,轉(zhuǎn)換成一系列對 Redis 的操作指令,序列化到一個新的 AOF 日志文件中。系列化完成后再將發(fā)送的增量 AOF 日志追加到這個新的 AOF 日志中,追加完成后用新的 AOF 日志代替舊的。

(3)混合持久化

由于單純 RDB 的話,可能存在數(shù)據(jù)的丟失,而頻繁的 AOF 又會影響了性能,在 Redis 4.0 之后,支持了混合持久化,也就是每次啟動時(shí)候通過 RDB+增量的 AOF 文件來進(jìn)行回復(fù),由于增量的 AOF 僅記錄了開始持久化到持久化結(jié)束期間發(fā)生的增量,這樣日志不會太大,性能相對較高。

4. 主從同步

Redis 的同步方式有:主從同步、從從同步(由于全部都由 master 同步的話,會損耗性能,所以部分的 slave 會通過 slave 之間進(jìn)行同步)。

Redis 的原理和作用是什么

同步過程:

  • 建立連接,然后從庫告訴主庫:“我要同步啦,你給我準(zhǔn)備好”,然后主庫跟從庫說:“收到”。

  • 從庫拿到數(shù)據(jù)后,要把數(shù)據(jù)保存到庫里。這個時(shí)候就會在本地完成數(shù)據(jù)的加載,會用到 RDB 。

  • 主庫把新來的數(shù)據(jù) AOF 同步給從庫。

5. Sentine

Redis 的主從切換是通過哨兵來解決的。這里哨兵主要解決的問題就是:當(dāng) master 掛了的情況下,如果在短時(shí)間內(nèi)重新選舉出一個新的 master 。

Redis 的原理和作用是什么

Sentinel 集群是一個由 3-5 個(可以更多)節(jié)點(diǎn)組成的,用來監(jiān)聽整個 Redis 的集群,如果發(fā)現(xiàn) master 不可用的時(shí)候,會關(guān)閉和斷開全部的與 master 相連的舊鏈接。這個時(shí)候 Sentinel 會完成選舉和故障轉(zhuǎn)移,新的請求則會轉(zhuǎn)到新到 master 中。

6. Redis集群工作原理

Redis 集群通過槽指派機(jī)制來決定寫命令應(yīng)該被分配到那個節(jié)點(diǎn)。整個集群對應(yīng)的槽是由 16384 大小的二進(jìn)制數(shù)組組成,集群中每個主節(jié)點(diǎn)分配一部分槽,每條寫命令落到二進(jìn)制數(shù)組中的某個位置,該位置被分配給了哪個節(jié)點(diǎn),則對應(yīng)的命令就由該節(jié)點(diǎn)去執(zhí)行。槽指派對應(yīng)的二進(jìn)制數(shù)組如下圖所示:

Redis 的原理和作用是什么

從上圖可以看到:節(jié)點(diǎn) 1 只負(fù)責(zé) 執(zhí)行 0 - 4999 的槽位,而節(jié)點(diǎn) 2 負(fù)責(zé)執(zhí)行 5000 - 9999,節(jié)點(diǎn) 3 執(zhí)行 9999- 16383 。當(dāng)進(jìn)行寫的時(shí)候:

set key value

命令通過 CRC16(key) & 16383 = 6789(假設(shè)結(jié)果),由于節(jié)點(diǎn) 2 負(fù)責(zé) 5000~9999 的槽位,則該命令的結(jié)果 6789 最終由節(jié)點(diǎn) 2 執(zhí)行。當(dāng)然如果在節(jié)點(diǎn) 2 執(zhí)行一條命令時(shí),假設(shè)通過 CRC 計(jì)算后得到的值為 567,則其應(yīng)該由節(jié)點(diǎn) 1 執(zhí)行,此時(shí)命令會進(jìn)行轉(zhuǎn)向操作,將要執(zhí)行的命令流轉(zhuǎn)到節(jié)點(diǎn) 1 上去執(zhí)行。

Redis 的原理和作用是什么

集群節(jié)點(diǎn)同步:
集群中每個主節(jié)點(diǎn)都會定時(shí)發(fā)送信息到其他主節(jié)點(diǎn)進(jìn)行同步,如果其他主節(jié)點(diǎn)在規(guī)定時(shí)間內(nèi)響應(yīng)了發(fā)送消息的主節(jié)點(diǎn),則發(fā)送消息的主節(jié)點(diǎn)認(rèn)為響應(yīng)了消息的主節(jié)點(diǎn)正常,反之則認(rèn)為響應(yīng)消息的主節(jié)點(diǎn)疑似下線,則發(fā)送消息的主節(jié)點(diǎn)在其節(jié)點(diǎn)上將其標(biāo)記“疑似下線”。

當(dāng)集群中超過一半以上的節(jié)點(diǎn)認(rèn)為某個主節(jié)點(diǎn)被標(biāo)記為“疑似下線”,則其中某個主節(jié)點(diǎn)將疑似下線節(jié)點(diǎn)標(biāo)記為下線狀態(tài),并向集群廣播一條下線消息,當(dāng)下線節(jié)點(diǎn)對應(yīng)的從節(jié)點(diǎn)接收到該消息時(shí),則從從節(jié)點(diǎn)中選舉出一個節(jié)點(diǎn)作為主節(jié)點(diǎn)繼續(xù)對外提供服務(wù)。

四、Redis為什么變慢了

業(yè)務(wù)場景中,不知道大家是否碰到過 Redis 變慢的情況:

  • 執(zhí)行 SET、DEL 命令耗時(shí)也很久;

  • 偶現(xiàn)卡頓,之后又恢復(fù)正常了;

  • 在某個時(shí)間點(diǎn),突然開始變慢了。

原因分析

查看慢查詢,由于筆者本身機(jī)器沒有慢查詢,所以這里看到是空(實(shí)在尷尬,這里沒有可用的例子~~)

Redis 的原理和作用是什么

  • 由于 Redis 在 IO 操作和對鍵值對的操作是單線程的,所以直接在客戶端 Redis-cli 上執(zhí)行的 Redis 命令有可能會導(dǎo)致操作延遲變大;

  • 使用復(fù)雜的命令會讓 Redis的處理變慢,以及CPU過高,例如 SORT、SUNION、ZUNIONSTORE 聚合類命令(時(shí)間負(fù)責(zé)度O(N) );

  • 查詢的數(shù)據(jù)量過大,使得更多時(shí)間花費(fèi)在數(shù)據(jù)協(xié)議的組裝和網(wǎng)絡(luò)傳輸過程中;

  • 大 key 查詢,比如對于一個很大的 hash、zset 等,這樣的對象對 Redis 的集群數(shù)據(jù)遷移帶來了很大的問題,因?yàn)樵诩涵h(huán)境下,如果某個 key 太大,會導(dǎo)致數(shù)據(jù)遷移卡頓;

  • 另外在內(nèi)存分配上,如果一個 key 太大,那么當(dāng)它需要擴(kuò)容時(shí),會一次性申請更大的一塊內(nèi)存,這也會導(dǎo)致卡頓。如果這個大 key 被刪除,內(nèi)存會一次性回收,卡頓現(xiàn)象會再一次產(chǎn)生。

  • 集中過期,變慢的時(shí)間統(tǒng)一,所以業(yè)務(wù)中的 Key 過期時(shí)間盡量在統(tǒng)一的一個時(shí)間點(diǎn)加上一個隨機(jī)數(shù)時(shí)間;

  • 內(nèi)存使用達(dá)到上限,當(dāng)內(nèi)存達(dá)到內(nèi)存上限的時(shí)候,就不許淘汰一些數(shù)據(jù),這個時(shí)候也可能導(dǎo)致 Redis 查詢效率低;

  • 碎片整理,Redis 在 4.0 版本后會自動整理碎片(由于內(nèi)存回收過程中存在大量的碎片空間,不整理會導(dǎo)致 Redis 的空間少量浪費(fèi)),而在整理碎片的過程中會消耗 CPU 的資源,從而影響了請求得到性能;

  • 網(wǎng)絡(luò)帶寬,Redis 集群和業(yè)務(wù)混部,或者并發(fā)量過大以及每次返回的數(shù)據(jù)也很大,網(wǎng)卡帶寬跑滿的情況容易導(dǎo)致網(wǎng)絡(luò)阻塞;

  • AOF 的頻率過高,由于 AOF 需要將全部的寫命令同步,如果同步的間隔比較短,也會影響到 Redis 的性能;

  • Redis 提供了 flushdb 和 flushall 指令,用來清空數(shù)據(jù)庫,這也是導(dǎo)致 Redis 緩慢的操作。

五、Redis安全

默認(rèn)會監(jiān)聽 6379 端口,最好在 Redis 的配置文件中指定監(jiān)聽的 IP 地址,更進(jìn)一步還可以增加 Redis 的 ACL 訪問控制,對客戶指定群組,并限限制用戶對數(shù)據(jù)的讀寫權(quán)限。

訪問 Redis 盡量走公司代理,由于 Redis 本身不支持 SSL 的鏈接,所以走公司代理可以保證安全??蛻舳说顷?Redis 必須設(shè)置 Auth 秘密登陸。

到此,關(guān)于“Redis 的原理和作用是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI