批里批里 (゜-゜)つ🍺 干|

七つ一旋桜

园龄:4年2个月粉丝:6关注:3

Day17 redis | 青训营笔记

这是我参与「第五届青训营」伴学笔记创作活动的第 17 天

为什么需要redis

数据分冷热

  • 热数据:经常被访问的数据

经常访问的数据如果直接从数据库读取那么性能会非常差,因此将数据存储在内存中的redis应运而生

redis的使用分读写两种场景

  • 读场景 客户端获取后台的数据前先从redis中读取,如果redis中没有相应的数据才会去数据库中读取,数据库中社区到数据之后会将数据存入redis

  • 写场景

    数据库中的数据发生改变,redis中如果有对应的数据,redis中的数据原需要修改

    redis中的数据和mysql同步可以使用redis监听mysql的binlog来实现

基本工作原理

redis将数据存入内存会导致redis服务重启之后数据丢失,如果直接存入磁盘那么会导致redis的性能损耗

那么redis是怎么做到读写性能快,并且可以数据持久化的呢?

redis客户端对redis服务侥幸读写操作使用的是RESP协议

redis进行读写操作之前会将读写操作的日志写入磁盘中的AOF文件中

除了AOF文件,redis还会将数据存入RDB文件中,增量数据redis会存入AOF文件,全量数据redis会存入RDB文件,redis重启时会读取RDB文件

redis使用案例

  1. 连续签到

    用户每日有一次签到机会,用户断签则将用户的签到计数归0 redis可以将用户的签到次数存入redis,并且设定为次日0点过期 签到次数建议使用String数据结构

  2. 消息通知 使用list作为消息队列 list数据结构(QuickList)由一个双向链表和listpack实现

    redis中的双向链表的每个节点除了有前后指针,还包含一个listpack结构,listpack可以存储多个数据元素,每个listpack都包含一个tot-bytes表明listpack所申请的空间,以及一个num-elements代表listpack中的元素个数,listpack的末尾还有一个listpack-end-byte,限定为255,在listpack末尾占位

  3. 计数 一个用户有多项计数需求,可以使用hash结构存储 可以快速地从redis中取出多个数据

  4. 排行榜 积分变化,排名根据积分实时变更 使用zset

    redis的zskiplist层数不会超过4层

  5. 限流 要求1秒内放行的请求数为N,超过N则禁止访问 key: freq_limit_114514 (114514为时间戳) 对这个key调用自增,key的值超过N则禁止访问

  6. 分布式锁 一次只能由一个协程执行 可以用redis的setnx实现

    • redis时单线程执行
    • setnx只有未设置过才能执行成功

注意事项

大Key、热Key

大key:

数据类型大key标准
Stringvalue的字节数大于10KB
hash/set/zset/list等复杂数据类型元素个数大于5000个或总字节数大于10MB

危害:

  • 读取成本过高
  • 容易导致慢查询
  • 主从复制异常

消除大key的方法

  1. 拆分 将大key拆分为小key。例如一个String拆分为多个String
  2. 压缩 将value压缩后写入redis,读取时解压后再使用,可以使用gzip、snappy、lz4等算法压缩数据。如果使用的是json数据,那么可以使用MessagePack进行序列化
  3. 对于集合类数据结构
    • 拆分:可以用hash取余、位掩码(位掩码速度更快)的方式决定放在哪个key中
    • 区分冷热:例如表单类场景使用zset,可以只存放前10页数据,其他数据从数据库中查询

热key:

用户访问一个key的qps特别高,就会导致server出现cpu负载突增或不均

热key没有明确定义,qps超过500就有可能被识别为热key

解决方法:

  1. localcache 访问redis之前,在服务侧设置localcache,降低redis的qps(例如java的guava, golang的bigcache)

  2. 拆分

    key:value这个热key复制多分,例如拆分成key1:value key2:value,缺点是容易导致短暂的数据不一致

  3. redis代理

    本质是结合了热key发现localcache两个方功能

    客户端通过proxy访问redis,访问过程中会对key进行次数统计,如果判定一个key为热key,那么热key的数据就不再从redis中读取,而是从proxy服务的localcache读取

慢查询

  1. 使用pipeline可以进行批量操作,但是如果单批次操作超过100会导致明显的性能下降
  2. zset大部分命令是O(logn)O(log_n)的时间复杂度,当大小超过5kb以上,简单的zadd/zre操作也会导致慢查询
  3. 操作的单个value过大(应避免使用大key)

缓存穿透 缓存雪崩

缓存穿透:热点数据直接绕过查询,直接查询数据库

缓存雪崩:大量缓存同时过期

缓存穿透的危害

  1. 查询一个一定不存在的数据

    这类请求的查询会传到数据库,如果这是系统bug或人为攻击,会导致db服务异常

  2. 缓存过期 高并发场景下,热key过期会有大量的请求击穿至数据库,会导致db服务异常

    同一时间大量的key集中过期也是如此

减少缓存穿透

  1. 缓存空值 如果一个值在缓存和数据库中都不存在,则可以缓存为一个空值,下次查询直接返回空值
  2. 布隆过滤器 通过布隆过滤器存储合法的key

避免缓存雪崩

  1. 分散缓存时间

    将缓存的失效时间分开,在原有的缓存时间上增加一个随机值 对于热点数据的过期时间要尽量长一些,冷数据可以相对短一些

  2. 使用缓存集群,避免单机宕机导致雪崩

本文作者:七つ一旋桜

本文链接:https://www.cnblogs.com/poifa/p/17716910.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   七つ一旋桜  阅读(16)  评论(0编辑  收藏  举报  
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起