不少文章都會說,redis支持5種經常使用的數據類型,這實際上是存在很大的歧義。redis裏存的都是二進制數據,其實就是字節數組(byte[]),這些字節數據是沒有數據類型的,只有把它們按照合理的格式解碼後,能夠變成一個字符串,整數或對象,此時才具備數據類型。面試
這一點必需要記住。因此任何東西只要能轉化成字節數組(byte[])的,均可以存到redis裏。管你是字符串、數字、對象、圖片、聲音、視頻、仍是文件,只要變成byte數組。redis
所以redis裏的String指的並非字符串,它其實表示的是一種最簡單的數據結構,即一個key只能對應一個value。這裏的key和value都是byte數組,只不過key通常是由一個字符串轉換成的byte數組,value則根據實際須要而定。算法
在特定狀況下,對value也會有一些要求,好比要進行自增或自減操做,那value對應的byte數組必需要能被解碼成一個數字才行,不然會報錯。數據庫
那麼List這種數據結構,其實表示一個key能夠對應多個value,且value之間是有前後順序的,value值能夠重複。windows
Set這種數據結構,表示一個key能夠對應多個value,且value之間是沒有前後順序的,value值也不能夠重複。後端
Hash這種數據結構,表示一個key能夠對應多個key-value對,此時這些key-value對之間的前後順序通常意義不大,這是一個按照名稱語義來訪問的數據結構,而非位置語義。數組
Sorted Set這種數據結構,表示一個key能夠對應多個value,value之間是有大小排序的,value值不能夠重複。每一個value都和一個浮點數相關聯,該浮點數叫score。元素排序規則是:先按score排序,再按value排序。緩存
集羣帶來的好處是顯而易見的,好比容量增長、處理能力加強,還能夠按須要進行動態的擴容、縮容。但同時也會引入一些新的問題,至少會有下面這兩個。服務器
一是數據分配:存數據時應該放到哪一個節點上,取數據時應該去哪一個節點上找。
二是數據移動:集羣擴容,新增長節點時,該節點上的數據從何處來;集羣縮容,要剔除節點時,該節點上的數據往何處去。網絡
上面這兩個問題有一個共同點就是,如何去描述和存儲數據與節點的映射關係。又由於數據的位置是由key決定的,因此問題就演變爲如何創建起各個key和集羣全部節點的關聯關係。
集羣的節點是相對固定和少數的,雖然有增長節點和剔除節點。但集羣裏存儲的key,則是徹底隨機、沒有規律、不可預測、數量龐多,還很是瑣碎。
這就比如一所大學和它的全部學生之間的關係。若是大學和學生直接掛鉤的話,必定會比較混亂。現實是它們之間又加入了好幾層,首先有院系,其次有專業,再者有年級,最後還有班級。通過這四層映射以後,關係就清爽不少了。
這實際上是一個很是重要的結論,這個世界上沒有什麼問題是不能經過加入一層來解決的。若是有,那就再加入一層。計算機裏也是這樣的。
redis在數據和節點之間又加入了一層,把這層稱爲槽(slot),因該槽主要和哈希有關,又叫哈希槽。
最後變成了,節點上放的是槽,槽裏放的是數據。槽解決的是粒度問題,至關於把粒度變大了,這樣便於數據移動。哈希解決的是映射問題,使用key的哈希值來計算所在的槽,便於數據分配。
能夠這樣來理解,你的學習桌子上堆滿了書,亂的很,想找到某本書很是困難。因而你買了幾個大的收納箱,把這些書按照書名的長度放入不一樣的收納箱,而後把這些收納箱放到桌子上。
這樣就變成了,桌子上是收納箱,收納箱裏是書籍。這樣書籍移動很方便,搬起一個箱子就走了。尋找書籍也很方便,只要數一數書名的長度,去對應的箱子裏找就好了。
其實咱們也沒作什麼,只是買了幾個箱子,按照某種規則把書裝入箱子。就這麼簡單的舉動,就完全改變了原來人心渙散的情況。是否是有點小小的神奇呢。
一個集羣只能有16384個槽,編號0-16383。這些槽會分配給集羣中的全部主節點,分配策略沒有要求。能夠指定哪些編號的槽分配給哪一個主節點。集羣會記錄節點和槽的對應關係。
接下來就須要對key求哈希值,而後對16384取餘,餘數是幾key就落入對應的槽裏。slot = CRC16(key) % 16384。
以槽爲單位移動數據,由於槽的數目是固定的,處理起來比較容易,這樣數據移動問題就解決了。
使用哈希函數計算出key的哈希值,這樣就能夠算出它對應的槽,而後利用集羣存儲的槽和節點的映射關係查詢出槽所在的節點,因而數據和節點就映射起來了,這樣數據分配問題就解決了。
客戶端只要和集羣中的一個節點創建連接後,就能夠獲取到整個集羣的全部節點信息。此外還會獲取全部哈希槽和節點的對應關係信息,這些信息數據都會在客戶端緩存起來,由於這些信息至關有用。
客戶端能夠向任何節點發送請求,那麼拿到一個key後到底該向哪一個節點發請求呢?其實就是把集羣裏的那套key和節點的映射關係理論搬到客戶端來就好了。
因此客戶端須要實現一個和集羣端同樣的哈希函數,先計算出key的哈希值,而後再對16384取餘,這樣就找到了該key對應的哈希槽,利用客戶端緩存的槽和節點的對應關係信息,就能夠找到該key對應的節點了。
接下來發送請求就能夠了。還能夠把key和節點的映射關係緩存起來,下次再請求該key時,直接就拿到了它對應的節點,不用再計算一遍了。
理論和現實老是有差距的,集羣已經發生了變化,客戶端的緩存還沒來得及更新。確定會出現拿到一個key向對應的節點發請求,其實這個key已經不在那個節點上了。此時這個節點應該怎麼辦?
這個節點能夠去key實際所在的節點上拿到數據再返回給客戶端,也能夠直接告訴客戶端key已經不在我這裏了,同時附上key如今所在的節點信息,讓客戶端再去請求一次,相似於HTTP的302重定向。
這實際上是個選擇問題,也是個哲學問題。結果就是redis集羣選擇了後者。所以,節點只處理本身擁有的key,對於不擁有的key將返回重定向錯誤,即-MOVED key 127.0.0.1:6381,客戶端從新向這個新節點發送請求。
因此說選擇是一種哲學,也是個智慧。稍後再談這個問題。先來看看另外一個狀況,和這個問題有些相同點。
redis有一種命令能夠一次帶多個key,如MGET,我把這些稱爲多key命令。這個多key命令的請求被髮送到一個節點上,這裏有一個潛在的問題,不知道你們有沒有想到,就是這個命令裏的多個key必定都位於那同一個節點上嗎?
就分爲兩種狀況了,若是多個key不在同一個節點上,此時節點只能返回重定向錯誤了,可是多個key徹底可能位於多個不一樣的節點上,此時返回的重定向錯誤就會很是亂,因此redis集羣選擇不支持此種狀況。
若是多個key位於同一個節點上呢,理論上是沒有問題的,redis集羣是否支持就和redis的版本有關係了,具體使用時本身測試一下就好了。
在這個過程當中咱們發現了一件很有意義的事情,就是讓一組相關的key映射到同一個節點上是很是有必要的,這樣能夠提升效率,經過多key命令一次獲取多個值。
那麼問題來了,如何給這些key起名字才能讓他們落到同一個節點上,難不成都要先計算個哈希值,再取個餘數,太麻煩了吧。固然不是這樣了,redis已經幫咱們想好了。
能夠來簡單推理下,要想讓兩個key位於同一個節點上,它們的哈希值必需要同樣。要想哈希值同樣,傳入哈希函數的字符串必須同樣。那咱們只能傳進去兩個如出一轍的字符串了,那不就變成同一個key了,後面的會覆蓋前面的數據。
這裏的問題是咱們都是拿整個key去計算哈希值,這就致使key和參與計算哈希值的字符串耦合了,須要將它們解耦才行,就是key和參與計算哈希值的字符串有關可是又不同。
redis基於這個原理爲咱們提供了方案,叫作key哈希標籤。先看例子,{user1000}.following,{user1000}.followers,相信你已經看出了門道,就是僅使用Key中的位於{和}間的字符串參與計算哈希值。
這樣能夠保證哈希值相同,落到相同的節點上。可是key又是不一樣的,不會互相覆蓋。使用哈希標籤把一組相關的key關聯了起來,問題就這樣被輕鬆愉快地解決了。
相信你已經發現了,要解決問題靠的是巧妙的奇思妙想,而不是非要用牛逼的技術牛逼的算法。這就是小強,小而強大。
最後再來談選擇的哲學。redis的核心就是以最快的速度進行經常使用數據結構的key/value存取,以及圍繞這些數據結構的運算。對於與核心無關的或會拖累核心的都選擇弱化處理或不處理,這樣作是爲了保證核心的簡單、快速和穩定。
除此以外,選擇單線程還有如下這些緣由:
一、redis都是對內存的操做,速度極快(10W+QPS)
二、總體的時間主要都是消耗在了網絡的傳輸上
三、若是使用了多線程,則須要多線程同步,這樣實現起來會變的複雜
四、線程的加鎖時間甚至都超過了對內存操做的時間
五、多線程上下文頻繁的切換須要消耗更多的CPU時間
六、還有就是單線程自然支持原子操做,並且單線程的代碼寫起來更簡單
事務你們都知道,就是把多個操做捆綁在一塊兒,要麼都執行(成功了),要麼一個也不執行(回滾了)。redis也是支持事務的,但可能和你想要的不太同樣,一塊兒來看看吧。
redis的事務能夠分爲兩步,定義事務和執行事務。使用multi命令開啓一個事務,而後把要執行的全部命令都依次排上去。這就定義好了一個事務。此時使用exec命令來執行這個事務,或使用discard命令來放棄這個事務。
redis事務具備如下特色:
一、若是開始執行事務前出錯,則全部命令都不執行
二、一旦開始,則保證全部命令一次性按順序執行完而不被打斷
三、若是執行過程當中遇到錯誤,會繼續執行下去,不會中止的
四、對於執行過程當中遇到錯誤,是不會進行回滾的
看完這些,真想問一句話,你這能叫事務嗎?很顯然,這並非咱們一般認爲的事務,由於它連原子性都保證不了。保證不了原子性是由於redis不支持回滾,不過它也給出了不支持的理由。
不支持回滾的理由:
一、redis認爲,失敗都是由命令使用不當形成
二、redis這樣作,是爲了保持內部實現簡單快速
三、redis還認爲,回滾並不能解決全部問題
哈哈,這就是霸王條款,所以,好像使用redis事務的不太多
客戶端和集羣的交互過程是串行化阻塞式的,即客戶端發送了一個命令後必須等到響應回來後才能發第二個命令,這一來一回就是一個往返時間。若是你有不少的命令,都這樣一個一個的來進行,會變得很慢。
redis提供了一種管道技術,可讓客戶端一次發送多個命令,期間不須要等待服務器端的響應,等全部的命令都發完了,再依次接收這些命令的所有響應。這就極大地節省了許多時間,提高了效率。
聰明的你是否是意識到了另一個問題,多個命令就是多個key啊,這不就是上面提到的多key操做嘛,那麼問題來了,你如何保證這多個key都是同一個節點上的啊,哈哈,redis集羣又放棄了對管道的支持。
簡單瞭解下redis的協議,知道redis的數據傳輸格式。
發送請求的協議:
參數個數CRLF[圖片上傳失敗...(image-db6153-1582806589792)]
參數N的字節數CRLF參數N的數據CRLF
例如,SET name lixinjie,實際發送的數據是:
*3\r\n$3\r\nSET\r\n$4\r\nname\r\n$8\r\nlixinjie\r\n
接受響應的協議:
單行回覆,第一個字節是+
錯誤消息,第一個字節是-
整型數字,第一個字節是:
批量回復,第一個字節是$
例如,
+OK\r\n -ERR Operation against\r\n :1000\r\n $6\r\nfoobar\r\n *2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n
可見redis的協議設計的很是簡單。
文章篇幅問題,我這裏只解析部分題目,,若有須要所有答案的能夠關注個人公衆號【風平浪靜如碼】點資料領取獲取,另外我也整理出了全套Java面試題解析PDF版,有須要也能夠進公衆號獲取!
一、什麼是 Redis?
Redis 本質上是一個 Key-Value 類型的內存數據庫,很像 memcached,整個數據庫通通加載在內存當中進行操做,按期經過異步操做把數據庫數據 flush 到硬盤上進行保存。由於是純內存操做,Redis 的性能很是出色,每秒能夠處理超過 10 萬次讀寫操做,是已知性能最快的 Key-Value DB。
Redis 的出色之處不只僅是性能,Redis 最大的魅力是支持保存多種數據結構,此外單個value 的最大限制是 1GB,不像 memcached 只能保存 1MB 的數據,所以 Redis 能夠用來實現不少有用的功能,比方說用他的 List 來作 FIFO 雙向鏈表,實現一個輕量級的高性 能消息隊列服務,用他的 Set 能夠作高性能的 tag 系統等等。另外 Redis 也能夠對存入的Key-Value 設置 expire 時間,所以也能夠被看成一 個功能增強版的 memcached 來用。Redis 的主要缺點是數據庫容量受到物理內存的限制,不能用做海量數據的高性能讀寫,所以 Redis 適合的場景主要侷限在較小數據量的高性能操做和運算上。
二、Redis 相比 memcached 有哪些優點?
三、Redis 支持哪幾種數據類型?
String、List、Set、Sorted Set、hashes
四、Redis 主要消耗什麼物理資源?
內存。
五、Redis 的全稱是什麼?
Remote Dictionary Server。
六、Redis 有哪幾種數據淘汰策略?
noeviction:返回錯誤當內存限制達到而且客戶端嘗試執行會讓更多內存被使用的命令(大部分的寫入指令,但 DEL 和幾個例外)
allkeys-lru: 嘗試回收最少使用的鍵(LRU),使得新添加的數據有空間存放。
volatile-lru: 嘗試回收最少使用的鍵(LRU),但僅限於在過時集合的鍵,使得新添加的數據有空間存放。
allkeys-random: 回收隨機的鍵使得新添加的數據有空間存放。
volatile-random: 回收隨機的鍵使得新添加的數據有空間存放,但僅限於在過時集合的鍵。
volatile-ttl: 回收在過時集合的鍵,而且優先回收存活時間(TTL)較短的鍵,使得新添加的數據有空間存放。
七、Redis 官方爲何不提供 Windows 版本?
由於目前 Linux 版本已經至關穩定,並且用戶量很大,無需開發 windows 版本,反而會帶來兼容性等問題。
八、一個字符串類型的值能存儲最大容量是多少?
512M
九、爲何 Redis 須要把全部數據放到內存中?
Redis 爲了達到最快的讀寫速度將數據都讀到內存中,並經過異步的方式將數據寫入磁盤。
因此 Redis 具備快速和數據持久化的特徵。若是不將數據放在內存中,磁盤 I/O 速度爲嚴重影響 Redis 的性能。在內存愈來愈便宜的今天,Redis 將會愈來愈受歡迎。
若是設置了最大使用的內存,則數據已有記錄數達到內存限值後不能繼續插入新值。
十、Redis 集羣方案應該怎麼作?都有哪些方案?
十一、Redis 集羣方案什麼狀況下會致使整個集羣不可用?
有 A,B,C 三個節點的集羣,在沒有複製模型的狀況下,若是節點 B 失敗了,那麼整個集羣就會覺得缺乏 5501-11000 這個範圍的槽而不可用。
十二、MySQL 裏有 2000w 數據,Redis 中只存 20w 的數據,如何保證 Redis 中的數據都是熱點數據?
Redis 內存數據集大小上升到必定大小的時候,就會施行數據淘汰策略。
1三、Redis 有哪些適合的場景?
1四、Redis 支持的 Java 客戶端都有哪些?官方推薦用哪一個?
Redisson、Jedis、lettuce 等等,官方推薦使用 Redisson。
1五、Redis 和 Redisson 有什麼關係?
Redisson 是一個高級的分佈式協調 Redis 客服端,能幫助用戶在分佈式環境中輕鬆實現一些 Java 的對象 (Bloom filter, BitSet, Set, SetMultimap, ScoredSortedSet, SortedSet, Map, ConcurrentMap, List,ListMultimap, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, ReadWriteLock,AtomicLong, CountDownLatch, Publish / Subscribe, HyperLogLog)。
1六、Jedis 與 Redisson 對比有什麼優缺點?
Jedis 是 Redis 的 Java 實現的客戶端,其 API 提供了比較全面的 Redis 命令的支持;Redisson 實現了分佈式和可擴展的 Java 數據結構,和 Jedis 相比,功能較爲簡單,不支持字符串操做,不支持排序、事務、管道、分區等 Redis 特性。Redisson 的宗旨是促進使用者對 Redis 的關注分離,從而讓使用者可以將精力更集中地放在處理業務邏輯上。
1七、Redis 如何設置密碼及驗證密碼?
設置密碼:config set requirepass 123456
受權密碼:auth 123456
1八、說說 Redis 哈希槽的概念?
Redis 集羣沒有使用一致性 hash,而是引入了哈希槽的概念,Redis 集羣有 16384 個哈希槽,每一個 key 經過 CRC16 校驗後對 16384 取模來決定放置哪一個槽,集羣的每一個節點負責一部分hash 槽。
1九、Redis 集羣的主從複製模型是怎樣的?
爲了使在部分節點失敗或者大部分節點沒法通訊的狀況下集羣仍然可用,因此集羣使用了主從複製模型,每一個節點都會有 N-1 個複製品.
20、Redis 集羣會有寫操做丟失嗎?爲何?
Redis 並不能保證數據的強一致性,這意味這在實際中集羣在特定的條件下可能會丟失寫操做。
2一、Redis 集羣之間是如何複製的?
2二、Redis 集羣最大節點個數是多少?
2三、Redis 集羣如何選擇數據庫?
2四、怎麼測試 Redis 的連通性?
2五、Redis 中的管道有什麼用?
2六、怎麼理解 Redis 事務?
2七、Redis 事務相關的命令有哪幾個?
2八、Redis key 的過時時間和永久有效分別怎麼設置?
2九、Redis 如何作內存優化?
30、Redis 回收進程如何工做的?
3一、Redis 回收使用的是什麼算法?
3二、Redis 如何作大量數據插入?
3三、爲何要作 Redis 分區?
3四、你知道有哪些 Redis 分區實現方案?
3五、Redis 分區有什麼缺點?
3六、Redis 持久化數據和緩存怎麼作擴容?
3七、分佈式 Redis 是前期作仍是後期規模上來了再作好?爲何?
3八、Twemproxy 是什麼?
3九、支持一致性哈希的客戶端有哪些?
40、Redis 與其餘 key-value 存儲有什麼不一樣?
4一、Redis 的內存佔用狀況怎麼樣?
4二、都有哪些辦法能夠下降 Redis 的內存使用狀況呢?
4三、查看 Redis 使用狀況及狀態信息用什麼命令?
4四、Redis 的內存用完了會發生什麼?
4五、Redis 是單線程的,如何提升多核 CPU 的利用率?
4六、一個 Redis 實例最多能存放多少的 keys?List、Set、Sorted Set 他們最多能存放多少元素?
4七、Redis 常見性能問題和解決方案?
4八、Redis 提供了哪幾種持久化方式?
4九、如何選擇合適的持久化方式?
50、修改配置不重啓 Redis 會實時生效嗎?
文章篇幅問題,我這裏只解析部分題目,,若有須要所有答案的能夠關注個人公衆號【風平浪靜如碼】點資料領取獲取,另外我也整理出了全套Java面試題解析PDF版,有須要也能夠進公衆號獲取!
部分資料圖分享
歡迎你們關注我新開通的公衆號【風平浪靜如碼】,海量Java相關文章,學習資料都會在裏面更新,整理的資料也會放在裏面。
以爲寫的還不錯的就點個贊,加個關注唄!點關注,不迷路,持續更新!!!