我之前還沒接觸Redis的時候,聽到大數據組的小夥伴在討論Redis,以爲這東西好高端,要是哪天咱們組也可使用下Redis就行了,好長一段時間後,咱們項目中終於引入了Redis這個技術,我用了幾下,感受Redis也就那麼回事啊,不就是get set嗎?當我又知道Redis還有自增、自減操做,並且這些操做仍是原子性的,秒殺就能夠用這個技術,我就以爲我已經熟悉Redis了。相信有很多curd boy是和之前的我一個想法:Redis不就是get set increment嗎?其實否則,Redis遠遠沒有咱們想象中的那麼簡單,今天我就在此獻醜來談談Redis。linux
關於Redis是什麼,如何安裝等問題就不闡述了,咱們直接進入正題吧。程序員
Redis有五種數據類型,即 string,list,hash,set,zset(sort set),我想這點只要稍微對Redis有點了解的小夥伴都應該清楚。下面,咱們就來討論下這五種數據類型的應用場景。面試
這個類型相信是你們最熟悉的了,可是千萬不要小瞧它,它能夠作不少事情,也能夠牽出一系列的問題。redis
咱們先從最簡單的入手:算法
localhost:6379> set coderbear hello OK localhost:6379> get codebear "hello"
這兩個命令相信你們都知道,我就不解釋了,咱們再來用下strlen這個命令:shell
localhost:6379> strlen codebear (integer) 5
哦,我明白了strlen這個命令能夠得到Value的長度啊,hello的長度是5,因此輸出就是5。這個解釋對不對呢?不着急,咱們慢慢往下看。數據庫
咱們使用append命令爲codebear這個key追加點東西:編程
APPEND codebear 中國
若是咱們再次使用strlen命令會輸出什麼呢?固然是7啊,雖然我數學很差,可是10之內的數數,我仍是no problem的,可是當咱們再次執行strlen命令,你會發現一個奇怪的現象:windows
localhost:6379> strlen codebear (integer) 11
納尼,爲何是11,是否是咱們的打開方式不對,要再也不試下?不用了,就算再試上三生三世,你看到的輸出仍是11。這是爲何呢?這就牽扯到二進制安全問題了。api
所謂的二進制安全就是隻會嚴格的按照二進制的數據存取,不會妄圖以某種特殊格式解析數據。Redis就是二進制安全的,它存取的永遠是二進制數據,也能夠說存取的永遠是字節數組。
咱們來get下codebear康康:
get codebear "hello\xe4\xb8\xad\xe5\x9b\xbd"
你會發現好端端的"hello中國",存儲到Redis居然變成這樣了,由於咱們的Xshell客戶端使用的是UTF-8,在UTF-8下,一箇中文一般是三個字節,兩個中文就是6個字節,因此在Redis內部"hello中國"佔了5+6=11個字節。
若是你還不信,咱們把Xshell的編碼改爲GBK看看,在GBK的世界裏,一箇中文一般佔兩個字節,因此:
localhost:6379> set codebeargbk 中國 OK localhost:6379> get codebeargbk "\xd6\xd0\xb9\xfa" localhost:6379> strlen codebeargbk (integer) 4
因此說,醒醒吧,小夥計,在Redis裏面是不可能存中文的,咱們之因此在程序裏面能夠輕輕鬆鬆的拿到中文,只是由於API作了解碼的操做。
沒想到一個String還牽出二進制安全的問題,看來真是不能小瞧任何一個知識點啊,這也就是常說的搜索地獄,當你查找一個問題,發現這個問題的答案又出現了一個你不懂的東西,因而你又開始看那個你不懂的東西,而後又冒出另一個你不懂的概念,因而...說多了都是淚啊。
咱們常常用Redis作緩存,用到的就是set get這兩個命令了,咱們還能夠用Redis作秒殺系統,在絕大部分狀況下,用的也是String這個數據類型,讓咱們繼續往下看:
localhost:6379> set codebearint 5 OK localhost:6379> incr codebearint (integer) 6
也許你沒用過incr命令,可是能夠從結果和命令名稱猜出incr這個命令是幹嗎的把,沒錯,就是自增,既然有自增,還能夠作自減:
localhost:6379> decr codebearint (integer) 5
剛纔是6,調用了decr 命令後,又變成5了。
好了,又有一個問題,String是字符串啊,它怎麼能夠作加法或減法的操做?
咱們用type命令來檢查下codebearint 這個key的類型是什麼:
localhost:6379> type codebearint string
沒錯,是如假包換的String類型啊。
咱們再來看一個東西:
localhost:6379> object encoding codebear "raw" localhost:6379> object encoding codebearint "int"
原來在Redis的內部還會爲這個key打上一個標記,來標記它是什麼類型的(這個類型可和Redis的五種數據類型不同哦)。
有這麼一個需求:統計指定用戶一年之中登陸的天數?這還不簡單,我建個登陸表,不就能夠了嗎?沒錯,確實能夠,可是這代價是否是有點高,若是有100萬個用戶,那麼這登陸表要有多大啊。這個時候,bitmap就橫空出世了,它簡直是解決此類問題的神器。
咱們先來看看什麼是bitmap,說穿了,就是二進制數組,咱們來畫一張圖說明下:
這就是bitmap了,由許許多多的小格子組成,格子裏面只能放1或者0,說的專業點,那一個個小格子就是一個個bit。
String就很好的支持了bitmap,提供了一系列bitmap的命令,讓咱們來試試:
setbit codebear 3 1 (integer) 0 localhost:6379> get codebear "\x10"
這是什麼意思呢,就是說如今有8個小格子,第四個格子裏面放的是1(索引從0開始嘛),其餘都是0,就像這樣的:
讓咱們計算下,大小應該是多少,1 2 4 8 16 ,沒錯,用十進制表示是16,而咱們get codebear輸出的是「\x10」,「\x」表明是十六進制,也就是16進制的10,16進制的10就是十進制的16了。
咱們再用下strlen命令看下:
localhost:6379> strlen codebear (integer) 1
看來只佔據了一個字節,讓咱們繼續:
localhost:6379> setbit codebear 5 1 (integer) 0
bitmap就變成了下面這個醬紫:
大小用十進制表示就是20。
咱們繼續看下strlen:
localhost:6379> strlen codebear (integer) 1
仍是隻佔據了一個字節,咱們明明已經存儲了兩個數據了,是否是很是神奇。
讓咱們繼續:
localhost:6379> setbit codebear 15 1 (integer) 0 localhost:6379> strlen codebear (integer) 2
從這裏能夠看出bitmap是能夠擴展的,因爲如今我在第16個格子裏面放了1,因此bitmap擴展了,如今strlen是2。
那麼我想知道如今16個格子裏面有多少格子是1的,怎麼辦呢?用bitcount命令:
localhost:6379> bitcount codebear (integer) 3
到了這一步,是否是豁然開朗了,用bitmap能夠輕鬆統計指定用戶一年之中登陸的天數。
咱們假設codebear第一天登陸過,次日登陸過,最後一天登陸過:
localhost:6379> setbit codebear 0 1 (integer) 0 localhost:6379> setbit codebear 1 1 (integer) 0 localhost:6379> setbit codebear 364 1 (integer) 0 localhost:6379> bitcount codebear (integer) 3
繼續用strlen來看看,記錄了整年登陸過的日子佔據了多少字節:
localhost:6379> strlen codebear (integer) 46
僅僅46個字節,就算每一年都登陸,也只佔用46個字節,我不知道這樣的數據存在數據庫應該是多大的,可是我想遠遠不止46個字節把,若是有100萬個用戶,也就不到50M,哪怕這100萬個用戶每天登陸佔據的字節也是這些。
咱們再把上面的需求改下:統計指定用戶在任意時間窗口內登陸的天數?
bitcount命令後面還能夠帶兩個參數,即 開始 和 結束:
localhost:6379> bitcount codebear 0 2 (integer) 2
咱們還能夠把第二個參數寫成-1,表明直到最後一位,即:
localhost:6379> bitcount codebear 0 -1 (integer) 3
bitmap的強大遠遠不止這些,咱們再來康康第二個需求:統計任意日期內,全部用戶登陸狀況:
腦闊疼啊,這特麼的是人乾的事情嗎?別急,這一切均可以用bitmap來實現。
第一個需求,很好實現,假設用戶codebear的userId是5,用戶小強的userId是10,咱們能夠創建一個key爲日期的bitmap,其中第四個、第九個小格子是1,表明userId是五、userId是1的用戶在這一天登陸過,而後bitcount下就萬事大吉,以下所示:
localhost:6379> setbit 20200301 4 1 (integer) 0 localhost:6379> setbit 20200301 9 1 (integer) 0 localhost:6379> bitcount 20200301 (integer) 2
要實現下面兩個需求,得用新的命令了,直接看結果吧:
localhost:6379> setbit 20200229 9 1 (integer) 1 localhost:6379> bitop and andResult 20200301 20200229 (integer) 2 localhost:6379> bitcount andResult (integer) 1 localhost:6379> bitop or orResult 20200301 20200229 (integer) 2 localhost:6379> bitcount orResult (integer) 2
下面來解釋下,首先又建立了一個key爲20200229的bitmap,其中第10個小格子爲1,表明用戶Id爲10的用戶在20200229這一天登陸過,接下來對key爲20200301和20200229的bitmap作與運算,結果也是一個bitmap,而且把結果放入了andResult這個key中,下面就是熟悉的bitcount命令了,康康有多少個小格子爲1的,結果是1,也就是這兩天,天天都登陸的用戶有一個。
既然有與運算,那麼就有或運算,下面就是或運算的命令,求出了這兩天有兩位用戶登陸。
這樣後面兩個需求就輕鬆搞定了。
還有大名鼎鼎的布隆過濾器也是用bitmap實現的,關於布隆過濾器在之前的博客也介紹過。
看了那麼多的例子,你們有沒有發現一個問題,全部的運算都在Redis內部完成,對於這種狀況,有一個很高大上的名詞:計算向數據移動。與之相對的,把數據從某個地方取出來,而後在外部計算,就叫數據向計算移動。
Redis的list底層是一個雙向鏈表,咱們先來康康幾個命令:
localhost:6379> lpush codebear a b c d e (integer) 5 localhost:6379> lrange codebear 0 -1 1) "e" 2) "d" 3) "c" 4) "b" 5) "a"
push,我懂,推嘛,可是前面+個l是什麼意思呢,前面的l表明左邊,lpush就是在左邊推,這樣第一個推動去的,就是在最右邊,lrange是從左開始拿出指定索引範圍內的數據,後面的-1就是表明拿到最後一個爲止。
既然能夠在左邊推,那麼必須能夠在右推啊,咱們康康:
localhost:6379> rpush codebear z (integer) 6 localhost:6379> lrange codebear 0 -1 1) "e" 2) "d" 3) "c" 4) "b" 5) "a" 6) "z"
還有兩個彈出命令也很經常使用,咱們來使用下:
localhost:6379> lpop codebear "e" localhost:6379> lrange codebear 0 -1 1) "d" 2) "c" 3) "b" 4) "a" 5) "z" localhost:6379> rpop codebear "z" localhost:6379> lrange codebear 0 -1 1) "d" 2) "c" 3) "b" 4) "a"
lpop是彈出左邊第一個元素,rpop就是彈出右邊第一個元素。
若是咱們使用lpush,rpop或者rpush,lpop這樣的組合,就是先進先出,就是隊列了;若是咱們使用lpush,lpop或者rpush,rpop這樣的組合,就是先進後出,就是棧了,因此Redis還能夠做爲消息隊列來使用,用到的就是list這個數據類型了。
相信你們必定都玩過論壇,後面發帖的,帖子一般在前面。爲了性能,咱們能夠把帖子的數據放在Redis中的list裏面,可是總不能無限往list裏面扔數據吧,通常前面幾頁的帖子翻看的人會多一些,再日後面的帖子就不多有人看了,因此咱們能夠把前面幾頁的帖子數據放在list中,而後設定一個規則,定時去list刪數據,咱們就能夠用到list的ltrim嗎,命令:
localhost:6379> ltrim codebear 1 -1 OK localhost:6379> lrange codebear 0 -1 1) "c" 2) "b" 3) "a"
這個ltrim有點奇怪,它是保留索引範圍以內的數據,刪除索引範圍以外的數據,如今給定的第一個參數是1,第二個參數是-1,就是要保留從索引爲1到結束的數據,因此索引爲0的數據被刪除了。
如今有一個產品詳情頁,裏面有產品介紹,有價格,有舒適提示,有瀏覽數,有購買人數等等一堆信息,固然咱們能夠把整個對象都用String來存儲,可是可能有一些地方只須要產品介紹,儘管是這樣,咱們仍是必須得把整個對象都拿出來,是否是有點不太划算呢?hash就能夠解決這樣的問題:
localhost:6379> hset codebear name codebear (integer) 1 localhost:6379> hset codebear age 18 (integer) 1 localhost:6379> hset codebear sex true (integer) 1 localhost:6379> hset codebear address suzhou (integer) 1 localhost:6379> hget codebear address "suzhou"
若是咱們是存儲整個對象,如今想修改下age,怎麼辦?要把整個對象所有拿出來,而後再賦值,最後又得放回去,可是如今:
localhost:6379> hincrby codebear age 2 (integer) 20 localhost:6379> hget codebear age "20"
set是一種無序,且去重的數據結構,咱們能夠用它去重,好比我如今要存儲全部商品的Id,就能夠用set來實現,有什麼場景須要存儲全部商品的Id呢?防止緩存穿透,固然防止緩存穿透有不少實現方案,set方案只是其中的一種。咱們來康康它的基本用法:
localhost:6379> sadd codebear 6 1 2 3 3 8 6 (integer) 5 localhost:6379> smembers codebear 1) "1" 2) "2" 3) "3" 4) "6" 5) "8"
能夠很清楚的看到咱們存進去的數據被去重了,並且數據被打亂了。
咱們再來看看srandmember這個命令有什麼用?
localhost:6379> srandmember codebear 2 1) "6" 2) "3" localhost:6379> srandmember codebear 2 1) "6" 2) "2" localhost:6379> srandmember codebear 2 1) "6" 2) "3" localhost:6379> srandmember codebear 2 1) "6" 2) "2" localhost:6379> srandmember codebear 2 1) "8" 2) "3"
srandmember 後面能夠帶參數,後面跟着2,就表明隨機取出兩個不重複的元素,若是想取出兩個能夠重複的元素,怎麼辦呢?
localhost:6379> srandmember codebear -2 1) "6" 2) "6"
若是後面跟着負數,就表明取出的元素能夠是重複的。
若是後面跟的數字大於set元素的個數呢?
localhost:6379> srandmember codebear 100 1) "1" 2) "2" 3) "3" 4) "6" 5) "8" localhost:6379> srandmember codebear -10 1) "8" 2) "1" 3) "1" 4) "1" 5) "6" 6) "1" 7) "1" 8) "2" 9) "6" 10) "8"
若是是正數的話,最多把set中全部的元素都返回出來,由於正數是不重複的,再多返回一個出來,就重複了,若是是負數,那麼不影響,後面跟着幾,就返回多少個元素出來。
咱們作抽獎系統,就能夠用到這個命令了,若是能夠重複中獎,後面帶着負數,若是不能重複中獎,後面帶着正數。
set還能夠計算差集、並集、交集:
localhost:6379> sadd codebear1 a b c (integer) 3 localhost:6379> sadd codebear2 a z y (integer) 3 localhost:6379> sunion codebear1 codebear2 1) "a" 2) "c" 3) "b" 4) "y" 5) "z" localhost:6379> sdiff codebear1 codebear2 1) "b" 2) "c" localhost:6379> sinter codebear1 codebear2 1) "a"
上面的命令就不過多解釋了,這有什麼用呢,咱們能夠利用它來作一個「騙取融資」的推薦系統:大家的共同好友是誰,大家都在玩的遊戲是哪一個,你可能認識的人。
set是無序的,而zset是有序的,其中每一個元素都有一個score的概念,score越小排在越前面,仍是先來康康它的基本使用把:
localhost:6379> zadd codebear 1 hello 3 world 2 tree (integer) 3 localhost:6379> zrange codebear 0 -1 withscores 1) "hello" 2) "1" 3) "tree" 4) "2" 5) "world" 6) "3" localhost:6379> zrange codebear 0 -1 1) "hello" 2) "tree" 3) "world"
如今咱們就建立了一個key爲codebear 的zset,往裏面添加了三個元素:hello ,world ,tree,score分別爲1,3,2,後面用zrange取出結果,發現已經按照score的大小排好序了,若是後面跟着withscores,就會把score一塊兒取出來。
若是咱們想看看tree排在第幾位,咱們能夠用zrank命令:
localhost:6379> zrank codebear tree (integer) 1
由於是從0開始的,因此結果是1。
若是咱們想查詢tree的score是多少:
localhost:6379> zscore codebear tree "2"
若是咱們想取出從大到小的前兩個,怎麼辦:
localhost:6379> zrange codebear -2 -1 1) "tree" 2) "world"
可是這樣的結果是有些錯誤的,從大到小的前兩個,第一個元素是world,又該如何呢:
localhost:6379> zrevrange codebear 0 1 1) "world" 2) "tree"
像排行榜,熱點數據,延遲任務隊列均可以用zset來實現,其中延遲任務隊列在我之前的博客有介紹過。
談到szet,可能還會引出一個問題,Redis中的zset是用什麼實現的?跳錶。
關於跳錶,在這裏就不展開了,爲何要用跳錶實現呢,是由於跳錶的特性:
讀寫均衡。
這是一個經典的面試題,幾乎面試談到Redis,80%都會問這問題,爲何Redis那麼快呢?主要有如下緣由:
這就是一個開放式的問題了,有不少答案,好比:
由於Redis是單線程的,因此同時只能處理一個讀寫請求,因此能夠保證原子性。
咱們一直在強調Redis是單線程的,Redis是單線程的,可是Redis真的徹底是單線程的嗎?其實否則,咱們說的Redis是單線程的,只是Redis的讀寫是單線程的,也就是work thread只有一個。
I/O Threads是Redis 6.0推出的新特性,在之前Redis從socket拿到請求、處理、把結果寫到socket是串行化的,即:
而Redis6.0推出了I/O Threads後:
能夠看到I/O Thread有多個,I/O Thread負責從socket讀數據和寫數據到socket,work thread在處理數據的同時,其餘I/O Thread能夠再從socke讀數據,先準備好,等work thread忙完手中的事情了,立馬能夠處理下個請求。
可是work thread只有一個,這點要牢記。
epoll是一種多路複用IO模型,在說epoll以前,不得不說下傳統的IO模型,傳統的IO模型是同步阻塞的,什麼意思呢?就是服務端創建的socket會死死的等待客戶端的鏈接,等客戶端鏈接上去了,又會死死的等待客戶端的寫請求,一個服務端只能爲一個客戶端服務。
後來,程序員們發現能夠用多線程來解決這個問題:
看起來,很美好,一個服務端能夠爲N個客戶端服務,可是總不能無限開線程把 ,在Java中,線程是有本身的獨立棧的,一個線程至少消耗1M,並且無限開線程,CPU也會受不鳥啊。
雖而後面還經歷了好幾個時代才慢慢來到了epoll的時代,可是我做爲一個curd boy,api boy就不去研究的那麼深了,如今咱們跨過中間的時代,直接來到epoll的時代吧。
咱們先來認識下epoll的方法,在linux中,能夠用man來看看OS函數:
man epoll
在介紹中有這麼一段話:
* epoll_create(2) creates a new epoll instance and returns a file descriptor referring to that instance. (The more recent epoll_create1(2) extends the functionality of epoll_create(2).) * Interest in particular file descriptors is then registered via epoll_ctl(2). The set of file descriptors currently registered on an epoll instance is sometimes called an epoll set. * epoll_wait(2) waits for I/O events, blocking the calling thread if no events are currently available.
雖然我英語實在是爛,可是藉助翻譯,仍是能夠勉強看懂一些,大概的意思是:
下面還給出了一個demo,咱們來試着看下:
epollfd = epoll_create1(0);//建立一個epoll實例,返回一個 epoll文件描述符 if (epollfd == -1) { perror("epoll_create1"); exit(EXIT_FAILURE); } ev.events = EPOLLIN; ev.data.fd = listen_sock; // 註冊感興趣的事件 // 第一個參數爲epoll文件描述符 // 第二個參數爲動做,如今是要添加感興趣的事件 // 第三個參數爲被監聽的文件描述符 // 第四個參數告訴內核須要監聽什麼事件 // 如今監聽的事件是EPOLLIN,表示對應的文件描述符上有可讀數據 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) { perror("epoll_ctl: listen_sock"); exit(EXIT_FAILURE); } // 一個死循環 for (;;) { // 等待IO事件的發生 // 第一個參數是epoll文件描述符 // 第二個參數是發生的事件集合 // 第三個參數不重要 // 第四個參數是等待時間,-1爲永遠等待 // 返回值是發生的事件的個數 nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1); if (nfds == -1) { perror("epoll_wait"); exit(EXIT_FAILURE); } // 循環 for (n = 0; n < nfds; ++n) { // 若是發生的事件對應的文件描述符是listen_sock if (events[n].data.fd == listen_sock) { // 創建鏈接 conn_sock = accept(listen_sock, (struct sockaddr *) &addr, &addrlen); if (conn_sock == -1) { perror("accept"); exit(EXIT_FAILURE); } setnonblocking(conn_sock);// 設置非阻塞 ev.events = EPOLLIN | EPOLLET;// 設置感興趣的事件 ev.data.fd = conn_sock; // 添加感興趣的事件,爲 EPOLLIN或者EPOLLET if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1) { perror("epoll_ctl: conn_sock"); exit(EXIT_FAILURE); } } else { do_use_fd(events[n].data.fd); } } }
因爲本人沒有學習過C語言,有些註釋的不對的地方請多擔待,可是自認爲大概就是這麼個意思。
若是學過Java中的NIO的話,就會發現這個模式和Java中的NIO很像,那是由於Java中的NIO最終調用的就是OS的epoll函數。
epoll究竟是個什麼鬼呢,說的簡單點,就是告訴內核我對哪些事件感興趣,內核就會幫你監聽,當發生了你感興趣的事件後,內核就會主動通知你。
這有什麼優勢呢:
epoll函數是基於OS的,在windows裏面,沒有epoll這東西。
好了,關於epoll的介紹就到這裏了,又出現了三個新名詞:用戶態、內核態、文件描述符,就先不解釋了,之後寫NIO的博客再說吧。那時候,會更詳細的介紹epoll。
通常來講,經常使用的過時策略有三種:
Redis使用的是按期刪除+懶刪除的策略。
若是咱們有好多命令要交給Redis,第一個方案是一條一條發,缺點不言而喻:每條命令都須要通過網絡,性能比較低下,第二個方案就是用管道。
在介紹管道以前,先要演示一個東西:
[root@localhost ~]# nc localhost 6379 set codebear hello +OK get codebear $5 hello
咱們往Redis發送命令,不必定必需要用Redis的客戶端,只要鏈接上Redis服務器的端口就能夠了,至於get codebear命令後面輸出了$5是什麼意思,就不在這裏討論了。
管道到底怎麼使用呢,有了上面的基礎,其實也很簡單:
[root@localhost ~]# echo -e "set codebear hello1234 \n incr inttest \n set haha haha" | nc localhost 6379 +OK :1 +OK
把命令與命令之間用\n分割,而後經過nc發送給Redis。
咱們再來康康是否成功了:
[root@localhost ~]# nc localhost 6379 get inttest $1 1 get codebear $9 hello1234 get haha $4 haha
須要注意的,雖然多條命令是一塊兒發送出去的,可是總體不具備原子性。
各大操做Redis的組件也提供了管道發送的方法,若是下次在項目中須要發送多個命令不妨試下。
當咱們有個消息須要以廣播的形式推送給各個系統,除了採用消息隊列的方式,還能夠採用發佈與訂閱的方式,在Redis中就提供了發佈訂閱的功能,咱們來看下如何使用。
首先,咱們要建立一個訂閱者,訂閱名稱爲hello的channel:
localhost:6379> subscribe hello Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "hello" 3) (integer) 1
而後,要建立一個發佈者,往名稱爲hello的channel發送消息:
localhost:6379> publish hello goodmorning (integer) 1
最後,再回到訂閱者,發現接收到了消息:
1) "message" 2) "hello" 3) "goodmorning"
可是須要注意,若是先發布消息,訂閱者再去訂閱,是收不到歷史消息的。
是否是特別簡單,在我還不知道有ZooKeeper的時候,我以爲能夠用Redis的發佈訂閱功能來作配置中心。
若是Redis內存滿了,再也容納不下新數據了,就會觸發Redis的內存淘汰策略,在redis.conf有一個配置,就是用來配置具體的內存淘汰策略的:
maxmemory-policy volatile-lru
它有好幾個配置,在講具體的配置前,要先說兩個名詞,若是這兩個名詞不瞭解的話,那麼每一個配置的含義真是隻能死記硬背了。
下面就是具體的配置了,咱們一一來看:
在生產環境中,到底應該使用哪一個配置呢?
能夠說網上的答案千差萬別,可是能夠統一的是通常不會選擇noeviction,因此這個問題仍是用萬金油的答案,一個徹底正確的廢話答案:看場景。
本篇博客到這裏就結束了,還有不少東西沒有提到,先拋開主從、集羣,光單機版的Redis就還有持久化、事務、協議、modules、GEO、hyperLogLog等等,還有Redis的延伸問題——緩存擊穿、緩存雪崩、緩存穿透等等問題,都沒有提到,等之後再和你們嘮嘮嗑把。