1、主从复制
目的:读写分离,主写,从读,容灾的快速恢复
主从复制原理:
- Slave 启动成功连接到master后会发送—个sync命令。
- Master 接到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,以完成一次完全同步。
- 全量复制:而 slave 服务在接收到数据库文件数据后,将其存盘并加载到内存中。
- 增量复制:Master 继续将新的所有收集到的修改命令依次传给 slave,完成同步。
- 但是只要是重新连接mater,一次完全同步(全量复制)将被自动执行。
主节点配置:
port 6379
daemonize yes
bind 主节点机器ip
requirepass 123456
pidfile /var/run/redis-6379.pid
logfile /var/log/redis/redis-6379.log
dbfilename /var/db/dump-6379.rdb
rdbcompression yes # 指定存储到本地数据库的时候是否进行压缩
从节点配置:默认从不可写,只能读
port 6379
daemonize yes
bind 从节点机器ip
requirepass 123456
masterauth 123456
pidfile /var/run/redis-6380.pid
logfile /var/log/redis/redis-6380.log
dbfilename /var/db/dump-6380.rdb
rdbcompression yes # 指定存储到本地数据库的时候是否进行压缩
slaveof 主ip 主redis端口 #或 直接在从服务器客户端执行命令 slaveof 主ip 主redis端口
slave-priority 100 # 哨兵选举优先级,值越小,优先级越高
查看redis运行情况
# ./redis-cli -p 6379
# info replication
注意:
使用主从模式时应注意matser节点的持久化操作,matser节点在未使用持久化的情况详情下如果宕机,并自动重新拉起服务,从服务器会出现丢失数据的情况。(关掉master持久化 # CONFIG SET save 的时候)
数据丢失的原因:
因为master服务挂了之后,重启服务后,slave节点会与master节点进行一次完整的重同步操作,所以由于master节点没有持久化,就导致slave节点上的数据也会丢失掉。所以在配置了Redis的主从模式的时候,应该打开主服务器的持久化功能。
2、哨兵模式
sentinel,哨兵是 redis 集群中非常重要的一个组件,主要有以下功能:
- 集群监控:负责监控 redis master和 slave 进程是否正常工作。
- 消息通知:如果某个 redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员。
- 故障转移:如果 master node 挂掉了,会自动转移到 slave node 上。
- 配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址。
哨兵用于实现 redis 集群的高可用,本身也是分布式的,作为一个哨兵集群去运行,互相协同工作。
- 故障转移时,判断一个 master node 是否宕机了,需要大部分的哨兵都同意才行,涉及到了分布式选举
- 即使部分哨兵节点挂掉了,哨兵集群还是能正常工作的
- 哨兵通常需要3个实例,来保证自己的健壮性。
- 哨兵+redis 主从的部署架构,是不保证数据零丢失的,只能保证 redis 集群的高可用性。
- 对于哨兵 + redis 主从这种复杂的部署架构,尽量在测试环境和生产环境,都进行充足的测试和演练。
选择条件:
- 优先级最高的(redis.conf中的slave-priority配置),不存在则找下一条
- 偏移量最大的(获取主机数据最全的),不存在则找下一条
- 选择runid最小的(每个redis实例启动后都会随机生成一个40位的runid)
配置:
1、新建配置文件 sentinel.conf:
# 修改redis-sentinel配置文件:/etc/redis-sentinel.conf
# 1. 绑定的地址
bind 172.19.131.247
# 2. 保护模式修改为否,允许远程连接
protected-mode no
# 3. 设定sentinel myid 每个都不一样,使用yum安装的时候,直接就生成了
sentinel myid 04d9d3fef5508f60498ac014388571e719188527
# 4. 设定监控地址,为对应的主redis库的内网地址
sentinel monitor mymaster 主ip 6379 2[至少有2个哨兵同意后才进行主从切换]
# 5. 设定5秒内没有响应,说明服务器挂了,需要将配置放在sentinel monitor master 127.0.0.1 6379 1下面
sentinel down-after-milliseconds mymaster 5000
# 6. 设定15秒内master没有活起来,就重新选举主
sentinel failover-timeout mymaster 15000
# 7. 表示如果master重新选出来后,其它slave节点能同时并行从新master同步缓存的台数有多少个,显然该值越大,所有slave节点完成同步切换的整体速度越快,但如果此时正好有人在访问这些slave,可能造成读取失败,影响面会更广。最保定的设置为1,只同一时间,只能有一台干这件事,这样其它slave还能继续服务,但是所有slave全部完成缓存更新同步的进程将变慢。
sentinel parallel-syncs mymaster 2
# 8. 主数据库密码,需要将配置放在sentinel monitor master 127.0.0.1 6379 1下面
sentinel auth-pass mymaster 123456789
2、重新启动:
# 启动需要按照Master->Slave->Sentinel的顺序进行启动
启动redis
# 启动redis哨兵 默认端口(26379)
redis-sentinel sentinel.conf
java识别主从:
private static JedisSentinelPool jedisSentinelPool = null;
public static Jedis getJedisFromSentinel() {
if (jedisSentinelPool == null) {
Set<String> sentinelSet = new HashSet<>();
sentinelSet.add("redisIp:26379");
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(10); //最大可用连接数:
jedisPoolConfig.setMaxIdle(5); //最大闲置连接数
jedisPoolConfig.setMinIdle(5); //最小闲置连接数。
jedisPoolConfig.setBlockWhenExhausted(true);//连接耗尽是否等待
jedisPoolConfig.setMaxWaitMillis(2000); //等待时间:
jedisPoolConfig.setTestOnBorrow(true); //取连接的时候进行一下测试 ping
jedisSentinelPool = new JedisSentinelPool("mymaster", sentinelSet, jedisPoolConfig);
return jedisSentinelPool.getResource();
}
}
集群(cluster):(无中心化集群,任何一个节点都可以作为集群入口 )
解决问题:
- 容量扩容(分布式存储数据,启动n个节点,每个节点存储数据的1/n ,通过计算key所在的插槽-CRC16(key)%集群插槽总数,每个集群节点处理其中一部分的插槽)
- 并发写操作,分摊压力
配置:
1、redis.conf
# 打开集群模式
cluster-enabled yes
# 设置节点配置文件名
cluster-config-file nodes-6379.conf
# 设定节点失联时间,超过该时间(毫秒),集群自动进行主从切换
cluster-node-timeout 15000
2、启动redis
启动完成后会生成节点对应的nodes-6379.conf文件
3、节点合并为集群(自动选择主和从)
$ cd redis安装包(不是安装目录)/src
# 执行命令
redis-cli --cluster create --cluster-replicas 1
[以最简单的方式配置集群,一主一从,三个节点] 节点1ip:端口 节点2ip:端口 节点3ip:端口 ...
# 分配原则,尽量保证每个主节点分配在不同ip上,每个主库和从库分配在不同的ip上
4、连接
# 普通连接
$ redis-cli -p 6379
# 集群连接
$ redis-cli -c -p 6379[任何一个节点都可]
> cluster nodes # 查看集群节点信息
5、集群操作
# 查询key的插槽值
> cluster keyslot keyName
# 计算插槽值中有几个key
> cluster countkeysinslot 12709[数值]
# 返回插槽中符合key的10个值
> cluster getkeysinslot 12709 10
6、故障恢复
- 节点主机挂掉后,从机代替主机,重启主机,主机变为从机
- 如果所有某一段插槽的主从节点都宕掉,redis 服务是否还能继续?
如果某一段插槽的主从都挂掉,而cluster-require-full-coverage为yes,那么,整个集群都挂掉。
如果某一段插槽的主从都挂掉,而cluster-require-full-coverage为no,那么,该插槽数据全都不能使用,也无法存储。
redis.conf中的参数 cluster-require-full-coverage.
7、集群jedis开发
public static void main(String[] args) {
Set<HostAndPort>set =new HashSet<HostAndPort>();
set.add(new HostAndPort("192.168.0.101",6379));
JedisCluster jedisCluster = new JedisCluster(set);
jedisCluster.set("k1", "v1");
System.out,println(jedisCluster.get("k1"));
}
8、集群操作的不足
- 多键操作是不被支持的。
- 多键的 Redis 事务是不被支持的。lua脚本不被支持。
- 由于集群方案出现较晚,很多公司已经采用了其他的集群方案,而代理或者客户端分片的方案想要迁移至 redis cluster,需要整体迁移而不是逐步过渡,复杂度较大。