46.Redis持久化、主从与哨兵架构详解

Redis持久化

RDB快照

Redis 将内存数据保存至二进制文件中。

配置文件中

  • dbfilename dump.rdb
  • dir ./
  • # save 60 1000
    • 60 秒内有至少有 1000 个键被改动触发保存数据
    • 注释所有 save 策略,即关闭RDB快照

客户端执行命令生成二进制文件

  • save 阻塞客户端命令
  • bgsave
    • 借助操作系统提供的写时复制技术(Copy-On-Write, COW),不会阻塞客户端命令
    • 异步执行,fork子进程,消耗内存

AOF

记录一种resp协议格式数据

配置文件中

  • appendonly yes
  • appendfilename “appendonly.aof”
  • appendfsync always 性能差,最安全
  • appendfsync everysec:每秒 fsync 一次,足够快,并且在故障时只会丢失 1 秒钟的数据。
  • appendfsync no:从不 fsync ,将数据交给操作系统来处理。

客户端执行命令重写AOF

  • bgrewriteaof

RDB vs AOF

RDB文件小,恢复速度快,容易丢失数据。

AOF体积大,恢复慢,数据安全性根据策略决定。

Redis 4.0 混合持久化

配置文件中

  • aof-use-rdb-preamble yes
    • 必须先开启aof

如果开启混合持久化,AOF重写时,将之前的记录做RDB快照处理 + 新增命令以AOF格式存储,提升重启效率。

Redis数据备份策略

  1. 写crontab定时调度脚本,每小时都copy一份rdb或aof的备份到一个目录中去,仅仅保留最近48小时的备份
  2. 每天都保留一份当日的数据备份到一个目录中去,可以保留最近1个月的备份
  3. 每次copy备份的时候,都把太旧的备份给删了
  4. 每天晚上将当前机器上的备份复制一份到其他机器上,以防机器损坏

Redis主从架构

redis主从架构搭建配置

#复制一份redis.conf文件
#修改配置
port 6380
pidfile /var/run/redis_6380.pid
logfile "6380.log"
dir ./data/6380  #需要自建目录
replicaof  

Redis主从工作原理

  • 全量复制
    • 主: rdb数据 + repl buffer
    • 从:清空数据并加载rdb数据 + 执行 repl buffer
  • 部分复制
    • 主:repl backlog buffer (最近的一些命令)
      • 配置文件控制缓存大小 repl-backlog-size 1mb

如果有很多从节点,会出现主从复制风暴,可以让部分从节点与从节点同步数据。

pipeline

管道的命令执行方式:cat redis.txt | redis-cli -h 127.0.0.1 -a password - p 6379 --pipe

@Test
public void pipelineDemo() {
    Jedis jedis = pool.getResource();
    Pipeline pl = jedis.pipelined();
    for (int i = 0; i < 100; i++) {
        pl.incr("pipelineKey");
        pl.set("pipe:" + i, "v" + i);
    }
    List<Object> objects = pl.syncAndReturnAll();
    for (Object object : objects) {
        System.out.println(object);
    }
}

lua脚本

lua脚本命令执行方式:redis-cli --eval /tmp/test.lua

Redis会将整个脚本作为一个整体执行,中间不会被其他命令插入。管道不是原子的,不过redis的批量操作命令(类似mset)是原子的。

@Test
public void luaDemo() {
    Jedis jedis = pool.getResource();
    jedis.set("product_stock_10016", "15");
    String script = " local count = redis.call('get', KEYS[1]) " +
        " redis.call('set', 'haha', '一只小苹果') " +
        " local a = tonumber(count) " +
        " local b = tonumber(ARGV[1]) " +
        " if a >= b then " +
        "   redis.call('set', KEYS[1], a-b) " +
        "   return 1 " +
        " end " +
        " return 0 ";
    Object result = jedis.eval(script, Arrays.asList("product_stock_10016"), Arrays.asList("10"));
    System.out.println(result);
}

Redis哨兵高可用架构

sentinel哨兵是特殊的redis服务,不提供读写服务,主要用来监控redis实例节点。

工作原理

哨兵架构下client端第一次从哨兵找出redis的主节点,后续就直接访问redis的主节点,不会每次都通过sentinel代理访问redis的主节点,当redis的主节点发生变化,哨兵会第一时间感知到,并且将新的redis主节点通知给client端

redis哨兵架构搭建步骤
1、复制一份sentinel.conf文件
cp sentinel.conf sentinel-26379.conf
2、将相关配置修改为如下值:
port 26379
daemonize yes
pidfile "/var/run/redis-sentinel-26379.pid"
logfile "26379.log"
dir "/usr/local/redis-5.0.3/data"
# sentinel monitor    
# quorum是一个数字,指明当有多少个sentinel认为一个master失效时(值一般为:sentinel总数/2 + 1),master才算真正失效
sentinel monitor mymaster 192.168.0.60 6379 2   # mymaster这个名字随便取,客户端访问时会用到

3、启动sentinel哨兵实例
src/redis-sentinel sentinel-26379.conf

4、查看sentinel的info信息
src/redis-cli -p 26379
127.0.0.1:26379>info

哨兵的Jedis连接代码

@Test
public void sentinelDemo() {
    //哨兵的Jedis连接代码
    JedisPoolConfig config = new JedisPoolConfig();
    config.setMaxTotal(20);
    config.setMaxIdle(10);
    config.setMinIdle(5);

    Set<String> sentinels = new HashSet<>();
    sentinels.add(new HostAndPort("192.168.139.150",26379).toString());
    sentinels.add(new HostAndPort("192.168.139.150",26380).toString());
    sentinels.add(new HostAndPort("192.168.139.150",26381).toString());

    JedisSentinelPool pool = new JedisSentinelPool("mymaster", sentinels, config, 3000, null);

    Jedis resource = pool.getResource();
    resource.set("sentinelKey", "master");
    System.out.println(resource.get("sentinelKey"));

    resource.close();
}

你可能感兴趣的:(726打卡,redis,架构,java)