对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形式的具体过程:

  1. 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

  1. maxmemory:最大内存
  2. 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是个单线程模型,客户端过去的命令是依照程序执行的。比拟常见的提早是带宽,通过千兆网卡的提早大概有200s。假使显著看到命令的响应工夫变慢,提早高于200s,那可能是Redis命令队列里期待解决的命令数量比拟多。 如上所述,延迟时间减少导致响应工夫变慢可能是因为一个或多个慢命令引起的,这时能够看到每秒命令解决数在显著降落,甚至于前面的命令齐全被阻塞,导致Redis性能升高。要剖析解决这个性能问题,须要跟踪命令解决数的数量和延迟时间。

3、上述total_commands_processed的介绍中波及了延迟时间的概念,那么如何查看延迟时间呢,能够用Redis-cli工具加--latency参数运行,如redis-cli --latency -h 127.0.0.1 6379

其host和port是Redis实例的ip及端口。因为以后服务器不同的运行状况,延迟时间可能有所误差,通常1G网卡的延迟时间是200s。

以毫秒为单位测量Redis的响应延迟时间,我本机的提早是90s。

备注:

因为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...