12. 测试搭建百万并发项目

简介: 12. 测试搭建百万并发项目

本文利用四台虚拟机,实现了百万并发的项目,并解决其中遇到的一些问题


一、百万并发项目

准备4个虚拟机,其中一个4G内存,2核CPU;另外三个2G内存,1核CPU。

在服务器中运行11节的代码,客户端中运行mul_port_client_epoll.c代码。


二、问题与解决


1、Connection refused ——出现服务器不允许链接的错误


这是因为在Linux系统中,每个进程都有一些打开的文件(open files),而文件系统默认每个进程默认最多可以打开fd(File Descriptor)=1024个文件描述符。可以通过命令ulimit -a进程查看

通过命令sudo vim /etc/security/limits.conf,可修改open files最大个数。在limits.conf文件末尾添加如下命令,指定了所有用户在系统中可以同时打开的最大文件数量为 1048576。

*       hard    nofile  1048576
*       soft    nofile  1048576

修改后输入命令sudo reboot,进行重启。


2、connect: Cannot assign requested address ;error: Cannot assign requested address


在计算机网络中,Socket(套接字)是应用程序与网络之间的接口。它提供了一种通信机制,使得运行在不同主机上的应用程序可以互相发送和接收数据。

一个 Socket 由 IP 地址、协议类型和端口号三部分组成。其中,IP 地址指定了目标主机的地址;协议类型指定了要使用的传输层协议,如 TCP 或 UDP;而端口号则表示应用程序所使用的特定服务或进程。

当一个 Socket 发送数据时,它将数据包添加到网络层协议中,并通过 IP 地址找到目标主机。一旦到达目标主机后,在传输层上根据端口号找到对应的应用程序,并将数据包交给该程序处理。类似地,在接收数据时,Socket 需要指定本地 IP 和端口号以便正确地处理来自其他主机发来的数据。

出现“无法分配请求的地址”的错误,是因为在目标主机IP、远程端口号、本机IP以及协议确定时,出现本机端口号被耗尽的情况。这种情况通常会发生在客户端同时请求大量数据或者建立大量连接时,但服务器没有足够的资源来处理这些请求。

解决办法是:一个服务器监听多个端口,修改代码放在后面,监听100个端口(原来是一个)。


3、connect: Connection timed out error ;error: Connection timed out error


fd的个数与fd的最大值有以下区别:


  • fd的个数指当前进程已经打开并正在使用的文件描述符数量。
  • fd的最大值指当前进程可以同时打开并使用的最大文件描述符数量。

可以通过命令cat \proc\sys\fs\file-max查看fd的个数(本例结果为1048576)

通过命令cat /proc/sys/net/netfilter/nf_conntrack_max查看fd的最大数(本例结果为65536)

因此需要修改客户端fd的最大数,通过命令sudo vim /etc/sysctl.conf,添加以下命令

fs.file-max=1048576
net.nf_conntrack_max=1048576

输入命令sudo sysctl -p应用新的配置


4、Cannot open /proc/meminfo: Too many open files in system

与问题3一样,修改服务器的file-max


5、sysctl: cannot stat /proc/sys/net/nf_conntrack_max: No such file or directory

输入命令sudo modprobe ip_conntrack


6、内存回收

复制会话,输入命令htop


业务中CPU和内存消耗最好不要超过80%。因此需要优化TCP协议栈,通过命令sudo vim /etc/sysctl.conf,添加以下命令

net.ipv4.tcp_mem = 252144 524288 786432
net.ipv4.tcp_wmem = 1024 1024 2048
net.ipv4.tcp_rmem = 1024 1024 2048

输入命令sudo sysctl -p应用新的配置。

这是Linux系统中的TCP参数设置,具体含义如下:

  • net.ipv4.tcp_mem: 这个参数定义了 TCP 协议栈所使用的内存总量。它由三个数字组成,分别表示:最小值、默认值和最大值(单位为页面大小)。在这个例子中,其值为 252144 524288 786432。
  • net.ipv4.tcp_wmem: 这个参数定义了发送缓冲区的大小。它由三个数字组成,分别表示:最小值、默认值和最大值(单位为字节)。在这个例子中,其值为 1024 1024 2048。
  • net.ipv4.tcp_rmem: 这个参数定义了接收缓冲区的大小。它由三个数字组成,分别表示:最小值、默认值和最大值(单位为字节)。在这个例子中,其值为 1024 1024 2048。
    说明:

以上这些参数都是 TCP/IP 协议栈所使用的参数。其中 tcp_mem 参数控制着协议栈所使用的内存总量;tcp_wmem 和 tcp_rmem 参数则控制着发送缓冲区和接收缓冲区的大小。

三、代码

#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <errno.h>
#include <fcntl.h> 
#include <unistd.h> 
#include <sys/epoll.h>
#define BUFFER_LENGTH       1024
#define EPOLL_SIZE          1024
#define MAX_PORT            100
int islistenfd(int fd,int *fds){
    int i=0;
    for (i=0;i<MAX_PORT;i++){
        if(fd==*(fds+i)) return fd;
    }
    return 0;
}
int main(int argc,char *argv[]){
    if (argc < 2) {
        printf("Param Error \n");
        return -1;
    }
    int port=atoi(argv[1]);//开始的端口
    int sockfds[MAX_PORT]={0};  //lisiten fd
     int epfd=epoll_create(1); 
    int i=0;
    for(i=0;i<MAX_PORT;i++){
        int sockfd=socket(AF_INET,SOCK_STREAM,0);
        struct sockaddr_in addr;
        memset(&addr,0,sizeof(struct sockaddr_in));
        addr.sin_family=AF_INET;
        addr.sin_port=htons(port+i); //8888 --->  8889  ---->  8890 ----> ....
        addr.sin_addr.s_addr=INADDR_ANY;
        if (bind(sockfd,(struct sockaddr*)&addr,sizeof(struct sockaddr_in))<0){
            perror("bind");
            return -2;
        }
        if(listen(sockfd,5)<0){
            perror("listen");
            return -3;
        }
        printf("tcp server listen on port : %d\n", port + i);
        struct epoll_event ev;  
        ev.events=EPOLLIN;  
        ev.data.fd = sockfd;
        epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&ev);  
        sockfds[i]=sockfd;
    }
    struct epoll_event events[EPOLL_SIZE] = {0};    //创建一个结构体数组 events 用于存储 epoll_wait() 返回的事件列表。
    while (1){
        int nready=epoll_wait(epfd,events,EPOLL_SIZE,5); //
        if (nready == -1) continue; //表示5秒内,没有事件,继续监听
        int i=0;
        for (i=0;i<nready;i++){
            int sockfd=islistenfd(events[i].data.fd ,sockfds);
            if(sockfd){
                struct sockaddr_in client_addr;
                memset(&client_addr,0,sizeof(struct sockaddr_in));
                socklen_t client_len =sizeof(client_addr);
                int clientfd=accept(sockfd,(struct sockaddr *)&client_addr,&client_len);
                fcntl(clientfd,F_SETFL,O_NONBLOCK);
                int reuse=1;
                setsockopt(clientfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
                struct epoll_event ev;
                ev.events=EPOLLIN | EPOLLET;  //EPOLLET 则表示将 I/O 事件设置为边缘触发模式。
                ev.data.fd=clientfd;
                epoll_ctl(epfd,EPOLL_CTL_ADD,clientfd,&ev);
            }
            else{
                //当某个客户端套接字上出现可读事件时(即该文件描述符在 events 中对应的元素有 EPOLLIN 标志),则调用 recv() 函数从该套接字中读取数据
                int clientfd=events[i].data.fd;
                char buffer[BUFFER_LENGTH]={0};
                int len=recv(clientfd,buffer,BUFFER_LENGTH,0);
                if (len < 0){//出现了异常情况或者非阻塞状态下没有更多数据可读
                    //关闭该套接字并将其从 epoll 实例中删除
                    close(clientfd);
                    struct epoll_event ev;
                    ev.events=EPOLLIN;  
                    ev.data.fd=clientfd;
                    epoll_ctl(epfd,EPOLL_CTL_DEL,clientfd,&ev); //从 epoll 实例中删除 clientfd 对应的文件描述符,并且停止监听该套接字上的事件。
                }
                else if(len == 0) {//对方已经断开连接
                    //关闭该套接字并将其从 epoll 实例中删除
                    close(clientfd);
                    struct epoll_event ev;
                    ev.events=EPOLLIN;  
                    ev.data.fd=clientfd;
                    epoll_ctl(epfd,EPOLL_CTL_DEL,clientfd,&ev);
                }
                else{
                    printf("Recv: %s, %d byte(s), clientfd: %d\n", buffer, len, clientfd);
                }
            }
        }
    }
    return 0;
}
目录
相关文章
|
1月前
|
人工智能 测试技术 项目管理
测试不再碎片化:AI智能体平台「项目资料套件」功能上线!
在实际项目中,需求文档分散、整理费时、测试遗漏等问题常困扰测试工作。霍格沃兹推出AI智能体测试平台全新功能——项目资料套件,可将多个关联文档打包管理,并一键生成测试用例,提升测试完整性与效率。支持套件创建、文档关联、编辑删除及用例生成,适用于复杂项目、版本迭代等场景,助力实现智能化测试协作,让测试更高效、更专业。
|
1月前
|
测试技术 UED 开发者
性能测试报告-用于项目的性能验证、性能调优、发现性能缺陷等应用场景
性能测试报告用于评估系统性能、稳定性和安全性,涵盖测试环境、方法、指标分析及缺陷优化建议,是保障软件质量与用户体验的关键文档。
|
3月前
|
Java 测试技术 Spring
简单学Spring Boot | 博客项目的测试
本内容介绍了基于Spring Boot的博客项目测试实践,重点在于通过测试驱动开发(TDD)优化服务层代码,提升代码质量和功能可靠性。案例详细展示了如何为PostService类编写测试用例、运行测试并根据反馈优化功能代码,包括两次优化过程。通过TDD流程,确保每项功能经过严格验证,增强代码可维护性与系统稳定性。
176 0
|
3月前
|
人工智能 数据可视化 测试技术
UAT测试排程工具深度解析:让验收测试不再失控,项目稳稳上线
在系统交付节奏加快的背景下,“测试节奏混乱”已成为项目延期的主因之一。UAT测试排程工具应运而生,帮助团队结构化拆解任务、清晰分配责任、实时掌控进度,打通需求、测试、开发三方协作闭环,提升测试效率与质量。本文还盘点了2025年热门UAT工具,助力团队选型落地,告别靠表格和群聊推进测试的低效方式,实现有节奏、有章法的测试管理。
|
8月前
|
人工智能 自然语言处理 测试技术
Potpie.ai:比Copilot更狠!这个AI直接接管项目代码,自动Debug+测试+开发全搞定
Potpie.ai 是一个基于 AI 技术的开源平台,能够为代码库创建定制化的工程代理,自动化代码分析、测试和开发任务。
658 19
Potpie.ai:比Copilot更狠!这个AI直接接管项目代码,自动Debug+测试+开发全搞定
|
8月前
|
缓存 Java 测试技术
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
957 3
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
|
8月前
|
JSON 前端开发 API
以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡
以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡
395 5
以项目登录接口为例-大前端之开发postman请求接口带token的请求测试-前端开发必学之一-如果要学会联调接口而不是纯写静态前端页面-这个是必学-本文以优雅草蜻蜓Q系统API为实践来演示我们如何带token请求接口-优雅草卓伊凡
|
9月前
|
Dart 前端开发 Android开发
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
263 1
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
|
11月前
|
监控 安全 测试技术
如何在实际项目中应用Python Web开发的安全测试知识?
如何在实际项目中应用Python Web开发的安全测试知识?
188 61
|
11月前
|
机器学习/深度学习 算法 UED
在数据驱动时代,A/B 测试成为评估机器学习项目不同方案效果的重要方法
在数据驱动时代,A/B 测试成为评估机器学习项目不同方案效果的重要方法。本文介绍 A/B 测试的基本概念、步骤及其在模型评估、算法改进、特征选择和用户体验优化中的应用,同时提供 Python 实现示例,强调其在确保项目性能和用户体验方面的关键作用。
387 6

热门文章

最新文章