redis 同步延迟键空间通知 多大量延迟

Redis中统计各种数据大小的方法
投稿:junjie
字体:[ ] 类型:转载 时间:
这篇文章主要介绍了Redis中统计各种数据大小的方法,本文使用PHP实现统计Redis内存占用比较大的键,需要的朋友可以参考下
如果 MySQL 数据库比较大的话,我们很容易就能查出是哪些表占用的空间;不过如果 Redis 内存比较大的话,我们就不太容易查出是哪些(种)键占用的空间了。
有一些工具能够提供必要的帮助,比如
可以直接分析 RDB 文件来生成报告,可惜它不能百分百实现我的需求,而我也不想在它的基础上二次开发。实际上开发一个专用工具非常简单,利用 和 等命令,没多少行代码就能实现:
$patterns = array(
&&& 'foo:.+',
&&& 'bar:.+',
$redis = new Redis();
$redis-&setOption(Redis::OPT_SCAN, Redis::SCAN_RETRY);
$result = array_fill_keys($patterns, 0);
while ($keys = $redis-&scan($it, $match = '*', $count = 1000)) {
&&& foreach ($keys as $key) {
&&&&&&& foreach ($patterns as $pattern) {
&&&&&&&&&&& if (preg_match("/^{$pattern}$/", $key)) {
&&&&&&&&&&&&&&& if ($v = $redis-&debug($key)) {
&&&&&&&&&&&&&&&&&&& $result[$pattern] += $v['serializedlength'];
&&&&&&&&&&&&&&& }
&&&&&&&&&&&&&&&
&&&&&&&&&&& }
var_dump($result);
当然,前提是你需要提前总结出可能的键模式,简单但不严谨的方法是 :
shell& /path/to/redis-cli monitor |
&&&&&& awk -F '"' '$2 ~ "ADD|SET|STORE|PUSH" {print $4}'
此外,需要注意的是:因为 DEBUG 返回的 serializedlength 是序列化后的长度,所以最终计算的值小于实际内存占用,但考虑到相对大小依然是有参考意义的。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具redis(40)
& & & & &Redis的键空间通知(keyspace notifications)功能是自2.8.0版本开始加入的,客户端可以通过订阅/发布(Pub/Sub)机制,接收那些以某种方式改变了Redis数据空间的事件通知。比如:所有改变给定key的命令;所有经过lpush操作的key;所有在0号数据库中过期的key等等。
&&&&&&&& 通知是通过Redis的订阅/发布机制发送的,因此,所有支持订阅/发布功能的客户端都可在无需调整的情况下,使用键空间通知功能。
& & & & &Redis的发布/订阅目前是即发即弃(fire and forget)模式的,因此无法实现事件的可靠通知。也就是说,如果发布/订阅的客户端断链之后又重连,则在客户端断链期间的所有事件都丢失了。
& & & & &未来计划支持事件的可靠通知,但是这可能会通过让订阅与发布功能本身变得更可靠来实现,也可能会在Lua脚本中对消息的订阅与发布进行监听,从而实现类似将事件推入到列表这样的操作。
一:事件的类型
&&&&&&&& 针对改变Redis数据空间的每个操作,键空间通知都会发送两类不同的事件。
&&&&&&&& 比如在0号数库中,执行del mykey操作,将会触发两个消息,等价于执行下面两个publish命令:
PUBLISH __keyspace@0__:mykey del
PUBLISH __keyevent@0__:del mykey
&&&&&&&& 一个频道发布0号数据库中,所有针对mykey键执行的操作,这类事件,以keyspace为前缀,称为keyspace通知;
& & & & &另一个频道发布0号数据库中,所有成功执行del操作的键,这类事件,以keyevent为前缀,称为keyevent通知;
& & & & &在上面的例子中,当执行del &mykey时,会发生:
& & & & &a:keyspace频道的订阅者会收到消息,消息中包含键执行的操作的名字;
& & & & &b:keyevent频道的订阅者会收到消息,消息中包含执行某种操作的键的名字;
&&&&&&&& 可以通过配置,使Redis仅发送某一类我们感兴趣的通知。
& & & & &因键空间通知功能需要耗费一定的CPU时间,因此默认情况下,该功能是关闭的。可以通过修改配置文件redis.conf,或者通过CONFIG SET命令,设置notify-keyspace-events选项,来启用或关闭该功能。
&&&&&&&& 该选项的值为空字符串时,该功能禁用,选项值为非空字符串时,启用该功能,非空字符串由特定的多个字符组成,每个字符表示不同的意义:
& & & & &K:keyspace事件,事件以__keyspace@&db&__为前缀进行发布;
& & & & &E:keyevent事件,事件以__keyevent@&db&__为前缀进行发布;
& & & & &g:一般性的,非特定类型的命令,比如del,expire,rename等;
& & & & &$:字符串特定命令;
& & & & &l:列表特定命令;
& & & & &s:集合特定命令;
& & & & &h:哈希特定命令;
& & & & &z:有序集合特定命令;
& & & & &x:过期事件,当某个键过期并删除时会产生该事件;
& & & & &e:驱逐事件,当某个键因maxmemore策略而被删除时,产生该事件;
& & & & &A:g$lshzxe的别名,因此”AKE”意味着所有事件。
&&&&&&&& 注意,该选项的值中至少需要包含K或者E,否则不会发布任何事件。比如,如果需要开启针对列表的keyspace事件通知,则该选项需要配置为“Kl”;
三:不同命令产生的事件通知
& & & & &DEL&命令为每个被删除的键产生一个&del&事件;
& & & & &RENAME&产生两个事件:为源键产生一个&rename_from&事件,并为目标键产生一个&rename_to&事件;
& & & & &EXPIRE命令,在设置键的过期时间时产生一个&expire事件;当键因过期而被删除时,产生一个&expired事件;
& & & & &SORT命令,在带有&STORE&参数时产生一个&sortstore事件。如果&STORE&指示的用于保存排序结果的键已经存在,则原键会被删除,因此还会产生一个&del&事件;
& & & & &SET&以及它的所有变种(SETEX、SETNX和GETSET)都产生set事件。另外,SETEX命令还会产生expire&事件;
& & & & &MSET&命令,为每个键产生一个&set&事件;
& & & & &SETRANGE&产生一个&setrange&事件;
& & & & &INCR&、DECR、INCRBY和DECRBY都产生&incrby&事件;
& & & & &INCRBYFLOAT产生incrbyfloat事件;
& & & & &APPEND产生append事件;
& & & & &LPUSH和LPUSHX都产生单个&lpush&事件,即使有多个输入元素时,也是如此;
& & & & &RPUSH&和&RPUSHX&都产生单个rpush事件,即使有多个输入元素时,也是如此;
& & & & &RPOP&产生&rpop&事件,如果被弹出的元素是列表的最后一个元素,那么还会产生一个&del&事件;
& & & & &LPOP&产生&lpop&事件,如果被弹出的元素是列表的最后一个元素,那么还会产生一个&del&事件;
& & & & &LINSERT&产生一个&linsert&事件;
& & & & &LSET&产生一个&lset&事件;
& & & & &LREM产生一个lrem事件,如果该命令执行之后,列表键被清空,则还会产生一个&del&事件;
& & & & &LTRIM&产生一个ltrim事件,如果该命令执行之后,列表键被清空,则还会产生一个&del&事件;
& & & & &RPOPLPUSH&和&BRPOPLPUSH&产生一个&rpop&事件,以及一个&lpush&事件。两个命令都保证rpop事件在&lpush&事件之前发出。如果弹出元素之后,列表键被清空,则还会产生一个&del&事件;
& & & & &HSET&、&HSETNX&和&HMSET&都只产生一个&hset&事件;
& & & & &HINCRBY&产生一个&hincrby&事件;
& & & & &HINCRBYFLOAT&产生一个&hincrbyfloat&事件;
& & & & &HDEL&产生一个&hdel&通知。如果执行该命令之后,哈希键被清空,则还会产生一个del事件;
& & & & &SADD&产生一个&sadd&事件,即使有多个输入元素时,也是如此;
& & & & &SREM&产生一个&srem&事件,如果执行该命令之后,集合键被清空,则还会产生一个&del&事件;
& & & & &SMOVE&为源键产生一个&srem&事件,并为目标键产生一个sadd&事件;
& & & & &SPOP&产生一个&spop&事件。如果执行该命令之后,集合键被清空,则还会产生一个&del&事件;
& & & & &SINTERSTORE、SUNIONSTORE和SDIFFSTORE分别产生&sinterstore、sunionostore和sdiffstore&三种事件。如果用于保存结果的键已经存在,则还会产生一个&del&事件;
& & & & &ZINCR产生一个&zincr&事件;
& & & & &ZADD&产生一个&zadd事件,即使有多个输入元素时,也是如此;
& & & & &ZREM&产生一个&zrem&通知,即使有多个输入元素时,也是如此。如果执行&ZREM&之后,有序集合键被清空,则还会产生一个&del&事件;
& & & & &ZREMEBYSCORE&产生一个&zrembyscore事件,如果用于保存结果的键已经存在,则还会产生一个&del&事件。
& & & & &ZREMBYRANK&产生一个&zrembyrank事件,如果用于保存结果的键已经存在,则还会产生一个&del&事件。
& & & & &ZINTERSTORE&和&ZUNIONSTORE&分别产生&zinterstore&和&zunionstore&两种事件。如果用于保存结果的键已经存在,那么还会产生一个&del&事件。
& & & & &每当一个键因为过期而被删除时,产生一个&expired&事件。
& & & & &每当一个键因为&maxmemory策略而被删除并回收内存时,产生一个&evicted&事件。
& & & & &注意:所有命令都只在键真的被改动了之后,才会产生事件通知。比如,当srem命令试图删除不存在于集合的元素时,删除操作执行失败,因为没有真正的改动键,所以这一操作不会发送通知。
四:expired事件通知的发送时间
& & & & &Redis 使用以下两种方式删除过期的键:
& & & & &a:当一个键被访问时,程序会对这个键进行检查,如果键已过期,则删除该键;
& & & & &b:系统会在后台定期扫描并删除那些过期的键;
& & & & &当过期键被以上两种方式中的任意一种发现并且删除时,才会产生expired事件通知。
& & & & &Redis不保证生存时间(TTL)变为&0&的键会立即被删除:如果没有命令访问这个键,或者设置生存时间的键非常多的话,那么在键的生存时间变为0,到该键真正被删除,这中间可能会有一段比较显著的时间间隔。
& & & & &因此,Redis产生expired事件通知的时间,是过期键被删除的时候,而不是键的生存时间变为&0&的时候。
& & & & &1:Redis发布所有通知,客户端A订阅所有消息:
127.0.0.1:6379& config set notify-keyspace-events KEA
127.0.0.1:6379& psubscribe __key*@0__:*
Reading messages... (press Ctrl-C to quit)
1) &psubscribe&
2) &__key*@0__:*&
3) (integer) 1
&&&&&&&& 然后,在客户端B上执行set和del命令:
127.0.0.1:6379& set msg &hello&
127.0.0.1:6379& del msg
(integer) 1
127.0.0.1:6379& del msg
(integer) 0
&&&&&&&& 然后客户端A的打印如下:
1) &pmessage&
2) &__key*@0__:*&
3) &__keyspace@0__:msg&
1) &pmessage&
2) &__key*@0__:*&
3) &__keyevent@0__:set&
1) &pmessage&
2) &__key*@0__:*&
3) &__keyspace@0__:msg&
1) &pmessage&
2) &__key*@0__:*&
3) &__keyevent@0__:del&
&&&&&&&& 可见,针对每一个操作,客户端A都收到了两种消息,分别是keyspace和keyevent消息。
& & & & &2:使Redis仅发布keyspace通知,而客户端A订阅所有消息类型:
127.0.0.1:6379& config set notify-keyspace-events KA
127.0.0.1:6379& psubscribe __key*@0__:*
Reading messages... (press Ctrl-C to quit)
1) &psubscribe&
2) &__key*@0__:*&
3) (integer) 1
&&&&&&&& 在客户端B上执行,与上面同样的步骤。此时,客户端A上的打印:
1) &pmessage&
2) &__key*@0__:*&
3) &__keyspace@0__:msg&
1) &pmessage&
2) &__key*@0__:*&
3) &__keyspace@0__:msg&
&&&&&&&& 可见,尽管客户端A订阅了所有消息,但是Redis仅发布了keyspace事件。而且,在客户端B上执行了两次del操作,而只有第一个del成功执行了,从而产生了一个事件。
& & & & &3:Redis发布所有通知,客户端A仅订阅keyspace消息:
127.0.0.1:6379& config set notify-keyspace-events KEA
127.0.0.1:6379& psubscribe __keyspace@0__:*
Reading messages... (press Ctrl-C to quit)
1) &psubscribe&
2) &__keyspace@0__:*&
3) (integer) 1
& & & & &在客户端B上,执行与上面同样的步骤。然后客户端A的打印如下:
1) &pmessage&
2) &__keyspace@0__:*&
3) &__keyspace@0__:msg&
1) &pmessage&
2) &__keyspace@0__:*&
3) &__keyspace@0__:msg&
&&&&&&&& 可见,针对每一个操作,客户端A只收到了keyspace消息。
& & & & &4:Redis仅发布字符串特定类型的通知,客户端A订阅所有类型的消息:
127.0.0.1:6379& config set notify-keyspace-events KE$
127.0.0.1:6379&
psubscribe __key*@0__:*
Reading messages... (press Ctrl-C to quit)
1) &psubscribe&
2) &__key*@0__:*&
3) (integer) 1
& & & & &在客户端B上,分别执行lpush,set和del命令:
127.0.0.1:6379& lpush alist 1 2 3
(integer) 3
127.0.0.1:6379& set msg &hello&
127.0.0.1:6379& del msg
(integer) 1
& & & & &此时,客户端A上的打印:
1) &pmessage&
2) &__key*@0__:*&
3) &__keyspace@0__:msg&
1) &pmessage&
2) &__key*@0__:*&
3) &__keyevent@0__:set&
& & & & &可见,针对字符串,产生了keyspace和keyevent类型的消息,而针对列表的lpush命令并没有产生消息,而且,del命令是非特定类型的命令,也没有产生消息。
& & & & &/article/15/.html
& & & & &http://redis.io/topics/notifications
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:62483次
积分:2664
积分:2664
排名:第9810名
原创:187篇
转载:44篇
译文:15篇
评论:11条
(3)(9)(5)(4)(6)(11)(4)(5)(12)(8)(9)(16)(16)(18)(47)(24)(22)(5)(7)(1)(2)(10)(4)本文将有助于你找出Redis 响应延迟的问题所在。
文中出现的延迟(latency)均指从发出一条命令到客户端接受到该命令的反馈所用的最长响应时间。Reids通常处理(命令的)时间非常的慢,大概在次微妙范围内,但也有更长的情况出现。
计算延迟时间
如果你正在经历响应延迟问题,你或许能够根据应用的具体情况算出它的延迟响应时间,或者你的延迟问题非常明显,宏观看来,一目了然。不管怎样吧,用redis-cli可以算出一台Redis 的到底延迟了多少毫秒。踹这句:
redis-cli --latency -h `host` -p `port`
和通信引起的延迟
当用户连接到Redis通过TCP/IP连接或Unix域连接,千兆网络的典型延迟大概200us,而Unix域socket可能低到30us。这完全基于你的网络和系统硬件。在通信本身之上,系统增加了更多的延迟(线程调度,CPU缓存,NUMA替换等等)。系统引起的延迟在环境远远高于在物理机器环境。
实际情况是即使Redis处理大多数命令在微秒之下,客户机和服务器之间的交互也必然消耗系统相关的延迟。
一个高效的客户机因而试图通过捆绑多个命令在一起的方式减少交互的次数。服务器和大多数客户机支持这种方式。聚合命令象MSET/MGET也可以用作这个目的。从Redis 2.4版本起,很多命令对于所有的数据类型也支持可变参数。
这里有一些指导:
如果你负担的起,尽可能的使用物理机而不是虚拟机来做服务器
不要经常的connect/disconnect与服务器的连接(尤其是对基于web的应用),尽可能的延长与服务器连接的时间。
如果你的客户端和服务器在同一台主机上,则使用Unix域套接字
尽量使用聚合命令(MSET/MGET)或可变参数命令而不是pipelining
如果可以尽量使用pipelining而不是序列的往返命令。
针对不适合使用原始pipelining的情况,如某个命令的结果是后续命令的输入,在以后的版本中redis提供了对服务器端的lua的支持,实验分支版本现在已经可以使用了。
在上,你可以通过process placement(taskset)、cgroups、real-time priorities(chrt)、NUMA(numactl)或使用低延迟的方式来获取较低的延迟。请注意Redis&并不适合被绑到单个CPU核上。redis会在后台创建一些非常消耗CPU的进程,如bgsave和AOF重写,这些任务是绝对不能和主事件循环进程放在一个CPU核上的。
大多数情况下上述的优化方法是不需要的,除非你确实需要并且你对优化方法很熟悉的情况下再使用上述方法。
Redis的单线程属性
Redis 使用了单线程的设计, 意味着单线程服务于所有的客户端请求,使用一种复用的。这种情况下redis可以在任何时候处理单个请求, 所以所有的请求是顺序处理的。这和Node.js的工作方式很像, 所有的产出通常不会有慢的感觉,因为处理单个请求的时间非常短,但是最重要的是这些被设计为非阻塞系统调用,比如从套接字中读取或写入数据。
我提到过Redis从2.4版本后几乎是单线程的,我们使用线程在后台运行一些效率低下的I/O操作, 主要关系到硬盘I/O,但是这不改变Redis使用单线程处理所有请求的事实。
低效操作产生的延迟
单线程的一个结果是,当一个请求执行得很慢,其他的客户端调用就必须等待这个请求执行完毕。当执行GET、SET或者 LPUSH 命令的时候这不是个问题,因为这些操作可在很短的常数时间内完成。然而,对于多个的操作,像SORT, LREM, SUNION&这些,做两个大数据集的交叉要花掉很长的时间。
文档中提到了所有操作的算法复杂性。 在使用一个你不熟悉的命令之前系统的检查它会是一个好办法。
如果你对延迟有要求,那么就不要执行涉及多个元素的慢操作,你可以使用Redis的replication功能,把这类慢操作全都放到replica上执行。
可以用Redis 的来监控慢操作。
此外,你可以用你喜欢的进程监控程序(top, htop, prstat, 等...)来快速查看Redis进程的CPU使用率。如果traffic不高而CPU占用很高,八成说明有慢操作。
延迟由k产生
Redis不论是为了在后台生成一个RDB文件,还是为了当AOF持久化方案被开启时重写Append>系统总是要应对内存不足的压力,因为每个运行的进程都想申请更多的物理内存,而这些申请的内存的数量往往超过了实际拥有的内存。简单来说就是redis使用的内存总是比可用的内存数量更多。
redis实例的数据,或者部分数据可能就不会被客户端访问,所以系统可以把这部分闲置的数据置换到硬盘上。需要把所有数据都保存在内存中的情况是非常罕见的。
一些进程会产生大量的读写I/O。因为文件通常都有缓存,这往往会导致文件缓存不断增加,然后产生交换(swap)。请注意,redis RDB和AOF后台线程都会产生大量文件。
所幸Linux提供了很好的工具来诊断这个问题,所以当延迟疑似是swap引起的,最简单的办法就是使用Linux提供的工具去确诊。
首先要做的是检查swap到硬盘上的redis内存的数量,为实现这个目的要知道redis实例的进程id:
$ redis-cli info | grep process_id
process_id:5454
进入进程目录:
$ cd /proc/5454
在这里你会发现一个名为smaps&的文件,它描述了redis进程的内存布局&(假定你使用的是Linux 2.6.16或者更新的版本)。这个文件包括了很多进程所使用内存的细节信息,其中有一项叫做Swap的正是我们所关心的。不过仅看这一项是不够的,因为smaps文件包括有redis进程的多个不同的的内存映射区域的使用情况(进程的内存布局远不是线性排列那么简单)。
从我们对所有进程的内存交换情况感兴趣以来,我们首先要做的事情是使用grep命令显示进程的smaps文件
$ cat smaps | grep 'Swap:'
0 kB 假如所有的数据显示为0kb或者某些数据偶尔显示为4kb,表示当前一切正常。实际上我们的例子是一个真实的运行着Redis并每秒为数百的用户提供服务的,会显示更多的交换页。为了研究是否存在一个严重的问题,我们改变命令打印出分配的内存尺寸
$ cat smaps | egrep '^(Swap|Size)'
0 kB 在输出信息中,你能看到有一个720896kb的内存分配(有12kb的交换)还有一个156kb的交换是另一个进程的。基本上我们的内存只会有很小的内存交换,因此不会产生任何的问题 假如进程的内存有相当部分花在了swap上,那么你的延迟可能就与swap有关。假如redis出现这种情况那么可以用 vmstat 命令来验证一下猜测:
$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- --- ----cpu----
cs us sy id wa
输出中我们最感兴趣的两行是si 和 so,这两行分别统计了从swap文件恢复到内存的数量和swap到文件的内存数量。如果在这两行发现了非0值那么就说明系统正在进行swap。
最后,可以用iostat命令来查看系统的全局I/O行为。
$ iostat -xk 1
%nice %system %iowait
wkB/s avgrq-sz avgqu-sz
如果确认延迟是由于swap引起的,那么就需要减小系统的内存压力,要么给机器增加内存,要么不要在同一个机器上运行其他消耗内存的程序。
AOF 和硬盘I/O操作延迟
另一个延迟的根源是Redis的AOF(仅附加文件)模式。AOF基本上是通过两个系统间的调用来完成工作的。 一个是写,用来写数据到AOF, 另外一个是文件数据同步,通过清除硬盘上空核心文件的缓冲来保证用户指定的持久级别。
包括写和文件数据同步的调用都可以导致延迟的根源。 写实例可以阻塞系统范围的同步操作,也可以阻塞当输出的缓冲区满并且内核需要清空到硬盘来接受新的写入的操作。
文件数据同步对于延迟的影响非常大,因为它涉及到好几步调用,可能要花掉几毫秒以致几秒的时间,特别是在还有其他进程后也在占用I/O的情况下。因为这个原因,从redis2.4开始用一个单独的线程来做文件数据同步。
我们来看看当使用AOF的时候如何配置来降低延迟。
通过设置AOF相关的appendfsync项,可以使用三种不同的方式来同步(也可以在运行时使用CONFIG SET&命令来修改这个配置)。
appendfsync 的值设置为no,redis不执行fsync。这种情况下造成延迟的唯一原因就是写操作。这种延迟没有办法可以解决,因为redis接收到数据的速度是不可控的,不过这种情况也不常见,除非有其他的进程占用I/O使得硬盘速度突然下降。
appendfsync 的值设置为everysec,每秒都会执行fsync。fsync 由一个单独线程执行,如果需要写操作的时候有fsync正在执行redis就会用一个buffer来延迟写入2秒(因为在Linux如果一个fsync 正在运行那么对该文件的写操作就会被堵塞)。如果fsync 耗时过长(译者注:超过了2秒),即使fsync 还在进行redis也会执行写操作,这就会造成延迟。
appendfsync 的值设置为always&,fsync 会在每次写操作返回成功之前执行(事实上redis会积累多个命令在一次fsync 过程中执行)。这种模式下的性能表现是非常差劲的,所以最好使用一个快速的磁盘和文件系统以加快fsync 的执行。
大多数redis用户都会把这个值设成&no&或者&everysec。要减少延迟,最好避免在同一个机器上有其他耗费I/O的程序。用SSD也有益于降低延迟,不过即使不使用SSD,如果能有冗余的硬盘专用于AOF也会减少寻址时间,从而降低延迟。
如果你想诊断AOF相关的延迟原因可以使用strace 命令:
sudo strace -p $(pidof redis-server) -T -e trace=fdatasync
上面的命令会展示redis主线程里所有的fdatasync系统调用。不包括后台线程执行的fdatasync 调用。如果appendfsync 配置为everysec,则给strace增加-f选项。
用下面命令可以看到fdatasync和write调用:
sudo strace -p $(pidof redis-server) -T -e trace=fdatasync,write
不过因为write也会向客户端写数据,所以用上面的命令很可能会获得许多与磁盘I/O没有关系的结果。似乎没有办法让strace 只显示慢系统调用,所以要用下面的命令:
sudo strace -f -p $(pidof redis-server) -T -e trace=fdatasync,write 2&&1 | grep -v '0.0' | grep -v unfinished
数据过期造成的延迟
redis有两种方式来去除过期的key:
lazy&方式,在key被请求的时候才检查是否过期。 to be already expired.
active&方式,每0.1秒进行一次过期检查。
active过期模式是自适应的,每过100毫秒开始一次过期检查(每秒10次),每次作如下操作:
根据 REDIS_EXPIRELOOKUPS_PER_CRON 的值去除已经过期的key(是指如果过期的key数量超过了REDIS_EXPIRELOOKUPS_PER_CRON 的值才会启动过期操作,太少就不必了。这个值默认为10), evicting all the keys already expired.
假如超过25%(是指REDIS_EXPIRELOOKUPS_PER_CRON这个值的25%,这个值默认为10,译者注)的key已经过期,则重复一遍检查失效的过程。
REDIS_EXPIRELOOKUPS_PER_CRON 默认为10, 过期检查一秒会执行10次,通常在actively模式下1秒能处理100个key。在过期的key有一段时间没被访问的情况下这个清理速度已经足够了,所以&lazy模式基本上没什么用。1秒只过期100个key也不会对redis造成多大的影响。
这种算是自适应的,如果发现有超过指定数量25%的key已经过期就会循环执行。这个过程每秒会运行10次,这意味着随机样本中超过25%的key会在1秒内过期。
通常来讲如果有很多key在同一秒过期,超过了所有key的25%,redis就会阻塞直到过期key的比例下降到25%以下。
使用这种策略是为了避免清除过期key的过程占用太多内存,这种方法对系统几乎不会有不良影响,因为大量key同时到期并非是一种常见现象,不过如果用户使用了& 来设置过期时间的话也是有可能的。
总而言之: 要知道大量key同时过期会对系统延迟造成影响。
Redis 看门狗
Redis2.6版本引进了redis看门狗(watchdog),这是个调试工具用于诊断Redis的延迟问题
这个看门狗软件还是一个实验性功能,当用于生产环境时,请小心并做好备份工作,可能有意想不到的问题影响正常的redis服务。
当你没有更好的工具追踪问题时,可以使用它。
这个功能是这样工作的:
用户通过命令CONFIG SET开启软件看门狗
Redis启动监测程序监测自己的状态
如果Redis检测到服务器被某些操作阻塞了,并运行速度不够快,也许是因为延迟导致的,Redis就会在log文件中写入一份关于被阻塞服务器的底层监测数据报表
用户通过Redis
Group发送消息给人员,消息包括看门狗报表。
请注意,这项功能不能通过redis.conf文件开启,因为这项够能设计之初就是面向正在运行的服务器,而且只是为了调试程序。
如果要开启该功能,只需运行如下命令:
CONFIG SET watchdog-period 500 时间间隔以毫秒为单位。在上面的例子中,我指定了,当服务器检测到500毫秒或更大的延迟的时候,才记录延迟事件。最小的时间间隔是200毫秒。 当你运行完了软件看门狗,你可以通过设置时间间隔参数为0来关闭看门狗。需要注意的:记得关闭看门狗,因为开启看门狗太长时间并不是一个好主意。
以下的例子,你可以看到,当看门狗监测到延迟事件的时候,输出日志文件的内容:
[8547 | signal handler] ()
--- WATCHDOG TIMER EXPIRED ---
/lib/libc.so.6(nanosleep+0x2d) [0x7f16b5c2d39d]
/lib/libpthread.so.0(+0xf8f0) [0x7f16b5f158f0]
/lib/libc.so.6(nanosleep+0x2d) [0x7f16b5c2d39d]
/lib/libc.so.6(usleep+0x34) [0x7f16b5c62844]
./redis-server(debug+0x3e1) [0x43ab41]
./redis-server(call+0x5d) [0x415a9d]
./redis-server(processCommand+0x375) [0x415fc5]
./redis-server(processInputBuffer+0x4f) [0x4203cf]
./redis-server(readQueryFromClient+0xa0) [0x4204e0]
./redis-server(aeProcessEvents+0x128) [0x411b48]
./redis-server(aeMain+0x2b) [0x411dbb]
./redis-server(main+0x2b6) [0x418556]
/lib/libc.so.6(__libc_start_main+0xfd) [0x7f16b5ba1c4d]
./redis-server() [0x411099]
注意:例子中
DEBUG SLEEP 命令是用于阻塞服务器的。在不同的阻塞背景下,堆栈信息会有不同。
如果收集到多个看门狗的监测堆栈信息,我们鼓励你把这些信息发送到Redis Google Group:我们获得越多的信息,我们就越容易分析得到你的服务器到底有什么问题。
附录A:大内存页的实验
fork产生的延迟,可以通过大内存页来减缓,只是需要耗费更大的内存。下面的附录将详细描述在Linux内核中实现的这个功能。
虽然某些CPU会使用不同大小的页面。AMD和Intel CPU可以支持2MB的页面大小。这些页面有个别名,叫做“大页面”。某些可以实时地优化页面大小,透明地把小页面聚合成大页面。
在Linux系统,显式的huge page管理在2.6.16中得到支持,并且隐式透明的huge page管理也在2.6.38中得到支持。如果你的是最近的Linux发行版本(例如 RH6或者其派生版本),透明的huge page可以被开启,并且你可以使用包含这项够能的Redis版本。
这个是在Linux中,实验/使用huge page的最佳方法。
现在,如果运行旧版本的Linux(RH5, SLES 10-11, 或者其派生版本),不要害怕使用一些,Redis可以通过补丁来支持huge page。
第一步,阅读&。需要注意,这个补丁依赖于匿名mmap huge page的支持,这项功能只能从2.6.32之后才得到支持,所以这个方法不能用于旧的版本(RH5 ,SLES 10, 和其派生版本)
对于Redis 2.2 或者2.4,附带libc分配器,必须修改redis makefile,使Redis和进行连接。这个是最直接的
然后,系统必须配置为支持huge page
以下命令分配和创建 N个huge page:
$ sudo sysctl -w vm.nr_hugepages=&N&
以下命令huge page到文件系统
$ sudo mount -t hugetlbfs none /mnt/hugetlbfs 在所有的情况下,一旦Redis运行huge page(透明或者非透明),将会得到如下的好处:
由于fork引起的延迟将得到缓解。尤其是对超大的实例,尤其是在VM上运行的实例。
Redis速度得到提够,是因为CPU的转换旁视缓冲(TLB)更有效的缓存页面(例如命中率会更高)。不要期望有奇迹发生,性能至多只能提高一点。
&Redis内存不会再被换走,这样就能避免由于虚拟内存造成的不必的延迟。
很不幸,除了更多的复杂操作,还有redis使用huge page会带来一个明显的缺陷。COW机制的粒度是页面。伴随2MB页面,页面被后台操作修改的可能性是4KB页面的512倍。实际的内存需要后台存储,所以可能性会增加很多,尤其是,当写操作很随机,并且伴随很差的定位。通过huge page,使用两倍的内存,而存储将不再是理论的突发事件。它真的会发生。
完整的性能评估结果可以参阅.

我要回帖

更多关于 redis 网络延迟 的文章

 

随机推荐