zoukankan      html  css  js  c++  java
  • Reids命令解析-RENAME

    有一天开发突然照过来问,维萨我这个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 命令会做以下操作:

    1. 先对比 rename 中的两个KEY是不是一样,如果不相同则继续
    2. 对第一个KEY在db 中查找,如果存在则继续,并记录 value 对象地址
    3. 获取这个KEY 的过期时间,继续下一步
    4. 尝试着查找第二个KEY,如果第二个KEY存在则删除第二个KEY
    5. 把第二个KEY名字和第一个KEY的value 作为K-V 添加到DB中
    6. 如果第一个KEY有过期时间,则为该KEY设置过期时间
    7. 最后删除掉第一个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,如果进行删除,请查看我的前两篇文章 :)

  • 相关阅读:
    时间日期事件处理、长按事件
    单选按钮触发事件、下拉列表触发事件
    事件
    笔记3
    笔记2
    笔记1
    布局管理器
    08、shell三剑客之sed
    07、shell三剑客之grep
    06、shell正则表达式
  • 原文地址:https://www.cnblogs.com/svan/p/7082077.html
Copyright © 2011-2022 走看看