redis的特征:
1、基于記憶體的
2、key-value鍵值對的存儲結構
3、對于工作流是單線程的
4、io模型 epoll(多路複用)
5、value有類型
6、value有類型使具有本地方法->觸發計算向資料移動(結合redis工作單線程使redis在計算上能達到最大的性能效果)
工作模型:
下面展示一個操作模型

kernel是核心,redis和很多的用戶端并發通路通信的時候,因為可能發資料也有可能沒發資料,如何快速知道那個用戶端有資料進行讀取,沒有資料不進行讀取減少沒必要的操作,就用到了epoll 多路複用器(如果核心沒有epoll會降級成select或者poll)多路複用器隻能傳回io事件,隻能通過多路複用知道事件
演變為:
有了事件之後程式自己調代碼,比如從某個用戶端的inputStream流讀取資料,然後把讀取的資料放在記憶體裡進行計算
因為redis是單線程的,通過epoll知道有多個用戶端讀,但是因為是單線程,是以是周遊 inputStream,故io讀取是串行的,因為讀取出來一個要參與計算才能都第二個,是以計算也是串行的,是以讀取計算再讀取再計算整體是一個串行的。
存在問題:讀取一個然後計算,然後輸出結果,輸出之後讀取第二個,再計算,io網卡輸出方向是有時間間隔的,導緻有一段一段的時間被浪費。
io的輸出其實是有間隔的,沒有被使用
解決辦法:
多開ioThread,讓其中一個cpu單獨進行worker的計算,另外的cpu來讀取用戶端資料輸出資料
redis具有本地方法:
memcache 是kv 沒有資料類型,隻認識string串,是以存儲複雜機構的資料類型,就可以使用json,下面是一個解釋案例:
memcache存儲一個數組,可能就會存儲成k1,[a,b,c,d],但是如果我用戶端隻想取到下标為2的c,它需要完整的取回整個資料,在用戶端實作 計算(反序列化)->轉類型->截取 擷取到c
資料伺服器端往用戶端移動,移動資料量大(占帶寬),計算在用戶端(反複計算)
redis kv v有資料類型就有了本地方法,同樣的資料存在伺服器,會把字元串識别為list,有本地方法,用戶端拿值隻需要調用本地方法,拿k1的下标為2的資料,隻傳回一個c從網卡裡流出來,a,b,d不會參與網卡輸出流的過程,本地也不需要計算實作
計算向資料移動
單線程(worker)
redis的工作過程應該是 io讀取c1内容,讀取到記憶體後再計算c1,計算完後再把c1的結果 傳回,傳回後對于c1用戶端的線程就已經處理完了;才能去處理c2
秒殺場景:
解決高并發的場景,第一應該想到負載均衡,可以使用四層或者七層兩種技術(LVS/Nginx),有了負載均衡之後其實是讓伺服器變多一些,将用戶端分别發給不同的服務端處理,隻要最終保證資料中心想接受承受的并發量和服務端能構承受的并發量,比例關系合适(負載均勻沒有傾斜)
這個時候并發連接配接數是3,并行處理度是2,這時候 需要知道tomcat線程池的并行度是多少,這時候就能算出來 并行度是多少
是以衡量系統的業務性能,一個是并發連接配接數,一個考慮的是并行的處理能力
server1、server2最終通路db庫存的時候,要執行嚴格的串行化。是以要開事務,串行化多次通信,傳輸資料量比較大。将db換成redis,這時候他的key是item,value是99(有value類型就有本地方法,可以進行decrement減一操作),這時候用戶端通路->server1、server2->對redis進行并發調用(redis是單線程worker,串行化,是以他要先處理完一個decr,再進行第二個decr,天生的單線程),這一過程是天生的因為他單線程,前面server和redis裡面隻有一個io和線程處理的行為。
redis串行化 原子
弊端:伺服器多核,redis單核隻能放在一個cpu上(部署很多的redis,但是網卡吞吐量一定,一個redis消耗完網卡的性能帶寬,部署其他的redis發生網卡上的資源争搶)
worker thread壓在了 cpu上,這時候多起幾個iothread,每個線程壓在獨立的cpu上,worker、兩個iothread 可以達到并行執行(如果你隻有一顆cpu同時跑三個程式 ,cpu的時間片切換是串行的)
c1讓cpu2來讀取同時,c2讓cpu3來讀取,可能cpu2先讀完也可能cou3先讀完,但是 worker線程可以介入,c1讀完了worker可以計算處理c1,c1
worker處理完後可以把輸出押給cpu2來輸出,同時worker處理着c2,這個時候cpu2排程的網卡往外輸出【網卡使用率提高】
在整個實際計算複雜度上來說,一個機關一并行,完全串行就是可能要等6個時間機關【從計算上來講一直都是串行的】io綁定線程禁止多個線程去通路一個channel(阻止c1有人讀的時候,其他的也來讀c1)
場景解決方案:
String字元串完成的存儲場景:
字元串:對象的存儲、檔案的存儲、小圖檔的存儲、css樣式等等->session共享、uuid、VFS inmemory(小檔案)
數值:限流器等等->限流器(使用者通路一次+1操作,判斷機關時間通路的次數,超過就禁止通路)、統計點選率、統計
bitMap:12306、二進制、權限(思考linux的777)
nc localhost 6379 //連接配接上redis
keys * //展示有多少key
set k1 hello
get k1 //hello
keys *
*1 //一個key
$2 //兩個位元組
k1 //讀出來是k1
set k2 world
//讀完$2之後切割,再讀完$2再切割,redis當中傳輸的協定
keys *
*2
$2
k1
$2
k2
FlushAll
redis是二進制安全的,将要存儲的資料由用戶端存儲為byte(任何類型的資料交給redis都轉換為byte,其他人取也取到的是byte)
setbit k1 1(偏移量1) 1 //開辟了一個位元組,一個八進制的二進制位 0000 0000->開辟一個位元組在相應的偏移量打了1,0100 0000
STRLEN k1 ->1
get k1 ->@
setbit k1 7 1 //0100 0001
STRLEN k1 ->1
get k1 ->A
setbit k1 7 0
setbit k1 5 1->B
setbit k1 9999999 1
STRLEN 1250000//開辟很多的位元組出去,動态的擴寬value的位元組數量
bitcount k1 0(從第一個位元組)-1(到最後一個位元組,-1雙向索引代表最後一個)//會統計從開始到結束位元組的位置1的數量
![]()
關于redis在分布式架構當中使用的一些了解和總結
![]()
關于redis在分布式架構當中使用的一些了解和總結
二進制位有與或非的操作使用者統計:在一個時間窗裡,統計使用者的登入天數![]()
關于redis在分布式架構當中使用的一些了解和總結 ![]()
關于redis在分布式架構當中使用的一些了解和總結 STRLEN sean->消耗46位元組
JD登入 送禮物 2e使用者 需備用多少禮物 ->算活躍使用者
setbit 20210101 2 1//2021年一月一号 3号使用者登陸了
setbit 20210101 8 1//2021年一月一号 9号使用者登陸了
setbit 20210102 8 1//2021年一月2号 9号使用者登陸了
bittop or result 20210101 or 20210102 ->2
bitcount res 0 -1 ->2
list類型
list有序:放入順序
同向(lpush lpop)->實作了棧,(lpush rpop)->實作了隊列,利用下标準元素取值->實作了數組,LTRIM保留熱資料
場景:文章分頁、紅包(lpush 2 3 4 1)
LTRIM k1 0 4//删除的是索引之外的資料![]()
關于redis在分布式架構當中使用的一些了解和總結
hash指令的服務場景:
如果沒有hash’可能使用的是一個string類型的場景随着key’數量變多,整個redis為一個hashtable性能下降(除了做使用者io的處理還要做使用者的過期)![]()
關于redis在分布式架構當中使用的一些了解和總結 ![]()
關于redis在分布式架構當中使用的一些了解和總結 減少了 redis總體的數量,sean為一個次元,減少了網絡通信
HINCRBY