Linux(服务器编程):百万并发服务器系统参数调优

一、本文目的

  • 在编写服务器时 , 如果服务器的设计初衷是要可以承担百万、千万的客户端连接 , 那么默认的情况下 , Linux操作系统提供的相关配置参数(比如说进程可分配的文件数目等)是不能够满足我们的程序需求的 , 因此需要自己调整系统的相关参数
并发的概念是什么?什么是并发?
  • 对于服务器并发的概念 , 下面几点是错误的定义:
    • ①服务器处理客户端请求的数量:没有时间、空间等限制 , 因此不能作为并发的概念
    • ②单位时间内 , 能够处理请求的数量:这也是不正确的定义 , 因为这个定义是针对于服务器吞吐量(qps)的 , 而不是并发
    • 其他等......
  • 下面几点组成在一起可以作为服务器“并发”的概念:
    • ①服务器能够同时承担的客户端数量(最基本要求)
    • ②能处理指定数量以上的相应请求
    • ③能够对数据库进行操作
    • ④有磁盘的操作
    • ⑤CPU的占用率最好不要超过60%
    • ⑥内存占用率最好不要超过80%
视频资料详解:
实现单机百万连接丨优化三次握手四次挥手
揭秘百万并发服务器的奥秘
Linux(服务器编程):百万并发服务器系统参数调优文章插图
要C/C++ Linux服务器架构师学习资料后台私信“1”获取(资料包括C/C++ , Linux , golang技术 , Nginx , ZeroMQ , MySQL , Redis , fastdfs , MongoDB , ZK , 流媒体 , CDN , P2P , K8S , Docker , TCP/IP , 协程 , DPDK , ffmpeg等) , 免费分享二、本文环境搭建
  • 本文准备了两份代码 , 作为测试环境:
    • reactor.c:作为服务端 , 采用单进程reactor模式编写 , 持续接收客户端的连接 , 并且与客户端有数据的读写(recv()、send())
    • mul_port_client_epoll.c:作为客户端 , 会向reactor.c服务端发起不超过340000的客户端连接 , 并且每个客户端都会与服务端有数据的读写(recv()、send())
reactor.c
  • Github源码链接参阅:
// reactor.c// 源码链接: #include #include #include #include #include #include #include #include #include #include#define BUFFER_LENGTH4096#define MAX_EPOLL_EVENTS 1024#define SERVER_PORT8888 typedef int NCALLBACK(int ,int, void*); struct ntyevent { int fd;int events;void *arg;int (*callback)(int fd, int events, void *arg); int status;char buffer[BUFFER_LENGTH]; int length; long last_active;}; struct ntyreactor { int epfd;struct ntyevent *events;}; int recv_cb(int fd, int events, void *arg);int send_cb(int fd, int events, void *arg);int nty_event_set(struct ntyevent *ev, int fd, NCALLBACK callback, void *arg) { ev->fd = fd; ev->callback = callback; ev->events = 0; ev->arg = arg; ev->last_active = time(NULL);return 0;} int nty_event_add(int epfd, int events, struct ntyevent *ev) {struct epoll_event ep_ev = {0, {0}}; ep_ev.data.ptr = ev; ep_ev.events = ev->events = events;int op; if (ev->status == 1) {op = EPOLL_CTL_MOD; } else {op = EPOLL_CTL_ADD;ev->status = 1; }if (epoll_ctl(epfd, op, ev->fd,return -1; }return 0;} int nty_event_del(int epfd, struct ntyevent *ev) {struct epoll_event ep_ev = {0, {0}}; if (ev->status != 1) { return -1; }ep_ev.data.ptr = ev; ev->status = 0; epoll_ctl(epfd, EPOLL_CTL_DEL, ev->fd,return 0;} int recv_cb(int fd, int events, void *arg) { struct ntyreactor *reactor = (struct ntyreactor*)arg; struct ntyevent *ev = reactor->events + fd;int len = recv(fd, ev->buffer, BUFFER_LENGTH, 0); nty_event_del(reactor->epfd, ev);if (len > 0) {ev->length = len;ev->buffer[len] = '\0';printf("C[%d]:%s\n", fd, ev->buffer);nty_event_set(ev, fd, send_cb, reactor);nty_event_add(reactor->epfd, EPOLLOUT, ev);} else if (len == 0) {close(ev->fd); printf("[fd=%d] pos[%ld], closed\n", fd, ev-reactor->events);} else { //if(errno == EAGAIN || errno == EWOULDBLOCK) // continue; return 0;close(ev->fd); printf("recv[fd=%d] error[%d]:%s\n", fd, errno, strerror(errno));}return len;} int send_cb(int fd, int events, void *arg) {struct ntyreactor *reactor = (struct ntyreactor*)arg; struct ntyevent *ev = reactor->events + fd;int len = send(fd, ev->buffer, ev->length, 0); if (len > 0) { printf("send[fd=%d], [%d]%s\n", fd, len, ev->buffer);nty_event_del(reactor->epfd, ev);nty_event_set(ev, fd, recv_cb, reactor);nty_event_add(reactor->epfd, EPOLLIN, ev);} else {close(ev->fd);nty_event_del(reactor->epfd, ev); printf("send[fd=%d] error %s\n", fd, strerror(errno)); }return len;} int accept_cb(int fd, int events, void *arg) { struct ntyreactor *reactor = (struct ntyreactor*)arg; if (reactor == NULL) return -1; struct sockaddr_in client_addr; socklen_t len = sizeof(client_addr); int clientfd; if ((clientfd = accept(fd, (struct sockaddr*) return -1; }int i = 0; do { for (i = 0;i < MAX_EPOLL_EVENTS;i ++) { if (reactor->events[i].status == 0) { break;}} if (i == MAX_EPOLL_EVENTS) { printf("%s: max connect limit[%d]\n", __func__, MAX_EPOLL_EVENTS); break;}int flag = 0; if ((flag = fcntl(clientfd, F_SETFL, O_NONBLOCK))