高并发服务器的限制有哪些,如何提高并发量

这篇具有很好参考价值的文章主要介绍了高并发服务器的限制有哪些,如何提高并发量。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

前言

并发量限制因素 (五元组)

准备

测试并发量

思考局限

如何打破

超时连接问题何在

connection timeout的解决办法

实际开发中的处理方案

文章小结


前言

本文纯粹就是小杰学习后端服务器开发的一个学习笔记系列.
小杰会尽量地将其梳理清楚, 大家一起学习,共同进步, 知识不分高低, 计算机的学习小杰认为也是一个    
量变   --->   质变    的过程
天道酬勤, 水滴石穿, 在不同的阶段就干好自己当前阶段力所能及之事,  至少是没有在寝室的床上瘫着消磨时光                                                 --------   愿大家都学有所成,所获

并发量限制因素 (五元组)

五元组: (srcip, dstip, srcport, dstport, proto) 

  1. 文件句柄, 文件描述符数量  open files
  2. 系统内存限制 
  3. 端口数量限制
  4. 网络带宽的限制 (一般不做考虑)
  5. 数据库的并发量限制

准备

先将 open files 修改到 100W的上限

查看单个进程可以打开的文件句柄的数目, open files的大小

命令:ulimit 

ulimit -a 显示当前所有的资源限制
ulimit -H 设置硬件资源限制
ulimit -S 设置软件资源限制
ulimit -n 设置进程最大打开文件描述符数

服务器高并发,后端服务器开发,网络,服务器,测试,学习,并发量

我的已经被我自己修改为了100W的量级了 

修改方式:

  1. 命令修改 : ulimit -n  <value>    缺陷:不是永久修改, 不涉及写磁盘, 重启shell之后修改消失
  2. 修改配置文件  limits.conf 文件限制着用户可以使用的最大文件数,最大线程,最大内存等资源使用量。    vim /etc/security/limits.conf        涉及写磁盘, 每一次登录shell都会加载配置文件, 永久修改         配置文件记忆技巧, 资源使用限制涉及到系统安全, 故而在security中

服务器高并发,后端服务器开发,网络,服务器,测试,学习,并发量

服务器高并发,后端服务器开发,网络,服务器,测试,学习,并发量

测试并发量

首先针对之前写的reactor进行一个并发量的测试.

测试代码server代码在上一篇文章中:

epoll高度封装reactor,几乎所有可见服务器的底层框架_小杰312的博客-CSDN博客_小杰框架epoll高度封装reactor,几乎所有可见服务器的底层框架https://blog.csdn.net/weixin_53695360/article/details/123894158?spm=1001.2014.3001.5502

并发量:服务器可以承载的客户端的连接数量, 也就是可以维护的 sockfd的数量.

客户端并发量测试

初始版本测试结果如下:

服务器高并发,后端服务器开发,网络,服务器,测试,学习,并发量

思考局限

srcip 客户端的ip是固定的 srcport 客户端的可用端口数理论值是 65535

dstip +  dstport 固定, 服务器ip 跟 端口固定

 此时并发量可以达到2.8W, 然后报错不能分配地址了. 其实是客户端端口分配上限了.

如何打破

增加服务器端口数,  此时完全先从五元组确定唯一连接的方向切入,思考出可以增加服务端的监视窗口数量来提高并发量, 打破限制.       (多端口, 多窗口监视,有效提升客户接入量)

  • 将服务器的端口数开启到100个
  • 核心改变代码:

创建监视端口 init_listen_sock

int init_sock(short port) {

	int sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (sockfd == -1) {
		err_exit("socket");
	}

	sockaddr_in addr;

	memset(&addr, 0, sizeof(addr));
	addr.sin_port = htons(port);
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = INADDR_ANY;

	if (-1 == bind(sockfd, (SA*)&addr, sizeof(addr))) {
		err_exit("bind");
	}

	if (-1 == listen(sockfd, 5)) {
		err_exit("listen");
	}

	return sockfd;
}
	//循环向eventloop中添加多监视窗口, 多port
    int i = 0;
	for (i = 0; i < LISTEN_PORT; ++i) {
		sockfd = init_sock(i + port);
		//将其加入到event_loop中
		struct epoll_event ev;
		ev.events = EPOLLIN;	//level 触发 
		//注册监视事件
		struct sockitem* si = (struct sockitem*)malloc(sizeof(struct sockitem));
		si->sockfd = sockfd;
		si->callback = accept_cb;//设置事件处理器

		ev.data.ptr = si;
		epoll_ctl(eventloop->epfd, EPOLL_CTL_ADD, sockfd, &ev);
	}
  • 再测试

经过漫长等待之后它终于还是没有达到100W左右, 而是killed了, 因为内存限制被killed了

服务器高并发,后端服务器开发,网络,服务器,测试,学习,并发量

其实这个不是正常现象,我这里是因为内存限制而产生了killed, 实际上,内存限制没有打破的情况下也还是无法达到100W, 会出现    connection timeout 连接超时的错误 

超时连接问题何在

100 * 2.8W  服务端端口数(100端口) * 客户端端口数 (随机2.8W端口, 之前测试) 可以达到100W,所以接入量的限制不是五元组. 而是其他因素

针对connect的超时连接错误, 我们透过TCP三次握手去看, 问题在于服务端没有向客户端返回一个ACK, 导致了connect 超时.                                       --- server 的ACK为何没有到

此时的限制其实在于协议栈了. iptables, 一种过滤装置  防火墙

服务器高并发,后端服务器开发,网络,服务器,测试,学习,并发量

connection timeout的解决办法

修改  /etc/sysctl.conf 配置文件, 打破限制.

net.nf_conntrack_max 就是防火墙的限制

fs.file-max = 1048576        
net.nf_conntrack_max = 1048576
net.ipv4.tcp_rmem =128 256 512
net.ipv4.tcp_wmem =128 256 512

至此其实可以完成百万接入量了, 只是我的服务器内存是在太小, 无法达到要求, 内存足够是可以跑到100W的.

服务器高并发,后端服务器开发,网络,服务器,测试,学习,并发量

实际开发中的处理方案

采用多进程的方式, 而不是多端口的方式.

测试代码:   MAX_PORT : 代表的是端口数, 与服务器端口数保持一致文章来源地址https://www.toymoban.com/news/detail-702935.html

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <errno.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>

#define MAX_BUFFER		128
#define MAX_EPOLLSIZE	(384*1024)
#define MAX_PORT		1


#define TIME_SUB_MS(tv1, tv2)  ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000)

int isContinue = 0;

static int ntySetNonblock(int fd) {
	int flags;

	flags = fcntl(fd, F_GETFL, 0);
	if (flags < 0) return flags;
	flags |= O_NONBLOCK;
	if (fcntl(fd, F_SETFL, flags) < 0) return -1;
	return 0;
}

// s设置好地址可复用
static int ntySetReUseAddr(int fd) {
	int reuse = 1;
	return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
}


int main(int argc, char **argv) {
	if (argc <= 2) {
		printf("Usage: %s ip port\n", argv[0]);
		exit(0);
	}

	const char *ip = argv[1];
	int port = atoi(argv[2]);
	int connections = 0;
	char buffer[128] = {0};
	int i = 0, index = 0;

	struct epoll_event events[MAX_EPOLLSIZE];
	
	int epoll_fd = epoll_create(MAX_EPOLLSIZE);
	
	strcpy(buffer, " Data From MulClient\n");
		
	struct sockaddr_in addr;
	memset(&addr, 0, sizeof(struct sockaddr_in));
	
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr(ip);

	struct timeval tv_begin;
	gettimeofday(&tv_begin, NULL);

	while (1) {
		if (++index >= MAX_PORT) index = 0;
		
		struct epoll_event ev;
		int sockfd = 0;

		if (connections < 340000 && !isContinue) {
			sockfd = socket(AF_INET, SOCK_STREAM, 0);
			if (sockfd == -1) {
				perror("socket");
				goto err;
			}

			//ntySetReUseAddr(sockfd);
			addr.sin_port = htons(port+index);

			if (connect(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0) {
				perror("connect");
				goto err;
			}
			ntySetNonblock(sockfd);
			ntySetReUseAddr(sockfd);

			sprintf(buffer, "Hello Server: client --> %d\n", connections);
			send(sockfd, buffer, strlen(buffer), 0);

			ev.data.fd = sockfd;
			ev.events = EPOLLIN | EPOLLOUT;
			epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sockfd, &ev);
		
			connections ++;
		}
		//connections ++;
		if (connections % 1000 == 999 || connections >= 340000) {
			struct timeval tv_cur;
			memcpy(&tv_cur, &tv_begin, sizeof(struct timeval));
			
			gettimeofday(&tv_begin, NULL);
			//计算出时间
			int time_used = TIME_SUB_MS(tv_begin, tv_cur);
			printf("connections: %d, sockfd:%d, time_used:%d\n", connections, sockfd, time_used);
			//每一次仅仅只是拿出来
			int nfds = epoll_wait(epoll_fd, events, connections, 100);
			for (i = 0;i < nfds;i ++) {
				int clientfd = events[i].data.fd;

				if (events[i].events & EPOLLOUT) {
					sprintf(buffer, "data from %d\n", clientfd);
					send(sockfd, buffer, strlen(buffer), 0);
				} else if (events[i].events & EPOLLIN) {
					char rBuffer[MAX_BUFFER] = {0};				
					ssize_t length = recv(sockfd, rBuffer, MAX_BUFFER, 0);
					if (length > 0) {
						printf(" RecvBuffer:%s\n", rBuffer);

						if (!strcmp(rBuffer, "quit")) {
							isContinue = 0;
						}
						
					} else if (length == 0) {
						printf(" Disconnect clientfd:%d\n", clientfd);
						connections --;
						close(clientfd);
					} else {
						if (errno == EINTR) continue;

						printf(" Error clientfd:%d, errno:%d\n", clientfd, errno);
						close(clientfd);
					}
				} else {
					printf(" clientfd:%d, errno:%d\n", clientfd, errno);
					close(clientfd);
				}
			}
		}

		usleep(1 * 1000);
	}

	return 0;

err:
	printf("error : %s\n", strerror(errno));
	return 0;
	
}

文章小结

  1. 做并发测试时候出现了问题,我们思考的方式是: 内存限制,  open files 文件句柄数限制,  五元组组合限制, 网络带宽, 数据库... 方向入手思考
  2. 对于各种系统资源的限制, 可以通过修改配置文件的方式做出永久修改   /etc/security/limits.conf       +     /etc/sysctl.conf  
  3. 五元组组合限制      防火墙限制
  4. ulimit -a 查看所有的资源限制, free -h 查看内存限制, htop 动态观察CPU  + 内存占用情况, 便于分析异常

到了这里,关于高并发服务器的限制有哪些,如何提高并发量的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 如何增加服务器的高并发

    随着互联网的快速发展和普及,越来越多的应用程序需要支持高并发的请求处理。在这种情况下增加服务器的高并发能力成为了一个热门的话题。下面简单的介绍如果提高服务器的高并发能力。 负载均衡 是把请求分发到多个服务器上,来实现请求的平衡和分担。负载均衡可

    2024年01月16日
    浏览(43)
  • 如何调整Hostease服务器cPanel中的域名数量限制

    近段时间我们的网站总是受到攻击,为了保障网站的安全,我们准备将所有网站迁移至Hostease提供的高防服务器中。我们的服务器配置是Intel I3 - 2120,8GB 内存 1TB 机械硬盘,100M 带宽出口,外加10G 防御的防御,服务器配置了cPanel面板。 我们在WHM面板中新建了cPanel账户后,发现

    2024年04月27日
    浏览(39)
  • 高并发大游戏如何选择阿里云服务器配置?

    阿里云服务器配置如何选择?用于高性能计算或大游戏并发,可选择企业级第七代云服务器计算型g7、ECS计算型c7、内存型r7独享型云服务器,CPU采用第三代Intel Xeon可扩展处理器(Ice Lake),基频2.7 GHz,全核睿频3.5 GHz,计算性能稳定。活动 https://t.aliyun.com/U/bLynLC 第七代云服务

    2024年01月21日
    浏览(48)
  • 轻量应用服务器和云服务器有哪些区别,该如何选择?

    我们很多朋友看到阿里云和腾讯云有在促销活动云服务器的时候,有云服务器和轻量服务器,而且我们看到大部分时候轻量服务器是比较便宜的。这个有一定的因素是轻量服务器是新出来的促销力度大一些,二来轻量服务器是面向基础用户的所以便宜一点。轻量应用服务器和

    2024年02月01日
    浏览(47)
  • 服务器的安全包括哪些方面-服务器安全该如何去加固处理-

    服务器安全包括如下几个方面: 系统安全:包括操作系统的安全性、系统的漏洞和补丁管理、用户管理、文件权限和访问控制等。 网络安全:包括网络拓扑结构、网络设备的安全性、网络协议的安全性、防火墙和入侵检测等。 数据安全:包括数据备份和恢复、数据加密、数

    2024年04月17日
    浏览(59)
  • 游戏后端如何实现服务器之间的负载均衡?

    网络游戏已成为人们休闲娱乐的重要方式之一。而在游戏开发中,如何实现服务器之间的负载均衡是一个非常关键的问题。负载均衡不仅可以提高服务器的处理能力,还能保证游戏的稳定性和流畅性。本文将探讨游戏后端如何实现服务器之间的负载均衡。 一、负载均衡的概述

    2024年01月25日
    浏览(46)
  • 【服务器清理】Centos7 服务器磁盘爆满,如何清理,有哪些清理方式

    如果线上服务器磁盘爆满,但是我又不敢轻易清除,这个时候可以参考以下解决方案; 提示:需要操作人员具备链接服务器,使用命令操作; 检查磁盘爆满 大文件,删除 检索当前系统,大于100M的文件,进行查看 检索出来之后,请自行根据需求进行删除,那些文件; 如果那

    2024年02月13日
    浏览(52)
  • 如何隐藏服务器真实 IP,有哪些方法

    网站服务器的安全受到越来越多的重视,但是难免会遇到黑客使用 DDoS 攻击网站,为了网站的安全通常都会做好防御,其中防止 DDoS 攻击有效方法:隐藏服务器真实 IP ,该技术能够有效地保护网站的安全 隐藏服务器真实 IP 地址的方法如下:        1、CDN:CDN 可以隐藏服务

    2024年02月01日
    浏览(37)
  • 用Rust设计一个并发的Web服务:常用Rust库如Tokio、Hyper等,基于TCP/IP协议栈,实现了一个简单的并发Web服务器,并结合具体的代码讲解如何编写并发Web服务器的程序

    作者:禅与计算机程序设计艺术 1994年,互联网泡沫破裂,一批优秀的程序员、工程师纷纷加入到web开发领域。而其中的Rust语言却备受瞩目,它是一种现代系统编程语言,专注于安全和并发。因此,Rust在当下成为最流行的编程语言之一,很多框架也开始使用Rust重构,这使得

    2024年02月06日
    浏览(62)
  • 如何在linux服务器上用Nginx部署Vue项目,以及如何部署springboot后端项目

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 提示:这里可以添加本文要记录的大概内容: 本文内容记录如何在Linux(Ubuntu)系统上安装Nginx,并部署打包好的Vue前端项目,最后通过浏览器访问。 提示:以下是本篇文章正文内容,下面案例可供参考

    2024年04月16日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包