一 应用场景
为什么需要redis集群?
当主备复制场景,无法满足主机的单点故障时,需要引入集群配置。
一般数据库要处理的读请求远大于写请求 ,针对这种情况,我们优化数据库可以采用读写分离的策略。我们可以部 署一台主服务器主要用来处理写请求,部署多台从服务器 ,处理读请求。
基本机制,哨兵选举机制,如果有半数节点发现某个异常节点,共同决定改异常节点的状态,如果该节点是主节点,对应的备节点自动顶替为主节点。
主从复制的作用
1、数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
2、故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
3、负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
4、读写分离:可以用于实现读写分离,主库写、从库读,读写分离不仅可以提高服务器的负载能力,同时可根据需求的变化,改变从库的数量。
5、高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。
集群搭建
配置集群所需的环境
Redis集群至少需要3个节点,因为投票容错机制,所以2个节点无法构成集群。
要保证集群的高可用,需要每个节点都有从节点,也就是备份节点,所以Redis集群至少需要6台服务器。这里搭建的是伪分布式集群,即一台服务器虚拟运行6个redis实例,修改端口号为(7001-7006),实际生产环境的Redis集群搭建和这里是一样的。
1,规划网络。
用一台虚拟机模拟6个节点,一台机器6个节点,创建出3 master、3 salve 环境。ip地址192.168.44.34
2,创建 Redis 节点
首先在 192.168.44.34 机器上 /usr/java/目录下创建 redis_cluster 目录;
mkdir redis_cluster
3 创建目录
在 redis_cluster 目录下,创建名为7001、7002,7003、7004、7005,7006的目录
mkdir 7001 7002 7003 7004 7005 7006
4 将 redis.conf 拷贝到这六个目录中,
echo ./7002 ./7003 ./7004 ./7005 ./7006 | xargs -n 1 cp -v /usr/java/redis_cluster/7001/redis.conf
5 配置redis7001.conf
伪集群:
- 创建六个文件夹
- 文件夹里面写入配置文件
Redis 启动的时候使用不同的端口号
- 启动redis
使用六个配置文件
redis-cli --cluster create 集群节点-cluster-replicas 1
7001配置文件
include /usr/redis/bin/redis.conf
port 7001
dbfilename "dumb_7001.rdb"
appendfilename "appendonly_7001.apf"
pidfile "/var/run/redis_7001.pid"
daemonize yes
logfile "/usr/redis/redis_cluster/7001/redis_err_7001.log"
bind 0.0.0.0
save 60 1
dir "/usr/redis/redis_cluster/7001"
appendonly yes
appendfsync always
protected-mode no
cluster-enabled yes
cluster-config-file nodes-7001.conf
cluster-node-timeout 15000
批量复制
echo ./7002 ./7003 ./7004 ./7005 ./7006 | xargs -n 1 cp -v /usr/java/redis_cluster/7001/redis.conf
启动命令
[root@localhost redis_cluster]# /usr/redis/bin/redis-server /usr/redis/redis_cluster/7001/redis.conf
6 创建redis的集群
按照写的从前到后的顺序配置主节点从节点,前三个是主后三个是从
/usr/redis/bin/redis-cli --cluster create 192.168.44.34:7001 192.168.44.34:7002 192.168.44.34:7003 192.168.44.34:7004 192.168.44.34:7005 192.168.44.34:7006 --cluster-replicas 1
redis-cli --cluster create 集群节点
cluster-replicas 1
1 代表的是主从的比例 1:1
三主三从配置
输入yes配置成功
什么是slots
[OK] All 16384 slots covered.
一个 Redis 集群包含 16384 个插槽(hash slot), 数据库中的每个键都属于这 16384 个插槽的其中一个,
集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪个槽, 其中 CRC16(key) 语句用于计算键 key 的 CRC16 校验和 。
name 2 [0-5460]
集群中的每个节点负责处理一部分插槽。 举个例子, 如果一个集群可以有主节点, 其中:
节点 A 负责处理 0 号至 5460 号插槽。
节点 B 负责处理 5461 号至 10922 号插槽。
节点 C 负责处理 10923 号至 16383 号插槽。
连接集群:
redis-cli -c -h 127.0.0.1 -p 7001
(-h 127.0.0.1 -p 7001
查看集群的节点的信息
cluster nodes
检查集群的状态
./redis-cli --cluster check 127.0.0.1:7004
ID
对应的父节点的ID
给集群添加节点:
配置文件 7007 /redis.conf
修改内部
%s/7006/7007/g (将端口号改为新端口号)
启动
在添加之前首先要像7001-6一样,修改配置文件,启动7007 服务
redis-cli --cluster add-node 新节点 集群节点
/usr/redis/bin/redis-cli --cluster add-node 127.0.0.1:7007 127.0.0.1:7001
前面的IP加端口号是要添加的redis节点,后面的IP和端口号是集群中的任意一个节点。
分配槽
/usr/redis/bin/redis-cli --cluster reshard 127.0.0.1:7003(这个节点号可以随意写)
主节点写东西需要slots
7007 设置成主节点 默认slots =0
- 分配slots
Slots是一定的 16384
刚才添加的主节点还没有分配槽,所以无法使用
分配成功
添加从节点
redis-cli --cluster add-node 新节点 集群节点 --cluster-slave --cluster-master-id 主节点的id
代码示例
/usr/redis/bin/redis-cli --cluster add-node 127.0.0.1:7008 127.0.0.1:7001 --cluster-slave --cluster-master-id e4207653125f544d6f810bbf004f0fd47c58ae63
从节点配置成功
从节点里面不存数据 所以不需要slots
删除节点:
从节点:
/usr/redis/bin/redis-cli --cluster del-node 集群节点 节点id
成功删除
主节点:
/usr/redis/bin/redis-cli --cluster reshared 127.0.0.1:7001
删除主节点需要先使用 reshard 把主节点的slots移到其他节点才可以
原路返回
再次删除,成功
集群关闭
集群关闭的时候一定要优雅
千万不要kill 如果kill 集群里面的信息会被破坏
集群关机之后,集群重启,只需要直接启动各个节点,不需要重新组网,redis会根据node.conf自动组网
一键启动脚本
一键启动脚本 一键关闭脚本 redis的脚本的名称不能是redis否则错误难搞
#!/bin/bash
echo "开始启动redis集群"
l=`find /usr/redis/redis_cluster -name redis.conf`
for i in $l
do
/usr/redis/bin/redis-server $i
done
echo "集群启动成功"
启动成功
在集群中录入值
会根据计算出的值自动分配节点位置
不在一个slot下的键值,是不能使用mget,mset等多键操作。
可以通过{}来定义组的概念,从而使key中{}内相同内容的键值对放到一个slot中去。(按组分配插槽)
取也要加分组
高薪必问
什么是缓存穿透
缓存穿透是指缓存和数据库中都没有的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。
解决方案:
(1) 对空值缓存:如果一个查询返回的数据为空(不管是数据是否不存在),我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间会很短,最长不超过五分钟
(2) 设置可访问的名单(白名单):
使用bitmaps类型定义一个可以访问的名单,名单id作为bitmaps的偏移量,每次访问和bitmap里面的id进行比较,如果访问id不在bitmaps里面,进行拦截,不允许访问。
(3) 采用布隆过滤器:(布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量(位图)和一系列随机映射函数(哈希函数)。
布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。)
将所有可能存在的数据哈希到一个足够大的bitmaps中,一个一定不存在的数据会被 这个bitmaps拦截掉,从而避免了对底层存储系统的查询压力。
(4) 进行实时监控:当发现Redis的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单限制服务
缓存击穿是指缓存中没有但数据库中有的数据
一般是缓存时间到期
(name)
key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:缓存被“击穿”的问题。
解决问题:
(1)预先设置热门数据:在redis高峰访问之前,把一些热门数据提前存入到redis里面,加大这些热门数据key的时长
(2)实时调整:现场监控哪些数据热门,实时调整key的过期时长
(3)加锁
缓存雪崩:
缓存雪崩是指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。
Name k1 k2 k3
解决方案:
构建多级缓存架构:nginx缓存 + redis缓存 +其他缓存(ehcache等)
(2) 使用锁或队列:
5000 1000
用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。不适用高并发情况
(3) 设置过期标志更新缓存:
记录缓存数据是否过期(设置提前量),如果过期会触发通知另外的线程在后台去更新实际key的缓存。
(4) 将缓存失效时间分散开:
比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
Name k1 v1 : 3000s
时间随机3000 78000 900000
缓存预热:
提前将数据存放到缓存里面
Reddision