【存储中间件】Redis焦点技术与实战(二):Redis高级特性与应用(慢查询、 ...

打印 上一主题 下一主题

主题 921|帖子 921|积分 2765


个人主页:道友老李
接待参加社区:道友老李的学习社区
Redis高级特性和应用

Redis的慢查询

很多存储系统(比方 MySQL)提供慢查询日记资助开辟和运维人员定位系统存在的慢操作。所谓慢查询日记就是系统在命令执行前后计算每条命令的执行时间,当超过预设阀值,就将这条命令的相关信息(比方:发生时间,耗时,命令的详细信息)记录下来,Redis也提供了雷同的功能。
Redis客户端执行一条命令分为如下4个部门:

1、发送死令
2、命令排队
3、命令执行
4、返回结果
需要留意,慢查询只统计步调3的时间,以是没有慢查询并不代表客户端没有超时问题。因为有大概是命令的网络问题大概是命令在Redis在排队,以是不是说命令执行很慢就说是慢查询,而有大概是网络的问题大概是Redis服务非常繁忙(队列等待长)。
慢查询设置

对于任何慢查询功能,需要明白两件事:多慢算慢,也就是预设阀值怎么设置?慢查询记录存放在哪?
Redis提供了两种方式进行慢查询的设置
1、动态设置
慢查询的阈值默认值是10毫秒
参数:slowlog-log-slower-than就是时间预设阀值,它的单位是微秒(1秒=1000毫秒=1 000 000微秒),默认值是10 000,如果执行了一条“很慢”的命令(比方keys *),如果它的执行时间超过了10 000微秒,也就是10毫秒,那么它将被记录在慢查询日记中。
我们通过动态命令修改
  1. config set slowlog-log-slower-than 20000  
复制代码

使用config set完后,若想将设置持久化保存到Redis.conf,要执行config rewrite


  1. config rewrite
复制代码

留意:
如果设置slowlog-log-slower-than=0表现会记录全部的命令,slowlog-log-slower-than<0对于任何命令都不会进行记录。
2、设置文件设置(修改后需重启服务才生效)
打开Redis的设置文件redis.conf,就可以看到以下设置:

slowlog-max-len用来设置慢查询日记最多存储多少条

另外Redis还提供了slowlog-max-len设置来解决存储空间的问题。


实际上Redis服务器将全部的慢查询日记保存在服务器状态的slowlog链表中(内存列表),slowlog-max-len就是列表的最大长度(默认128条)。当慢查询日记列表被填满后,新的慢查询命令则会继续入队,队列中的第一条数据时机出列。
虽然慢查询日记是存放在Redis内存列表中的,但是Redis并没有告诉我们这里列表是什么,而是通过一组命令来实现对慢查询日记的访问和管理。并没有说明存放在哪。这个怎么办呢?Redis提供了一些列的慢查询操作命令让我们可以方便的操作。
慢查询操作命令

获取慢查询日记
  1. slowlog get [n]
复制代码
参数n可以指定查询条数。

可以看到每个慢查询日记有6个属性构成,分别是慢查询日记的标识id、发生时间戳、命令耗时(单位微秒)、执行命令和参数,客户端IP+端口和客户端名称。
获取慢查询日记列表当前的长度
  1. slowlog len
复制代码

慢查询日记重置
  1. slowlog reset
复制代码
实际是对列表做清理操作

慢查询发起

慢查询功能可以有效地资助我们找到Redis大概存在的瓶颈,但在实际使用过程中要留意以下几点:
slowlog-max-len设置发起:
发起调大慢查询列表,记录慢查询时Redis会对长命令做截断操作,并不会占用大量内存。增大慢查询列表可以减缓慢查询被剔除的大概,线上生产发起设置为1000以上。
slowlog-log-slower-than设置发起:
设置发起:默认值超过10毫秒判定为慢查询,需要根据Redis并发量调整该值。
由于Redis接纳单线程响应命令,对于高流量的场景,如果命令执行时间在1毫秒以上,那么Redis最多可支持OPS不到1000。因此对于高OPS场景的Redis发起设置为1毫秒大概更低比如100微秒。
慢查询只记录命令执行时间,并不包罗命令排队和网络传输时间。因此客户端执行命令的时间会大于命令实际执行时间。因为命令执行排队机制,慢查询会导致其他命令级联阻塞,因此当客户端出现哀求超时,需要查抄该时间点是否有对应的慢查询,从而分析出是否为慢查询导致的命令级联阻塞。

由于慢查询日记是一个先进先出的队列,也就是说如果慢查询比较多的环境下,大概会丢失部门慢查询命令,为了防止这种环境发生,可以定期执行slow get命令将慢查询日记持久化到其他存储中。
Pipeline

前面我们已经说过,Redis客户端执行一条命令分为如下4个部门:1)发送死令2)命令排队3)命令执行4)返回结果。

此中1和4花费的时间称为Round Trip Time (RTT,来回时间),也就是数据在网络上传输的时间。
Redis提供了批量操作命令(比方mget、mset等),有效地节流RTT。
但大部门命令是不支持批量操作的,比方要执行n次 hgetall命令,并没有mhgetall命令存在,需要消耗n次RTT。
举例:Redis的客户端和服务端大概部署在不同的机器上。比方客户端在本地,Redis服务器在阿里云的广州,两地直线间隔约为800公里,那么1次RTT时间=800 x2/ ( 300000×2/3 ) =8毫秒,(光在真空中传输速率为每秒30万公里,这里假设光纤为光速的2/3 )。而Redis命令真正执行的时间通常在微秒(1000玄妙=1毫秒)级别,以是才会有Redis 性能瓶颈是网络如许的说法。
Pipeline(流水线)机制能改善上面这类问题,它能将一组 Redis命令进行组装,通过一次RTT传输给Redis,再将这组Redis命令的执行结果按次序返回给客户端,没有使用Pipeline执行了n条命令,整个过程需要n次RTT。

使用Pipeline 执行了n次命令,整个过程需要1次RTT。

Pipeline并不是什么新的技术或机制,很多技术上都使用过。而且RTT在不同网络环境下会有不同,比方同机房和同机器会比较快,跨机房跨地区会比较慢。
redis-cli的–pipe选项实际上就是使用Pipeline机制,但绝对部门环境下,我们使用Java语言的Redis客户端中的Pipeline会更多一点。
代码参见:
  1. com.msb.redis.adv.RedisPipeline
复制代码

总的来说,在不同网络环境下非Pipeline和Pipeline执行10000次set操作的结果,在执行时间上的比对如下:

差距有100多倍,可以得到如下两个结论:
1、Pipeline执行速率一样平常比逐条执行要快。
2、客户端和服务端的网络延时越大,Pipeline的结果越显着。
Pipeline虽然好用,但是每次Pipeline组装的命令个数不能没有控制,否则一次组装Pipeline数据量过大,一方面会增长客户端的等待时间,另一方面会造成肯定的网络阻塞,可以将一次包罗大量命令的Pipeline拆分成多次较小的Pipeline来完成,比如可以将Pipeline的总发送大小控制在内核输入输出缓冲区大小之内大概控制在单个TCP 报文最大值1460字节之内。
内核的输入输出缓冲区大小一样平常是4K-8K,不同操作系统会不同(固然也可以设置修改)
最大传输单位(Maximum Transmission Unit,MTU),这个在以太网中最大值是1500字节。那为什么单个TCP 报文最大值是1460,因为因为还要扣减20个字节的IP头和20个字节的TCP头,以是是1460。
同时Pipeline只能操作一个Redis实例,但是即使在分布式Redis场景中,也可以作为批量操作的重要优化本事。
事务

大家应该对事务比较了解,简朴地说,事务表现一组动作,要么全部执行,要么全部不执行。
比方在社交网站上用户A关注了用户B,那么需要在用户A的关注表中参加用户B,并且在用户B的粉丝表中添加用户A,这两个行为要么全部执行,要么全部不执行,否则会出现数据不同等的环境。
Redis提供了简朴的事务功能,将一组需要一起执行的命令放到multi和exec两个命令之间。multi 命令代表事务开始,exec命令代表事务结束。另外discard命令是回滚。
一个客户端

另外一个客户端
在事务没有提交的时查询(查不到数据)

在事务提交后查询(可以查到数据)

可以看到sadd命令此时的返回结果是QUEUED,代表命令并没有真正执行,而是临时保存在Redis中的一个缓存队列(以是discard也只是丢弃这个缓存队列中的未执行命令,并不会回滚已经操作过的数据,这一点要和关系型数据库的Rollback操作区分开)。
只有当exec执行后,用户A关注用户B的行为才算完成,如下所示exec返回的两个结果对应sadd命令。
但是要留意Redis的事务功能很弱。在事务回滚机制上,Redis只能对基本的语法错误进行判定。
如果事务中的命令出现错误,Redis 的处理机制也不尽相同。
1、语法命令错误

比方下面操作错将set写成了sett,属于语法错误,会造成整个事务无法执行,事务内的操作都没有执行:
2、运行时错误
比方:事务内第一个命令简朴的设置一个string类型,第二个对这个key进行sadd命令,这种就是运行时命令错误,因为语法是正确的:

可以看到Redis并不支持回滚功能,第一个set命令已经执行成功,开辟人员需要自己修复这类问题。
Redis的事务原理

事务是Redis实现在服务器端的行为,用户执行MULTI命令时,服务器会将对应这个用户的客户端对象设置为一个特殊的状态,在这个状态下后续用户执行的查询命令不会被真的执行,而是被服务器缓存起来,直到用户执行EXEC命令为止,服务器会将这个用户对应的客户端对象中缓存的命令按照提交的次序依次执行。
Redis的watch命令

有些应用场景需要在事务之前,确保事务中的key没有被其他客户端修改过,才执行事务,否则不执行(雷同乐观锁)。Redis 提供了watch命令来解决这类问题。
客户端1:

客户端2:

客户端1继续:

可以看到“客户端-1”在执行multi之前执行了watch命令,“客户端-2”在“客户端-1”执行exec之前修改了key值,造成客户端-1事务没有执行(exec结果为nil)。
Redis客户端中的事务使用代码参见:
com.msb.redis.adv.RedisTransaction

Pipeline和事务的区别

PipeLine看起来和事务很雷同,感觉都是一批批处理,但两者照旧有很大的区别。简朴来说。
1、pipeline是客户端的行为,对于服务器来说是透明的,可以以为服务器无法区分客户端发送来的查询命令是以普通命令的情势照旧以pipeline的情势发送到服务器的;
2、而事务则是实现在服务器端的行为,用户执行MULTI命令时,服务器会将对应这个用户的客户端对象设置为一个特殊的状态,在这个状态下后续用户执行的查询命令不会被真的执行,而是被服务器缓存起来,直到用户执行EXEC命令为止,服务器会将这个用户对应的客户端对象中缓存的命令按照提交的次序依次执行。
3、应用pipeline可以提服务器的吞吐能力,并进步Redis处理查询哀求的能力。
但是这里存在一个问题,当通过pipeline提交的查询命令数据较少,可以被内核缓冲区所容纳时,Redis可以保证这些命令执行的原子性。然而一旦数据量过大,超过了内核缓冲区的汲取大小,那么命令的执行将会被打断,原子性也就无法得到保证。因此pipeline只是一种提拔服务器吞吐能力的机制,如果想要命令以事务的方式原子性的被执行,照旧需要事务机制,大概使用更高级的脚本功能以及模块功能。
4、可以将事务和pipeline结合起来使用,淘汰事务的命令在网络上的传输时间,将多次网络IO缩减为一次网络IO。
Redis提供了简朴的事务,之以是说它简朴,重要是因为它不支持事务中的回滚特性,同时无法实现命令之间的逻辑关系计算,固然也体现了Redis 的“keep it simple”的特性,下一小节先容的Lua脚本同样可以实现事务的相关功能,但是功能要强大很多。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

拉不拉稀肚拉稀

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表