0%

Redis基础

基础

数据库

Redis中的数据库概念与MySQL中类似,但Redis中的数据库不支持自定义数据库的名字,每个数据库以编号命名。Redis不支持为每个数据库设置不同的访问密码,一个客户端可以访问到所有的数据库。所以对于Redis来说数据库更像是一种命名空间,且不适宜存储不同应用程序的数据

比如可以使用0号数据库存储某个应用生产环境中的数据,使用1号数据库存储测试环境中的数据,但不适宜使用0号数据库存储A应用的数据而使用1号数据库B应用的数据,不同的应用应该使用不同的Redis实例存储数据。

Redis默认有16个数据库,可以通过redis.conf文件中的databases进行修改。

1713342432845

客户端与Redis建立连接后默认选择0号数据库,使用select [数据库编号]可以选择使用第几个数据库(集群不支持,集群模式下只有一个db0)。

常用指令

中文官方文档(5.0.4):redis命令手册

  1. SET、MSET

SET命令用于存储一个或多个字符串值到一个键中。如果该键不存在,则会创建一个新键。

1
SET key value [EX seconds] [PX milliseconds] [NX|XX]

key是要存储的键名,value是要存储的值。EX和PX参数可选,用于设置键的过期时间,单位分别为秒和毫秒。NX和XX参数也可选,用于控制键的创建行为,NX表示只在键不存在时创建,XX表示只在键已存在时执行操作。

MSET命令可用于一次设置多个键值对。

1
MSET key1 value1 [key2 value2 ...]
  1. GET、MGET

GET命令用户返回给定key的值。如果key不存在返回null。

1
MGET key1 [key2 value2 ...]
  1. EXPIRE、PEXPIRE

EXPIRE命令用于设置键的过期时间,单位为秒,PEXPIRE类似,单位为毫秒。

1
EXPIRE key seconds

key是要设置过期时间的键名,seconds是过期时间,单位为秒。

  1. SETEX、SETNX、MSETNX

SETEX命令可用于一次设置带有过期时间的键值对。

1
SETEX key seconds value

key是要存储的键名,seconds是过期时间,单位为秒,value是要存储的值。

SETNX命令判断key是否存在,不存在才设置。常用来实现分布式锁

1
SETNX key value

MSETNX用来批量设置key,但该操作是原子的,在设置多个键的时候,如果其中一个key存在,那么其他未存在的key也会设置失败。

  1. KEYS

KEYS 用来查看key是否存在或有哪些key

1
KEYS keyname/*

*用来查看所有key

  1. FLUSHDB、FLUSHALL

FLUSHDB用来清空当前数据库中的所有key。

FLUSHALL用来清空所有数据库中的key。

  1. MOVE

MOVE用来移除数据库中对应的key和value

1
MOVE key
  1. TTL

TTL用来查看某个key的过期时间。

1
TTL key
  1. EXISTS

EXISTS用来判断某个key是否存在数据库中。

1
EXISTS key

如果存在返回1,不存在返回0

  1. APPEND

APPEND对某个key的value后追加内容。

1
APPEND key "value"

如果当前追加的key不存在,相当于set key。APPEND追加成功会返回value的长度。

  1. STRLEN

STRLEN用来获得某个key对应value的长度。

1
STRLEN key
  1. INCR、DECR、INCRBY、DECRBY

INCR用来使key对应的value值+1,DECR使key对应的value值-1。

1
2
INCR key
DECR key

INCRBY和DECRBY可以按照指定的步长增加或减少,返回value的长度。

1
INCRBY key steps

steps代表增加的步长,返回value的长度。

  1. GETRANGE、SETRANGE

GETRANGE用来获取一个左右闭合区间内的值,下标从0开始。

1
GETRANGE key start end

start代表起始位置,end代表终止位置,注意这个区间是左右闭合,start和end的值都能获取到。end为-1时表示到最后一个字符。

SETRANGE用来替换一个区间内的值。

1
SETRANGE key start value

start表示开始替换的起点,value为需要替换的值。替换时从起点开始(起点也会被替换)替换长度为value的内容。

数据类型

5种基础数据类型

String(字符串)

String使用场景:

  • 计数器
  • 统计多单位的数量(统计粉丝数量) uid:xxxxx:follow 0
  • 对象缓存存储 user:{id}:name zhangsan user:{id}:age 18

String最长可以存512MB数据。

List(列表)

List底层是一个链表,如果key不存在创建新的链表,如果存在新增内容。在两边插入效率最高,在中间插入效率较低。

List常用命令如下:

LPUSH key value [key, value, …]

LPUSH用来将value放入一个list中。放入后的顺序是倒着的,相当于头插。

RPUSH key value [key, value, …]

RPUSH以尾插的方式将value放入list中。

LRANGE key start end

LRANGE用来获得list中[start, end]的value。

LPOP key

LPOP弹出头部第一个元素

RPOP key

RPOP弹出尾部第一个元素

LINDEX key index

LINDEX通过下标获得list中的某一个值

LLEN key

LLEN返回list的长度

LREM key count value

LREM移除list中count个value

LTRIM key start length

LTRIM从下标为start开始(包括start),保留length个元素

RPOPLPUSH curlist newlist

将当前curlist中的最后一个元素弹出,并放入到新的列表newlist中

LSET key index value

LSET将指定下标的值替换为value,若该下标不存在或列表不存在则会报错

LINSERT key BEFORE|AFTER pivot value

LINSERT将value插入到列表中某个元素pivot前面或者后面

Set(集合)

Set常用命令:

SADD key value [value2, value3, …]

给set中添加value

SMEMBERS key

查看set中的所有value

SISMEMBER key value

查看set中的value是否存在,存在返回1,不存在返回0

SCARD key

获取set中的元素个数

SREM key value

移除set中指定的value

SRANDMEMBER key count

随机选出count个元素

SPOP key

随即删除一个元素

SMOVE key1 key2 value

将key1中的value移动到key2

SDIFF key1 key2

查看key1中与key2的差集

SINTER key1 key2

查看key1和key2的交集

SUNION key1 key2

查看key1和key2的并集

应用场景:

共同关注,共同爱好,二度好友(六度分割理论)

Hash(哈希)

常用命令:

HSET key hashkey hashvalue

存入一个hash值

HGET key hashkey

获取对应hashkey的value

HGETALL key

获取hash中的所有值

HDEL key hashkey [hashkey2, …]

删除hash中指定的key-value

HLEN key

获取hash中的value的数量

HKEYS key

获取hash中所有的key

HVALS key

获取hash中所有的value

hash更适合对象的存储,尤其是经常变动的信息

Zset(有序集合)

底层采用跳表实现。

常用命令:

ZADD key [NX|XX] [CH] [INCR] score member [score member]

将指定成员添加到zset中。XX表示仅更新存在成员,不添加新成员。NX表示不更新存在成员,仅添加新成员。CH修改返回值为发生变化的成员总数,原始返回值是新添加成员的总数。INCR与ZINCRBY相似,对成员分数进行递增。

ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]

升序返回score在[min, max]之间的value,withscores返回时会带上scores

ZREVRANGE key start stop [WITHSCORES]

start=0,stop=-1,从大到小进行排序

ZREM key member

移除zset中的成员

ZCARD key

获取zset中的成员个数

ZCOUNT key min max

获取[min, max]之间的成员数量

3种特殊数据类型

geospatial(地理位置)

用于朋友的定位、附近的人,打车距离计算等等。

常用命令如下:

GEOADD key 经度 维度 member

两极无法添加。

GEOPOS key member

获取指定member的经纬度

GEODIST key member1 member2 [unit]

查看两个成员之间的距离,unit指定单位:m、km、mi(英里)、ft(英尺)

GEORADIUS key 经度 维度 半径 [withdist] [withcoord] count

以经纬度为中心,查找半径内的成员,withdist返回距离,withcoord返回经纬度,count返回的个数

GEORADIUSBYMEMBER key member radius [unit]

找出位于指定元素周围的其他元素。

GEO底层实现原理是Zset,可以使用zset的命令操作geo。

Hyperloglog

Hyperloglog用来进行基数统计,可以用来实现网页的UV统计,但无法记录在线用户名。

基数是一个集合中不重复的元素,例如集合A={1,2,2,3,4},基数=4。

官方介绍具有0.81%错误率,在UV统计中可以忽略不计。

优点:占用的内存是固定的,2^64的元素仅需要12KB内存。从内存角度考虑首选Hyperloglog

常用指令:

PFADD key element [element2…]

添加元素

PFCOUNT key

统计元素数量

PFMERGE newkey sourcekey1 sourcekey2 [sourcekey3…]

合并(取并集)sourcekey1和sourcekey2中的元素到新的newkey中。

Bitmap

位数组,统计用户信息,是否活跃,是否登录,是否打卡等。两个状态的都可以使用

常用命令:

SETBIT key offset value

设置第offset位的值为value,value只能为0或1

GETBIT key offset

获取第offset位的值

BITCOUNT key [start end]

统计从start到end值为1的数量

事务

Redis事务本质是一组命令的集合,一个事务中的所有命令会被序列化,在事务执行过程中,会按照顺序执行。一次性、顺序性、排他性。因此Redis事务没有隔离级别的概念。

Redis单条命令保证原子性,但是事务不保证原子性。

事务使用:

  • 开启事务(multi)
  • 命令入队(……)
  • 执行事务(exec)

放弃事务:

  • 开启事务(multi)
  • 命令入队(……)
  • 放弃事务(discard)

编译型异常(代码有问题),事务中的所有命令都不会被执行。

运行时异常,执行时错误命令会抛出异常,其他命令正常执行。

Redis实现乐观锁

使用watch命令监控某个值,若该值被修改则事务执行失败。

1
2
3
4
5
6
7
8
# 线程A
set money 100
set out 0
watch money #监控money
multi # 开启事务
DECRBY money 20
INCRBY out 20
exec # 执行事务
1
2
# 线程B
set money 1000

若线程A声明事务后还未执行,此时线程B修改了money的值,那么线程A开始事务后,事务执行失败。

可以使用unwatch解锁,然后再重新使用watch加锁,然后再执行事务。

该过程与乐观锁的Version实现类似。

Jedis

在Java中使用Redis需要使用中间加Jedis。

导入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<dependencies>
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>5.1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.fastjson2/fastjson2 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.48</version>
</dependency>
</dependencies>

连接数据库

1
2
3
4
5
public static void main(String[] args) {
// 1. new jedis 对象
Jedis jedis = new Jedis("172.29.1.122", 6379);
System.out.println(jedis.ping());
}

连接成功输出PONG。

连接失败参考:idea连接云服务器上的redis报错:Failed to connect to any host resolved for DNS name.【已解决】-CSDN博客

Jedis中的命令与直接在Redis中操作命令相同。

Java实现Redis事务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static void main(String[] args) {
try (Jedis jedis = new Jedis("172.29.1.122", 6379)) {
JSONObject jsonObject = new JSONObject();
jsonObject.put("hello","world");
jsonObject.put("name","fjz");
String result = jsonObject.toJSONString();
Transaction multi = jedis.multi();

try {
multi.set("user1", result);
multi.set("user2", result);
int i = 1/0; //抛出异常事务
multi.exec(); //执行事务
} catch (Exception e) {
multi.discard(); //放弃事务
throw new RuntimeException(e);
} finally {
System.out.println(jedis.get("user1"));
System.out.println(jedis.get("user2"));
jedis.close();
}
}
}

SpringBoot整合Redis

在SpringBoot2.x之后,原来底层使用Jedis被替换成了lettuce。

jedis:采用的直连,多个线程操作的话,是不安全的,想要避免需要使用jedis pool连接池。类似BIO模式。

lettuce:采用netty,实例可以在多个线程中共享,不存在线程不安全的情况。可以减少线程数量。类似NIO模型。

源码分析:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Bean
@ConditionalOnMissingBean(
name = {"redisTemplate"}
) // 存在自定义的redisTemplate则这个不生效,可以自定义一个redisTemplate来替换这个默认类
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
// 默认的RedisTemplate没有过多的设置,redis对象都是需要序列化的
//两个泛型都是Object类型,使用需要强制转换
RedisTemplate<Object, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}

@Bean
@ConditionalOnMissingBean //由于String类型是最常使用的类,所以专门写了一个String
@ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
return new StringRedisTemplate(redisConnectionFactory);
}

使用步骤:

  1. 导入依赖
1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  1. 配置连接
1
2
spring.redis.host=172.29.1.122
spring.redis.port=6379
  1. 使用
1
2
3
4
5
6
7
8
9
10
void contextLoad(){
redisTemplate.opsForValue(); // 操作字符串,类似String
redisTemplate.opsForList(); //操作列表
redisTemplate.opsForSet(); //操作集合
// 除了基本的操作,常用的方法可以通过redisTemplate进行操作,比如事务

// 可以连接redis后直接使用类似redis中的命令进行操作,不常用!
RedisConnection connection = redisTemplate.getConnectionFactory().getConnection();
connection.flushDb();
}

自定义RedisTemplate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.fjz.redis02springboot.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
// 为了开发方便,一般直接使用<String, Object>
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(redisConnectionFactory);
// 配置具体的序列化方式
Jackson2JsonRedisSerializer Jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.activateDefaultTyping(om.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
Jackson2JsonRedisSerializer.setObjectMapper(om);
// String的序列化方式
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(Jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(Jackson2JsonRedisSerializer);
template.afterPropertiesSet();

return template;
}
}

持久化

Redis是内存数据库,如果不将数据持久化到磁盘中,那么服务器一旦退出或者挂掉,那么服务器中的数据也会丢失。Redis提供了RDB(Redis DataBase)和AOF(Append Only File)两种持久化方式。

RDB

在指定的时间间隔内将内存中的数据快照写入磁盘,恢复时将快照文件直接读到内存中。默认采用RDB持久化。

1713574276693

Redis会单独创建(fork)一个子进程来进行持久化,先将数据写入到一个临时文件中,等待持久化过程结束,再用这个临时文件替换上次持久化好的文件。在整个过程中,主进程不进行任何IO操作,保证不影响主线程的性能。

如果需要进行大规模数据恢复,并且对于数据完整性不是特别敏感,使用RDB方式比AOF方式更加高效。

RDB的缺点是最后一次持久化后的数据可能丢失。

RDB触发机制

  • save规则满足的情况下,会自动触发RDB规则
  • 执行flushall命令,也会触发RDB规则
  • 默认情况下退出Redis时也会产生RDB文件
  • 手动使用SAVEBGSAVE命令(SAVE阻塞主进程直接调用rdbSave,BGSAVE使用子进程调用rdbSave)
  • 主从复制时,从节点要从主节点进行全量复制也会触发bgsave操作,生成当时的快照发送给从节点
  • 执行debug reload命令重新加载redis时也会触发bgsave

备份会自动生成一个dump.rdb文件(该文件名可在redis.conf中进行配置)

如何使用RDB恢复数据

只需要将rdb文件放在Redis启动目录即可,Redis启动时会自动检查dump.rdb并恢复其中的数据。

使用以下命令可以查看dump.rdb需要存在的位置。

1
2
3
127.0.0.1:6379> config get dir
1) "dir"
2) "/usr/local/bin" # 如果这个目录下存在dump.rdb文件,启动时就会自动恢复其中的数据

优缺点

  • 优点

    • RDB文件是某个时间节点的快照,默认使用LZF算法进行压缩,压缩后的文件体积远远小于内存大小,适用于备份、全量复制等场景
    • Redis加载RDB文件恢复数据要远远快于AOF方式
  • 缺点

    • RDB方式实时性不够,无法做到秒级的持久化
    • 每次调用bgsave都需要fork子进程,fork子进程属于重量级操作,频繁执行成本较高
    • RDB文件是二进制的,没有可读性,AOF文件在了解其结构的情况下可以手动修改或者补全
    • 版本兼容RDB文件问题

AOF

以日志的形式来记录每个写操作,将Redis执行过的所有指令记录下来(不记录读操作),只允许追加文件但不可以改写文件,Redis启动的时候会读取AOF文件重新构建数据,即Redis重启后根据日志文件的内容将写指令全部执行一次,完成数据恢复。

同步步骤

  1. 命令传播: Redis 将执行完的命令、命令的参数、命令的参数个数等信息发送到 AOF 程序中
  2. 缓存追加: AOF 程序根据接收到的命令数据,将命令转换为网络通讯协议的格式,然后将协议内容追加到服务器的 AOF 缓存中
  3. 文件写入和保存: AOF 缓存中的内容被写入到 AOF 文件末尾,如果设定的 AOF 保存条件被满足的话,fsync函数或者fdatasync函数会被调用,将写入的内容真正地保存到磁盘中

AOF保存模式

Redis 目前支持三种 AOF 保存模式,可以在redis.conf文件中选择。

  • Always,同步写回:每个写命令执行完,立马同步地将日志写回磁盘
  • Everysec,每秒写回:每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,每隔一秒把缓冲区中的内容写入磁盘
  • No,操作系统控制的写回:每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘

保存模式优缺点

AOF后台重写

AOF 后台重写,是为了避免主进程被阻塞,无法处理请求,所以采用主进程fork出子进程,用于 AOF 重写。为了避免在 AOF 重写期间新命令对现有数据的修改导致的不一致问题,Redis 增加了一个AOF 重写缓存,这个缓存在fork出子进程之后开始启用,Redis 主进程在接到新的写命令之后,除了会将这个写命令的协议内容追加到现有的 AOF 文件之外,还会追加到这个缓存中。

当子进程在执行 AOF 重写时, 主进程需要执行以下三个工作:

  1. 处理命令请求
  2. 将写命令追加到现有的 AOF 文件中
  3. 将写命令追加到 AOF 重写缓存中

当子进程完成 AOF 重写之后,它会向主进程发送一个完成信号,主进程在接到完成信号之后,会调用一个信号处理函数,并完成以下工作:

  1. 将 AOF 重写缓存中的内容全部写入到新 AOF 文件中。
  2. 对新的 AOF 文件进行改名,覆盖原有的 AOF 文件

AOF优缺点

  • 优点

    • 拥有不同的fsync策略,fsync是使用后台线程执行的,写入性能很好
    • AOF是一个仅追加日志,没有查找和断电时的损坏问题。即使由于某种原因(磁盘已满或其他原因)日志以写入一半的命令结束,redis-check-aof工具也能够轻松修复它
    • 当 AOF 变得太大时,Redis 能够在后台自动重写 AOF
    • AOF 以易于理解和解析的格式包含一个接一个地记录所有操作的日志,使得导出和恢复十分简单
  • 缺点

    • 对于相同的数据集,AOF 文件通常比等效的 RDB 文件大

    • 根据确切的 fsync 策略,AOF 可能比 RDB 慢

      (Redis < 7.0)

    • 如果在重写期间有对数据库的写入,AOF 会使用大量内存

    • 重写期间到达的所有写入命令都会写入磁盘两次

    • Redis 可能会在重写结束时冻结写入并将这些写入命令同步到新的 AOF 文件

Redis主从复制

基本概念

主从复制是将一台Redis服务器的数据复制到其他Redis服务器。数据的复制是单向的,只能由主节点到从节点。主节点以写为主,从节点以读为主。

默认情况下,每台Redis服务器都是主节点,且一个弓主节点可以有多个从节点(或没有从节点),但一个从节点只能有一个主节点。

主从复制的主要作用:

  1. 数据冗余:主从复制实现了数据的热备份,是持久化之外的另一种数据冗余方式。
  2. 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复。
  3. 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务,分担服务器负载压力。
  4. 高可用:主从复制是哨兵和集群的基础。

环境配置

  1. 查看当前数据库的信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
127.0.0.1:6379> info replication	# 查看当前库的信息
# Replication
role:master # 当前库的角色为主库
connected_slaves:0 # 当前的从机数量
master_failover_state:no-failover
master_replid:3a8f232a02a30c574554d2527b8fd34b4ca68349
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:5
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

  1. 修改每个数据库的配置文件
1
2
3
4
port 6379	# 为每个数据库指定不同的端口
logfile "6379.log" # 因为有多个数据库,不能使用默认的log文件名,避免重复
dbfilename dump6379.rdb # 同理,防止rdb文件重名
pidfile /var/run/redis_6379.pid # 同理
  1. 启动Redis并配置从库

默认情况下,启动后的Redis数据库都是主库,此时需要对从库进行配置。

1
2
SLAVEOF host port
# SLAVEOF no one # 使自己成为主节点

在从库中输入以上命令,host为主机地址,port为主机端口号。

以上配置是通过命令配置的,只是暂时的主从,实际生产中应该在配置文件中配置,保证永久主从。

  1. 配置文件配置主从

在配置文件中的replication部分添加以下配置:

1
2
replicaof <masterip> <masterport>	# 分别代表主机的ip和port
masterauth <master-password> # 主机的密码,若没有密码可不要

通过以上配置后,Redis数据库启动后默认为从库。

复制原理

  1. Slave启动成功后连接到master后会发送一个sync同步命令。
  2. master接收到命令后,启动后台的存盘进程,同时收集所有接收到的用于修改数据集的命令,在后台进程执行完毕后,master将传送整个数据文件到slave,并完成一次完全同步。
  3. slave接收到数据库文件数据后,将其存盘并加载到内存中(全量复制)。
  4. master继续将新的所有收集到的修改命令依次传给slave,完成同步(增量复制)。

slave重新连接master后,会自动执行一次全量复制。

哨兵模式

哨兵配置

创建一个sentinel.conf文件,在文件中输入以下内容。

1
2
3
4
5
6
7
8
9
sentinel monitor <master-name> <ip> <redis-port> <quorum>	# quorum配置多少个哨兵统一认为master节点失联,那么客观上就认为主节点失联了
port 26379 # 如果有哨兵集群,需要配置多个哨兵端口
dir /tmp #哨兵的工作目录
sentinel auth-pass <master-name> <password>
sentinel parallel-syncs <master-name> <numslaves> #指定在发生主备切换时,最多有多少个slave可以同时对新的master进行同步
sentinel down-after-milliseconds <master-name> <milliseconds> # 指定在多少毫秒之后,主节点没有应答哨兵,此时哨兵主观认为主节点下线,默认为30秒
sentinel failover-timeout <master-name> <milliseconds> # 故障转移时间,默认为3分钟
sentinel notification-script <master-name> <script-path> # 当哨兵有警告级别的事件发生时,执行该脚本。可以用来将错误发送到邮箱等等
sentinel client-reconfig-script <master-name> <script-path> # 当master因failover发生改变时,调用该脚本。可以用来告诉运维新的master是哪个

redisname为该哨兵监控的redis的名字,host为监控redis的ip,port为端口,1代表当监控的redis挂掉后,哨兵可以发起投票,选举新的主节点。

如果主机重新上线了,会被当做从节点。

优缺点

  • 优点:
    • 主从可以切换,故障可以转移,系统可用性高
    • 哨兵模式是主从模式的升级,更加健壮
  • 缺点:
    • 实现哨兵模式的配置较为麻烦
原创技术分享,您的支持将鼓励我继续创作