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

歡迎訪問 生活随笔!

生活随笔

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

数据库

redis单线程原理___Redis为何那么快-----底层原理浅析

發(fā)布時間:2025/3/12 数据库 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 redis单线程原理___Redis为何那么快-----底层原理浅析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

redis單線程原理

redis單線程問題

單線程指的是網(wǎng)絡(luò)請求模塊使用了一個線程(所以不需考慮并發(fā)安全性),即一個線程處理所有網(wǎng)絡(luò)請求,其他模塊仍用了多個線程。

1. 為什么說redis能夠快速執(zhí)行

(1) 絕大部分請求是純粹的內(nèi)存操作(非??焖?#xff09;

(2) 采用單線程,避免了不必要的上下文切換和競爭條件

(3) 非阻塞IO - IO多路復用

2. redis的內(nèi)部實現(xiàn)

內(nèi)部實現(xiàn)采用epoll,采用了epoll+自己實現(xiàn)的簡單的事件框架。epoll中的讀、寫、關(guān)閉、連接都轉(zhuǎn)化成了事件,然后利用epoll的多路復用特性,絕不在io上浪費一點時間 這3個條件不是相互獨立的,特別是第一條,如果請求都是耗時的,采用單線程吞吐量及性能可想而知了。應(yīng)該說redis為特殊的場景選擇了合適的技術(shù)方案。

3. Redis關(guān)于線程安全問題

redis實際上是采用了線程封閉的觀念,把任務(wù)封閉在一個線程,自然避免了線程安全問題,不過對于需要依賴多個redis操作的復合操作來說,依然需要鎖,而且有可能是分布式鎖。

4. IO多路復用

參考:https://www.zhihu.com/question/32163005

要弄清問題先要知道問題的出現(xiàn)原因

原因:

由于進程的執(zhí)行過程是線性的(也就是順序執(zhí)行),當我們調(diào)用低速系統(tǒng)I/O(read,write,accept等等),進程可能阻塞,此時進程就阻塞在這個調(diào)用上,不能執(zhí)行其他操作.阻塞很正常.

接下來考慮這么一個問題:一個服務(wù)器進程和一個客戶端進程通信,服務(wù)器端read(sockfd1,bud,bufsize),此時客戶端進程沒有發(fā)送數(shù)據(jù),那么read(阻塞調(diào)用)將阻塞,直到客戶端調(diào)用write(sockfd,but,size)發(fā)來數(shù)據(jù).在一個客戶和服務(wù)器通信時這沒什么問題;

當多個客戶與服務(wù)器通信時當多個客戶與服務(wù)器通信時,若服務(wù)器阻塞于其中一個客戶sockfd1,當另一個客戶的數(shù)據(jù)到達套接字sockfd2時,服務(wù)器不能處理,仍然阻塞在read(sockfd1,…)上;此時問題就出現(xiàn)了,不能及時處理另一個客戶的服務(wù),咋么辦?

I/O多路復用來解決!

I/O多路復用:

繼續(xù)上面的問題,有多個客戶連接,sockfd1,sockfd2,sockfd3…sockfdn同時監(jiān)聽這n個客戶,當其中有一個發(fā)來消息時就從select的阻塞中返回,然后就調(diào)用read讀取收到消息的sockfd,然后又循環(huán)回select阻塞;這樣就不會因為阻塞在其中一個上而不能處理另一個客戶的消息

“I/O多路復用”的英文是“I/O multiplexing”,可以百度一下multiplexing,就能得到這個圖:

Q:

那這樣子,在讀取socket1的數(shù)據(jù)時,如果其它socket有數(shù)據(jù)來,那么也要等到socket1讀取完了才能繼續(xù)讀取其它socket的數(shù)據(jù)吧。那不是也阻塞住了嗎?而且讀取到的數(shù)據(jù)也要開啟線程處理吧,那這和多線程IO有什么區(qū)別呢?

A:

1.CPU本來就是線性的不論什么都需要順序處理并行只能是多核CPU

2.io多路復用本來就是用來解決對多個I/O監(jiān)聽時,一個I/O阻塞影響其他I/O的問題,跟多線程沒關(guān)系.

3.跟多線程相比較,線程切換需要切換到內(nèi)核進行線程切換,需要消耗時間和資源.而I/O多路復用不需要切換線/進程,效率相對較高,特別是對高并發(fā)的應(yīng)用nginx就是用I/O多路復用,故而性能極佳.但多線程編程邏輯和處理上比I/O多路復用簡單.而I/O多路復用處理起來較為復雜.

5. 使用Redis有哪些好處?

(1) 速度快,因為數(shù)據(jù)存在內(nèi)存中,類似于HashMap,HashMap的優(yōu)勢就是查找和操作的時間復雜度都是O(1)

(2) 支持豐富數(shù)據(jù)類型,支持string,list,set,sorted set,hash

(3) 支持事務(wù),操作都是原子性,所謂的原子性就是對數(shù)據(jù)的更改要么全部執(zhí)行,要么全部不執(zhí)行

(4) 豐富的特性:可用于緩存,消息,按key設(shè)置過期時間,過期后將會自動刪除

6. Redis相比memcached有哪些優(yōu)勢?

(1) memcached所有的值均是簡單的字符串,redis作為其替代者,支持更為豐富的數(shù)據(jù)類型

(2) redis的速度比memcached快很多

(3) redis可以持久化其數(shù)據(jù)

(4)Redis支持數(shù)據(jù)的備份,即master-slave模式的數(shù)據(jù)備份。

(5) 使用底層模型不同,它們之間底層實現(xiàn)方式 以及與客戶端之間通信的應(yīng)用協(xié)議不一樣。Redis直接自己構(gòu)建了VM 機制 ,因為一般的系統(tǒng)調(diào)用系統(tǒng)函數(shù)的話,會浪費一定的時間去移動和請求。

(6)value大小:redis最大可以達到1GB,而memcache只有1MB

7. Redis常見性能問題和解決方案:

(1) Master最好不要做任何持久化工作,如RDB內(nèi)存快照和AOF日志文件;(Master寫內(nèi)存快照,save命令調(diào)度rdbSave函數(shù),會阻塞主線程的工作,當快照比較大時對性能影響是非常大的,會間斷性暫停服務(wù),所以Master最好不要寫內(nèi)存快照;AOF文件過大會影響Master重啟的恢復速度)

(2) 如果數(shù)據(jù)比較重要,某個Slave開啟AOF備份數(shù)據(jù),策略設(shè)置為每秒同步一次

(3) 為了主從復制的速度和連接的穩(wěn)定性,Master和Slave最好在同一個局域網(wǎng)內(nèi)

(4) 盡量避免在壓力很大的主庫上增加從庫

(5) 主從復制不要用圖狀結(jié)構(gòu),用單向鏈表結(jié)構(gòu)更為穩(wěn)定,即:Master <- Slave1 <- Slave2 <- Slave3…;這樣的結(jié)構(gòu)方便解決單點故障問題,實現(xiàn)Slave對Master的替換。如果Master掛了,可以立刻啟用Slave1做Master,其他不變。

8. Redis的回收策略

volatile-lru:從已設(shè)置過期時間的數(shù)據(jù)集(server.db[i].expires)中挑選最近最少使用的數(shù)據(jù)淘汰

volatile-ttl:從已設(shè)置過期時間的數(shù)據(jù)集(server.db[i].expires)中挑選將要過期的數(shù)據(jù)淘汰

volatile-random:從已設(shè)置過期時間的數(shù)據(jù)集(server.db[i].expires)中任意選擇數(shù)據(jù)淘汰

allkeys-lru:從數(shù)據(jù)集(server.db[i].dict)中挑選最近最少使用的數(shù)據(jù)淘汰

allkeys-random:從數(shù)據(jù)集(server.db[i].dict)中任意選擇數(shù)據(jù)淘汰

no-enviction(驅(qū)逐):禁止驅(qū)逐數(shù)據(jù)

注意這里的6種機制,volatile和allkeys規(guī)定了是對已設(shè)置過期時間的數(shù)據(jù)集淘汰數(shù)據(jù)還是從全部數(shù)據(jù)集淘汰數(shù)據(jù),后面的lru、ttl以及random是三種不同的淘汰策略,再加上一種no-enviction永不回收的策略。

使用策略規(guī)則:

1、如果數(shù)據(jù)呈現(xiàn)冪律分布,也就是一部分數(shù)據(jù)訪問頻率高,一部分數(shù)據(jù)訪問頻率低,則使用allkeys-lru

2、如果數(shù)據(jù)呈現(xiàn)平等分布,也就是所有的數(shù)據(jù)訪問頻率都相同,則使用allkeys-random

9. 五種I/O模型介紹

IO 多路復用是5種I/O模型中的第3種,對各種模型講個故事,描述下區(qū)別:

故事情節(jié)為:老李去買火車票,三天后買到一張退票。參演人員(老李,黃牛,售票員,快遞員),往返車站耗費1小時。

1.阻塞I/O模型

老李去火車站買票,排隊三天買到一張退票。

耗費:在車站吃喝拉撒睡 3天,其他事一件沒干。

2.非阻塞I/O模型

老李去火車站買票,隔12小時去火車站問有沒有退票,三天后買到一張票。

耗費:往返車站6次,路上6小時,其他時間做了好多事。

3.I/O復用模型

1.select/poll

老李去火車站買票,委托黃牛,然后每隔6小時電話黃牛詢問,黃牛三天內(nèi)買到票,然后老李去火車站交錢領(lǐng)票。

耗費:往返車站2次,路上2小時,黃牛手續(xù)費100元,打電話17次

2.epoll

老李去火車站買票,委托黃牛,黃牛買到后即通知老李去領(lǐng),然后老李去火車站交錢領(lǐng)票。

耗費:往返車站2次,路上2小時,黃牛手續(xù)費100元,無需打電話

4.信號驅(qū)動I/O模型

老李去火車站買票,給售票員留下電話,有票后,售票員電話通知老李,然后老李去火車站交錢領(lǐng)票。

耗費:往返車站2次,路上2小時,免黃牛費100元,無需打電話

5.異步I/O模型

老李去火車站買票,給售票員留下電話,有票后,售票員電話通知老李并快遞送票上門。

耗費:往返車站1次,路上1小時,免黃牛費100元,無需打電話

1同2的區(qū)別是:自己輪詢

2同3的區(qū)別是:委托黃牛

3同4的區(qū)別是:電話代替黃牛

4同5的區(qū)別是:電話通知是自取還是送票上門


Redis為何那么快-----底層原理淺析

Redis的快速很多人都知道是因為基于內(nèi)存,但這只是一方面,其實redis在底層是一套很完善的多路復用事件處理機制來保證執(zhí)行的高效的

線程模型
redis內(nèi)部使用文件事件處理器file event handler,它包含如下幾個部分

  • 多個socket
  • IO多路復用程序
  • 文件事件分派器
  • 事件處理器(連接應(yīng)答處理器,命令請求處理器,命令回復處理器)

之所以說redis是單線程其實是指這個文件事件處理器是單線程的,它采用多路復用的方式監(jiān)聽系統(tǒng)上多個socket,將socket上產(chǎn)生的事件壓入隊列中,由文件事件分派器從隊列中取出一個socket根據(jù)事件類型發(fā)給相應(yīng)的事件處理器

整個處理過程如圖:

處理過程可以分為以下幾個步驟:

  • 客戶端向redis發(fā)起一個socket請求,向redis的server socket請求連接,這里命名為socket01
  • server socket產(chǎn)生一個AE_READABLE事件,IO多路復用程序監(jiān)聽到事件后將這個socket01壓入隊列
  • 文件事件分派器從隊列中取出socket01,交給連接應(yīng)答處理器
  • 連接應(yīng)答處理器會將socket01的AE_READABLE事件與命令請求處理器相關(guān)聯(lián)
  • 假設(shè)客戶端執(zhí)行set操作,這時命令請求處理器會從socket01讀取key value,在內(nèi)存中完成key value的設(shè)置
  • 在內(nèi)存中完成設(shè)置后,會將socket01的AE_WRITEABLE事件與命令回復處理器相關(guān)聯(lián),然后壓入隊列中
  • 事件分派器拿到socket01后,交給命令回復處理器,由命令回復處理器向socket01寫入本次操作的結(jié)果,比如OK,之后解除關(guān)聯(lián)

以上就是一個命令在redis中執(zhí)行的過程

總結(jié)一下效率高的原因

  • 內(nèi)存操作
  • IO多路復用機制,減少了阻塞
  • 單線程避免了線程切換的開銷和競爭問題
  • 最最根本的redis是用C語言寫的,本來就直接跟操作系統(tǒng)交互,命令執(zhí)行快得飛起
  • Redis內(nèi)部原理簡介

    知道了Redis的各種數(shù)據(jù)結(jié)構(gòu),對象結(jié)構(gòu),那么Redis是如何保存數(shù)據(jù)的,又是如何操作數(shù)據(jù)的呢,Redis里面的命令是怎么實現(xiàn)的呢?這一系列問題值得我們思考

    一.Redis維護多個數(shù)據(jù)庫

    Redis內(nèi)部維護一個db數(shù)組,每個db都是一個數(shù)據(jù)庫,默認情況下Redis會創(chuàng)建16個數(shù)據(jù)庫。我們可以通過select命令來切換數(shù)據(jù)庫,如select1切換到數(shù)據(jù)庫號為1的數(shù)據(jù)庫。select實現(xiàn)是通過修改客戶端的db指針,通過指針指向不同的數(shù)據(jù)庫來實現(xiàn)數(shù)據(jù)庫的切換操作的。

    需要注意的是,為了不造成操作數(shù)據(jù)庫號錯誤,最好執(zhí)行命令之前,手動select一下數(shù)據(jù)庫。

    二.數(shù)據(jù)庫鍵空間

    Redis是一個鍵值對數(shù)據(jù)庫服務(wù)器,Redis通過字典保存了數(shù)據(jù)庫中的所有鍵值對,我們將這個字典稱為鍵空間。鍵空間的每個鍵都是一個字符串對象,鍵空間的值也就是數(shù)據(jù)庫的值,可以是字符串對象,列表對象,哈希表對象,集合對象,有序集合對象中的任何一種。

    1.添加新鍵

    每次添加一個新鍵就是將一個新鍵值對添加到鍵空間里面,其中鍵為字符串對象,值為任意一種類型的Redis對象。

    2.刪除鍵

    刪除鍵就是在鍵空間里刪除鍵所對應(yīng)的鍵值對對象。

    3.更新鍵

    更新鍵就是對鍵空間里面鍵所對應(yīng)的值對象進行更新。

    4.查找鍵

    查找鍵就是在鍵空間中取出鍵所對應(yīng)的值對象。

    每次在鍵空間讀取一個鍵之后,服務(wù)器會更新鍵的LRU時間,用于計算鍵的閑置時間。如果服務(wù)器在讀取一個鍵時發(fā)現(xiàn)該鍵已經(jīng)過期,那么服務(wù)器會先刪除這個過期鍵,然后才執(zhí)行后續(xù)操作。如果有客戶端使用watch命令監(jiān)視了某個鍵,那么服務(wù)器在對被監(jiān)視的鍵進行修改之后,會將這個鍵標記為dirty,從而讓事務(wù)注意到這個鍵被修改過。服務(wù)器每次修改一個鍵之后,都會對鍵計數(shù)器的值+1,這個計數(shù)器用來觸發(fā)服務(wù)器的持久化操作。如果服務(wù)器開啟了數(shù)據(jù)庫通知功能,那么在對鍵進行修改之后,服務(wù)器將按配置發(fā)送相應(yīng)的數(shù)據(jù)庫通知。

    三.設(shè)置鍵的生存時間和過期時間

    我們知道expire命令或者pexpire命令可以對一個鍵設(shè)置生存時間,經(jīng)過指定的時間之后,服務(wù)器會自動刪除生存時間為0的鍵。那么Redis是如何實現(xiàn)刪除過期鍵的操作的呢?

    Redis有四個命令可以設(shè)置鍵的過期時間,包括expire,pexpire,expireat,pexpireat,不過這四個命令最后都會轉(zhuǎn)化成pexpireat命令來實現(xiàn)。

    Redis使用一個過期字典記錄所有帶過期時間的鍵,字典的鍵指向鍵空間中的某個鍵對象,字典的值是一個longlong類型的整數(shù),這個證書保存了鍵空間所指向的數(shù)據(jù)庫鍵的過期時間。通過過期字典,程序可以檢查一個給定鍵是否過期,檢查給定鍵是否存在于過期字典,如果存在,取得鍵的過期時間,檢查當前時間戳是否大于鍵的過期時間,如果是的話,鍵已經(jīng)過期,否則鍵未過期。

    四.過期鍵的刪除策略

    如果一個鍵過期了,那么它什么時候被刪除呢?通常我們可以用三種刪除策略刪除過期鍵

    1.定時刪除:在設(shè)置鍵過期時間的同時,創(chuàng)建一個定時器,讓定時器在鍵的過期時間來臨時,刪除鍵

    2.惰性刪除:放任鍵過期不管,但是每次動鍵空間獲取鍵時,都會檢查鍵是否過期,如果過期,則刪除。

    3.定期刪除:每隔一段時間,程序就對數(shù)據(jù)庫進行一次檢查,刪除里面的過期鍵。

    這幾種方式各有利有弊,首先定時刪除對內(nèi)存最友好,當一個鍵過期時,一定會刪除這個鍵,釋放內(nèi)存。不過定時刪除對CPU最不友好,在過期鍵比較多的情況下,刪除過期鍵這一行為可能會占用相當一部分CPU時間。此外,創(chuàng)建定時器需要用到Redis服務(wù)器中的時間時間,而當前時間時間的實現(xiàn)方式-無序鏈表查找一個事件的時間復雜度為O(N),不能高效地處理大量時間事件。

    惰性刪除策略對CPU是最友好的,但是對內(nèi)存最不友好。如果一個鍵已經(jīng)過期,這個鍵又保留在數(shù)據(jù)庫中,那么內(nèi)存就會一直占用不釋放。

    定期刪除算是前兩種策略的一種整合和折中,定期策略每隔一段時間執(zhí)行一次刪除過期鍵操作,并通過限制刪除操作執(zhí)行的時長和頻率減少刪除操作對CPU時間的影響。定期刪除過期鍵可以有效地減少因為過期鍵帶來的內(nèi)存浪費。

    Redis過期鍵的刪除使用惰性刪除和定期刪除兩種策略配合使用。惰性策略比較好理解,所有讀寫數(shù)據(jù)庫的命令執(zhí)行之前都會對輸入鍵進行檢查,如果鍵過期,那么從數(shù)據(jù)庫中刪除鍵。定期刪除策略的實現(xiàn)由Redis的serverCron函數(shù)來執(zhí)行,這個函數(shù)每100ms執(zhí)行一次,它在規(guī)定的時間內(nèi),分多次遍歷服務(wù)器中的各個數(shù)據(jù)庫,從數(shù)據(jù)庫的expires字典中隨機檢查一部分鍵的過期時間,刪除其中的過期鍵。

    五.復制功能對過期鍵的處理

    Redis復制主要包括RDB復制和AOF復制,在RDB復制中,每次執(zhí)行SAVE或BGSAVE命令創(chuàng)建一個新的RDB文件時,程序會對數(shù)據(jù)庫中的鍵進行檢查,已過期的鍵不會被保存到新創(chuàng)建的RDB文件中。載入RDB文件時,服務(wù)器也會對保存的鍵進行檢查,如果鍵已過期,則不會載入。當使用AOF持久化模式運行時,當過期鍵被惰性刪除或者定期刪除之后,程序會向AOF文件追加一條刪除命令,記錄鍵已被刪除。

    總結(jié)

    以上是生活随笔為你收集整理的redis单线程原理___Redis为何那么快-----底层原理浅析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。