环境
考虑到既然是高可用,那么Sentinel 也得是一个以上。
IP | port | 部署 |
---|---|---|
192.168.81.101 | 6379 | Redis6 master |
192.168.81.101 | 26379 | Redis6 Sentinel |
192.168.81.102 | 6379 | Redis6 slave |
192.168.81.102 | 26379 | Redis6 Sentinel |
![](https://img.haomeiwen.com/i13859779/ba461db3eca2cd72.png)
主从搭建
为了主从 Redis 安全,密码是必须设置的,否则等着被挖矿吧。在配置文件修改如下:
主从密码可以一样,方便记忆。
requirepass ilovejj
设置连接 master 时的认证密码,一搬给 slave 的配置文件设置
masterauth ilovejj
都启动成功之后在 slave 使用以下命令
127.0.0.1:6379> slaveof 192.168.81.111 6379
OK
可以从日志里面看到是否启动成功,如果没有启动成功则会一直打印如下,我这里故意弄一个错误的IP加以说明。
2187:S 16 Nov 2020 17:19:17.913 # Error condition on socket for SYNC: Operation now in progress
2187:S 16 Nov 2020 17:19:18.526 * Connecting to MASTER 192.168.81.111:6379
2187:S 16 Nov 2020 17:19:18.526 * MASTER <-> REPLICA sync started
一定要记得加日志,否则以后怎么死的都不知道。
哨兵
在 Redis 目录下,自带着一个 sentinel.cnf 文件,有着相关 sentinel 配置,我们修改如下:
# 端口默认
port 26379
daemonize yes
logfile "/opt/module/redis-6.0.8/log/sentinel.log"
sentinel monitor mymaster 192.168.81.101 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
sentinel auth-pass mymaster ilovejj
切记哨兵,一定要用的是 master 的IP,哪怕在同一台服务器上,也要使用 IP,不要使用127.0.0.1,否则挂掉一台哨兵,salve 可能无法复制。
-
daemonize yes 默认 no
默认是no,改为yes让在后台运行 -
logfile "/opt/module/redis-6.0.8/log/sentinel.log"
默认不输出日志,一定要配置日志,否则... -
sentinel monitor mymaster 192.168.81.101 6379 2
监视一个名为 mymaster 的主服务器, 这个主服务器的 IP 地址为 192.168.81.101 , 端口号为 6379 , 而将这个主服务器判断为失效至少需要 2 个 Sentinel 同意。这里的 mymaster 只是一个匿名,供以下配置使用。 -
sentinel down-after-milliseconds mymaster 60000 默认 30000ms
如果服务器在给定的毫秒数之内, 没有返回 Sentinel 发送的 PING 命令的回复, 或者返回一个错误, 那么 Sentinel 将这个服务器标记为主观下线(subjectively down,简称 SDOWN )。
不过只有一个 Sentinel 将服务器标记为主观下线并不一定会引起服务器的自动故障迁移: 只有在足够数量的 Sentinel 都将一个服务器标记为主观下线之后, 服务器才会被标记为客观下线(objectively down, 简称 ODOWN ), 这时自动故障迁移才会执行。
将服务器标记为客观下线所需的 Sentinel 数量由对主服务器的配置决定。 -
sentinel failover-timeout mymaster 180000 默认 180000ms
故障转移时间 -
sentinel parallel-syncs mymaster 1 默认1
在执行故障转移时, 最多可以有多少个从服务器同时对新的主服务器进行同步, 这个数字越小, 完成故障转移所需的时间就越长。
如果从服务器被设置为允许使用过期数据集(参见对 redis.conf 文件中对 slave-serve-stale-data 选项的说明), 那么你可能不希望所有从服务器都在同一时间向新的主服务器发送同步请求, 因为尽管复制过程的绝大部分步骤都不会阻塞从服务器, 但从服务器在载入主服务器发来的 RDB 文件时, 仍然会造成从服务器在一段时间内不能处理命令请求: 如果全部从服务器一起对新的主服务器进行同步, 那么就可能会造成所有从服务器在短时间内全部不可用的情况出现。
你可以通过将这个值设为 1 来保证每次只有一个从服务器处于不能处理命令请求的状态。 -
sentinel auth-pass mymaster ilovejj
配置密码
哨兵启动
我这里哨兵和redis实例是同一台,意思就是可以一起使用,不需要在部署一个哨兵。
./redis-server ../sentinel.conf --sentinel
启动后记得查看日志,一些不为人知的配置错误都会在日志里面显示。其中会有一台一直输出和其他哨兵连接的信息。
spring boot redis 哨兵
maven,只放关于Redis的
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
</dependencies>
配置文件
spring
redis:
timeout: 10000
sentinel:
nodes:
- 192.168.81.101:26379
- 192.168.81.102:26379
password: ilovejj
master: mymaster
# 这是我框架自己得一个属性大家忽略
enable: true
lettuce:
pool:
max-wait: 10000
max-active: 30
max-idle: 15
min-idle: 15
配置类
package com.giant.cloud.config;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import java.util.HashSet;
/**
* @author big uncle
* @date 2020/11/17 11:57
* @module
**/
@Configuration
@Slf4j
@ConditionalOnExpression("${spring.redis.sentinel.enable:false}")
public class RedisSentinelConfig {
@Autowired
RedisProperties redisProperties;
/**
* GenericObjectPoolConfig 连接池配置
*/
@Bean
public GenericObjectPoolConfig genericObjectPoolConfig() {
GenericObjectPoolConfig genericObjectPoolConfig = new GenericObjectPoolConfig();
genericObjectPoolConfig.setMaxIdle(redisProperties.getLettuce().getPool().getMaxIdle());
genericObjectPoolConfig.setMinIdle(redisProperties.getLettuce().getPool().getMinIdle());
genericObjectPoolConfig.setMaxTotal(redisProperties.getLettuce().getPool().getMaxActive());
genericObjectPoolConfig.setMaxWaitMillis(redisProperties.getLettuce().getPool().getMaxWait().toMillis());
return genericObjectPoolConfig;
}
/**
* 哨兵
**/
@Bean
public LettuceConnectionFactory redisConnectionFactory(GenericObjectPoolConfig genericObjectPoolConfig) {
RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration(redisProperties.getSentinel().getMaster(),
new HashSet<>(redisProperties.getSentinel().getNodes()));
redisSentinelConfiguration.setPassword(redisProperties.getSentinel().getPassword());
// 配置池
LettuceClientConfiguration clientConfig = LettucePoolingClientConfiguration.builder()
.commandTimeout(redisProperties.getTimeout())
.poolConfig(genericObjectPoolConfig)
.build();
LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisSentinelConfiguration,clientConfig);
log.debug("redis 哨兵启动");
return lettuceConnectionFactory;
}
}
网友评论