Redis最佳实践 | 青训营

78 阅读4分钟
  1. 为什么需要Redis
    • MySQL从单机演进成了集群
    • Redis放到内存里 先去Redis访问看看在不在 不在去mysql找
    • 写 先写mysql 再写入redis
    • 增量数据 AOF文件 全量数据 RDB文件
    • Redis是单进程处理所有命令
  2. Redis具体应用
    • 1 连续签到 string
      • 四个字段 len alloc flags buf
      • 指针指向flags和buf之间
      • buf会额外分配空间
      • alloc就是分配了的空间
      • len是实际使用的空间
    • 2 消息通知 list ex04_list.go
      • Quicklist 双向链表和 listpack实现
      • 双向链表每一个实体都是listpack
      • 会在一个节点存几个数据(listpack)
      • num-elements记录元素数 tot_bytes得到listbytes的长度
    • 3 计数
      • 点赞 阅读 关注 关注者 收藏 可以存redis
      • 使用hash key 为user_count_ID 值为结构体 所有的count数据打包
      • rehash 哈希表要扩容 但是也要保证业务
      • 再开一张哈希表 所以每次用户请求时 扩容一部分数据 等扩容完毕时 改变原哈希表的指针
    • 4 排行榜
      • zset数据结构 zskiplist 跳表 内部的数据域是是哈希实现的 键值对
      • 这部分确实不熟悉 当时ck看了一点点 没有实现过
    • 5 限流 要求1s放行的请求为N 超过N禁止访问
      • 用秒级时间戳作键 每次看该秒的访问量有没有超限
    • 6 分布式锁 --用在 秒杀问题里
      • Redis是单线程 这是保证setnx成功的关键 没有redis内部枪锁
      • setnx只有未设置过才能执行成功
      • 存在的问题 Ex02不能实现高可用的分布式锁实现
      • 1 业务超时问题 抢到锁的不释放 其他会饿死 ---可以设置业务超时(主动释放)
      • 2 存在主备切换临界点问题 A获取了主节点 切换时还未同步 B获取新主节点的锁
      • 3 redis集群脑裂 导致出现多个节点 ---可以再去详细了解了解
  3. Redis使用注意事件
    • 大Key
      • String value的字节数大于10KB
      • Hash/Set/Zset/list 元素个数大于5000 Value大于10MB
      • 危害:
        • 读取成本高
        • 容易导致慢查询(过期 删除)
        • 主从复制异常,服务阻塞,无法响应正常请求
        • 业务侧的表现:请求Redis超时报错
      • 消除方法
        • 拆分 大Key拆小key
        • 压缩(首选) 压缩写入 redis 读取再解压后 压缩算法:gzip snappy lz4
        • 通常 压缩率高 解压时间长 需要选择合适的算法
        • redis重点考虑解压时间 因为redis多用于写少读多的场景
        • 如果存的JSON字符串 可以考虑使用MessagePack 进行序列化
        • 集合类结构
        • 区分冷热(常用):榜单类场景使用zset 只缓存前10页数据 后续数据走db
        • 拆分之后 可以用hash取余 位掩码决定放哪个key里
    • 热Key QPS大概超过500 出现CPU负载突增的情况
      • Redis集群 可能会出现一台机子负载很高 其他的很低
      • 解决:
        • 设置Localcache 就是业务侧的内存本机的内存 不用通过网络再去访问rediis
        • 设置localcache 过期时间 例如两秒 2s同步一次
        • Golang的 Bigcache Java的Guava
        • 拆分 复制热key的value到不同的redis实例上 key1:value key2:value...
        • 访问的时候访问多个key 降低负载 但需要更新多个 存在数据不一致的风险
        • 字节内部使用Redis代理的热key承载能力
    • 慢查询
      • 一次性传入过多的key/value 如mset/hmset/sadd/zadd等O(n)操作 建议单批次不要超过100 超过100之后性能下降明显 还要pipeline
      • zset大部分命令是O(logn) 大小不要超过5K
      • 操作的单个value超过10KB
      • 大KEY的delete /expire也会
    • 缓冲穿透:热点数据的查询绕过缓存 直接查询数据库 redis宕机
      • 危害:
      • 查询一个一定不存在的key 系统bug或者人为攻击会导致db慢甚至宕机
      • 热key过期 大量key集中过期
      • 解决:
      • 缓冲空值 当空值缓冲和数据库都不存在 可以缓冲空值
      • 布隆过滤器 使用bloom filter算法来存储合法key 先问key存不存在
    • 缓存雪崩:大量的缓存同时过期
      • 讲缓冲失效时间分散开,比如在原有失效时间的基础上增加一个随机值
      • 热点数据过期的时间设置的长 冷门数据设置的短
      • 使用缓冲集成 避免单机宕机