今日內容概要
- redis高可用
- redis叢集
- redis快取優化
內容詳細
1、redis高可用
# 主從複製存在的問題:
1 主從複製,主節點發生故障,需要做故障轉移,可以手動轉移:讓其中一個slave變成master--->哨兵
2 主從複製,只能主寫資料,所以寫能力和儲存能力有限----》叢集
# 案例
-一主兩從,主寫資料,從讀資料
-如果主庫掛掉,從庫只能讀,redis就不能對外提供服務了,它就不高可用
-即便主掛掉,選一個從庫作為主庫,繼續對外提供服務 就是高可用
-原來的主庫,又啟動起來了,它現在作為從庫
# 使用哨兵完成上面的事情 sentinel--》哨兵
##### 搭建步驟
# 搭建一主兩從
# 設定3個哨兵
# 主一
daemonize yes
dir ./data3
protected-mode no
bind 0.0.0.0
logfile "redis_sentinel3.log"
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
# 從一
port 26380
daemonize yes
dir ./data2
protected-mode no
bind 0.0.0.0
logfile "redis_sentinel3.log"
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
# 從二
port 26381
daemonize yes
dir ./data
protected-mode no
bind 0.0.0.0
logfile "redis_sentinel1.log"
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000
# 啟動三個哨兵
./src/redis-sentinel sentinel_26379.conf
./src/redis-sentinel sentinel_26378.conf
./src/redis-sentinel sentinel_26377.conf
# 使用者端連線到某一個redis上
info # 檢視主從資訊
# 使用者端連到某個 sentinel上(一個sentinel類似於一個redis-server,使用者端可以連線)
redis-cli -p 26379 # 連到這個哨兵上
info
'''
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=127.0.0.1:6379,slaves=2,sentinels=3
'''
# 演示故障切換
# 停掉主庫---》6379
shutdown
# 哨兵認為主掛了,會自動選一個從庫當主庫
info
選擇了6380作為主了
# 把6379啟動,6379現在變成從庫
哨兵搭建後的python連線
# python連線redis---》寫寫到主庫,讀從從庫中讀---》一旦用了高可用(主庫會變)---》python連線哨兵---》通過哨兵返回主,去寫,返回從,去讀
import redis
from redis.sentinel import Sentinel
# 連線哨兵伺服器(主機名也可以用域名)
# 127.0.0.1:26379
sentinel = Sentinel([('127.0.0.1', 26379),
('127.0.0.1', 26380),
('127.0.0.1', 26381)
],
socket_timeout=5)
print(sentinel)
# 獲取主伺服器地址
master = sentinel.discover_master('mymaster')
print(master) # 返回所有主
# 獲取從伺服器地址
slave = sentinel.discover_slaves('mymaster')
print(slave) # 返回所有從
##### 讀寫分離
# 獲取主伺服器進行寫入
master = sentinel.master_for('mymaster', socket_timeout=0.5)
w_ret = master.set('foo', 'bar')
slave = sentinel.slave_for('mymaster', socket_timeout=0.5)
r_ret = slave.get('foo')
print(r_ret)
2、redis叢集
# 主從複製,只能主寫資料,所以寫能力和儲存能力有限----》叢集
# 存在問題
1 並行量:單機redis qps為10w/s,但是我們可能需要百萬級別的並行量
2 資料量:機器記憶體16g--256g,如果存500g資料呢?
# 解決:加機器,分散式
redis cluster 在2015年的 3.0 版本加入了,滿足分散式的需求
# 分散式資料庫
假設全量的資料非常大,500g,單機已經無法滿足,我們需要進行分割區,分到若干個子集中
# 分割區方式
-雜湊分佈
原理:hash分割區: 節點取餘 ,假設3臺機器, hash(key)%3,落到不同節點上
優點:熱點資料分散
缺點:不利於批次查詢
-順序分佈
原理:100個資料分到3個節點上 1--33第一個節點;34--66第二個節點;67--100第三個節點(很多關係型資料庫使用此種方式,mysql通常用它)
缺點:熱點資料太集中
# mysql 官方沒有叢集方案---》第三方解決方案---》順序,雜湊
# 雜湊分割區
-節點取餘:後期擴容--》遷移資料總量大---》推薦翻倍庫容
-一致性 hash
每個節點負責一部分資料,對key進行hash,得到結果在node1和node2之間,就放到node2中,順時針查詢
擴容遷移資料遷移少,資料不均衡
-虛擬槽分割區(redis叢集)
預設虛擬槽:每個槽對映一個資料子集,一般比節點數大
良好的雜湊函數:如CRC16
伺服器端管理節點、槽、資料:如redis cluster(槽的範圍0–16383)
2.1 搭建
# 6臺機器,3個節點的叢集,另外三臺做副本庫(從庫)
# 自動故障轉移,3個主節點,如果有一個掛了,另外一個從庫就會升級為主庫
# redis的埠7000
# redis的埠7001
# redis的埠7002
# redis的埠7003
# redis的埠7004
# redis的埠7005
# 只要叢集中有一個故障了,整個就不對外提供服務了,這個實際不合理,假設有50個節點,一個節點故障了,所有不提供服務了
# 組態檔
port 7000
daemonize yes
dir "/root/s20/redis-5.0.7/data"
logfile "7000.log"
dbfilename "dump-7000.rdb"
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-require-full-coverage yes
# 快速生成其他設定
sed 's/7000/7001/g' redis-7000.conf > redis-7001.conf
sed 's/7000/7002/g' redis-7000.conf > redis-7002.conf
sed 's/7000/7003/g' redis-7000.conf > redis-7003.conf
sed 's/7000/7004/g' redis-7000.conf > redis-7004.conf
sed 's/7000/7005/g' redis-7000.conf > redis-7005.conf
# 啟動6個節點
./src/redis-server ./redis-7000.conf
ps -ef |grep redis
./src/redis-server ./redis-7001.conf
./src/redis-server ./redis-7002.conf
./src/redis-server ./redis-7003.conf
./src/redis-server ./redis-7004.conf
./src/redis-server ./redis-7005.conf
### 使用者端連上---》放資料--->想搭建叢集---》叢集模式沒有分槽---》放的這個資料不知道放到哪個節點--》放不進去----》搭建完成才能寫入資料
## 使用者端連結上的命令:
cluster nodes # 如果沒有搭建完成,只能看到自己
cluster info # 叢集狀態是成功\失敗的
# 搭建叢集 4.x以前版本,比較麻煩
-先meet
-指派槽
-建立主從
# 快速搭建叢集 4.x以後,只需要這一條,自動meet,自動指派槽,自動建主從
# 注意這個數位 cluster-replicas 1 ---》指的是每個主節點有幾個從節點
redis-cli --cluster create --cluster-replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
### 演示寫入資料
-在7001上寫入 name lqz
-去7002上查不到name
-對name crc16雜湊運算完---》算完的槽--->知道哪個節點管了哪些槽---》告訴你去哪個節點存
# 以叢集模式登陸,
-無論在哪個主節點,都能寫入資料,獲取資料
redis-cli -c -p 埠 # 以叢集模式登陸,如果操作不到,自動重定向過去
# 演示故障轉移
-7001 是個主庫---》主庫停掉--》7005從庫會自動升級為主庫
2.2 叢集擴容/縮容
## 叢集擴容
sed 's/7000/7006/g' redis-7000.conf > redis-7006.conf
sed 's/7000/7007/g' redis-7000.conf > redis-7007.conf
./src/redis-server ./redis-7006.conf
./src/redis-server ./redis-7007.conf
### 方式一
在7000上執行
redis-cli -p 7000 cluster meet 127.0.0.1 7006
redis-cli -p 7000 cluster meet 127.0.0.1 7007
### 方式二
redis-cli --cluster add-node 127.0.0.1:7006 127.0.0.1:7000
redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7000
# 讓7007做為7006的從
redis-cli -p 7007 cluster replicate 2d657119470fd7c65c366698f20cc104295b7555
##### 分槽
redis-cli --cluster reshard 127.0.0.1:7000
# 16384總共平均分配到4個節點,每個節點需要有:4096槽
數4096 指定到7006節點上
自動從三個節點中的每個節點拿一部分槽放到7006身上,湊夠4096個
###### 縮容
# 下線遷槽(把7006的1366個槽遷移到7000上)--->把槽遷走
# 從誰那裡遷到誰身上
redis-cli --cluster reshard --cluster-from 2d657119470fd7c65c366698f20cc104295b7555 --cluster-to 997257c78c2995372c8cde228850b4b101d2a03b --cluster-slots 1365 127.0.0.1:7000
yes
redis-cli --cluster reshard --cluster-from 2d657119470fd7c65c366698f20cc104295b7555 --cluster-to c763786ad7fa9c65fb9182a8cfe0be4825ee96a0 --cluster-slots 1366 127.0.0.1:7005
yes
redis-cli --cluster reshard --cluster-from 2d657119470fd7c65c366698f20cc104295b7555 --cluster-to 1993efb87276df5986bdca56930aaa8ec3e78287 --cluster-slots 1366 127.0.0.1:7002
yes
# 忘記節點,關閉節點
redis-cli --cluster del-node 127.0.0.1:7000 1cddf0889d525516ad38a714ad5d38bead74dbcb(從庫id) # 先下從,再下主,因為先下主會觸發故障轉移
redis-cli --cluster del-node 127.0.0.1:7000 2d657119470fd7c65c366698f20cc104295b7555(主庫id)
# 關掉其中一個主,另一個從立馬變成主頂上, 重啟停止的主,發現變成了從
3、redis快取優化
# 雙寫一致性
-定時更新
-增資料刪快取
-增資料改快取
# redis自身有快取更新策略---》redis佔記憶體不能無限大,可以控制,記憶體就是滿了
# 快取更新策略
1. LRU -Least Recently Used,沒有被使用時間最長的
# LRU設定
maxmemory-policy:volatile-lru
(1)noeviction: 如果記憶體使用達到了maxmemory,client還要繼續寫入資料,那麼就直接報錯給使用者端
(2)allkeys-lru: 就是我們常說的LRU演演算法,移除掉最近最少使用的那些keys對應的資料,ps最長用的策略
(3)volatile-lru: 也是採取LRU演演算法,但是僅僅針對那些設定了指定存活時間(TTL)的key才會清理掉
(4)allkeys-random: 隨機選擇一些key來刪除掉
(5)volatile-random: 隨機選擇一些設定了TTL的key來刪除掉
(6)volatile-ttl: 移除掉部分keys,選擇那些TTL時間比較短的keys
2. LFU -Least Frequenty User,一定時間段內使用次數最少的
# LFU設定 Redis4.0之後為maxmemory_policy淘汰策略新增了兩個LFU模式:
volatile-lfu:對有過期時間的key採用LFU淘汰演演算法
allkeys-lfu:對全部key採用LFU淘汰演演算法
# 還有2個設定可以調整LFU演演算法:
lfu-log-factor 10
lfu-decay-time 1
# lfu-log-factor可以調整計數器counter的增長速度,lfu-log-factor越大,counter增長的越慢。
# lfu-decay-time是一個以分鐘為單位的數值,可以調整counter的減少速度
3. FIFO -First In First Out
### 快取穿透--(快取中沒有,資料中也沒有---》基本是惡意攻擊)
# 描述:
快取穿透是指快取和資料庫中都沒有的資料,而使用者不斷髮起請求,如發起為id為「-1」的資料或id為特別大不存在的資料。這時的使用者很可能是攻擊者,攻擊會導致資料庫壓力過大
# 解決方案:
1 介面層增加校驗,如使用者鑑權校驗,id做基礎校驗,id<=0的直接攔截
2 從快取取不到的資料,在資料庫中也沒有取到,這時也可以將key-value對寫為key-null,快取有效時間可以設定短點,如30秒(設定太長會導致正常情況也沒法使用)。這樣可以防止攻擊使用者反覆用同一個id暴力攻擊
3 通過布隆過濾器實現---》把資料庫中存在的資料,放到布隆過濾器中--》查的時候,去布隆過濾器查一下在不在---》在的話,繼續往後走,不在的話直接給前端錯誤
### 快取擊穿(快取中沒有,資料庫中有)
# 描述:
快取擊穿是指快取中沒有但資料庫中有的資料(一般是快取時間到期),這時由於並行使用者特別多,同時讀快取沒讀到資料,又同時去資料庫去取資料,引起資料庫壓力瞬間增大,造成過大壓力
# 解決方案:
設定熱點資料永遠不過期。
### 快取雪崩
# 描述:
快取雪崩是指快取中資料大批次到過期時間,而查詢資料量巨大,引起資料庫壓力過大甚至down機。和快取擊穿不同的是,快取擊穿指並行查同一條資料,快取雪崩是不同資料都過期了,很多資料都查不到從而查資料庫
# 解決方案:
1 快取資料的過期時間設定隨機,防止同一時間大量資料過期現象發生。
2 如果快取資料庫是分散式部署,將熱點資料均勻分佈在不同搞得快取資料庫中
3 設定熱點資料永遠不過期。