Redis系列-慢查询、pipeline流水线和数据库

慢查询、pipeline流水线和数据库


本文将对Redis一些 相对冷门的知识点进行介绍,分别是慢查询、pipeline管道和数据库。
说明:本文引用Redis 源码版本为: 6.0.19

慢查询

在关系型数据库比如说Mysql中,慢查询日志是一种性能优化手段,通过开启慢查询日志,然后针对运行速度较慢的sql语句进行相应优化。实际上在Redis中也有类似的概念。
在Redis中,一条命令的生命周期大致是:客户端发送命令、命令排队、执行命令和回复结果。慢查询就发生在执行命令这个阶段。
具体执行命令的逻辑在server.c中的void call(client *c, int flags)函数中,以下是统计命令运行时间的代码

    start = server.ustime;   // 记录开始时间
    c->cmd->proc(c);   // 执行命令
    duration = ustime()-start;  // 统计运行命令占用的时间

而后进行相关判断

/* Log the command into the Slow log if needed, and populate the
     * per-command statistics that we show in INFO commandstats. */
    // 调用call的时候设置了慢查询且命令没有设置忽略慢查询
    if (flags & CMD_CALL_SLOWLOG && !(c->cmd->flags & CMD_SKIP_SLOWLOG)) {
        char *latency_event = (c->cmd->flags & CMD_FAST) ?
                              "fast-command" : "command";
        // 监测相关的命令
        latencyAddSampleIfNeeded(latency_event,duration/1000);
        // 根据执行时间,决定是否加入到慢查询队列中
        slowlogPushEntryIfNeeded(c,c->argv,c->argc,duration);
    }

具体慢查询命令相关的逻辑都在程序文件slowlog.c中。

/* Push a new entry into the slow log.
 * This function will make sure to trim the slow log accordingly to the
 * configured max length. */
void slowlogPushEntryIfNeeded(client *c, robj **argv, int argc, long long duration) {
    // 配置的慢查询阈值小于零,表示禁用慢查询日志
    if (server.slowlog_log_slower_than < 0) return; /* Slowlog disabled */
    if (duration >= server.slowlog_log_slower_than)  // 大于阈值
        listAddNodeHead(server.slowlog,
                        slowlogCreateEntry(c,argv,argc,duration));

    /* Remove old entries if needed. */
    // 超过配置的慢查询日志队列长度,移除
    while (listLength(server.slowlog) > server.slowlog_max_len)
        listDelNode(server.slowlog,listLast(server.slowlog));
}

本质上,slowlog是一个双向链表,加入的时候默认加载头部,默认去除链表的最后一个节点。

pipeline管道

pipeline管道是Redis提供的批量执行命令的功能。Redis的命令执行速度相对较快,可能比命令发送回复的时间还要短,这种情况下,Redis的性能瓶颈就在这个网络上了。而在管道机制下,客户端一次性发送一批命令给Redis执行,当然在服务端这些命令还是顺序执行,然后再一起打包返回。
管道技术也存在一些缺点,比如说不能保证原子性,并且如果命令过多,会占用大量内存。

数据库

我们都知道,在连接关系型数据库比如Mysql中,不但要指定数据库服务器服务的ip地址和端口号,可能还需要指定使用那个数据库database,实际上在Redis中也有类似的概念,只不过很多时候都是默认使用数据库db0。
在初始化redisserver中,会默认创建16个数据库,代码如下。16是由配置文件的databases字段决定的。

 /* Create the Redis databases, and initialize other internal state. */
    for (j = 0; j < server.dbnum; j++) {
        server.db[j].dict = dictCreate(&dbDictType,NULL);
        server.db[j].expires = dictCreate(&keyptrDictType,NULL);
        server.db[j].expires_cursor = 0;
        server.db[j].blocking_keys = dictCreate(&keylistDictType,NULL);
        server.db[j].ready_keys = dictCreate(&objectKeyPointerValueDictType,NULL);
        server.db[j].watched_keys = dictCreate(&keylistDictType,NULL);
        server.db[j].id = j;
        server.db[j].avg_ttl = 0;
        server.db[j].defrag_later = listCreate();
        listSetFreeMethod(server.db[j].defrag_later,(void (*)(void*))sdsfree);
    }

默认使用db0,但是可以通过select命令切换选中的数据库,命令实现逻辑如下

void selectCommand(client *c) {
    long id;

    if (getLongFromObjectOrReply(c, c->argv[1], &id,
        "invalid DB index") != C_OK)  // 提取数据库编号且完成校应
        return;

    if (server.cluster_enabled && id != 0) {  // 集群模式下只能使用db0
        addReplyError(c,"SELECT is not allowed in cluster mode");
        return;
    }
    if (selectDb(c,id) == C_ERR) {
        addReplyError(c,"DB index is out of range");
    } else {
        addReply(c,shared.ok);
    }
}

多数据库提高了管理数据的灵活性和可靠性,可以将不同类型的数据保存到不同数据库中。

参考

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值