[C/C++后端开发学习] 9 服务端百万并发测试

本文介绍了服务端并发的概念,常见单机服务模型,并详细探讨了如何进行并发测试,包括socket数量的限制、客户端测试代码及结果。通过单线程多端口监听的改进,成功将并发量提升到100万级别,讨论了实际应用中的多进程和多线程处理方法。
摘要由CSDN通过智能技术生成

服务端并发的概念

并发量:同时承载的客户端的数量,实质上就是同时能够维护的 socket 的数量

比如要实现10W客户端同时在线,200ms内正常返回结果,承载量的影响因素:

  • 数据库
  • 网络带宽
  • 内存操作
  • 日志

测试服务器十万、百万并发能力的意义更多地在于测试服务器是否具备这种能力,它并不是与业务直接相关的。

常见单机服务模型

  • 单线程同步:NTP
  • 多线程同步:Natty
  • 纯异步:Redis、HAProxy
  • 半同步半异步:Natty
  • 多进程同步:fastcgi
  • 多线程异步:memcached
  • 多进程异步:Nginx
  • 一个请求一个进程/线程:Apache/CGI
  • 微进程框架:erlang/go/lua
  • 协程框架:libco/ntyco

并发测试方法

实际上,我们之前基于epoll实现的Reactor模型的简单echo服务器就应经可以实现几十万量级的并发了,我们可以测试一下。测试之前需要先修改一下描述符数量的限制,否则可用的描述符资源会耗尽。服务端测试代码为之前这篇博文中的Reactor模型的代码。

socket数量的限制(描述符数量的限制)

两种修改方法:

  • ulimit -n <value>
    这种方法不能持久,重启后就得重新设置

  • vim /etc/security/limits.conf
    limits.conf文件的格式如下:
    在这里插入图片描述

    • domain就是指用户;
    • 限制策略的type分soft软和hard硬,所谓hard就是硬性限制,数量达到value这个上限就不分配了;soft相对宽松,达到上限后开始回收;
    • item:对于文件描述符的数量限制,其对应的item就是 nofile - max number of open files

    增加两行:

*	soft	nofile	1048576
*	hard	nofile	1048576

客户端测试代码

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <sys/time.h>
#include <errno.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <fcntl.h>

#define MAX_CONNECTION  340000  // 单个客户端建立34W个连接,3个客户端就有100W
#define MAX_BUFSIZE		128
#define MAX_EPOLLSIZE	(384*1024)
#define MAX_PORT		100     // 最大端口数量

#define TIME_MS_USED(tv1, tv2)  ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000)  // 用于计算耗时

/* 设置fd为非阻塞 */
static int fdSetNonBlock(int fd)
{
   
    int flags;

    flags = fcntl(fd, F_GETFL);
    if(flags < 0) return flags;

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

    return 0;
}

/* 设置socket SO_REUSEADDR*/
static int sockSetReuseAddr(int sockfd)
{
   
    int reuse = 1;
    return setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
}

struct epoll_event events[MAX_EPOLLSIZE];
int main(int argc, char *argv[])
{
   
    if(argc < 3)
    {
   
        printf("Usage: %s ip port", argv[0]);
        return 0;
    }

    const char* ip = argv[1];
    int port = atoi(argv[2]);
    int connections = 0;    // 建立连接的计数,用于统计
    char buffer[MAX_BUFSIZE] = {
   0};
    int i;
    int clientFinishTest = 0;
    int portOffset = 0;
    int epfd = epoll_create(1);

    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 loopBegin, loopEnd;
    gettimeofday(&loopBegin, NULL);

    while(1)
    {
   
        struct epoll_event ev;
		int sockfd = 0;

        if(connections < MAX_CONNECTION
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值