單進程單線程的Redis如何能夠高並發


1、基本原理
采用多路 I/O 復用技術可以讓單個線程高效的處理多個連接請求(盡量減少網絡IO的時間消耗)
(1)為什么不采用多進程或多線程處理?

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

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

無法發揮多核CPU性能,不過可以通過在單機開多個Redis實例來完善

2、Redis不存在線程安全問題?
Redis采用了線程封閉的方式,把任務封閉在一個線程,自然避免了線程安全問題,不過對於需要依賴多個redis操作的復合操作來說,依然需要鎖,而且有可能是分布式鎖

3、什么是多路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)

4、其它開源軟件采用的模型

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永不回收的策略。

        使用策略規則:

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

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




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM