redis | 青训营笔记

59 阅读5分钟

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

Redis是什么

为什么需要Redis

  • 传统互联网业务是一个简单的web Server

    image.png

  • 随着数据量增长,读写数据压力不断增加,数据从单表演进出了库分表,MySQL从单机演进出了集群 image.png

  • 随着压力越来越大,像高QPS查询MySQL支撑不住,因此如果把数据存到内存中,则会加快数据IO速度

    • 经常访问的数据称为热数据
    • 热数据放在Redis中,冷数据放到MySQL中 image.png

    binlog记录MySQL数据的变更,同步Redis和MySQL只需要把binlog变更的数据写入Redis中就行

Redis基本原理

  • Redis在内存中存储数据,内存很大的问题是重启服务器数据会丢失,但是Redis的一个重要特征则是其数据一定程度上做到持久化 image.png
  • Redis是单进程处理系统 image.png

    两条命令同时到达但是顺序执行

Redis应用

  • 连续签到

    • 使用了数据的过期处理连续签到场景,即累计连续签到天数,断签则把签到天数归零
    • String数据结构
      • 数据结构学到什么程度呢?

      实际工作中应用到某个功能时能够知道为啥使用这个数据结构,为啥这个数据结构能提高性能或者压缩存储就可 image.png

    • 特点:
      • 存储时足够节省空间
      • 快速读取
      • 字符发生变更时快速写入数据
    • 实现
  • 消息通知

    image.png

    使用list作为消息队列

    • list数据结构quicklist

      image.png

      image.png

  • 计数-hash实现

    • 如下业务场景

      读取掘金文章被点赞数,如果把被点赞信息存到MySQL表中,被点赞一次存储一行记录,读取被点赞数时count该表,如该例,则需要count10693次记录,这还是一个用户需要count的数量,如果同时有100人访问,则服务压力很大 image.png 所以这些数据最好存在redis里,如果使用key来存这些数据如关注数,点赞数,阅读数等待,返回需要一个key一个key的返回,会很慢,最好能打包返回,因此使用hash image.png 如上,只需要get userid就能取出这些数据

    • 那么怎么一次性io多条数据呢-pipeline打包
    • hash数据结构 image.png

      拉链很长时,需要扩容,同时还需要保证正常响应,会触发渐进式rehash

  • 排行榜

    • 需求

      玩游戏场景,榜单上依据玩家战力排名,每个区有一个统一的榜单,用户数量是千万级别

      image.png

    • MySQl实现

      一个表存储一千万条数据,数据记录了用户的userid和积分,每次用户访问排名的时候,按照积分倒排,这种解决方案对单个用户访问没问题,但是访问的QPS很高的时候服务器就会挂了

    • Redis特别适合该业务场景实现-zset数据结构

    • skiplist

      如下链表,要取"7"则需要跳跃7次,时间复杂度是o(7)

      image.png

      有没有更快的方法?-使用跳跃表,把数据链分成许多子链

      image.png

    • redis使用了跳跃表加hash的数据结构

      image.png

      • 使用hash方便查找key
      • 跳跃表通过backward实现双向链表,backward指针指向前序节点,方便排序
      • obj指针指向hash表
  • 限流

    防止出现恶意刷单之类对网站不利的行为,要求一秒内放行的请求为N,超过N则禁止访问

    image.png

    时间戳的计数单位是秒,因此只需要统计相同时间戳内超过N的key禁止访问即可

  • 分布式锁

    要求一次只能有一个协程执行,执行完成后,其他等待中发协程才能执行

    • 场景

      考虑如下场景,秒杀业务中,产品库存为1,但是两个协程抢到了锁,因此产品被超卖

    • 实现

      使用redis的setnx,利用了

      • Redis是单线程执行命令,所有并行请求都会顺序执行
      • setnx只有在这个key未设置过的情况下才能执行成功 image.png setnx不能做成高可用的分布式锁,如:
      • 某请求某情况下很长时间无法执行完,那么后续的请求都抢不到锁
      • redis主备切换临界点问题,主备切换后,A在主库的锁写进去了,但是在从库可能还没写进去,这个时候客户端访问从库是可以拿到锁的
      • redis集群脑裂,出现多个主节点,那么也会导致并发的请求

Redis使用注意事项

  • 大key

    image.png

    • 危害

      因为redis是顺序执行的,因此io大key会导致很多问题 image.png

    • 大key处理方法
      • 拆分

        image.png

      • 压缩

        image.png

      • 使用集合类结构

        image.png

  • 热key

    image.png

    image.png

    • 处理方法
      • 设置localcache

        image.png

      • 拆分

        image.png

        风险:一个key的更新需要写多个redis实例,如果更新失败,会出现key不完整的问题

      • redis代理

        如果每个业务都实现一个localcache显然是不合理的,因此使用redis代理localcache

        image.png

        与localcache不同,其实现由proxy完成,而不是业务端

  • 慢查询

    慢查询容易导致每个实例访问速度慢,同时可能导致集群崩溃,因此需要避免慢查询

    image.png

  • 缓存传统,缓存雪崩

    image.png

    由于业务的发展,发现MySQl扛不住了,因此使用redis,如果redis服务宕机,则大量请求直接打到数据库上,出现缓存穿透,由于数据库访问很慢,则容易使数据库宕机。缓存雪崩则是大量key同时过期,即缓存失效,这时请求也会直接落到数据库中

    • 减少缓存穿透

      image.png

    • 减少缓存雪崩

      image.png