Redis最佳实践 | 青训营
- 为什么需要Redis
- MySQL从单机演进成了集群
- Redis放到内存里 先去Redis访问看看在不在 不在去mysql找
- 写 先写mysql 再写入redis
- 增量数据 AOF文件 全量数据 RDB文件
- Redis是单进程处理所有命令
- 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集群脑裂 导致出现多个节点 ---可以再去详细了解了解
- 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存不存在
- 缓存雪崩:大量的缓存同时过期
- 讲缓冲失效时间分散开,比如在原有失效时间的基础上增加一个随机值
- 热点数据过期的时间设置的长 冷门数据设置的短
- 使用缓冲集成 避免单机宕机