.net core 3.1float转int_Redis小功能大用处total_net_output_bytes

由于诸多原因,现在已经很少能长篇大论介绍Redis的相关技术,但日常工作以及脑子中经常想整理和总结一些Redis的点点滴滴,既能帮助自己记录问题,又能帮助他人减少碰到类似问题,于是有个想法,准备写一个小的系列:Redis小功能大用处。

本文将介绍Redis 3后一个新的统计项total_net_output_bytes。

一、问题

之前有朋友问我,Redis统计的网络输出流量总值total_net_output_bytes和瞬时值instantaneous_output_kbps比实际机器统计的要高。(Redis版本3.2.3)

fb4b3f48e4567f221e2fc695557b9fab.png

经试验证明,确实如此:一个机器的输出网络流量远远小于几个Redis实例的。

1.单机Redis实例网络输出流量统计:

2ac3673d0cc24d157da93d5feef2fbea.png

2.单机整机网络输出流量统计:

02cd58d965af72db0dd2a79821e32ae3.png

一般碰到这类问题,习惯性的在源码里找下,看看到底是如何计算的。

二、网络输出流量计算

代码里搜server.stat_net_output_bytes,找到如下这个代码

1. networking.c的writeToClient函数:

将输出缓冲区数据通过socket发送给客户端,源码比较长:

/* Write data in output buffers to client
int writeToClient(int fd, client *c, int handler_installed) {
    ssize_t nwritten = 0, totwritten = 0;
    size_t objlen;
    size_t objmem;
    robj *o;

    while(clientHasPendingReplies(c)) {
        if (c->bufpos > 0) {
            nwritten = write(fd,c->buf+c->sentlen,c->bufpos-c->sentlen);
            if (nwritten <= 0) break;
            c->sentlen += nwritten;
            totwritten += nwritten;

            if ((int)c->sentlen == c->bufpos) {
                c->bufpos = 0;
                c->sentlen = 0;
            }
        } else {
            o = listNodeValue(listFirst(c->reply));
            objlen = sdslen(o->ptr);
            objmem = getStringObjectSdsUsedMemory(o);

            if (objlen == 0) {
                listDelNode(c->reply,listFirst(c->reply));
                c->reply_bytes -= objmem;
                continue;
            }

            nwritten = write(fd, ((char*)o->ptr)+c->sentlen,objlen-c->sentlen);
            if (nwritten <= 0) break;
            c->sentlen += nwritten;
            totwritten += nwritten;

            if (c->sentlen == objlen) {
                listDelNode(c->reply,listFirst(c->reply));
                c->sentlen = 0;
                c->reply_bytes -= objmem;
            }
        }
        server.stat_net_output_bytes += totwritten;
        if (totwritten > NET_MAX_WRITES_PER_EVENT &&
            (server.maxmemory == 0 ||
             zmalloc_used_memory() break;
    }
    .............忽略忽略忽略..............

2. 基础知识:

Redis为每个客户端配置了输入缓冲区和输出缓冲区,用户暂存发送的命令和返回的结果,其中输出缓冲区分为:普通客户端缓冲区、复制客户端缓冲区、pubsub客户端缓冲区,并且输出缓冲区内部分为bufpos用于缓存一些小结果集,另外设置一个队列缓存大结果:

(1) 小结果集:

typedef struct redisClient {

 // 缓存小结果集
 char buf[REDIS_REPLY_CHUNK_BYTES]
 int bufpos

}

8a104814fd4d2a8da5e75c09082f36a6.png

(2) 小结果集:

typedef struct redisClient {

 // 缓存队列
 list *reply

}

1f9a7f87b3c2960a3ecbc8a7aa87372c.png

三、Redis作者的低级失误:

server.stat_net_output_bytes记录从输出缓冲区累加的字节数,但3.2.3之前似乎放错了位置,导致过大。

可以想到这个bug肯定已经被提过并修复了(https://github.com/redis/redis/commit/d70ac1d1)

2bafe48f44be70b33f55cccd700b119c.png

四、其他

1.instantaneous_output_kbps:total_net_output_bytes是一个累计值,为了方便看到瞬时值提供了instantaneous_output_kbps,它在内部用采样的方法计算的,如果你比较懒,不乐意自己按一定时间计算差值,可以使用instantaneous_output_kbps。

instantaneous_output_kbps = (float)getInstantaneousMetric(STATS_METRIC_NET_OUTPUT)/1024,

/* Return the mean of all the samples. */
long long getInstantaneousMetric(int metric) {
    int j;
    long long sum = 0;

    for (j = 0; j         sum += server.inst_metric[metric].samples[j];
    return sum / STATS_METRIC_SAMPLES;
}

2.作用

该统计指标非常重要:通过对其监控,规划和防止打爆机器网卡(千兆、万兆)、找到bigkey(例如执行大的mget、hgetall、lrange等等)。

五、最后

希望自己有足够的时间学习和撰写文章,希望2021会更好。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值