您好,登錄后才能下訂單哦!
這篇文章主要講解了“Redis的異步機(jī)制是什么”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“Redis的異步機(jī)制是什么”吧!
和 Redis 實(shí)例交互的對(duì)象,以及交互時(shí)會(huì)發(fā)生的操作:
客戶端:網(wǎng)絡(luò) IO,鍵值對(duì)增刪改查操作,數(shù)據(jù)庫(kù)操作;
磁盤(pán):生成 RDB 快照,記錄 AOF 日志,AOF 日志重寫(xiě);
主從節(jié)點(diǎn):主庫(kù)生成、傳輸 RDB 文件,從庫(kù)接收 RDB 文件、清空數(shù)據(jù)庫(kù)、加載 RDB 文件;
切片集群實(shí)例:向其他實(shí)例傳輸哈希槽信息,數(shù)據(jù)遷移。
和客戶端交互時(shí)的阻塞點(diǎn):
網(wǎng)絡(luò) IO 有時(shí)候會(huì)比較慢,但是 Redis 使用了 IO 多路復(fù)用機(jī)制,避免了主線程一直處在等待網(wǎng)絡(luò)連接或請(qǐng)求到來(lái)的狀態(tài),所以網(wǎng)絡(luò) IO 不是導(dǎo)致 Redis 阻塞的因素。
鍵值對(duì)的增刪改查操作是 Redis 和客戶端交互的主要部分,也是 Redis 主線程執(zhí)行的主要任務(wù)。復(fù)雜度高的增刪改查操作肯定會(huì)阻塞 Redis。
判斷操作復(fù)雜度高低的標(biāo)準(zhǔn):看操作的復(fù)雜度是否為 O(N)。
Redis 的第一個(gè)阻塞點(diǎn):集合全量查詢和聚合操作:
Redis 中涉及集合的操作復(fù)雜度通常為 O(N),使用時(shí)需重視起來(lái)。
例如集合元素全量查詢操作 HGETALL、SMEMBERS,以及集合的聚合統(tǒng)計(jì)操作,例如求交、并和差集。
Redis 的第二個(gè)阻塞點(diǎn) :bigkey 刪除操作
集合自身的刪除操作同樣也有潛在的阻塞風(fēng)險(xiǎn)。刪除操作的本質(zhì)是要釋放鍵值對(duì)占用的內(nèi)存空間。 釋放內(nèi)存只是第一步,為了更加高效地管理內(nèi)存空間,在應(yīng)用程序釋放內(nèi)存時(shí),操作系統(tǒng)需要把釋放掉的內(nèi)存塊插入一個(gè)空閑內(nèi)存塊的鏈表,以便后續(xù)進(jìn)行管理和再分配。
這個(gè)過(guò)程本身需要一定時(shí)間,而且會(huì)阻塞當(dāng)前釋放內(nèi)存的應(yīng)用程序,如果一下子釋放了大量?jī)?nèi)存,空閑內(nèi)存塊鏈表操作時(shí)間就會(huì)增加,相應(yīng)地就會(huì)造成 Redis 主線程的阻塞。
釋放大量?jī)?nèi)存的時(shí)機(jī):在刪除大量鍵值對(duì)數(shù)據(jù)的時(shí)候,刪除包含了大量元素的集合,也稱(chēng)為 bigkey 刪除。
不同元素?cái)?shù)量的集合在進(jìn)行刪除操作時(shí)所消耗的時(shí)間:
得出三個(gè)結(jié)論:
當(dāng)元素?cái)?shù)量從 10 萬(wàn)增加到 100 萬(wàn)時(shí),4 大集合類(lèi)型的刪除時(shí)間的增長(zhǎng)幅度從 5 倍上升到了近 20 倍;
集合元素越大,刪除所花費(fèi)的時(shí)間就越長(zhǎng);
當(dāng)刪除有 100 萬(wàn)個(gè)元素的集合時(shí),最大的刪除時(shí)間絕對(duì)值已經(jīng)達(dá)到了 1.98s(Hash 類(lèi) 型)。Redis 的響應(yīng)時(shí)間一般在微秒級(jí)別,一個(gè)操作達(dá)到了近 2s,不可避免地會(huì)阻塞主線程。
Redis 的第三個(gè)阻塞點(diǎn):清空數(shù)據(jù)庫(kù)
既然頻繁刪除鍵值對(duì)都是潛在的阻塞點(diǎn)了,在 Redis 的數(shù)據(jù)庫(kù)級(jí)別操作中,清空數(shù)據(jù)庫(kù)(例如 FLUSHDB 和 FLUSHALL 操作)也是一個(gè)潛在的阻塞風(fēng)險(xiǎn),因?yàn)樗婕暗絼h除和釋放所有的鍵值對(duì)。
Redis 的第四個(gè)阻塞點(diǎn):AOF 日志同步寫(xiě)
磁盤(pán) IO 一般都是比較費(fèi)時(shí)費(fèi)力的,需要重點(diǎn)關(guān)注。 Redis 開(kāi)發(fā)者早已認(rèn)識(shí)到磁盤(pán) IO 會(huì)帶來(lái)阻塞,所以把 Redis 設(shè)計(jì)為采用子進(jìn)程的方式生成 RDB 快照文件、執(zhí)行 AOF 日志重寫(xiě)操作。由子進(jìn)程負(fù)責(zé)執(zhí)行,慢速的磁盤(pán) IO 就不會(huì)阻塞主線程了。
Redis 直接記錄 AOF 日志時(shí),會(huì)根據(jù)不同的寫(xiě)回策略對(duì)數(shù)據(jù)做落盤(pán)保存。一個(gè)同步寫(xiě)磁盤(pán)的操作的耗時(shí)大約是 1~2ms,如果有大量的寫(xiě)操作需要記錄在 AOF 日志中,并同步寫(xiě)回的話,會(huì)阻塞主線程。
Redis 的第五個(gè)阻塞點(diǎn):從庫(kù)加載 RDB 文件
在主從集群中,主庫(kù)需要生成 RDB 文件,并傳輸給從庫(kù)。
主庫(kù)在復(fù)制的過(guò)程中,創(chuàng)建和傳輸 RDB 文件都是由子進(jìn)程來(lái)完成的,不會(huì)阻塞主線程。
但是從庫(kù)在接收了 RDB 文件后,需要使用 FLUSHDB 命令清空當(dāng)前數(shù)據(jù)庫(kù),正好撞上了第三個(gè)阻塞點(diǎn)。
從庫(kù)在清空當(dāng)前數(shù)據(jù)庫(kù)后,需要把 RDB 文件加載到內(nèi)存,這個(gè)過(guò)程的快慢和 RDB 文件的大小密切相關(guān),RDB 文件越大,加載過(guò)程越慢。
部署 Redis 切片集群時(shí),每個(gè) Redis 實(shí)例上分配的哈希槽信息需要在不同實(shí)例間進(jìn)行傳遞,當(dāng)需要進(jìn)行負(fù)載均衡或者有實(shí)例增刪時(shí),數(shù)據(jù)會(huì)在不同的實(shí)例間進(jìn)行遷移。不過(guò)哈希槽的信息量不大,而數(shù)據(jù)遷移是漸進(jìn)式執(zhí)行的,這兩類(lèi)操作對(duì) Redis 主線程的阻塞風(fēng)險(xiǎn)不大。
如果使用了 Redis Cluster 方案,而且同時(shí)正好遷移的是 bigkey 的話,就會(huì)造成主線程的阻塞,因?yàn)?Redis Cluster 使用了同步遷移。
五個(gè)阻塞點(diǎn):
集合全量查詢和聚合操作;
bigkey 刪除;
清空數(shù)據(jù)庫(kù);
AOF 日志同步寫(xiě);
從庫(kù)加載 RDB 文件。
為了避免阻塞式操作,Redis 提供了異步線程機(jī)制:
Redis 會(huì)啟動(dòng)一些子線程,然后把一些任務(wù)交給這些子線程,讓它們?cè)诤笈_(tái)完成,而不再由主線程來(lái)執(zhí)行這些任務(wù)??梢员苊庾枞骶€程。
異步執(zhí)行對(duì)操作的要求:
一個(gè)能被異步執(zhí)行的操作并不是 Redis 主線程的關(guān)鍵路徑上的操作(客戶端把請(qǐng)求發(fā)送給 Redis 后,等著 Redis 返回?cái)?shù)據(jù)結(jié)果的操作)。
主線程接收到操作 1 后,操作 1 并不用給客戶端返回具體的數(shù)據(jù),主線程可以把它交給后臺(tái)子線程來(lái)完成,同時(shí)只要給客戶端返回一個(gè)“OK”結(jié)果就行。
在子線程執(zhí)行操作 1 的時(shí)候,客戶端又向 Redis 實(shí)例發(fā)送了操作 2,客戶端是需要使用操作 2 返回的數(shù)據(jù)結(jié)果的,如果操作 2 不返回結(jié)果,那么客戶端將一直處于等待狀態(tài)。
操作 1 就不算關(guān)鍵路徑上的操作,因?yàn)樗挥媒o客戶端返回具體數(shù)據(jù),所以可以由后臺(tái)子線程異步執(zhí)行。
操作 2 需要把結(jié)果返回給客戶端,它就是關(guān)鍵路徑上的操作,所以主線程必須立即把這個(gè)操作執(zhí)行完。
Redis 讀操作是典型的關(guān)鍵路徑操作,因?yàn)榭蛻舳税l(fā)送了讀操作之后,就會(huì)等待讀取的數(shù)據(jù)返回,以便進(jìn)行后續(xù)的數(shù)據(jù)處理。而 Redis 的第一個(gè)阻塞點(diǎn)“集合全量查詢 和聚合操作”都涉及到了讀操作,不能進(jìn)行異步操作。
刪除操作并不需要給客戶端返回具體的數(shù)據(jù)結(jié)果,不算是關(guān)鍵路徑操作?!癰igkey 刪除”和“清空數(shù)據(jù)庫(kù)”都是對(duì)數(shù)據(jù)做刪除,并不在關(guān)鍵路徑上。可以使用后臺(tái)子線程來(lái)異步執(zhí)行刪除操作。
“AOF 日志同步寫(xiě)”,為了保證數(shù)據(jù)可靠性,Redis 實(shí)例需要保證 AOF 日志中的操作記錄已經(jīng)落盤(pán),這個(gè)操作雖然需要實(shí)例等待,但它并不會(huì)返回具體的數(shù)據(jù)結(jié)果給實(shí)例。所以可以啟動(dòng)一個(gè)子線程來(lái)執(zhí)行 AOF 日志的同步寫(xiě)。
“從庫(kù)加載 RDB 文件”要想對(duì)客戶端提供數(shù)據(jù)存取服務(wù),就必須把 RDB 文件加載完成。這個(gè)操作也屬于關(guān)鍵路徑上的操作,必須讓從庫(kù)的主線程來(lái)執(zhí)行。
除了“集合全量查詢和聚合操作”和“從庫(kù)加載 RDB 文 件”,其他三個(gè)阻塞點(diǎn)涉及的操作都不在關(guān)鍵路徑上,可以使用 Redis 的異步子線程機(jī)制來(lái)實(shí)現(xiàn) bigkey 刪除,清空數(shù)據(jù)庫(kù),以及 AOF 日志同步寫(xiě)。
Redis 主線程啟動(dòng)后,會(huì)使用操作系統(tǒng)提供的 pthread_create 函數(shù)創(chuàng)建 3 個(gè)子線程,負(fù)責(zé)AOF 日志寫(xiě)操作、鍵值對(duì)刪除、文件關(guān)閉的異步執(zhí)行。
主線程通過(guò)一個(gè)鏈表形式的任務(wù)隊(duì)列和子線程進(jìn)行交互。
當(dāng)收到鍵值對(duì)刪除和清空數(shù)據(jù)庫(kù)的操作時(shí),主線程會(huì)把這個(gè)操作封裝成一個(gè)任務(wù),放入到任務(wù)隊(duì)列中,然后給客戶端返回一個(gè)完成信息,表明刪除已經(jīng)完成。
但實(shí)際上,這個(gè)時(shí)候刪除還沒(méi)有執(zhí)行,等到后臺(tái)子線程從任務(wù)隊(duì)列中讀取任務(wù)后,才開(kāi)始實(shí)際刪除鍵值對(duì),并釋放相應(yīng)的內(nèi)存空間。這種異步刪除也稱(chēng)為惰性刪除 (lazy free)。
當(dāng) AOF 日志配置成 everysec 選項(xiàng)后,主線程會(huì)把 AOF 寫(xiě)日志操作封裝成一個(gè)任務(wù),也放到任務(wù)隊(duì)列中。后臺(tái)子線程讀取任務(wù)后,開(kāi)始自行寫(xiě)入 AOF 日志,主線程就不用一直等待 AOF 日志寫(xiě)完了。
Redis 中的異步子線程執(zhí)行機(jī)制:
異步的鍵值對(duì)刪除和數(shù)據(jù)庫(kù)清空操作是 Redis 4.0 后提供的功能,Redis 也提供了新的命令來(lái)執(zhí)行這兩個(gè)操作:
鍵值對(duì)刪除:集合類(lèi)型中有大量元素(例如有百萬(wàn)級(jí)別或千萬(wàn)級(jí)別元素)需要?jiǎng)h除時(shí),建議使用 UNLINK 命令;
清空數(shù)據(jù)庫(kù):可以在 FLUSHDB 和 FLUSHALL 命令后加上 ASYNC 選項(xiàng),讓后臺(tái)子線程異步地清空數(shù)據(jù)庫(kù)。
FLUSHDB ASYNC FLUSHALL AYSNC
感謝各位的閱讀,以上就是“Redis的異步機(jī)制是什么”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)Redis的異步機(jī)制是什么這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。