Redis基础使用(四)——缓存优化

1. 如何查看Redis性能

info命令输出的数据可以分为10个分类,分别是:

server,clients,memory,persistence,stats,replication,cpu,commandstats,cluster,keyspace

为了快速定位并解决性能问题,我们选取其中几个作为参考:

redis:6379> info memory
"# Memory
used_memory:31590440
used_memory_human:30.13M
used_memory_rss:38260736
used_memory_rss_human:36.49M
used_memory_peak:31625024
used_memory_peak_human:30.16M
used_memory_peak_perc:99.89%
used_memory_overhead:9672728
used_memory_startup:862392
used_memory_dataset:21917712
used_memory_dataset_perc:71.33%
allocator_allocated:31686224
allocator_active:32690176
allocator_resident:35946496
total_system_memory:16585785344
total_system_memory_human:15.45G
used_memory_lua:37888
used_memory_vm_eval:37888
used_memory_lua_human:37.00K
used_memory_scripts_eval:0
number_of_cached_scripts:0
number_of_functions:0
number_of_libraries:0
used_memory_vm_functions:37888
used_memory_vm_total:75776
used_memory_vm_total_human:74.00K
used_memory_functions:184
used_memory_scripts:184
used_memory_scripts_human:184B
maxmemory:4294967296
maxmemory_human:4.00G
maxmemory_policy:allkeys-lru
allocator_frag_ratio:1.03
allocator_frag_bytes:1003952
allocator_rss_ratio:1.10
allocator_rss_bytes:3256320
rss_overhead_ratio:1.06
rss_overhead_bytes:2314240
mem_fragmentation_ratio:1.21
mem_fragmentation_bytes:6650024
mem_not_counted_for_evict:0
mem_replication_backlog:0
mem_total_replication_buffers:0
mem_clients_slaves:0
mem_clients_normal:24072
mem_cluster_links:0
mem_aof_buffer:0
mem_allocator:jemalloc-5.2.1
active_defrag_running:0
lazyfree_pending_objects:0
lazyfreed_objects:0
"

used_memory是Redis使用的内存总量,包含了实际缓存占用的内存和Redis自身运行所占用的内存。used_memory_rss:从操作系统上显示已经分配的内存总量。maxmemory最大内存容量。

1.1 内存交换引起的性能问题

如果Redis使用的内存超过了最大可用内存,那么操作系统开始进行内存与swap空间交换,这时Redis和依赖Redis上数据的应用会受到严重的性能影响,所以通过查看used_memory指标可知道Redis的性能情况;

运行过程中触发RDB功能时,Redis会fork一个子进程把当前内存中的数据完全复制一份写入到硬盘上,若当前使用内存超过可用内存的45%,就会触发内存交换,大量频繁的更新操作,可能会加剧性能下降。

1.2 命令处理数

redis:6379> info stats
"# Stats
total_connections_received:395
total_commands_processed:530848
instantaneous_ops_per_sec:3
total_net_input_bytes:41630627
total_net_output_bytes:12904524
instantaneous_input_kbps:0.22
instantaneous_output_kbps:0.02
rejected_connections:0
total_reads_processed:531868
total_writes_processed:531477
io_threaded_reads_processed:0
io_threaded_writes_processed:0
reply_buffer_shrinks:1729
reply_buffer_expands:1356
"

Redis是单线程模型,客户端发送过来的命令会按照顺序执行,通过total_connections_received获取命令数量,如果命令处理总数处于上升或下降状态,那么可能是有2个原因引起的:

  • 命令队列里的命令数量过多,后面命令一直在等待中
  • 前面慢命令阻塞Redis

解决办法有:

  • 通过单命令多参数的形式取代多命令单参数的形式,减少命令发送的数量,页减小网络交互;
  • 管道命令,把几个命令合并一起执行,减少因网络开销引起的延迟问题;
  • 避免操作大集合的慢命令;

1.3 延迟时间

Redis的延迟数据是无法从info信息中获取的,可以用 Redis-cli工具加 --latency参数运行。

redis-cli -h 127.0.0.1 -p 6379 --latency

该命令会统计三个延迟指标:最小值(min),最大值(max)和平均值(avg),单位是ms。如果发现延迟较大,有一些方法可以定位延迟出现的情况:

  • 确保没有执行慢指令(慢指令会导致Redis服务阻塞),可以使用 slowlog 查看,具体:https://redis.io/commands/slowlog
  • 关闭内核Transparent huge pages:echo never > /sys/kernel/mm/transparent_hugepage/enabled(需要重启Redis服务)
  • 测试固有延迟(如果固有延迟已经较大,可能是操作系统负载较高或性能不佳)
  • 使用Redis的Latency Monitoring功能监测延迟情况,具体:https://redis.io/topics/latency-monitor

1.4 客户端连接数

redis:6379> info clients
"# Clients
connected_clients:2
cluster_connections:0
maxclients:10000
client_recent_max_input_buffer:20480
client_recent_max_output_buffer:0
blocked_clients:0
tracking_clients:0
clients_in_timeout_table:0
"

Redis默认允许客户端连接的最大数量是10000,但是连接数过大会对性能影响较大;自Redis2.6以后,允许在配置文件(Redis.conf)maxclients属性上修改客户端连接的最大数,也可以通过在Redis-cli工具上输入config set maxclients 去设置最大连接数。

1.5 内存碎片率

在info中通过mem_fragmentation_ratio = used_memory_rss/used_memory,如果内存碎片率超过1.5,那可能是操作系统或Redis实例中内存管理变差的表现。解决方法:

  • 重启Redis服务器:额外碎片的产生是由于Redis释放了内存块,但内存分配器并没有返回内存给操作系统,这个内存分配器是在编译时指定的,可以是libc、jemalloc或者tcmalloc。重启Redis服务器可以让额外产生的内存碎片失效并重新作为新内存来使用。
  • 限制内存交换: 如果内存碎片率低于1,Redis实例可能会把部分数据交换到硬盘上。内存交换会严重影响Redis的性能,所以应该增加可用物理内存或减少实Redis内存占用。
  • 修改内存分配器:Redis支持glibc’s malloc、jemalloc11、tcmalloc几种不同的内存分配器,每个分配器在内存分配和碎片上都有不同的实现。不建议修改Redis默认内存分配器。

2. 缓存应用优化

2.1 缓存穿透

缓存穿透是指查询缓存中一个不存在的数据,请求直接访问到数据库服务。大量的恶意请求会导致存储层压力过大而崩溃。解决方案:

  • 缓存空对象:第一次请求缓存和DB都没有,就存个空对象到缓存里面。但如果大批量的恶意请求过来,这样做就会导致缓存的key暴增,显然不是一个很好的方案。
  • 布隆过滤器:请求通过布隆过滤器过滤,当布隆过滤器说某个值存在时,这个值可能不存在;但是它说不存在时,那就肯定不存在。

2.2 缓存失效

大批量的key同时失效,导致大量请求同时打向数据库,造成数据库压力过大,甚至直接挂掉。解决方案是失效时间随机化,可以是一个固定时间+随机时间方式来生成,更加保险的方案可以加分布式锁,拿到锁的才去访问数据库。

2.3 缓存雪崩

缓存雪崩是指缓存层挂掉之后,所有请求都打向数据库,数据库扛不住挂掉,导致对应的服务也挂掉,从而影响整个链路服务雪崩挂掉。解决方案:

  • 保证缓存层的高可用性,可参考:Redis高可用方案_西木风落的博客-CSDN博客。
  • 服务做限流、熔断,降级等,避免雪崩出现,比如Hystrix.

2.4 缓存一致性

引入缓存后,并发请求可能导致缓存中的数据就会与db数据不一致。如果先更新缓存,然后更新DB失败,那么下一个请求过来读取的缓存数据不是最新的。如果先更新db再更新缓存,更新DB时的请求读取数据是缓存的旧值。

保障缓存一致性可采用方案:加锁——淘汰缓存——更新DB——重新刷进缓存

3. Redis使用优化

3.1 消除bigKey

Redis中一个字符串最大512MB,一个二级数据结构(如hash、list、set、zset)可以存储大约40亿个(2^32-1)个元素,但实际中如果满足下面两种情况,就认为它是bigkey。

  • 单个key对应的value超过10kb就是bigkey。
  • 非字符串类型:哈希、列表、集合、有序集合,元素个数太多。

bigkey的坏处:

  • 占用带宽大,容易造成网络堵塞。假设一个key的value大小为1M,有1000个连接并发,1s所占用的带宽就是1000M,而千兆网卡是 128M/s。
  • redis命令堵塞,单线程处理bigkey有可能造成其他连接排队。

一般来说,string类型控制在10KB以内,hash、list、set、zset元素个数不要超过5000(超过5000了可以采用分拆思想)

3.2 优化的一些建议

  • 尽量使用短的key:短key减少网络消耗,对于value有些也可精简,比如性别使用0、1。
  • 避免使用keys *: keys *命令是阻塞的,数据量大会严重影响性能,可以使用SCAN代替。
  • Redis数据存储压缩:redis为每种数据类型都提供了两种内部编码方式,在不同的情况下redis会自动调整合适的编码方式。
  • 设置key有效期:失效key及时清除,减小内存消耗占用
  • 选择合适回收策略:Redis 基本知识_西木风落的博客-CSDN博客
  • 使用管道替代多次命令交互;
  • SLOWLOG优化
  • 配置合适的持久化方案

4. 服务器配置优化

  • 修改linuxTCP监听的最大容纳数量

在高并发环境下你需要一个高backlog值来避免慢客户端连接问题。注意Linux内核默默地将这个值减小到/proc/sys/net/core/somaxconn的值,所以需要确认增大somaxconn和tcp_max_syn_backlog两个值来达到想要的效果。

  • 修改linux内核内存分配策略

redis在备份数据的时候,会fork出一个子进程,理论上child进程所占用的内存和parent是一样的,比如parent占用的内存为8G,这个时候也要同样分配8G的内存给child,如果内存无法负担,往往会造成redis服务器的down机或者IO负载过高,效率下降。所以内存分配策略应该设置为 1(表示内核允许分配所有的物理内存,而不管当前的内存状态如何)。
内存分配策略有三种
可选值:0、1、2。
0, 表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。
1, 不管需要多少内存,都允许申请。
2, 只允许分配物理内存和交换内存的大小(交换内存一般是物理内存的一半)。

  • 修改Transparent Huge Pages(THP)的相关配置

Linux kernel 在2.6.38内核增加了 THP 特性,支持大内存页(2MB)分配,默认开启。当开启时可以降低 fork 子进程的速度,但 fork 操作之后,每个内存页从原来 4KB 变为 2MB,会大幅增加重写期间父进程内存消耗。同时每次写命令引起的复制内存页单位放大了512倍,会拖慢写操作的执行时间,导致大量写操作慢查询。


参考连接:https://blog.csdn.net/qq_39399966/article/details/101211939

 关于redis性能问题分析和优化 - 踏雪无痕SS - 博客园

你可能感兴趣的:(redis,redis性能调优,Redis,bigKey,redis,缓存一致性,内存碎片化)