AOF append only file

    记录命令,而非数据
    后写日志,不阻塞当前操作,但阻塞下次操作,主线程写回磁盘文件,有可能丢最后一条命令日志
    写回策略
    always(同步/高可靠/对性能有一定影响) 每条命令立刻写回磁盘
    everysec(推荐使用) 先存在内存缓冲区 每秒写一次到磁盘
    no(高性能) 由操作系统决定什么时候从缓冲区到磁盘文件
    AOF文件过大问题
    AOF重写,将操作同一个数据的多条命令缩减为一条以减少文件大小
    主线程fork一个子进程,同时备份一份最新的数据在内存,然后该进程根据该份数据进行重写日志编写(只记录数据的写入操作,就比记录全部命令小很多)
    同时,主线程还是正常写入AOF日志,并且记录拷贝数据之后的写入记录到AOF重写日志
    上面两个步骤结合,就能保证最新的(主线程保证)最全的(子进程+主线程保证)写入记录是有的,且没有多余的操作记录,然后用重写日志替换(写会磁盘时做)原有全部操作记录的AOF日志就达到了减少AOF体积的目的

    RDB RedisDataBase 内存快照

    采用全量数据的快照
    bgsave 默认,fork出子进程执行快照操作不阻塞主线程
    save 阻塞方式

    使用写时复制(Copy-on-write COW),解决子线程做快照时主线程不能执行写操作(此时执行写会破坏快照的正确性)的问题
    做快照的过程中,如果主线程有写入操作,先行拷贝原值供子进程做快照,主线程照常执行
    为了解决,快照间隔过短(时间足够短才能降低丢失数据)加之全量数据过大导致的,
    1. 频繁fork导致主线程性能下降
    在适当长时间的做快照
    2. 连续写磁盘压力过大问题。
    两次 快照之间只为修改了的数据(使用多余的1/4空间记录修改)做快照,但因该多余的修改记录带来了内存开销
    Redis 4.0 提出 RDB AOF混合,两次快照之间的数据修改使用AOF记录(如果此中间宕机了可以使用AOF,且非全量数据的AOF避免了重写机制的开销),
    快照方式依然是全量(RDB保证了恢复的效率)

    数据结构

    数据类型
    String Hash Set SortedSet List
    底层数据结构
    动态字符串 双向链表 压缩列表 跳表 hash表 整数数组
    全局使用 hash表查询 key
    使用两个全局hash表,渐进式rehash进行扩容
    使用拉链法解决hash冲突
    开放定址法(线性探索法)遇到冲突,顺序向数组末尾继续查找直到有空位填充

    缓存一致性问题

    Redis中有,数据库必须一致。Redis中没有,数据库必须是最新的。
    Redis的作用分为:
    读写缓存(对redis执行读和增删改操作)
    同步直写(事务操作,写入Redis同个事务写入DB),采用此法即可
    异步写回(删Redis才会写回DB,若此时Redis故障,出现不一致)
    只读缓存(只会读,没读到从DB加载,增删改直操DB并标记Redis过期)
    新增数据,直写DB无一致性问题
    删改,因不保证操作DB和Redis是同事务,加上并发情况,出现不一致
    1、因DB和Redis两步操作有失败出现不一致,使用消息队列等重试机制
    e13f86cd46ab6bd51568afb8179b7eaa.jpg

    2、因两步操作并发导致出现不一致,使用延时双删(DB完成后, sleep另一个线程的操作时间再删一次redis)
    缓存雪崩 (大量崩溃)
    大量数据同时过期导致,数据库压力剧增
    过期时间加随机
    暂停服务等待恢复,核心继续走库,服务降级
    缓存击穿(热点被打穿了)
    部分数据(热点数据),被并发访问,数据库压力剧增
    热点不过期
    缓存穿透(直接穿过了)
    大量请求获取redis和数据库都不存在的数据,库压力剧增
    类似恶意请求,解决办法
    布隆过滤器(3个hash函数+bit数组)
    经过函数计算得到的三个位置不是全部为true,则数据不存在
    前端过滤,幂等性接口

    原子操作的实现

    • INCR 原子加1,DNCR 原子减1单命令,复杂情况下不可用
    • Lua脚本,多命令原子执行

      // eval 执行, args参数
      redis-cli —eval lua.script keys , args
      分布式锁实现
      单命令实现
      // setnx 存在key则不做操作,没有则创建并设为value
      SETNX lock_key value
      DEL lock_key
      为防止出现有客户端出现不 DEL锁的情况,加入过期时间。防止出现误释放,value设为唯一标识
      SET lock_key unique_value NX PX 1000
      DEL时使用Lua脚本来判断是否是本客户端加的锁,是则可释放

    高可靠多节点锁 RedLock

    多个节点,有半数以上节点加锁成功则认为加锁成功,否则失败,如此即使有个别节点有问题还有其他节点提供锁支持
    步骤:
    客户端记录加锁开始时间
    向N个Redis节点 发起加锁命令(key, unique_value,过期时间)
    客户端接收返回并判断
    加锁耗时是否超过了过期时间,业务操作耗时是否会大于过期时间
    有N/2个节点加锁成功,否 开始释放锁操作
    客户端使用Lua脚本向N个实例发送释放操作

    印象笔记,让记忆永存。
    下载印象笔记