文章目录
一、Nginx监控的重要性
在服务端性能监控领域中,Nginx是其中非常重要的一部分,不仅仅是因为它是所有请求的入口、必经之处。还因为它的日志包含了请求的关键信息,像每次请求的返回状态码、处理时间、由哪一台后端机器处理,从这些信息里面,能分析出请求的处理情况,从中定位到有问题的请求,为我们的性能优化提供很重要的参考。
网络上常见的Nginx监控,一般是通过nginx-module-vts模块,使用这个模块,能获取到某个模块的分域名请求数量、1xx 2xx的请求占比,和nginx的进出流量,因为只能获取到统计数据,对监控nginx正常运行能启动一定作用,但对实际请求分析作用不大。
今天我们要采用的是借助lua脚本的形式,对Nginx的请求进行具体到url的监控,通过grafana提供多维度的数据分析。先上图,最终能对每个Url进行非常详细的请求监控
二、配置Nginx
1、Nginx支持lua
首先nginx当然要支持lua脚本,这个可以进行验证,当然一般nginx默认是不会安装支持这个模块的,需要进行重新编译,这里提供两种方式。如下
①直接使用openresty
openresty是基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。
建议懒得动手的同学可以直接安装openresty,使用起来和只用nginx并没有区别,相反包含了很多第三方模块,省了很多麻烦。
②安装nginx-lua-module
nginx-lua-module是nginx的一个模块,可以支持nginx运行lua脚本,需要重新编译nginx,这个步骤晚上的教程有很多,可以参考https://blog.csdn.net/qq_25551295/article/details/51744815。
2、配置nginx.conf
需要在conf文件夹进行配置lua脚本。
① conf.d
创建conf.d文件夹,新建文件counter.conf,写入内容
# Please copy to nginx's conf.d directory
# Set search paths for pure Lua external libraries (';;' is the default path):
lua_package_path "/usr/local/openresty/nginx/conf/conf.d/?.lua;;/usr/local/openresty/nginx/conf/lua/?.lua;;";
# Set Prometheus global dict
lua_shared_dict prometheus_metrics 10M; #init 10M memory
lua_shared_dict uri_by_host 10M;
lua_shared_dict global_set 1M;
# Development option, if deploy production, pls cache on!
lua_code_cache off;
init_by_lua_block {
counter = require 'counter'
counter.init()
}
log_by_lua_block {
counter.log()
}
# Expose prometheus's metrics scrape port
server {
listen 9145;
allow all;
deny all;
access_log off;
location /metrics {
content_by_lua 'prometheus:collect()';
}
}
②lua文件夹
创建lua文件夹,创建两个文件 counter.lua prometheus.lua 内容如下:
counter.lua
local pcall = pcall
local ngx = ngx
local ngx_log = ngx.log
local ngx_err = ngx.ERR
local _M = {}
function _M.init()
uris = ngx.shared.uri_by_host
global_set = ngx.shared.global_set
global_set:set("initted", false)
global_set:set("looped", false)
prometheus = require("prometheus").init("prometheus_metrics")
metric_latency = prometheus:histogram("nginx_http_request_duration_seconds", "HTTP request latency status", {"host", "status", "scheme", "method", "endpoint", "fullurl"})
end
local function split(inputstr, sep)
if sep == nil then
sep = "%s"
end
local t={} ; i=1
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
t[i] = str
i = i + 1
end
return t
end
local function parse_fullurl(request_uri)
result_table = {}
if string.find(request_uri, "%.") ~= nil then
return nil
end
parts = split(request_uri, "/")
if table.getn(parts) == 1 then
return nil
end
for j=1, #parts do
if(j == 1) then
endpoint = "/"..parts[j]
fullurl = "/"..parts[j]
elseif(j <= 5) then
if tonumber(parts[j]) ~= nil then
break
end
fullurl = fullurl.."/"..parts[j]
else
break
end
end
result_table["endpoint"] = endpoint
result_table["fullurl"] = fullurl
return result_table
end
function _M.log()
local request_host = ngx.var.host
local request_uri = ngx.unescape_uri(ngx.var.uri)
local request_status = ngx.var.status
local request_scheme = ngx.var.scheme
local request_method = ngx.var.request_method
local remote_ip = ngx.var.remote_addr
local ngx_sent = ngx.var.body_bytes_sent
local latency = ngx.var.upstream_response_time or 0
result_table = parse_fullurl(request_uri)
if result_table == nil then
return
end
ngx_log(ngx_err,"latency=", tonumber(latency), ",status=", request_status, ",endpoint=", result_table["endpoint"], ",fullurl=", result_table["fullurl"])
metric_latency:observe(tonumber(latency), {request_host, request_status, request_scheme, request_method, result_table["endpoint"], result_table["fullurl"]})
end
return _M
prometheus.lua
-- vim: ts=2:sw=2:sts=2:expandtab
--
-- This module uses a single dictionary shared between Nginx workers to keep
-- all metrics. Each counter is stored as a separate entry in that dictionary,
-- which allows us to increment them using built-in `incr` method.
--
-- Prometheus requires that (a) all samples for a given metric are presented
-- as one uninterrupted group, and (b) buckets of a histogram appear in
-- increasing numerical order. We satisfy that by carefully constructing full
-- metric names (i.e. metric name along wi