網上有很多關于pos機流量卡號,Redis流量統(tǒng)計問題如何解的知識,也有很多人為大家解答關于pos機流量卡號的問題,今天pos機之家(m.afbey.com)為大家整理了關于這方面的知識,讓我們一起來看下吧!
本文目錄一覽:
1、pos機流量卡號
pos機流量卡號
背景近日有用戶反饋Redis的流量統(tǒng)計有問題,實際出口流量比客戶端監(jiān)察到的還大,通過監(jiān)控我們可以看到后端采集的Redis出口流量為以下圖表,其中單位為KByte每秒,所以我們可以看到內核統(tǒng)計的有10MB左右的流量。
我們后端天象系統(tǒng)會從協(xié)議棧層面統(tǒng)計每個Redis實例的流量情況,同一時刻圖表如下,我們可以發(fā)現出口流量在2MB左右,和Redis統(tǒng)計的有一定偏差。
Redis 流量統(tǒng)計原理后端監(jiān)控采集的Redis出口流量為info命令返回的instantaneous_output_kbps值,該值的計算方式為
(float)getInstantaneousMetric(STATS_METRIC_NET_OUTPUT)/1024
查看getInstantaneousMetric實現如下:
/* Return the mean of all the samples. */long long getInstantaneousMetric(int metric) { int j; long long sum = 0; for (j = 0; j < STATS_METRIC_SAMPLES; j++) sum += server.inst_metric[metric].samples[j]; return sum / STATS_METRIC_SAMPLES;}
我們可以看到出口流量是由server.inst_metric里面根據統(tǒng)計的類型得到的一個平均值,繼續(xù)查看server.inst_metric的計算函數為trackInstantaneousMetric實現如下:
/* Add a sample to the operations per second array of samples. */void trackInstantaneousMetric(int metric, long long current_reading) { long long t = mstime() - server.inst_metric[metric].last_sample_time; long long ops = current_reading - server.inst_metric[metric].last_sample_count; long long ops_sec; ops_sec = t > 0 ? (ops*1000/t) : 0; server.inst_metric[metric].samples[server.inst_metric[metric].idx] = ops_sec; server.inst_metric[metric].idx++; server.inst_metric[metric].idx %= STATS_METRIC_SAMPLES; server.inst_metric[metric].last_sample_time = mstime(); server.inst_metric[metric].last_sample_count = current_reading;}
trackInstantaneousMetric在serverCtron里面定時調用,代碼如下:
run_with_period(100) { trackInstantaneousMetric(STATS_METRIC_COMMAND,server.stat_numcommands); trackInstantaneousMetric(STATS_METRIC_NET_INPUT, server.stat_net_input_bytes); trackInstantaneousMetric(STATS_METRIC_NET_OUTPUT, server.stat_net_output_bytes);}
從以上函數我們可以看到流量的統(tǒng)計為定期對server.stat_net_output_bytes做統(tǒng)計計算得到的平均值,所以Redis出口流量計算的關鍵在于server.stat_net_output_bytes的計算,查看內核計算server.stat_net_output_bytes的代碼如下:
/* Return true if the specified client has pending reply buffers to write to* the socket. */int clientHasPendingReplies(client *c) { return c->bufpos || listLength(c->reply);}/* Write data in output buffers to client. Return C_OK if the client* is still valid after the call, C_ERR if it was freed. */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 the buffer was sent, set bufpos to zero to continue with * the remainder of the reply. */ 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 we fully sent the object on head go to the next one */ 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() < server.maxmemory)) break; } if (nwritten == -1) { if (errno == EAGAIN) { nwritten = 0; } else { serverLog(LL_VERBOSE, "Error writing to client: %s", strerror(errno)); freeClient(c); return C_ERR; } } if (totwritten > 0) { /* */ if (!(c->flags & CLIENT_MASTER)) c->lastinteraction = server.unixtime; } if (!clientHasPendingReplies(c)) { c->sentlen = 0; if (handler_installed) aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE); if (c->flags & CLIENT_CLOSE_AFTER_REPLY) { freeClient(c); return C_ERR; } } return C_OK;}
仔細分析以上代碼我們可以發(fā)現server.stat_net_output_bytes增加的totwritten的值會累加每次進入while循環(huán)的值,然后如果while循環(huán)多次執(zhí)行的情況下每次都會累加一次totwritten這個值,而這個值沒有復位,導致server.stat_net_output_bytes的值會重復計算之前的值,最終導致出口流量計算錯誤,我們可以將server.stat_net_output_bytes的計算移動到while循環(huán)外即可修復這個統(tǒng)計問題。根據以上分析修改內核重新查看監(jiān)控圖標如下,我們可以看到監(jiān)控的數值和天象采集到的數值基本一致了。
總結由于云數據庫的資源限制并非采用的server.stat_net_output_bytes的值,所以資源限制方面并不會由于原生內核的流量計算錯誤受到影響,目前這個問題已經提交了一個pull request給antirez等待官方確定合并修復。阿里云Redis致力于提供最好的云數據庫Redis服務,我們正在尋找有一樣志向的同學加入我們,有興趣的同學請猛擊鏈接:https://job.alibaba.com/zhaopin/position_detail.htm
以上就是關于pos機流量卡號,Redis流量統(tǒng)計問題如何解的知識,后面我們會繼續(xù)為大家整理關于pos機流量卡號的知識,希望能夠幫助到大家!
