对 redis 性能问题的总结
前言
编写背景:
xxx 零碎因 redis 内存溢出导致现网故障,联合之前局部我的项目也用到 redis 组件且存在或多或少的问题,但都没有造成针对性的无效的剖析。思考到应用 redis 组件的我的项目越来越多,须要对 redis 进行针对性的剖析。
编写目标:
1、不便相干人员理解 redis 的作用、应用办法,能够对 redis 的我的项目中的作用有个清晰的意识
2、剖析 redis 的运行机制,对 redis 的缓存过程有个大抵认知
3、列举 redis 的长处与有余,对 redis 常遇到的问题进行粗疏剖析
4、提供性能测试过程中对 redis 的监控办法,及如何评估和设置 redis 相干参数
Redis 概述
1. 什么是 redis
Redis(REmote DIctionary Server,近程数据字典服务器)是开源的内存数据库,罕用作缓存或者音讯队列,因为该数据库是存在于零碎内存中,因而具体内存占用高,执行速度快等特点
2. Redis 的特点
a) Redis 存在于内存,应用硬盘作为长久化;每秒十万读写,执行速度快且稳固。
b) 具备丰盛的数据结构,字符串、哈希表、列表、汇合、有序汇合;提供交加、并集、差集等操作。
c) 设置 TTL 存活工夫,到期主动删除。
d) Redis 的所有操作都是原子性的,同时 Redis 还反对对几个操作全并后的原子性执行。
e) Redis 反对主从及集群。
3. Redis 在以后 Xxx 我的项目中的作用
从“Redis 的概述”中能够理解到 redis 的特点,进而对 redis 的作用有肯定理解。这里在在对 redis 的作用进行总结,以便提供一个更加清晰的意识。
Redis 是一种内存型的数据库,比 mysql 快的多,通常被用作缓存框架和音讯解决队列,可能更疾速的解决音讯。
在 XXX 零碎中,redis 是这样被应用的:零碎的业务数据依然存在 mysql 数据库中,每当一个新用户登录零碎进行查分时,会将数据从 mysql 数据库中取出并存入 redis 中,当这个用户第二次在进行查分时,会间接从 redis 中取数据,而不会在去查 mysql 数据库。因为数据曾经被缓存至 redis 库中,从 redis 中读取间接走内存,比 mysql 更快,能够防止大量查问会导致 mysql 数据库出现异常。
Redis 次要机制介绍及会带来的性能问题
这里介绍的次要机制为容易引起性能问题的机制
1. Redis 长久化
Redis 提供了两种长久化形式:1 RDB 快照形式 2 AOF 形式
1.1 RDB 长久化介绍及性能
1.1.1 RDB 长久化介绍
满足肯定条件时,会创立一个子过程,复制以后的数据,把数据写入到硬盘中某个文件,写入实现后替换原来的存储文件,用二进制压缩。数据个别存储在 dump.rdb 中。UNIX 零碎中反对写时复制,即刚开始会执行长久化写入磁盘的操作,如果此时有其余的数据产生扭转,就复制一份数据执行。
除了这种主动的快照形式,还反对命令形式长久化:
SAVE:通过阻塞的形式,用父过程来长久化,此时无奈执行其余的申请。
BGSAVE:通过 fork 子过程的形式,长久化。
RDB 形式的具体过程:
- redis 调用 fork, 当初有了子过程和父过程。2. 父过程持续解决 client 申请,子过程负责将内存内容写入到临时文件。因为 os 的写时复制机制(copy on write)父子过程会共享雷同的物理页面,当父过程解决写申请时 os 会为父过程要批改的页面创立正本,而不是写共享的页面。所以子过程的地址空间内的数据是 fork 时刻整个数据库的一个快照。3. 当子过程将快照写入临时文件结束后,用临时文件替换原来的快照文件,而后子过程退出
1.1.2 RDB 长久化带来的性能问题
问题 1 :
在保留快照时,Redis 调用 fork 产生父过程和子过程,父过程根底解决 client 的申请,而子过程则负责将内存写入临时文件。内存耗费会变成原来的两倍(具体起因与子过程的执行内容无关,不在深究)。
问题 2 :
每次快照长久化都是将内存数据残缺写入到磁盘一次,并不是增量的只同步脏数据。如果数据量大的话,而且写操作比拟多,必然会引起大量的磁盘 io 操作,可能会重大影响性能。
问题 3 :
因为快照形式是在肯定间隔时间做一次的,所以如果 redis 意外 down 掉的话,就会失落最初一次快照后的所有批改。如果利用要求不能失落任何批改的话,这种形式实现的长久化有会有问题
1.1.3 RDB 长久化性能问题解决思路
针对上述可能呈现的性能问题,通过材料收集,总结可对应的解决办法如下:
问题一,两倍内存问题:
必须保留足够的内存。对内存的估算办法:对缓存数据进行评估,预估出最大的缓存数据容量,则给 redis 预留的缓存空间至多为最大缓存数据容量的两倍
问题二,大量磁盘 IO操作:
对于数据量十分大的状况下,倡议减少 redis 服务做主从或者集群,防止大量 io 导致服务器呈现高负载的状况
问题三,最新数据失落
该问题不属于性能问题。能够通过 AOF 长久化形式解决
1.2 AOF 长久化介绍及性能
1.2.1 AOF 长久化介绍
aof 长久化是 redis 会将每一个收到的写命令都通过 write 函数追加到文件中(默认是 appendonly.aof)。当 redis 重启时会通过从新执行文件中保留的写命令来在内存中重建整个数据库的内容。AOF 长久化以日志的模式记录服务器所解决的每一个写、删除操作,查问操作不会记录.
AOF 形式的具体过程:
1. redis 调用 fork,当初有父子两个过程 2. 子过程依据内存中的数据库快照,往临时文件中写入重建数据库状态的命令 3. 父过程持续解决 client 申请,除了把写命令写入到原来的 aof 文件中。同时把收到的写命令缓存起来。这样就能保障如果子过程重写失败的话并不会出问题。4. 当子过程把快照内容写入已命令形式写到临时文件中后,子过程发信号告诉父过程。而后父过程把缓存的写命令也写入到临时文件。5. 当初父过程能够应用临时文件替换老的 aof 文件,并重命名,前面收到的写命令也开始往新的 aof 文件中追加。
1.2.2 AOF 长久化的性能问题
问题 1 :
追加 log 文件可能导致体积过大,当零碎重启复原数据时如果是 aof 的形式则加载数据会十分慢,会导致这个期间 Redis 的读写性能会大幅降落
问题 2 :
追加 log 的频率不同,对磁盘 IO 的影响也不同,在性能方面的体现也不一样。配置读写频率能够通过一个配置文件进行更改,须要联合服务器理论的内存、数据量等因素进行评估比拟正当的形式
问题 3 :
如果一直的将写指令记录到 AOF 的日志文件中,那么文件体积会越来越大,势必会产生很多冗余。
1.2.2 AOF 长久化性能问题解决
针对问题 1 ,大数据量下复原零碎,会导致数据加载迟缓
大数据量只能通过负载或者集群来解决。
针对问题 2 :如何正当的配置写文件的频率,具体参考下列配置阐明
appendonly yes #启用 aof 长久化形式
appendfsync always #每次收到写命令就立刻强制写入磁盘,最慢的,然而保障齐全的长久化,不举荐应用
appendfsync everysec #每秒钟强制写入磁盘一次,在性能和长久化方面做了很好的折中,举荐
appendfsync no #齐全依赖 os,性能最好, 长久化没保障
针对问题3:须要触发 AOF 的 rewrite 操作,对 AOF 的文件进行重写,替换原来的文件
Redis 触发 AOF rewrite 机制有三种:
1、Redis Server 接管到客户端发送的 BGREWRITEAOF 指令申请,如果以后 AOF/RDB 数据长久化没有在执行,那么执行,反之,等以后 AOF/RDB 数据长久化完结后执行 AOF rewrite
2、在 Redis 配置文件 redis.conf 中,用户设置了 auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size 参数,并且以后 AOF 文件大小 server.aof_current_size 大于 auto-aof-rewrite-min-size(server.aof_rewrite_min_size),同时 AOF 文件大小的增长率大于 auto-aof-rewrite-percentage(server.aof_rewrite_perc)时,会主动触发 AOF rewrite
3、用户设置“config set appendonly yes”开启 AOF 的时,调用 startAppendOnly 函数会触发 rewrite
1.3 Redis 长久化总结
以下内容为网上原文,解释 redis的内存占用:
Redis 在物理内存应用比拟多,但还没有超过理论物理内存总容量 时就会产生不稳固甚至解体的问题,有人认为是基于快照形式长久化的 fork 零碎调用造成内存占用加倍而导致的,这种观点是不精确的,因为 fork 调用的 copy-on-write 机制是基于操作系统页这个单位的,也就是只有有写入的脏页会被复制,然而个别你的零碎不会在短时间内所有的页都产生了写入而导致复制,那么是什么起因导致 Redis 解体的呢?
答案是 Redis 的长久化应用了 Buffer IO 造成的,所谓 Buffer IO 是指 Redis 对长久化文件的写入和读取操作都会应用物理内存的 Page Cache,而大多数数据库系统会应用 Direct IO来绕过这层 Page Cache并自行保护一个数据的 Cache,而当 Redis 的长久化文件过大 (尤其是快照文件),并对其进行读写时,磁盘文件中的数据都会被加载到物理内存中作为操作系统对该文件的一层 Cache, 而这层 Cache的数据与 Redis内存中治理的数据理论是反复存储的 ,尽管内核在物理内存缓和时会做 Page Cache 的剔除工作,但内核很可能认为某块 Page Cache 更重要,而让你的过程开始 Swap , 这时你的零碎就会开始呈现不稳固或者解体了。咱们的教训是当你的 Redis 物理内存应用超过内存总容量的 3 / 5 时就会开始比拟危险了。(Redis 自身会有一个 page cache ,然而数据库不应用这个 cache并自行保护一个 cache)
总结:
u 依据业务须要抉择适合的数据类型,并为不同的利用场景设置相应的紧凑存储参数。
u 当业务场景不须要数据长久化时,敞开所有的长久化形式能够获得最佳的性能以及最大的内存使用量。
u 如果须要应用长久化,依据是否能够容忍重启失落局部数据在快照形式与语句追加形式之间抉择其一,不要应用虚拟内存以及 diskstore 形式。
u 不要让你的 Redis 所在机器物理内存应用超过理论内存总量的3/5。
2. Redis 的音讯队列
2.1 音讯队列介绍
Redis 用于音讯队列,通常有两种应用形式:
LIST:基于列表的形式,所有的消费者数据加起来是列表中的所有数据.
公布 / 订阅:每个消费者订阅独立的 channel, 每个数据都是独立的
2.2 用 redis 的 list 当作队列可能存在的问题
1) redis 解体的时候队列性能生效
2) 如果入队端始终在塞数据,而出队端没有生产数据,或者是入队的频率大而多,出队端的生产频率慢会导致内存暴涨
3) Redis 的队列也能够像 rabbitmq 那样 即能够做音讯的长久化,也能够不做音讯的长久化。当做长久话的时候,须要启动 redis 的 dump 数据的性能. 临时不倡议开启长久化。Redis 其实只适宜作为缓存,而不是数据库或是存储。
4) 如果有多个消费者同时监听一个队列,其中一个出队了一个元素,另一个则获取不到该元素
5) Redis 的队列利用场景是一对多或者一对一的关系,即有多个入队端,然而只有一个生产端(出队)
3. Redis 的虚拟内存
3.1 虚拟内存介绍
因为服务器的内存是无限的,且内存容量小于磁盘容量,且联合用户的应用习惯,个别只有少部分的数据是用户常常会用到的,基于以上两点状况,redis 采纳虚拟内存技术来将不常应用的数据存入磁盘中,将常常用到的数据保留在无限的内存中,一旦磁盘中的数据须要读取时,能够在将须要读取的数据从磁盘中读入内存中,从而达到既节俭内存空间,又能提供效率的目标,这就是 redis 的虚拟内存技术
然而值得注意的有两点:
1) Redis 没有应用 Linux 提供的虚拟内存机制,它是实现了本人的虚拟内存机制
2) 通过查阅材料,redis 的虚拟内存技术并不是很成熟稳固
3.2 虚拟内存易引起的性能问题
Redis 减少虚拟内存个性自身目标是为了解决 redis 耗内存所带来的性能问题的,然而因为 redis 的虚拟内存当初不是很成熟,redis 默认敞开虚拟内存,须要手动去开启,然而在 redis 的虚拟内存技术稳固之前不倡议开启。
Redis 性能测试自测办法
redis 性能测试的根本命令如下:redis-benchmark [option] [option value]
如应用一个参数来测试性能:
同时执行 10000 个申请来检测性能:redis-benchmark -n 10000
应用了多个参数来测试 redis 性能:
redis-benchmark -h 127.0.0.1 -p 6379 -t set,lpush -n 10000 –q
redis 性能测试工具可选参数如下所示:
序号
选项
形容
默认值
1
-h
指定服务器主机名
127.0.0.1
2
-p
指定服务器端口
6379
3
-s
指定服务器 socket
4
-c
指定并发连接数
50
5
-n
指定申请数
10000
6
-d
以字节的模式指定 SET/GET 值的数据大小
2
7
-k
1=keep alive 0=reconnect
1
8
-r
SET/GET/INCR 应用随机 key, SADD 应用随机值
9
-P
通过管道传输 <numreq> 申请
1
10
-q
强制退出 redis。仅显示 query/sec 值
11
–csv
以 CSV 格局输入
12
-l
生成循环,永恒执行测试
13
-t
仅运行以逗号分隔的测试命令列表。
14
-I
Idle 模式。仅关上 N 个 idle 连贯并期待。
Redis 罕用的优化办法
1、针对虚拟内存的优化
vm-enabled=no
敞开 Redis 的虚拟内存性能,并不成熟。
2、针对长久化的优化
(1) Master 最好不要做任何长久化工作,如 RDB 内存快照和 AOF 日志文件
(2) 如果数据比拟重要,不倡议在 Master 开长久化设置,能够在 Slave 开启 AOF 备份数据,策略设置为每秒同步一次
3、针对主从的优化
(1) 为了主从复制的速度和连贯的稳定性,Master 和 Slave 最好在同一个局域网内
(2) 尽量避免在压力很大的主库上减少从库
(3) 主从复制不要用图状构造,用单向链表构造更为稳固,即:Master <- Slave1 <- Slave2 <- Slave3…(这样的构造不便解决单点故障问题,实现 Slave 对 Master 的替换。如果 Master 挂了,能够立即启用 Slave1 做 Master,其余不变)
4、应用场景考量
(1)redis 因为是将数据存入内存,因为该个性,redis 以后不适宜做大容量数据的缓存机制,否则容易导致内存故障
(2)redis 的数据类型考量是否正当,如 string、list 等
(3)长久化形式考量、是否须要主从等
5、限度 redis内存大小
(1) 通过 redis 的 info 命令查看内存应用状况
如果不设置 maxmemory 或者设置为 0,64 位零碎不限度内存,32 位零碎最多应用 3GB 内存。
批改配置文件中的 maxmemory 和 maxmemory-policy
- maxmemory:最大内存
- maxmemory-policy:内存不足时, 数据革除策略
6、批改 linux中 TCP 监听的最大包容数量
在高并发环境下你须要一个高 backlog 值来防止慢客户端连贯问题。留神 Linux 内核默默地将这个值减小到 /proc/sys/net/core/somaxconn 的值,所以须要确认增大 somaxconn 和 tcp_max_syn_backlog 两个值来达到想要的成果。
办法:echo 511 > /proc/sys/net/core/somaxconn
留神:这个参数并不是限度 redis 的最大链接数。如果想限度 redis 的最大连接数须要批改 maxclients,默认最大连接数为 10000。
7、敞开 Transparent Huge Pages(THP)
THP 会造成内存锁影响 redis 性能,倡议敞开
Transparent HugePages:用来进步内存治理的性能
Transparent Huge Pages 在 32 位的 RHEL 6 中是不反对的
应用 root 用户执行上面命令
echo never > /sys/kernel/mm/transparent_hugepage/enabled
Redis 其余异样事件实例参考
事件一:Redis 开启 AOF 导致的删库事件
事变具体过程:
http://www.cnblogs.com/wangxin37/p/7084410.html
事件二:redis 的延时问题及长久化造成的阻塞
事件具体过程
http://www.cnblogs.com/me115/p/5032177.html
Redis 性能测试留神点
对我的项目进行性能测试时,须要重点关注 redis 的内存应用状况,目前已遇到的 redis 性能问题根本都是与内存无关
监控内存的办法:
1、linux 零碎自带的监控命令,如 top、free、vmstat 等
2、其余资源监控工具,如:nmon
3、针对 redis,有本人的一套内存监控:Redis-cli 命令行查看相干 info 信息
Redis 自带组件监控应用办法
因为无论是 linux 零碎自带的内存监控命令,还是 nmon 监控工具,都是针对零碎级别的监控,这里重点介绍 redis 组件本身带的监控工具。
redis-cli 是根本的 redis 查问工具,如果没有更改 redis 端口,能够间接通过运行 redis-cli
进入该工具命令行,如图:
能够输出 dbsize 查看 redis 的 key 值数量,如:
应用 info 命令查看 redis 能够查看的信息,如图:
info 命令输入的数据可分为 10 个类别,别离是:
Ø server
Ø clients
Ø memory
Ø persistence
Ø stats
Ø replication
Ø cpu
Ø commandstats
Ø cluster
Ø keyspace
咱们重点关注其中容易引起性能问题的 memory 和 stats 选项。
1、能够通过输出:info memory 来间接查看 memory 相干信息
咱们针对上述要害指标进行剖析:
· used_memory 字段数据表示的是:由 Redis 分配器调配的内存总量,以字节(byte)为单位。其中 used_memory_human 上的数据和 used_memory 是一样的值,它的单位是 M
留神:used_memory 是 Redis 应用的内存总量,它蕴含了理论缓存占用的内存和 Redis 本身运行所占用的内存(如元数据、lua)。它是由 Redis 应用内存分配器调配的内存,所以这个数据并没有把内存碎片节约掉的内存给统计进去。
其余字段代表的含意,都以字节为单位:
· used_memory_rss:从操作系统上显示曾经调配的内存总量。
· mem_fragmentation_ratio:内存碎片率。
备注:mem_fragmentation_ratio = used_memory_rss/used_memory. mem_fragmentation_ratio 介于 1~1.5 之间是失常的,阐明内存碎片率比拟低。如果大于 1.5 则阐明 Redis 耗费了理论须要物理内存的 150%,其中 50% 是内存碎片率。若是内存碎片率低于 1 的话,阐明 Redis 内存调配超出了物理内存,操作系统正在进行内存替换。内存替换会引起非常明显的响应提早
· used_memory_lua:Lua 脚本引擎所应用的内存大小。
· mem_allocator:在编译时指定的 Redis 应用的内存分配器,能够是 libc、jemalloc、tcmalloc。
异样阐明:通过查看 used_memory 指标可晓得 Redis 正在应用的内存状况,如果 used_memory> 可用最大内存,那就阐明 Redis 实例正在进行内存替换或者曾经内存替换结束。管理员依据这个状况,执行绝对应的应急措施
2、能够通过输出:info stats 来间接查看 stats 相干信息
这外面须要重点关注 total_commands_processed 字段,它显示了 Redis 服务解决命令的总数,total_commands_processed 字段的值是递增的。
备注:在 Redis 实例中,跟踪命令解决总数是解决响应提早问题最要害的局部,因为 Redis 是个单线程模型,客户端过去的命令是依照程序执行的。比拟常见的提早是带宽,通过千兆网卡的提早大概有 200μs。假使显著看到命令的响应工夫变慢,提早高于 200μs,那可能是 Redis 命令队列里期待解决的命令数量比拟多。如上所述,延迟时间减少导致响应工夫变慢可能是因为一个或多个慢命令引起的,这时能够看到每秒命令解决数在显著降落,甚至于前面的命令齐全被阻塞,导致 Redis 性能升高。要剖析解决这个性能问题,须要跟踪命令解决数的数量和延迟时间。
3、上述 total_commands_processed 的介绍中波及了延迟时间的概念,那么如何查看延迟时间呢,能够用 Redis-cli 工具加 –latency 参数运行,如 redis-cli –latency -h 127.0.0.1 6379
其 host 和 port 是 Redis 实例的 ip 及端口。因为以后服务器不同的运行状况,延迟时间可能有所误差,通常 1G 网卡的延迟时间是 200μs。
以毫秒为单位测量 Redis 的响应延迟时间,我本机的提早是 90μs。
备注:
因为 redis 的命令是程序执行的,一旦呈现慢命令,其余命令必须等慢命令执行结束后能力继续执行,因而在 total_commands_processed 和延迟时间上会有体现,一旦确定是性能问题后,能够通过以下两个办法进行剖析:
l 应用 slowlog 查出引发提早的慢命令。Redis 中的 slowlog 命令能够让咱们疾速定位到那些超出指定执行工夫的慢命令,默认状况下命令若是执行工夫超过 10ms 就会被记录到日志。应用办法:在 Redis-cli 工具,输出 slowlog get 命令查看
图中字段别离意思是:
² 1= 日志的惟一标识符
² 2= 被记录命令的执行工夫点,以 UNIX 工夫戳格局示意
² 3= 查问执行工夫,以微秒为单位。例子中命令应用 54 毫秒。
² 4= 执行的命令,以数组的模式排列。残缺命令是前面几个命令的组合。
l 监控客户端的连贯:
因为 Redis 是单线程模型(只能应用单核),来解决所有客户端的申请,但因为客户端连接数的增长,解决申请的线程资源开始升高调配给单个客户端连贯的解决工夫,这时每个客户端须要破费更多的工夫去期待 Redis 共享服务的响应。这种状况下监控客户端连接数是十分重要的,因为客户端创立连接数的数量可能超出预期的数量,也可能是客户端端没有无效的开释连贯。
应用办法:在 Redis-cli 工具中输出 info clients,如
上图中,第一个字段 (connected_clients) 显示以后实例客户端连贯的总数。Redis 默认容许客户端连贯的最大数量是 10000。若是看到连接数超过 5000 以上,那可能会影响 Redis 的性能
Redis 常见问题收集
redis overcommit memory(oom)问题
什么是 overcommit memory(oom)
Linux 零碎中,要运行某个程序时,都会先申请内存,然而内存申请后零碎并不是马上就运行,两头有一段时间距离,这种技术就是 overcommit。当零碎发现内存不够调配时就会产生 out of memory 报错,即简称 OOM,这时零碎会抉择杀死一些过程以开释内存,即为 OOM killer。
问题景象:redis 运行一段时间后挂掉了,ps 查看过程没有问题,查看 redis 的 log 后发现存在 warning
[26145] 07 Dec 19:54:54 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add ‘vm.overcommit_memory = 1’ to /etc/sysctl.conf and then reboot or run the command ‘sysctl vm.overcommit_memory=1’ for this to take effect.
查看 redis 端口,发现端口不通(端口查看:telnet,查看端口 lsof -i:6379)
查看相干材料,理解报错中所波及的参数含意。参数 overcommit_memory 是内核参数,用来调整零碎的内存调配策略:
overcommit_memory= 0 示意零碎在分配内存前将查看内存是否够用,内存足够则容许调配,内存不足则返回正告信息给利用
overcommit_memory=1 示意容许调配所有物理内存,而不对内存状态做查看
overcommit_memory=2 示意容许调配超过所有物理内存加替换区间内存总和的内存
上述问题景象的解决办法:
1,批改内核参数(3 种办法,任选其一)
(1)编辑 /etc/sysctl.conf,改 vm.overcommit_memory=1,而后 sysctl -p 使配置文件失效
(2)sysctl vm.overcommit_memory=1
(3)echo 1 > /proc/sys/vm/overcommit_memory
2,批改 redis.conf, 而后重启 redis
maxmemory 5368709120
maxmemory-policy allkeys-lru
maxmemory-samples 3
设置一下 maxmemory,倡议设置为物理内存的 1 / 2 到 3 /4,大小不要超过最大物理内存。
附录:
1、redis 优化文章举荐:
http://www.cnblogs.com/jandis…