You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenResty与Lua性能调优:定位高CPU耗时代码方案示例

Hey there! Let’s dig into troubleshooting your OpenResty 1.15.8.1 (Lua 5.2.4) performance issues—slow request handling and high CPU during validation are classic bottlenecks we can pinpoint with targeted tools. Below are practical, accurate methods to analyze function-level CPU usage, memory allocation, and latency, along with actionable examples:

1. Precision Timing for Function Latency

Use OpenResty’s built-in ngx.now() to wrap your validation and request-handling functions, tracking exact execution time, call counts, and aggregated stats. This is great for pinpointing slow individual functions.

-- Initialize a global table to track performance stats
local perf_stats = {}

local function timeit(func, ...)
    local func_name = debug.getinfo(func).name or "anonymous"
    local start = ngx.now()
    -- Execute the function and capture its return values
    local result = {func(...)}
    local elapsed = (ngx.now() - start) * 1000 -- Convert to milliseconds

    -- Update stats for the function
    if not perf_stats[func_name] then
        perf_stats[func_name] = {count = 0, total_ms = 0, max_ms = 0}
    end
    local stats = perf_stats[func_name]
    stats.count = stats.count + 1
    stats.total_ms = stats.total_ms + elapsed
    stats.max_ms = math.max(stats.max_ms, elapsed)

    -- Print a summary every 100 requests to avoid log spam
    if stats.count % 100 == 0 then
        local avg_ms = stats.total_ms / stats.count
        ngx.log(ngx.INFO, string.format(
            "[PERF SUMMARY] %s: Calls=%d | Avg=%.3fms | Max=%.3fms",
            func_name, stats.count, avg_ms, stats.max_ms
        ))
    end

    return unpack(result)
end

-- Wrap your validation function with timeit when calling it
local request_data = ngx.req.get_body_data()
local is_valid = timeit(your_validation_function, request_data)

2. CPU Sampling to Identify Hot Functions

Lua’s debug.sethook lets you sample the call stack periodically, revealing which functions consume the most CPU. This is ideal for finding CPU-intensive code segments without adding heavy overhead.

local sample_interval = 0.01 -- Sample every 10ms (adjust based on needs)
local sample_counts = {}

-- Hook function to count active functions during sampling
local function sample_hook()
    local call_info = debug.getinfo(2, "n") -- Get the calling function
    if call_info and call_info.name then
        sample_counts[call_info.name] = (sample_counts[call_info.name] or 0) + 1
    end
end

-- Start sampling (run this in init_worker_by_lua* or your request handler)
debug.sethook(sample_hook, "c", sample_interval * 1000000) -- Convert to microseconds

-- Schedule a periodic report to log CPU distribution
local function report_cpu_samples()
    ngx.log(ngx.INFO, "[CPU SAMPLE REPORT]")
    local total_samples = 0
    for _, count in pairs(sample_counts) do
        total_samples = total_samples + count
    end
    -- Sort functions by sample count (descending)
    local sorted_funcs = {}
    for name, count in pairs(sample_counts) do
        table.insert(sorted_funcs, {name = name, count = count})
    end
    table.sort(sorted_funcs, function(a, b) return a.count > b.count end)
    -- Print results
    for _, func in ipairs(sorted_funcs) do
        local percentage = (func.count / total_samples) * 100
        ngx.log(ngx.INFO, string.format("  %s: %.2f%% (%d samples)", func.name, percentage, func.count))
    end
    -- Reset counts for next interval
    sample_counts = {}
    return true
end

-- Run the report every 60 seconds
ngx.timer.every(60, report_cpu_samples)

Note: Sampling adds minor overhead—disable it once you’ve identified bottlenecks, or increase the interval in production.

3. Memory Allocation Tracking

Use Lua’s garbage collector functions to measure how much memory a function allocates, helping spot leaks or excessive memory usage during validation.

local function track_memory(func, ...)
    -- Force garbage collection to get a clean baseline
    collectgarbage("collect")
    local start_mem_kb = collectgarbage("count") -- Returns KB used
    -- Execute the function
    local result = {func(...)}
    -- Collect garbage again to measure net allocation
    collectgarbage("collect")
    local end_mem_kb = collectgarbage("count")
    local mem_diff_kb = end_mem_kb - start_mem_kb

    ngx.log(ngx.INFO, string.format(
        "[MEM TRACK] %s allocated %.2f KB",
        debug.getinfo(func).name or "anonymous", mem_diff_kb
    ))

    return unpack(result)
end

-- Use it with your validation function
local is_valid = track_memory(your_validation_function, request_data)

4. System-Level Profiling with perf

For deeper insights (including interactions between Lua code and Nginx’s C core), use the Linux perf tool to sample your OpenResty worker process:

# Find the PID of your OpenResty worker process
ps aux | grep nginx | grep worker

# Sample CPU usage for 30 seconds, capturing call graphs
perf record -p <WORKER_PID> -g -F 99 -- sleep 30

# Generate a human-readable report
perf report

This will show you which Lua functions (and Nginx internal functions) are consuming the most CPU, even for low-level operations.

5. Offline Testing with resty-cli

If your validation logic can run independently, use resty-cli’s profiling mode to get a quick breakdown of function performance in a development environment:

# Run your validation script with profiling enabled
resty --profile your_validation_logic.lua

The output will include call counts, total time, and average time per function call—perfect for iterative testing.

Key Tips for Production

  • Avoid long-running debug tools: All profiling methods add overhead—enable them only during troubleshooting windows.
  • Prioritize validation logic: Focus your analysis on functions tied to request validation (signature checks, parameter parsing, external auth calls) since that’s where you’ve observed issues.
  • Check for blocking IO: If latency comes from waiting on external services (e.g., Redis, databases), switch to async patterns like resty.http’s async requests or ngx.timer to avoid blocking the worker process.

内容的提问来源于stack exchange,提问作者Abdol Seed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 11:12:51