redis的搭建,我是使用docker方式部署。
首先拉取镜像
docker pull redis
主从,哨兵,集群的区别
特性/配置 | Redis 主从复制 | Redis 哨兵 | Redis 集群 |
---|---|---|---|
主要目的 | 数据备份与读写分离 | 高可用性和故障自动切换 | 高并发和数据分散处理 |
架构 | 一个主节点和多个从节点 | 监控主从结构并自动切换 | 多个主节点,数据分片 |
数据复制 | 主节点到从节点 | 监控并管理主从复制 | 每个主节点管理自己的数据集 |
故障转移机制 | 手动或哨兵自动切换 | 自动故障转移 | 自动处理节点故障 |
可伸缩性 | 有限,依赖主节点 | 为主从结构增加高可用性 | 高,因为数据分布式处理 |
使用场景 | 数据备份和读扩展 | 关键应用的高可用性 | 大规模应用的高性能需求 |
设置复杂度 | 相对简单 | 中等,需配置哨兵 | 复杂,需规划数据分区 |
JedisConnectionFactory和LettuceConnectionFactory区别
JedisConnectionFactory和LettuceConnectionFactory区别
1. 连接方式
Lettuce 采用 Netty 底层网络框架,使用异步非阻塞式 IO 模型,支持多个 Redis 节点的连接池复用,适合高并发场景。
Jedis 采用传统的阻塞 IO 模型,每个 Redis 节点需要维护一个连接池,适合低并发场景。
2. 线程安全性
Lettuce 是线程安全的,可以在多线程环境下共享连接,而 Jedis 不是线程安全的,需要使用连接池进行连接复用。
在 Spring Boot 中配置 Redis 哨兵模式使用 Lettuce 和Jedis 作为 Redis 客户端的步骤分别如下。 推荐使用Lettuce 方式配置。
1.单机模式
启动redis服务
#方式一:无密码
docker run --name=redies-server -p 6379:6379 -d redis
#方式二:有密码认证
docker run --name=redies-server -p 6379:6379 -d redis --requirepass 123456
#方式三:自定义配置,--net="bridge": 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型;
docker run --name=redies-server-master -p 6379:6379 --net=host -v $PWD/redis-master.conf:/etc/redis/redis-master.conf -d redis /etc/redis/redis-master.conf
redis-master.conf配置文件
#绑定端口
port 6379
#设置指定的日志
logfile "redis-6379.log"
#Redis持久化擦用aof文件增量增加的方式
appendonly yes
appendfilename appendonly.aof
#设置主节点(master)认证的密码
masterauth 123456
#设置认证密码
requirepass 123456
1.1 SpringBoot连接单机Redis
SpringBoot方式使用Redis,直接使用RedisTemplete注入即可。SpringBoot配置如下
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=192.168.31.59
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=123456
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=20
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=10
# 连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=1000
2.哨兵模式
Redis的主从模式是一种部署多个Redis节点的方式,其中一个节点作为主节点(Master),其他节点作为从节点(Slave)。在这种模式下,主节点负责处理数据的事务性操作(如增删改),而从节点则主要用于提供读取操作。所有从节点的数据都是从主节点同步过来的。属于读写分离。
哨兵模式相对于主从模式,只是在主从模式的基础上增加了哨兵,实现了主节点宕机的情况下自动实将某一从节点转换成主节点。我这里使用1主2从2哨兵方式。
2.1 主从配置
1. redis-master.conf
#绑定端口
port 6379
#设置指定的日志
logfile "redis-6379.log"
#Redis持久化擦用aof文件增量增加的方式
appendonly yes
appendfilename appendonly.aof
#设置主节点(master)认证的密码
masterauth 123456
#设置认证密码
requirepass 123456
2. redis-slave1.conf
replicaof是新版本的命令,旧版本是slaveof命令,redis高版本向下兼容旧版命令
#绑定端口
port 6380
#设置指定的日志
logfile "redis-6380.log"
#Redis持久化擦用aof文件增量增加的方式
appendonly yes
appendfilename appendonly.aof
# 配置master节点信息
# 格式:slaveof <masterip> <masterport>
##<masterip> 是被监控的master的IP或主机名。因为Docker容器之间可以使用容器名访问,所以这里写master节点的容器名.
#<redis-port> 是被监控节点所监听的端口号
#salveof-read-only yes #表示只读,replicaof-read-only yes #表示只读,replicaof 192.168.31.59 6379
slaveof 192.168.31.59 6379
#设置主节点(master)认证的密码
masterauth 123456
#设置认证密码
requirepass 123456
3. redis-slave2.conf
#绑定端口
port 6381
#设置指定的日志
logfile "redis-6381.log"
#Redis持久化擦用aof文件增量增加的方式
appendonly yes
appendfilename appendonly.aof
# 配置master节点信息
# 格式:slaveof <masterip> <masterport>
##<masterip> 是被监控的master的IP或主机名。因为Docker容器之间可以使用容器名访问,所以这里写master节点的容器名.
#<redis-port> 是被监控节点所监听的端口号
#salveof-read-only yes #表示只读,replicaof-read-only yes #表示只读,replicaof 192.168.31.59 6379
slaveof 192.168.31.59 6379
#设置主节点(master)认证的密码
masterauth 123456
#设置认证密码
requirepass 123456
然后启动主从redis容器:
docker run --name=redies-server-master -p 6379:6379 -v $PWD/redis-master.conf:/etc/redis/redis-master.conf -d redis /etc/redis/redis-master.conf
docker run --name=redies-server-slave1 -p 6380:6380 -v $PWD/redis-slave1.conf:/etc/redis/redis-slave1.conf -d redis /etc/redis/redis-slave1.conf
docker run --name=redies-server-slave2 -p 6381:6381 -v $PWD/redis-slave2.conf:/etc/redis/redis-slave2.conf -d redis /etc/redis/redis-slave2.conf
进入主节点容器,输入redis-cli 连接主节点的redis 输入info relication命令查看信息:
这里两个从节点的发现ip并不是主机的IP,而是docker容器的IP地址。所以通过查看容器信息docker inspect redies-server-slave2。发现创建容器时未设置网路,默认使用了docker的桥接模式
修改创建容器的命令在创建容器时增加参数--net=host,network_mode设置host模式,就不需要设置ports。
host:使用宿主机网络接口功能与port映射同时使用,逻辑比较容易理解,本身已经使用了本地网络,所有端口是与宿主机同步,再作端口映射是本机映射到本机。network_mode的host模式和ports是互斥的
再次启动容器
docker run --name=redies-server-master --net=host -v $PWD/redis-master.conf:/etc/redis/redis-master.conf -d redis /etc/redis/redis-master.conf
docker run --name=redies-server-slave1 --net=host -v $PWD/redis-slave1.conf:/etc/redis/redis-slave1.conf -d redis /etc/redis/redis-slave1.conf
docker run --name=redies-server-slave2 --net=host -v $PWD/redis-slave2.conf:/etc/redis/redis-slave2.conf -d redis /etc/redis/redis-slave2.conf
启动完成之后连接主节点发现连接正常。
4.主节点和从节点
主节点可以set和get,从节点只能get。从节点是Redis复制模式的一种,它可以接收并复制主节点的数据,并提供读服务。与主节点不同,从节点不能进行写操作,因为所有写操作都必须由主节点执行。Redis从节点仅可用于读取,以降低主节点的访问压力。
Redis复制有两种模式:主从模式和Sentinel哨兵模式。在主从模式中,从节点只能执行读操作,而在Sentinel哨兵模式中,如果主节点失效时可以自动切换成从节点,变成一个能够写入的主节点,但这个过程需要时间,造成实时性和数据完整性的风险。因此,在实践中,建议把从节点作为读的备份节点使用,以确保数据的安全性和完整性。
4.1 断开主从关系
#连接上redis输入
slaveof no one
4.2 切换主从复制关系
slaveof {newMasterIp} {newMasterPort}
5.Springboot连接主从Redis
spring:
# redis 配置
redis:
master-slave:
master: 192.168.31.59:6380
password: 123456
slaves:
- 192.168.31.59:6381
- 192.168.31.59:6379
# 连接超时时间
timeout: 10s
# Lettuce 连接池配置
lettuce:
pool:
# 连接池中的最小空闲连接
min-idle: 5
# 连接池中的最大空闲连接
max-idle: 10
# 连接池的最大数据库连接数
max-active: 20
# 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: 1000ms
@Data
public class RedisMasterSlaveProperties {
private String master;
private String password;
private List<String> slaves;
}
Readform:见 Lettuce 的官方文档: 5.4.4. Read from settings
@Configuration
@ConditionalOnProperty(value = "spring.profiles.active", havingValue = "masterslave")
public class RedisMasterSlaveConfig {
@Bean
@ConfigurationProperties(prefix = "spring.redis.master-slave")
public RedisMasterSlaveProperties redisMasterSlaveProperties() {
return new RedisMasterSlaveProperties();
}
@Bean
public RedisTemplate redisTemplate(@Autowired @Qualifier("mylettuceConnectionFactory") RedisConnectionFactory connectionFactory) {
RedisTemplate redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(connectionFactory);
return redisTemplate;
}
@Bean("mylettuceConnectionFactory")
public RedisConnectionFactory lettuceConnectionFactory(RedisMasterSlaveProperties redisMasterSlaveProperties) {
// 解析主节点
String[] masterParts = redisMasterSlaveProperties.getMaster().split(":");
RedisStaticMasterReplicaConfiguration masterReplicaConfig = new RedisStaticMasterReplicaConfiguration(
masterParts[0], Integer.parseInt(masterParts[1])
);
masterReplicaConfig.setPassword(redisMasterSlaveProperties.getPassword());
// 添加从节点
for (String slave : redisMasterSlaveProperties.getSlaves()) {
String[] parts = slave.split(":");
masterReplicaConfig.addNode(parts[0], Integer.parseInt(parts[1]));
}
// 配置Lettuce客户端与读取策略
LettuceClientConfiguration lettuceClientConfiguration = LettuceClientConfiguration.builder()
.readFrom(ReadFrom.REPLICA_PREFERRED)
.build();
return new LettuceConnectionFactory(masterReplicaConfig, lettuceClientConfiguration);
}
}
2.2 哨兵配置
1. sentinel-26379.conf
#绑定端口
port 26379
#设置redis的工作目录
dir "/app/application"
sentinel resolve-hostnames yes
# 配置哨兵的监控参数
# 格式:sentinel monitor <master-name> <ip> <redis-port> <quorum>
# <master-name> 是为这个被监控的master起的名字
#<ip> 是被监控的master的IP或主机名。因为Docker容器之间可以使用容器名访问,所以这里写master节点的容器名.只有版本高于 6.2 的 sentinel 才能解析主机名,但默认情况下不启用此功能。sentinel resolve-hostnames yes sentinel.conf。如果您的哨兵具有较旧的版本,则主机名应替换为 和 ip。
#<redis-port> 是被监控节点所监听的端口号
#<quorom> 设定了当几个哨兵判定这个节点失效后,才认为这个节点真的失效了
sentinel monitor mymaster 192.168.31.59 6379 2
# master在连续多长时间无法响应PING指令后,就会主观判定节点下线,默认是30秒
# 格式:sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds mymaster 10000
sentinel failover-timeout mymaster 60000
# 连接主节点的密码
# 格式:sentinel auth-pass <master-name> <password>
sentinel auth-pass mymaster 123456
#设置认证密码
requirepass 123456
2. sentinel-26380.conf
#绑定端口
port 26380
#设置redis的工作目录
dir "/app/application"
sentinel resolve-hostnames yes
# 配置哨兵的监控参数
# 格式:sentinel monitor <master-name> <ip> <redis-port> <quorum>
# <master-name> 是为这个被监控的master起的名字
#<ip> 是被监控的master的IP或主机名。因为Docker容器之间可以使用容器名访问,所以这里写master节点的容器名.只有版本高于 6.2 的 sentinel 才能解析主机名,但默认情况下不启用此功能。sentinel resolve-hostnames yes sentinel.conf。如果您的哨兵具有较旧的版本,则主机名应替换为 和 ip。
#<redis-port> 是被监控节点所监听的端口号
#<quorom> 设定了当几个哨兵判定这个节点失效后,才认为这个节点真的失效了
sentinel monitor mymaster 192.168.31.59 6379 2
# master在连续多长时间无法响应PING指令后,就会主观判定节点下线,默认是30秒
# 格式:sentinel down-after-milliseconds <master-name> <milliseconds>
sentinel down-after-milliseconds mymaster 10000
sentinel failover-timeout mymaster 60000
# 连接主节点的密码
# 格式:sentinel auth-pass <master-name> <password>
sentinel auth-pass mymaster 123456
#设置认证密码
requirepass 123456
然后启动哨兵,哨兵启动需要增加redis-sentinel参数
docker run --name=redies-server-sentinell --net=host -p 26379:26379 -v $PWD/sentinel/sentinel-26379.conf:/etc/redis/sentinel-26379.conf -d redis redis-sentinel /etc/redis/sentinel-26379.conf
docker run --name=redies-server-sentinel2 --net=host -p 26380:26380 -v $PWD/sentinel/sentinel-26380.conf:/etc/redis/sentinel-26380.conf -d redis redis-sentinel /etc/redis/sentinel-26380.conf
然后连接其中一个哨兵,就可以查看当前主从节点信息
停止主节点看下主节点是否变化,发现主节点已经变化成6380的端口
3 SpringBoot连接Redis配置
#redis 哨兵模式
spring.redis.database=0
spring.redis.password=123456
#哨兵的配置列表,master地址哨兵会自动返回
spring.redis.sentinel.password=123456
spring.redis.sentinel.master=mymaster
spring.redis.sentinel.nodes=192.168.31.59:26379,192.168.31.59:26380
#最大连接数据库连接数,设 0 为没有限制
spring.redis.lettuce.pool.max-active=8
#最大等待连接中的数量,设 0 为没有限制
spring.redis.lettuce.pool.max-idle=8
#最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。
spring.redis.lettuce.pool.max-wait=-1ms
#最小等待连接中的数量,设 0 为没有限制
spring.redis.lettuce.pool.min-idle=0
spring.redis.lettuce.shutdown-timeout=100ms
@Autowired
RedisTemplate redisTemplate;
@PostConstruct
public void redisTemplate() {
redisTemplate.setKeySerializer(RedisSerializer.string());
redisTemplate.setValueSerializer(RedisSerializer.string());
redisTemplate.setDefaultSerializer(RedisSerializer.string());
}
2.集群模式
Redis集群介绍
Redis 集群是一个提供在多个Redis间节点间共享数据的程序集。
Redis集群并不支持处理多个keys的命令,因为这需要在不同的节点间移动数据,从而达不到像Redis那样的性能,在高负载的情况下可能会导致不可预料的错误.
Redis 集群通过分区来提供一定程度的可用性,在实际环境中当某个节点宕机或者不可达的情况下继续处理命令. Redis 集群的优势:
- 自动分割数据到不同的节点上。
- 整个集群的部分节点失败或者不可达的情况下能够继续处理命令。
Redis 集群的数据分片
Redis 集群没有使用一致性hash, 而是引入了 哈希槽的概念.
Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽,举个例子,比如当前集群有3个节点,那么:
- 节点 A 包含 0 到 5500号哈希槽.
- 节点 B 包含5501 到 11000 号哈希槽.
- 节点 C 包含11001 到 16384号哈希槽.
这种结构很容易添加或者删除节点. 比如如果我想新添加个节点D, 我需要从节点 A, B, C中得部分槽到D上. 如果我想移除节点A,需要将A中的槽移到B和C节点上,然后将没有任何槽的A节点从集群中移除即可. 由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态.
Redis 集群的主从复制模型
为了使在部分节点失败或者大部分节点无法通信的情况下集群仍然可用,所以集群使用了主从复制模型,每个节点都会有N-1个复制品.
在我们例子中具有A,B,C三个节点的集群,在没有复制模型的情况下,如果节点B失败了,那么整个集群就会以为缺少5501-11000这个范围的槽而不可用.
然而如果在集群创建的时候(或者过一段时间)我们为每个节点添加一个从节点A1,B1,C1,那么整个集群便有三个master节点和三个slave节点组成,这样在节点B失败后,集群便会选举B1为新的主节点继续服务,整个集群便不会因为槽找不到而不可用了
不过当B和B1 都失败后,集群是不可用的.
以上都是我摘抄的Reds官网消息,主要就是描述Redis集群是分片处理数据,如果需要高可用就需要依赖哨兵模式。这里我只创建集群模式。
redis-node1.conf
#绑定端口
port 6379
#设置指定的日志
logfile "redis-6379.log"
#Redis持久化擦用aof文件增量增加的方式
appendonly yes
appendfilename appendonly.aof
#开启集群配置
cluster-enabled yes
#集群配置文件
cluster-config-file nodes-node-1.conf
#集群超时时间
cluster-node-timeout 15000
#设置主节点(master)认证的密码
masterauth 123456
#设置认证密码
requirepass 123456
redis-node2.conf
#绑定端口
port 6380
#设置指定的日志
logfile "redis-6380.log"
#Redis持久化擦用aof文件增量增加的方式
appendonly yes
appendfilename appendonly.aof
#开启集群配置
cluster-enabled yes
#集群配置文件
cluster-config-file nodes-node-1.conf
#集群超时时间
cluster-node-timeout 15000
#设置主节点(master)认证的密码
masterauth 123456
#设置认证密码
requirepass 123456
redis-node3.conf
#绑定端口
port 6381
#设置指定的日志
logfile "redis-6381.log"
#Redis持久化擦用aof文件增量增加的方式
appendonly yes
appendfilename appendonly.aof
#开启集群配置
cluster-enabled yes
#集群配置文件
cluster-config-file nodes-node-1.conf
#集群超时时间
cluster-node-timeout 15000
#设置主节点(master)认证的密码
masterauth 123456
#设置认证密码
requirepass 123456
然后分别启动三个redis容器
docker run --name=redies-cluster-node1 -p 6379:6379 --net=host -v $PWD/redis-node1.conf:/etc/redis/redis-node1.conf -d redis /etc/redis/redis-node1.conf
docker run --name=redies-cluster-node2 -p 6380:6379 --net=host -v $PWD/redis-node2.conf:/etc/redis/redis-node2.conf -d redis /etc/redis/redis-node2.conf
docker run --name=redies-cluster-node3 -p 6381:6379 --net=host -v $PWD/redis-node3.conf:/etc/redis/redis-node3.conf -d redis /etc/redis/redis-node3.conf
启动完成之后连接任意一个redis,查看集群的状态是失败的
这时候需要进入容器执行redis集群的构建命令
redis-cli -h 192.168.31.193 -p 6379 -a 123456 --cluster create 192.168.31.193:6379 192.168.31.193:6380 192.168.31.193:6381 --cluster-replicas 0
redis-cli的参数说明:
1)# --cluster create 表示需要集群的redis主机和端口.
2) --cluster-replicas 0
表示为集群中的每一个主节点指定一个从节点,即一比一的复制,1表示一主一从。
再次连接redis,发现redis集群初始化成功。
使用redis客户端连接redis集群(注意加-c)
redis-cli -c -h 192.168.31.193 -a 123456 -p 6379
springboot配置使用
spring:
redis:
cluster:
nodes:
- 192.168.31.193:6379
- 192.168.31.193:6380
- 192.168.31.193:6381
max-redirects: 3 # 获取失败 最大重定向次数
password: 123456
pool:
max-active: 1000 # 连接池最大连接数(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
min-idle: 5 # 连接池中的最小空闲连接
timeout: 6000 # 连接超时时长(毫秒)
参考:
Docker部署Redis哨兵模式 - 小白一只726 - 博客园
https://www.jianshu.com/p/ce1d78cd368a
REDIS cluster-tutorial -- Redis中文资料站 -- Redis中国用户组(CRUG)