正文
Redis 菜鸟进阶
背景
最近产品一直要优化性能,加强高可用.
有一个课题是Redis高可用与性能调优.
我这边其实获取到的内容很有限.
最近济南疫情严重,自己锁骨骨折.
然后通勤时间基本上都用来查资料了.
但是毕竟水平有限..简单整理总结一下.
估计纰漏很多..需要进一步学习.
单点
观点: Redis是单线程结构.
需要注意事项:
1. Redis 在使用rdb模式在进行备份,或者是使用bgsave命令时
会folk一个线程出来进行保存, 减少阻塞时间.
2. Redis 6.0以上,增加IO多线程模式. 但是Redis的核心依旧是单线程.
3. IO多线程不建议太多, 超过CPU核数,或者是超过8个提升可能并不是非常明显.
单线程的Redis 是性能最好的redis
损耗和开销是最小的.
但是容量和连接是有限制的.
一个Redis最多不超过64k的TCP连接.
内部的maxclients 默认值是10000
关于性能最佳实践:
1. 建议直接物理机部署Redis. 或者是高性能虚拟机.
2. 建议选用高主频的CPU的服务器, 不要主频太低.
3. 如果有持久化,建议选用SSD高速存储设备, 避免影响吞吐量.
4. 不建议容器化,K8S内部署,会有性能损耗和开销.
5. 可以使用systemd守护进程进行服务保活.
集群
集群 是redis4.0 左右才开始支持的一种部署模式.
他主要是为了解决单点情况下的容量问题.
因为第一步针对key的CRC16的hash运算步骤,
所以实际上集群的性能是不如单点的redis性能好的
但是他可以支撑更多的容量,扩展产品的使用.
Redis Cluster的部署很简单. 但是需要注意使用
使用注意事项:
1. 需要客户端实现 Smart Client,完成重定向等工作
2. 批量操作限制,不支持跨 slot 查询,所以批量操作支持不友好
3. Key 事务操作支持有限,只支持多 key 在同一节点上的事务操作,当多个 Key 分布于不同的节点上时无法使用事务功能
4. Key 作为数据分区的最小粒度,不能将一个很大的键值对象如 hash、list 等映射到不同的节点
5. 不支持多数据库空间,单机下的 redis 可以支持到 16 个数据库,集群模式下只能使用 1 个数据库空间,即 db 0
Copy From https://juejin.cn/post/6865687858905088008
非常感谢原作者.
一键部署脚本
# 需要有redis-server 存在于 PATH 中.
ps -ef |grep redis |grep 700 |awk '{print $2}' |xargs kill -9
rm -rf /redis_cluster_file700
mkdir -p /redis_cluster_file700
cat >/redis_cluster_file700/redis_cluster.template <<EOF
port \${PORT}
requirepass Testxxxx
masterauth Testxxxx
protected-mode no
daemonize yes
appendonly yes
dir /redis_cluster_file700/\${PORT}/data/
cluster-enabled yes
cluster-config-file /redis_cluster_file700/\${PORT}/conf/nodes.conf
cluster-node-timeout 15000
cluster-announce-ip `ip addr |grep inet |grep ens192 |awk '{print $2}' |awk -F "/" '{print $1}'`
cluster-announce-port \${PORT}
cluster-announce-bus-port 1\${PORT}
EOF
cd /redis_cluster_file700
for port in `seq 7001 7006`; do \
mkdir -p ${port}/conf \
&& PORT=${port} envsubst < redis_cluster.template > ${port}/conf/redis.conf \
&& mkdir -p ${port}/data; \
done
for port in $(seq 7001 7006); do \
redis-server /redis_cluster_file700/$port/conf/redis.conf; \
done
redis-cli -a Testxxxx --cluster create \
`ip addr |grep inet |grep ens192 |awk '{print $2}' |awk -F "/" '{print $1}'`:7001 \
`ip addr |grep inet |grep ens192 |awk '{print $2}' |awk -F "/" '{print $1}'`:7002 \
`ip addr |grep inet |grep ens192 |awk '{print $2}' |awk -F "/" '{print $1}'`:7003 \
`ip addr |grep inet |grep ens192 |awk '{print $2}' |awk -F "/" '{print $1}'`:7004 \
`ip addr |grep inet |grep ens192 |awk '{print $2}' |awk -F "/" '{print $1}'`:7005 \
`ip addr |grep inet |grep ens192 |awk '{print $2}' |awk -F "/" '{print $1}'`:7006 \
--cluster-replicas 1
哨兵
其实我没太安装过哨兵
这里说一下哨兵应对的场景(解决的问题):
1. 只依靠持久化方案,在服务器下线后无法恢复服务
2. 使用主从复制,在 master 节点下线后,
可以手动将 slave 节点切换为 master,但是不能自动完成故障转移
哨兵的实现机制:
1. 监控(Monitoring):Sentinel会不断的检查你的主节点和从节点是否正常工作。
2. 通知(Notification):被监控的Redis实例如果出现问题,
Sentinel可以通过API(pub)通知系统管理员或者其他程序。
3. 自动故障转移(Automatic failover):如果一个 master 离线,Sentinel 会开始进行故障转移,
master 下的一个slave 会被选为新的 master,其他的 slave 会开始复制新的 master。
应用可以通过 Redis 服务的通知机制更新新的master 地址。
4. 配置提供(Configuration provider):客户端可以把 Sentinel 作为权威的配置发布者来获得最新的 master 地址。
如果发生了故障转移,Sentinel 集群会通知客户端新的 master 地址,并刷新 Redis 的配置。
哨兵这里其实是一些缺点的:
1. Sentinel 模式下,写操作仍然只能在 Sentinel 提供的 master
数据节点上执行,无法负载均衡. 写操作的支撑能力比较弱.
2. 持久化时 master 节点刷盘阻塞,服务请求成功率下降
3. slave 节点存储能力受到单机的限制
4. 分区问题:原 master redis 3 断开与 redis 1 和 redis 2 的连接,
此时 redis 1 和 redis 2 执行故障转移,
达到大多数,选择 redis 1 为 master。
这样,redis 1 和 redis 3 都能接受写请求,但数据无法同步,数据不一致
也是学习自:
https://juejin.cn/post/6865687858905088008
但是我理解. 如果sentinel 自己的集群出问题, 也会出现脑裂或者是其他问题
还是需要应用服务器做规划和处理的.
主从-读写分离
可以使用Redis Master-Slave + Keepalive +VIP 的方式进行实现.
需要自己编写脚本. 定时探测Master是否正常, 如果Master不正确则需要进行替换
需要注意的是 肯定有 20s-30s的延迟(多次判断.重启Redis等.)
优点:
1. 可用性高.
2. 与原生redis几乎完全一致的体验.
3. 实现成本较低. 业务层几乎无任何修改.
缺点:
1. Master宕机时有延迟. 无法做到无感.
2. 多了一个VIP层,性能会有开销.
3. 本质还是一个Redis来提供服务. 性能和容量没有提高.