生产服务GC调优实践基本流程总结

Linux服务器JDK8部署全攻略:从OpenJDK选择到生产环境调优 Java开发工具包(JDK)是Java应用运行和编译的核心环境,其版本选择与部署方式直接影响应用的稳定性和性能。JDK8作为长期支持版本,因其卓越的稳定性和广泛的生态兼容性,在企业级应用、大数据框架和遗留系统中仍占据主导地位。从技术原理看,JDK包含Java运行时环境(JRE)和编译器(javac)等工具,而OpenJDK作为开源实现,提供了免费且功能完整的替代方案,有效规避了Oracle JDK的商业许可风险。在Linux服务器上部署时,需重点关注环境变量配置、多版本管理和权限控制,以确保各组件协同工作。 阅读详情

前言

对Java虚拟机进行性能调优是一个非常宽泛的话题,在实践上也是非常棘手的过程。因为它需要一种系统的优化方法和清晰的优化期望。默认的JVM参数尝试在大多数情况下提供可接受的性能;但是,根据应用程序的行为和它所处的工作负载,默认值可能不会产生理想的结果。如果Java虚拟机没有按照预期运行就可能需要对应用程序进行基准测试并进行调优,以找到一组合适的 JVM参数。

大多数情况下谈论的“JVM调优”都是在说“Java GC调优”,Java官方手册上关于HotSpot虚拟机下的第一个主题就是HotSpot Virtual Machine Garbage Collection Tuning Guide。

本文记录的是从真实业务开发GC调优中总结的一个“基本步骤和流程“,结合着一些参考资料给出一个案例,以及个人对这块知识点的理解进行讲解。

1. 开始优化前的准备

  • 深入理解需要优化系统的业务逻辑
  • 深入理解Java虚拟机相关的概念(书籍、官方文档)
  • 思考一下JVM调优的目的,真的需要调优吗?90%以上的问题都是业务代码导致的,把调优的精力放到业务逻辑的优化上是不是可以达到更好的效果?

有一些因素会影响你得到的最终调优参数:

  • JDK的版本
  • 服务器硬件
  • 操作系统
  • 系统的负载曲线
  • 系统的业务类型,优化需要围绕的业务类型进行
  • 系统的数据集

以上所有内容构成了调优GC性能的环境。调优参数越具体,解决方案就越不通用,它适用的环境也就越少。这意味着,如果任何变量发生变化(例如,更多用户被授予请求应用程序、应用程序升级、硬件升级的权限),那么所做的任何性能调优都可能需要重新评估。

另外必须理解通过显式调优,实际上可能会降低性能。重要的是要持续监控应用程序,并检查基于调优的假设是否仍然有效。如果经过仔细的调试后仍达不到目标,或许应该考虑GC调优之外的更改,例如更换更适合的硬件、操作系统调优和应用程序调优。

生产服务GC调优实践基本流程总结

Default Arrangement of Generations 。 图不重要,看文本~

2.选择优化目标

JVM优化首先需要选择目标。在下一步为GC调优准备系统时围绕着这些目标设置值。可参考的目标选择方向:

  • 延迟——JVM在执行垃圾收集时引起的Stop The World(STW)。有两个主要的指标,平均GC延迟和最大GC延迟。这个目标的动机通常与客户感知到的性能或响应能力有关。
  • 吞吐量——JVM可用于执行应用程序的时间百分比。可用来执行应用程序的时间越多,可用来服务请求的处理时间就越多。需要注意的是,高吞吐量和低延迟并不一定相关——高吞吐量可能伴随着较长但不频繁的暂停时间。
  • 内存成本——内存占用是JVM为执行应用程序所消耗的内存量。如果应用程序环境内存有限,将此项设为目标也可以起到降低成本的作用。

以上内容可以在Java官方手册的HotSpot调优部分找到,而一些经验性的优化原则如下:

  • 优先考虑MinorGC。在大多数应用程序中,大多数垃圾都是由最近短暂的对象分配创建的,所以优先考虑年轻代的GC。年轻代对象生命周期越短,不会因为动态年龄判断和空间分配担保等因素导致存活时间不长的对象被分配到老年代;同时老年代对象生命周期长,JVM的整体垃圾收集就越高效,这将导致更高的吞吐量。
  • 设定合适的堆区大小。给JVM的内存越多,收集频率就越低。此外,这还意味着可以适当地调整年轻代的大小,以更好地应对短期对象的创建速度,这就减少了向老年代分配的对象数量。
  • 设定简单的目标。为了使事情变得更容易,把JVM调优的目标设定的简单一点,例如只选择其中两个性能目标进行调整,而牺牲另一个甚至只选择一个。通常情况下,这些目标是相互竞争的,例如,为了提高吞吐量,你给堆的内存越多,平均暂停时间就可能越长;反之,如果你给堆的内存越少,从而减少了平均暂停时间,暂停频率就可能增加,降低吞吐量。同样,对于堆的大小,如果所有分代区域的大小合适则可以提供更好的延迟和吞吐量,这通常是以牺牲JVM的占用率为代价的。
    简而言之,调整GC是一种平衡的行为。通常无法仅仅通过GC的调整来实现所有的目标。

生产服务GC调优实践基本流程总结

Typical Distribution for Lifetimes of Objects 。 图不重要,看文本~

3.业务逻辑分析

这里并不会把真实的业务系统拿出来进行分析,而是模拟类似的场景,大致的业务信息如下:

  1. 一个微服务系统(本例中是一个SpringBoot Demo,以下简称D服务)主要提供书籍实体信息的缓存和搜索业务
  2. 底层数据库为MySQL+Redis+Elasticsearch
  3. 业务场景为向其他微服务模块或者其他部分提供高速缓存及书籍信息检索
  4. 实际实现需求时采用MySQL+Redis+应用内存式多级缓存

从D服务的性质来说并不属于用户强交互类型的后端服务,主要面向的部门内的其他微服务和其他部门的后端服务,所以对于请求的响应速度(延迟)并不属于第一目标,所以可以把主要的调优目标设定为增加吞吐量或者降低内存占用。当然由于服务本身并不算臃肿,生产资源也不是很吃紧,所以也不考虑降低内存,则最后的目标为增加吞吐量。

从业务逻辑的角度分析主要是对书籍信息的增删改查,请求流量中90%以上是查,增删改则大多是服务内部对于多方数据的维护。

查询的类型分为多种,从对象的角度来说大多数是短期对象,例如:

  • 通过AdvanceSearch(AS)模块生成的复杂ES查询语句对象(数据量小,频率中等,存活时间极短)
  • 从多方数据源整合业务逻辑的数据响应对象(数据量中,频率极高,存活时间极短)
  • 多级缓存体系中在内存中暂存的数据对象(数据量小,频率高,存活时间中等,因为是LRU缓存)
  • 定期维护任务处理分发的数据对象(数据量大、频率低、存活时间极短)

可能会进入老年代的业务对象只有内存缓存中的对象,这一块结合业务量+过期时间常时保持在数百MB以内,这里的大小是多次压测中Dump堆内存+MAT分析得出的结果。

统合以上所有信息可以看出这是一个大部分对象存活时间都不会太长的应用,所以初步的想法是增大年轻代的大小,让大部分对象都在年轻代被回收,减少进入老年代的几率。

下面贴出Demo的代码,为了模拟一个类似的情况可能Demo中的代码采用了一些取巧或者极端的设定,或许这也不能很好的表达原本的逻辑,但一个40行不到就可以运行的Demo总比一个复杂的项目或者开源软件容易理解

复制代码12345678910111213141516171819202122232425262728293031323334353637383940414243444546JAVA/**
 * @author fengxiao
 * @date 2021-11-09
 */
@RestController
@SpringBootApplication
public class Application {
    private final Logger logger = LoggerFactory.getLogger(Application.class);

    //1. 模拟内存缓存, 短期对象
    private Cache<Integer, Book> shortCache;

    //2. 模拟业务流程里 中等存活时长 对象,,从而使短期对象更有可能进入老年代
    private Cache<Integer, Book> mediumCache;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @PostConstruct
    public void init() {
        //3. 这里本地缓存的数值设定在实际业务中并不具有参考性,只是设法让一部分对象在初始的设定下进入老年代
        shortCache = Caffeine.newBuilder().maximumSize(800).initialCapacity(800)
                .expireAfterWrite(3, TimeUnit.SECONDS)
                .removalListener((k, v, c) -> logger.info("Cache Removed,K:{}, V:{}, Cause:{}", k, v, c))
                .build();
        mediumCache = Caffeine.newBuilder().maximumSize(1000).softValues()
                .expireAfterWrite(30, TimeUnit.SECONDS)
                .build();
    }

    @GetMapping("/book")
    public Book book() {
        //4. 模拟业务处理流程中其他模块短期对象生成的消耗,可以调整这个参数来对老年代无干扰的增加YoungGC的频率
//        byte[] bytes = new byte[16 * 1024];
        return shortCache.get(new Random().nextInt(5000), (id) -> {
                    //5. 模拟正常的LRU缓存场景消耗
                    Book book = new Book().setId(id).setArchives(new byte[256 * 1024]);
                    //6. 模拟业务系统中对老年代的正常消耗
                    mediumCache.put(id, new Book().setArchives(new byte[128 * 1024]));
                    return book;
                }
        );
    }
}

4.准备调优环境

一旦确定了方向,就需要为GC调优准备环境。这一步的结果将是你所选择目标的价值。总之,目标和价值将成为要调优的环境的系统需求。

4.1 容器镜像选择

其实就是选择JDK的版本,不同版本的JDK可选择的收集器组合不尽相同,而根据业务类型选择收集器也是至关重要的。

因为在日常工作中使用的JDK版本还是1.8,结合上面谈到的吞吐量目标自然就选择了PS/PO(也是JDK1.8服务端默认收集器),关于收集器的特性和组合在这里不做展开,有需要自行查阅书籍和文档。

4.2 启动/预热工作负载

在测量特定应用程序JVM的GC性能之前,需要能够让应用程序执行工作并达到稳定状态。这是通过将load应用到应用程序来实现的。

建议将负载建模为希望调优GC的稳定状态负载,即反映应用程序在生产环境中使用时的使用模式和使用量的负载。这里可以拉上测试部门的同事一起完成,通过压测、流量回放等手段让目标程序接近于真实生产中的状态,同时需要注意的是类似的硬件、操作系统版本、加载配置文件等等。负载环境、配额可以通过容器化很方便的实现。

Demo这里以MeterSphere来模拟压力。简单的一点也可以用Jmeter快速启动或者直接录制真实的流量进行回放。

4.3 开启GC日志/监控

这一点相信大部分生产上的系统都是默认开启的,如果是JDK9以下则:

复制代码1SHELLJAVA_OPT="${JAVA_OPT} -Xloggc:${BASE_DIR}/logs/server_gc.log -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M"

JDK9则整合在了xlog参数中:

复制代码1SHELL-Xlog:gc*:file=${BASE_DIR}/logs/server_gc.log:time,tags:filecount=10,filesize=102400"

然后就需要理解GC日志的各种字段信息含义了,这里建议多观察自己系统中的GC日志,理解日志含义。

至于监控的话可以接入类似Prometheus+Grafana这样的监控系统,监控+报警,谁也不想天天盯着GC日志看。所以此处为了方便展示结果临时搭建了一个Prometheus+Grafana监控,Elasticsearch+Kibana用来分析GC日志。用最小的配置启动Grafana:

复制代码1234567891011121314151617YAMLversion: '3.1'

services:
  prometheus:
    image: prom/prometheus
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - 9090:9090
    container_name: prometheus
  grafana:
    image: grafana/grafana
    depends_on:
      - prometheus
    ports:
      - 3000:3000
    container_name: grafana

对Prometheus和Grafana做一些基本的配置后随意导入一个JVM相关的监控面板即可:

生产服务GC调优实践基本流程总结

4.4 确定内存足迹

内存足迹是指程序在运行时使用或引用的主内存的数量(Wiki传送门:Memory footprint,以下以内存占用这个通俗的理解作为简称)

为了优化JVM分代的大小,需要很好地了解稳定状态活动数据集的大小,可以通过以下两种方式获得相关信息:

  • 从GC日志观察
  • 从可视化监控中观察(直观)

5. 确定系统需求

回到性能目标,我们讨论了VM GC调优的三个性能目标。现在需要确定这些目标的值,它们表示你正在调优GC性能的环境的系统需求。需要确定的一些系统要求是:

  • 可接受的平均Minor GC暂停时间
  • 可接受的平均GC暂停时间
  • 最大可容忍的Full GC暂停时间
  • 可用时间百分比表示的可接受的最小吞吐量

通常,如果关注的是Latency(延迟)或Footprint(内存占用)目标,那么可能倾向于较小的堆内存值,并使用较小的吞吐量值设置暂停时间的最大容限;相反,如果您关注的是吞吐量,那么您可能会希望在没有最大容差的情况下使用更大的暂停时间值和更大的吞吐量值。

这部分最好结合自己当前负责业务系统的现状进行评估和拟定,在一个基准值上进行调优。以D服务的原始吞吐量举例(实际的业务系统中各种复杂的情况都要细致考虑):

系统要求

值

可接受的Minor GC暂停时间:

0.2秒

可接受的Full GC暂停时间:

2秒

可接受的最低吞吐量:

95%

这一步可以多理解Java官方文档中的 Behavior-Based Tuning ,以及一些现成的JVM调优案例,重要的是理解思想然后结合自己的业务来确定需求。

6. 设定样本参数开始压测

以下为本例中D服务的基准运行参数

复制代码12345678910111213SHELLjava -Xms4g -Xmx4g
-XX:-OmitStackTraceInFastThrow
-XX:+HeapDumpOnOutOfMemoryError 
-XX:HeapDumpPath=logs/java_heapdump.hprof 
-Xloggc:logs/server_gc.log 
-verbose:gc 
-XX:+PrintGCDetails 
-XX:+PrintGCDateStamps 
-XX:+PrintGCTimeStamps 
-XX:+UseGCLogFileRotation 
-XX:NumberOfGCLogFiles=10 
-XX:GCLogFileSize=100M 
-jar spring-lite-1.0.0.jar

此时使用jmap命令分析堆区情况如下,程序是跑在虚拟机里的,因为调试参数的时候发现有些情况下会频繁GC所以只分配了4个逻辑处理器:

复制代码123456789101112131415161718192021222324252627282930313233343536373839404142434445SHELLDebugger attached successfully.
Server compiler detected.
JVM version is 25.40-b25

using thread-local object allocation.
Parallel GC with 4 thread(s)

Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 4294967296 (4096.0MB)
   NewSize                  = 1431306240 (1365.0MB)
   MaxNewSize               = 1431306240 (1365.0MB)
   OldSize                  = 2863661056 (2731.0MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 1073741824 (1024.0MB)
   used     = 257701336 (245.76314544677734MB)
   free     = 816040488 (778.2368545532227MB)
   24.00030717253685% used
From Space:
   capacity = 178782208 (170.5MB)
   used     = 0 (0.0MB)
   free     = 178782208 (170.5MB)
   0.0% used
To Space:
   capacity = 178782208 (170.5MB)
   used     = 0 (0.0MB)
   free     = 178782208 (170.5MB)
   0.0% used
PS Old Generation
   capacity = 2863661056 (2731.0MB)
   used     = 12164632 (11.601097106933594MB)
   free     = 2851496424 (2719.3989028930664MB)
   0.42479301014037324% used

14856 interned Strings occupying 1288376 bytes.

Jmeter请求设置如下,因为Demo的流程里没有任何业务逻辑所以即使单线程都有较高的吞吐量,但要注意测试环境配置的区别,例如我在IDE中直接使用Jmeter单线程吞吐量就可以达到1800/s,而到了一个配置较低的虚拟机中需要多个线程才能达到相似的吞吐量级,所以可以加几个线程同时用吞吐量定时器控制请求速率:

生产服务GC调优实践基本流程总结

每次调整参数反复的进行请求,每次半个小时。这是对于Demo的,如果时真实的业务系统务必多花时间采样

生产服务GC调优实践基本流程总结

7.分析GC日志

对于本例中的Demo取了四种参数下的GC日志结果,Grafana概览如下:

生产服务GC调优实践基本流程总结

最终产生了四个GC日志样本,文件名里的内存大小是指年轻代的大小,对于生产服务可以从多个角度采集更多参数样本:

生产服务GC调优实践基本流程总结

7.1 导入Elasticsearch

接下来我们将GC日志导入到Elasticsearch中,并来到Kibana查看(注意这里的Elasticsearch和Kibana必需是7.14版本以上的,否则后续的操作会因为版本原因无法完成):

生产服务GC调优实践基本流程总结

此时索引中的GC还是原始格式,就像是在Linux中直接打开一样,所以我们需要通过Grok Pattern将日志拆分成各个关键字段。实际开发场景可以用Logstash解析并传输,这里只是做个演示,所以通过IngestPipeline + Reindex 快速处理索引数据。

成功后索引如下所示,我们拥有了可以制作可视化面板的结构化GC数据(Grok Pattern这里就不分享了,主要是我花了半个小时写出来的表达式似乎还不能完美匹配一些特殊的GC日志行= =。也是建议大家自己编写匹配表达式,这样可以细致的消化GC日志的结构)

生产服务GC调优实践基本流程总结

7.2 制作可视化面板

现在通过聚合找到每个日志索引对应的开始时间以及结束时间

复制代码123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354JSONGET throughput-gc-log-converted*/_search
{
  "size": 0,
  "aggs": {
    "index": {
      "terms": { "field": "_index", "size": 10 },
      "aggs": {
        "start_time": {
          "min": { "field": "timestamp" }
        },
        "stop_time": {
          "max": { "field": "timestamp" }
        }
      }
    }
  }
}
// 响应如下:
"aggregations" : {
    "index" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "throughput-gc-log-converted-eden1.3g",
          "doc_count" : 1165,
          "start_time" : { "value" : 1.637476135722E12, "value_as_string" : "2021-11-21T06:28:55.722Z"
          },
          "stop_time" : { "value" : 1.637478206592E12, "value_as_string" : "2021-11-21T07:03:26.592Z" }
        },
        {
          "key" : "throughput-gc-log-converted-eden1.6g",
          "doc_count" : 898,
          "start_time" : { "value" : 1.637480290228E12, "value_as_string" : "2021-11-21T07:38:10.228Z"
          },
          "stop_time" : { "value" : 1.637482100695E12, "value_as_string" : "2021-11-21T08:08:20.695Z" }
        },
        {
          "key" : "throughput-gc-log-converted-eden2.0g",
          "doc_count" : 669,
          "start_time" : { "value" : 1.63747831467E12, "value_as_string" : "2021-11-21T07:05:14.670Z"
          },
          "stop_time" : { "value" : 1.637480148437E12, "value_as_string" : "2021-11-21T07:35:48.437Z" }
        },
        {
          "key" : "throughput-gc-log-converted-eden2.5g",
          "doc_count" : 505,
          "start_time" : { "value" : 1.637482323999E12, "value_as_string" : "2021-11-21T08:12:03.999Z"
          },
          "stop_time" : { "value" : 1.637484145358E12, "value_as_string" : "2021-11-21T08:42:25.358Z" }
        }
      ]
    }
  }

确定了时间范围之后进入Dashboard页面,创建可视化面板如下。之所以需要精确的时间范围,就是需要精确的偏移时间以对比不同情况下GC的表现,现在我们可以观察不同设置下的GC次数和GC耗时,另外和同事分享或者向领导汇报调优结果时有现成的图标总比一堆数据好用吧~

生产服务GC调优实践基本流程总结

7.3 获得性能指标

使用聚合语句来计算GC各项指标:

复制代码12345678910111213141516171819202122232425262728293031JSGET throughput-gc-log-converted*/_search
{
  "size": 0,
  "aggs": {
    "index": {
      "terms": {
        "field": "_index",
        "size": 10
      },
      "aggs": {
        "gc_type_count": {
          "terms": { "field": "gc_type.keyword" },
          "aggs": {
            "cost": {
              "sum": { "field": "clock_time" }
            }
          }
        },
        "total_cost": {
          "sum": { "field": "clock_time" }
        },
        "throughput_calc": {
          "bucket_script": {
            "buckets_path": { "total_cost": "total_cost" },
            "script": "1 -(params.total_cost/1800)"
          }
        }
      }
    }
  }
}

结果如图所示:

生产服务GC调优实践基本流程总结

8.确定结果参数

分析之后的结果其实并不重要,因为最终的决定要看调优者对业务系统以及垃圾收集的理解。在上一小节我们得到了在不同参数下D服务的吞吐量表现,最终是否要选那个看起来数值最好的参数还要结合其他情况。

本例中,最好的吞吐量结果 98.2%是在年轻代2.5G的设置下得到的,那为什么不尝试着再加大年轻代的大小呢?因为没有意义,真实的业务系统不太可能出现年轻代和老年代比例超过3:1的。即使真的有,这样的虚拟机参数似乎也有点偏激了,业务需求永远不会变动吗?

最后如何改变参数还是得结合着一些成熟稳定的调优准则和经验,例如你可以在各种GC优化的博客里看到诸如:

  • 最大堆大小应该在老年代平均值的3 - 4倍之间。
  • 观察内存足迹,老年代不应少于老年代平均值的1.5倍。
  • 年轻代应该大于整个堆的10%。
  • 在调整JVM的大小时,不要超过可用的物理内存量。
  • 。。。。。

话题回到本例中的Demo,如果看到一个生产服务这样的综合结果,我不会显式的设置-Xmn到任何值,而是会设置例如-XX:NewRatio=1这样的相对比值(本文参考最近一次真实的生产服务调优,真实的调优结果就是NewRatio和一些其他值)。

如果正在看文章的你仔细的观察了Demo 的代码并分析其对象消耗就会发现,笔者花费不少时间调制了一些参数让这个Demo在较低年轻代分配下会产生年轻代对象刚进入老年代就进入濒死状态了,从而导致高频的GC;而当年轻代达到2.3G+的阈值时,缓存对象和超时时间达到了一个微妙的平衡,缓存对象根本不可能进入老年代,不会产生Full GC。如以下聚合结果所示(这个SpringBoot程序启动基础产生了2次Full GC):

复制代码123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566JSON{
    "key": "throughput-gc-log-converted-eden1.3g",
    "doc_count": 1165,
    "total_cost": { "value": 75.87 },
    "gc_type_count": {
        "doc_count_error_upper_bound": 0,
        "sum_other_doc_count": 0,
        "buckets": [
            {
                "key": "GC",
                "doc_count": 1113,
                "cost": { "value": 69.86 }
            },
            {
                "key": "Full GC",
                "doc_count": 52,
                "cost": { "value": 6.01 }
            }
        ]
    },
    "throughput_calc": { "value": 0.95785 }
},
{
    "key": "throughput-gc-log-converted-eden2.0g",
    "doc_count": 669,
    "total_cost": { "value": 45.75 },
    "gc_type_count": {
        "doc_count_error_upper_bound": 0,
        "sum_other_doc_count": 0,
        "buckets": [
            {
                "key": "GC",
                "doc_count": 650,
                "cost": { "value": 43.65 }
            },
            {
                "key": "Full GC",
                "doc_count": 19,
                "cost": { "value": 2.1 }
            }
        ]
    },
    "throughput_calc": { "value": 0.9745833333333334 }
},
{
    "key": "throughput-gc-log-converted-eden2.5g",
    "doc_count": 505,
    "total_cost": { "value": 30.66 },
    "gc_type_count": {
        "doc_count_error_upper_bound": 0,
        "sum_other_doc_count": 0,
        "buckets": [
            {
                "key": "GC",
                "doc_count": 503,
                "cost": { "value": 30.57 }
            },
            {
                "key": "Full GC",
                "doc_count": 2,
                "cost": { "value": 0.09 }
            }
        ]
    },
    "throughput_calc": { "value": 0.9829666666666667 }
}

而在实际快速迭代的生产服务中很少出现这样的巧合,即使真的出现了也不要自作聪明的取巧设置。因为在错综复杂的业务系统之上,任何一个简单的业务需求改动都能轻松的破坏精心设置的参数。当然如果你开发的系统是定期发布的中间件产品或类似的软件那无所谓。

9. 测量参数变化后的状况

这一步的耗时通常比调优的过程更长。在实际的确定了调优方向和参数后,制定结果预期、和测试部门的同事进行对接,各种方面的测试全部走起来,从系统顶层收集指标变化,顺利的话花费数周的时间或许参数配置就可以被合并到配置仓库主干分支了。

如果结果没有达到预期,那重新来~

10. 总结

最近杂项事情很多,匆匆忙忙整理的一篇随笔,结构和措辞可能没有经过细致整理,还请谅解 =_=

PTC Windchill安装与迁移实战:从环境准备到性能调优的完整指南 企业级应用部署是系统工程,尤其对于像PLM(产品生命周期管理)这类复杂系统。其核心在于理解软件并非孤立运行,而是由应用服务器、数据库、文件库等多个组件构成的生态系统。部署原理涉及环境适配、服务配置与数据迁移,技术价值在于为企业构建统一、可靠的产品数据管理核心。在制造业、工程设计等应用场景中,稳定的系统是业务连续性的基石。本文聚焦PTC Windchill,深入剖析其安装与系统拷贝(迁移)的全过程。针对安装,详解从硬件规划、软件依赖(如特定版本的JDK和Oracle数据库)配置到核心服务设置的步骤。对于更复杂 阅读详情

相关推荐

深入理解Elasticsearch日志中的GC日志

GC(垃圾回收)是一种自动内存管理机制,用于管理Java虚拟机(JVM)中的对象分配和回收。在大数据应用程序中,如Elasticsearch,GC对于保持系统性能和稳定性至关重要。本文将深入探讨Elasticsearch日志中的GC日志,了解其含义和如何解读。同时,我们将提供相关的源代码示例以帮助读者更好地理解。在上面的示例中,我们可以看到四行GC日志记录。

2301_79366435的博客 686

GC如何调优?

写在前面 本文隶属于专栏《100个问题搞定Java虚拟机》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢! 本专栏目录结构和文献引用请见100个问题搞定Java虚拟机 解答 谈到调优,这一定是针对特定场景、特定目的的事情, 对于 GC 调优来说,首先就需要清楚调优的目标是什么? 从性能的角度看,通常关注三个方面,内存占用(footprint)、延时(latency)和吞吐量(throughput),大多数情况下调优会侧重于其中一个或者两个方面的目标,很少有情况可以兼顾三个不同

Shockang的博客 1万+

【Elasticsearch】你看懂 Elasticsearch Log 中的 GC 日志了吗?

1.概述 转载:https://elasticsearch.cn/article/812 如果你关注过 elasticsearch 的日志,可能会看到如下类似的内容: [2018-06-30T17:57:23,848][WARN ][o.e.m.j.JvmGcMonitorService] [qoo--eS] [gc][228384] overhead, spent [2.2s] collecting in the last [2.3s] [2018-06-30T17:57:29,020][INFO ].

九师兄 2454

JVM实战篇:GC调优

JVM实战篇:GC调优

qq_62767608的博客 2657

prometheus 从入门到精通(史上最全)

Prometheus(由go语言开发)是一套开源的监控&报警&时间序列(按照时间排序)数据库的组合。因为kubernetes(俗称k8s)的流行带动了prometheus的发展。它可以监控主机,服务,容器,支持多种exporter采集数据,还支持pushgateway进行数据上报,Prometheus性能足够支撑上万台规模的集群。原文链接:https://blog.youkuaiyun.com/qq_45277554/article/details/130917620时间序列数据。

流水_鱼鱼的博客 1万+

期末求生指南:手把手教你用浏览器开发者工具绕过百一测评切屏检测

本文详细介绍了如何利用浏览器开发者工具绕过百一测评的切屏检测功能。通过分析JavaScript事件监听机制,定位关键检测代码,并提供实时调试和本地覆盖两种修改方法,帮助学生在遵守规则的前提下更灵活地应对在线考试。文章还包含风险控制和替代方案等实用建议。

weixin_28698059的博客 547

深入JVM:全面解析GC调优

本文小豪将带大家学习GC调优,了解常见的GC监控和日志分析工具,通常GC性能的评判指标包含三个方面,分别是吞吐量、暂停时间和内存占用,但往往三者不可兼得,一般更为关注其中的吞吐量和暂停时间。而GC调优主要是针对垃圾回收的性能优化,减少产生Full GC的频率和次数,一般我们可以从调整JVM内存大小、择优垃圾回收器和优化垃圾回收器参数这三方面入手优化。

Code豪客 2061

南京工业大学高性能计算平台基础使用指南

高性能计算平台基础使用指南前言什么高性能计算南京工业大学高性能计算平台如何登录如何进行文件传输进行任务提交(本文以提交MATLAB任务为例)环境变量的配置(推荐)使用Environment Modules进行环境变量管理Modules 指令自定义MODULEFILE常见软件任务脚本 前言 第一次接触使用学校的高性能平台是在今年上半年进行毕业设计的时候,当时有大量的数据需要在Matab中进行模型运算,便向学校申请了账号,使用了HPC平台。计算速度确实比个人电脑快了太多太多。 近期,有很多初次想使用高性能计算

weixin_45710019的博客 6878

生产服务GC调优实践基本流程总结(1)

1、看视频进行系统学习这几年的Crud经历,让我明白自己真的算是菜鸡中的战斗机,也正因为Crud,导致自己技术比较零散,也不够深入不够系统,所以重新进行学习是很有必要的。我差的是系统知识,差的结构框架和思路,所以通过视频来学习,效果更好,也更全面。关于视频学习,个人可以推荐去B站进行学习,B站上有很多学习视频,唯一的缺点就是免费的容易过时。2、读源码,看实战笔记,学习大神思路“编程语言是程序员的表达的方式,而架构是程序员对世界的认知”。所以,程序员要想快速认知并学习架构,读源码是必不可少的。

2401_84048225的博客 523

手把手教你用TUSB2E22中继器实现eUSB2与USB 2.0互转(附实测数据对比)

本文详细介绍了如何利用TUSB2E22中继器实现eUSB2与USB 2.0的高效互转,包括技术背景、硬件设计要点、信号完整性测试方法及故障排查策略。通过实测数据对比,展示了TUSB2E22在信号延迟、功耗和眼图性能上的显著优势,为工程师提供了实用的工程方案。

weixin_29199873的博客 283

HDMI设计2----EDID and E-EDID

1,EDID是什么?有什么用? 图1 应用场景 如图1所示的应用场景,PC将视频信号发送 到我们的设备上,经过一系列的传输和切换,设备将视频信号发送到显示器或者投影机上,也就是说,我们的设备位于PC和显示器之间。首先,在输入端,设备需要让PC知道自己是能够接受输入视频信号的,让PC认为自己是一台显示器。如果不这样做的话,PC可能会拒绝输出任何视频信号的(VGA接口不需要EDID也能输出)。除此之外,设备还要告诉PC自己支持的显示时序。而在输出端,当设备需要自建输出时序而不是简单的复制...

Archar_Saber的博客 7988

11-Java语言核心-JVM原理-JVM调优详解

JVM调优是提升Java应用性能的关键环节,主要涉及内存参数配置、GC行为分析和性能优化。调优目标包括低延迟、高吞吐量和小内存占用等性能指标,以及避免OOM异常、控制GC停顿等稳定性要求。常用参数包括-Xms/-Xmx设置堆大小、-Xmn配置新生代、-XX:MetaspaceSize调整元空间等。调优原则强调基于数据、逐步调整和对比验证。合理配置JVM参数能显著提升应用性能,需要结合实际场景进行针对性优化。

智慧是做事用的 263

Apache Flink集成HDFS报错Failed to create checkpoint storage at checkpoint coordinator side.

在网上查询相关资料后,在flink的lib目录添加flink-shaded-hadoop-3-3.1.1.7.0.3.0-79-7.0.jar、commons-cli-1.5.0.jar两个包,但报错依旧存在,添加了export HADOOP_CLASSPATH=后面发现是hadoop与flink的兼容性问题,hadoop原先使用的是3.3.4,与多个版本的flink集成都会出现报错,最后将Hadoop的版本改成3.1.3,使用flink run运行jar包就没有这个错误了,在hdfs上成功保存了检查点。

zywenmag的博客 623

TongWeb7企业版从安装到上线的完整实践:内存调优+端口安全配置全流程

本文提供TongWeb7企业版在生产环境中的完整部署与优化指南。内容涵盖从JDK环境准备、静默安装,到深入的内存参数调优(如堆内存、元空间设置),以及关键的安全加固配置(如修改默认端口、强化管理控制台)。旨在帮助运维工程师构建稳定、高效且安全的中间件运行环境。

f9g0h的博客 671

代码的自由之旅:用AI写出无版权烦恼的Verilog

他们还基于这个数据集,训练了一个名叫“FreeV”的AI模型,不仅能写出好用的Verilog代码,还把版权侵权的风险降到了仅3%。为了让AI安全地写Verilog,研究团队提出了三个“法宝”:一个检测AI是否会生成侵权代码的测试方法、一个干净的Verilog数据集FreeSet,还有一个基于FreeSet训练的AI模型FreeV。AI的记忆力超强,能记住训练时见过的代码。测试发现,一些用Verilog数据训练过的AI,比如VeriGen,生成侵权代码的概率从9%涨到了15%,说明它们可能学了不该学的代码。

步子哥的博客 1809

Qt for WebAssembly环境搭建

一、前言 二、Ubuntu 1、在线安装Qt15 在线安装下载器:https://download.qt.io/official_releases/online_installers/ 安装时记得勾选WebAssembly,如下: 2、安装依赖 # Install Python sudo apt-get install python2.7 # Install CMake (optional, only needed for tests and building Binaryen) sudo apt

贝勒里恩的博客 3668

CentOS 7下Tomcat 8.5生产环境部署与调优指南

Tomcat作为轻量级Java应用服务器,在企业级Web应用部署中扮演着关键角色。其基于Java Servlet和JSP规范实现,通过线程池管理和连接器优化实现高并发处理。在生产环境中,结合APR原生库可以显著提升静态资源处理性能,而JVM调优则直接影响应用稳定性。本文以CentOS 7系统为例,详细讲解从基础安装、性能调优到安全加固的全流程,涵盖线程池配置、G1垃圾回收器使用等关键技术点,适用于电商平台、金融系统等高并发场景的Tomcat生产级部署。

weixin_33563728的博客 222

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

从压测到调优:微服务系统性能评估与优化实战全解析

性能测试是保障软件系统稳定性和用户体验的关键环节,其核心在于通过科学的压力测试,评估系统在高并发下的表现。其原理在于模拟真实用户行为,对系统施加负载,并监控吞吐量、响应时间、错误率及资源利用率等核心指标,从而发现瓶颈。这项技术的价值在于,它能提前暴露生产环境可能出现的风险,避免因性能问题导致的业务中断和声誉损失,是系统上线前不可或缺的验证手段。应用场景广泛覆盖电商大促、秒杀活动等高并发业务。本文基于一次核心交易系统的性能攻坚实战,深入剖析了全链路压测的策略制定、JMeter分布式压测的实战技巧,以及从基础设

weixin_28829339的博客 246

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

深入CLR运行原理:从IL到GC、JIT与跨语言集成的工程实践

CLR(公共语言运行时)是.NET平台的核心执行引擎,其本质是一套覆盖编译器、运行时、操作系统与硬件的标准化契约体系。它通过ECMA-335规范定义IL指令语义、内存模型、异常传播和类型系统,确保C#、F#等语言在不同平台行为一致。理解CLR的关键在于掌握JIT编译流程——从IL解析、平台适配、寄存器分配到安全桩注入;以及GC机制——包括工作站/服务器模式差异、代际触发逻辑与LOH碎片化治理。这些底层能力直接决定云原生服务的内存稳定性、启动性能与跨平台兼容性。本文结合.NET 6/8真实迁移案例,解析JIT

diedangxiang4092的博客 366

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Beekeeper Studio SQL 客户端版本对比完全指南:3 个差异决定选社区版还是付费版

Beekeeper Studio 是一款支持 MySQL、PostgreSQL、SQLite 等数据库的跨平台 SQL 客户端,分 GPLv3 社区版与商业付费版两种形态。读完本文,你可以直接得到结论:免费版够用,还是需要采购付费许可。 **核心差异一句话:社区版已覆盖全部主流关系型数据库,付费版多买的是三样东西——云团队工作区、十余种小众数据库支持、AI Shell。** ## 授权差异与源

gitblog_00535的博客 438

VirtualVM:Java 应用性能监控与调优实战

本文详细介绍了如何使用JDK内置的VirtualVM工具进行Java应用性能监控与调优实战。通过内存、线程和CPU的实时可视化监控,开发者可以快速定位内存泄漏、线程死锁和CPU热点等常见性能瓶颈。文章结合真实案例,手把手指导从本地连接到远程JMX配置,并提供了堆转储分析与CPU采样等进阶技巧,帮助开发者将性能问题从“黑箱”变为可观测、可解决的工程问题。

qsc9012345的博客 229

【JVM调优】如何进行JVM调优?一篇文章就够了!

深入解读JVM性能的监控、定位和调优方案,阐述jps/stat/jstack、MAT等常用性能分析工具的使用,提出JVM参数、内存溢出、内存泄漏、CPU飙升、GC频繁等实际场景下JVM调优的方案。

种一棵树最好的时间是十年前,其次是现在 4万+
上一篇: 一份“内卷”面试题兼答案,直接让我15k变成30k
下一篇: 「RocketMQ技术专题」帮你梳理RocketMQ/Kafka的选择理由及二者PK
superjava_
博客等级 码龄5年 254粉丝 81原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值