服务器性能测试介绍
服务器的性能测试主要包括2部分:
- 并发量。能容纳多大的连接
- 效率。在不崩坏的情况下能对报文的处理效率。
本文主要进行效率测试,看看基于epoll模型和io_uring模型的tcp服务器,谁的效率更高。
测试思路
客户端(一个或多个)大量地向服务器发送报文,测试服务器的处理效率(tps:transaction per second,qps:queries per second)。这个或这些客户端也被成为测试工具。
测试工具需求
1、 基于tcp
2、 可以设置请求、线程与连接的数量。-n req -t threadnum -c connection。
在本文中,为了方便,我们为一个连接建立一个线程,也就是线程和连接一一对应。
getopt是一个解析命令行参数的函数,它不是一个线程安全的函数,尽量只在1个线程中使用,建议提前了解。
测试工具代码
代码有详细地注释,主要步骤为:
1、解析命令行参数,看看服务器的IP和port,以及要建立多少连接、发送多少数据等。
2、根据线程数建立线程,在线程里建立一个连接,连接服务器,并按每个线程的平均发送数据任务不间断地发送数据和接收数据。本案例中每笔报文的大小为64*8。
3、计算从开始发送到结束接收的耗时,并计算相关指标。
服务器的功能是:接收到什么数据就返回什么数据。
详细的服务器代码可看前文:
与epoll媲美的io_uring_io_uring tcp服务器-CSDN博客
用反应器模式和epoll构建百万并发服务器_如何设计一个支持百万并发的服务器-CSDN博客
#include<stdio.h> #include<string.h> #include<sys/socket.h> #include<stdlib.h> #include<unistd.h> #include<sys/time.h> #include<pthread.h> #include<arpa/inet.h> //设置该结构体用于存储线程函数所需的参数 typedef struct test_context_s{ char serverip[16]; //服务器ip int port; //服务器端口 int threadnum; //线程数量 int connection; //连接数量,此案例中与线程数量一致 int requestion; //请求数量,也就是报文数量 int failed; //统计发送失败的次数,有个大概的数就行,所以没用原子变量 }test_context_t; typedef struct test_context_s test_context_t; //与服务器建立tcp连接,常规的socket然后connect int connect_tcpserver(const char* ip,unsigned short port){ int connfd = socket(AF_INET,SOCK_STREAM,0); struct sockaddr_in tcpserver_addr; memset(&tcpserver_addr,0,sizeof(struct sockaddr_in)); tcpserver_addr.sin_family = AF_INET; tcpserver_addr.sin_addr.s_addr = inet_addr(ip); tcpserver_addr.sin_port = htons(port); int ret = connect(connfd,(struct sockaddr*)&tcpserver_addr,sizeof(struct sockaddr_in)); if(ret){ perror("connect"); return -1; } return connfd; } #define TIME_SUB_MS(tv1,tv2) ((tv1.tv_sec - tv2.tv_sec)*1000 + (tv1.tv_usec - tv2.tv_usec)/1000) //要发送给客户端的数据的基本单位 #define TEST_MESSAGE "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890abcdefghijklmnopqrstuvwxyz\r\n" #define RBUFFER_LENGTH 2048 //读数据的空间的大小,不一定用满 #define WBUFFER_LENGTH 2048 //写数据的空间的大小,不一定用满 //客户端发送并接收数据 int send_recv_tcppkt(int fd){ char wbuffer[WBUFFER_LENGTH] = {0}; //设置每次发送的报文包含多少个基本单位 int i = 0; for(i=0;i<8;i++){ strcpy(wbuffer+i *strlen(TEST_MESSAGE),TEST_MESSAGE); } //发送报文 int res = send(fd,wbuffer,strlen(wbuffer),0); if(res<0){ exit(1); } //接收报文 char rbuffer[RBUFFER_LENGTH] ={0}; res = recv(fd,rbuffer,RBUFFER_LENGTH,0); if(res<=0){ exit(1); } if(strcmp(rbuffer,wbuffer)!=0){ return -1; } } //线程函数,主要作用是建立连接、发送接收报文 static void *test_qps_entry(void* arg){ test_context_t *pctx = (test_context_t*)arg; //建立连接 int connfd = connect_tcpserver(pctx->serverip,pctx->port); if(connfd<0){ printf("connect_tcpserver failed!\n"); return NULL; } //每个线程要发送的报文数量 int count = pctx->requestion/pctx->threadnum; //发送报文 int i=0; int res; while(i++<count){ res = send_recv_tcppkt(connfd); if(res!=0){ printf("send_recv_tcppkt failed\n"); pctx->failed++; continue; } } return NULL; } int main(int argc,char *argv[]){ int ret =0; test_context_t ctx ={0}; int opt; //getopt函数可以一次解析出带有名称的输入参数 //注意这个函数是线程不安全的, while((opt = getopt(argc,argv,"s:p:t:c:n:?"))!=-1){ switch(opt){ case 's': printf("-s:%s\n",optarg); strcpy(ctx.serverip,optarg);//服务器IP break; case 'p': printf("-p:%s\n",optarg); ctx.port = atoi(optarg);//服务器端口 break; case 't': printf("-t:%s\n",optarg); ctx.threadnum = atoi(optarg);//线程数 break; case 'c': printf("-c:%s\n",optarg); ctx.connection = ctx.threadnum;//还是和线程数一致吧 break; case 'n': printf("-n:%s\n",optarg); ctx.requestion = atoi(optarg); break; default: return -1; } } //线程数组 pthread_t *ptid = malloc(ctx.threadnum *sizeof("pthread_t")); //开始大规模发送发送报文 struct timeval tv_begin; //记录报文开始发送的时间 gettimeofday(&tv_begin,NULL); int i = 0; for(i=0;i<ctx.threadnum;i++){ //建立线程运行线程函数 pthread_create(&ptid[i],NULL,test_qps_entry,&ctx); } for(i=0;i<ctx.threadnum;i++){ pthread_join(ptid[i],NULL); } struct timeval tv_end; //记录报文全部发送并接收完毕的时间 gettimeofday(&tv_end,NULL); int time_used = TIME_SUB_MS(tv_end,tv_begin);//计算用时 printf("success: %d, failed: %d, time_used: %d, qps: %d\n", ctx.requestion-ctx.failed, ctx.failed, time_used, ctx.requestion * 1000 / time_used); return 0; }
测试结果
epoll服务器
发送了100w数据,qps为33243
io_uring服务器
发送了100w数据,qps为43305
结论
在本机、本案例的情况下,io_uring服务器的效率比epoll服务器的效率高约30%。