redis中scan命令的基本实现方法_Redis

来源:脚本之家  责任编辑:小易  

如果 MySQL 数据库比较大的话,我2113们很容易就能查出是5261哪些表占用的空间;不过如果4102 Redis 内存比较大的话1653,我们就不太容易查出是哪些(种)键占用的空间了。有一些工具能够提供必要的帮助,比如 redis-rdb-tools 可以直接分析 RDB 文件来生成报告,可惜它不能百分百实现我的需求,而我也不想在它的基础上二次开发。实际上开发一个专用工具非常简单,利用SCAN和DEBUG等命令,没多少行代码就能实现:<?php$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'];}break;}}}}var_dump($result);?>当然,前提是你需要提前总结出可能的键模式,简单但不严谨的方法是MONITOR:shell> /path/to/redis-cli monitor |awk -F '"' '$2 ~ "ADD|SET|STORE|PUSH" {print $4}'此外,需要注意的是:因为 DEBUG 返回的 serializedlength 是序列化后的长度,所以最终计算的值小于实际内存占用,但考虑到相对大小依然是有参考意义的,如果MySQL数据库比较大的话,2113我们很容易就能查出是哪5261些表占用的空间;不4102过如果Redis内存比较大的话,我们1653就不太容易查出是哪些(种)键占用的空间了。有一些工具能够提供必要的帮助,比如redis-rdb-tools可以直接分析RDB文件来生成报告,可惜它不能百分百实现我的需求,而我也不想在它的基础上二次开发。实际上开发一个专用工具非常简单,利用SCAN和DEBUG等命令,没多少行代码就能实现:<?php$patterns=array('foo:.+','bar:.+','.+',);$redis=newRedis();$redis->setOption(Redis::OPT_SCAN,Redis::SCAN_RETRY);$result=array_fill_keys($patterns,0);while($keys=$redis->scan($it,$match='*',$count=1000)){foreach($keysas$key){foreach($patternsas$pattern){if(preg_match("/^{$pattern}$/",$key)){if($v=$redis->debug($key)){$result[$pattern]+=$v['serializedlength'];}break;}}}}var_dump($result);?>当然,前提是你需要提前总结出可能的键模式,简单但不严谨的方法是MONITOR:shell>/path/to/redis-climonitor|awk-F'"''$2~"ADD|SET|STORE|PUSH"{print$4}'此外,需要注意的是:因为DEBUG返回的serializedlength是序列化后的长度,所以最终计算的值小于实际内存占用,但考虑到相对大小依然是有参考意义的,使用Redis的脚本功能实现Redis中数2113据简单查询5261,有需要的朋友可以参考4102下。在Redis的设计中,key是一切,对于Redis是可1653见的,而value对于Redis来说就是一个字节数组,Redis并不知道你的value中存储的是什么,www.zgxue.com防采集请勿采集本网。

前言

在一个天朗气清的日子,小灰登上了线上的redis打算查询数据。然而他只记得前缀而不知道整个键是多少,于是在命令行敲入了“keys xxx*”命令。

这样的查询,在Redis是没办法通过value进行比较得出结果的。 但是可以通过不同的数据结构类型来做到这一点,比如如下的数据定义: users:1 {name:Jack,age:28,location:shanghai}users:2 {name:Frank,age:30,location:beijing}users:location:sh

瞬间服务卡死,报警邮件堆满了邮箱,而小灰,只能目瞪狗呆的等待着即将降临的case study。

1、Redis Get 命令用于获取指定 key 的值。如果 key 不存在,返回 nil 。如果key 储存的值不是字符串类型,返回一个错误。 2、语法 redis Get 命令基本语法如下: redis 127.0.0.1:6379> GET KEY_NAME 可用版本 >= 1.0.0 3、返回值 返回 key 的

基本上,keys *命令都是在线上是被运维禁止的。

redis主从复制总结整理 主题 Redis Redis的主从复制策略是通过其持久化的rdb文件来实现的,其过程是先dump出rdb文件,将rdb文件全量传输给slave,然后再将dump后的操作实时同步到slave中。让从服务器(slave server)成为主服务器(master server)

redis的键在键值对大小大于hash-max-ziplist-value且个数小于hash-max-ziplist-entries的时候,是存放在散列表数据结构中的,在运行keys命令的时候,需要遍历数据库键空间,把所有键都取出来后与keys后面的pattern匹配。

Redis Pgmerge 命令将多个 HyperLogLog 合并为一个 HyperLogLog ,合并后的 HyperLogLog 的基数估算值是通过对所有 给定 HyperLogLog 进行并集计算得出的。 语法 redis Pgmerge 命令基本语法如下: redis 127.0.0.1:6379> PFMERGE destkey sourc

在键很多的情况下,redis可能的卡顿会在秒级以上,导致所有流量都打到数据库,使得数据库雪崩。

1、如果是用apt-get或者yum install安装的redis,可以直接通过下面的命令停止/启动/重启redis:/etc/init.d/redis-server stop/etc/init.d/redis-server start/etc/init.d/redis-server restart 2、如果是通过源码安装的redis,则可以通过redis

那我们怎么才能够在查找到目标键呢?在redis2.8.0的时候加入了scan命令,可以分批次扫描redis键。虽然在应用的时候会使得要查询到全部符合要求的key的时间变长,但是大大大大减少了redis卡顿的几率

在这里先补充一下背景:

redis中的字典rehash是渐进式哈希,即不是一次性把所有的键都迁移到新的哈希表,而是在下面两种情况下迁移数据:

每次哈希表操作的时候,如果当前正在rehash,则迁移一个节点;

服务空闲时,会rehash一百个节点。

scan命令可以保证在(没有键修改的)字典正在rehash的过程中做到以下两点: 不出现重复数据 不遗漏数据

那scan命令是怎么做到在rehash过程中都能不重复不遗漏地遍历所有节点的呢?让我们来一起走读一下源码。

Let's GO!

在使用scan命令的时候,我们每次传入一个游标(从0开始),然后下一轮继续使用本轮redis返回的游标。scan字典的核心函数是dictScan,而dictScan的更新游标的核心代码如下:

v |= ~m0;//或者m1/* Increment the reverse cursor */v = rev(v);v++;v = rev(v);

其中m0、m1为当前哈希表大小减一,rev是二进制逆序。

看到这里,不知道在座的各位是不是也是跟我一样是下面这个表情

让我们来模拟一下问题,就清楚了。

我们假设现在在一个四个节点的哈希表中遍历,如下图,游标的遍历节点为:0 -> 2 -> 1 -> 3 :

再来模拟8节点的情况:

看到这里是不是稍微明白了,上面那段代码就是在当前的有效位数(比如四节点则有效位数2)范围内,从左到右进一位。

假设在遍历了0,返回2之后,字典进行了扩容,则接下来应该访问 2 -> 6 -> 1 -> 5 -> 3 -> 7。

小灰:咦,那4不是遗漏了吗?

4已经在第一轮遍历0的时候,把扩容后的4的数据也访问了。

所以,假设扩容前有效位为m,因为redis的哈希表扩容每次都是当前节点满了( use==size)的时候扩容为大于size的2^N,所以扩容后有效位则为m+1。

上面那段代码其实是保持低位的m位不变,高位一个为0一个为1。这样就保证了扩容后,跳过了的节点已经在之前被访问过,因为跳过的节点是被访问过的节点分出来的。

缩容同理,可以自己推一下。

看到这里,是不是觉得redis的scan游标设计的很巧妙呢?

小灰:原来如此,看来我又可以去查数据了呢!

最后附上完整的rehash过程中scan的代码:

// 指向两个哈希表t0 = &d->ht[0];t1 = &d->ht[1];/* Make sure t0 is the smaller and t1 is the bigger table */// 确保 t0 比 t1 要小if (t0->size > t1->size) { t0 = &d->ht[1]; t1 = &d->ht[0];}// 记录掩码m0 = t0->sizemask;m1 = t1->sizemask;/* Emit entries at cursor */// 指向桶,并迭代桶中的所有节点de = t0->table[v & m0];while (de) {//迭代第一张小hash表 next = de->next; fn(privdata, de); de = next;}/* Iterate over indices in larger table that are the expansion * of the index pointed to by the cursor in the smaller table */do {//迭代第二张大hash表 /* Emit entries at cursor */ if (bucketfn) bucketfn(privdata, &t1->table[v & m1]); de = t1->table[v & m1]; while (de) { next = de->next; fn(privdata, de); de = next; } //计算一个哈希表节点索引的方法 是 hash(key)&mask。哈希表容量为 8,则 mask 为 111,因此,节点的索引值就取决于哈希值的低 3 bit, // 设索引值是 abc。如果哈希表容量为 16,则 mask 为 1111,该节点的哈希值不变,而索引值是 ?abc,其中 ? 取 0 或 1 中的一个, // 也就是说,该节点在容量为 16 的哈希表中,索引要么是 0abc 要么是 1abc。以此类推,如果哈希表容量为32, // 则该节点的索引可能是 00abc,01abc,10abc 或者 11abc 中的一个。/* Increment the reverse cursor not covered by the smaller mask.*/ v |= ~m1;//用于保留 v 的低 n 位数,其余位全置为 1 //下面这一段,最终得到的新 v,就是向最高位加 1,且向低位方向进位 v = rev(v);//将 v 的二进制位进行翻转,所以,v的低 n 位数成了高 n 位数,并且进行了翻转 v++; v = rev(v);//再次二进制翻转 /* Continue while bits covered by mask difference is non-zero */} while (v & (m0 ^ m1));//终止条件是 v的高位区别位没有1了,其实就是说到头了。

总结

到此这篇关于redis中scan命令的基本实现方法的文章就介绍到这了,更多相关redis中scan命令实现内容请搜索真格学网以前的文章或继续浏览下面的相关文章希望大家以后多多支持真格学网! 您可能感兴趣的文章:Redis中scan命令的深入讲解php redis扩展支持scan命令实现方法Redis中Scan命令的基本使用教程详解Redis SCAN命令实现有限保证的原理Redis Scan命令的基本使用方法Redis中Scan命令的踩坑实录

首先肯定是打开一个控2113制台,在windows系统打开5261控制台的方式很多,我喜欢通4102过使用快捷方式“1653win+R”打开“运行”,输入“cmd”来打开控制台。在控制台输入命令redis-cli这将打开一个Redis提示127.0.0.1:6379>表示已经链接上ip:127.0.0.1,端口:6379的Redis服务了我们可以使用“PING”命令来检查Redis是否在工作,如下所示:127.0.0.1:6379> PINGPONG127.0.0.1:6379>表示Redis运行正常内容来自www.zgxue.com请勿采集。


  • 本文相关:
  • redis中事务机制及乐观锁的实现
  • redis教程(十):持久化详解
  • redis字符串原理的深入理解
  • 谈谈redis分布式锁的正确实现方法
  • redis的主从同步解析
  • python的flask框架使用redis做数据缓存的配置方法
  • win10下 redis启动 错误1067导致进程意外终止的解决方法
  • 深入理解redis分布式锁和消息队列
  • php结合redis实现高并发下的抢购、秒杀功能的实例
  • redis中键值过期操作示例详解
  • redis 命令在redis中怎么执行的
  • 如何统计Redis中各种数据的大小
  • redis sscan方法会全盘扫描吗
  • 如何批量删除Redis下特定pattern的keys?
  • redis里的hash类型怎么查询value?
  • redis 命令get什么意思
  • redis主从复制最好采用哪种结构
  • 如何将多个redis查询命令合并成一个执行
  • redis 如何重启? linux下请输入命令不要用kill 的方式
  • 如何对redis做测试
  • 网站首页网页制作脚本下载服务器操作系统网站运营平面设计媒体动画电脑基础硬件教程网络安全mssqlmysqlmariadboracledb2mssql2008mssql2005sqlitepostgresqlmongodbredisaccess数据库文摘数据库其它首页redis中scan命令的深入讲解php redis扩展支持scan命令实现方法redis中scan命令的基本使用教程详解redis scan命令实现有限保证的原理redis scan命令的基本使用方法redis中scan命令的踩坑实录redis中事务机制及乐观锁的实现redis教程(十):持久化详解redis字符串原理的深入理解谈谈redis分布式锁的正确实现方法redis的主从同步解析python的flask框架使用redis做数据缓存的配置方法win10下 redis启动 错误1067导致进程意外终止的解决方法深入理解redis分布式锁和消息队列php结合redis实现高并发下的抢购、秒杀功能的实例redis中键值过期操作示例详解超强、超详细redis数据库入门教程redis常用命令、常见错误、配置技redis操作命令总结redis中5种数据结构的使用场景介64位windows下安装redis教程redis中使用redis-dump导出、导入redis中统计各种数据大小的方法redis常用命令小结让redis在你的系统中发挥更大作用centos 6.6下redis安装配置记录redis set 集合的实例详解springsession+redis实现集群会话共享的方linux下redis安装配置教程redis中实现查找某个值的范围在redis数据库中实现分布式速率限制的方法redis源码解析:集群手动故障转移、从节点解锁redis锁的正确姿势redis 命令的详解及简单实例图文详解windows下使用redis缓存工具的方redis实现分布式的方法总结
    免责声明 - 关于我们 - 联系我们 - 广告联系 - 友情链接 - 帮助中心 - 频道导航
    Copyright © 2017 www.zgxue.com All Rights Reserved