Redis | 青训营笔记

147 阅读4分钟

Redis | 青训营笔记

这是我参与「第五届青训营 」伴学笔记创作活动的第 16 天,主要记录相关的知识点。

本堂课重点内容

  • redis相关概念

为什么需要redis

首先我们的数据存在冷数据和热数据

  • 热数据:经常被访问的数据
  • 冷数据:不会被经常访问的数据

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

redis常常在读写的基本场景下使用

  • 读场景:客户端获取后台的数据前先从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:字节数过大(10KB)的字符串,或复杂数据结构组成的集合,容易导致读取成本过高,慢查询,主从复制异常等问题。

消除大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读取使用大key)

个人总结

本次课程主要学习了:

  • Redis相关的一些应用场景