八、Redis.conf
容量單位不區分大小寫,G和GB有區別
可以使用 include 組合多個配置問題
網絡配置
日志
# 日志
# Specify the server verbosity level.
# This can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably) 生產環境
# warning (only very important / critical messages are logged)
loglevel notice
logfile "" # 日志的文件位置名
databases 16 # 數據庫的數量,默認是 16 個數據庫
always-show-logo yes # 是否總是顯示LOGO
日志輸出級別
debug
verbose
notice
waring
持久化規則
持久化, 在規定的時間內,執行了多少次操作,則會持久化到文件 .rdb. aof redis 是內存數據庫,如果沒有持久化,那么數據斷電及失!
由於Redis是基於內存的數據庫,需要將數據由內存持久化到文件中
持久化方式:
RDB
AOF
# 如果900s內,如果至少有一個1 key進行了修改,我們及進行持久化操作
save 900 1
# 如果300s內,如果至少10 key進行了修改,我們及進行持久化操作
save 300 10
# 如果60s內,如果至少10000 key進行了修改,我們及進行持久化操作
save 60 10000
# 我們之后學習持久化,會自己定義這個測試!
stop-writes-on-bgsave-error yes # 持久化如果出錯,是否還需要繼續工作!
rdbcompression yes # 是否壓縮 rdb 文件,需要消耗一些cpu資源!
rdbchecksum yes # 保存rdb文件的時候,進行錯誤的檢查校驗!
dir ./ # rdb 文件保存的目錄!
SECURITY 安全
可以在這里設置redis的密碼,默認是沒有密碼!
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> config get requirepass # 獲取redis的密碼
1) "requirepass"
2) ""
127.0.0.1:6379> config set requirepass "123456" # 設置redis的密碼
OK
127.0.0.1:6379> config get requirepass # 發現所有的命令都沒有權限了
(error) NOAUTH Authentication required.
127.0.0.1:6379> ping
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth 123456 # 使用密碼進行登錄!
OK
127.0.0.1:6379> config get requirepass
1) "requirepass"
2) "123456"
限制 CLIENTS(客戶端連接相關)
maxclients 10000 # 設置能連接上redis的最大客戶端的數量
maxmemory <bytes> # redis 配置最大的內存容量
maxmemory-policy noeviction # 內存到達上限之后的處理策略
1、volatile-lru:只對設置了過期時間的key進行LRU(默認值)
2、allkeys-lru : 刪除lru算法的key
3、volatile-random:隨機刪除即將過期key
4、allkeys-random:隨機刪除
5、volatile-ttl : 刪除即將過期的
6、noeviction : 永不過期,返回錯誤
APPEND ONLY 模式 aof配置
appendonly no # 默認是不開啟aof模式的,默認是使用rdb方式持久化的,在大部分所有的情況下,
rdb完全夠用!
appendfilename "appendonly.aof" # 持久化的文件的名字
# appendfsync always # 每次修改都會 sync。消耗性能
appendfsync everysec # 每秒執行一次 sync,可能會丟失這1s的數據!
# appendfsync no # 不執行 sync,這個時候操作系統自己同步數據,速度最快!
九、Redis持久化——RDB
面試和工作,持久化都是重點!
Redis 是內存數據庫,如果不將內存中的數據庫狀態保存到磁盤,那么一旦服務器進程退出,服務器中的數據庫狀態也會消失。所以 Redis 提供了持久化功能!
什么是RDB(Redis DataBase)
在指定時間間隔后,將內存中的數據集快照寫入數據庫 ;在恢復時候,直接讀取快照文件,進行數據的恢復 ;
默認情況下, Redis 將數據庫快照保存在名字為 dump.rdb的二進制文件中。文件名可以在配置文件中進行自定義。
在指定的時間間隔內將內存中的數據集快照寫入磁盤,也就是行話講的Snapshot快照,它恢復時是將快照文件直接讀到內存里。
Redis會單獨創建(fork)一個子進程來進行持久化,會先將數據寫入到一個臨時文件中,待持久化過程都結束了,再用這個臨時文件替換上次持久化好的文件。整個過程中,主進程是不進行任何IO操作的。
這就確保了極高的性能。如果需要進行大規模數據的恢復,且對於數據恢復的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺點是最后一次持久化后的數據可能丟失。我們默認的就是RDB,一般情況下不需要修改這個配置! 有時候在生產環境我們會將這個文件進行備份!
rdb保存的文件是dump.rdb 都是在我們的配置文件中快照中進行配置的!
工作原理
在進行 RDB 的時候,redis 的主線程是不會做 io 操作的,主線程會 fork 一個子線程來完成該操作;
- Redis 調用forks。同時擁有父進程和子進程。
- 子進程將數據集寫入到一個臨時 RDB 文件中。
- 當子進程完成對新 RDB 文件的寫入時,Redis 用新 RDB 文件替換原來的 RDB 文件,並刪除舊的 RDB 文件。
這種工作方式使得 Redis 可以從寫時復制(copy-on-write)機制中獲益(因為是使用子進程進行寫操作,而父進程依然可以接收來自客戶端的請求。)
觸發機制
- save的規則滿足的情況下,會自動觸發rdb原則
- 執行flushall命令,也會觸發我們的rdb原則
- 退出redis,也會自動產生rdb文件
save
使用 save 命令,會立刻對當前內存中的數據進行持久化 ,但是會阻塞,也就是不接受其他操作了;
由於 save 命令是同步命令,會占用Redis的主進程。若Redis數據非常多時,save命令執行速度會非常慢,阻塞所有客戶端的請求。
示意圖
flushall命令
flushall 命令也會觸發持久化 ;
觸發持久化規則
滿足配置條件中的觸發條件 ;
可以通過配置文件對 Redis 進行設置, 讓它在“ N 秒內數據集至少有 M 個改動”這一條件被滿足時, 自動進行數據集保存操作。
bgsave
bgsave 是異步進行,進行持久化的時候,redis 還可以將繼續響應客戶端請求 ;
bgsave和save對比
命令 | save | bgsave |
---|---|---|
IO類型 | 同步 | 異步 |
阻塞? | 是 | 是(阻塞發生在fock(),通常非常快) |
復雜度 | O(n) | O(n) |
優點 | 不會消耗額外的內存 | 不阻塞客戶端命令 |
缺點 | 阻塞客戶端命令 | 需要fock子進程,消耗內存 |
如果恢復rdb文件!
1、只需要將rdb文件放在我們redis啟動目錄就可以,redis啟動的時候會自動檢查dump.rdb 恢復其中的數據!
2、查看需要存在的位置
127.0.0.1:6379> config get dir
1) "dir"
2) "/usr/local/bin" # 如果在這個目錄下存在 dump.rdb 文件,啟動就會自動恢復其中的數據
優缺點
優點:
- 適合大規模的數據恢復
- 對數據的完整性要求不高
缺點:
- 需要一定的時間間隔進行操作,如果redis意外宕機了,這個最后一次修改的數據就沒有了。
- fork進程的時候,會占用一定的內容空間。
十、Redis持久化——AOF
Append Only File
將我們所有的命令都記錄下來,history,恢復的時候就把這個文件全部再執行一遍
以日志的形式來記錄每個寫的操作,將Redis執行過的所有指令記錄下來(讀操作不記錄),只許追加文件但不可以改寫文件,redis啟動之初會讀取該文件重新構建數據,換言之,redis重啟的話就根據日志文件的內容將寫指令從前到后執行一次以完成數據的恢復工作。
什么是AOF
快照功能(RDB)並不是非常耐久(durable): 如果 Redis 因為某些原因而造成故障停機, 那么服務器將丟失最近寫入、以及未保存到快照中的那些數據。 從 1.1 版本開始, Redis 增加了一種完全耐久的持久化方式: AOF 持久化。
appendonly no yes則表示啟用AOF
默認是不開啟的,我們需要手動配置,然后重啟redis,就可以生效了!
如果這個aof文件有錯位,這時候redis是啟動不起來的,我需要修改這個aof文件
redis給我們提供了一個工具redis-check-aof --fix
appendonly yes # 默認是不開啟aof模式的,默認是使用rdb方式持久化的,在大部分的情況下,rdb完全夠用 appendfilename "appendonly.aof"
appendfsync always # 每次修改都會sync 消耗性能
appendfsync everysec # 每秒執行一次 sync 可能會丟失這一秒的數據
appendfsync no # 不執行 sync ,這時候操作系統自己同步數據,速度最快
優缺點
優點
- 每一次修改都會同步,文件的完整性會更加好
- 沒秒同步一次,可能會丟失一秒的數據
- 從不同步,效率最高
缺點
- 相對於數據文件來說,aof遠遠大於rdb,修復速度比rdb慢!
- Aof運行效率也要比rdb慢,所以我們redis默認的配置就是rdb持久化
擴展:
1、RDB 持久化方式能夠在指定的時間間隔內對你的數據進行快照存儲
2、AOF 持久化方式記錄每次對服務器寫的操作,當服務器重啟的時候會重新執行這些命令來恢復原始的數據,AOF命令以Redis 協議追加保存每次寫的操作到文件末尾,Redis還能對AOF文件進行后台重寫,使得AOF文件的體積不至於過大。
3、只做緩存,如果你只希望你的數據在服務器運行的時候存在,你也可以不使用任何持久化
4、同時開啟兩種持久化方式
- 在這種情況下,當redis重啟的時候會優先載入AOF文件來恢復原始的數據,因為在通常情況下AOF文件保存的數據集要比RDB文件保存的數據集要完整。
- RDB 的數據不實時,同時使用兩者時服務器重啟也只會找AOF文件,那要不要只使用AOF呢?作者建議不要,因為RDB更適合用於備份數據庫(AOF在不斷變化不好備份),快速重啟,而且不會有AOF可能潛在的Bug,留着作為一個萬一的手段。
5、性能建議
- 因為RDB文件只用作后備用途,建議只在Slave上持久化RDB文件,而且只要15分鍾備份一次就夠了,只保留 save 900 1 這條規則。
- 如果Enable AOF ,好處是在最惡劣情況下也只會丟失不超過兩秒數據,啟動腳本較簡單只load自己的AOF文件就可以了,代價一是帶來了持續的IO,二是AOF rewrite 的最后將 rewrite 過程中產生的新數據寫到新文件造成的阻塞幾乎是不可避免的。只要硬盤許可,應該盡量減少AOF rewrite的頻率,AOF重寫的基礎大小默認值64M太小了,可以設到5G以上,默認超過原大小100%大小重寫可以改到適當的數值。
- 如果不Enable AOF ,僅靠 Master-Slave Repllcation 實現高可用性也可以,能省掉一大筆IO,也減少了rewrite時帶來的系統波動。代價是如果Master/Slave 同時倒掉,會丟失十幾分鍾的數據,啟動腳本也要比較兩個 Master/Slave 中的 RDB文件,載入較新的那個,微博就是這種架構。
如何選擇使用哪種持久化方式?
一般來說, 如果想達到足以媲美 PostgreSQL 的數據安全性, 你應該同時使用兩種持久化功能。
如果你非常關心你的數據, 但仍然可以承受數分鍾以內的數據丟失, 那么你可以只使用 RDB 持久化。
有很多用戶都只使用 AOF 持久化, 但並不推薦這種方式: 因為定時生成 RDB 快照(snapshot)非常便於進行數據庫備份, 並且 RDB 恢復數據集的速度也要比 AOF 恢復的速度要快。
十一、Redis發布訂閱
Redis 發布訂閱(pub/sub)是一種消息通信模式:發送者(pub)發送消息,訂閱者(sub)接收消息。微信、 微博、關注系統! Redis 客戶端可以訂閱任意數量的頻道。 訂閱/發布消息圖: 第一個:消息發送者, 第二個:頻道 第三個:消息訂閱者!
下圖展示了頻道 channel1 , 以及訂閱這個頻道的三個客戶端 —— client2 、 client5 和 client1 之間的關系:
當有新消息通過 PUBLISH 命令發送給頻道 channel1 時, 這個消息就會被發送給訂閱它的三個客戶端:
命令
PSUBSCRIBE pattern [pattern..]
訂閱一個或多個符合給定模式的頻道。PUNSUBSCRIBE pattern [pattern..]
退訂一個或多個符合給定模式的頻道。PUBSUB subcommand [argument[argument]]
查看訂閱與發布系統狀態。PUBLISH channel message
向指定頻道發布消息SUBSCRIBE channel [channel..]
訂閱給定的一個或多個頻道。UNSUBSCRIBE channel [channel..]
退訂一個或多個頻道
代碼示例
------------訂閱端---------------------- 127.0.0.1:6379> SUBSCRIBE sakura # 訂閱sakura頻道 Reading messages... (press Ctrl-C to quit) # 等待接收消息 1) "subscribe" # 訂閱成功的消息 2) "sakura" 3) (integer) 1 1) "message" # 接收到來自sakura頻道的消息 "hello world" 2) "sakura" 3) "hello world" 1) "message" # 接收到來自sakura頻道的消息 "hello i am sakura" 2) "sakura" 3) "hello i am sakura"
--------------消息發布端-------------------
127.0.0.1:6379> PUBLISH sakura "hello world" # 發布消息到sakura頻道
(integer) 1
127.0.0.1:6379> PUBLISH sakura "hello i am sakura" # 發布消息
(integer) 1-----------------查看活躍的頻道------------
127.0.0.1:6379> PUBSUB channels
"sakura"
原理
Redis是使用C實現的,通過分析 Redis 源碼里的 pubsub.c 文件,了解發布和訂閱機制的底層實現,籍此加深對 Redis 的理解。
Redis 通過 PUBLISH 、SUBSCRIBE 和 PSUBSCRIBE 等命令實現發布和訂閱功能。
每個 Redis 服務器進程都維持着一個表示服務器狀態的 redis.h/redisServer 結構, 結構的 pubsub_channels 屬性是一個字典, 這個字典就用於保存訂閱頻道的信息,其中,字典的鍵為正在被訂閱的頻道, 而字典的值則是一個鏈表, 鏈表中保存了所有訂閱這個頻道的客戶端。
客戶端訂閱,就被鏈接到對應頻道的鏈表的尾部,退訂則就是將客戶端節點從鏈表中移除。
缺點
- 如果一個客戶端訂閱了頻道,但自己讀取消息的速度卻不夠快的話,那么不斷積壓的消息會使redis輸出緩沖區的體積變得越來越大,這可能使得redis本身的速度變慢,甚至直接崩潰。
- 這和數據傳輸可靠性有關,如果在訂閱方斷線,那么他將會丟失所有在短線期間發布者發布的消息。
應用
- 消息訂閱:公眾號訂閱,微博關注等等(起始更多是使用消息隊列來進行實現)
- 多人在線聊天室。
稍微復雜的場景,我們就會使用消息中間件MQ處理。