Redis随手记(一)基础与应用

date
Feb 13, 2021
slug
redis-intro
status
Published
tags
Programming
Redis
summary
type
Page
Year
2021

Redis的数据类型

  • String
  • List(列表)
    • 相当于Java中的LinkedList
    • 大多数情况下使用右进左出的队列
      • 右进右出的栈比较少用
    • 快速列表
      • 当数据比较少的时候,使用ziplist
        • ziplist使用的是一块连续的内存
          • 而普通链表使用的是不连续内存, 同时队内元素需要附加指针空间指向下一元素
      • 当数据较多时,使用quicklist
        • quicklist就是多个ziplist按照普通链表的方式组合起来
  • hash(字典)
    • 与Java的HashMap一样, 使用closed hashing
    • 不同的是Java rehash的时候使用一次性全部rehash的策略
    • 而Redis为了不阻塞服务使用渐进式rehash
      • notion image
      • 渐进式rehash会在rehash的同时保留新旧两个hash结构
      • 查询时会同时查询两个hash结构
      • 然后在后续的定时任务以及hash操作指令中将旧hash的内容迁移到新hash里
      • 当全部迁移完成后回收旧hash
  • set
    • 相当于Java里的HashSet
  • zset(有序列表)
    • 每一个value都会有一个score用以排序
      • 使用场景可以为:value(粉丝用户ID)-score(关注时间), value(学生)-score(成绩)
    • zset内部的排序功能是通过跳跃列表数据结构来实现的
      • notion image
  • list、set、hash、zset通用规则
    • create if not exist
    • drop if no elements

分布式锁

  • 使用 setnx 指令来创建key, 用 expire来防止死锁
  • set lock:codehole true ex 5 nx
    • 使用setnx和expire组合在一起的原子指令
    • 其中"lock:codehole"是key, "true"是value, "ex" -> expire, "nx" -> setnx
  • 分布式锁不能解决超时问题, 如果在加锁和释放锁之间的逻辑执行得太长, 以至于超出了锁的超时限制, 就会出现问题
  • 因此Redis分布式锁不要用于较长时间的任务

延时队列

  • redis的list数据结构常用作异步消息队列使用
    • 它可以支持多个producer和consumer并发进出消息, 每个consumer拿到的消息都是不同的列表元素
      • notion image
    • 使用阻塞读
      • 当队列空了, consumer会陷入pop的死循环
        • 这时使用 blpop/brpop
      • 阻塞读在队列没有数据的时候立刻进入休眠状态, 一旦数据来时则立刻醒过来
  • 锁冲突处理
    • 客户端在处理请求时加锁没加成功该怎么办
      • 直接抛出特定类型的异常, 通知用户稍后重试
      • sleep一会儿, 然后重试
        • sleep会阻塞当前的消息处理线程, 会导致队列后续信息处理出现延迟
        • 不建议队列消息比较多时使用
      • 将请求转移到延时队列, 过一会儿再尝试
        • 比较适合异步消息处理, 将当前冲突请求扔到另一个队列延后处理以避开冲突
  • 延时队列的实现
    • 可以通过zset实现
      • 将消息序列化成一个字符串作为zset的value, 消息的expire时间作为score, 然后用多个线程轮询zset获取到期的任务进行处理
      • 多个线程保障了可用性, 但是需要注意并发

  • 位图
  • HyperLogLog
  • Bloom Filter
  • Geohash

© wongchihaul 2021 - 2022