咪免直播高品质美女在线视频互动社区_咪免直播官方版_咪免直播直播视频在线观看免费版下载

您的位置:首頁 > 軟件教程 > 教程 > 網(wǎng)絡(luò)服務(wù)性能優(yōu)化:Wrktcp與Perf工具詳解

網(wǎng)絡(luò)服務(wù)性能優(yōu)化:Wrktcp與Perf工具詳解

來源:好特整理 | 時間:2024-09-15 10:24:11 | 閱讀:166 |  標(biāo)簽: T wr KTC K C 服務(wù) 網(wǎng)絡(luò)   | 分享到:

wrktcp安裝 碼云地址:https://gitee.com/icesky1stm/wrktcp 直接下載,cd wrktcp-master && make,會生成wrktcp,就ok了,很簡單 wrktcp使用 壓測首先需要一個服務(wù),寫了一個epoll+邊沿觸發(fā)的服務(wù),業(yè)務(wù)是判斷

  • wrktcp安裝
    碼云地址: https://gitee.com/icesky1stm/wrktcp
    直接下載,cd wrktcp-master && make,會生成wrktcp,就ok了,很簡單

  • wrktcp使用
    壓測首先需要一個服務(wù),寫了一個epoll+邊沿觸發(fā)的服務(wù),業(yè)務(wù)是判斷ip是在國內(nèi)還是國外,rq:00000015CHECKIP1.0.4.0,rs:000000010,寫的有些就簡陋兌付看吧,主要為了壓測和分析性能瓶頸。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


std::map g_ip_list; // 存儲 IP 范圍

bool init_ip_list(const char* file_name, std::map &ip_list)
{
    FILE *fp = nullptr;
    if ((fp = fopen(file_name, "r")) == nullptr)
    {
        return false;
    }

    int i = 0;
    int total_count = 0;
    char buf[64] = {0};

    while (fgets(buf, sizeof(buf), fp))
    {
        i++;
        if (buf[0] == '#')
            continue;

        char *pout = nullptr;
        char *pbuf = buf;
        char *pc[10];
        int j = 0;

        while ((pc[j] = strtok_r(pbuf, "|", &pout)) != nullptr)
        {
            j++;
            pbuf = nullptr;
            if (j > 7)
                break;
        }

        if (j != 7)
        {
            syslog(LOG_ERR, "%s:%d, unknown format the line is %d", __FILE__, __LINE__, i);
            continue;
        }

        if (strcmp(pc[2], "ipv4") == 0 && strcmp(pc[1], "CN") == 0)
        {
            unsigned long ip_begin = inet_addr(pc[3]);

            if (ip_begin == INADDR_NONE)
            {
                syslog(LOG_ERR, "%s:%d, ip is unknown, the line is %d, the ip is %s", __FILE__, __LINE__, i, pc[3]);
                continue;
            }
            int count = atoi(pc[4]);
            ip_begin = ntohl(ip_begin);
            unsigned long ip_end = ip_begin + count - 1;
            ip_list.insert(std::make_pair(ip_end, ip_begin));

            total_count++;
        }
    }

    syslog(LOG_INFO, "%s:%d, init_ip_list, total count is %d", __FILE__, __LINE__, total_count);

    fclose(fp);
    return true;
}

void extract_ip(char *buf, char *ip) {  
    // 假設(shè)協(xié)議字符串格式總是 "00000015CHECKIPx.x.x.x"  
    // 找到IP地址的起始位置  
    char *start = strstr(buf, "CHECKIP");  
    if (start == NULL) {  
        fprintf(stderr, "Invalid protocol string\n");  
        return;  
    }  
    // 跳過"CHECKIP"  
    start += 7;  
    // 復(fù)制IP地址到ip變量,注意檢查邊界  
    strncpy(ip, start, 15); // IP地址最多15個字符,包括'\0'  
    ip[15] = '\0'; // 確保字符串以'\0'結(jié)尾  
} 

// server
int main(int argc, const char* argv[])
{
	const char* file_name = "ip_list.txt";
    if (!init_ip_list(file_name, g_ip_list)) {
        std::cerr << "Failed to initialize IP list." << std::endl;
        return 1;
    }
	
    // 創(chuàng)建監(jiān)聽的套接字
    int lfd = socket(AF_INET, SOCK_STREAM, 0);
    if(lfd == -1)
    {
        perror("socket error");
        exit(1);
    }

    // 綁定
    struct sockaddr_in serv_addr;
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(9999);
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);  // 本地多有的IP
    // 127.0.0.1
    // inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr.s_addr);
    
    // 設(shè)置端口復(fù)用
    int opt = 1;
    setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    // 綁定端口
    int ret = bind(lfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
    if(ret == -1)
    {
        perror("bind error");
        exit(1);
    }

    // 監(jiān)聽
    ret = listen(lfd, 64);
    if(ret == -1)
    {
        perror("listen error");
        exit(1);
    }

    // 現(xiàn)在只有監(jiān)聽的文件描述符
    // 所有的文件描述符對應(yīng)讀寫緩沖區(qū)狀態(tài)都是委托內(nèi)核進行檢測的epoll
    // 創(chuàng)建一個epoll模型
    int epfd = epoll_create(100);
    if(epfd == -1)
    {
        perror("epoll_create");
        exit(0);
    }

    // 往epoll實例中添加需要檢測的節(jié)點, 現(xiàn)在只有監(jiān)聽的文件描述符
    struct epoll_event ev;
    ev.events = EPOLLIN;    // 檢測lfd讀讀緩沖區(qū)是否有數(shù)據(jù)
    ev.data.fd = lfd;
    ret = epoll_ctl(epfd, EPOLL_CTL_ADD, lfd, &ev);
    if(ret == -1)
    {
        perror("epoll_ctl");
        exit(0);
    }


    struct epoll_event evs[1024];
    int size = sizeof(evs) / sizeof(struct epoll_event);
    // 持續(xù)檢測
    while(1)
    {
        // 調(diào)用一次, 檢測一次
        int num = epoll_wait(epfd, evs, size, -1);
        printf("==== num: %d\n", num);

        for(int i=0; i 判斷對方是否斷開連接
                        printf("客戶端斷開了連接...\n");
                        // 將這個文件描述符從epoll模型中刪除
                        epoll_ctl(epfd, EPOLL_CTL_DEL, curfd, NULL);
                        close(curfd);
                        break;
                    }
                    else if(len > 0)
                    {
                        // 通信
                        // 接收的數(shù)據(jù)打印到終端
                        write(STDOUT_FILENO, buf, len);
						char ip[16]; // 存儲IP地址  
						extract_ip(buf, ip);  
						printf("Received IP: %s\n", ip);
						
                        // 發(fā)送數(shù)據(jù)
                        //send(curfd, buf, len, 0);
						// 驗證 IP 地址
						struct in_addr address;
						int result = inet_pton(AF_INET, ip, &address); // 檢查 IP 地址的有效性
						if (result < 0) {
							std::cout << "Invalid IP address: " << result << " " << ip << std::endl;
							send(curfd, "-Err\n", 5, 0);
							continue;
						}

						unsigned long ip_num = ntohl(address.s_addr);
						auto it = g_ip_list.lower_bound(ip_num);
						if (it != g_ip_list.end() && it->first >= ip_num && it->second <= ip_num) {
							send(curfd, "000000010", 9, 0); // 國內(nèi)
						} else {
							send(curfd, "000000011", 9, 0); // 國外
						}
                    }
                    else
                    {
                        // len == -1
                        if(errno == EAGAIN)
                        {
                            printf("數(shù)據(jù)讀完了...\n");
							close(curfd);
                            break;
                        }
                        else
                        {
                            perror("recv");
                            exit(0);
                        }
                    }
                }
            }
        }
    }

    return 0;
}

編譯g++ epoll_test.cpp -o epoll_test,直接執(zhí)行./epoll_test,監(jiān)聽0的9999端口

  • wrk配置文件sample_tiny.ini
[common]
# ip & port
host = 127.0.0.1
port = 9999

[request]
req_body = CHECKIP1.0.4.0

[response]
rsp_code_location = head

說下其中的坑,req_body就是要發(fā)的協(xié)議,但是wrktcp會在前面加長度固定8位:00000015;默認(rèn)成功成功響應(yīng)碼是000000,設(shè)置rsp_code_location這個會讓wrktcp從返回協(xié)議(000000010)頭開始找成功響應(yīng)碼
上面那些說明:wrktcp的README有一些說明,但解釋的不太全,需要自己去試和看源碼

  • todo
    固定協(xié)議前面加8位長度,不可能每個服務(wù)都是這樣的協(xié)議,怎么去自定義的協(xié)議,希望大佬指教,好像wrk可以自定義協(xié)議。
  • wrk壓測命令
    ./wrktcp -t15 -c15 -d100s --latency sample_tiny.ini
-t, --threads:     使用線程總數(shù),一般推薦使用CPU核數(shù)的2倍-1
-c, --connections: 連接總數(shù),與線程無關(guān)。每個線程的連接數(shù)為connections/threads
-d, --duration:    壓力測試時間, 可以寫 2s, 2m, 2h
--latency:     打印延遲分布情況
--timeout:     指定超時時間,默認(rèn)是5000毫秒,越長占用統(tǒng)計內(nèi)存越大。
--trace: 	   打印出分布圖
--html: 	   將壓測的結(jié)果數(shù)據(jù),輸出到html文件中。
--test:		   每個連接只會執(zhí)行一次,一般用于測試配置是否正確。
-v  --version:     打印版本信息

測試了兩遍,TPS能維持在1600左右

  Running 2m loadtest @ 127.0.0.1:9999 using sample_tiny.ini
  15 threads and 15 connections
  Time:100s TPS:1644.64/0.00 Latency:7.69ms BPS:14.45KB Error:0
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     4.66ms   14.17ms 318.09ms   98.89%
    Req/Sec   113.66    233.09     1.69k    94.95%
  Latency Distribution
     50%  823.00us
     75%    8.17ms
     90%    9.15ms
     99%   23.08ms
  164554 requests in 1.67m, 1.41MB read
Requests/sec:   1643.21    (Success:1643.21/Failure:0.00)
Transfer/sec:     14.44KB
  • perf
    壓測監(jiān)測服務(wù):perf record -p 10263 -a -g -F 99 -- sleep 10
    參數(shù)說明:
    -p : 進程
    -a : 記錄所有事件
    -g : 啟用基于 DWARF 調(diào)試信息的函數(shù)調(diào)用棧跟蹤。這將記錄函數(shù)調(diào)用棧信息,使得生成的報告更加詳細,能夠顯示出函數(shù)調(diào)用的關(guān)系。
    -F : 采樣頻率
    --sleep:執(zhí)行 sleep 命令,使系統(tǒng)休眠 10 秒鐘。在這個期間,perf record 將記錄指定進程的性能數(shù)據(jù)。

會在當(dāng)前目錄生成perf.data文件,執(zhí)行perf report,會看到printf和write占用的CPU比較高,刪除上面服務(wù)的printf和write函數(shù),重新壓測
網(wǎng)絡(luò)服務(wù)性能優(yōu)化:Wrktcp與Perf工具詳解
重新壓測之后,TPS能維持在3W+

Running 2m loadtest @ 127.0.0.1:9999 using sample_tiny.ini
  15 threads and 15 connections
  Time:100s TPS:32748.45/0.00 Latency:438.00us BPS:287.83KB Error:0
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   519.35us    1.24ms  63.18ms   97.47%
    Req/Sec     2.19k   536.83     4.83k    76.97%
  Latency Distribution
     50%  349.00us
     75%  426.00us
     90%  507.00us
     99%    5.12ms
  3275261 requests in 1.67m, 28.11MB read
Requests/sec:  32716.39    (Success:32716.39/Failure:0.00)
Transfer/sec:    287.55KB
小編推薦閱讀

好特網(wǎng)發(fā)布此文僅為傳遞信息,不代表好特網(wǎng)認(rèn)同期限觀點或證實其描述。

K
K
類型:角色扮演  運營狀態(tài):封測  語言:中文   

游戲攻略

游戲禮包

游戲視頻

游戲下載

游戲活動

《K》是由樂次元開發(fā)的一款日系動漫RPG游戲,游戲根據(jù)同名動漫改編而來,高水準(zhǔn)的漫畫和音樂是這款游戲的

相關(guān)視頻攻略

更多

掃二維碼進入好特網(wǎng)手機版本!

掃二維碼進入好特網(wǎng)微信公眾號!

本站所有軟件,都由網(wǎng)友上傳,如有侵犯你的版權(quán),請發(fā)郵件[email protected]

湘ICP備2022002427號-10 湘公網(wǎng)安備:43070202000427號© 2013~2025 haote.com 好特網(wǎng)