目录
1. 取出所有指定前缀的 string 类型的 key 及其 value
2. 批量删除 key
3. 一键批量删除指定 key
4. 非阻塞批量删除指定 key
5. 批量修改特征 key 的过期时间为一个指定区间内的随机数
6. 查询每个客户端 IP 的连接数
7. 迁移 zset 类型的 key
8. 根据哨兵提供的信息更新配置文件
9. 根据哨兵提供的信息生成配置模板文件
1. 取出所有指定前缀的 string 类型的 key 及其 value
# 取出 key
redis-cli -p 6379 -a 123456 -n 0 --scan --pattern "g.at.ga.*" > a.txt# 拼出取 value 的命令
sed 's/^/get &/g' a.txt > b.txt# 取 value
cat b.txt | redis-cli -p 6379 -a 123456 -n 0 --pipe > c.txt# 将 key、value 拼成一个文件
paste a.txt c.txt > d.txt
2. 批量删除 key
(要删除的 key 已经导出到一个文件中)
# key 文件改名
mv keys.log keys.log.1# 拼接删除 key 的命令
sed 's/^/unlink &/g' key.log.1 > key.log# 执行批量删除
cat keys.log | redis-cli -p 6379 -a 123456 -n 0 --pipe
3. 一键批量删除指定 key
redis-cli -h 10.10.10.2 -p 6379 -a 123456 -n 1 --scan --pattern "g.at.ga.*" | \
xargs -n 1000 redis-cli -h 10.10.10.1 -p 6379 -a 123456 -n 1 unlink
4. 非阻塞批量删除指定 key
#!/bin/bashcommand_dir="/home/redis/redis-5.0.3/src"
REDIS_PASSWORD=123456# 已知主库和哨兵端口号,获取主库 IP
master_ip=`$command_dir/redis-cli -p 26379 info | grep 6379 | awk 'BEGIN{FS="[=:]"}{print $5}'`
# 从主库获取从库 IP 和端口
read slave_ip slave_port <<< `$command_dir/redis-cli -h $master_ip -p 6379 -a $REDIS_PASSWORD info replication | grep slave0 | awk -F"[=:,]" '{print $3,$5}'`# 读从库写主库执行删除
$command_dir/redis-cli -h $slave_ip -p $slave_port -a $REDIS_PASSWORD -n 1 --scan --pattern "m_roam_[123456789]*" | \
awk '{print "unlink "$0}' | \
$command_dir/redis-cli -h $master_ip -p 6379 -a $REDIS_PASSWORD -n 1 --pipe
5. 批量修改特征 key 的过期时间为一个指定区间内的随机数
# 方法1,用循环逐行拼命令,很慢
rm -f c.txt# 读从库导出 key
redis-cli -h 10.10.10.2 -p 6379 -a 123456 -n 1 --scan --pattern "room_onmic_photo:*" > a.txtcat a.txt|while read line
dor=`expr $RANDOM % 3600`echo "expire ${line} $r" >> c.txt
done# 主库执行修改操作
cat c.txt | redis-cli -h 10.10.10.1 -p 6379 -a 123456 -n 1 --pipe# 方法2,用 awk 拼命令,很快。通过管道一句执行,不需要临时文件。
redis-cli -h 10.10.10.2 -p 6379 -a 123456 -n 1 --scan --pattern "room_onmic_photo:*" | \
awk -v seed=$RANDOM 'BEGIN{srand(seed);} {print "expire "$0" " int(rand()*10000%3600+1) }' | \
redis-cli -h 10.10.10.1 -p 6379 -a 123456 -n 1 --pipe
6. 查询每个客户端 IP 的连接数
redis-cli -p 6379 -a 123456 client list | \
awk -F"[ =:]" '{print $4}' | sort -n | \
awk '{s[$1] += 1}END{ for(i in s){print i, s[i] } }' | sort -nrk2
7. 迁移 zset 类型的 key
# 导出
echo "zrange channel_overseas_final_hot 0 -1 withscores" | redis-cli -p 6379 -a 123456 -n 15 > zset.txt
# 导入
awk '{line=$0; getline; print "zadd channel_overseas_final_hot", $0,"\""line"\""}' zset.txt > zadd.txt
cat zadd.txt | redis-cli -p 6369 -a 123456 -n 15
8. 根据哨兵提供的信息更新配置文件
本例只更新 IP 地址的最后一段。
/bin/cp -f ~/tmp_sentinel_monitor.txt ~/tmp_sentinel_monitor.txt.bak
redis-cli -p 26379 info | egrep master[0-9]+ | \
awk -F"[,=.:]" '{print $3, $10, $11}' | \
while read master_name ip port;
dosed -i -E "s/(sentinel monitor ${master_name} [0-9]+\.[0-9]+\.[0-9]+\.)[0-9]+ ${port} /\1${ip} ${port} /" ~/tmp_sentinel_monitor.txt
done
这个需求无论怎样实现,本质上都是一个二重循环。上面这个脚本对配置文件执行了多次 sed 替换,次数是哨兵所监控的 master 数量。下面的脚本扫描一遍配置文件,但比上面的脚本执行还慢。
#!/bin/bash# 保存哨兵的 info 输出
redis-cli -p 26379 info | egrep master[0-9]+ | sed 's/123.123.123/10.10.10/g' > info_output # 模板文件路径
template_file="tmp_sentinel_monitor.txt"# 输出文件路径
output_file="output.conf"# 清空输出文件
> "$output_file"# 读取模板文件
while IFS= read -r line; do# 检查是否是 sentinel monitor 行if [[ "$line" =~ ^sentinel\ monitor ]]; then# 提取 Redis 实例名称redis_name=$(echo $line | awk '{print $3}')# 从 info 输出中提取对应的 IP 和端口address=$(cat info_output | grep "$redis_name," | awk -F"[=,]" '{print $6}')ip=$(echo "$address" | cut -d':' -f1)port=$(echo "$address" | cut -d':' -f2)# 替换模板中的 IP 和端口new_line="sentinel monitor $redis_name $ip $port 2"# 将新行写入输出文件echo "$new_line" >> "$output_file"else# 如果不是 sentinel monitor 行,直接写入输出文件echo "$line" >> "$output_file"fi
done < "$template_file"echo "配置文件已生成: $output_file"
高效的做法是,把 awk 输出的多列,每一列存储到一个 shell 数组中,然后用一个 sed 命令同时执行多个替换。这种方法只执行一次 awk 命令,通过遍历数组将多个 sed 替换命令写入一个临时脚本文件(避免单个 sed 命令过长),再只执行一次 sed 命令完成匹配和替换。update_tmp_sentinel_monitor.sh 文件内容如下:
#!/bin/bash# 初始化数组
col_name=()
col_ip=()
col_port=()# 使用 awk 一次性处理文件,并通过 read 解析每一列
while read -r c1 c2 c3; docol_name+=("$c1")col_ip+=("$c2")col_port+=("$c3")
done < <(redis-cli -p 26379 info | egrep master[0-9]+ | awk -F"[:=,.]" '{print $3,$10,$11}')# 将 sed 替换脚本写入临时文件
sed_script=$(mktemp)
for i in "${!col_name[@]}"; doecho "s/(sentinel monitor ${col_name[$i]} [0-9]+\.[0-9]+\.[0-9]+\.)[0-9]+ ${col_port[$i]} /\1${col_ip[$i]} ${col_port[$i]} /" >> "$sed_script"
done# 使用 sed -f 从临时文件中读取脚本并执行替换
sed -i -E -f "$sed_script" tmp_sentinel_monitor.txt# 删除临时文件
rm -f "$sed_script"
9. 根据哨兵提供的信息生成配置模板文件
generate_tmp_sentinel_monitor.sh 文件内容如下:
#!/bin/bash# 初始化变量
port=26379
sentinel_dir="/sentinel"
command_dir="/home/redis/redis-5.0.3/src"# 初始化数组
col_name=()
col_ip=()
col_port=()# 初始化文件
tmp_sentinel_monitor_file="${HOME}/tmp_sentinel_monitor.txt"
> "$tmp_sentinel_monitor_file"# 生成全局配置
echo -e "port ${port}\nprotected-mode no\ndir \"${sentinel_dir}\"\n" >> "$tmp_sentinel_monitor_file"# 将 awk 输出的三列按端口号排序后,分别存储到三个数组中
while read -r c1 c2 c3; docol_name+=("$c1")col_ip+=("$c2")col_port+=("$c3")
done < <($command_dir/redis-cli -p $port info | egrep master[0-9]+ | awk -F"[:=,]" '{print $3,$7,$8}' | sort -k3n)# 遍历数组,生成哨兵监控配置
for i in "${!col_name[@]}"; doif [ ${col_name[$i]} == "cluster1" ]; thenpassword="cluster1"elif [ ${col_name[$i]} == "cluster2" ] || [ ${col_name[$i]} == "cluster3" ] || [ ${col_name[$i]} == "cluster4" ]; thenpassword="cluster2"elif [ ${col_name[$i]} == "cluster5" ]; thenpassword="cluster5"elsepassword="123456"fiecho "sentinel monitor ${col_name[$i]} ${col_ip[$i]} ${col_port[$i]} 2" >> "$tmp_sentinel_monitor_file"echo "sentinel down-after-milliseconds ${col_name[$i]} 5000" >> "$tmp_sentinel_monitor_file"echo "sentinel failover-timeout ${col_name[$i]} 10000" >> "$tmp_sentinel_monitor_file"echo "sentinel auth-pass ${col_name[$i]} ${password}" >> "$tmp_sentinel_monitor_file"echo >> "$tmp_sentinel_monitor_file"
done# 删除最后一个空行,并替换成内网地址
sed -i '${/^\s*$/d};s/123.123.123/10.10.10/g' "$tmp_sentinel_monitor_file"