<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ? ? ?今天講的這個是用來給redis數據庫做性能測試的,說到性能測試,感覺這必然是高大上的操作了,redis性能測試,測的到底是哪方面的性能,如何測試,通過什么指標反映此次測試的性能好壞呢,下面我通過源碼給大家做一一解答。 ? ?redis做的性能測試時對立面的基本操作做的檢測,比如Client客戶端執行set,get,lpush等數據操作的性能,可以從他的測試程序可以看出: ~~~ if (test_is_selected("get")) { len = redisFormatCommand(&cmd,"GET key:__rand_int__"); benchmark("GET",cmd,len); free(cmd); } if (test_is_selected("incr")) { len = redisFormatCommand(&cmd,"INCR counter:__rand_int__"); benchmark("INCR",cmd,len); free(cmd); } if (test_is_selected("lpush")) { len = redisFormatCommand(&cmd,"LPUSH mylist %s",data); benchmark("LPUSH",cmd,len); free(cmd); } if (test_is_selected("lpop")) { len = redisFormatCommand(&cmd,"LPOP mylist"); benchmark("LPOP",cmd,len); free(cmd); } ~~~ 那么通過什么指標反映測試性能的好壞之分呢,在這里我們使用的就是延時性來判斷,最簡單的想法,就是在測試到額最開始,記錄一個時間,中間執行測試操作,在操作結束在記錄一個時間,中間的時間差就是執行的時間,時間越短說明性能越好。這也正是redis性能測試的做法。 ~~~ /* 對指定的CMD命令做性能測試 */ static void benchmark(char *title, char *cmd, int len) { client c; config.title = title; config.requests_issued = 0; config.requests_finished = 0; c = createClient(cmd,len,NULL); createMissingClients(c); config.start = mstime(); aeMain(config.el); //最后通過計算總延時,顯示延時報告,體現性能測試的結果 config.totlatency = mstime()-config.start; showLatencyReport(); freeAllClients(); } ~~~ 因為這樣的操作要求時間精度比較高,用秒做單位肯定不行了,所以這里用的是ms毫秒,在這里添加個知識點,在這里用到了時間相關的結構體,在Linux里也存在: ~~~ /* 介紹一下struct timeval結構體 struct timeval結構體在time.h中的定義為: struct timeval { __time_t tv_sec; // Seconds. __suseconds_t tv_usec; // Microseconds. (微秒) }; */ ~~~ 那么下面是最關鍵的問題了,如何測,測試肯定要通過一個模擬客戶端,按照配置文件中的設置去測試,所以必須存在一個配置信息,然后我們通過我們想要的配置再去逐步測試,亮出config,配置信息: ~~~ /* config配置信息結構體,static靜態變量,使得全局只有一個 */ static struct config { //消息事件 aeEventLoop *el; const char *hostip; int hostport; //據此判斷是否是本地測試 const char *hostsocket; //Client總數量 int numclients; int liveclients; //請求的總數 int requests; int requests_issued; //請求完成的總數 int requests_finished; int keysize; int datasize; int randomkeys; int randomkeys_keyspacelen; int keepalive; int pipeline; long long start; long long totlatency; long long *latency; const char *title; //Client列表,這個在下面會經常提起 list *clients; int quiet; int csv; //判斷是否loop循環處理 int loop; int idlemode; int dbnum; sds dbnumstr; char *tests; char *auth; } config; typedef struct _client { //redis上下文 redisContext *context; //此緩沖區將用于后面的讀寫handler sds obuf; //rand指針數組 char **randptr; /* Pointers to :rand: strings inside the command buf */ //randptr中指針個數 size_t randlen; /* Number of pointers in client->randptr */ //randptr中沒有被使用的指針個數 size_t randfree; /* Number of unused pointers in client->randptr */ unsigned int written; /* Bytes of 'obuf' already written */ //請求的發起時間 long long start; /* Start time of a request */ //請求的延時 long long latency; /* Request latency */ //請求的等待個數 int pending; /* Number of pending requests (replies to consume) */ int selectlen; /* If non-zero, a SELECT of 'selectlen' bytes is currently used as a prefix of the pipline of commands. This gets discarded the first time it's sent. */ } *client; ~~~ 上面還附帶了client的一些信息,這里的Client和之前的RedisClient還不是一個東西,也就是說,這里的Client會根據config結構體中的配置做相應的操作。client根據獲得到命令無非2種操作,read和Write,所以在后面的事件處理中也是針對這2種事件的處理,這里給出read的方法: ~~~ /* 讀事件的處理方法 */ static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) { client c = privdata; void *reply = NULL; REDIS_NOTUSED(el); REDIS_NOTUSED(fd); REDIS_NOTUSED(mask); /* Calculate latency only for the first read event. This means that the * server already sent the reply and we need to parse it. Parsing overhead * is not part of the latency, so calculate it only once, here. */ //計算延時,然后比較延時,取得第一個read 的event事件 if (c->latency < 0) c->latency = ustime()-(c->start); if (redisBufferRead(c->context) != REDIS_OK) { //首先判斷能否讀 fprintf(stderr,"Error: %s\n",c->context->errstr); exit(1); } else { while(c->pending) { if (redisGetReply(c->context,&reply) != REDIS_OK) { fprintf(stderr,"Error: %s\n",c->context->errstr); exit(1); } if (reply != NULL) { //獲取reply回復,如果這里出錯,也會直接退出 if (reply == (void*)REDIS_REPLY_ERROR) { fprintf(stderr,"Unexpected error reply, exiting...\n"); exit(1); } freeReplyObject(reply); if (c->selectlen) { size_t j; /* This is the OK from SELECT. Just discard the SELECT * from the buffer. */ //執行到這里,請求已經執行成功,等待的請求數減1 c->pending--; sdsrange(c->obuf,c->selectlen,-1); /* We also need to fix the pointers to the strings * we need to randomize. */ for (j = 0; j < c->randlen; j++) c->randptr[j] -= c->selectlen; c->selectlen = 0; continue; } if (config.requests_finished < config.requests) config.latency[config.requests_finished++] = c->latency; c->pending--; if (c->pending == 0) { //調用客戶端done完成后的方法 clientDone(c); break; } } else { break; } } } } ~~~ 這個方法其實是一個回調方法,會作為參數傳入另一個函數中,redis的函數式編程的思想又再次體現了,在這些操作都執行好了之后,會有個延時報告,針對各種操作的延時統計,這時我們就能知道,性能之間的比較了: ~~~ /* 輸出請求延時 */ static void showLatencyReport(void) { int i, curlat = 0; float perc, reqpersec; reqpersec = (float)config.requests_finished/((float)config.totlatency/1000); if (!config.quiet && !config.csv) { printf("====== %s ======\n", config.title); printf(" %d requests completed in %.2f seconds\n", config.requests_finished, (float)config.totlatency/1000); printf(" %d parallel clients\n", config.numclients); printf(" %d bytes payload\n", config.datasize); printf(" keep alive: %d\n", config.keepalive); printf("\n"); //將請求按延時排序 qsort(config.latency,config.requests,sizeof(long long),compareLatency); for (i = 0; i < config.requests; i++) { if (config.latency[i]/1000 != curlat || i == (config.requests-1)) { curlat = config.latency[i]/1000; perc = ((float)(i+1)*100)/config.requests; printf("%.2f%% <= %d milliseconds\n", perc, curlat); } } printf("%.2f requests per second\n\n", reqpersec); } else if (config.csv) { printf("\"%s\",\"%.2f\"\n", config.title, reqpersec); } else { printf("%s: %.2f requests per second\n", config.title, reqpersec); } } ~~~ 當然你能更改配置文件,做你想做的性能測試,不過這里我想吐槽一點,這么多個if判斷語句不是很好吧,換成switch也比這簡潔啊: ~~~ /* Returns number of consumed options. */ /* 根據讀入的參數,設置config配置文件 */ int parseOptions(int argc, const char **argv) { int i; int lastarg; int exit_status = 1; for (i = 1; i < argc; i++) { lastarg = (i == (argc-1)); //通過多重if判斷,但個人感覺不夠優美,穩定性略差 if (!strcmp(argv[i],"-c")) { if (lastarg) goto invalid; config.numclients = atoi(argv[++i]); } else if (!strcmp(argv[i],"-n")) { if (lastarg) goto invalid; config.requests = atoi(argv[++i]); } else if (!strcmp(argv[i],"-k")) { if (lastarg) goto invalid; config.keepalive = atoi(argv[++i]); } else if (!strcmp(argv[i],"-h")) { if (lastarg) goto invalid; config.hostip = strdup(argv[++i]); } else if (!strcmp(argv[i],"-p")) { if (lastarg) goto invalid; config.hostport = atoi(argv[++i]); } else if (!strcmp(argv[i],"-s")) { if (lastarg) goto invalid; config.hostsocket = strdup(argv[++i]); } else if (!strcmp(argv[i],"-a") ) { if (lastarg) goto invalid; config.auth = strdup(argv[++i]); } else if (!strcmp(argv[i],"-d")) { if (lastarg) goto invalid; config.datasize = atoi(argv[++i]); if (config.datasize < 1) config.datasize=1; if (config.datasize > 1024*1024*1024) config.datasize = 1024*1024*1024; } else if (!strcmp(argv[i],"-P")) { if (lastarg) goto invalid; config.pipeline = atoi(argv[++i]); //......省略 ~~~ redis的性能測試還能支持本地測試和指定Ip,端口測試,挺方便的。下面列出全部的API: ~~~ /* Prototypes */ /* 方法原型 */ static void createMissingClients(client c); /* 創建沒有Command命令要求的clint */ static long long ustime(void) /* 返回當期時間的單位為微秒的格式 */ static long long mstime(void) /* 返回當期時間的單位為毫秒的格式 */ static void freeClient(client c) /* 釋放Client */ static void freeAllClients(void) /* 釋放所有的Client */ static void resetClient(client c) /* 重置Client */ static void randomizeClientKey(client c) /* 隨機填充client里的randptr中的key值 */ static void clientDone(client c) /* Client完成后的調用方法 */ static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) /* 讀事件的處理方法 */ static void writeHandler(aeEventLoop *el, int fd, void *privdata, int mask) /* 寫事件方法處理 */ static client createClient(char *cmd, size_t len, client from) /* 創建一個基準的Client */ static int compareLatency(const void *a, const void *b) /* 比較延時 */ static void showLatencyReport(void) /* 輸出請求延時 */ static void benchmark(char *title, char *cmd, int len) /* 對指定的CMD命令做性能測試 */ int parseOptions(int argc, const char **argv) /* 根據讀入的參數,設置config配置文件 */ int showThroughput(struct aeEventLoop *eventLoop, long long id, void *clientData) /* 顯示Request執行的速度,簡稱RPS */ int test_is_selected(char *name) /* 檢測config中的命令是否被選中 */ ~~~
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看