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

歡迎訪問 生活随笔!

生活随笔

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

数据库

Redis高效性探索--线程IO模型,通信协议

發(fā)布時間:2023/12/4 数据库 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redis高效性探索--线程IO模型,通信协议 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Redis線程IO模型

  • Redis是單線程,這個毋庸置疑
  • Redis單線程能做到這么高的效率?不用懷疑,還有很多其他的服務都是單線程但是也有超高的效率,比如Node.js,Nginx也是單線程。
  • Redis單線程高效原因:
    • Redis所有數據都存儲在內存中,所有運算都是內存級別的運算,正是因為Redis是單線程,所有要小心使用,我們業(yè)務中可能會有一些耗時的操作keys(死亡命令)時間復雜度O(n),這種一定要謹慎使用,會造成Redis卡頓
  • Redis單線程如何處理這么多客戶端的并發(fā)連接?
    • 多路復用解決此問題,利用操作系統(tǒng)底層的select系列事件輪詢API,非阻塞IO的形式,就是java中NIO的理念同樣可以在Redis中復用
非阻塞IO
  • 當我們通過套接字(socket)利用網絡協議進行數據交換(讀寫)的時候,默認是阻塞的狀態(tài),比如read方法要傳遞進去一個參數n,標識最多讀取n個字節(jié)后在返回,如果一個字節(jié)都沒有,線程就會卡主,直到新的數據到來或者連接關閉,read方法才可以返回,線程才能繼續(xù)處理其他的事務。Write方法一般不阻塞,除非內核為套接字分配的緩沖區(qū)已經滿,write方法會阻塞,直到緩沖區(qū)空閑,在將剩下的寫入,如下是redis中socket讀寫的一個流程。

  • 非阻塞IO在套接字對象上提供了一個選項Non_blocking,當這個選項打開時候,讀寫方法不會阻塞,而是能讀多少讀多少,能寫多少寫多少。能讀多少取決于內核為套接字分配的讀緩沖區(qū)內部的數據字節(jié)數。寫多少取決于內核為套接字分配的寫緩沖區(qū)空閑空間字節(jié)數。讀方法和寫方法都會通過返回值來告知程序實際讀寫了多少字節(jié)
  • 有了非阻塞IO意味著線程無在IO操作時無需阻塞,可以瞬間完成,然后繼續(xù)別的事件
事件輪詢(多路復用)
  • 上文中提到的線程讀取數據時候,并不是一次性讀完,而是取決于緩沖區(qū)大小,讀取了一部分就返回,那么線程如何知道什么時候才繼續(xù)讀,也就是當數據來了,線程如何得到通知。寫也是一樣,如果緩沖區(qū)滿,寫不完,剩下的數據什么時候才繼續(xù)寫,線程也需要得到通知。
  • 事件輪詢API就是用來解決這個問題。最簡單的時間輪詢API是select函數。操作系統(tǒng)級別的API。
    • 輸入是讀寫描述符列表read_fds&write_fds,輸出是與之對應的可讀寫事件,還提供了timeout參數,
    • 沒有事件需要執(zhí)行的時候最多等待timeout時間線程處于阻塞狀態(tài)
    • 一旦期間有任何事件到來就可以返回。時間過了之后沒有任何事件到來也立刻返回
  • 例如RedisClient執(zhí)行一個 查詢命令,client通過socket在select上注冊一個read_fds,其他客戶端的任何操作也是想select中注冊事件,這個時間按定時任務執(zhí)行,當輪到你執(zhí)行的時候才執(zhí)行你的socket事件。如下圖

  • 每個套接字socket都有對應的讀寫文件描述符,偽代碼描述如下
read_events, write_events = select(read_fds, write_fds, timeout); for event in read_events:handle_read(event.fd); for event in write_events:handle_write(event.fd); handle_others() //處理其他事件
指令隊列
  • Redis為每個客戶端套接字關聯一個指令隊列。客戶端指令通過隊列排隊進行順序處理,先到先服務。
響應隊列
  • 同樣Redis也為每個客戶端套接字關聯一個響應隊列。Redis服務器通過響應隊列來將指令結果回復給客戶端。如果隊列空則空閑,此時可以將當前客戶端描述符從write_fds里面移除。等隊列有數據在將描述符放入,避免select系統(tǒng)調用立刻返回寫時間,結果發(fā)現沒有數據可以寫,空耗CPU資源
定時任務
  • 上文中socket注冊時間流程中,定時任務是關鍵的一環(huán),服務器除了處理IO操作以外,還有定時任務。
  • Redis的定時任務用來記錄需要執(zhí)行的任務,這些數據被記錄在一個被稱為“最小堆”的數據結構中。這個堆中最快執(zhí)行的在最上方。每個循環(huán)周期中,Redis服務器端都會對最小堆中已經到實際點的任務進行處理,并將下一個要執(zhí)行的任務還需要的時間記錄下來(此處的時間就是我們注冊時間到select中的socket的timeout)。因為Redis知道未來timeout時間內是沒有任務,所有可以休眠timeout時間。

通信協議

  • Redis序列化方法RESP(Redis Serialization Protocol)。一種直觀的文本協議,優(yōu)勢在于簡單直觀,易于實現,解析性能極好,Redis的高效性的原因之一。
  • Redis協議將傳輸結構分為五種單元類型,每種類型結束都加上回車換行(\r\n)。
    • 單行字符串以“+”符合開頭
    • 多行字符串以“$”符號開頭,后跟字符串長度
    • 整數以“:”開頭,后面跟整數字符串的形式
    • 錯誤信息以“-”開頭。
    • 數組以“*”開頭,后面跟數組長度
  • 一下示例:
//單行字符串 hello world +hello world\r\n //多行字符串hello world $11\r\nhello world\r\n //整數1024 :1024\r\n //錯誤信息 -WRONGTYPE Operation against a key holding the wrong kind of value\r\n //數組[1,2,3] *3\r\b:1\r\n:2\r\n:3 //NULL $-1\r\n //空串 $0\r\n\r\n
客戶端到服務器通信
  • 客戶端向服務器發(fā)送指令只有一種格式,多行字符串數組。比如一個簡單的set指令set myList addfirst,會被序列化如下格式
*3\r\n$3\r\nset\r\n$6\r\nmyList\r\n$8\r\naddfirst\r\n
  • 控制臺輸出這個字符串如下,可以看出來是一個很容易理解的格式:
*3 $3 set $6 myList $8 addfirst
服務器到客戶端
  • 服務器向客戶端回復響應信息要支持多種數據結構,所以消息響應在結構上要復雜一點,不過還是基于上文中的規(guī)則。
//單行字符串響應 docker-redis:0>set myList addfirst OK //OK是單行響應,沒有使用引號括起來 +OK//錯誤響應 新docker-redis:0>incr myList "ERR value is not an integer or out of range" //對字符串自增報錯,返回如下 -ERR value is not an integer or out of range//整數響應 新docker-redis:0>incr books "1" //此處1是整數 :1//多行字符串響應 新docker-redis:0>get myList "addfirst" //此處有引號,是多行響應 $8 addfirst//數組響應 新docker-redis:0>hset myMap name liaojiamin "1" 新docker-redis:0>hset myMap age 28 "1" 新docker-redis:0>hgetall myMap1) "name"2) "liao"3) "age"4) "28"//hgetall返回一個數組,第1,3 是key 2,4 是value,客戶端負責將數組組裝成字典放回,格式如下*4$4name$4liao$3age$228//嵌套方式 新docker-redis:0>scan 01) "2359296"2) 1) "Phone"2) "nettyim"3) "1027" //用sca掃描以游標形式獲取,第一個標識游標值,第二個標識當前游標下的數據返回的數組格式,數組的2個元素存儲的數組,數組第二個元素還是數組,三個元素 *2 $1 0 *3 $5 phone $7 nettyim $4 1027
  • 小結
    • Redis協議中大量冗余的回車換行,但是不影響性能,Redis的序列化協議還是互聯網技術領域非常受歡迎的文本協議。技術上,性能的確重要,但是同時兼具簡單易用,易實現,這些都是需要權衡。

上一篇:Redis高效性探索–管道

總結

以上是生活随笔為你收集整理的Redis高效性探索--线程IO模型,通信协议的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。