Linux LVS高并发测试程序,内核参数设置,连接数查询指令
2016-01-15 21:33
465 查看
最近在公司参与了一个LVS系统测试的项目,学习到了一些关于高并发测试相关的知识,写到博客里记录下
在服务器硬件支持,以及服务较轻量的情况下,最大连接数未必只限于100000,视情况而定吧
客户端需要发起大量连接,理论上是最多可支持65535个连接,但实际上Linux的默认可用端口号并没有这么多,需要修改
来查询,这个指令当连接数上万后就变得很慢,而且我们发现了一个略坑的问题,通过这组合指令查询到的结果是波动的,我特意试了10000个连接下,在程序没有报有连接关闭的情况下,通过netstat查出来的连接个数在9998到10000之间波动。最后我换了个指令
通过ss指令查询,不仅速度很快,而且不会出现计数不准的情况,需要注意的是,查询到的连接数要比实际多1
Linux内核参数设置
在服务器端需要调整系统最大文件句柄数ulimit -n 1000000
在服务器硬件支持,以及服务较轻量的情况下,最大连接数未必只限于100000,视情况而定吧
客户端需要发起大量连接,理论上是最多可支持65535个连接,但实际上Linux的默认可用端口号并没有这么多,需要修改
sudo echo 1024 65534 > /proc/sys/net/ipv4/ip_local_port_range
查看连接个数
我们一开始用的是netstat -nap | grep 程序名 | grep ESTABLISHED| wc -l
来查询,这个指令当连接数上万后就变得很慢,而且我们发现了一个略坑的问题,通过这组合指令查询到的结果是波动的,我特意试了10000个连接下,在程序没有报有连接关闭的情况下,通过netstat查出来的连接个数在9998到10000之间波动。最后我换了个指令
ss state ESTABLISHED dport = :端口号 and dst IP | wc -l
通过ss指令查询,不仅速度很快,而且不会出现计数不准的情况,需要注意的是,查询到的连接数要比实际多1
测试程序
/*client1.cpp *该程序需要libevent库支持 *测试有无LVS时连接延时区别的程序 *程序发起指定数量的连接后,将每秒给服务器发送一个报文,每个连接收到 *服务器返回的报文后计算耗时 */ #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <unistd.h> #include <netdb.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/types.h> #include <arpa/inet.h> #include <sys/time.h> #include <iostream> #include <map> #include <vector> #include <string> #include "event2/bufferevent.h" #include "event2/buffer.h" #include "event2/listener.h" #include "event2/util.h" #include "event2/event.h" using namespace std; typedef struct bufferevent* BufferEvent; map<struct bufferevent*, long long> bufferevent_map; map<struct bufferevent*, long long>::iterator iter; static int index_ = 0; struct cb_arg { struct event *ev; struct timeval tv; }; void timeout_cb(int fd, short event, void *params) { if (iter == bufferevent_map.end()) { return ; } char buf[1024]; struct cb_arg *arg = (struct cb_arg*)params; struct event *timeout = arg->ev; struct timeval tv = arg->tv; struct timeval start; struct bufferevent *bufevt = iter->first; gettimeofday(&start,NULL); iter->second = 1000000 * start.tv_sec + start.tv_usec; sprintf(buf, "%lld", iter->second); bufferevent_write(bufevt, buf, strlen(buf)); printf("fd %u send %s\n", fd, buf); index_++; iter++; evtimer_add(timeout, &tv); } void read_cb(struct bufferevent *bufevt, void *arg) { char line[1024] = {0}; size_t n; evutil_socket_t fd = bufferevent_getfd(bufevt); struct timeval start; map<struct bufferevent*, long long>::iterator it_temp; it_temp = bufferevent_map.find(bufevt); if (it_temp == bufferevent_map.end()) { return ; } gettimeofday(&start,NULL); long long now = 1000000 * start.tv_sec + start.tv_usec; long long used = now - it_temp->second; while (n = bufferevent_read(bufevt, line, 1024), n > 0) { printf("fd=%u, used time: %lld us\n", fd, used); } } void error_cb(struct bufferevent *bufevt, short events, void *user_data) { evutil_socket_t fd = bufferevent_getfd(bufevt); if (events & BEV_EVENT_EOF) { printf("Connection closed.\n"); printf("fd %u close !\n", fd); bufferevent_free(bufevt); } else if (events & BEV_EVENT_ERROR) { printf("Got an error on the connection: %s\n", strerror(errno)); printf("fd %u close !\n", fd); bufferevent_free(bufevt); } } int main(int argc, char *argv[]) { if (argc != 4) { printf("参数个数不正确 %d, 需要3个参数,连接个数,IP,端口号\n", argc - 1); return 0; } vector<string> argvs; for (int i = 1; i < argc; ++i) { argvs.push_back(argv[i]); } timeval tv = {1, 0}; int times = atoi(argvs[0].c_str()); int port = atoi(argvs[2].c_str()); struct sockaddr_in sin; struct bufferevent* bufevt; event_base *evbase = event_base_new(); if (evbase == NULL) { printf("err in new event_base\n"); return 0; } struct event* timeout; struct cb_arg arg; timeout = evtimer_new(evbase, timeout_cb, &arg); if (timeout == NULL) { printf("err in new evtimer\n"); return 0; } arg.ev = timeout; arg.tv = tv; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = inet_addr(argvs[1].c_str()); sin.sin_port = htons(port); memset(sin.sin_zero, 0x00, 8); for (int i = 0; i < times; ++i) { int fd = socket(AF_INET, SOCK_STREAM, 0); evutil_make_socket_nonblocking(fd); bufevt = bufferevent_socket_new(evbase, fd, BEV_OPT_CLOSE_ON_FREE); if (bufevt == NULL) { printf("err in new bufferevent, fd %u connect failed !\n", fd); continue ; } bufferevent_setcb(bufevt, read_cb, NULL, error_cb, NULL); bufferevent_enable(bufevt, EV_READ | EV_WRITE | EV_PERSIST); if (bufferevent_socket_connect(bufevt, (struct sockaddr *)&sin, sizeof(sin)) < 0) { printf("err in connect with server, fd %u connect failed !\n", fd); bufferevent_free(bufevt); continue ; } bufferevent_map.insert(make_pair(bufevt, 0)); } iter = bufferevent_map.begin(); evtimer_add(timeout, &tv); event_base_dispatch(evbase); evtimer_del(timeout); event_base_free(evbase); return 0; }
/*server.cpp *该程序需要libevent库支持 *简单的回射服务器 */ #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <assert.h> #include <event2/event.h> #include <event2/bufferevent.h> #define LISTEN_BACKLOG 1024 static int time_out_count = 0; static int err_conn_count = 0; static int err_accept_count = 0; void do_accept(evutil_socket_t listener, short event, void *arg); void read_cb(struct bufferevent *bev, void *arg); void error_cb(struct bufferevent *bev, short event, void *arg); void write_cb(struct bufferevent *bev, void *arg); int main(int argc, char *argv[]) { if (argc != 2) { printf("参数个数不正确 %d\n", argc); return 0; } int port = atoi(argv[1]); evutil_socket_t listener; listener = socket(AF_INET, SOCK_STREAM, 0); assert(listener > 0); evutil_make_listen_socket_reuseable(listener); struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_addr.s_addr = 0; sin.sin_port = htons(port); if (bind(listener, (struct sockaddr *)&sin, sizeof(sin)) < 0) { perror("bind"); return 1; } if (listen(listener, LISTEN_BACKLOG) < 0) { perror("listen"); return 1; } printf ("Listening...\n"); evutil_make_socket_nonblocking(listener); struct event_base *base = event_base_new(); assert(base != NULL); struct event *listen_event; listen_event = event_new(base, listener, EV_READ | EV_PERSIST, do_accept, (void*)base); event_add(listen_event, NULL); event_base_dispatch(base); printf("The End."); return 0; } void do_accept(evutil_socket_t listener, short event, void *arg) { struct event_base *base = (struct event_base *)arg; evutil_socket_t fd; struct sockaddr_in sin; socklen_t slen; fd = accept(listener, (struct sockaddr *)&sin, &slen); evutil_make_socket_nonblocking(fd); if (fd < 0) { printf("err in accept, err ccode %d, 发生accept错误的个数 %d", errno, ++err_accept_count); return; } printf("ACCEPT: fd = %u\n", fd); struct bufferevent *bev = bufferevent_socket_new(base, fd, BEV_OPT_CLOSE_ON_FREE); bufferevent_setcb(bev, read_cb, NULL, error_cb, arg); bufferevent_enable(bev, EV_READ | EV_WRITE | EV_PERSIST); } void read_cb(struct bufferevent *bev, void *arg) { #define MAX_LINE 256 char line[MAX_LINE+1]; int n; evutil_socket_t fd = bufferevent_getfd(bev); while (n = bufferevent_read(bev, line, MAX_LINE), n > 0) { line = '\0'; bufferevent_write(bev, line, n); printf("recv : %s\n", line); } } void write_cb(struct bufferevent *bev, void *arg) {} void error_cb(struct bufferevent *bev, short event, void *arg) { evutil_socket_t fd = bufferevent_getfd(bev); printf("fd = %u, ", fd); if (event & BEV_EVENT_TIMEOUT) { time_out_count++; printf("Timed out, 发生超时连接个数 %d", time_out_count); printf(", err code %d\n", errno); } else if (event & BEV_EVENT_EOF) { printf("connection closed\n"); } else if (event & BEV_EVENT_ERROR) { err_conn_count++; printf("some other error, 连接被异常关闭个数 %d", err_conn_count); printf(", err code %d\n", errno); } bufferevent_free(bev); }
/*client2.cpp *该程序需要libevent库支持 *测试高并发量的测试客户端程序,该程序每隔10s就会通过所有连接向服务 *器发送一个报文,以免长时间没有交互,连接被LVS断掉,同时测试服务器 *的负载 */ #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <unistd.h> #include <netdb.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/types.h> #include <arpa/inet.h> #include <sys/time.h> #include <iostream> #include <map> #include <vector> #include <string> #include "event2/bufferevent.h" #include "event2/buffer.h" #include "event2/listener.h" #include "event2/util.h" #include "event2/event.h" using namespace std; typedef struct bufferevent* BufferEvent; map<struct bufferevent*, long long> bufferevent_map; map<struct bufferevent*, long long>::iterator iter; FILE* fp = NULL; static int index_ = 0; static int counter = 0; static int begin_time = 0; struct cb_arg { struct event *ev; struct timeval tv; }; void timeout_cb(int fd, short event, void *params) { char buf[1024]; struct cb_arg *arg = (struct cb_arg*)params; struct event *timeout = arg->ev; struct timeval tv = arg->tv; for (iter = bufferevent_map.begin(); iter != bufferevent_map.end(); ++iter) { memset(buf, 0, sizeof(buf)); struct bufferevent *bufevt = iter->first; sprintf(buf, "%lld", iter->second); bufferevent_write(bufevt, buf, strlen(buf)); } evtimer_add(timeout, &tv); } void read_cb(struct bufferevent *bufevt, void *arg) { char line[1024] = {0}; size_t n; evutil_socket_t fd = bufferevent_getfd(bufevt); struct timeval start; map<struct bufferevent*, long long>::iterator it_temp; it_temp = bufferevent_map.find(bufevt); if (it_temp == bufferevent_map.end()) { return ; } while (n = bufferevent_read(bufevt, line, 1024), n > 0) { ; } } void write_count(int count) { char buf[1024] = {0}; int now_time = (int)time(NULL); sprintf(buf, "pass %d s, now connect count %d\n", now_time - begin_time, count); fputs(buf, fp); } void error_cb(struct bufferevent *bufevt, short events, void *user_data) { evutil_socket_t fd = bufferevent_getfd(bufevt); if (events & BEV_EVENT_EOF) { counter--; printf("Connection closed.\n"); printf("fd %u close ! count %d\n", fd , counter); printf("now EST connect count %d\n", counter); bufferevent_free(bufevt); bufferevent_map.erase(bufevt); write_count(counter); } else if (events & BEV_EVENT_ERROR) { counter--; printf("Got an error on the connection: %d\n", errno); printf("fd %u close ! count %d\n", fd , counter); printf("now EST connect count %d\n", counter); bufferevent_free(bufevt); bufferevent_map.erase(bufevt); write_count(counter); } } void create_file() { char buf[1024] = {0}; timeval tv; gettimeofday(&tv, NULL); int time_ = (int) (1000000 * tv.tv_sec + tv.tv_usec); sprintf(buf, "result_%d.txt", time_); fp = fopen(buf, "w+"); if (fp == NULL) { printf("create result file failed!\n"); exit(-1); } } int main(int argc, char *argv[]) { if (argc != 4) { printf("参数个数不正确 %d, 需要3个参数,连接个数,IP,端口号\n", argc - 1); return 0; } vector<string> argvs; for (int i = 1; i < argc; ++i) { argvs.push_back(argv[i]); } create_file(); timeval tv = {10, 0}; int times = atoi(argvs[0].c_str()); int port = atoi(argvs[2].c_str()); struct sockaddr_in sin; struct bufferevent* bufevt; event_base *evbase = event_base_new(); if (evbase == NULL) { printf("err %d in new event_base\n", errno); return 0; } struct event* timeout; struct cb_arg arg; timeout = evtimer_new(evbase, timeout_cb, &arg); if (timeout == NULL) { printf("err in new evtimer\n"); return 0; } arg.ev = timeout; arg.tv = tv; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = inet_addr(argvs[1].c_str()); sin.sin_port = htons(port); memset(sin.sin_zero, 0x00, 8); for (int i = 0; i < times; ++i) { int fd = socket(AF_INET, SOCK_STREAM, 0); evutil_make_socket_nonblocking(fd); bufevt = bufferevent_socket_new(evbase, fd, BEV_OPT_CLOSE_ON_FREE); if (bufevt == NULL) { printf("err %d in new bufferevent, fd %u connect failed !\n", fd, errno); continue ; } bufferevent_setcb(bufevt, read_cb, NULL, error_cb, NULL); bufferevent_enable(bufevt, EV_READ | EV_WRITE | EV_PERSIST); if (bufferevent_socket_connect(bufevt, (struct sockaddr *)&sin, sizeof(sin)) < 0) { printf("err %d in connect with server, fd %u connect failed !\n", fd, errno); continue ; } char buf[64] = {0}; sprintf(buf, "%d", i); bufferevent_map.insert(make_pair(bufevt, 0)); bufferevent_write(bufevt, buf, strlen(buf)); usleep(10); counter++; } printf("now EST connect count %d\n", counter); write_count(counter); evtimer_add(timeout, &tv); event_base_dispatch(evbase); evtimer_del(timeout); event_base_free(evbase); return 0; }
相关文章推荐
- Linux文件类型
- Linux基本命令――统计和检索文件内容
- Linux写时拷贝技术(copy-on-write)
- linux 挂载硬盘,创建新分区,删除分区
- 如何删除软连接文件
- Linux Is Not Matrix——keepalived 实现主备切换
- Linux基本命令――查看文件内容
- linux删除普通用户报错 userdel: user fancy is currently used by process 1973
- linux下ssh/scp无密钥登陆方法
- Linux Is Not Matrix——keepalived安装
- Linux驱动Platform总线模型
- Linux /UNIX 状态解释
- Linux 上搭建 git 的服务器
- linux 文件查找
- linux服务器 磁盘和文件系统管理(四) 磁盘配额管理与实例
- linux搭建git服务器
- Linux下MySQL慢查询分析mysqlsla安装使用
- Linux脚本练习一
- Linux busybox mount -a fstab
- linux下防DDOS攻击软件及使用方法详解