最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot實(shí)現(xiàn)QPS監(jiān)控的完整代碼

 更新時(shí)間:2025年12月10日 10:04:17   作者:悟空碼字  
本文介紹了QPS(每秒查詢率)的概念,并討論了三種監(jiān)控方案:簡易版(AOP攔截器)、專業(yè)版(Micrometer+Prometheus)和豪華版(SpringBootAdmin),每種方案都有詳細(xì)的實(shí)施步驟,文章還介紹了QPS統(tǒng)計(jì)的進(jìn)階技巧,并強(qiáng)調(diào)了監(jiān)控系統(tǒng)的重要性,需要的朋友可以參考下

一、什么是QPS?—— 系統(tǒng)的"心跳頻率" 

想象一下你的系統(tǒng)就像一個(gè)忙碌的外賣小哥,QPS(Query Per Second)就是他每秒能送多少份外賣!如果小哥每秒只能送1單,那估計(jì)顧客早就餓暈在廁所了;要是每秒能送100單,那他絕對(duì)是"閃電俠"附體!

正常系統(tǒng)的QPS就像人的心跳:

  • 60-100 QPS:健康小伙子,心跳平穩(wěn)
  • 100-1000 QPS:健身達(dá)人,有點(diǎn)小激動(dòng)
  • 1000+ QPS:跑馬拉松呢!快喘口氣!
  • 10000+ QPS:這貨是打了雞血吧?

二、方案大比拼——給系統(tǒng)裝上"智能手環(huán)"

方案1:簡易版手環(huán)(AOP攔截器)

適合小項(xiàng)目,就像給系統(tǒng)戴個(gè)手環(huán)

@Slf4j
@Aspect
@Component
public class QpsMonitorAspect {
    
    // 用ConcurrentHashMap存計(jì)數(shù)器,線程安全!
    private final ConcurrentHashMap<String, AtomicLong> counterMap = new ConcurrentHashMap<>();
    private ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    
    @PostConstruct
    public void init() {
        log.info("QPS監(jiān)控龜龜已啟動(dòng),開始慢慢爬...");
        // 每秒統(tǒng)計(jì)一次,像烏龜一樣穩(wěn)定
        scheduler.scheduleAtFixedRate(this::printQps, 0, 1, TimeUnit.SECONDS);
    }
    
    @Around("@annotation(org.springframework.web.bind.annotation.GetMapping) || " +
            "@annotation(org.springframework.web.bind.annotation.PostMapping)")
    public Object countQps(ProceedingJoinPoint joinPoint) throws Throwable {
        String methodName = joinPoint.getSignature().toShortString();
        
        // 計(jì)數(shù)器自增,像小松鼠囤松果一樣積極
        counterMap.computeIfAbsent(methodName, k -> new AtomicLong(0))
                 .incrementAndGet();
        
        long start = System.currentTimeMillis();
        try {
            return joinPoint.proceed();
        } finally {
            long cost = System.currentTimeMillis() - start;
            // 順便記錄一下響應(yīng)時(shí)間,看看系統(tǒng)是不是"老了腿腳慢"
            if (cost > 1000) {
                log.warn("方法 {} 執(zhí)行了 {}ms,比蝸牛還慢!", methodName, cost);
            }
        }
    }
    
    private void printQps() {
        if (counterMap.isEmpty()) {
            log.info("系統(tǒng)在睡大覺,沒有請(qǐng)求...");
            return;
        }
        
        StringBuilder sb = new StringBuilder("\n========== QPS報(bào)告 ==========\n");
        counterMap.forEach((method, counter) -> {
            long qps = counter.getAndSet(0); // 重置計(jì)數(shù)器
            String status = "";
            if (qps > 1000) status = "";
            if (qps > 5000) status = "";
            
            sb.append(String.format("%s %-40s : %d QPS%n", 
                    status, method, qps));
        });
        sb.append("================================");
        log.info(sb.toString());
    }
}

方案2:專業(yè)版體檢儀(Micrometer + Prometheus)

適合大項(xiàng)目,就像給系統(tǒng)做全面體檢

@Configuration
public class MetricsConfig {
    
    @Bean
    public MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
        return registry -> {
            registry.config().commonTags("application", "my-awesome-app");
            log.info("系統(tǒng)體檢中心開業(yè)啦!歡迎隨時(shí)來檢查身體~");
        };
    }
}

@Service
public class OrderService {
    
    private final Counter orderCounter;
    private final Timer orderTimer;
    private final MeterRegistry meterRegistry;
    
    public OrderService(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        
        // 創(chuàng)建訂單計(jì)數(shù)器,像收銀機(jī)一樣"叮叮叮"
        this.orderCounter = Counter.builder("order.count")
                .description("訂單數(shù)量統(tǒng)計(jì)")
                .tag("type", "create")
                .register(meterRegistry);
        
        // 創(chuàng)建訂單耗時(shí)計(jì)時(shí)器
        this.orderTimer = Timer.builder("order.process.time")
                .description("訂單處理時(shí)間")
                .register(meterRegistry);
    }
    
    public Order createOrder(OrderDTO dto) {
        // 記錄方法執(zhí)行時(shí)間
        return orderTimer.record(() -> {
            log.debug("正在打包訂單,請(qǐng)稍候...");
            
            // 業(yè)務(wù)邏輯...
            Order order = doCreateOrder(dto);
            
            // 訂單創(chuàng)建成功,計(jì)數(shù)器+1
            orderCounter.increment();
            
            // 動(dòng)態(tài)QPS統(tǒng)計(jì)(最近1分鐘)
            double qps = meterRegistry.get("order.count")
                    .counter()
                    .measure()
                    .stream()
                    .findFirst()
                    .map(Measurement::getValue)
                    .orElse(0.0) / 60.0;
            
            if (qps > 100) {
                log.warn("訂單處理太快了!當(dāng)前QPS: {}/s,考慮加點(diǎn)運(yùn)費(fèi)?", qps);
            }
            
            return order;
        });
    }
    
    // 動(dòng)態(tài)查看QPS的API
    @GetMapping("/metrics/qps")
    public Map<String, Object> getRealTimeQps() {
        Map<String, Object> metrics = new HashMap<>();
        
        // 收集所有接口的QPS
        meterRegistry.getMeters().forEach(meter -> {
            String meterName = meter.getId().getName();
            if (meterName.contains(".count")) {
                double qps = meter.counter().count() / 60.0; // 轉(zhuǎn)換為每秒
                metrics.put(meterName, String.format("%.2f QPS", qps));
                
                // 添加表情包增強(qiáng)可視化效果
                String emoji = "";
                if (qps > 100) emoji = "";
                if (qps > 500) emoji = "";
                metrics.put(meterName + "_emoji", emoji);
            }
        });
        
        metrics.put("report_time", LocalDateTime.now());
        metrics.put("message", "系統(tǒng)當(dāng)前狀態(tài)良好,吃嘛嘛香!");
        
        return metrics;
    }
}

方案3:豪華版監(jiān)控大屏(Spring Boot Admin)

給老板看的,必須高大上!

# application.yml
spring:
  boot:
    admin:
      client:
        url: http://localhost:9090  # Admin Server地址
        instance:
          name: "青龍系統(tǒng)"
          metadata:
            owner: "碼農(nóng)小張"
            department: "爆肝事業(yè)部"

management:
  endpoints:
    web:
      exposure:
        include: "*"  # 暴露所有端點(diǎn),不穿"隱身衣"
  metrics:
    export:
      prometheus:
        enabled: true
  endpoint:
    health:
      show-details: ALWAYS
@RestController
@Slf4j
public class QpsDashboardController {
    
    @GetMapping("/dashboard/qps")
    public String qpsDashboard() {
        // 模擬從各個(gè)服務(wù)收集QPS數(shù)據(jù)
        Map<String, Double> serviceQps = getClusterQps();
        
        // 生成ASCII藝術(shù)報(bào)表
        StringBuilder dashboard = new StringBuilder();
        dashboard.append("\n");
        dashboard.append("╔══════════════════════════════════════════╗\n");
        dashboard.append("║        系統(tǒng)QPS監(jiān)控大屏                     ║\n");
        dashboard.append("╠══════════════════════════════════════════╣\n");
        
        serviceQps.forEach((service, qps) -> {
            // 生成進(jìn)度條
            int bars = (int) Math.min(qps / 10, 50);
            String progressBar = "█".repeat(bars) + 
                               "?".repeat(50 - bars);
            
            String status = "正常";
            if (qps > 500) status = "警告";
            if (qps > 1000) status = "緊急";
            
            dashboard.append(String.format("║ %-15s : %-30s ║\n", 
                    service, progressBar));
            dashboard.append(String.format("║   %6.1f QPS %-20s        ║\n", 
                    qps, status));
        });
        
        dashboard.append("╚══════════════════════════════════════════╝\n");
        
        // 添加系統(tǒng)健康建議
        dashboard.append("\n 系統(tǒng)建議:\n");
        double maxQps = serviceQps.values().stream().max(Double::compare).orElse(0.0);
        if (maxQps < 50) {
            dashboard.append("   系統(tǒng)有點(diǎn)閑,可以考慮接點(diǎn)私活~ \n");
        } else if (maxQps > 1000) {
            dashboard.append("   系統(tǒng)快冒煙了!快加機(jī)器!\n");
        } else {
            dashboard.append("   狀態(tài)完美,繼續(xù)保持!\n");
        }
        
        return dashboard.toString();
    }
    
    // 定時(shí)推送QPS警告
    @Scheduled(fixedRate = 60000)
    public void checkQpsAlert() {
        Map<String, Double> currentQps = getClusterQps();
        
        currentQps.forEach((service, qps) -> {
            if (qps > 1000) {
                log.error("救命!{}服務(wù)QPS爆表了:{},快看看是不是被爬了!", 
                         service, qps);
                // 這里可以接入釘釘/企業(yè)微信告警
                sendAlertToDingTalk(service, qps);
            }
        });
    }
    
    private void sendAlertToDingTalk(String service, double qps) {
        String message = String.format(
            "{\"msgtype\": \"text\", \"text\": {\"content\": \"%s服務(wù)QPS異常:%.1f,快去看看吧!\"}}",
            service, qps
        );
        // 調(diào)用釘釘webhook
        log.warn("已發(fā)送釘釘告警:{}", message);
    }
}

三、方案詳細(xì)實(shí)施步驟

方案1實(shí)施步驟(簡易版):

  1. 添加依賴:給你的pom.xml來點(diǎn)"維生素"
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  1. 啟用AOP:在主類上貼個(gè)"創(chuàng)可貼"
@SpringBootApplication
@EnableAspectJAutoProxy  // 啟用AOP魔法
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
        System.out.println("QPS監(jiān)控小雞破殼而出!");
    }
}
  1. 創(chuàng)建切面類:如上文的QpsMonitorAspect
  2. 測試一下:瘋狂刷新接口,看看控制臺(tái)輸出

方案2實(shí)施步驟(專業(yè)版):

  1. 添加全家桶依賴
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-core</artifactId>
</dependency>
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
  1. 配置application.yml
management:
  endpoints:
    web:
      exposure:
        include: health,info,metrics,prometheus
  metrics:
    export:
      prometheus:
        enabled: true
    tags:
      application: ${spring.application.name}
  endpoint:
    metrics:
      enabled: true
  1. 訪問監(jiān)控?cái)?shù)據(jù)
http://localhost:8080/actuator/metrics  # 查看所有指標(biāo)
http://localhost:8080/actuator/prometheus  # Prometheus格式

方案3實(shí)施步驟(豪華版):

  1. 搭建Spring Boot Admin Server
@SpringBootApplication
@EnableAdminServer
public class AdminServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(AdminServerApplication.class, args);
        System.out.println("監(jiān)控大屏已就位,陛下請(qǐng)檢閱!");
    }
}
  1. 客戶端配置:如上文yml配置
  2. 訪問Admin UIhttp://localhost:9090

四、QPS統(tǒng)計(jì)的進(jìn)階技巧

1. 滑動(dòng)窗口統(tǒng)計(jì)(最近N秒的QPS)

public class SlidingWindowQpsCounter {
    // 用環(huán)形隊(duì)列實(shí)現(xiàn)滑動(dòng)窗口
    private final LinkedList<Long> timestamps = new LinkedList<>();
    private final int windowSeconds;
    
    public SlidingWindowQpsCounter(int windowSeconds) {
        this.windowSeconds = windowSeconds;
        log.info("創(chuàng)建滑動(dòng)窗口監(jiān)控,窗口大小:{}秒", windowSeconds);
    }
    
    public synchronized void hit() {
        long now = System.currentTimeMillis();
        timestamps.add(now);
        // 移除窗口外的記錄
        while (!timestamps.isEmpty() && 
               now - timestamps.getFirst() > windowSeconds * 1000) {
            timestamps.removeFirst();
        }
    }
    
    public double getQps() {
        return timestamps.size() / (double) windowSeconds;
    }
}

2. 分位數(shù)統(tǒng)計(jì)(P90/P95/P99響應(yīng)時(shí)間)

@Bean
public MeterRegistryCustomizer<MeterRegistry> addQuantiles() {
    return registry -> {
        DistributionStatisticConfig config = DistributionStatisticConfig.builder()
                .percentiles(0.5, 0.9, 0.95, 0.99)  // 50%, 90%, 95%, 99%
                .percentilePrecision(2)
                .build();
        
        registry.config().meterFilter(
            new MeterFilter() {
                @Override
                public DistributionStatisticConfig configure(
                    Meter.Id id, DistributionStatisticConfig config) {
                    if (id.getName().contains(".timer")) {
                        return config.merge(DistributionStatisticConfig.builder()
                                .percentiles(0.5, 0.9, 0.95, 0.99)
                                .build());
                    }
                    return config;
                }
            }
        );
        
        log.info("分位數(shù)統(tǒng)計(jì)已啟用,準(zhǔn)備精準(zhǔn)打擊慢查詢!");
    };
}

3. 基于QPS的自動(dòng)熔斷

@Component
public class AdaptiveCircuitBreaker {
    private volatile boolean circuitOpen = false;
    private double currentQps = 0;
    
    @Scheduled(fixedRate = 1000)
    public void monitorAndAdjust() {
        // 獲取當(dāng)前QPS
        currentQps = calculateCurrentQps();
        
        if (circuitOpen && currentQps < 100) {
            circuitOpen = false;
            log.info("熔斷器關(guān)閉,系統(tǒng)恢復(fù)供電!當(dāng)前QPS: {}", currentQps);
        } else if (!circuitOpen && currentQps > 1000) {
            circuitOpen = true;
            log.error("熔斷器觸發(fā)!QPS過高: {},系統(tǒng)進(jìn)入保護(hù)模式", currentQps);
        }
        
        // 動(dòng)態(tài)調(diào)整線程池大小
        adjustThreadPool(currentQps);
    }
    
    private void adjustThreadPool(double qps) {
        int suggestedSize = (int) (qps * 0.5);  // 經(jīng)驗(yàn)公式
        log.debug("建議線程池大小調(diào)整為: {} (基于QPS: {})", suggestedSize, qps);
    }
}

五、總結(jié):給系統(tǒng)做QPS監(jiān)控就像...

1.為什么要監(jiān)控QPS?

  • 對(duì)系統(tǒng):就像給汽車裝時(shí)速表,超速了會(huì)報(bào)警
  • 對(duì)開發(fā):就像給程序員裝"健康手環(huán)",代碼跑太快會(huì)冒煙
  • 對(duì)老板:就像給公司裝"業(yè)績大屏",數(shù)字好看心情好

2.各方案選擇建議:

  • 初創(chuàng)公司/小項(xiàng)目:用方案1,簡單粗暴見效快,就像"創(chuàng)可貼"
  • 中型項(xiàng)目/微服務(wù):用方案2,全面體檢不遺漏,就像"年度體檢"
  • 大型分布式系統(tǒng):用方案3,全景監(jiān)控?zé)o死角,就像"衛(wèi)星監(jiān)控"

3.最佳實(shí)踐提醒:

// 記住這些黃金法則:
public class QpsGoldenRules {
    // 法則1:監(jiān)控不是為了監(jiān)控而監(jiān)控
    public static final String RULE_1 = "別讓監(jiān)控把系統(tǒng)壓垮了!";
    
    // 法則2:告警要有意義
    public static final String RULE_2 = "狼來了喊多了,就沒人信了!";
    
    // 法則3:數(shù)據(jù)要可視化
    public static final String RULE_3 = "老板看不懂的圖表都是廢紙!";
    
    // 法則4:要有應(yīng)對(duì)方案
    public static final String RULE_4 = "光報(bào)警不解決,要你有何用?";
}

4.最后總結(jié):

給你的系統(tǒng)加QPS監(jiān)控,就像是:

  • 給外賣小哥配了計(jì)步器 —— 知道他每天跑多少
  • 給程序員裝了鍵盤計(jì)數(shù)器 —— 知道他有多卷
  • 給系統(tǒng)裝了"心電圖機(jī)" —— 隨時(shí)掌握生命體征

記住,一個(gè)健康的系統(tǒng)應(yīng)該:

  • 平時(shí) 心跳平穩(wěn)(QPS穩(wěn)定)
  • 大促時(shí) 適當(dāng)興奮(彈性擴(kuò)容)
  • 故障時(shí) 自動(dòng)降壓(熔斷降級(jí))

現(xiàn)在就去給你的SpringBoot系統(tǒng)裝上"智能手環(huán)"吧!讓它在代碼的海洋里,游得更快、更穩(wěn)、更健康!

最后的最后:監(jiān)控千萬條,穩(wěn)定第一條;QPS不規(guī)范,運(yùn)維兩行淚!

以上就是SpringBoot實(shí)現(xiàn)QPS監(jiān)控的完整代碼的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot實(shí)現(xiàn)QPS監(jiān)控的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論

宁河县| 信丰县| 潮州市| 海林市| 大埔县| 和硕县| 容城县| 绥滨县| 永修县| 临桂县| 比如县| 巴林右旗| 龙海市| 景德镇市| 海南省| 同仁县| 曲麻莱县| 商城县| 涪陵区| 南川市| 万山特区| 阿勒泰市| 陵川县| 娄烦县| 锡林浩特市| 米脂县| 竹北市| 棋牌| 曲水县| 深圳市| 呈贡县| 洛宁县| 嘉荫县| 和硕县| 灌阳县| 博爱县| 克什克腾旗| 石林| 桑植县| 龙井市| 高邑县|