Go_Redis

  • content {:toc}

基础知识

1 什么是 Redis

  • redis是内存数据库、key-value 数据库、以及 数据结构数据库
  • Redis 单线程指的是「接收客户端请求 -> 解析请求 -> 进行数据读写等操作 -> 发送数据给客户端」, 但是 redis 程序不是单线程的, redis 在启动的时候,是会启动后台线程

Redis 是一种基于内存的数据库,对数据的读写操作都是在内存中完成,因此读写速度非常快,常用于缓存,消息队列、分布式锁等场景

Redis 提供了多种数据类型来支持不同的业务场景,比如 String (字符串)、Hash (哈希)、 List (列表)、Set (集合)、Zset (有序集合)、Bitmaps(位图)、HyperLogLog(基数统计)、GEO(地理信息)、Stream(流),并且对数据类型的操作都是原子性的,因为执行命令由单线程负责的,不存在并发竞争的问题。

除此之外,Redis 还支持事务 、持久化、Lua 脚本、多种集群方案(主从复制模式、哨兵模式、切片机群模式)、发布 / 订阅模式,内存淘汰机制、过期删除机制等等

  • redis内存中的数据与redis磁盘一一对应
  • mysql有少部分热数据以及索引在mysql缓冲池
结构类型 结构存储的值 结构的读写能力
String字符串 可以是字符串、整数或浮点数 对整个字符串或字符串的一部分进行操作:对整数或浮点数进行自增或自减操作
List列表 一个链表,链表上的每个节点都包含一个字符串 对链表的两端进行push和pop操作,读取单个或多个元素:根据值查找或除元素
Set集合 包含宇符串的无序集合 字符串的集合,包含基础的方法有看是否存在添加、获取、删除:还包合计算交集、并集、差集等
Hash散列 包含键值对的无序散列表 包含方法有添加、获取、删除单个元素
Zset有序集合 和散列一样,用于存储键值对 字符串成员与浮点数分数之间的有序映射:元素的排列顺序由分数的大小决定:包含方法有添加、获取、删除单个元素以及根据分值范围或成员来获取元素

2 安装 Redis

3 什么是 QPS

  • QPS(Queries Per Second)是一种衡量系统处理能力和性能的度量单位,表示每秒钟能够处理的查询请求数量。
  • QPS 通常用于衡量数据库、网络服务器、Web 服务、缓存系统等对查询请求的处理速度。它表示在每秒的时间间隔内,系统能够处理的平均请求数量。QPS 的值越大,说明系统的处理能力越强。
  • QPS 的计算方式是根据一段时间内的请求数量来进行统计。例如,如果一个系统在 1 秒钟内处理了 100 个查询请求,那么它的 QPS 就是 100。
  • 需要注意的是,QPS 仅仅是衡量系统在某一时刻或时间段内的瞬时处理能力,它并不能全面反映系统的性能。还有其他指标如响应时间、并发数等也需要综合考虑,以全面评估系统的性能。
  • QPS 的具体值会受到多种因素的影响,包括硬件配置、网络带宽、查询复杂度、系统负载等。因此,针对不同的应用场景和需求,对 QPS 的要求也不同。
  • 总之,QPS 是衡量系统查询处理能力的重要指标,用于评估系统的性能和稳定性。

redis基本工作原理

  • 数据从内存中读写
  • 数据保存到硬盘上防止重启数据丢失
    • 增量数据保存到AOF文件
    • 全量数据RDB文件
  • 单线程处理所有操作命令 ( 顺序执行 )

应用场景

连续签到

  • 设计一个 包含日期的 key, value 为 天数, 然后设置过期时间

消息通知

  • 例如当文章更新时,将更新后的文章推送到ES, 用户就能搜索到最新的文章数据

排行榜

  • 积分要变化时, 排名要实时变更

mysql 中

  • userid + 积分, 对积分进行排序

限流

  • 要求1秒内放行的请求为N, 超过N则禁止访问

key中有时间戳, 对这个Key调用incr,超过限制N则禁止访问

分布式锁

  • 并发场景,要求一次只能有一个协程执行.
  • 执行完成后, 其它等待中的协程才能执行.

可以使用redis的setnx实现,利用了两个特性

  • Redis是单线程执行命令
  • setnx只有未设置过才能执行成功

不是高可用的分布式锁实现, 该实现存在的问题:

  • (1)业务超时解锁, 导致并发问题. => 业务执行时间超过锁超时时间
  • (2)redis主备切换临界点问题.主备切换后,A持有的锁还未同步到新的主节点时, B可在新主节点获取锁, 导致并发问题,
  • (3)redis集群脑裂,导致出现多个主节点

pipeline

  • 一次设置多个 key, 减少网络传输

rehash:rehash操作是将ht[0]中的数据,全部迁移到ht[1]中.数据量小的场景下直接将数据从ht[0]拷贝到ht[1]速度是较快的.数据量大的场景,例如存有上百万的KV时,迁移过程将会明显阻塞用户请求

渐进式rehash: 为避免出现这种情况,使用了rehash方案.基本原理就是,每次用户访问时都会迁移少量数据.将整个迁移过程, 平摊到所有的访问用不请求过程中.

2.2 list

  • List 列表是简单的字符串列表,按照插入顺序排序,(这不是就是队列的特性) 可以从头部或尾部向 List 列表添加元素。列表的最大长度为 2^32 - 1,也即每个列表支持超过 40 亿个元素。
  • List 类型的底层数据结构是由双向链表或压缩列表实现的:
  • 但是在 Redis 3.2 版本之后,List 数据类型底层数据结构就只由 quicklist 实现了,替代了双向链表和压缩列表
  • quicklist 每个节点都有很多数据, 结点内每个数据的大小相等的

问题

大 key

大Key的危害

  • 读取成本高
  • 容易导致慢查询(过期、删除)
  • 主从复制异常,服务阻塞无法正常响应请求

业务侧使用大Key的表现

  • 请求Redis超时报错

消除 大 key方法

  • 拆分, 将大key拆分为小key. 例如一个String拆分成多个String\
  • 压缩, 将value压缩后写入redis, 读取时解压后再使用.
  • 集合类结构hash、list、set、set (1)拆分:可以用hash取余、位掩码的方式决定放在哪个key中 (2)区分冷热: 如榜单列表场景使用zset, 只缓存前10页数据, 后续数据走db, ( 只关心第一名, 后面的人不关心 )

热Key的定义

  • 用户访问一个Key的QPS特别高,导致Server实例出现CPU负载突增或者不均的情况.
  • 热key没有明确的标准, QPS超过500 就有可能被识别为热Key

设置Localcache

  • 在访问Redis前,在业务服务侧设置Localcache, 降低访问 Redis 的 QPS. LocalCache中缓存过期或未命中,则从Redis中将数据更新到LocalCache.Java的Guava、Golang的Bigcache就是这类LocalCache

拆分

  • 将key:value这一个热Key复制写入多份, 例如key1:value,key2:value, 访问的时候访问多个key, 但value是同一个以此将 qps 分散到不同实例上, 降低负载 .代价是, 更新时需要更新多个key, 存在数据短暂不一致的风险

解决热Key的方法2.使用Redis代理的热Key承载能力字节跳动的Redis访问代理就具备热Key承载能力.本质上是结合了"热Key发现"、“LocalCache"两个功能

慢查询

导致慢查询的操作

  • 批量操作一次性传入过多的key/value,如mset/hmset/sadd/zadd等O(n)操作建议单批次不要超过100,超过100之后性能下降明显.
  • zset大部分命令都是O(log(n)),当大小超过5k以上时,简单的zadd/zrem也可能导致慢查询
  • 操作的单个value过大,超过10KB.也即,避免使用大Key
  • 对大key的delete/expire操作也可能导致慢查询,Redis4.0之前不支持异步删除unlink,大key删除会阻塞Redis

缓存穿透、缓存雪崩

缓存穿透:热点数据查询绕过缓存,直接查询数据库

缓存雪崩:大量缓存同时过期

缓存穿透

  • 查询一个一定不存在的数据通常不会缓存不存在的数据,这类查询请求都会直接打到db,如果有系统bug或人为攻击,那么容易导致db响应慢甚至宕机

如何减少缓存穿透

  • (1)缓存空值 如一个不存在的userlD.这个id在缓存和数据库中都不存在.则可以缓存一个空值,下次再查缓存直接反空值.
  • (2)布隆过滤器通过 bloom filter 算法来存储合法 Key, 得益于该算法超高的压缩率, 只需占用极小的空间就能存储大量 key 值

如何避免缓存雪崩

  • 1)缓存空值将缓存失效时间分散开,比如在原有的失效时间基础上增加一个随机值, 例如不同Key过期时间可以设置为10分1秒过期,10分23秒过期,10分8秒过期.单位秒部分就是随机时间,这样过期时间就分散了对于热点数据,过期时间尽量设置得长一些,冷门的数据可以相对设置过期时间短一些.
  • 2)使用缓存集群,避免单机宕机造成的缓存雪崩.
Licensed under CC BY-NC-SA 4.0
最后更新于 Oct 13, 2024 18:49 +0800
使用 Hugo 构建
主题 StackJimmy 设计