您的位置:首页 > 数据库 > Redis

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

2019-04-16 20:09 961 查看

持久化

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

RDB

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

dump.rdb

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

      配置的规则:

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

    1. save 或 bgsave 命令: 执行快照同步操作, 注意

      save
      这个操作会暂时阻塞客户端请求.
      bgsave
      则不会阻塞

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

    3. 执行复制:

  • 快照原理

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

  • 快照的优缺点:

      缺点: 可能会丢失数据, 在下一次快照前宕机
    1. 优点: 最大化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
    可以查看信息.

  • 实现原理:

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

      基于rdb文件复制
    1. 无硬盘复制 配置
      rpli-diskless-sync yes
    2. 增量复制 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 算法, 取得的结果与槽数取模.落入的槽的索引是固定的. 然后根据节点数将槽的范围确定到每个节点上.

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

  • 三方方案

      redis shardding : jedis支持
    1. codis : 代理, 分片和数据迁移自动化
    2. 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秒内不查询数据库
}
}
}
}
  • 使用

    ReentrantLock
    tryLock()
    ,else中线程等待一段时间, 这样不阻塞进程

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

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐