欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > IT业 > qps测试epoll和io_uring

qps测试epoll和io_uring

2024/10/25 7:25:05 来源:https://blog.csdn.net/qq_57259389/article/details/141403897  浏览:    关键词:qps测试epoll和io_uring

​ 前边我们了解了Reactor模式和Proactor模式,哪个性能更好呢?需要我们进行测试。前边我们用io_uring实现了Proactor模式,io_uring是2019年才加入到Linux内核中的,提供了三个系统调用函数。都有些抽象,我是直接来拿跑的。
​ 无论是我们epoll实现的Reactor模式还是io_uring实现的Proactor模式,两者都是服务器端。QPS:Queries Per Second意思是“每秒查询率”,是一台服务器每秒能够相应的查询次数,是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。互联网中,作为域名系统服务器的机器的性能经常用每秒查询率来衡量。也就是说,qps这个参数是我们服务器端的一个重要性能。计算 qps的方法是通过统计在一定时间内处理的请求数,然后除以该时间间隔,得到平均每秒的请求数。
​ 我们可以写一个客户端的代码,分别对epoll实现的Reactor服务器和io_uring实现的Proactor服务器进行测试。客户端大致流程:对服务端发起请求到接收到服务器回发的数据,统计期间的时间。

​ 用getopt进行解析命令行参数
-t:表示线程数量
-c:表示连接数量
-n:表示请求数量

tcp客户端测试代码如下:

#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>//定义函数计算两个时间结点的差(单位:毫秒)
#define TIME_SUB_MS(tv1, tv2)  ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000)//结构体test_context_s定义线程入口函数(test_qps_entry)需要的变量
typedef struct test_context_s {char serverip[16];int port;int threadnum;int connection;int requestion;#if 1int failed;
#endif} test_context_t;typedef struct test_context_s test_context_t;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;
}//定义测试发送数据 长度为64个字符
#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;//循环将字符串 TEST_MESSAGE 复制到 wbuffer 数组中//每次复制之前需要计算目标位置的偏移量(i * strlen(TEST_MESSAGE))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) {printf("failed: '%s' != '%s'\n", rbuffer, wbuffer);return -1;}return 0;
}//线程入口函数
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;//识别信息 ./test_qps_tcpclient -s 192.168.147.129(看自己的主机地址,或者用回环地址127.0.0.1也行) -p 2048 -t 50 -c 100 -n 1000000//地址:192.168.147.129//连接的端口:2048//创建的线程数:50//连接数:100//请求数:1000000//赋值给对应的变量while ((opt = getopt(argc, argv, "s:p:t:c:n:?")) != -1) {switch (opt) {//serverip:服务器ip地址case 's':printf("-s: %s\n", optarg);strcpy(ctx.serverip, optarg);break;//port:服务器的端口case 'p':printf("-p: %s\n", optarg);//atpi函数:将字符串转换成整数ctx.port = atoi(optarg);break;//threadnum:线程数case 't':printf("-t: %s\n", optarg);ctx.threadnum = atoi(optarg);break;//connection:连接数量case 'c':printf("-c: %s\n", optarg);ctx.connection = atoi(optarg);break;//requestion:请求数量case 'n':printf("-n: %s\n", optarg);ctx.requestion = atoi(optarg);break;default:return -1;}}//为threadnum个线程的内存pthread_t *ptid = malloc(ctx.threadnum * sizeof(pthread_t));int i = 0;struct timeval tv_begin;gettimeofday(&tv_begin, NULL);//创建我们设定的线程数量,数量为threadnumfor (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);//time_used单位是毫秒,要想计算qps,需要换算成秒,需要将请求数量*1000printf("success: %d, failed: %d, time_used: %d, qps: %d\n", ctx.requestion-ctx.failed, ctx.failed, time_used, ctx.requestion * 1000 / time_used);free(ptid);return ret;
}

1.测试epoll实现的服务器的qps:
服务器端代码(在前边文章C语言实现Reactor中有)进行编译运行等待客户端连接(关闭服务器端所有日志信息)外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

​ 上述客户端代码编译运行
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.测试io_uring实现的服务器的qps:
服务器端代码(在前边文章io_uring实现Proactor中有)进行编译运行等待客户端连接(关闭服务器端所有日志信息)
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

​ 上述客户端代码编译运行(注意修改自己服务器端代码中端口)
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

feXw-1724248941756)]

2.测试io_uring实现的服务器的qps:
服务器端代码(在前边文章io_uring实现Proactor中有)进行编译运行等待客户端连接(关闭服务器端所有日志信息)
[外链图片转存中…(img-5Ao2AjHx-1724248941756)]

​ 上述客户端代码编译运行(注意修改自己服务器端代码中端口)
[外链图片转存中…(img-XmFjRxwA-1724248941757)]

​ 通过上述测试,可以大致看出io_uring实现的异步Proactor性能的qps比epoll实现的同步Reactor性能要好。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com