欢迎您的光临,本博所发布之文章皆为作者亲测通过,如有错误,欢迎通过各种方式指正。

文摘  Redis性能问题分析和优化经验

Redis 本站 1169 0评论

一、优化详解


1.数据持久化


· 选择恰当的持久化方式。Redis提供RDB和AOF两种持久化方式。用户需要根据实际场景对两种持久化方式进行考量和选择。 RDB会在一定时间间隔内一次性将内存中的所有数据刷到磁盘上,非增量。它的一个主要缺点是如果Redis宕机了,那么可能会造成部分数据丢失,丢失的数据两和RDB持久化的时间间隔有关。此外,如果数据集非常大,Redis在创建子进程时可能会消耗相对较长的时间,这期间客户端请求都会被阻塞。这种情况下我们可以关闭自动保存,通过手动发送SAVE或者BGSAVE命令来控制停顿出现的时间。由于SAVE命令不需要创建子进程,从而避免了与子进程的资源竞争,因此它比BGSAVE速度更快。手动生成快照可以选择在线用户很少的情况下执行,比如使用脚本在凌晨三点执行SAVE命令。 

从上述内容可以看出,RDB适用于即使丢失部分数据也不会造成问题的场景。同时我们需要注意快照是否生成得过于频繁或者稀少。 AOF持久化会将被执行的命令追加到AOF文件末尾。在redis.conf中该功能默认是关闭的,设置appendonly yes以开启该功能。这种方式会对磁盘进行大量写入,因此Redis处理命令的速度会受到硬盘性能的限制。并且AOF文件通常比RDB文件更大,数据恢复速度比RDB慢,性能消耗也比RDB高。由于它记录的是实际执行的命令,所以也易读。为了兼顾写入性能和数据安全,可以在配置文件设置appendfsysnc everysec。并不推荐appendfsync no选项,因为这种方式是由操作系统决定何时对AOF文件进行写入。在缓冲区被待写入硬盘的数据填满时,可能造成Redis的写入操作被阻塞,严重影响性能。


· 重写AOF文件。如果用户开启了AOF功能,Redis运行时间越长,`AOF文件也会越来越大。用户可以发送BGREWRITEAOF重写AOF文件,它会移除AOF文件中的冗余命令以此来减小AOF文件的体积。由于AOF文件重写会用到子进程,因此也存在BGSAVE`命令持久化快照时因为创建子进程而导致的性能问题和内存占用问题。除了使用命令重写AOF文件,也可以在配置文件中配置,以让Redis自动执行重写命令。

#当aof文件体积大于64mb且比上次重写之后的体积增大了至少一倍

auto-aof-rewrite-percentage 100 

auto-aof-rewrite-min-size 64mb


2.内存优化


· 设置maxmemory。设置Redis使用的最大物理内存,即Redis在占用maxmemory大小的内存之后就开始拒绝后续的写入请求,该参数可以确保Redis因为使用了大量内存严重影响速度或者发生OOM。此外,可以使用info命令查看Redis占用的内存及其它信息。


· 让键名保持简短。键的长度越长,Redis需要存储的数据也就越多


· 使用短结构。这节主要谈谈Redis的list、hash、set、zset这四种数据结构的存储优化。 在Redis3.2之前,如果列表、散列或者有序集合的长度或者体积较小,Redis会选择一种名为ziplist的数据结构来存储它们。该结构是列表、散列和有序集合三种不同类型的对象的一种非结构化表示,与Redis在通常情况下使用双向链表来表示列表、使用散列表示散列、使用散列加跳跃表表示有序集合相比,它更加紧凑,避免了存储额外的指针和元数据(比如字符串值的剩余可用空间和结束符”\0″)。但是压缩列表需要在存储的时候进行序列化,读取的时候进行反序列化。以散列为例,在redis.conf中,可以进行如下设置

hash-max-ziplist-entries 512 hash-max-ziplist-value 64


entries选项说明允许被编码为ziplist的最大元素数量,value表示压缩列表每个节点的最大体积是多少个字节。如果任意一个条件不满足,则压缩列表会退化成相应的常规结构。这样做的原因是,当压缩列表的体积越来越大时,操作这些数据结构的速度也会越来越慢,特别是当需要扫描整个列表的时候,因为Redis需要解码很多单独的节点。


那么上述值各取多少合适呢?合理的做法是将压缩列表长度限制在500~2000个元素之内,并且每个元素体积在128字节之内。Redis实战推荐的做法是将压缩列表长度限制在1024个元素之内,并且每个元素体积不超过64字节。这类参数可能还得由应用的实际场景来定。此外,我们可以使用DEBUG OBJECT命令来查看某个存储的数据使用了何种数据结构及其它一些重要信息。 


在Redis3.2及以后,列表的内部实现变成了quicklist而非ziplist或者传统的双端链表。官方定义是A doubly linked list of ziplists,即由ziplist组成的双向链表。quicklist这样设计的原因大概是一个空间和时间的折中:(1)双向链表便于在表的两端进行push和pop操作,但是它的内存开销比较大。首先,它在每个节点上除了要保存数据之外,还要额外保存两个指针;其次,双向链表的各个节点是单独的内存块,地址不连续,节点多了容易产生内存碎片。(2)ziplist由于是一整块连续内存,所以存储效率很高。但是,它不利于修改操作,每次数据变动都会引发一次内存的realloc。特别是当ziplist长度很长的时候,一次realloc可能会导致大批量的数据拷贝,进一步降低性能。


那么到底一个quicklist节点包含多长的ziplist合适呢?我们从存储效率来分析:

(1)每个quicklist节点上的ziplist越短,则内存碎片越多。内存碎片多了,有可能在内存中产生很多无法被利用的小碎片,从而降低存储效率。这种情况的极端是每个quicklist节点上的ziplist只包含一个数据项,这就退化成一个普通的双向链表了。

(2)每个quicklist节点上的ziplist越长,则为ziplist分配大块连续内存空间的难度就越大。有可能出现内存里有很多小块的空闲空间(它们加起来很多),但却找不到一块足够大的空闲空间分配给ziplist的情况。这同样会降低存储效率。这种情况的极端是整个quicklist只有一个节点,所有的数据项都分配在这仅有的一个节点的ziplist里面。这其实退化成一个ziplist了。 redis.conf提供了以下参数来设置quicklist的相关属性

list-max-ziplist-size -2

list-compress-depth 0

size参数可取正值和负值,取正的时候表示按照数据项个数来限定每个quicklist节点上的ziplist长度。取负的时候表示按照数据项大小来限制每个quicklist上的ziplist长度。计算方式是2^(abs(n)+1),比如这里-2表示每个quicklist节点上的ziplist大小不能超过2^(2+1)即8kb。 当列表很长的时候,最容易被访问的很可能是两端的数据,中间的数据被访问的频率比较低(访问起来性能也很低)。如果应用场景符合这个特点,那么list还提供了一个选项,能够把中间的数据节点进行压缩,从而进一步节省内存空间。Redis的配置参数list-compress-depth就是用来完成这个设置的。它表示两端不被压缩的元素个数。这里节点个数指quicklist双向链表的节点个数,如果一个quicklist节点上的ziplist被压缩,就是整体被压缩。如果值为0,则表示两端数据都不被压缩,为n,则表示两端各n个数据不被压缩。 关于ziplist和quicklist细节可以阅读参考链接中的相关文章。


集合(set)也有自己的紧凑表示形式。如果集合元素全是整数,而这些整数处于平台的有符号范围之内,并且它们的数量又在一定范围内,那么Redis会以有序整数数组的方式存储集合,这种方式被成为整数集合(intset)。redis.conf中可以通过

set-max-intset-entries 512

设置该范围。当存储数据个数大于512的时候或者存储了其它类型的数据时,它会退化为hashtable。在数据量较大的时候,与ziplist由于编码解码数据(如果有对数据移动的操作也会有影响)主要造成性能瓶颈的原因不同,主要影响intset性能的原因是它在执行插入或者删除操作的时候都需要对数据进行移动。因此,需要根据实际情况设置intset最大的元素个数。


对数据进行分片。比如当单个散列比较大的时候,可以按一定规则(key+id%shard_num)对数据进行分片,然后ziplist便更不容易退化为hashtable,且不会出现编码解码引起的性能问题。


总结:

· 根据业务需要选择合适的数据类型,并为不同的应用场景设置相应的紧凑存储参数。

· 当业务场景不需要数据持久化时,关闭所有的持久化方式可以获得最佳的性能以及最大的内存使用量。

· 如果需要使用持久化,根据是否可以容忍重启丢失部分数据在快照方式与语句追加方式之间选择其一,不要使用虚拟内存以及diskstore方式。

· 不要让你的Redis所在机器物理内存使用超过实际内存总量的3/5。


3.扩展读写能力


· 扩展读性能。在redis.conf中添加slaveof host port即可将其配置为另一台Redis服务器的从服务器。注意,在从服务器连接主服务器的时候,从服务器之前的数据会被清空。可以用这种方式建立从服务器树,扩展其读能力。但这种方式并未做故障转移,高可用Redis部署方案可以参考Redis Sentinel,Redis Cluster和Codis。


· 扩展写性能

(1)使用集群分片技术,比如Redis Cluster;

(2)单机上运行多个Redis实例。由于Redis是单线程设计,在涉及到cpu bound的操作的时候,可能速度会大大降低。如果服务器的cpu、io资源充足,可以在同一台机器上运行多个Redis服务器。


4.应用程序优化


应用程序优化部分主要是客户端和Redis交互的一些建议。主要思想是尽可能减少操作Redis往返的通信次数。


· 使用流水线操作。Redis支持流水线(pipeline)操作,其中包括了事务流水线和非事务流水线。Redis提供了WATCH命令与事务搭配使用,实现CAS乐观锁的机制。WATCH的机制是:在事务EXEC命令执行时,Redis会检查被WATCH的key,只有被WATCH的key从WATCH起始时至今没有发生过变更,EXEC才会被执行。如果WATCH的key在WATCH命令到EXEC命令之间发生过变化,则EXEC命令会返回失败。使用事务的一个好处是被MULTI和EXEC包裹的命令在执行时不会被其它客户端打断。但是事务会消耗资源,随着负载不断增加,由WATCH、MULTI、EXEC组成的事务(CAS)可能会进行大量重试,严重影响程序性能。 如果用户需要向Redis发送多个命令,且一个命令的执行结果不会影响另一个命令的输入,那么我们可以使用非事务流水线来代替事务性流水线。非事务流水线主要作用是将待执行的命令一次性全部发送给Redis,减少来回通信的次数,以此来提升性能。


· 使用mset、lpush、zadd等批量操作数据。它的原理同非事务性流行线操作。


· 使用lua脚本。Lua脚本跟单个Redis命令及MULTI/EXEC组成的事务一样,都是原子操作。Redis采用单线程设计,每次只能执行一个命令,每个单独的命令都是原子的。Lua脚本有两个好处:(1)减少多个操作通信往返带来的开销(2)无需担心由于事务竞争导致的性能开销。


· 尽可能使用时间复杂度为O(1)的操作,避免使用复杂度为O(N)的操作。避免使用这些O(N)命令主要有几个办法:(1)不要把List当做列表使用,仅当做队列来使用;(2)通过机制严格控制Hash、Set、Sorted Set的大小;(3)可能的话,将排序、并集、交集等操作放在客户端执行;(4)绝对禁止使用KEYS命令;(5)避免一次性遍历集合类型的所有成员,而应使用SCAN类的命令进行分批的,游标式的遍历


Redis提供了Slow Log功能,可以自动记录耗时较长的命令,redis.conf中的配置如下

#执行时间慢于10000毫秒的命令计入Slow Log

slowlog-log-slower-than 10000  

#最大纪录多少条Slow Log

slowlog-max-len 128

使用SLOWLOG GET n命令,可以输出最近n条慢查询日志。使用SLOWLOG RESET命令,可以重置Slow Log。


在使用Redis时,你需要注意以下几点:


1. 掌控储存在Redis中的所有键

数据库的主要功能是储存数据,但是对于开发者来说,因为应用程序需求或者数据使用方法的改变,忽略存储在数据库中的某些数据是非常正常的,在Redis中同样如此。你可能忽视期满某些键,也可能因为应用程序的某个模块弃用而忘掉这些数据。


无论哪种情况,Redis都存储了一些不再使用的数据,平白无故的占用了一些空间。Redis的弱结构数据模式让集中储存的内容很难被弄清,除非你为键使用一套非常成熟的命名法则。使用合适的命名方法会简化你的数据库管理,当你通过你的应用程序或者服务做键的命名空间时(通常情况下是使用冒号来划分键名),你就可以在数据迁移、转换或者删除时轻松的识别。


Redis另一个常见用例是作为热数据项作的第二数据存储,大部分的数据被保存在其他的数据库中,比如PostgreSQL或MongoDB。在这些用例中,当数据从主存储移除时,开发者经常会忘记删除Redis中对应的数据。这种存在跨数据存储的情况下,通常需要做级联删除,这种情况下,可以通过在Redis配置保存特定数据项的所有识别符来实现,从而保证数据在主数据库被删除后,系统会调用一个清理程序来删除所有相关副本和信息。


2. 控制所有键名的长度

在上文我们说过要使用合适的命名规则,并且添加前缀来识别数据走向,因此这一条看起来似乎与之违背。但是,请别忘记,Redis是个内存数据库,键越短你需要的空间就越少。理所当然,当数据库中拥有数百万或者数十亿键时,键名的长度将影响重大。


举个例子:在一个32位的Redis服务器上,如果储存一百万个键,每个值的长度是32-character,那么在使用6-character长度键名时,将会消耗大约96MB的空间,但是如果使用12-character长度的键名时,空间消耗则会提升至111MB左右。随着键的增多,15%的额外开销将产生重大的影响。


3. 使用合适的数据结构

不管是内存使用或者是性能,有的时候数据结构将产生很大的影响,下面是一些可以参考的最佳实践:


取代将数据存储为数千(或者数百万)独立的字符串,可以考虑使用哈希数据结构将相关数据进行分组。哈希表是非常有效率的,并且可以减少你的内存使用;同时,哈希还更有益于细节抽象和代码可读。


合适时候,使用list代替set。如果你不需要使用set特性,List在使用更少内存的情况下可以提供比set更快的速度。


Sorted sets是最昂贵的数据结构,不管是内存消耗还是基本操作的复杂性。如果你只是需要一个查询记录的途径,并不在意排序这样的属性,那么轻建议使用哈希表。


Redis中一个经常被忽视的功能就是bitmaps或者bitsets(V2.2之后)。Bitsets允许你在Redis值上执行多个bit-level操作,比如一些轻量级的分析。


4. 使用SCAN时别使用键

从Redis v2.8开始,SCAN命令已经可用,它允许使用游标从keyspace中检索键。对比KEYS命令,虽然SCAN无法一次性返回所有匹配结果,但是却规避了阻塞系统这个高风险,从而也让一些操作可以放在主节点上执行。


需要注意的是,SCAN 命令是一个基于游标的迭代器。SCAN 命令每次被调用之后, 都会向用户返回一个新的游标,用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数, 以此来延续之前的迭代过程。同时,使用SCAN,用户还可以使用keyname模式和count选项对命令进行调整。


SCAN相关命令还包括SSCAN 命令、HSCAN 命令和 ZSCAN 命令,分别用于集合、哈希键及有续集等。


5. 使用服务器端Lua脚本

在Redis使用过程中,Lua脚本的支持无疑给开发者提供一个非常友好的开发环境,从而大幅度解放用户的创造力。如果使用得当,Lua脚本可以给性能和资源消耗带来非常大的改善。取代将数据传送给CPU,脚本允许你在最接近数据的地方执行逻辑,从而减少网络延时和数据的冗余传输。


在Redis中,Lua一个非常经典的用例就是数据过滤或者将数据聚合到应用程序。通过将处理工作流封装到一个脚本中,你只需要调用它就可以在更短的时间内使用很少的资源来获取一个更小的答案。


二、优化经验


Redis优化1:精简键名和键值


键名:尽量精简,但是也不能单纯为了节约空间而使用不易理解的键名。

键值:对于键值的数量固定的话可以使用0和1这样的数字来表示,(例如:male/female、right/wrong)

当业务场景不需要数据持久化时,关闭所有的持久化方式可以获得最佳的性能

 

内部编码优化(大家可以自己了解)

Redis为每种数据类型都提供了两种内部编码方式,在不同的情况下Redis会自动调整合适的编码方式。(如图所示)

111-20160503101230651.png

SLOWLOG [get/reset/len]

slowlog-log-slower-than //它决定要对执行时间大于多少微秒(microsecond,1秒 = 1,000,000 微秒)的命令进行记录

slowlog-max-len //它决定 slowlog 最多能保存多少条日志

当发现Redis性能下降的时候可以查看下是哪些命令导致的

 

Redis优化2:修改linux内核内存分配策略


原因:

Redis在运行过程中可能会出现下面问题

错误日志:

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'

Redis在备份数据的时候,会fork出一个子进程,理论上child进程所占用的内存和parent是一样的,比如parent占用的内存为8G,这个时候也要同样分配8G的内存给child,如果内存无法负担,往往会造成Redis服务器的down机或者IO负载过高,效率下降。所以内存分配策略应该设置为 1(表示内核允许分配所有的物理内存,而不管当前的内存状态如何)。

 

内存分配策略有三种

可选值:0、1、2。

0, 表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。

1, 不管需要多少内存,都允许申请。

2, 只允许分配物理内存和交换内存的大小。(交换内存一般是物理内存的一半)

 

向/etc/sysctl.conf添加

vm.overcommit_memory = 1 //然后重启服务器

或者执行

sysctl vm.overcommit_memory=1 //立即生效

 

问题图示:

222-20160503102633097.png


Redis优化3:关闭Transparent Huge Pages(THP)

 

THP会造成内存锁影响Redis性能,建议关闭

Transparent HugePages :用来提高内存管理的性能

Transparent Huge Pages在32位的RHEL 6中是不支持的

 

使用root用户执行下面命令

echo never > /sys/kernel/mm/transparent_hugepage/enabled

 

把这条命令添加到这个文件中/etc/rc.local

 333-20160503102751630.png

 

Redis优化4:修改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。

444-20160503102822173.png

 

Redis优化5:限制Redis的内存大小

 

· 通过Redis的info命令查看内存使用情况

· 如果不设置maxmemory或者设置为0,64位系统不限制内存,32位系统最多使用3GB内存。

· 修改配置文件中的maxmemory和maxmemory-policy

maxmemory:最大内存

maxmemory-policy:内存不足时,数据清除策略

 

如果可以确定数据总量不大,并且内存足够的情况下不需要限制Redis使用的内存大小。如果数据量不可预估,并且内存也有限的话,尽量限制下Redis使用的内存大小,这样可以避免Redis使用swap分区或者出现OOM错误。

 

注意:如果不限制内存,当物理内存使用完之后,会使用swap分区,这样性能较低,如果限制了内存,当到达指定内存之后就不能添加数据了,否则会报OOM错误。可以设置maxmemory-policy,内存不足时删除数据。

 

拓展:

used_memory是Redis使用的内存总量,它包含了实际缓存占用的内存和Redis自身运行所占用的内存(以字节(byte)为单位,其中used_memory_human上的数据和used_memory是一样的值,它以M为单位显示,仅为了方便阅读)。


如果一个Redis实例的内存使用率超过可用最大内存(used_memory >可用最大内存),那么操作系统开始进行内存与swap空间交换,把内存中旧的或不再使用的内容写入硬盘上(硬盘上的这块空间叫Swap分区),以便腾出新的物理内存给新页或活动页(page)使用。

 

在硬盘上进行读写操作要比在内存上进行读写操作,时间上慢了近5个数量级,内存是0.1us(微秒)、而硬盘是10ms(毫秒)。如果Redis进程上发生内存交换,那么Redis和依赖Redis上数据的应用会受到严重的性能影响。 通过查看used_memory指标可知道Redis正在使用的内存情况,如果used_memory>可用最大内存,那就说明Redis实例正在进行内存交换或者已经内存交换完毕。管理员根据这个情况,执行相对应的应急措施。

 

排查方案:

若是在使用Redis期间没有开启rdb快照或aof持久化策略,那么缓存数据在Redis崩溃时就有丢失的危险。因为当Redis内存使用率超过可用内存的95%时,部分数据开始在内存与swap空间来回交换,这时就可能有丢失数据的危险。

 

当开启并触发快照功能时,Redis会fork一个子进程把当前内存中的数据完全复制一份写入到硬盘上。因此若是当前使用内存超过可用内存的45%时触发快照功能,那么此时进行的内存交换会变的非常危险(可能会丢失数据)。 倘若在这个时候实例上有大量频繁的更新操作,问题会变得更加严重。

 

通过减少Redis的内存占用率,来避免这样的问题,或者使用下面的技巧来避免内存交换发生:

1、尽可能的使用Hash数据结构。因为Redis在储存小于100个字段的Hash结构上,其存储效率是非常高的。所以在不需要集合(set)操作或list的push/pop操作的时候,尽可能的使用Hash结构。比如,在一个web应用程序中,需要存储一个对象表示用户信息,使用单个key表示一个用户,其每个属性存储在Hash的字段里,这样要比给每个属性单独设置一个key-value要高效的多。 通常情况下倘若有数据使用string结构,用多个key存储时,那么应该转换成单key多字段的Hash结构。 如上述例子中介绍的Hash结构应包含,单个对象的属性或者单个用户各种各样的资料。Hash结构的操作命令是HSET(key, fields, value)和HGET(key, field),使用它可以存储或从Hash中取出指定的字段。

 

2、设置key的过期时间。一个减少内存使用率的简单方法就是,每当存储对象时确保设置key的过期时间。倘若key在明确的时间周期内使用或者旧key不大可能被使用时,就可以用Redis过期时间命令(expire,expireat, pexpire, pexpireat)去设置过期时间,这样Redis会在key过期时自动删除key。 假如你知道每秒钟有多少个新key-value被创建,那可以调整key的存活时间,并指定阀值去限制Redis使用的最大内存。


3、回收key。在Redis配置文件中(一般叫Redis.conf),通过设置“maxmemory”属性的值可以限制Redis最大使用的内存,修改后重启实例生效。也可以使用客户端命令config set maxmemory 去修改值,这个命令是立即生效的,但会在重启后会失效,需要使用config rewrite命令去刷新配置文件。 若是启用了Redis快照功能,应该设置“maxmemory”值为系统可使用内存的45%,因为快照时需要一倍的内存来复制整个数据集,也就是说如果当前已使用45%,在快照期间会变成95%(45%+45%+5%),其中5%是预留给其他的开销。 如果没开启快照功能,maxmemory最高能设置为系统可用内存的95%。


当内存使用达到设置的最大阀值时,需要选择一种key的回收策略,可在Redis.conf配置文件中修改“maxmemory-policy”属性值。 若是Redis数据集中的key都设置了过期时间,那么“volatile-ttl”策略是比较好的选择。但如果key在达到最大内存限制时没能够迅速过期,或者根本没有设置过期时间。那么设置为“allkeys-lru”值比较合适,它允许Redis从整个数据集中挑选最近最少使用的key进行删除(LRU淘汰算法)。Redis还提供了一些其他淘汰策略,如下:

volatile-lru: 使用LRU算法从已设置过期时间的数据集合中淘汰数据。

volatile-ttl:从已设置过期时间的数据集合中挑选即将过期的数据淘汰。

volatile-random:从已设置过期时间的数据集合中随机挑选数据淘汰。

allkeys-lru:使用LRU算法从所有数据集合中淘汰数据。

allkeys-random:从数据集合中任意选择数据淘汰

no-enviction:禁止淘汰数据。

 

通过设置maxmemory为系统可用内存的45%或95%(取决于持久化策略)和设置“maxmemory-policy”为“volatile-ttl”或“allkeys-lru”(取决于过期设置),可以比较准确的限制Redis最大内存使用率,在绝大多数场景下使用这2种方式可确保Redis不会进行内存交换。倘若你担心由于限制了内存使用率导致丢失数据的话,可以设置noneviction值禁止淘汰数据。

 

Redis优化6

 

Redis是个单线程模型,客户端过来的命令是按照顺序执行的,所以想要一次添加多条数据的时候可以使用管道,或者使用一次可以添加多条数据的命令,例如:

555-20160503102911537.png


三、优化的一些建议


尽量使用短的key

当然在精简的同时,不要完了key的“见名知意”。对于value有些也可精简,比如性别使用0、1。


避免使用keys *

keys *, 这个命令是阻塞的,即操作执行期间,其它任何命令在你的实例中都无法执行。当redis中key数据量小时到无所谓,数据量大就很糟糕了。所以我们应该避免去使用这个命令。可以去使用SCAN,来代替。


在存到Redis之前先把你的数据压缩下

redis为每种数据类型都提供了两种内部编码方式,在不同的情况下redis会自动调整合适的编码方式。


设置 key 有效期

我们应该尽可能的利用key有效期。比如一些临时数据(短信校验码),过了有效期Redis就会自动为你清除!


选择回收策略(maxmemory-policy)

当 Redis 的实例空间被填满了之后,将会尝试回收一部分key。根据你的使用方式,强烈建议使用 volatile-lru(默认)策略——前提是你对key已经设置了超时。但如果你运行的是一些类似于 cache 的东西,并且没有对 key 设置超时机制,可以考虑使用 allkeys-lru 回收机制,具体讲解查看 。maxmemory-samples 3 是说每次进行淘汰的时候 会随机抽取3个key 从里面淘汰最不经常使用的(默认选项)


maxmemory-policy 六种方式 :

volatile-lru:只对设置了过期时间的key进行LRU(默认值)

allkeys-lru : 是从所有key里 删除 不经常使用的key

volatile-random:随机删除即将过期key

allkeys-random:随机删除

volatile-ttl : 删除即将过期的

noeviction : 永不过期,返回错误


使用bit位级别操作和byte字节级别操作来减少不必要的内存使用。

bit位级别操作:GETRANGE, SETRANGE, GETBIT and SETBIT

byte字节级别操作:GETRANGE and SETRANGE


尽可能地使用hashes哈希存储。

当业务场景不需要数据持久化时,关闭所有的持久化方式可以获得最佳的性能。


想要一次添加多条数据的时候可以使用管道。


限制redis的内存大小(64位系统不限制内存,32位系统默认最多使用3GB内存)

数据量不可预估,并且内存也有限的话,尽量限制下redis使用的内存大小,这样可以避免redis使用swap分区或者出现OOM错误。(使用swap分区,性能较低,如果限制了内存,当到达指定内存之后就不能添加数据了,否则会报OOM错误。可以设置maxmemory-policy,内存不足时删除数据。)


SLOWLOG [get/reset/len]

slowlog-log-slower-than 它决定要对执行时间大于多少微秒(microsecond,1秒 = 1,000,000 微秒)的命令进行记录。

slowlog-max-len 它决定 slowlog 最多能保存多少条日志,当发现redis性能下降的时候可以查看下是哪些命令导致的。


参考网址:

https://www.infoq.cn/article/tq-redis-memory-usage-optimization-storage 

https://blog.csdn.net/lihuaxin_bj/article/details/80895520 

https://www.cnblogs.com/chenpingzhao/p/6859041.html

https://www.cnblogs.com/duanxz/p/5447402.html


原文地址:https://blog.csdn.net/achuo/article/details/80600170

转载请注明: ITTXX.CN--分享互联网 » Redis性能问题分析和优化经验

最后更新:2018-12-07 20:15:55

赞 (6) or 分享 ()
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽