Reids命令解析-RENAME
2017-06-26 19:23
211 查看
有一天开发突然照过来问,维萨我这个Redis实例这么慢呢?为什么这么慢,于是连上实例SLOWLOG 一看,这些慢日志都是大部分是RENMAE操作导致的,可是为什么RENAME操作会慢呢?不就是改个名字么? 难道它还做了别的事? 又或者学习Linux 的mv 操作? 先copy 再DEL ?
于是带着这个问题,问问来拜访一下REDIS源码,看看为什么RENAME操作会慢的?在Redis中RENAME相关命令有两个 rename、renamenx。
我们找到入库函数 server.c [struct redisCommand redisCommandTable[] = {}],定位到renameCommand,可以发现这两个命令后端都是调用同一个函数[ renameGenericCommand(c,N)],只是这个N这个值不同而已
所以问题就很简单了, 我们只需要知道 [renameGenericCommand] 这个函数到底做了什么操作即可,定位到这个函数不难发现,对于Rename 命令会做以下操作:
先对比 rename 中的两个KEY是不是一样,如果不相同则继续
对第一个KEY在db 中查找,如果存在则继续,并记录 value 对象地址
获取这个KEY 的过期时间,继续下一步
尝试着查找第二个KEY,如果第二个KEY存在则删除第二个KEY
把第二个KEY名字和第一个KEY的value 作为K-V 添加到DB中
如果第一个KEY有过期时间,则为该KEY设置过期时间
最后删除掉第一个KEY
精简过得源代码如下:
所以通过以上我们可以得到如下结论:
实际上RENAME = Query * 2 + ADD + [ DEL ] + [ EXPIRE ]
而对于RENAMENX = Query * 2 + ADD + [ EXPIRE ] ,这里一定没有DEL操作
对于内存数据库REDIS 来说, QUERY 、ADD 、EXPIRE 都是很快的,但是对于某些KEY DEL则不一定块,如果这个KEY的内存占用比较多,那么DEL 是个比较慢的过程。
OK,结论似乎有了, 那么需要进一步的来验证一下这个结论,怎么验证呢?很简单,我们可以GET 出来看看这个KEY 有多大, 或者使用 DEBUG OBJECT XXXKEY 看一下序列化后的内存大小。
OK,结论也有了,也验证了,看起来是 大KEY 惹的货啊, 那么对于我们怎么找到这些大KEY,如果进行删除,请查看我的前两篇文章 :)
于是带着这个问题,问问来拜访一下REDIS源码,看看为什么RENAME操作会慢的?在Redis中RENAME相关命令有两个 rename、renamenx。
我们找到入库函数 server.c [struct redisCommand redisCommandTable[] = {}],定位到renameCommand,可以发现这两个命令后端都是调用同一个函数[ renameGenericCommand(c,N)],只是这个N这个值不同而已
所以问题就很简单了, 我们只需要知道 [renameGenericCommand] 这个函数到底做了什么操作即可,定位到这个函数不难发现,对于Rename 命令会做以下操作:
先对比 rename 中的两个KEY是不是一样,如果不相同则继续
对第一个KEY在db 中查找,如果存在则继续,并记录 value 对象地址
获取这个KEY 的过期时间,继续下一步
尝试着查找第二个KEY,如果第二个KEY存在则删除第二个KEY
把第二个KEY名字和第一个KEY的value 作为K-V 添加到DB中
如果第一个KEY有过期时间,则为该KEY设置过期时间
最后删除掉第一个KEY
精简过得源代码如下:
void renameGenericCommand(client *c, int nx) { robj *o; long long expire; int samekey = 0; if (sdscmp(c->argv[1]->ptr,c->argv[2]->ptr) == 0) samekey = 1; if ((o = lookupKeyWriteOrReply(c,c->argv[1],shared.nokeyerr)) == NULL) return; if (samekey) return; incrRefCount(o); expire = getExpire(c->db,c->argv[1]); if (lookupKeyWrite(c->db,c->argv[2]) != NULL) { dbDelete(c->db,c->argv[2]); } dbAdd(c->db,c->argv[2],o); if (expire != -1) setExpire(c,c->db,c->argv[2],expire); dbDelete(c->db,c->argv[1]); }
所以通过以上我们可以得到如下结论:
实际上RENAME = Query * 2 + ADD + [ DEL ] + [ EXPIRE ]
而对于RENAMENX = Query * 2 + ADD + [ EXPIRE ] ,这里一定没有DEL操作
对于内存数据库REDIS 来说, QUERY 、ADD 、EXPIRE 都是很快的,但是对于某些KEY DEL则不一定块,如果这个KEY的内存占用比较多,那么DEL 是个比较慢的过程。
OK,结论似乎有了, 那么需要进一步的来验证一下这个结论,怎么验证呢?很简单,我们可以GET 出来看看这个KEY 有多大, 或者使用 DEBUG OBJECT XXXKEY 看一下序列化后的内存大小。
OK,结论也有了,也验证了,看起来是 大KEY 惹的货啊, 那么对于我们怎么找到这些大KEY,如果进行删除,请查看我的前两篇文章 :)
相关文章推荐
- net命令用法解析
- ping 命令工作原理详细解析
- Linux系统中关机命令详细解析
- DOS命令全解析(1)
- 完全解析MySQL数据库中Show命令用法
- DOS命令全解析(2)
- Linux系统中关机命令详细解析
- 命令模式(Command)解析例子
- Linux:用命令之make常见规则解析
- ping 命令工作原理详细解析
- rpm 命令解析参考(转)
- 特殊格式命令解析
- Linux中rename命令的用法
- DICOM命令集和数据集解析
- 用Viusal Basic命令操作目录解析
- ping 命令工作原理详细解析
- Apache源代码分析——命令表解析
- Linux中rename命令的用法
- 完全解析MySQL数据库中Show命令用法(网上资料整理)
- linux常用命令解析