一、關於 Redis
1.Redis 是什么
Redis 是一個開放源代碼(BSD 許可)的內存中數據結構存儲,可用作數據庫,緩存和消息代理,是一個基於鍵值對的 NoSQL 數據庫。
2.Redis 特性有哪些
- 速度快
- 基於鍵值對的數據結構服務器
- 豐富的功能、豐富的數據結構
- 簡單穩定
- 客戶端語言多
- 持久化
- 主從復制
- 高可以 & 分布式
3.Redis 合適的應用場景
- 緩存
- 排行榜
- 計數器
- 分布式會話
- 分布式鎖
- 社交網絡
- 最新列表
- 消息系統
4.除了 Redis 以外的 NoSQL 數據庫
MongoDB、MemcacheDB、Cassandra、CouchDB、Hypertable、Leveldb。
5.Redis 和 Memcache 區別
- 支持的存儲類型不同,memcached 只支持簡單的 k/v 結構。redis 支持更多類型的存儲結構類型(詳見問題6)。
- memcached 數據不可恢復,redis 則可以把數據持久化到磁盤上。
- 新版本的 redis 直接自己構建了 VM 機制 ,一般的系統調用系統函數的話,會浪費一定的時間去移動和請求。
- redis 當物理內存用完時,可以將很久沒用到的 value 交換到磁盤。
6.Redis 的幾種數據類型
基礎:字符串(String)、哈希(hash)、列表(list)、集合(set)、有序集合(zset)。
還有HyperLogLog、流、地理坐標等。
7.Redis 的高級功能
消息隊列、自動過期刪除、事務、數據持久化、分布式鎖、附近的人、慢查詢分析、Sentinel 和集群等多項功能。
二、Redis 啟動和執行
1.Redis 幾個比較主要的可執行文件
2.啟動 Redis 的幾種方式
- 默認配置 : ./redis-server
- 運行啟動: redis-server 加上要修改配置名和值(可以是多對),沒有配置的將使用默認配置。例如: redis-server ———port 7359
- 指定配置文件啟動: ./redis-server/opt/redis/redis.conf
3.Redis 配置自定義配置
redis 目錄下有一個 redis.conf 的模板配置。只需要復制模板配置然后修改即可。
一般來說大部分生產環境都會用指定配置文件的方式啟動redis。
4.Redis 客戶端命令執行的方式
- (1)交互方式:
redis-cli -h 127.0.0.1 -p 6379 # 連接到redis后,后面執行的命令就可以通過交互方式實現了。
- (2)命令行方式:
redis-cli -h 127.0.0.1 -p 6379 get value
5.停止 Redis 服務
- Kill-9 pid (粗暴,請不要使用,數據不僅不會持久化,還會造成緩存區等資源不能被優雅關閉)。
- 可以用 redis 的 shutdown 命令,可以選擇是否在關閉前持久化數據。
redis-cli shutdown nosave|save
6.如何查看當前鍵是否存在?
exists key
7.如何刪除數據?
del key
三、Redis 注意事項
1.Redis 為什么快
- redis 使用了單線程架構和 I/O 多路復用模型模型。
- 純內存訪問。
- 由於是單線程避免了線程上下文切換帶來的資源消耗。
- C語言實現,優化過的數據結構,基於幾種基礎的數據結構,redis做了大量的優化,性能極高
C語言實現,優化過的數據結構,基於幾種基礎的數據結構,redis做了大量的優化,性能極高
2.為什么 Redis6.0 是想用多線程
redis 使用多線程並非是完全摒棄單線程,redis 還是使用單線程模型來處理客戶端的請求,只是使用多線程來處理數據的讀寫和協議解析,執行命令還是使用單線程。
這樣做的目的是因為 redis 的性能瓶頸在於網絡 IO 而非 CPU,使用多線程能提升 IO 讀寫的效率,從而整體提高 redis 的性能。
3.字符串最大不能超過多少
512MB。
4.Redis 默認分多少個數據庫
16個。
5.Redis 持久化的幾種方式?
RDB、AOF、混合持久化。
四、RDB 持久化
RDB(Redis DataBase)持久化是把當前進程數據生成快照保存到硬盤的過程。
Tips:是以二進制的方式寫入磁盤。
1.RDB 的持久化是如何觸發的?
- 手動觸發:
- save :阻塞當前 Redis 服務器,直到 RDB 過程完成為止,如果數據比較大的話,會造成長時間的阻塞,線上不建議。
- bgsave:redis 進程執行 fork 操作創作子進程,持久化由子進程負責,完成后自動結束,阻塞只發生在fork階段,一半時間很短。
- 自動觸發:
- savexsecends n: 表示在 x 秒內,至少有 n 個鍵發生變化,就會觸發 RDB 持久化。也就是說滿足了條件就會觸發持久化。
- flushall:主從同步觸發
2.RDB 的優點
- rdb 是一個緊湊的二進制文件,代表 Redis 在某個時間點上的數據快照。
- 適合於備份,全量復制的場景,對於災難恢復非常有用。
- Redis 加載 RDB 恢復數據的速度遠快於 AOF 方式。
3.RDB的缺點
- RDB 沒法做到實時的持久化。中途意外終止,會丟失一段時間內的數據。
- RDB 需要 fork() 創建子進程,屬於重量級操作,可能導致 Redis卡頓若干秒。
4.如何禁用持久化
一般來說生成環境不會用到,了解一下也有好處的。
config set save ""
五、AOF 持久化
AOF(appendonly file)為了解決 rdb 不能實時持久化的問題,aof 來搞定。以獨立的日志方式記錄把每次命令記錄到 aof 文件中。
1.如何查詢 AOF 是否開啟
config get appendonly
2.如何開啟 AOF
- 命令行方式:實時生效,但重啟后失效。
config set appendonly
- 配置文件:需要重啟生效,重啟后依然生效。
appendonly yes
3.AOF 的工作流程
- 所有寫入命令追加到 aof_buf 緩沖區。
- AOF 緩沖區根據對應的策略向硬盤做同步操作。
- 隨着 AOF 文件越來越大,需要定期對 AOF 文件進行重寫,達到壓縮的目的。
- 當 redis 服務器重啟時,可以加載 AOF 文件進行數據恢復。
4.為什么 AOF 要先把命令追加到緩存區(aof_buf)中
Redis 使用單線程響應命令,如果每次寫入文件命令都直接追加到硬盤,性能就會取決於硬盤的負載。如果使用緩沖區,redis提供多種緩沖區策略,在性能和安全性方面做出平衡。
5.AOF 持久化如何觸發的
- 自動觸發:滿足設置的策略和滿足重寫觸發。策略:(在配置文件中配置
- 手動觸發:(執行命令)
bgrewriteaof
6.AOF 優點
- AOF 提供了 3 種保存策略:每秒保存、跟系統策略、每次操作保存。實時性比較高,一般來說會選擇每秒保存,因此意外發生時頂多失去一秒的數據。
- 文件追加寫形式,所以文件很少有損壞問題,如最后意外發生少寫數據,可通過 redis-check-aof 工具修復。
- AOF 由於是文本形式,直接采用協議格式,避免二次處理開銷,另外對於修改也比較靈活。
7.AOF 缺點
- AOF 文件要比 RDB 文件大。
- AOF 冷備沒 RDB 迅速。
- 由於執行頻率比較高,所以負載高時,性能沒有 RDB 好。
六、混合持久化
一般來說線上都會采取混合持久化。redis4.0 以后添加了新的混合持久化方式。
1.優點:
在快速加載的同時,避免了丟失過更多的數據。
2.缺點:
- 由於混合了兩種格式,所以可讀性差。
- 兼容性,需要 4.0 以后才支持。
七、緩存
1. 緩存穿透
正常情況下,我們去查詢數據都是存在。那么請求去查詢一條數據庫中根本就不存在的數據,也就是緩存和數據庫都查詢不到這條數據,但是請求每次都會打到數據庫上面去。這種查詢不存在數據的現象稱為緩存穿透。
緩存穿透產生大量的請求到數據庫去查詢。可能會導致數據庫由於壓力過大而宕機。
解決方案:在緩存中將該鍵對應的值為設置為 null,配置過期時間
2.緩存擊穿
在平常高並發的系統中,大量的請求同時查詢一個 key 時,此時若這個 key 正好失效了,就會導致大量的請求都打到數據庫上面去。這種現象即緩存擊穿。
解決方案:緩存擊穿的現象是多個線程同時去查詢數據庫的同一條數據,可以在第一個查詢數據的請求上使用一個互斥鎖來鎖住它。其他的線程走到這一步拿不到鎖就等着,等第一個線程查詢到了數據,然后做緩存。后面的線程進來發現已經有緩存了,就直接走緩存。
3.緩存雪崩
當某一時刻發生大規模的緩存失效的情況。比如緩存服務宕機或集中過期,會有大量的請求直接打到DB上。結果 DB 稱不住,掛掉。
解決方案:
-
事前:使用集群緩存,保證緩存服務的高可用。如果是使用 Redis,可以使用 主從+哨兵 ,Redis Cluster 來避免 Redis 全盤崩潰的情況。
-
事中:使用 ehcache 本地緩存 + Hystrix 限流&降級 ,避免 MySQL 被打死的情況發生。使用 Hystrix 進行 限流 & 降級 ,比如一秒來了5000個請求,可以設置假設只能有一秒 2000 個請求能通過這個組件,那么其他剩余的 3000 請求就會走限流邏輯,然后去調用降級組件(降級)。比如設置的一些默認值呀之類的。以此來保護最后的 MySQL 不會被大量的請求給打死。
-
事后:開啟 Redis 持久化機制,盡快恢復緩存集群
4.緩存預熱
系統上線后,提前將相關數據加載到緩存系統,避免用戶先查庫,然后在緩存。
八、其他
1.安裝 Redis 步驟
- 下載 Redis 指定版本源碼安裝包壓縮到當前目錄。
- 解壓縮 Redis 源碼安裝包。
- 建立一個 redis 目錄軟鏈接,指向解壓包。
- 進入 redis 目錄
- 編譯
- 安裝
或者:docker pull redis。
2.Redis 事務
事務提供了一種將多個命令請求打包,一次性、按順序的執行多個命令的機制。並且在事務執行期間,服務器不會中斷事務而改去執行其他客戶端命令請求,它會
3.Redis 事務開始到結束的幾個階段?
- 開啟事務
- 命令入隊
- 執行事務/放棄事務
4.Redis 中 key 的過期操作?
# 設置key的生存時間為n秒: expire key nseconds # 設置key的生存時間為nmilliseconds: pxpire key milliseconds # 設置過期時間為timestamp所指定的秒數時間戳: expireat key timespamp # 設置過期時間為timestamp毫秒級時間戳: pexpireat key millisecondsTimestamp
5.Redis 過期鍵刪除策略?
- 定時刪除:在設置的過期時間同時,創建一個定時器在鍵的過期時間來臨時,立即執行隊鍵的操作刪除。
- 惰性刪除:放任過期鍵不管,但每次從鍵空間中獲取鍵時,都檢查取得的鍵是否過期,如果過期就刪除,如果沒有就返回該鍵。
- 定期刪除:每隔一段時間執行一次刪除過期鍵操作,並通過先吃刪除操作執行的時長和頻率來減少刪除操作對 CPU 時間的影響。
定期+惰性都沒有刪除怎么辦
假設 redis 每次定期隨機查詢 key 的時候沒有刪掉,這些 key 也沒有做查詢的話,就會導致這些key一直保存在 redis 里面無法被刪除,這時候就會走到 redis 的內存淘汰機制。
- volatile-lru:從已設置過期時間的key中,移出最近最少使用的key進行淘汰
- volatile-ttl:從已設置過期時間的key中,移出將要過期的key
- volatile-random:從已設置過期時間的key中隨機選擇key淘汰
- allkeys-lru:從key中選擇最近最少使用的進行淘汰
- allkeys-random:從key中隨機選擇key進行淘汰
- noeviction:當內存達到閾值的時候,新寫入操作報錯
6.Pipeline
命令批處理技術,對命令進行組裝,然后一次性執行多個命令。可以有效的節省 RTT(Round Trip Time 往返時間)。
經過測試驗證:
- pipeline 執行速度一般比逐條執行快。
- 客戶端和服務的網絡延越大,pipeline 效果越明顯。
7.如何獲取當前最大內存?如何動態設置?
# 獲取最大內存: config get maxmemory # 設置最大內存: config set maxmemory 1GB
8.Redis 內存溢出控制
當 Redis 所用內存達到 maxmemory 上限時,會出發相應的溢出策略。
9.Redis 內存溢出策略
- noeviction(默認策略):拒絕所有寫入操作並返回客戶端錯誤信息(error) OOM command not allowed when used memory,只響應讀操作。
- volatile-lru:根據 LRU 算法刪除設置了超時屬性(expire)的鍵,直到騰出足夠空間為止。如果沒有可刪除的鍵對象,回退到noeviction策略。
- allkeys-lru:根據 LRU 算法刪除鍵,不管數據有沒有設置超時屬性, 直到騰出足夠空間為止。
- allkeys-random:隨機刪除所有鍵,直到騰出足夠空間為止。
- volatile-random:隨機刪除過期鍵,直到騰出足夠空間為止。
- volatile-tth 根據鍵值對象的 ttl 屬性,刪除最近將要過期數據。如果沒有,回退到 noeviction 策略。
10.Redis 高可用方案
RedisSentinel(哨兵)能自動完成故障發現和轉移。
哨兵功能比單純的主從架構全面,它具備自動故障轉移、集群監控、消息通知等功能。
哨兵可以同時監視多個主從服務器,並且在被監視的master下線時,自動將某個slave提升為master,然后由新的master繼續接收命令。整個過程如下:
- 初始化 sentinel,將普通的 redis 代碼替換成 sentinel 專用代碼
- 初始化 masters 字典和服務器信息,服務器信息主要保存 ip:port,並記錄實例的地址和 ID
- 創建和 master 的兩個連接,命令連接和訂閱連接,並且訂閱 sentinel:hello 頻道
- 每隔 10 秒向 master 發送 info 命令,獲取 master 和它下面所有 slave 的當前信息
- 當發現 master 有新的 slave 之后,sentinel 和新的 slave 同樣建立兩個連接,同時每個 10 秒發送 info 命令,更新 master 信息
- sentinel 每隔 1 秒向所有服務器發送 ping 命令,如果某台服務器在配置的響應時間內連續返回無效回復,將會被標記為下線狀態
- 選舉出領頭 sentinel,領頭 sentinel 需要半數以上的 sentinel 同意
- 領頭 sentinel 從已下線的的 master 所有 slave 中挑選一個,將其轉換為 master
- 讓所有的 slave 改為從新的 master 復制數據
- 將原來的 master 設置為新的 master 的從服務器,當原來 master 重新回復連接時,就變成了新 master 的從服務器
sentinel 會每隔 1 秒向所有實例(包括主從服務器和其他 sentinel)發送 ping 命令,並且根據回復判斷是否已經下線,這種方式叫做主觀下線。當判斷為主觀下線時,就會向其他監視的 sentinel 詢問,如果超過半數的投票認為已經是下線狀態,則會標記為客觀下線狀態,同時觸發故障轉移。
11.Redis 集群方案
Twemproxy、Redis Cluster、Codis。
如果說依靠哨兵可以實現 redis 的高可用,如果還想在支持高並發同時容納海量的數據,那就需要 redis 集群。redis集群是 redis 提供的分布式數據存儲方案,集群通過數據分片 sharding 來進行數據的共享,同時提供復制和故障轉移的功能。
一個redis集群由多個節點 node 組成,而多個 node 之間通過 cluster meet 命令來進行連接,節點的握手過程:
- 節點A收到客戶端的 cluster meet 命令
- A 根據收到的 IP 地址和端口號,向 B 發送一條 meet 消息
- 節點 B 收到 meet 消息返回 pong
- A 知道 B 收到了 meet 消息,返回一條 ping 消息,握手成功
- 最后,節點 A 將會通過 gossip 協議把節點 B 的信息傳播給集群中的其他節點,其他節點也將和 B 進行握手
12.RedisCluster 槽
范圍:0~16383
redis 通過集群分片的形式來保存數據,整個集群數據庫被分為 16384 個槽,集群中的每個節點可以處理 0-16384 個槽,當數據庫16384個槽都有節點在處理時,集群處於上線狀態,反之只要有一個槽沒有得到處理都會處理下線狀態。通過 cluster addslots 命令可以將槽指派給對應節點處理。
槽是一個位數組,數組的長度是 16384/8=2048,而數組的每一位用 1 表示被節點處理,0 表示不處理,如圖所示的話表示 A 節點處理 0-7 的槽。
當客戶端向節點發送命令,如果剛好找到槽屬於當前節點,那么節點就執行命令,反之,則會返回一個 MOVED 命令到客戶端指引客戶端轉向正確的節點。(MOVED 過程是自動的)
如果增加或者移出節點,對於槽的重新分配也是非常方便的,redis 提供了工具幫助實現槽的遷移,整個過程是完全在線的,不需要停止服務。
13.Redis 鎖實現思路
- setnx(set if not exists),如果創建成功則表示獲取到鎖。
- setnxlock true 創建鎖
- dellock 釋放鎖
如果中途崩潰,無法釋放鎖?此時需要考慮到超時時間的問題。比如 :expire lock 300。由於命令是非原子的,所以還是會死鎖,如何解決?Redis支持 set 並設置超時時間的功能。比如: set lock true ex 30 nx。
14.布隆過濾器
是1970年由布隆提出的。它實際上是一個很長的二進制向量和一系列隨機映射函數。布隆過濾器可以用於檢索一個元素是否在一個集合中。它的優點是空間效率和查詢時間都比一般的算法要好的多,缺點是有一定的誤識別率和刪除困難。
Tips:當判斷一定存在時,可能會誤判,當判斷不存在時,就一定不存在。