# 性能优化

  • Redis 的 QPS 主要受网络延迟、CPU 频率影响。
  • Redis 的读写速度很快,IO 压力小。因此没有必要读写分离,只是需要横向扩容。

# 内存

  • 相关命令:
    memory stats        # 显示内存的统计信息,指标含义见 https://redis.io/commands/memory-stats/
    memory usage <key>  # 查询一个 key 及其 value 占用的内存体积,单位 bytes
    
  • Redis 占用的内存主要受 key 影响。如果存在很多 key ,或 key、value 的长度大,则会占用很多内存。
  • 如果 Redis 的内存开销大,可通过 shell 脚本统计所有 key 的 name、占用内存、ttl ,找到哪些 key 占用内存最多。

# 缓存

当 MySQL 等数据库的读操作远多于写操作时,可以用 Redis 作为读缓存。

  • 当用户查询某个 Key 时,先到 Redis 缓存中查询,如果查询不到再到数据库查询。这样可以降低数据库的压力。
  • 如果在数据库查询到了该 key 的值,则放入缓存,并设置几分钟的过期时间。

# 部署架构

  • 本地缓存
    • :将缓存服务器与客户端部署在同一主机,甚至集成在客户端进程中。
    • 优点:响应速度很快,因为只需要读写内存,不需要等待网络 IO 。
    • 缺点:单个主机的内存容量有限。
  • 分布式缓存
    • :在客户端主机之外的其它主机上,部署一个或多个缓存服务器。
    • 优点:容易横向扩容。
    • 缺点:响应速度较慢,因为需要等待网络 IO 。
  • 多级缓存
    • :将访问频率高的 key 存储在本地缓存中,其它 key 存储在分布式缓存中。

# 缓存穿透

  • :有恶意请求不断地查询一些不存在的 key ,绕过缓存,直接冲向数据库。
  • 解决方案:
    • 即使查询到的值为空,也将该 key 放入缓存。
    • 在查询缓存之前,先过滤掉明显不正常的查询请求。

# 缓存击穿

  • :大量请求一直频繁地查询某个 key(称为热 key),当该 key 在某一时刻缓存过期时,这些请求会同时冲向数据库,造成数据库负载突增。
  • 解决方案:
    • 自动发现热 key ,并延长其过期时间。

# 缓存雪崩

  • :在某一时刻,大量 key 同时缓存过期,导致大量请求同时冲向数据库。
  • 缓存击穿是研究一个热 key ,而缓存雪崩是研究大量普通 key 。
  • 解决方案:
    • 给不同用途的各个 key 设置不同的缓存时长,给同一用途的各个 key 设置缓存时长时加上随机数,尽量分散所有 key 的缓存时间。

# redis-benchmark

:Redis 官方提供的性能测试工具, Redis 安装时自带。

命令:

redis-benchmark
               -h 127.0.0.1 # redis 服务器的 IP 地址
               -p 6379      # redis 服务器的端口号
               -a ******    # 密码

               -c 50        # 模拟连接的 client 数(默认 50 个)
               -n 100000    # 模拟发出的请求数
               -l           # 循环测试,不停止
               -d 3         # set、get 时的 value 大小(默认为 3 bytes)
               -r 10000     # 使用随机的名字创建 key
               -t set,get   # 只执行某些测试用例(默认执行所有测试用例)
               -P 10        # 使用管道,每次通信发送 10 条命令(默认每次只发送一条)
  • 例:redis-benchmark -h redis-1 -a ****** -t set,get
  • 即使用 -a 选项指定的密码是错的,redis-benchmark 也依然可以运行,且不会报错。
  • 当 -c 太少时,QPS 会比较小。当 QPS 达到瓶颈时,增加 -c 数,QPS 也不会增加。
  • 测试时会在 Redis 服务器的 0 号数据库中创建几个 key ,比如 mylistkey:__rand_int__ 等。测试完之后不会删除。
  • 使用 -r 10000 选项时,会用 10000 范围内的随机数给 key 命名,例如:key:000000000912key:000000000882 。这样测试写入 3 次,虽然会有 key 重名,但总计能创建接近 10000 个 key ,每个 key 占用的内存由 -d 选项决定。