22、jedis連接阿里雲服務器
4.配置
復制源目錄根目錄下的redis.conf文件到生成的/usr/local/redis目錄下,執行命令
cp redis.conf /usr/local/redis
使用vi編輯配置redis.conf
bind 0.0.0.0 設置綁定的主機ip,0.0.0.0表示監聽所有地址
protected-mode no 關閉安全模式,允許外網訪問
daemonize yes 后台啟動
5.添加開放端口號到防火牆
添加端口並重啟防火牆
firewall-cmd --zone=public --add-port=6379/tcp --permanent && firewall-cmd --reload
列出已經開放的端口號
firewall-cmd --zone=public --permanent --list-ports
6.啟動
啟動redis,進入redis根目錄,執行命令
./bin/redis-server redis.conf
使用redis工具或API遠程訪問。
OK,單機版搭建成功!
27、Redis配置文件詳解
啟動的時候,就通過配置文件來啟動.
redis.conf配置文件不區分大小寫.
daemonize yes #是否以守護進程來運行,默認為no
pidfile /var/run/redis_6379.pid #如果以后台的方式運行,我們就需要一個pid文件
logfile #日志的文件名
databases 16 #默認有16個數據庫
快照
#如果900秒內,至少有1個 key進行了修改,我們進行持久化操作
save 900 1
#如果300秒內,只要有10個key進行了修改,我們進行持久化操作
save 300 10
#如果60秒內,至少1000個key進行了修改,我們進行持久化操作
save 60 10000
stop-writes-on-bgsave-error yes #如果持久化出錯,是否還繼續工作
rdbcompression yes #是否壓縮rdb文件,需要消耗cpu資源.
rdbchecksum yes #保存rdb文件的時候,進行錯誤的檢查效驗
dir ./ #rdb文件保存的目錄
密碼
config get requirepass #獲取redis密碼
config set requirepass 123 #設置redis密碼
auth 123 #當有密碼的時候登錄時需要密碼登錄
config set requirepass '' # 取消密碼,重啟redis服務,重啟的時候加載復制的配置文件
內存達到限制值的處理策略
maxmemory-policy noeviction # 內存達到限制值的處理策略
config set maxmemory-policy volatile-lru #設置為volatile-lru
maxmemory-policy 六種方式
1、volatile-lru:只對設置了過期時間的key進行LRU(默認值)
2、allkeys-lru : 刪除lru算法的key
3、volatile-random:隨機刪除即將過期key
4、allkeys-random:隨機刪除
5、volatile-ttl : 刪除即將過期的
6、noeviction : 永不過期,返回錯誤
APPEND ONLY MODE模式 aof配置
appendonly no #默認是不開啟aof模式的,默認使用rdb方式持久化,在大部分所有的情況下,rdb完全夠用
appendfilename "appendonly.aof" #持久化的文件名
# appendfsync always #每次修改都會sync,消耗性能
appendfsync everysec #每秒執行一次sync,可能會丟失這1s的數據
# appendfsync no #不執行sync,這時候操作系統自己同步數據,速度更快.
save #設置完配置,可以用save保存
28、持久化之RDB操作
redis是內存數據庫,如果不將內存中的數據庫狀態保存到磁盤,那么一旦服務器進程退出,服務器中的數據庫狀態也會消失.
RDB類似於VM的快照功能,在指定時間間隔后,將內存中的數據集快照寫入數據庫;在恢復的時候,直接讀取快照文件,進行數據的恢復.
RDB(Redis DataBase)
持久化快照保存過程(工作原理)
兩個進程,父進程和子進程,父進程fork子進程,父進程繼續處理client請求,父進程處理新的寫請求到內存頁面副本,父進程OS寫時復制機制共享內存.
子進程是被父進程fork出來的,父進程和子進程共享內存,子進程將內存內容寫入臨時RDB文件,快照寫入完成后,替換原來的快照文件,子進程退出成為正式的RDB二進制文件.
-
Redis會單獨創建(fork)一個子進程來進行持久化,會先將數據寫到一個臨時文件中,等待持久化過程都結束了,再用這個臨時文件替換上次持久化好的文件。整個過程中,主進程是不進行任何IO操作的,這就確保了極高的性能。如果需要進行大規模數據的恢復,且對於數據恢復的完整性不是很敏感,那么RDB方式要比AOF方式更加的高效。RDB的缺點是最后一次持久化的數據,可能丟失。
-
RDB保存的文件是dump.rdb,在配置文件中配置的。
這種工作方式使得redis可以從寫時復制(copy-on-write)機制中獲益(因為是使用子進程進行寫操作,而父進程依然可以接受來自客戶端的請求)
觸發機制
-
save的規則滿足的情況下,會自動觸發RDB規則,但會堵塞,也就是不接受其他操作了;
(由於save命令是同步命令,會占用redis的主進程.若redis數據非常多時,save命令執行的速度會非常慢,阻塞所有用戶的請求.)
(滿足配置條件中的觸發條件 :可以通過配置文件對 Redis 進行設置, 讓它在“ N 秒內數據集至少有 M 個改動”這一條件被滿足時, 自動進行數據集保存操作。) -
執行flushall命令,也會觸發RDB規則
-
退出redis,也會產生RDB文件
bgsave
bgsave是異步進行,進行持久化的時候,redis可以將繼續響應客戶端請求.
bgsave和save對比
命令 save bgsave IO類型 同步 異步 阻塞? 是 是(阻塞發生在fock(),通常非常快) 復雜度 O(n) O(n) 優點 不會消耗額外的內存 不阻塞客戶端命令 缺點 阻塞客戶端命令 需要fock子進程,消耗內存
簡述同步和異步的區別
同步:
同步的思想是:所有的操作都做完,才返回給用戶。這樣用戶在線等待的時間太長,給用戶一種卡死了的感覺(就是系統遷移中,點擊了遷移,界面就不動了,但是程序還在執行,卡死了的感覺)。這種情況下,用戶不能關閉界面,如果關閉了,即遷移程序就中斷了。
異步:
將用戶請求放入消息隊列,並反饋給用戶,系統遷移程序已經啟動,你可以關閉瀏覽器了。然后程序再慢慢地去寫入數據庫去。這就是異步。但是用戶沒有卡死的感覺,會告訴你,你的請求系統已經響應了。你可以關閉界面了。
恢復RDB文件
- 只需要將RDB文件放在我們redis啟動目錄就可以,redis啟動的時候會自動檢查dump.rdb(dump轉存)
- 查看存在的位置:config get dir
優點:
- 適合大規模的數據恢復
- 對數據的完整性要求不高
缺點:
- 需要一定的時間間隔進程操作,如果redis意外崩潰了,最后一次修改的數據就不會生效
- fork進程的時候,會占用一定的內存空間
29、持久化之AOF(Append Only File)操作
將我們所有的命令都記錄下來,類似於linux的history,恢復的時候就把這個文件全部執行一遍.
以日志的形式來記錄每個寫的操作,將Redis執行過的所有指令記錄下來(讀操作不記錄),只許追加文件但不可以改寫文件,redis啟動之初會讀取該文件重新構建數據,換言之,redis重啟的話就根據日志文件的內容將寫指令從前到后執行一次以完成數據的恢復工作。
什么是AOF
快照功能(RDB)並不是很持久(durable):如果redis因為某些原因而造成故障停機,那么服務器將丟失最近寫入,以及未保存到快照中的那些數據.從1.1版本開始,redis增加了一種完全耐久的持久化方式:AOF持久化.
如果要使用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持久化.
RDB和AOP選擇
RDB 和 AOF 對比
RDB | AOF | |
---|---|---|
啟動優先級 | 低 | 高 |
體積 | 小 | 大 |
恢復速度 | 快 | 慢 |
數據安全性 | 丟數據 | 根據策略決定 |
如何選擇使用哪種持久化方式?選RDB就行了
一般來說,如果想達到足以媲美PostgreSQL的數據安全性,應該同時使用兩種持久化功能.
如果你非常關心你的數據, 但仍然可以承受數分鍾以內的數據丟失, 那么你可以只使用 RDB 持久化。
有很多用戶都只使用 AOF 持久化, 但並不推薦這種方式: 因為定時生成 RDB 快照(snapshot)非常便於進行數據庫備份, 並且 RDB 恢復數據集的速度也要比 AOF 恢復的速度要快。
30、Redis訂閱發布(微信公眾號)
https://www.runoob.com/redis/redis-pub-sub.html
------------訂閱端----------------------
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
1) "sakura"
原理
每個redis服務器進程都維持這一個表示服務器狀態的redis.h/redisServer結構,結構的pubsub_channels屬性是一個字典,這個字典就用於保存訂閱頻道的信息,其中,字典的鍵為正在被訂閱的頻道,而字典的值則是一個鏈表,鏈表中保存了所有訂閱這個頻道的客戶端.
客戶端訂閱,就被連接到對應頻道的鏈表的尾部,退訂則就是將客戶端節點從鏈表中移除.
缺點
- 如果一個客戶端訂閱了頻道,但自己讀取消息的速度卻不夠快的話,那么不斷積壓的消息會使redis輸出緩沖區的體積變得越來越大,這可能使得redis本身的速度變慢,甚至直接崩潰。
- 這和數據傳輸可靠性有關,如果在訂閱方斷線,那么他將會丟失所有在短線期間發布者發布的消息。
應用
- 消息訂閱:公眾號訂閱,微博關注等等(起始更多是使用消息隊列來進行實現)
- 多人在線聊天室。
稍微復雜的場景,我們就會使用消息中間件MQ(ActiveMQ,RabbitMQ 活動的兔子 kafka)處理。
31、Redis集群環境搭建
為什么使用集群
- 單台服務器難以負載大量的請求;
- 單台服務器故障率高,系統崩壞幾率大;
- 單台服務器內存容量有限.
環境配置
我們在講解配置文件的時候,注意到有一個replication
模塊 (見Redis.conf中第8條)
查看當前庫的信息:info replication
127.0.0.1:6379> info replication
# Replication
role:master # 角色
connected_slaves:0 # 從機數量
master_replid:3b54deef5b7b7b7f7dd8acefa23be48879b4fcff
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
既然需要啟動多個服務,就需要多個配置文件。每個配置文件對應修改以下信息:
- 端口號
- pid文件名
- 日志文件名
- rdb文件名
啟動單機多服務集群:
32、主從復制之復制原理
一主二從配置
默認情況下,每台Redis服務器都是主節點;我們一般情況下只用配置從機就好了!
認老大!一主(79)二從(80,81)
使用SLAVEOF host port
就可以為從機配置主機了。
然后主機上也能看到從機的狀態:
我們這里是使用命令搭建,是暫時的,真實開發中應該在從機的配置文件中進行配置,這樣的話是永久的。
使用規則
-
從機只能讀,不能寫,主機可讀可寫,一般多用於寫.
127.0.0.1:6381> set name sakura # 從機6381寫入失敗 (error) READONLY You can't write against a read only replica. 127.0.0.1:6380> set name sakura # 從機6380寫入失敗 (error) READONLY You can't write against a read only replica. 127.0.0.1:6379> set name sakura OK 127.0.0.1:6379> get name "sakura"
-
當主機斷電宕機后,默認情況下從機的角色不會發生變化,集群中只是失去了寫操作,當主機恢復以后,又會連接上從機恢復原狀.
-
當從機斷電宕機后,若不是使用配置文件配置的從機,再次啟動后作為主機是無法獲取之前主機的數據的,,若此時重新配置成為從機,又可以獲取到主機的所有數據.這里就要提到一個同步原理.
-
第二條中提到,默認情況下,主機故障后,不會出現新的主機,有兩種方式可以產生新的主機:
-
從機手動執行命令
slaveof no one
,這樣執行以后從機會獨立出來成為一個主機 -
使用哨兵模式(自動選舉)
-
33、宕機后手動配置主機
如果沒有老大了,這個時候能不能選擇出來一個老大呢?手動!
如果主機斷開了連接,我們可以使用slaveof no one
讓自己變成主機,其他的節點就可以手動連接到最新的主節點(手動)!如果這個時候老大修復了,那么就重新連接!
34、哨兵模式詳解
-
主從切換技術的方法是:當主服務器宕機后,需要手動把一台從服務器切換為主服務器,這就需要人工干預,費事費力,還會造成一段時間內服務不可用.這不是一種推薦的方式,更多時候,我們優先考慮哨兵模式.
-
謀朝篡位的自動版,能夠后台監視主機是否故障,如果發生故障根據投票數自動將從庫轉換為主庫.
-
哨兵模式是一種特殊的模式,首先redis提供了哨兵的命令,哨兵是一個獨立的進程,作為進程,它會獨立運行.其原理是哨兵通過發送命令(發送心跳包,看服務器是否存活),等待redis服務器響應,從而監控運行的多個redis實例.(心跳包ping命令?)
單機單個哨兵
哨兵的作用:
- 通過發送命令,讓redis服務器返回監控其運行狀態,包括主服務器何從服務器.
- 當哨兵檢測到master宕機,會自動將slave切換成master,然后通過發布訂閱模式通知其他的從服務器,修改配置文件,讓它們切換主機.
多哨兵模式
哨兵的核心配置
sentinel monitor mymaster 127.0.0.1 6379 1
- 數字1表示:當一個哨兵主觀認為主機斷開,就可以客觀認為主機故障,然后開始選舉新的主機.
測試
redis-sentinel xxx/sentinel.conf
成功啟動哨兵模式
此時哨兵監視着我們的主機6379,當我們斷開主機后:
優點:
- 哨兵集群,基於主從復制,所有主從復制的優點,它都有,
- 主從可以切換,故障轉移,系統的可用性更好;
- 哨兵模式是主從模式的升級,手動到自動,更加健壯.
缺點:
- redis不好在線擴容,集群容量一旦達到上限,在線擴容就十分麻煩
- 實現哨兵模式的配置其實是很麻煩的,里面有很多配置項
完整的哨兵模式配置文件 sentinel.conf
# Example sentinel.conf
# 哨兵sentinel實例運行的端口 默認26379
port 26379
# 哨兵sentinel的工作目錄
dir /tmp
# 哨兵sentinel監控的redis主節點的 ip port
# master-name 可以自己命名的主節點名字 只能由字母A-z、數字0-9 、這三個字符".-_"組成。
# quorum 當這些quorum個數sentinel哨兵認為master主節點失聯 那么這時 客觀上認為主節點失聯了
# sentinel monitor <master-name> <ip> <redis-port> <quorum> 仲裁,出席人數
sentinel monitor mymaster 127.0.0.1 6379 1
# 當在Redis實例中開啟了requirepass foobared 授權密碼 這樣所有連接Redis實例的客戶端都要提供密碼
# 設置哨兵sentinel 連接主從的密碼 注意必須為主從設置一樣的驗證密碼
# sentinel auth-pass <master-name> <password>
sentinel auth-pass mymaster MySUPER--secret-0123passw0rd
# 指定多少毫秒之后 主節點沒有應答哨兵sentinel 此時 哨兵主觀上認為主節點下線 默認30秒
# sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds mymaster 30000
# 這個配置項指定了在發生failover主備切換時最多可以有多少個slave同時對新的master進行 同步,
這個數字越小,完成failover所需的時間就越長,
但是如果這個數字越大,就意味着越 多的slave因為replication而不可用。
可以通過將這個值設為 1 來保證每次只有一個slave 處於不能處理命令請求的狀態。
# sentinel parallel-syncs <master-name> <numslaves>
sentinel parallel-syncs mymaster 1
# 故障轉移的超時時間 failover-timeout 可以用在以下這些方面:
#1. 同一個sentinel對同一個master兩次failover之間的間隔時間。
#2. 當一個slave從一個錯誤的master那里同步數據開始計算時間。直到slave被糾正為向正確的master那里同步數據時。
#3.當想要取消一個正在進行的failover所需要的時間。
#4.當進行failover時,配置所有slaves指向新的master所需的最大時間。不過,即使過了這個超時,slaves依然會被正確配置為指向master,但是就不按parallel-syncs所配置的規則來了
# 默認三分鍾
# sentinel failover-timeout <master-name> <milliseconds>
sentinel failover-timeout mymaster 180000
# SCRIPTS EXECUTION
#配置當某一事件發生時所需要執行的腳本,可以通過腳本來通知管理員,例如當系統運行不正常時發郵件通知相關人員。
#對於腳本的運行結果有以下規則:
#若腳本執行后返回1,那么該腳本稍后將會被再次執行,重復次數目前默認為10
#若腳本執行后返回2,或者比2更高的一個返回值,腳本將不會重復執行。
#如果腳本在執行過程中由於收到系統中斷信號被終止了,則同返回值為1時的行為相同。
#一個腳本的最大執行時間為60s,如果超過這個時間,腳本將會被一個SIGKILL信號終止,之后重新執行。
#通知型腳本:當sentinel有任何警告級別的事件發生時(比如說redis實例的主觀失效和客觀失效等等),將會去調用這個腳本,
#這時這個腳本應該通過郵件,SMS等方式去通知系統管理員關於系統不正常運行的信息。調用該腳本時,將傳給腳本兩個參數,
#一個是事件的類型,
#一個是事件的描述。
#如果sentinel.conf配置文件中配置了這個腳本路徑,那么必須保證這個腳本存在於這個路徑,並且是可執行的,否則sentinel無法正常啟動成功。
#通知腳本
# sentinel notification-script <master-name> <script-path>
sentinel notification-script mymaster /var/redis/notify.sh
# 客戶端重新配置主節點參數腳本
# 當一個master由於failover而發生改變時,這個腳本將會被調用,通知相關的客戶端關於master地址已經發生改變的信息。
# 以下參數將會在調用腳本時傳給腳本:
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
# 目前<state>總是“failover”,
# <role>是“leader”或者“observer”中的一個。
# 參數 from-ip, from-port, to-ip, to-port是用來和舊的master和新的master(即舊的slave)通信的
# 這個腳本應該是通用的,能被多次調用,不是針對性的。
# sentinel client-reconfig-script <master-name> <script-path>
sentinel client-reconfig-script mymaster /var/redis/reconfig.sh
35、緩存穿透和雪崩
緩存穿透(查不到)
概念
在默認情況下,用戶請求數據時,會現在緩存(redis)中查找,若沒找到即緩存未命中,再到數據庫中進行查找,數量少可能問題不大,一旦大量的請求數據(例如秒殺場景)緩存都沒有命中的話,就會全部轉移到數據庫上,造成數據庫極大的壓力,就有可能導致數據庫崩潰.網絡安全中也有人惡意使用這種手段進行攻擊被稱為洪水攻擊.
解決方案
布隆過濾器
對所有可能查詢的參數以Hash的形式存儲,以便快速確定是否存在這個值,在控制層先進行攔截校驗,校驗不通過直接打回,減輕了存儲系統的壓力.
緩存空對象
一次請求若在緩存和數據庫中都沒找到,就在緩存中返回一個空對象用於處理后續這個請求.
這樣做有一個缺陷:存儲空對象也需要空間,大量的空對象會耗費一定的空間,存儲效率並不高.解決這個缺陷的方式就是設置較短過期時間.
即使對空值設置了過期時間,還是會存在緩存層和存儲層的數據會有一段時間窗口的不一致,這對於需要保持一致性的業務會有影響.
緩存擊穿(量太大,緩存過期)
概念
相較於緩存穿透,緩存擊穿的目的性更強,一個存在的key,在緩存過期的一刻,同時有大量的請求,這些請求都匯集傳到DB,造成瞬時DB請求量大,壓力驟增.這就是緩存被擊穿,只是針對某個key的緩存不可用而導致擊穿,但其他的key依然可以使用緩存相應.
比如熱搜排行榜,一個熱點新聞被同時大量訪問就可能造成緩存穿透.
解決方案
-
設置熱點數據永不過期
這個就不會出現熱點數據過期的情況,但是當redis內存滿的時候也會清理部分數據,而且此方案會占用空間,一旦熱點數據多了起來,就會占用部分空間. -
加互斥鎖(分布式鎖)
在訪問key之前,采用SETNX(set if not exists)來設置另一個短期key來鎖住當前key的訪問,訪問節后再刪除該短期key.保證同時刻只有一個線程訪問.這樣對所的要求就是十分高.
緩存雪崩(大量緩存同時過期,DB壓力驟增)
概念
大量的key設置了相同的過期時間,導致在緩存在同一時刻全部失效,造成瞬時DB請求量大,壓力驟增,引起雪崩.
解決方案
- redis高可用
既然redis有可能掛掉,那我就多增設幾台redis,這個一台掛掉之后其他的還可以繼續工作,其實就是搭建的集群
-
限流降級
在緩存失效后,通過加鎖或者隊列來控制讀DB寫緩存的線程數量.比如對某個key只允許一個線程查詢數據和寫緩存,其他線程等待. -
數據預熱
數據預熱的含義就是正式部署之前,我先把可能的數據先預先訪問一遍,這個部分可能大量訪問的數據就會加載到緩存中.在即將發生大並發訪問前手動觸發加載緩存不同的key,設置不同的過期時間,讓緩存失效的時間盡量均勻.