Redis详解|青训营笔记

76 阅读5分钟

Redis|青训营笔记

这是我参与【第五届青训营】伴学笔记创作活动的第15天。

一、重点知识

  • redis的简介,内存/硬盘
  • 应用案例:典型数据结构
  • redis可能发生的问题,解决方法

二、详细知识点

1. Redis简介

1.1 为何需要Redis

  • 数据从单表演进出分库分表
  • MySQL从单机演进出集群
    • 数据量增长:数据更多
    • 读写数据压力不断增加
    • MySQL无法应对压力
  • 数据分冷热:热数据经常被访问
  • 因此将热数据放在内存中会减轻磁盘读取压力
    • 先检查内存中是否存在
    • 若miss,去数据库读取
    • 读取的数据写入redis中

1.2 工作原理

  • 数据从内存中读写
  • 数据保存到硬盘上防止重启数据丢失
    • 增量数据保存到AOF文件
    • 全量数据保存到RDB文件
  • 单线程处理所有操作命令

2. Redis应用案例

2.1 连续签到

  • key:uid; value:252; expireAt:23:59:59
  • 设置过期
  • String数据结构
    • sds
    • 可以存储字符串、数字、二进制数据
      • 需要节省空间
      • 需要很快的写入和读取
    • 通常和expire配合使用
    • 场景:存储计数、session

2.2 消息通知

  • 用list作为消息队列
  • 使用场景::消息通知,文章更新后将更新的文章推送到ES
  • 可以用消息队列或pub和sub
  • list数据结构
    • 监听链表头部pop
    • 用户推送push进入list
    • 实现一个队列
    • quicklist
      • 双向链表
      • listpack:一个节点上有大量的数据(LinkedArrayList)
        • 通过读total byte获得长度
        • 通过读num-elements获得数量
        • 之后为值
        • 定长+变长

2.3 计数

  • 多项计数需求,可以通过hash结构存储
  • 每个数据使用一个key来读取,即hash
  • hash数据结构
    • 使用的时hash表+链表结构
    • 扩容时需要rehash
    • rehash:将ht[0]中的数据全部迁移到ht[1]中;数据量小时就很快,但数据量大时会明显阻塞用户请求
    • 渐进式rehash:为避免出现这种情况,使用了rehash方案,基本原理就是每次用户访问时都会迁移少量数据,整个迁移的过程平摊到所有访问请求过程。

2.4 排行榜

  • 积分变化时排名实时变更
  • 结合dict后可以实现通过key操作跳表的功能
  • zset数据结构 zskiplist
    • 查找数字路径 head 3,3,7
    • 将数据分成多条子链
    • redis时跳跃表+hash

2.5 限流

  • 一秒内放行请求为N,超过则禁止访问
  • 对key调用incr,超过N则禁止访问
  • 构建key+当前时间戳,当后续时间戳大于前置时间戳时停止访问

2.6 分布式锁

  • 并发场景要求一次只有一个协程执行
  • 执行完成后其他等待的才能开始执行
  • redis的setnx实现
    • redis是单线程执行命令
    • setnx只有未设置过才能成功

3.Redis使用注意事项

3.1 大Key

  • 大Key标准
    • String:value字节大于10kb
    • hash/set/Zset/list等:元素个数大于5000,或总字节大于10MB
  • 大Key危害
    • 读取成本高
    • 容易导致慢查询(过期、删除)
    • 主从复制异常,服务阻塞无法正常响应请求
  • 业务侧使用大key表现
    • 请求redis超时报错
  • 消除大key的方法
    • 拆分:将大key拆分为小key,例如一个String拆成多个String
      • prefix通知当前拆分量
    • 压缩
      • 将value压缩后写入redis,读取是解压后再使用
      • 压缩算法:gzip、snappy、lz4
      • 一个压缩算法压缩率高,解压耗时长
      • 需要对实际数据测试后选择合适算法
      • JSON:MessagePack序列化
    • 集合类结构
      • 拆分:hash取余,位掩码方式决定放在哪个key中
      • 区分冷热:榜单列表场景使用zset只缓存前10页数据,后续数据走db

3.2 热key

  • 定义
    • 用户访问一个key的qps特别高
    • server出现CPU负载突增或不均情况
    • 没有明确标准,qps超过500则为热key
  • 解决方法
    • 设置localcache:在业务服务侧设置localcache,降低访问redis的qps,localcache缓存过期或未命中则从redis中将数据更新到localcache
      • java:Guava
    • 拆分:将KV这个热key复制写入多份,K1V, K2V,访问时候访问多个key以此将qps分散到不同实例上降低负载;但是更新时需要更新多个key,存在数据不一致风险
    • 使用Redis的代理热key承载能力:使用redis代理,具备热key承载能力,结合了热key发现,localcache两个功能;proxy统计一个key在一定时间内读取的次数,如果发现热key则存到proxy的localcache;

3.3 慢查询

  • 容易导致的操作
    • 批量操作:一次传入过多的KV,如批量加入,不要单批超过100
    • zset大小不要超过5k
    • 单个value过大 大key
    • 对大key的删除和过期会阻塞redis

3.4 缓存穿透

  • 缓存穿透:热点数据查询绕过缓存直接查询数据库
  • 缓存穿透危害
    • 查询一个一定不存在的数据:通常不会缓存不存在的数据,请求直接打到db,容易导致db响应慢、宕机;
    • 缓存过期时:高并发场景下一个热key如果过期会大量请求击穿至db,影响db
    • 同一时间大量key过期时也会导致大量请求落到db上
  • 减少缓存穿透
    • 缓存空值:如一个不存在的值,缓存一个空值下次再查询直接返回空
    • bloomfilter:存储合法key

3.5 缓存雪崩

  • 缓存雪崩:大量缓存同时过期
  • 避免方法
    • 缓存空值:将缓存失效时间分散开,在原有时间基础上加随机值;热门时间过期时间长一点,冷漠短一点
    • 使用缓存集群。

三、个人总结

今天主要学习了redis的实际应用,以及各种数据结构的底层逻辑;最后介绍了redis的问题以及解决方法。课程是从比较抽象的角度进行讲解,需要结合代码进一步理解。