Nginx与Spring Cloud Gateway QPS统计全攻略

一、为什么QPS统计如此重要

1. 性能监控的核心指标

  • QPS(Queries Per Second):每秒查询率,是衡量系统性能的关键指标
  • 容量规划:帮助预估系统承载能力和扩展需求
  • 故障预警:及时发现系统性能瓶颈和异常

2. 不同场景下的QPS统计策略

  • 网关层统计:适用于微服务架构的整体监控
  • 应用层统计:适用于具体业务接口的精细化监控
  • 基础设施统计:基于Nginx等基础组件的统计方案

二、Nginx网关层QPS统计实战

1. 基础配置实现

1.1 nginx.conf配置详解
ini 复制代码
http {
    # 开启状态监控页面
    server {
        listen 8080;
        location /nginx-status {
            stub_status on;
            allow 192.168.0.0/24; # 只允许内网访问
            deny all;
        }
    }

    # 记录详细请求日志(用于离线分析)
    log_format main '$remote_addr [$time_local] "$request" $status $request_time';
    server {
        listen 80;
        server_name api.example.com;
        access_log /var/log/nginx/api-access.log main; # 日志路径

        # 转发到后端服务
        location / {
            proxy_pass http://backend-service;
        }
    }
}

配置要点说明:

  • stub_status on:启用Nginx状态模块
  • 访问控制:只允许内网IP访问状态页面,保证安全性
  • 自定义日志格式:便于后续分析
1.2 实时QPS查看

访问 http://192.168.0.100:8080/nginx-status,返回信息:

yaml 复制代码
Active connections: 200
server accepts handled requests
 10000  10000  100000
Reading: 0 Writing: 1  Waiting: 190

数据解读:

  • Active connections:当前活跃连接数
  • accepts/handled/requests:分别表示接受的连接数、处理的连接数、总请求数
  • QPS计算公式:requests/时间间隔 100000/10 =10000 QPS

2. 自动化QPS统计脚本

2.1 Shell脚本实现
bash 复制代码
while true; do
    # 取当前请求数
    current=$(curl -s http://192.168.0.100:8080/nginx-status | awk 'NR==3 {print $3}')
    sleep 1
    # 取1秒后请求数
    next=$(curl -s http://192.168.0.100:8080/nginx-status | awk 'NR==3 {print $3}')
    qps=$((next - current))
    echo "当前QPS: $qps"
done
2.2 脚本优化建议
  • 添加错误处理机制
  • 输出格式化为JSON便于集成
  • 支持阈值告警功能

三、Spring Cloud Gateway QPS统计实践

1. 自定义全局过滤器实现

1.1 QpsStatisticsFilter核心代码
java 复制代码
@Component
public class QpsStatisticsFilter implements GlobalFilter, Ordered {
    // 存储接口QPS:key=接口路径,value=原子计数器
    private final Map<String, AtomicLong> pathQpsMap = new ConcurrentHashMap<>();

    // 定时1秒清零计数器(避免数值过大)
    @PostConstruct
    public void init() {
        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
        executor.scheduleAtFixedRate(() -> {
            // 遍历所有接口,打印QPS后清零
            pathQpsMap.forEach((path, counter) -> {
                long qps = counter.getAndSet(0);
                log.info("接口[{}] QPS: {}", path, qps);
            });
        }, 0, 1, TimeUnit.SECONDS);
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 获取请求路径(如/order/seckill)
        String path = exchange.getRequest().getPath().value();
        // 计数器自增(线程安全)
        pathQpsMap.computeIfAbsent(path, k -> new AtomicLong()).incrementAndGet();
        // 继续转发请求
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -1; // 过滤器优先级:数字越小越先执行
    }
}
1.2 关键设计思路
  • ConcurrentHashMap:保证线程安全的同时提供高并发性能
  • AtomicLong:原子操作确保计数准确性
  • ScheduledExecutorService:定时任务清理计数器

2. 踩坑经验总结

2.1 健康检查请求过滤
java 复制代码
if (path.startsWith("/actuator")) return chain.filter(exchange);

四、应用层AOP QPS统计深度解析

1. Spring AOP实现方案

1.1 依赖配置
xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
1.2 自定义切面实现
java 复制代码
@Aspect
@Component
@Slf4j
public class ApiQpsAspect {
    // 存储接口QPS:key=接口名(如com.example.OrderController.createOrder),value=计数器
    private final Map<String, AtomicLong> apiQpsMap = new ConcurrentHashMap<>();

    // 定时1秒打印QPS并清零
    @PostConstruct
    public void scheduleQpsPrint() {
        Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> {
            apiQpsMap.forEach((api, counter) -> {
                long qps = counter.getAndSet(0);
                if (qps > 0) { // 只打印有请求的接口
                    log.info("[QPS统计] 接口: {}, QPS: {}", api, qps);
                }
            });
        }, 0, 1, TimeUnit.SECONDS);
    }

    // 切入点:拦截所有Controller方法
    @Pointcut("execution(* com.example.*.controller..*(..))")
    public void apiPointcut() {}

    // 环绕通知:统计请求数
    @Around("apiPointcut()")
    public Object countQps(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取接口名(类名+方法名)
        String apiName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
        // 计数器自增
        apiQpsMap.computeIfAbsent(apiName, k -> new AtomicLong()).incrementAndGet();
        // 执行原方法
        return joinPoint.proceed();
    }
}

2. 进阶优化方案

2.1 有效请求过滤
java 复制代码
// 在countQps方法中添加响应状态判断
if (response.getStatusCode().is2xxSuccessful()) {
    apiQpsMap.computeIfAbsent(apiName, k -> new AtomicLong()).incrementAndGet();
}
2.2 响应时间统计增强
java 复制代码
// 记录响应时间
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long cost = System.currentTimeMillis() - start;
// 存储响应时间(key=接口名,value=时间列表)
timeMap.computeIfAbsent(apiName, k -> new CopyOnWriteArrayList<>()).add(cost);
// 计算平均响应时间
double avgTime = timeMap.get(apiName).stream().mapToLong(Long::longValue).average().orElse(0);

3. 生产环境最佳实践

3.1 并发安全保障
  • 必须使用AtomicLong进行计数
  • 避免long变量的线程安全问题
3.2 性能影响控制
  • AOP开销:单请求约0.1ms,影响较小
  • 条件启用 :使用@Conditional控制只在非生产环境启用
  • Java Agent替代:减少代码侵入性

五、三种方案对比与选型建议

方案 优势 劣势 适用场景
Nginx统计 简单易用,性能好 无法区分业务接口 中小项目,基础监控
Gateway统计 统一入口,功能丰富 部署复杂,学习成本高 微服务架构
AOP统计 精细控制,业务感知强 侵入性强,性能开销 单体应用,业务监控

选型建议:

  1. 中小项目:优先选择Nginx方案
  2. 微服务架构:推荐Gateway方案
  3. 精细化监控:采用AOP方案
  4. 混合使用:多维度监控,相互验证

通过本文的深入分析,相信你已经掌握了不同场景下QPS统计的最佳实践。记住,选择合适的方案比盲目追求复杂的技术更重要!

相关推荐
进阶的猿猴2 小时前
java中实现markdown转为pdf
java·pdf·markdown
康王有点困2 小时前
Link入门
后端·flink
Coder_Boy_2 小时前
基于SpringAI的在线考试系统-试卷管理模块完整优化方案
前端·人工智能·spring boot·架构·领域驱动
海南java第二人2 小时前
Spring Boot全局异常处理终极指南:打造优雅的API错误响应体系
java·spring boot·后端
南朝雨2 小时前
Spring Boot Admin日志监控坑点:远程配置的logging.file.name为何生效又失效?
java·spring boot·spring cloud·微服务·logback
何以不说话2 小时前
zabbix部署及nginx的监控
运维·nginx·zabbix
sanggou2 小时前
Spring Cloud Gateway 转发 SSE 的那些坑
java
それども2 小时前
理解 Java21 虚拟线程
java
毕设源码-赖学姐2 小时前
【开题答辩全过程】以 基于JAVA的宠物医院管理系统的设计为例,包含答辩的问题和答案
java·开发语言