單進程單線程的Redis如何可以高併發

一、基本原理
採用多路 I/O 複用技術可讓單個線程高效的處理多個鏈接請求(儘可能減小網絡IO的時間消耗)
(1)爲何不採用多進程或多線程處理?mysql

多線程處理可能涉及到鎖 
多線程處理會涉及到線程切換而消耗CPU

(2)單線程處理的缺點?redis

沒法發揮多核CPU性能,不過能夠經過在單機開多個Redis實例來完善

二、Redis不存在線程安全問題?
Redis採用了線程封閉的方式,把任務封閉在一個線程,天然避免了線程安全問題,不過對於須要依賴多個redis操做的複合操做來講,依然須要鎖,並且有多是分佈式鎖sql

三、什麼是多路I/O複用(Epoll)
(1) 網絡IO都是經過Socket實現,Server在某一個端口持續監聽,客戶端經過Socket(IP+Port)與服務器創建鏈接(ServerSocket.accept),成功創建鏈接以後,就可使用Socket中封裝的InputStream和OutputStream進行IO交互了。針對每一個客戶端,Server都會建立一個新線程專門用於處理
(2) 默認狀況下,網絡IO是阻塞模式,即服務器線程在數據到來以前處於【阻塞】狀態,等到數據到達,會自動喚醒服務器線程,着手進行處理。阻塞模式下,一個線程只能處理一個流的IO事件
(3) 爲了提高服務器線程處理效率,有如下三種思路數據庫

1)非阻塞【忙輪詢】:採用死循環方式輪詢每個流,若是有IO事件就處理,這樣可使得一個線程能夠處理多個流,可是效率不高,容易致使CPU空轉

(2)Select代理(無差異輪詢):能夠觀察多個流的IO事件,若是全部流都沒有IO事件,則將線程進入阻塞狀態,若是有一個或多個發生了IO事件,則喚醒線程去處理。可是仍是得遍歷全部的流,才能找出哪些流須要處理。若是流個數爲N,則時間複雜度爲O(N)

(3)Epoll代理:Select代理有一個缺點,線程在被喚醒後輪詢全部的Stream,仍是存在無效操做。 Epoll會哪一個流發生了怎樣的I/O事件通知處理線程,所以對這些流的操做都是有意義的,複雜度下降到了O(1)

四、其它開源軟件採用的模型緩存

Nginx:多進程單線程模型 
Memcached:單進程多線程模型

 

Redis爲何是單線程的?安全

由於CPU不是Redis的瓶頸。Redis的瓶頸最有多是機器內存或者網絡帶寬。(以上主要來自官方FAQ)既然單線程容易實現,並且CPU不會成爲瓶頸,那就瓜熟蒂落地採用單線程的方案了。關於redis的性能,官方網站也有,普通筆記本輕鬆處理每秒幾十萬的請求,參見:How fast is Redis?服務器

 

若是萬一CPU成爲你的Redis瓶頸了,或者,你就是不想讓服務器其餘核閒置,那怎麼辦?網絡

那也很簡單,你多起幾個Redis進程就行了。Redis是keyvalue數據庫,又不是關係數據庫,數據之間沒有約束。只要客戶端分清哪些key放在哪一個Redis進程上就能夠了。redis-cluster能夠幫你作的更好。多線程

 

單線程能夠處理高併發請求嗎?架構

固然能夠了,Redis都實現了。

有一點概念須要澄清,併發並非並行。

(相關概念:併發性I/O流,意味着可以讓一個計算單元來處理來自多個客戶端的流請求。並行性,意味着服務器可以同時執行幾個事情,具備多個計算單元)

 

Redis整體快速的緣由:

採用隊列模式將併發訪問變爲串行訪問(?)

 

單線程指的是網絡請求模塊使用了一個線程(因此不需考慮併發安全性),其餘模塊仍用了多個線程。

 

 

整體來講快速的緣由以下:

1)絕大部分請求是純粹的內存操做(很是快速)

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

3)非阻塞IO

內部實現採用epoll,採用了epoll+本身實現的簡單的事件框架。epoll中的讀、寫、關閉、鏈接都轉化成了事件,而後利用epoll的多路複用特性,毫不在io上浪費一點時間

這3個條件不是相互獨立的,特別是第一條,若是請求都是耗時的,採用單線程吞吐量及性能可想而知了。應該說redis爲特殊的場景選擇了合適的技術方案。

 

======

 

1. Redis服務端是個單線程的架構,不一樣的Client雖然看似能夠同時保持鏈接,但發出去的命令是序列化執行的,這在一般的數據庫理論下是最高級別的隔離(serialize)
2. 用MULTI/EXEC 來把多個命令組裝成一次發送,達到原子性
3. 用WATCH提供的樂觀鎖功能,在你EXEC的那一刻,若是被WATCH的鍵發生過改動,則MULTI到EXEC之間的指令所有不執行,不須要rollback
4. 其餘回答中提到的DISCARD指令只是用來撤銷EXEC以前被暫存的指令,並非回滾


多線程對同一個Key操做時,Redis服務是根據先到先做的原則,其餘排隊(可設置爲直接丟棄),由於是單線程。

修改默認的超時時間,默認2秒。可是大部份的操做都在30ms之內。

========

 

 

 

1. 使用Redis有哪些好處?

(1) 速度快,由於數據存在內存中,相似於HashMap,HashMap的優點就是查找和操做的時間複雜度都是O(1)

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

(3) 支持事務,操做都是原子性,所謂的原子性就是對數據的更改要麼所有執行,要麼所有不執行

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

 

2. Redis相比memcached有哪些優點?

(1) memcached全部的值均是簡單的字符串,redis做爲其替代者,支持更爲豐富的數據類型

(2) redis的速度比memcached快不少

(3) redis能夠持久化其數據

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

 

 

(5)、使用底層模型不一樣

它們之間底層實現方式 以及與客戶端之間通訊的應用協議不同。

Redis直接本身構建了VM 機制 ,由於通常的系統調用系統函數的話,會浪費必定的時間去移動和請求。

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

 

 

 

3. redis常見性能問題和解決方案:

(1) Master最好不要作任何持久化工做,如RDB內存快照和AOF日誌文件

(Master寫內存快照,save命令調度rdbSave函數,會阻塞主線程的工做,當快照比較大時對性能影響是很是大的,會間斷性暫停服務,因此Master最好不要寫內存快照;AOF文件過大會影響Master重啓的恢復速度)

(2) 若是數據比較重要,某個Slave開啓AOF備份數據,策略設置爲每秒同步一次

(3) 爲了主從複製的速度和鏈接的穩定性,Master和Slave最好在同一個局域網內

(4) 儘可能避免在壓力很大的主庫上增長從庫

(5) 主從複製不要用圖狀結構,用單向鏈表結構更爲穩定,即:Master <- Slave1 <- Slave2 <- Slave3...

這樣的結構方便解決單點故障問題,實現Slave對Master的替換。若是Master掛了,能夠馬上啓用Slave1作Master,其餘不變。

 

redis的一些其餘特色:

 

(1)Redis是單進程單線程的

 

redis利用隊列技術將併發訪問變爲串行訪問,消除了傳統數據庫串行控制的開銷

 

(2)讀寫分離模型

 

經過增長Slave DB的數量,讀的性能能夠線性增加。爲了不Master DB的單點故障,集羣通常都會採用兩臺Master DB作雙機熱備,因此整個集羣的讀和寫的可用性都很是高。
讀寫分離架構的缺陷在於,無論是Master仍是Slave,每一個節點都必須保存完整的數據,若是在數據量很大的狀況下,集羣的擴展能力仍是受限於單個節點的存儲能力,並且對於Write-intensive類型的應用,讀寫分離架構並不適合。

 

(3)數據分片模型

 

爲了解決讀寫分離模型的缺陷,能夠將數據分片模型應用進來。

能夠將每一個節點當作都是獨立的master,而後經過業務實現數據分片。

結合上面兩種模型,能夠將每一個master設計成由一個master和多個slave組成的模型。

(4)Redis的回收策略

 

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

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

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

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

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

    • no-enviction(驅逐):禁止驅逐數據

    •  

      注意這裏的6種機制,volatile和allkeys規定了是對已設置過時時間的數據集淘汰數據仍是從所有數據集淘汰數據,後面的lru、ttl以及random是三種不一樣的淘汰策略,再加上一種no-enviction永不回收的策略。

        使用策略規則:

        一、若是數據呈現冪律分佈,也就是一部分數據訪問頻率高,一部分數據訪問頻率低,則使用allkeys-lru

        二、若是數據呈現平等分佈,也就是全部的數據訪問頻率都相同,則使用allkeys-random

相關文章
相關標籤/搜索