
从业务服务器到Redis服务器这条调用链路中变慢的原因可能有2个
但是大多数情况下都是Redis服务的问题。但是应该如何衡量Redis变慢了呢?命令执行时间大于1s,大于2s?这其实并没有一个固定的标准。
例如在一个配置较高的服务器中,05毫秒就认为Redis变慢了,在一个配置较低的服务器中,3毫秒才认为Redis变慢了。所以我们要针对自己的机器做基准测试,看平常情况下Redis处理命令的时间是多长?
我们可以使用如下命令来监测和统计测试期间的最大延迟(以微秒为单位)
比如执行如下命令
参数中的60是测试执行的秒数,可以看到最大延迟为3725微秒(3毫秒左右),如果命令的执行远超3毫秒,此时Redis就有可能很慢了!
那么Redis有哪些慢 *** 作呢?
Redis的各种命令是在一个线程中依次执行的,如果一个命令在Redis中执行的时间过长,就会影响整体的性能,因为后面的请求要等到前面的请求被处理完才能被处理,这些耗时的 *** 作有如下几个部分
Redis可以通过日志记录那些耗时长的命令,使用如下配置即可
执行如下命令,就可以查询到最近记录的慢日志
之前的文章我们已经介绍了Redis的底层数据结构,它们的时间复杂度如下表所示
名称 时间复杂度 dict(字典) O(1) ziplist (压缩列表) O(n) zskiplist (跳表) O(logN) quicklist(快速列表) O(n) intset(整数集合) O(n)
「单元素 *** 作」 :对集合中的元素进行增删改查 *** 作和底层数据结构相关,如对字典进行增删改查时间复杂度为O(1),对跳表进行增删查时间复杂为O(logN)
「范围 *** 作」 :对集合进行遍历 *** 作,比如Hash类型的HGETALL,Set类型的SMEMBERS,List类型的LRANGE,ZSet类型的ZRANGE,时间复杂度为O(n),避免使用,用SCAN系列命令代替。(hash用hscan,set用sscan,zset用zscan)
「聚合 *** 作」 :这类 *** 作的时间复杂度通常大于O(n),比如SORT、SUNION、ZUNIONSTORE
「统计 *** 作」 :当想获取集合中的元素个数时,如LLEN或者SCARD,时间复杂度为O(1),因为它们的底层数据结构如quicklist,dict,intset保存了元素的个数
「边界 *** 作」 :list底层是用quicklist实现的,quicklist保存了链表的头尾节点,因此对链表的头尾节点进行 *** 作,时间复杂度为O(1),如LPOP、RPOP、LPUSH、RPUSH
「当想获取Redis中的key时,避免使用keys 」 ,Redis中保存的键值对是保存在一个字典中的(和Java中的HashMap类似,也是通过数组+链表的方式实现的),key的类型都是string,value的类型可以是string,set,list等
例如当我们执行如下命令后,redis的字典结构如下
我们可以用keys命令来查询Redis中特定的key,如下所示
keys命令的复杂度是O(n),它会遍历这个dict中的所有key,如果Redis中存的key非常多,所有读写Redis的指令都会被延迟等待,所以千万不用在生产环境用这个命令(如果你已经准备离职的话,祝你玩的开心)。
「既然不让你用keys,肯定有替代品,那就是scan」
scan是通过游标逐步遍历的,因此不会长时间阻塞Redis
「用用zscan遍历zset,hscan遍历hash,sscan遍历set的原理和scan命令类似,因为hash,set,zset的底层实现的数据结构中都有dict。」
「如果一个key对应的value非常大,那么这个key就被称为bigkey。写入bigkey在分配内存时需要消耗更长的时间。同样,删除bigkey释放内存也需要消耗更长的时间」
如果在慢日志中发现了SET/DEL这种复杂度不高的命令,此时你就应该排查一下是否是由于写入bigkey导致的。
「如何定位bigkey」
Redis提供了扫描bigkey的命令
可以看到命令的输入有如下3个部分
这个命令的原理就是redis在内部执行了scan命令,遍历实例中所有的key,然后正对key的类型,分别执行strlen,llen,hlen,scard,zcard命令,来获取string类型的长度,容器类型(list,hash,set,zset)的元素个数
使用这个命令需要注意如下两个问题
「如何解决bigkey带来的性能问题?」
我们可以给Redis中的key设置过期时间,那么当key过期了,它在什么时候会被删除呢?
「如果让我们写Redis过期策略,我们会想到如下三种方案」
定时删除策略对CPU不友好,当过期键比较多的时候,Redis线程用来删除过期键,会影响正常请求的响应
惰性删除读CPU是比较有好的,但是会浪费大量的内存。如果一个key设置过期时间放到内存中,但是没有被访问到,那么它会一直存在内存中
定期删除策略则对CPU和内存都比较友好
redis过期key的删除策略选择了如下两种
「惰性删除」 客户端在访问key的时候,对key的过期时间进行校验,如果过期了就立即删除
「定期删除」 Redis会将设置了过期时间的key放在一个独立的字典中,定时遍历这个字典来删除过期的key,遍历策略如下
「因为Redis中过期的key是由主线程删除的,为了不阻塞用户的请求,所以删除过期key的时候是少量多次」 。源码可以参考expirec中的activeExpireCycle方法
为了避免主线程一直在删除key,我们可以采用如下两种方案
Redis是一个内存数据库,当Redis使用的内存超过物理内存的限制后,内存数据会和磁盘产生频繁的交换,交换会导致Redis性能急剧下降。所以在生产环境中我们通过配置参数maxmemoey来限制使用的内存大小。
当实际使用的内存超过maxmemoey后,Redis提供了如下几种可选策略。
「Redis的淘汰策略也是在主线程中执行的。但内存超过Redis上限后,每次写入都需要淘汰一些key,导致请求时间变长」
可以通过如下几个方式进行改善
Redis的持久化机制有RDB快照和AOF日志,每次写命令之后后,Redis提供了如下三种刷盘机制
「当aof的刷盘机制为always,redis每处理一次写命令,都会把写命令刷到磁盘中才返回,整个过程是在Redis主线程中进行的,势必会拖慢redis的性能」
当aof的刷盘机制为everysec,redis写完内存后就返回,刷盘 *** 作是放到后台线程中去执行的,后台线程每隔1秒把内存中的数据刷到磁盘中
当aof的刷盘机制为no,宕机后可能会造成部分数据丢失,一般不采用。
「一般情况下,aof刷盘机制配置为everysec即可」
在持久化一节中,我们已经提到 「Redis生成rdb文件和aof日志重写,都是通过主线程fork子进程的方式,让子进程来执行的,主线程的内存越大,阻塞时间越长。」
可以通过如下方式优化
当机器的内存不够时, *** 作系统会将部分内存的数据置换到磁盘上,这块磁盘区域就是Swap分区,当应用程序再次访问这些数据的时候,就需要从磁盘上读取,导致性能严重下降
「当Redis性能急剧下降时就有可能是数据被换到Swap分区,我们该如何排查Redis数据是否被换到Swap分区呢?」
每一行Size表示Redis所用的一块内存大小,Size下面的Swap表示这块大小的内存,有多少已经被换到磁盘上了,如果这2个值相等,说明这块内存的数据都已经被换到磁盘上了
我们可以通过如下方式来解决
最后我们总结一下Redis的慢 *** 作
update之后,写MySql,再写入Redis,替旧数据(可在MySql端定义CRUD触发器,触发后写数据到Redis,也可Redis端解析binlog)
设定超时时间,redis自动删除数据。第二次删除前最好休眠时间,比如500毫秒,又增加写耗时。
一、Redis不会自己同步变更,要告诉。机制(不仅限于):
1 Redis过期去DB取,不立刻更新,顺带重新set redis(称作“Cache Aside”)。不一致时间可设置有效期,如10min。没设置不灵。
2 通过代码更新DB。然后马上del掉redis数据。下次取数据时,恢复上一条方式。Cache Aside变体。好处一致性比较好,一般情况,不一致时间1s以下,绝大部分足够。极少不一致
Cache Aside,“Cache”在DB访问的主流程上帮个忙
1和2的做法常规上被称为“Cache“。而且因为1有更新不及时的问题,2有极端情况下数据会不一致的问题,所以常规Cache代码会把1+2组合起来,要求Redis里的数据必须有过期时间,并且不能太长,这样即便是不一致也能混过去。同时如果是主动对数据进行更新,Cache的数据更新也会比较及时。
并且2并不一定总是行得通。比如OLTP的服务在前面是Cache+DB的模式,而数据是由后台管理系统来更新的,总是不会触碰OLTP服务,更不会动Cache。这时将Redis看作是存储也算是一种方案
不知道你是想怎么判断,但是select table_name from user_tables;就会查询出所有的表名字(不区分大小写); 你要是用hibernate注入的话,在配置文件中直接弄成update,那么有表的时候就不会创建表,没有的时候就会创建一个表。
I 问题背景
你或许希望一个Redis应用(一个Redis server,或者一个Redis server/slaves群组)能为多个客户端应用服务,如果这些客户端应用都各自为营,向Redis写数据的话,很可能会导致key冲突(我们知道Redis是一个key-value结构的存储结构)。为了将不同的应用分开,你可以用不同的前缀去区分(eg: app_i:xx:yy, app_ii:xx:yy)。Redis已经有更好的分割这些key的机制:Database。
II 定义
Redis Databases是一个下标基于0的数组,我们可以用指令:
SELECT 2
将当前Database切换到“2”这个空间,此后所有的 *** 作都是在这个空间(对应客户端的应用)内的,直到再次执行 SELECT n。
III 实施方案
Database切换 *** 作:SELECT n
清除当前Database下的所有key(所有数据):FLUSHDB,之后用 keys 查看是否还有残key存在?没有了!
IV 其他
Databases的数量可以在redisconf中配置:
databases 42,从“客户端应用都各自为营”的角度来看,Database的概念是很适用的,它让我们有清晰的数据划分,可以放心的把注意力放在key的设计上。
Redis暂不提供将字符串索引Databases的方式(只能用Number),所以只能自己铭记哪个数子代表那块数据。
Redis 是一个高性能的key-value数据库, 使用内存作为主存储,数据访问速度非常快,当然它也提供了两种机制支持数据持久化存储比较遗憾的是,Redis项目不直接支持Windows,Windows版项目是由微软开放技术团队建立和维护一个实验性项目(支持32,64位),所以并不适用生产环境,但可在Windows环境下用于开发测试。
1下载安装
猛戳这里就到了开源首页,下载源码包,解压ZIP包后进入msvsbinrelease文件夹有三个文件分别对应32,64位,windows服务三个版本,在这里我们选择64位为例,解压redisbin64zip 到D:redis24,这里主要用到redis-serverexe和redis-cliexe, redis-server用于运行Redis服务器,redis-cli是命令行客户端,通过它连接Redis服务器,并使用Redis命令进行各种 *** 作。
2服务启动配置
复制源码包根目录下redisconf到D:redis24,打开CMD命令提示符,输入以下命令启动redis服务。
启动:
redis-server redisconf
这样redis服务就启动成功了。
配置:
更改redis的配置需要修改redisconf文件,以下是它一些主要的配置注释:
#是否作为守护进程运行 daemonize no #Redis 默认监听端口 port 6379 #客户端闲置多少秒后,断开连接 timeout 300 #日志显示级别 loglevel verbose #指定日志输出的文件名,也可指定到标准输出端口 logfile redislog #设置数据库的数量,默认最大是16,默认连接的数据库是0,可以通过select N 来连接不同的数据库 databases 32 #Dump持久化策略 #当有一条Keys 数据被改变是,900 秒刷新到disk 一次 #save 900 1 #当有10 条Keys 数据被改变时,300 秒刷新到disk 一次 save 300 100 #当有1w 条keys 数据被改变时,60 秒刷新到disk 一次 save 6000 10000 #当dump rdb 数据库的时候是否压缩数据对象 rdbcompression yes #dump 持久化数据保存的文件名 dbfilename dumprdb ########### Replication ##################### #Redis的主从配置,配置slaveof则实例作为从服务器 #slaveof 1921680105 6379 #主服务器连接密码 # masterauth <master-password> ############## 安全性 ########### #设置连接密码 #requirepass <password> ############### LIMITS ############## #最大客户端连接数 # maxclients 128 #最大内存使用率 # maxmemory <bytes> ########## APPEND ONLY MODE ######### #是否开启日志功能 appendonly no # AOF持久化策略 #appendfsync always #appendfsync everysec #appendfsync no ################ VIRTUAL MEMORY ########### #是否开启VM 功能 #vm-enabled no # vm-enabled yes #vm-swap-file logs/redisswap #vm-max-memory 0 #vm-page-size 32 #vm-pages 134217728 #vm-max-threads 4
主从复制
在从服务器配置文件中配置slaveof ,填写服务器IP及端口即可,如果主服务器设置了连接密码,在masterauth后指定密码就行了。
持久化
redis提供了两种持久化文案,Dump持久化和AOF日志文件持久化。 Dump持久化是把内存中的数据完整写入到数据文件,由配置策略触发写入,如果在数据更改后又未达到触发条件而发生故障会造成部分数据丢失。 AOF持久化是日志存储的,是增量的形式,记录每一个数据 *** 作动作,数据恢复时就根据这些日志来生成。
3命令行 *** 作
使用CMD命令提示符,打开redis-cli连接redis服务器 ,也可以使用telnet客户端
# redis-cli -h 服务器 –p 端口 –a 密码
redis-cliexe -h 127001 -p 6379
连接成功后,就可对redis数据增删改查了,如字符串 *** 作:
以下是一些服务器管理常用命令:
info #查看服务器信息 select <dbsize> #选择数据库索引 select 1 flushall #清空全部数据 flushdb #清空当前索引的数据库 slaveof <服务器> <端口> #设置为从服务器 slaveof no one #设置为主服务器 shutdown #关闭服务
应用Redis实现数据的读写,同时利用队列处理器定时将数据写入mysql。同时要注意避免冲突,在redis启动时去mysql读取所有表键值存入redis中,往redis写数据时,对redis主键自增并进行读取,若mysql更新失败,则需要及时清除缓存及同步redis主键。这样处理,主要是实时读写redis,而mysql数据则通过队列异步处理,缓解mysql压力,不过这种方法应用场景主要基于高并发,而且redis的高可用集群架构相对更复杂,一般不是很推荐。
以上就是关于Redis有哪些慢 *** 作全部的内容,包括:Redis有哪些慢 *** 作、redis同步到数据库多长时间间隔、redis数据库判断表是否存在,存在就删除等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)