• 分布式系列十二: Redis高级主题


    持久化

    Redis 支持持久化, 其持久化数据有两种方式. 两种可以同时使用. 如果同时使用, Reids 在重启时将使用 AOF 方式来还原数据.

    RDB

    按照一定策略定时同步内存的数据到磁盘.文件名 dump.rdb

    • snapshot: 快照复制. Redis在指定情况下触发快照: (1) 按配置的规则;(2) save 或 bgsave 命令执行;(3) flushall 命令; (4)执行复制

      1. 配置的规则: save seconds exchange 当在 seconds 指定的时间内, key 的数量更改大于 exchange 时发生快照.

      2. save 或 bgsave 命令: 执行快照同步操作, 注意save这个操作会暂时阻塞客户端请求. bgsave则不会阻塞

      3. flushall: 清除内存所有数据, 只要规则不为空, redis就会执行快照

      4. 执行复制:

    • 快照原理

      fork 复制一份当前进程的副本, 这个进程是子进程, 负责同步持久化到磁盘. 而父进程负责处理客户端请求.

    • 快照的优缺点:

      1. 缺点: 可能会丢失数据, 在下一次快照前宕机
      2. 优点: 最大化Redis的性能, 父子进程职责分离

    AOF

    保存命令到磁盘, 也就是持久化日志.

    • 配置: appendonly yes 启动aof. 默认的文件名是 appendonly.aof.

    • 配置 auto-aof-rewrite-percentage 100 当 aof 文件与上一次文件的大小相比, 超过配置的百分比就进行重写

    • 配置 auto-aof-rewrite-min-size 64m 限制允许重写最小 aof 文件大小, 即小于64m时不重写

    • aof 重写原理: aof 重写是安全的. 相当于同时将命令追加到现有的aof文件, 同时写入新的 aof 临时文件, 临时文件最终将覆盖原 aof 文件.

    • 同步磁盘数据: aof机制会将命令记录到aof文件, 但实际是同步到操作系统的缓存区, 最终由操作系统同步到磁盘. 可以通过下面配置修改策略
      appendsync always 每次执行写入就同步, 安全但影响性能
      appendsync everysec 每一秒执行
      appendsync no 不执行同步, 由操作系统去执行, 效率高但不安全

    • aof 文件损坏后的修复, 使用redis-check-aof-fix

    集群

    master/slave 复制

    主从方式, 从是只读的, slave也可以有自己的slave.

    • slave节点上配置 slaveof masterip masterport

    • 配置 slave-serve-stale-data no 可以用来保证数据同步后再做其他操作

    • 命令info replication可以查看信息.

    • 实现原理:

      1. slave 连接到 master 后, 会向 master 发送 SYNC 命令.
      2. master 收到命令后, 会做两件事(1) 执行bgsave;(2)master 将收到的修改命令存入缓冲区, 再将命令传输给slave
    • 复制方式:

      1. 基于rdb文件复制
      2. 无硬盘复制 配置rpli-diskless-sync yes
      3. 增量复制 PSYNC master run id. offset
    • 命令replconf listening-port 6379可以用来查看复制过程

    • 缺点: 无法做master选举

    sentinale 哨兵模式

    1. 监控
    2. master选举
    • 配置文件为sentinel.conf

    • 配置节点: sentinel monitor mymaster 192,168,11,111 6379 2 最后的2为投票数

    • 是高可用方案, 但不是高性能方案

    集群

    • 原理

      Reids有slot槽的概念: redis中有16384个. 根据key的 CRC16 算法, 取得的结果与槽数取模.落入的槽的索引是固定的. 然后根据节点数将槽的范围确定到每个节点上.

      当节点新增和删除时, 节点的槽范围发生变化, 数据迁移需要人工干预.

    • 三方方案

      1. redis shardding : jedis支持
      2. codis : 代理, 分片和数据迁移自动化
      3. twemproxy :

    缓存穿透问题

    • 数据库中不存在的对象查询后也缓存.
    if(objJson!=null){
        redisService.expire("key",timeout:3*60);
    } else {
        redisService.expire("key",timeout:5); //5秒内不查询数据库
    }
    
    • synchronized 方法, 不理想, 排队影响性能.
    • 同步块, 需要双重判定, 否则阻塞的线程均会查询数据库, 代码如下
    String value = redisService.get("key");
    if(value==null){
        synchronized(lock){
            value = redisService.get("key"); //多线程再次查询,防止数据库多次查询
            if(value==null){
                value = dao.get();
                redisService.set("key",value);
                if(objJson!=null){
                    redisService.expire("key",timeout:3*60);
                } else {
                    redisService.expire("key",timeout:5); //5秒内不查询数据库
                }
            }
        }
    }
    
    • 使用ReentrantLocktryLock(),else中线程等待一段时间, 这样不阻塞进程

    • 使用分布式锁

    if(redisService.setNx("key")==true){
        //查询数据库
    }
    
    • 不设超时时间或设置一个较长的超时时间, 然后判断当前时间是否超过缓存时间, 结合分布式锁, 超过则刷新缓存. 此解决方法可能会发生少量数据不一致的情况.

    采用何种策略需要结合实际需求, 是保证可用, 还是保证一致性? 对于一致性要求不高的场景, 可能最后一种方案可以彻底解决击穿问题. 对于一致性要求较高的场景, 使用同步/锁的方式会更好.

  • 相关阅读:
    使用扩展运算符实现数组,对象的深拷贝
    将图片文件转成BASE64格式
    怎么让input默认为0
    两次取反的意义
    css世界一
    Q&H
    .gitignore 中添加.vscode 无效
    百度小程序
    定位元素和opacity
    js 设置元素样式
  • 原文地址:https://www.cnblogs.com/walkinhalo/p/10719688.html
Copyright © 2020-2023  润新知