爆肝 30 天!从 JVM 调优到百万级 QPS,我的 Java 性能飞升全记录(2)

【信息科学与工程学】【数据中心】第三十二篇 云数据中心的计算/存储/网络的核心挑战01 状态方程: SOCk+1​=SOCk​−Qn​ik​Δt​;: 三相电流变换到αβ坐标系: iα​=32​​(ia​−21​ib​−21​ic​), iβ​=32​​(23​​ib​−23​​ic​). 计算瞬时有功功率p和无功功率q,经低通滤波器分离直流分量,反变换得基波电流,差值即为谐波指令。: 节点i的信念 bi​(xi​)=ϕi​(xi​)∏j∈N(i)​mji​(xi​), 消息 mij​(xj​)=∑xi​​ϕi​(xi​)ψij​(xi​,xj​)∏k∈N(i)\j​mki​(xi​). 阅读详情

前言:从崩溃边缘到百万级 QPS 的逆袭

凌晨 3 点的办公室,监控大屏突然飙红,QPS 从 5 万断崖式下跌到 800,CPU 满载报警,GC 时间突破 3 秒大关——这是我们的电商大促系统在压测中遭遇的至暗时刻。经过 30 天不眠不休的鏖战,最终实现了 单集群百万 QPS、平均响应时间 23ms、GC 停顿控制在 50ms 内 的蜕变。本文将完整还原这场技术攻坚的每个关键细节。


第一章:JVM 调优生死局 —— 从参数盲调到精准打击

1.1 内存模型重构实战

初始配置(踩坑典型):

bashCopy Code
-Xmx32g -Xms32g -XX:+UseParallelGC

系统运行 2 小时后 Full GC 时长突破 4 秒,年轻代频繁晋升导致老年代积压。

优化后配置(经过 17 次压测验证):

bashCopy Code
# 电商交易核心服务(32C128G 物理机)
-Xmx96g -Xms96g 
-XX:MaxMetaspaceSize=512m
-XX:+UseG1GC 
-XX:G1HeapRegionSize=8m                  # 匹配订单对象平均大小
-XX:InitiatingHeapOccupancyPercent=35     # 比默认值激进 10%
-XX:G1NewSizePercent=30                   # 年轻代初始占比
-XX:G1MaxNewSizePercent=60                # 动态扩容上限
-XX:ConcGCThreads=12                      # 并发标记线程数=总核数*0.25
-XX:ParallelGCThreads=24                  # 并行回收线程数=总核数*0.75
-XX:+UnlockExperimentalVMOptions 
-XX:G1MixedGCLiveThresholdPercent=85      # 混合GC存活率阈值

调优成效:

  • Young GC 频率从 15次/分钟 → 5次/分钟
  • Mixed GC 耗时从 1800ms → 120ms
  • 对象晋升率降低 67%

第二章:GC 日志的福尔摩斯式侦查

2.1 关键日志模式识别

shellCopy Code
# 异常模式:过早晋升
[GC pause (G1 Evacuation Pause) (young)  
  Survived: 2048M->2048M(3072M)          # 存活对象零回收!
  Eden: 4096M->0M(6144M)  
  Heap: 92G->92G(96G)]  

# 健康模式:合理回收
[GC pause (G1 Evacuation Pause) (young)  
  Survived: 512M->128M(3072M)  
  Eden: 6144M->0M(6144M)  
  Heap: 94G->88G(96G)]  

诊断工具链:

  1. GCViewer:可视化 GC 事件分布
  2. GCEasy:自动生成吞吐量/停顿时间报告
  3. 自研分析脚本:实时监控晋升速率(代码片段):
pythonCopy Code
def check_promotion_rate(log_line):
    if "Survivor" in log_line:
        before = extract_value(log_line, "Survivor Before: (\d+)M")
        after = extract_value(log_line, "Survivor After: (\d+)M")
        rate = (after - before)/before
        if rate > 0.7:
            alert("对象晋升异常!检查年龄阈值")

第三章:线程池的军火库 —— 参数矩阵与动态兵法

3.1 线程池黄金法则

场景

核心公式

特殊处理

CPU密集型

核心数 = N + 1

队列容量 ≤ 核心数 × 2

IO密集型

最大线程数 = 核心数 × (1 + WT/ST)

监控上下文切换频率

混合型

按业务拆分独立池

使用不同队列策略

动态调参实战(基于 Spring Boot Actuator):

javaCopy Code
@RestController
public class ThreadPoolController {

    @Autowired
    private ThreadPoolTaskExecutor orderExecutor;

    @PostMapping("/adjust-pool")
    public void adjustPool(
        @RequestParam int coreSize,
        @RequestParam int maxSize) {
        
        // 热更新核心参数
        orderExecutor.setCorePoolSize(coreSize);
        orderExecutor.setMaxPoolSize(maxSize);
        
        // 队列容量动态扩容(需自定义队列实现)
        ResizableCapacityBlockingQueue queue = 
            (ResizableCapacityBlockingQueue) orderExecutor.getThreadPoolExecutor().getQueue();
        queue.setCapacity(newCapacity);
    }
}

第四章:数据库生死时速 —— 连接池与索引的终极对决

4.1 连接池优化公式

yamlCopy Code
# HikariCP 极限配置(验证于 1000TPS 场景)
maximumPoolSize = (核心数 × 2) + 有效磁盘数  
minimumIdle = maximumPoolSize × 0.5  
connectionTimeout = 平均查询耗时 × 3  
maxLifetime = 1800000(避免 TCP 端口耗尽)

4.2 索引手术案例

慢SQL(优化前) :

sqlCopy Code
SELECT * FROM orders 
WHERE user_id = ? 
AND create_time BETWEEN ? AND ? 
ORDER BY total_amount DESC 
LIMIT 100;

执行计划:

  • 全表扫描 2,300 万行
  • Using filesort

优化方案:

sqlCopy Code
ALTER TABLE orders 
ADD INDEX idx_user_time_amount 
(user_id, create_time, total_amount DESC) 
COMMENT '覆盖排序字段';

成效:

  • 扫描行数 2,300 万 → 87
  • 执行时间 4.2s → 23ms

第五章:缓存核弹防御系统 —— 从击穿到雪崩的全面布防

5.1 多级缓存架构

javaCopy Code
// L1:本地缓存(Caffeine)
LoadingCache<String, Object> localCache = Caffeine.newBuilder()
    .maximumSize(10_000)
    .expireAfterWrite(30, TimeUnit.SECONDS)
    .recordStats()  // 命中率监控
    .build(key -> {
        // L2:Redis 获取
        return redisTemplate.opsForValue().get(key);
    });

// L3:DB 兜底(带熔断)
@HystrixCommand(fallbackMethod = "getFromBackup")
public Object getUltimate(String key) {
    return dbLoader.load(key);
}

5.2 热点 Key 自动探测

javaCopy Code
// Redis 监控数据采集
public class HotKeyDetector implements Runnable {
    private static final Map<String, AtomicLong> counter = new ConcurrentHashMap<>();

    @Override
    public void run() {
        redisTemplate.execute((RedisCallback<Void>) connection -> {
            // 使用 Redis MONITOR 命令
            connection.monitor(new RedisMonitorCallback() {
                @Override
                public void onCommand(String command) {
                    String key = extractKey(command);
                    counter.computeIfAbsent(key, k -> new AtomicLong()).incrementAndGet();
                }
            });
            return null;
        });
    }

    // 每 5 秒输出 Top10 热点 Key
    public static void printHotKeys() {
        counter.entrySet().stream()
            .sorted((e1, e2) -> Long.compare(e2.getValue().get(), e1.getValue().get()))
            .limit(10)
            .forEach(e -> System.out.println(e.getKey() + ": " + e.getValue()));
    }
}

第六章:百万 QPS 的终极考验 —— 全链路压测实弹演练

6.1 混沌工程注入

bashCopy Code
# 模拟真实故障场景
# 1. 网络抖动
tc qdisc add dev eth0 root netem delay 200ms 50ms 30%

# 2. 节点宕机
docker kill -s SIGKILL 3 node-05

# 3. 数据库主从延迟
mysql> STOP SLAVE; SET GLOBAL slave_net_timeout=60;

6.2 监控指标看板(Prometheus + Grafana)

关键报警阈值:

  • 线程池活跃度 > 90% 持续 1 分钟
  • 99 分位延迟 > 200ms
  • 分代内存使用率突变 > 20%/min

结语:性能优化的三重境界

  1. 参数调优:掌握 JVM/中间件的基础配置
  2. 模式识别:从日志/metrics 中读取系统语言
  3. 架构防控:设计自适应的弹性系统

当系统在凌晨 4 点的大促中平稳运行的那一刻,我忽然明白:真正的性能优化,不是追求参数极值,而是让系统在混沌中保持优雅。

Excel COUNTIF函数精确统计全解析:从模糊匹配到精准计数 在数据处理与办公自动化领域,条件计数是数据分析的基础操作,其核心原理在于对特定范围内满足设定条件的单元格进行识别与汇总。Excel中的COUNTIF函数是实现这一功能的常用工具,它通过文本匹配逻辑与通配符机制来执行条件判断。然而,其默认的模糊匹配行为常导致统计结果偏离预期,这正是精确统计的技术价值所在——确保数据汇总的准确性与可靠性,直接影响业务报告、薪酬核算、销售分析等应用场景的决策质量。本文聚焦COUNTIF函数的精确匹配技巧,深入剖析通配符(如星号*和问号?)的转义使用(通过波浪号~),并针对大小写敏 阅读详情

相关推荐

【ESP32-IDF笔记】20-配置以太网网络(W5500)

基于ESP32IDF和官方的ethernet驱动,配置W5500以太网驱动芯片,实现ESP32的有线网络

别看了,就这些信息 3471

Guava Cache LoadingCache 之 refreshAfterWrites和expireAfterWrite区别 使用说明

三种基于时间清理或刷新缓存数据的方式: expireAfterAccess: 当缓存项在指定的时间段内没有被读或写就会被回收。 expireAfterWrite:当缓存项在指定的时间段内没有更新就会被回收(移除key),需要等待获取新值才会返回。 refreshAfterWrite:当缓存项上一次更新操作之后的多久会被刷新。第一个请求进来,执行load把数据加载到内存中(同步过程),指定的过期时间内比如10秒,都是从cache里读取数据。过了10秒后,没有请求进来,不会移除key。再有请求过来,才则执行

fengbin2005的专栏 7112

深入解析HAL_UART_Receive_IT:如何高效配置串口中断接收

本文深入解析了STM32 HAL库中`HAL_UART_Receive_IT`函数的工作原理与高效配置方法。该函数并非直接接收数据,而是作为中断接收的启动器和配置器,通过开启相关中断,由`UART_Receive_IT`在后台完成数据搬运。文章详细对比了中断与轮询模式的区别,并提供了不定长数据接收的完整实战流程、常见问题避坑指南及高级应用技巧,帮助开发者构建稳定高效的串口通信。

weixin_29162439的博客 638

深入Guava Cache的refresh和expire刷新机制

Guava Cache是本地缓存的不二之选,用起来真不错呵,可是你真的知道怎么使用才能满足需求?今天我们深入探讨一下Expire和Refresh。(废话少说) 一、思考和猜想 首先看一下三种基于时间的清理或刷新缓存数据的方式: expireAfterAccess:当缓存项在指定的时间段内没有被读或写就会被回收。 expireAfterWrite:当缓存项在指定的时间段内没有更新就会...

7万+

迪文串口屏开发环境搭建全流程:从DGUS Tool到串口联调

串口屏作为嵌入式人机交互的核心组件,通过串口通信实现主控MCU与显示终端的指令交互。其工作原理基于变量地址映射,主控读写VP地址即可驱动屏上控件,兼具低功耗与高稳定性。在工业控制、医疗设备及智能家居面板等场景中,串口屏能显著降低开发门槛与硬件成本。迪文屏凭借DGUS Tool上位机与自定义串口协议,成为主流选择。掌握DGUS Tool版本匹配、串口驱动安装及VP地址规划,是快速搭建开发环境的关键。

weixin_33937499的博客 607

基于51单片机语音识别智能台灯设计

智能台灯;语音识别;STC89C52RC单片机

Benso_H的博客 5842

Mongo expireAfterSeconds 时间设置

开始接触并要实现mongo的expireAfterSeconds功能;一直用的mongovue客户端界面简洁清晰都挺好,这次碰到了砍。 expireAfterSeconds有两种实现方法,例如我们有叫test的collection,test里有expire字段。 1. expireAfterSeconds值设置成0,expire设置未来时间值,例如当前时间+1day,等明天的这个时间就

hiangcun的专栏 1万+

Python办公自动化:用python-docx打造专业级Word表格边框(附完整代码)

本文深入探讨了如何利用python-docx库精细控制Word表格边框,实现办公自动化。通过解析底层XML结构,提供了通用的`set_cell_border`函数,并附上完整代码,帮助用户轻松打造符合商业规范的专业级表格,提升报告、合同等文档的生成效率与视觉效果。

weixin_29089057的博客 546

爆肝 30 天!从 JVM 调优到百万级 QPS,我的 Java 性能飞升全记录(1)

在 Java 开发的世界里,性能优化是永恒的话题。当系统面临高并发、大数据量时,如何让 Java 应用程序保持高效运行,成为了每个开发者必须攻克的难题。接下来,我将分享自己通过 30 天时间,从 JVM 调优到实现百万级 QPS 的 Java 性能优化全历程,希望能给大家带来启发。

java_beautiful的博客 975

Java开发者必备:Ollama4j客户端库全面指南与实战

在AI应用开发领域,本地部署大型语言模型(LLM)已成为降低成本和提升隐私安全的重要趋势。其核心原理是通过REST API与模型服务器交互,实现文本生成、对话和语义理解等功能。这一技术为Java生态系统带来了显著的工程价值,使开发者能够便捷地将AI能力集成到企业级应用中。Ollama4j作为一款专为Java设计的轻量级客户端库,通过封装底层HTTP通信和JSON处理,提供了类型安全、面向对象的API,极大地简化了与Ollama服务器的交互。它全面支持流式生成、多轮对话、嵌入向量计算以及高级的**工具调用**

weixin_28295799的博客 436

【AI黑话日日新】什么是AI云原生?

云原生赋能AI:利用容器、微服务、Serverless、DevOps等云原生技术,解决AI应用(尤其是大模型)在部署、扩展、运维、成本控制方面的痛点,让AI服务具备高可用、高性能、易运维、易扩展的特性AI赋能云原生:将AI技术(如智能调度、异常检测、自动优化)融入云基础设施管理,使云平台具备自我感知、自我优化、自我修复的能力,从"被动响应"升级为"主动适配"其本质是实现从""(AI运行在云上)到""(为AI量身打造的云)的根本性转变。

专注:太空算力、AI infra、异构调度、大模型成本工程 627

爆肝 30 天!从 JVM 调优到百万级 QPS,我的 Java 性能飞升全记录(3)

JVM参数:-XX:+AlwaysPreTouch 启动时预热内存页(避免运行时缺页中断)线程池:核心线程数 ≠ 最大线程数,动态扩容间隔应 ≥ 30秒SQL优化:联合索引字段顺序遵守AER原则(等值查询在前,范围在后,排序最后)缓存策略:热点Key检测算法需满足T时间内访问次数 > 3σ(标准差)混沌工程:每月至少执行一次随机杀节点演练附录:工具链全家福诊断工具Arthas:线上线程/内存实时分析async-profiler:无侵入式性能剖析压测工具Venom:全链路染色压测系统。

java_beautiful的博客 888

FISCO BCOS 三、多群组部署以及新节点加入群组

本章主要以星形组网和并行多组组网拓扑为例,指导您了解如下内容:了解如何使用创建多群组区块链安装包;了解创建的多群组区块链安装包目录组织形式;学习如何启动该区块链节点,并通过日志查看各群组共识状态;学习如何向各群组发送交易,并通过日志查看群组出块状态;了解群组内节点管理,包括节点入网、退网等;了解如何新建群组。

qq_63235624的博客 2920

内存数据库SQLite

本文以“黑板”比喻内存数据库,对比传统硬盘数据库,详解 SQLite 使用 :memory: 实现高速临时存储的原理与优势。通过动态占位符生成、executemany 批量操作等技巧,实现毫秒级数据读写,适用于单元测试、临时计算与隐私保护场景。强调其瞬时性与内存限制,提醒开发者注意数据量控制与安全防护,突出参数化查询防注入的核心价值。

看了都说刑的博客 326

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

深入理解 JVM 垃圾回收:GC 是什么、如何判定垃圾、四大回收算法全解析

本文深入解析JVM垃圾回收机制,涵盖GC核心概念、垃圾判定(基于可达性分析)、四大回收算法(标记清除、复制、标记整理、分代回收)及其应用场景。重点说明GC主要作用于堆内存,通过根对象遍历识别不可达对象,避免循环引用问题;并结合新生代与老年代特性,阐述分代回收如何提升效率,实现高效内存管理。

qq_61228769的博客 660

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

11-01-演进-.NET GC发展史

.NET GC发展史映射硬件演进:从单核STW到多核并发,再到区域化细粒度回收。历经分代管理、ServerGC、BackgroundGC、LOH自动压缩、POH隔离、DATC自适应线程数及Region-based管理等关键革新,代码量从5000行增至4万+,复杂度指数上升。每一步优化均在暂停时间、吞吐量与资源开销间权衡,体现“实用主义”哲学。核心启示:GC演进由硬件驱动,方向明确——更短暂停、更高效率,但代价是工程复杂性持续攀升。

设计 AI 玩游戏🎮 373

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

JVM中的GC垃圾回收器

同时,引入ZGC:可伸缩的低延迟垃圾回收器(Experimental)。删除CMS垃圾回收器,并弃用Parallel Scavenge和Serial Old的组合。1999年随JDK1.3.1一起来的是串行方式的Serial GC,它是第一款GC。有了虚拟机,就一定需要收集垃圾的机制,这就是Garbage Collection,对应的产品称为Garbage Collector。2018年3月,JDK 10中G1垃圾回收器的并行完整垃圾回收,实现并行性来改善最坏情况下的延迟。2020年9月,JDK15发布。

记录一点 400

智学文枢:题目管理页

题目管理页是「智学文枢」的数据基座入口,用一个 10 列的 QTableWidget 承载学生级习题的筛选、搜索、CRUD 与自动流水线触发,其核心难点不是"画表格",而是把"前端过滤 + Store 信号刷新 + 组合题父子展示 + 懒加载规避"组织成一条不卡 UI 的渲染管线。

caixuwen的专栏 290

在.NET WinForms中创建SQLite数据库

本文介绍在WinForms项目中使用SQLite的完整流程:通过NuGet安装System.Data.SQLite.Core包,将数据库文件置于程序目录下,利用CREATE TABLE IF NOT EXISTS实现自动建库建表;通过封装GetConnection()方法管理连接,初始化时调用Init()创建表结构;后续通过参数化SQL实现增删改查操作,支持数据绑定、登录验证等场景,确保安全高效。

2301_80809484的博客 295

DeepSeek总结的 SQLite 某些 double 值的最后一位与 Python 不同

2 不能整除 10,所以转换是混乱的。然而,在这种情况下,由于它是完美的 2 的幂,那个舍入残留实际上是正确的。但你必须理解,超过第 15 位小数,对于这些特定数字来说,更多的是副作用,而不是预期行为。归根结底,你在这里看到的差异最直接地可以称为 SQLite 的“错”,因为它不同,但它以一种聪明的方式不同——至少是一种主要面向人类而非计算机的聪明方式。而且,如果作为开发者的你试图使用已转换为十进制字符串的数字进行数学运算,那是更大的错。据你所知,它们存储的是完全相同的值,只是打印例程输出它们的方式不同。

l1t的专栏 439

Mandate持久化实测:nonce落盘之后,进程重启再也撕不开重放窗口

Mandate授权系列第⑦篇,直接修上一篇发现的最大残留风险。上一篇实测:nonce缓存只在内存,进程重启后窗口期内逐字节重放成功。本篇把nonce、Mandate、revoke三类安全状态落盘SQLite,重跑攻击:重启后重放被拒(R1)、Mandate重载验签有效且越界仍拦(R2)、revoke重启后仍生效(R3),内存版对照重启后重放照样成功(R4)。安全状态的生命周期必须覆盖进程的生命周期。

weixin_39885962的博客 491

ERP单据已作废为什么商品仍不能删除,引用检查与软删除怎么查

ERP销售单作废后,商品引用仍可能保留。本文用真实Store和内存SQLite对照无引用、草稿引用及作废引用,核对删除确认、deleted标记和列表过滤范围。

qq_52097248的博客 332
上一篇: 爆肝 30 天!从 JVM 调优到百万级 QPS,我的 Java 性能飞升全记录(1)
下一篇: 爆肝 30 天!从 JVM 调优到百万级 QPS,我的 Java 性能飞升全记录(3)
程序员职业指南
博客等级 码龄4年 2136粉丝 960原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值