100万并发连接服务器笔记之测试端就绪
重新編寫測試端程序
測試端程序需要增加綁定本機IP和本地端口的功能,以盡可能的向外發(fā)出更多的tcp請求。需要對client1.c重構(gòu),增加參數(shù)傳遞。 下面是client2.c的代碼
| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 | #include <sys/types.h>#include <sys/time.h>#include <sys/queue.h>#include <stdlib.h>#include <err.h>#include <event.h>#include <evhttp.h>#include <unistd.h>#include <stdio.h>#include <string.h>#include <sys/socket.h>#include <netinet/in.h>#include <time.h>#include <pthread.h>#define BUFSIZE 4096#define SLEEP_MS 10char buf[BUFSIZE];int bytes_recvd = 0;int chunks_recvd = 0;int closed = 0;int connected = 0;static char ip_array[300] = "192.168.190.134,192.168.190.143,192.168.190.144,192.168.190.145,192.168.190.146,192.168.190.147,192.168.190.148,192.168.190.149,192.168.190.151,192.168.190.152";static char server_ip[16] = "192.168.190.133";static int server_port = 8000;static int max_conns = 62000;// called per chunk receivedvoid chunkcb(struct evhttp_request *req, void *arg) { int s = evbuffer_remove( req->input_buffer, &buf, BUFSIZE ); bytes_recvd += s; chunks_recvd++; if (connected >= max_conns && chunks_recvd % 10000 == 0) printf(">Chunks: %d\tBytes: %d\tClosed: %d\n", chunks_recvd, bytes_recvd, closed);}// gets called when request completesvoid reqcb(struct evhttp_request *req, void *arg) { closed++;}int main(int argc, char **argv) { int ch; while ((ch = getopt(argc, argv, "o:h:p:m:")) != -1) { switch (ch) { case 'h': printf("host is %s\n", optarg); strncpy(server_ip, optarg, 15); break; case 'p': printf("port is %s\n", optarg); server_port = atoi(optarg); /*strncpy(server_ip, optarg, 15);*/ break; case 'm': printf("max_conns is %s\n", optarg); max_conns = atoi(optarg); /*strncpy(server_ip, optarg, 15);*/ break; case 'o': printf("ori_ips is %s\n", optarg); strncpy(ip_array, optarg, 300 - 1); break; } } event_init(); struct evhttp *evhttp_connection; struct evhttp_request *evhttp_request; char path[32]; int i; char delims[] = ","; char *ori_ip = NULL; ori_ip = strtok( ip_array, delims ); while (ori_ip != NULL) { for (i = 1; i <= max_conns; i++) { evhttp_connection = evhttp_connection_new(server_ip, server_port); evhttp_connection_set_local_address(evhttp_connection, ori_ip); evhttp_set_timeout(evhttp_connection, 864000); // 10 day timeout evhttp_request = evhttp_request_new(reqcb, NULL); evhttp_request->chunk_cb = chunkcb; sprintf(&path, "/test/%d", ++connected); if (i % 1000 == 0) printf("Req: %s\t->\t%s\n", ori_ip, &path); evhttp_make_request( evhttp_connection, evhttp_request, EVHTTP_REQ_GET, path ); evhttp_connection_set_timeout(evhttp_request->evcon, 864000); event_loop( EVLOOP_NONBLOCK ); if ( connected % 1000 == 0 ) printf("\nChunks: %d\tBytes: %d\tClosed: %d\n", chunks_recvd, bytes_recvd, closed); usleep(SLEEP_MS * 10); } ori_ip = strtok( NULL, delims ); } event_dispatch(); return 0;} |
若不指定端口,系統(tǒng)會隨機挑選沒有使用到的端口,可以節(jié)省些心力。
編譯:
gcc -o client2 client2.c -levent參數(shù)解釋
- -h 要連接的服務(wù)器IP地址
- -p 要連接的服務(wù)器端口
- -m 本機IP地址需要綁定的隨機端口數(shù)量
- -o 本機所有可用的IP地址列表,注意所有IP地址都應(yīng)該可用
運行:
./client2 -h 192.168.190.230 -p 8000 -m 64000 -o 192.168.190.134,192.168.190.143,192.168.190.144,192.168.190.145,192.168.190.146,192.168.190.147,192.168.190.148,192.168.190.149,192.168.190.150,192.168.190.151太長了,每次執(zhí)行都要粘貼過去,直接放在一個client2.sh文件中,執(zhí)行就很簡單方便多了。
#!/bin/sh ./client2 -h 192.168.190.230 -p 8000 -m 64000 -o 192.168.190.134,192.168.190.143,192.168.190.144,192.168.190.145,192.168.190.146,192.168.190.147,192.168.190.148,192.168.190.149,192.168.190.150,192.168.190.151保存,賦值可運行:
chmod +x client2.sh啟動測試:
sh client2.sh第三個遇到的問題:fs.file-max的問題
測試端程序client2.c在發(fā)出的數(shù)量大于某個值(大概為40萬時)是,通過dmesg命令查看會得到大量警告信息:
[warn] socket: Too many open files in system此時,就需要檢查/proc/sys/fs/file-max參數(shù)了。
查看一下系統(tǒng)對fs.file-max的說明
/proc/sys/fs/file-max This file defines a system-wide limit on the number of open files for all processes. (See also setrlimit(2), which can be used by a process to set the per-process limit, RLIMIT_NOFILE, on the number of files it may open.) If you get lots of error messages about running out of file handles, try increasing this value: echo 100000 > /proc/sys/fs/file-max The kernel constant NR_OPEN imposes an upper limit on the value that may be placed in file-max. If you increase /proc/sys/fs/file-max, be sure to increase /proc/sys/fs/inode-max to 3-4 times the new value of /proc/sys/fs/file-max, or you will run out of inodes.file-max表示系統(tǒng)所有進(jìn)程最多允許同時打開所有的文件句柄數(shù),系統(tǒng)級硬限制。Linux系統(tǒng)在啟動時根據(jù)系統(tǒng)硬件資源狀況計算出來的最佳的最大同時打開文件數(shù)限制,如果沒有特殊需要,不用修改,除非打開的文件句柄數(shù)超過此值。
在為測試機分配4G內(nèi)存時,對應(yīng)的fs.file-max值為386562,很顯然打開的文件句柄很受限,38萬個左右。 很顯然,無論是測試端還是服務(wù)端,都應(yīng)該將此值調(diào)大些,一定要大于等于/etc/security/limits.conf送所設(shè)置的soft nofile和soft nofile值。?
注意ulimit -n,僅僅設(shè)置當(dāng)前shell以及由它啟動的進(jìn)程的資源限制。
備注:以上參數(shù),具有包含和被包含的關(guān)系。
當(dāng)前會話修改,可以這么做:
echo 1048576 > /proc/sys/fs/file-max但系統(tǒng)重啟后消失。
永久修改,要添加到 /etc/sysctl.conf 文件中:
fs.file-max = 1048576保存并使之生效:
sysctl -p再測,就不會出現(xiàn)此問題了。
一臺6G內(nèi)存機器測試機,分配7個網(wǎng)卡,可以做到不占用虛擬內(nèi)存,對外發(fā)出64000 * 7 = 448000個對外持久請求。要完成100萬的持久連接,還得再想辦法。
最終測試端組成如下:
- 兩臺物理機器各自一個網(wǎng)卡,每個發(fā)出64000個請求
- 兩個6G左右的centos測試端機器(綁定7個橋接或NAT連接)各自發(fā)出64000*7 = 448000請求
- 共使用了16個網(wǎng)卡(物理網(wǎng)卡+虛擬網(wǎng)卡)
- 1M ≈ 1024K ≈ 1024000 = (64000) + (64000) + (64000*7) + (64000*7)
- 共耗費16G內(nèi)存,16個網(wǎng)卡(物理+虛擬),四臺測試機
備注:?
下面就要完成1M持久連接的目標(biāo),但在服務(wù)端還會遇到最后一個問題。
總結(jié)
以上是生活随笔為你收集整理的100万并发连接服务器笔记之测试端就绪的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 背景图片浮动居中
- 下一篇: HDOJ1874最短路【spfa】