Redis做者: 意大利人 Salvatore Sanfilippo(網名 Antirez) 開發。Antirez 不只帥的不像實力派,也很是有趣。Antirez 今年已經四十歲了,依舊在孜孜不倦地寫代碼,爲 Redis 的開源事業持續貢獻力量。html
Redis是一個開放源代碼(BSD許可)內存中的數據結構存儲,用做數據庫、緩存和消息代理。它支持字符串、哈希、列表、集合、帶範圍查詢的排序集合、位圖、超日誌和流的地理空間索引等數據結構。Redis具備內置的複製、lua腳本、lru回收、事務和不一樣級別的磁盤上持久性,並經過Redis Sentinel和Redis集羣的自動分區提供高可用性。java
源碼github:github.com/antirez/red…python
先經過一段測試來看下Redis的性能如何 Redis 自帶了一個壓力測試工具redis-benchmark,使用這個工具就能夠進行管道測試。git
首先咱們對一個普通的 set 指令進行壓測,QPS 大約 5w/s。github
> redis-benchmark -t set -q
SET: 51975.05 requests per second
複製代碼
咱們加入管道選項-P參數,它表示單個管道內並行的請求數量,看下面P=2,QPS 達到了 9w/s。redis
> redis-benchmark -t set -P 2 -q
SET: 91240.88 requests per second
複製代碼
再看看P=3,QPS 達到了 10w/s。數據庫
> redis-benchmark -t set -P 3 -q
SET: 102354.15 requests per second
複製代碼
但若是再繼續提高 P 參數,發現 QPS 已經上不去了。這是爲何呢?緩存
由於這裏 CPU 處理能力已經達到了瓶頸,Redis 的單線程 CPU 已經飆到了 100%,因此沒法再繼續提高了。bash
Redis爲何這麼快?服務器
正常狀況下,Redis執行命令的速度很是快,官方給出的數字是讀寫性能能夠達到10萬/秒,固然這也取決於機器的性能,但這裏先不討論機器性能上的差別,只分析一下是什麼造就了Redis除此之快的速度,能夠大體概括爲如下五點:
Redis是用C語言實現的,通常來講C語言實現的程序「距離」操做系統更近,執行速度相對會更快。
徹底基於內存,絕大部分請求是純粹的內存操做,很是快速。數據存在內存中,相似於HashMap,HashMap的優點就是查找和操做的時間複雜度都是O(1);正由於 Redis 是單線程,因此要當心使用 Redis 指令,對於那些時間複雜度爲 O(n) 級別的指令,必定要謹慎使用,一不當心就可能會致使 Redis 卡頓。
數據結構簡單,對數據操做也簡單,Redis中的數據結構是專門進行設計的;採用單線程,避免了沒必要要的上下文切換和競爭條件,也不存在多進程或者多線程致使的切換而消耗 CPU,不用去考慮各類鎖的問題,不存在加鎖釋放鎖操做,沒有由於可能出現死鎖而致使的性能消耗。
使用多路I/O複用模型,非阻塞IO,Redis 單線程處理大量的併發客戶端鏈接的模型。使用底層模型不一樣,它們之間底層實現方式以及與客戶端之間通訊的應用協議不同,Redis直接本身構建了VM 機制 ,由於通常的系統調用系統函數的話,會浪費必定的時間去移動和請求;
做者對於Redis源代碼能夠說是精打細磨,曾經有人評價Redis是少有的集性能和優雅於一身的開源代碼。
知道了Redis爲何這麼快的緣由,接下來看下redis的實現架構
第一層:客戶端,你們熟知的如原生redis-cli、java語言Jedis、python語言redis-py等
第二層:通訊,傳輸層基於TCP的resp協議
第三層:服務端,多路複用、事件循環、持久化等
redis的總體核心在服務端的處理
流程圖以下:
epoll:多路複用模型的基礎
事件:多路複用的設計方案,包含文件事件和時間事件。 命令處理:鏈接過程、處理過程、響應過程
上述三點,相輔相成共同構成了redis服務的核心處理流程。
總體流程以下: Client 發起socket鏈接
Server 接受socket鏈接
客戶端寫入
Server端接收寫入
Server返回結果
Client收到返回結果
看到這裏,對總體流程有個大概的印象了,你可能好奇兩個點,一個是Redis事件是什麼,第二個是I/O多路複用是什麼,下面分別簡單的說一下:
Redis經過套接字與客戶端(或者其餘服務器)進行鏈接,而文件事件就是服務器對套接字操做的抽象。服務器與客戶端的通訊會產生相應的文件事件,而服務器則經過監聽並處理這些事件來完成一系列的網絡通訊操做。
Redis基於Reactor模式開發了本身的網絡事件處理器:這個處理器則被稱爲文件時間處理器。
文件事件處理器使用I/O多路複用程序來同時監聽多個套接字,並根據套接字目前執行的任務來爲套接字關聯不一樣的時間處理器。
當被監聽的套接字準備好執行鏈接應答accept、讀取read、寫入write、關閉close等操做時,與操做相對應的文件事件就會產生,這時文件事件處理器就會調用套接字以前關聯好的事件處理器來處理這些事件。
Redis服務器中一些操做(好比serverCron的函數)則須要在給定的時間點執行,時間事件就是服務器對這類定時操做的抽象。默認一秒執行10次,即100ms執行一次。配置在redis.conf中的hz
serverCron函數的主要工做:
更新服務器的各種統計信息,好比內存佔用、數據庫佔用狀況等。
清理數據庫中的過時鍵值對。
關閉和清理連接失效的客戶端。
嘗試進行AOF或RDB持久化操做。
若是服務器是主服務器,對從服務器進行定時同步。
集羣模式,對集羣進行按期同步和鏈接測試。
詳解:
blog.chinaunix.net/uid-2451754…
實現機制:
多種線程模型:同步阻塞、同步非阻塞、多路複用、異步的對比,這裏不展開介紹,感興趣的同窗能夠自行查看相關資料。
下面介紹一下多路複用中的epoll,Redis事件管理器核心實現基本依賴於它。
epoll是在Linux 2.6內核中引進的,是一種強大的I/O多路複用技術,上面咱們已經說到在進行網絡操做的時候是經過文件描述符來進行讀寫的,那麼日常咱們就是一個進程操做一個文件描述符。然而epoll能夠經過一個文件描述符管理多個文件描述符,而且不阻塞I/O。這使得咱們單進程能夠操做多個文件描述符,這就是redis在高併發性能還如此強大的緣由之一。
下面簡單介紹epoll 主要的三個方法:
int epoll_create(int size) //建立一個epoll句柄用於監聽文件描述符FD,size用於告訴內核這個監聽的數目一共有多大。該epoll句柄建立後在操做系統層面只會佔用一個fd值,可是它能夠監聽size+1 個文件描述符
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) //epoll事件註冊函數,在建立文件事件的時候進行調用註冊
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout)//等待事件的產生
Redis 的事件管理器主要是基於epoll機制,先採用 epoll_ctl方法 註冊事件,而後再使用epoll_wait方法取出已經註冊的事件。
以上就是本篇文章的所有內容,感謝您的閱讀,若是您在其中發現任何不正確或者不嚴謹的描述,歡迎指正。
原文地址:Redis服務設計
歡迎關注做者公衆號: