redis高可用、redis叢集、redis快取優化

2022-05-23 21:05:18

今日內容概要

  • 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 設定熱點資料永遠不過期。