美文网首页
redis学习笔记

redis学习笔记

作者: 一个坏人_9c31 | 来源:发表于2022-04-05 20:07 被阅读0次
    数据结构
    String (二进制安全)
    • 底层结构是array(类似与java的 ArrayList)
    • 内容小于1M时扩容是加倍现有的空间
    • 大于1M时 每次扩容1M,最大长度512M
    List
    • 元素较少时会为元素分配一块连续的内存(ziplist)
    • 元素较多时会将多个块(ziplist)组成双向链表(quicklist),块内是连续存储的(节省内存且保持插入性能)
    Set
    • 底层是通过字典(Hash表)来实现的
    Hash
    • 当field-value长度较短且个数较少时用ziplist
    • 否则使用hashtable
    Zset

    数据结构包含包含两部分

    • hash结构,用于关联value和权重score
    • 跳跃表(skiplist) ,目的在于给value排序,根据score的范围获取元素列表
    事务
    乐观锁

    redis事务的实现方式,在更新前判断有没有别的事务已经改过这个数据(版本号机制),适用于多读的情况

    redis事务的三个特性
    • 单独的隔离操作(单线程的原因,命令执行时不会因为线程调度被打断)
    • 没有隔离级别,事务被提交之前任何指令都不会被实际执行(实际上可以理解为只有串行化)
    • 不保证原子性,命令执行失败时不会回滚,不影响后续指令的执行
    持久化

    官方建议RDB与AOF同时开启(启动时优先读取AOF文件),对数据不敏感的可以只用RDB,不建议单独开启AOF

    RDB(默认开启)

    fork一个子进程,会先将数据写入一个临时文件,待持久化结束再替换上次的备份文件(写时复制技术)

    • 优点:恢复速度快,节省磁盘空间(适合大规模数据)
    • 缺点:最后一次备份后的数据可能会丢失数据(适合完整性和一致性要求不高的应用),临时文件的存在使得redis的最大占用内存只能为物理内存的一半,备份消耗性能,存在一些bug(?待了解)
    AOF(默认关闭)

    以日志的方式记录写操作(增量保存),记录redis所有执行过的写指令,只允许追加文件但不允许改写文件

    • 优点:丢失数据的概率更低,备份是可读的日志文件
    • 缺点: 占用更多的磁盘空间,备份恢复速度慢,always模式下会有性能压力,
    • 异常恢复

    redis可以对损坏的aof文件进行修复 [redis-check-aof --fix]

    • AOF 同步频率
    • appendfsync always 始终同步,每次redis写入时会立即记入日志,性能差但数据完整性好
    • appendfsync everysec 每秒钟计入日志一次,如果宕机最后一秒的数据可能丢失
    • appendfsync no redis不主动同步,把同步时机交给操作系统(原理?)
    • AOF重写压缩操作

    AOF文件持续增长过大时会fork出一条新进程来将文件重写,本质是把ADB附在AOF文件头部

    • AOF持久化流程
    • Client的写命令会被追加到AOF的缓冲区内
    • AOF缓冲区根据AOF持久化策略将操作sync到磁盘AOF文件中
    • AOF文件大小超过重写策略时,会对AOF文件rewrite,压缩AOF容量
    • 当redis服务重启的时候会重新加载AOF文件中的写操作达到数据恢复的目的
    主从复制
    全量复制

    TODO

    增量复制

    TODO

    哨兵模式
    master选举规则
    1. 选择优先级高的【redis.conf->replica-priority】
    2. 选择偏移量最大的(保证slave数据是最新的)
    3. 选择runid(redis启动时随机生成)最小的
    redis集群(无中心化集群)
    插槽(16383个)

    【CRC(key)%16384】来计算key属于哪个插槽

    故障恢复
    • 主机挂掉后,从机会作为主机提供服务
    • 如果主从都挂了,且【redis.conf->cluster-require-full-coverage】为yes,那么整个集群都挂掉
    • 如果为no,那么该段插槽全都不能使用也无法存储
    缓存
    缓存穿透

    应用服务器压力变大,redis命中率降低,一直查询数据库
    【解决方案】

    • 对空值进行缓存,对于在db中查询结果即使是不存在的数据(null)也进行缓存
    • 设置访问的名单,利用redis的bitmaps类型,名单id作为bitmaps的偏移量,每次访问时看id是否在bitmaps中,不在就不允许访问,缺点是每次都要访问bitmaps效率不高
    • 采用布隆过滤器,底层使用一个bitmaps和一系列哈希函数来检索是否在集合中,缺点是存在一定的误识别率和删除困难
    • 进行实时监控,设置黑名单限制访问
    缓存击穿

    redis中的某个key过期了,服务器压力突然增大,大量访问这个key
    【解决方案】

    • 预先设置热门数据,在redis访问高峰前提前缓存
    • 实时调整过期时间,热点数据的过期时间增大
    • 加锁,对某个不存在的key同一时刻只允许一个线程loaddb(可以利用sentnx)
    缓存雪崩

    短时间内key大量过期,数据库压力变大而崩溃
    【解决方案】

    • 多级缓存架构,nginx缓存+redis缓存+其他缓存(ehcache等)
    • 使用锁或者队列,避免大量的请求落在db上,不适合高并发
    • 设置过期标志更新缓存,缓存过期时触发另外的线程去更新缓存
    • 分散缓存失效时间,可以在缓存实现时间设置一个随机值
    分布式锁

    分布式锁的主流实现方式

    • 基于数据库实现分布式锁
    • 基于缓存(redis)实现(性能最高)
    • 基于ZooKeeper(可靠性最高)
    Redlock算法

    目标:互斥、无死锁、容错(大部分redis节点还活着就可以获取锁释放锁)
    【算法】

    1. 获取当前系统时间(ms),作为开始获取锁的时间
    2. 尝试从N个master中使用相同的Key和随机值获取锁,设置一个网络超时时间且小于锁的超时时间,避免redis挂了client还在等待
    3. client在获取到锁的时候计算:
      获取锁使用的时间=当前时间-开始获取锁的时间
      当且仅当大多数(半数以上)的redis获取到锁且获取锁的时间小于锁超时时间,锁才算获取成功
    4. 如果获取到了锁,则:
      key真正有效时间=有效时间-获取锁的时间
    5. 如果锁获取失败(重试防止脑裂),则client在所有的redis上解锁
    • 问题:

    redlock只保证了锁的高可用性,无法保证锁的正确性,例如:
    在获取锁后提交前被阻塞,锁超时失效,此时另一个线程获得锁并提交 ,那么就会发生两次提交。

    实际上作者提供了一个解决思路,client在获得锁的同时获取一个全局递增的token值,在提交时如果当前的token值小于上一次提交的token值就会被拒绝提交,看起来还是zookeeper好用

    相关文章

      网友评论

          本文标题:redis学习笔记

          本文链接:https://www.haomeiwen.com/subject/mnpcsrtx.html