问题
需要配置自定义格式的访问日志(access log)
解决方案
配置访问日志格式:

http {
log_format geoproxy
	'[$time_local] $remote_addr '
	'$realip_remote_addr $remote_user '
	'$request_method $server_protocol '
	'$scheme $server_name $uri $status '
	'$request_time $body_bytes_sent '
	'$geoip_city_country_code3 $geoip_region '
	'"$geoip_city" $http_x_forwarded_for '
	'$upstream_status $upstream_response_time '
	'"$http_referer" "$http_user_agent"';
...
}

这个日志配置被命名为 geoproxy,它使用许多 NGINX 变量来演示 NGINX 日志记录功能。接下来详细讲解配置选项中各个变量的具体含义:当用户发起请求时,会记录服务器时间( 修改nginx的日志级别为info nginx日志级别顺序_客户端remote_user 值为通过基本授权的用户名称;之后记录 HTTP 请求方法( $request_method )、协议( $server_protocol )和 HTTP 方法( $scheme:http 或 https ) ;当然还有服务器名称( $server_name )、请求的 URI 和响应状态码。除基本信息外,还有一些统计的结果数据:包括请求处理的毫秒级时间( $request_time)、服务器响应的数据块大小( $body_bytes_sent )。此外,客户端所在国家( $geoip_city_country_code3 )、地区( $geoip_region )和城市信息( $geoip_city )也被记录在内。变量 $http_x_forwarded_for 用于记录由其它代理服务器发起的请求的 X-Forwarded-For 头消息。upstream 模块中一些数据也被记录到日志里:被代理服务器的响应状态码( $upstream_status ) 和服务器处理时间( $upstream_response_time )。请求来源( $http_referer )和用户代理( $http_user_agent ) 也有被记录在日志里。从上面可以看出 NGINX 日志记录功能还是非常强大和灵活的,不过用于定义日志格式的 log_format 指令仅适用于 http 块级指令内,这一点需要注意。

这个日志的每个日志记录结果类似下面示例:

[25/Nov/2016:16:20:42 +0000] 10.0.1.16 192.168.0.122 Derek
GET HTTP/1.1 http www.example.com / 200 0.001 370 USA MI
"Ann Arbor" - 200 0.001 "-" "curl/7.47.0"

如果需要使用这个日志配置,需要结合使用 access_log 指令,access_log 指令接收一个日志目录和使用的配置名作为参数:

server {
	access_log /var/log/nginx/access.log geoproxy;
...
}

access_log 能在多个上下文使用,每个上下文中可以定义各自的日志目录和日志记录格式。

结论
NGINX 中的日志模块允许您为不同的场景配置日志格式,以便查看不同的日志文件。在实际运用中,为不同上下文配置不同的日志会非常有用,记录的日志内容可以简单的信息,也可以事无巨细的记录所有必要信息。不仅如此,日志内容除了支持文本也能记录 JSON 格式和 XML 格式数据。实际上 NGINX 日志有助于您了解服务器流量、客户端使用情况和客户端来源等信息。此外,访问日志还可以帮助您定位与上游服务器或特定 uri 相关的响应和问题;对于测试来讲,访问日志同样有用,它可以用于分析流量情况,模拟真实的用户交互场景。日志在故障排除、调试、应用分析及业务调整中作用是不可或缺的。

问题
需要更深入的定位 NGINX 服务器问题,以配置错误日志。
解决方案
使用 error_log 指令定义错误日志目录及记录错误日志的等级:

error_log /var/log/nginx/error.log warn;

error_log 指令配置时需要一个必选的日志目录和一个可选的错误等级选项。除 if 指令外,error_log 指令能在所有的上下文中使用。错误日志等级包括:debug、info、notice、warn、error、crit、alert 和 emerg。给出的日志等级顺序就是记录最小到最严谨的日志等级顺序。需要注意的是 debug 日志需要在编译 NGINX 服务器时,带上 --with-debug 标识才能使用。

结论
请牢记当服务器配置出错时,首先需要查看错误日志以定位问题。当然,错误日志也是定温应用服务器(如 FastCGI 服务)的利器。通过错误日志,我们可以调试 worder进程连接错误、内存分配、客户端 IP 和 应用服务器等问题。错误日志格式虽然不支持自定义日志格式;但是,它同样记录当前时间、日志等级和具体信息等数据。

问题
需要将错误日志通过 syslog 服务记录到集中日志服务器。
解决方案
在使用 error_log 和 access_log 指令时,将日志发送至 syslog 监听器:

error_log syslog:server=10.0.1.42 debug;
access_log syslog:server=10.0.1.42,tag=nginx,severity=info geoproxy;

error_log 和 access_log 指令的 syslog 参数紧跟冒号(:)和一些参数选项。包括:必选的 server 标记表示需要连接的 IP、DNS 名称或 UNIX 套接字;可选参数有 facility、severity、tag 和 nohostname。server 参数接收带端口的 IP 地址或 DNS 名称;默认是 UDP 514 端口。facility 参数设置syslog 的类型(facility),值是 syslog RFC 标准定义的 23 个值中的一个(@todo)。tag 参数表示日志文件中显示时候的标题,默认值是 nginx。
severity 设置消息严重程度,默认是 info 级别日志。nohostname 选项,禁止将 hostname 域添加到syslog的消息头中。

结论
syslog 是用于在单台服务器或服务器集群中记录和收集日志的标准协议。在多个主机上运行相同服务的多个实例时,将日志发送到集中位置有助于调试,这称为聚合日志。聚合日志允许您在一个地方查看日志,而不必切换不同服务器,并通过时间戳将日志文件集成在一起。常见聚合日志解决方案有 ElasticSearch、Logstash、Kibana 和 ELK Stack。但 NGINX 通过发送日志到 syslog 监听器,能够很容易的将 access_log 和 error_log 指令捕捉的日志发送到聚合日志服务器上。

问题
需要结合 NGINX 日志和应用日志,查看请求调用栈。
解决方案
使用 request 标识,并将标识写入到应用日志里:

log_format trace '$remote_addr - $remote_user [$time_local] '
				'"$request" $status $body_bytes_sent '
				'"$http_referer" "$http_user_agent" '
				'"$http_x_forwarded_for" $request_id';
	upstream backend {
		server 10.0.0.42;
	}
	server {
		listen 80;
		add\_header X-Request-ID $request\_id; \# Return to client
	location / {
		proxy_pass http://backend;
		proxy_set_header X-Request-ID $request_id; \#Pass to app
		access_log /var/log/nginx/access_trace.log trace;
	}
}

示例中,配置了名为 trace 的访问日志格式,并在日志中使用 $request_id 参数。同时,通过 proxy_set_header 指令将 request 标记(request ID)设置到请求头里,当请求匹配到 location / 前缀,请求被转发到 upstream 模块,这样同一个 request 标识就能记录到应用服务器日志里;此外,通过 add_header 指令将 reqeust 标识设置到响应消息头,供客户端使用。

结论
该功能在 NGINX Plus R10 版本和 NGINX 开源版的 1.11.0 版本可用,$request_id 提供了一个随机生成的 32 个十六进制字符的字符串,这些字符可以用来唯一地标识请求。通过将此标识符传递给客户端和应用服务器,可以将日志与请求关联起来。客户端会收到唯一的 request 标识,服务端也能使用该标识进行日志筛选。应用服务器使用时,需要获取这个消息头,以建立日之间的关联。基于这个特性,NGINX 能够构建从客户端请求到应用服务器做出响应的整个请求调用周期的所有日志信息之间的关联。

问题
使用负载测试工具实现自动化测试
解决方案
使用 HTTP 负载测试工具:如 Apache JMeter/ Locust/ Gatling/或团队自研的负载工具。为测试定制测试配置,并对服务器进行全面测试,基于测试结果量化性能指标;之后,逐步增加用户数增加并发量,以模拟生产环境真实请求,找出性能瓶颈优化;如此反复,直至达到项目的预期性能。
结论
使用自动化的测试工具来定义您的测试,可以让您通过一个一致的测试来找出对 NGINX 进行调优的基准。性能测试必须是可重复的,通过对性能测试结果进行科学分析。在对 NGINX 配置进行优化前,需对服务器进行测试确定标准,这样,才能确定之后的配置优化是否实现了性能的优化。对每个配置优化进行度量,将帮助您确定性能得以提升的根源。

问题
增加单个连接的请求数,同时增加空闲连接(idle connections)的的连接时长。
解决方案
keepalive_requests 和 keepalive_timeout 指令允许变更单个连接的最大请求数和空闲连接的连接时长:

http {
	keepalive_requests 320;
	keepalive_timeout 300s;
...
}

keepalive_requests 默认为 100,keepalive_timeout 的默认值为 75 秒。

结论
一般情况下,keepalive_requests 和 keepalive_timeout 的默认配置,能够满足客户端的请求,因为,现代浏览器能为不同域名打开多个连接。但对于同一个域名仅能同时发起 10 以内的请求,这将带来性能瓶颈。CDN 的实现原理是启用多个域名指向内容服务器,并以编码的方式指定使用的域名,以使浏览器能够打开更多的连接。你会发现使用更多的请求连接数和连接时长配置,在客户端需要频繁更新数据能提升服务器性能。

问题
需要增加代理服务器与被代理服务器的连接数,提升服务器性能。
解决方案
在 upstream 会计指令中使用 keepalive 指令保持代理服务与被代理服务器连接以复用:

proxy_http_version 1.1;
proxy_set_header Connection "";
upstream backend {
	server 10.0.0.42;
	server 10.0.2.56;
	keepalive 32;
}

keepalive 指令会为每个 NGINX worker 进程创建一个连接缓存,表示每个worker 进程能保持打开的空闲连接的最大连接数量。如果要使 keepalive指令正常工作,在 upstream 指令上使用的 proxy 模块指令则是必须的。proxy_http_version 指令表示启用的 http 1.1 版本,它允许在单个连接上发送多个请求;proxy_set_header 指令删除 connection 消息头的默认值 close,这样就允许保持连接的打开状态。

结论
当需要保持代理服务器与被代理服务器的连接打开状态,以节省启动连接
所需的时间;同时,需要将 worker 进程收到的请求分发值空闲的连接直接
处理。有一点需要注意,开启的连接数可以多于 keepalive 配置的连接数,
因为开启的连接数和空闲连接数不是同一个东西。keepalive 配置的连接数
应尽量少,以确保新的请求能够被分发到被代理服务器。这条配置技巧能够
通过减少请求连接的生命周期的手段,提升服务器性能。

问题
将服务器对客户端的响应写入内存缓冲区而不是文件里。
解决方案
调整代理模块的缓存区设置,允许 NGINX 服务器将响应消息体写入内存缓冲区:

server {
	proxy_buffering on;
	proxy_buffer_size 8k;
	proxy_buffers 8 32k;
	proxy_busy_buffer_size 64k;
...
}

proxy_buffering 值可以使 on 或 off,默认是 on。proxy_buffer_size 指令表示用于读取来自代理服务器响应的缓冲大小,依据平台不同它的默认值为4k 或 8k。proxy_buffers 指令包含两个值,支持的缓存区个数和单个缓存区容量大小,默认是 8 个缓存区,依据平台不同单个缓存区默认容量为 4k 或 8k。proxy_busy_buffer_size 指令用于配置未完全读取响应时直接响应客户端的缓冲区大小,它的空间一般为 proxy_buffers 的两倍为最佳。

结论
代理缓存能显著提升代理服务性能,这取决于响应内容的大小。开启缓冲区设置应当仔细测试响应内容的平均大小,并进行大量测试和调试,否则可能引发副作用。而如果将缓存区大小设置的非常大也不行,这回占用大量的 NGINX 内存。一种方案是将缓冲区大小设置为与最大响应消息相同以提升性能。

问题
当系统处于负载状态时,启用日志缓冲区以降低 NGINX worker 进程阻塞。
解决方案
设置 access_log 的 buffer 和 flush 参数:

http {
	access_log /var/log/nginx/access.log main buffer=32k flush=1m;
}

buffer 参数用于设置,写入文件前的缓冲区内存大小;flush 参数设置缓冲区内日志在缓冲区内存中保存的最长时间。

结论
将日志数据缓冲到内存中可能是很小的一个优化手段。但是,对于有大量请求的站点和应用程序的磁盘读写和 CPU 使用性能有重大意义。buffer 参数的功能是当缓冲区已经写满时,日志会被写入文件中;flush 参数的功能是,当缓存中的日志超过最大缓存时间,也会被写入到文件中,不过也有不足的地方即写入到日志文件的日志有些许延迟。