## 1、項目中redis的應用場景?
redis的應用場景與其提供的數據結構有關,雖然redis也提供了持久化的功能,但是通常的都會將redis作為緩存來使用。
- redis基本的數據結構有:string、hash、list、set、sortedset。
- 項目中典型的應用場景有緩存token來記錄用戶的登錄狀態,緩存session或者緩存一些頻繁被查詢的數據。
- 由于redis工作線程是單線程的特性,可以實現服務的無狀態化和無鎖化;單機鎖或者分布式鎖都可以抽離到redis中實現。
## 2、set和zset的應用場景?
* set是使用哈希表構造的,根據哈希表的特性可以用在給用戶打上感興趣的標簽、知道不同用戶之間相互的愛好群體或者是用在共同好友的功能上。
* zset使用hashmap和skipList實現;常用在根據時間排序的新聞列表和閱讀排行榜上。
>跳表參考:[https://www.cnblogs.com/bigsai/p/14193225.html](https://www.cnblogs.com/bigsai/p/14193225.html)
## 3、redis是單線程還是多線程?
redis的工作線程仍然是單線程,在redis6之前redis只有一個線程處理IO操作和執行指令。在redis6之后出現了IO多線程,每個客戶端都會綁定一個IO線程,但是redis服務器執行指令仍然是單線程的。
redis5的工作模式如下:內核到redis服務器的數據、指令搬運都是串行的,只有一個工作線程負責輸入、計算、輸出。
redis6的工作模式如下:工作線程是單線程,但是每個客戶端的IO操作是多線程的,這樣可以很好的縮短執行時間,更好的利用網卡的資源。
總之從客戶端的時候上來將redis是單線程還是多線程的沒有區別。
## 4、redis存在線程安全問題嘛?為什么?
因為redis的工作線程是單線程的,所以redis服務器內部執行指令不存在線程安全問題;但是業務上的線程安全問題需要程序員自己保證。
## 5、緩存穿透、緩存擊透、緩存雪崩問題?
這三個問題都是在【客戶端——redis——數據庫】這樣的一個拓撲模型下出現的。
1. **緩存穿透**:緩存穿透指的是redis和數據庫中都沒有用戶查詢的數據,如果大量這樣無效的請求達到數據庫則會造成無意義的壓力。解決方法為:
- 在redis中沒有查詢到鍵緩存空值或者默認值。
- 使用布隆過濾器快速判斷數據是否存在。
- 進一步優化可以在客戶端從redis讀取key的時候加入鎖,避免數據庫中大量事務同時排隊,這樣也是會直接對數據庫造成壓力的。
2. **緩存擊透**:緩存中的某個或某幾個熱點數據過期了(或者沒有緩存過),同時大量的并發請求訪問該熱點數據,這些并發請求就會直接去訪問數據庫。(注意與緩存穿透相比數據庫中是有這些數據的),解決方法:
- 互斥鎖方案,客戶端從redis中讀取key時加入鎖,第一個請求去數據庫中讀取輸入放入redis中,其他請求被阻塞等待;等到第一個鎖釋放的時候redis中已經有數據了,其他請求直接讀取內存中的數據阻塞也就沒有意義了(同樣快)。
- 不給熱點數據設置過期時間,由后臺異步更新緩存。
3. **緩存雪崩**:很多熱點數據同時過期,或者沒有被緩存過,緩存擊透可以說是緩存雪崩的子集。緩存雪崩的解決思路與緩存擊透一致。
## 6、redis如何刪除過期key?
過期鍵的刪除策略主要有三種,分別為:
- 定時刪除:在設置過期時間的時候設置定時器,由定時器刪除。
- 惰性刪除:每次訪問數據的時候判斷是否過期了,過期了則刪除。
- 定期刪除:由后臺線程按照固定周期的刪除。
redis過期鍵的刪除策略采用**惰性刪除和定期刪除**的組合:
1. 惰性刪除策略表現為當每次get一個鍵的內容的時候,就會先判斷(expireIfNeeded方法)鍵是否過期了,如果過期了則進行刪除,不過期的話則獲取值返回。
2. 定期刪除表現為redis服務器后臺會周期性的執行一個函數(activeExpireCycle),檢查某幾個數據庫中的某部分鍵是否過期,不會一次性的將所有的鍵都檢查一遍;下次執行的時候則會接著上次檢查的剩下的繼續檢查下去,重復循環。
>備注:因為redis工作線程是單線程的,因此后臺執行刪除鍵的時候會暫停其他工作服務,所以redis服務器不會讓這個延遲時間過長而盡可能的去刪除數據。
## 7、緩存如何淘汰?
在內存空間不足的情況下就會淘汰數據,根據作用數據范圍的不同主要有如下的幾種淘汰算法:
1. 作用在設置了過期時間的key上:
- volatile-TTL:設置過期時間越早的數據越先被淘汰。
- volatile-random:隨機淘汰設置了過期時間的數據。
- volatile-LRU:根據LRU算法淘汰過期時間的數據。
- volatile-LFU:根據LFU算法淘汰過期時間的數據。
2. 作用在所有的key上:
- volatile-random
- volatile-LRU
- volatile-LFU
## 8、如何進行緩存預熱?
手動的提前將數據放入redis中,但是有個如何區分哪些數據是熱點數據的問題!需要分析具體的業務得出。也是會造成緩存穿透、緩存擊透和雪崩問題。
## 9、數據庫和redis如何解決緩存不一致問題?
對于緩存不一致的問題一般有4種解決思路:
1. 先更新數據庫,再更新緩存。
2. 先更新緩存,再更新數據庫。
3. 刪除緩存,再更新數據庫。
4. 先更新數據庫,刪除緩存:在單機中最終采取這種方案,有時也會采用延遲刪除的方式刪除緩存。
但是第四種方案在mysql主從架構中容易出現問題,主要問題在于從服務器復制主服務器的數據可能存在網絡延遲,因此一般在分布式中都會采用binlog的訂閱機制來解決。
阿里云開發的canal可以模擬mysql 的slave來訂閱主服務器的binlog,因此通過canal訂閱binlog來更新redis中的緩存是現在開發中常用的解決方案。同時如果為了實現高可用,避免redis宕機時更新的數據丟失,可以使用MQ來保存更新的數據。(注意使用這種方式mysql與redis不再直接連接。)
- 第一章 Java基礎
- ThreadLocal
- Java異常體系
- Java集合框架
- List接口及其實現類
- Queue接口及其實現類
- Set接口及其實現類
- Map接口及其實現類
- JDK1.8新特性
- Lambda表達式
- 常用函數式接口
- stream流
- 面試
- 第二章 Java虛擬機
- 第一節、運行時數據區
- 第二節、垃圾回收
- 第三節、類加載機制
- 第四節、類文件與字節碼指令
- 第五節、語法糖
- 第六節、運行期優化
- 面試常見問題
- 第三章 并發編程
- 第一節、Java中的線程
- 第二節、Java中的鎖
- 第三節、線程池
- 第四節、并發工具類
- AQS
- 第四章 網絡編程
- WebSocket協議
- Netty
- Netty入門
- Netty-自定義協議
- 面試題
- IO
- 網絡IO模型
- 第五章 操作系統
- IO
- 文件系統的相關概念
- Java幾種文件讀寫方式性能對比
- Socket
- 內存管理
- 進程、線程、協程
- IO模型的演化過程
- 第六章 計算機網絡
- 第七章 消息隊列
- RabbitMQ
- 第八章 開發框架
- Spring
- Spring事務
- Spring MVC
- Spring Boot
- Mybatis
- Mybatis-Plus
- Shiro
- 第九章 數據庫
- Mysql
- Mysql中的索引
- Mysql中的鎖
- 面試常見問題
- Mysql中的日志
- InnoDB存儲引擎
- 事務
- Redis
- redis的數據類型
- redis數據結構
- Redis主從復制
- 哨兵模式
- 面試題
- Spring Boot整合Lettuce+Redisson實現布隆過濾器
- 集群
- Redis網絡IO模型
- 第十章 設計模式
- 設計模式-七大原則
- 設計模式-單例模式
- 設計模式-備忘錄模式
- 設計模式-原型模式
- 設計模式-責任鏈模式
- 設計模式-過濾模式
- 設計模式-觀察者模式
- 設計模式-工廠方法模式
- 設計模式-抽象工廠模式
- 設計模式-代理模式
- 第十一章 后端開發常用工具、庫
- Docker
- Docker安裝Mysql
- 第十二章 中間件
- ZooKeeper