Nginx啟動配置加載性能分析:作為http服務(wù)器
本文測試了在配置文件規(guī)模較大時, Nginx作為http服務(wù)器的啟動速度,并分析耗時原因。
結(jié)論:
1. Nginx初始化中影響性能點在于listen IP:PORT, 其中port的匯聚會造成初始化速度變得很慢
2. 對于Server_name的初始化相當快, 對初始化性能無影響
一、測試內(nèi)容
腳本創(chuàng)建3類配置文件, 規(guī)則如下:
1. 共創(chuàng)建2萬條Server{}配置
2. server_name基本定長, PerformanceTestxxx
3. 第1類是listen的IP完全一致,port全不同, 配置文件實例:
- http{
- server{
- listen 192.168.0.1:8080;
- server_name PerformanceTest8080;
- }
- …
- server{
- listen 192.168.0.1:8081;
- server_name PerformanceTest8081;
- ….
- }
- }
3. 第2類是listen的Port完全一致,IP全不同, 配置文件實例:
- http{
- server{
- listen 192.168.0.1:80;
- server_name PerformanceTest1;
- }
- …
- server{
- listen 192.168.0.2:80;
- server_name PerformanceTest2;
- ….
- }
- }
4. 第3類是listen的IP:PORT完全一致, server_name全不同, 配置文件實例:
- http{
- server{
- listen 192.168.0.1:80;
- server_name PerformanceTest001;
- }
- …
- server{
- listen 192.168.0.1:80;
- server_name PerformanceTest002;
- ….
- }
- }
二、 測試數(shù)據(jù)
對于3類配置, 再加入3組變量:
1. 不配置server_name
2. server_name全配置一樣
3. server_name全配置不一樣
看server_name對于初始化速度的影響
9種組合的性能如下:
nginx 啟動時間:time ./nginx -c /root/nginx.conf.sameport.noloc
nginx reload時間:time ./nginx -c /root/nginx.conf.sameport.noloc –s reload
從測試數(shù)據(jù)可以看出, 對nginx啟動速度影響的因素為server{}中l(wèi)isten的port, server_name指令基本無影響。
三、 原因分析
3.1 http{}初始化流程簡單介紹:
解析配置文件是遞歸地調(diào)用ngx_conf_parse函數(shù)完成的, http{}配置塊的解析流程:
1. 解析到http指令, 執(zhí)行ngx_http_block函數(shù), 創(chuàng)建http module的配置上下文后, 繼續(xù)ngx_conf_parse解析http{}內(nèi)部的內(nèi)容;
2. 解析到server指令, 執(zhí)行ngx_http_core_server函數(shù), 創(chuàng)建該server{}的配置上下文后, 繼續(xù)ngx_conf_parse解析server{}內(nèi)部的內(nèi)容;
3. 解析到listen指令, 添加到cscf以及cmcf配置中, 如下圖:
1. cmcf->servers數(shù)組保存了所有監(jiān)聽的server數(shù)據(jù)
2. cmcf->ports數(shù)組保存了所有port匯聚的ip的數(shù)據(jù). listen同一個ip:port, server_name不同的srv_conf會掛在ngx_http_conf_addr_t的servers數(shù)組下。
一個配置好的樣子可能是這樣:
3.2 耗時位置定位
代碼中加變量記錄函數(shù)耗時總時間, 得到啟動時耗時在2個步驟:
1) 解析配置文件, 對應(yīng)ngx_conf_parse函數(shù)
2) 初始化socket, 對應(yīng)ngx_open_listening_sockets函數(shù)
3.3 ngx_conf_parse耗時分析
主要是ngx_http_block函數(shù)的耗時, 分為以下2個部分:
很明顯, ngx_http_add_addresses函數(shù)的性能消耗在對相同port已存在ip的查找上面, 這里用的是線性的遍歷查找,
且需要進行字符串比較ngx_memcmp被執(zhí)行了2w*2w共4億次:
- for (i = 0; i < port->addrs.nelts; i++) {
- // 遍歷查找, 如果配置文件中,相同port的IP過多,字符串比較帶來較大性能問題, 2w個listen,這一塊耗時需要8s左右
- if (ngx_memcmp(p, addr[i].opt.u.sockaddr_data + off, len) != 0) {
- continue;
- }
- /* the address is already in the address list */
- // 找到對應(yīng)的ip, 添加cscf到IP
- if (ngx_http_add_server(cf, cscf, &addr[i]) != NGX_OK) {
- return NGX_ERROR;
- }
3.4 ngx_open_listening_sockets耗時分析
函數(shù)中初始化所有l(wèi)istening的socket
- /* for each listening socket */
- ls = cycle->listening.elts;
- for (i = 0; i < cycle->listening.nelts; i++) {
- if (bind(s, ls[i].sockaddr, ls[i].socklen) == -1) {
- …
- …
- if (listen(s, ls[i].backlog) == -1) {
- }
對于同1個IP,新建不同port的socket相比新建多個不同IP的socket更省時間。