服务端性能监控最佳实践(一)—— 炫酷的Nginx请求分析监控

本文介绍了如何通过lua脚本增强Nginx请求监控,利用openresty或nginx-lua-module配置Nginx,并结合Prometheus和Grafana实现详细的请求分析和多维度数据展示,包括Nginx整体、单个host、endpoint和url的监控。
摘要由CSDN通过智能技术生成

一、Nginx监控的重要性

在服务端性能监控领域中,Nginx是其中非常重要的一部分,不仅仅是因为它是所有请求的入口、必经之处。还因为它的日志包含了请求的关键信息,像每次请求的返回状态码、处理时间、由哪一台后端机器处理,从这些信息里面,能分析出请求的处理情况,从中定位到有问题的请求,为我们的性能优化提供很重要的参考。

网络上常见的Nginx监控,一般是通过nginx-module-vts模块,使用这个模块,能获取到某个模块的分域名请求数量、1xx 2xx的请求占比,和nginx的进出流量,因为只能获取到统计数据,对监控nginx正常运行能启动一定作用,但对实际请求分析作用不大。

今天我们要采用的是借助lua脚本的形式,对Nginx的请求进行具体到url的监控,通过grafana提供多维度的数据分析。先上图,最终能对每个Url进行非常详细的请求监控

8HpLOP.png

二、配置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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值