Redis | 青训营笔记

197 阅读5分钟

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

Redis 是什么

为什么需要Redis

随着互联网业务场景的发展,对系统QPS的要求越来越高,系统架构从原来的单机数据库,发展到数据库主从集群(主服务器写,从服务器读)。

到最后提出把常用的数据放在内存中,需要的时候直接读取。

于是,就诞生了内存数据库,Redis。

特性

  • 单线程处理所有操作命令。

数据结构

String 数据结构

Hash 数据结构

List 数据结构

Set 数据结构

Zset 数据结构

Redis 基本原理

架构

持久化实现

image.png

  1. 客户端输入 Redis 命令,会通过RESP协议发送指令到 redis 服务端。
  2. 服务端的服务进程接收到读写命令后,会将数据读写到内存中
  3. 如果是写操作,在写入之前,会追加一条写命令到 AOF 文件(循环写入,最新的会覆盖最久的)中。
  4. 如果发生宕机操作,首先会从 RDB 文件(全量备份,一般每隔5分钟同步一次)中恢复原来数据。
  5. 再读取 AOF 文件,如果发现有没有执行的 AOF 日志,就执行来同步数据。

应用场景

连续签到

使用 string 数据类型

消息通知

技术

排行榜

限流

分布式锁

Redis 使用注意事项

大Key

大Key标准

  • string类型
    • value 的字节数大于10KB即为大key
  • Hash/Set/Zset/list等复杂数据结构
    • 元素个数大于5000个或总value字节数大于10MB即为大Key。

大Key危害

原因

redis 是单线程程序所有命令,所以没处理完大key,其他命令都不能处理,会被阻塞掉。

总结

  • 读取成本高

  • 容易导致慢查询(过期、删除)

  • 主从复制异常,服务阻塞。

    • 主节点数据需要同步给从节点,对于大key,消耗大量网络资源、CPU资源。
  • 访问缓存数据超时

怎么解决大key

KV 数据结构

拆分

image.png

将一个大key拆分为小key。

如图,将 article:70011 拆分为 article:70011、article:70011_2、article:70011_3。 其中第一个 key 的值的前缀 [3] 代表key被拆分成了三份,并紧跟id [70011]。

这样,就可以推断出拆分后的两个 key 的名字。

最后将结果拼接就可以得到原来的数据。

缺点

  • 拼接数据这个逻辑太复杂了(维护多个key,拼接数据)。
  • 解析[3] 这个字符消耗大量时间。

压缩

将 value 压缩后再存入 key,读取的时候解压缩。

性能优化

  1. 选择合适的解压算法,由于读取的时间比较多,所以更关注解压性能,可以写入100key,然后反解压出来,看消耗时间。

  2. json 字符串可以尝试 MessagePack

集合数据结构hash、list、set、zset

拆分

可以 hash 取余,将 key 分配到新的数据结构中。

比如 hash 得到 0、1,就可将得到0的,分到一个集合,结果为1的,分配到另一个集合。

区分冷热

像排行榜这种业务场景,可以使用 zset 只存前十页的数据,其他的数据,访问去数据库读取。

这样就可以减少 key 存储的数据量。

热 key

定义

一个 key 保存的数据大量被访问,如果此时 redis 做了分区,那么大量的流量就会打到集群的某一台机器上。

机器承载不住,就会出现问题。

QPS一般大于500的 Key,可以被称作热Key,没有固定标准。

热 key 会导致 CPU 负载突增或者不均的情况。

解决方案

Localcache

image.png

从 redis 中读取数据后,放到 JVM 或者 Golang 服务器的缓存中,下次再有相同的访问请求时,可以直接从本机读取,也就是本地缓存。

本地缓存可以承载比分布式缓存更大的压力,更高的QPS。

本地缓存通过缓存过期管理、缓存分片技术。

缓存过期管理会给本地缓存设置过期时间,一旦过期后,立马去 redis 里更新缓存。

拆分

image.png

对于一个热 Key,将这个 Key 拆分成多个 Key,数据分成多份进行存储。

这样做,原本只访问集群中一台服务器的请求,现在会访问到集群中多台服务器,实现了对高 qps 请求的负载均衡。

但这样做可能会导致,更新 key 的时候,多台服务器必须都更新成功,否则就会出现数据不一致的问题。这需要大量代码逻辑维护。

字节跳动实现 --使用 redis 代理的热 Key 承载能力

image.png

客户端所有的 redis Get 请求都会先发给 Proxy 服务器,由 Proxy 服务器将请求转发给 Redis 服务器执行。

Proxy 服务器会统计 Redis 中每个 Key 执行的次数,一旦达到某个阈值,比如500,就会将这个定义为热 Key。

Proxy 服务器就会将这个键值对保存在本机的本地缓存中。

下次再有请求访问时,直接返回,就实现了对热 Key 的处理逻辑。

慢查询

容易导致 redis 慢查询的操作

  • 一次性传入过多的 key/value,一般规定单批次不要超过100个。
  • zset 大部分命令都是o(log(n)),当大小超过5K以上时,普通的zadd、zrem 也可能导致慢查询。
  • key 的单个 value 过大,超过10KB。
  • 对大 key 的 delete/expire 操作也可能导致慢查询。

缓存穿透

简介

请求的 key 在redis,大量请求直接访问到数据库,可能会导致服务器宕机。

解决方案

  • 缓存空值
  • 布隆过滤器

缓存雪崩

简介

缓存在同一时间大量过期,就是缓存雪崩。

解决方案

  • 缓存设置过期时间时在原有时间基础上加上随机值。
  • 使用集群,避免单机宕机导致缓存雪崩。