[Java Virtual Machine] JVM tuning and analysis case comprehensive practice

1. What is JVM performance optimization

JVM performance optimization involves two very important concepts: throughput and response time. JVM tuning is mainly to adjust and optimize them to achieve an ideal goal, and determine whether the goal is to prioritize throughput or response time according to the business.

  • Throughput: user code execution time / (user code execution time + GC execution time).
  • Response time: The response time of the entire interface (user code execution time + GC execution time), the shorter the STW time, the shorter the response time.

Tuning Methodology

  • Monitor JVM performance

    • Monitor the running status of the JVM to understand application bottlenecks and performance bottlenecks
    • You can use the tools that come with the JVM, such as jstat, jmap, jstack, etc., or third-party tools, such as VisualVM, JProfiler, etc.
  • Benchmarks for stress testing

    • Perform pressure test on the program to obtain the throughput and response time corresponding to the interface
    • External phenomenon
      • For user experience, it is response speed
      • You can use the pressure measurement tool jmeter to perform pressure measurement to obtain relevant performance indicators
    • Internal phenomenon:
      • Analyzing the GC situation is an important factor in JVM performance tuning. It is necessary to master the working mechanism of GC and the meaning of GC logs
      • You can use the GC log that comes with the JVM or third-party tools, such as GCEasy, to analyze the GC situation and understand the GC frequency, time, memory usage, etc.
  • Adjust JVM parameters

    • Improve application performance by adjusting parameters such as heap size, GC algorithm, thread pool size, etc.
    • Note: Different applications and environments may require different JVM parameter configurations, such as IO-intensive and CPU-intensive applications
  • Secondary stress analysis

    • After adjusting the jvm parameters, the second pressure test to see whether the performance indicators are improved or decreased
    • Internal: GC log, see throughput, GC times, pause time changes
    • External: Whether the throughput and response time corresponding to the interface are better
  • Other optimization methods

    • optimize code

      • Optimize your code by avoiding unnecessary object creation, reducing synchronization operations, using caches, etc.
      • Note: Code optimization should follow the principle of "correct first, then optimize", and should not sacrifice code readability and maintainability
    • Use concurrent programming

      • Use multi-threading, thread pool, etc. to improve concurrency performance, such as adjusting the queue length of the thread pool, the number of surviving threads, etc.
      • Note: Concurrent programming needs to consider issues such as thread safety and lock competition, and requires correct design and implementation
    • use cache

      • You can use local cache, distributed cache, etc. to improve data access performance
      • Note: Caching needs to consider issues such as cache consistency and cache invalidation, and requires correct design and implementation
    • Avoid IO blocking

      • Use asynchronous IO, NIO, etc. to improve IO performance, such as the previously learned CompletableFuture asynchronous task arrangement
      • Note: IO programming needs to consider issues such as concurrency and reliability, and requires correct design and implementation
    • Distributed + cluster technology

      • Use load balancing + cluster technology to improve the processing capacity of a single node

2. JVM tuning pressure test environment preparation

  • The jar program written by SpringBoot, the interface returns a list of randomly composed objects within 100 (using JDK17)
/**
 * @author lixiang
 * @date 2023/5/8 21:44
 */
@Slf4j
@RestController
@RequestMapping("/spring-test")
public class SpringTestController {
    
    

    @RequestMapping("query")
    public Map<String, Object> query() throws InterruptedException {
    
    

        int num = (int) (Math.random() * 100) + 1;
        //申请5MB内存
        Byte[] bytes = new Byte[5 * 1024 * 1024];

        List<Product> productList = new ArrayList<>();
        for (int i = 0; i < num; i++) {
    
    
            Product product = new Product();
            product.setPrice((int) Math.random() * 100);
            product.setTitle("商品编号" + i);
            productList.add(product);
        }

        Thread.sleep(5);
        Map<String, Object> map = new HashMap<>(16);
        map.put("data", productList);
        return map;

    }

}
  • Jmeter pressure test tool preparation, test plan 200 concurrency, cycle 500 times

3. Heap size configuration for JVM performance optimization

  • Heap size configuration, performance impact of FullGC times
  • Performance optimized initial value
-Xms1g # 配置初始堆内存1G
-Xmx1g # 配置最大堆内存1G
-XX:+UseG1GC # 使用G1回收器
-XX:MaxGCPauseMillis=200 # 设置最大停顿时间200ms
-XX:G1HeapRegionSize=32M # 设置G1每个region块大小为32M
-XX:ActiveProcessorCount=8 # 设置JVM使用的CPU核数限制为8
-XX:+HeapDumpOnOutOfMemoryError # 当JVM发生OOM时,自动生成DUMP文件
-XX:HeapDumpPath=heapdump.hprof # DUMP文件路径
-XX:+PrintCommandLineFlags # 监控开启
-Xlog:gc=info:file=portal_gc.log:utctime,level,tags:filecount=50,filesize=100M 
  # Xlog:指定日志输出方式为日志文件。
  # gc*:指定日志输出类型为GC相关的日志。
  # info:指定输出日志的级别为info级别。
  # file=portal_gc.log:指定日志输出的文件名为portal_gc.log。
  # utctime:指定日志输出的时间戳使用UTC时间。
  # level,tags:指定日志输出的格式包含级别和标签信息。
  # filecount=50:指定最多保存50个日志文件。
  # filesize=100M:指定每个日志文件的大小为100MB。
  • The machine configuration is: 8-core 16G 500M bandwidth

insert image description here

  • Set initial heap memory and maximum heap memory to 1G, pressure test
nohup java -jar spring-test-1.0-SNAPSHOT.jar -Xms1g -Xmx1g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=32M -XX:ActiveProcessorCount=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/jmeter/heapdump.hprof -XX:+PrintCommandLineFlags -Xlog:gc=info:file=/usr/local/jmeter/portal_gc.log:utctime,level,tags:filecount=50,filesize=100M &

insert image description hereinsert image description here

When we set the heap memory to 1G, the overall throughput is more than 40%, which is already very low. During this period, Young GC occurred 7451 times, and Full GC occurred 142 times.

  • Set initial heap memory and maximum heap memory to 2G, pressure test
nohup java -jar spring-test-1.0-SNAPSHOT.jar -Xms2g -Xmx2g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=32M -XX:ActiveProcessorCount=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/jmeter/heapdump.hprof -XX:+PrintCommandLineFlags -Xlog:gc=info:file=/usr/local/jmeter/portal_gc.log:utctime,level,tags:filecount=50,filesize=100M &

insert image description hereinsert image description here

When we set the heap memory to 2G, compared to 1G, the throughput increased to more than 70%, and the number of Young GC was 752, and the number of Full GC was 6 times, which was doubled compared with 1G.

  • Set initial heap memory and maximum heap memory to 4G, pressure test
nohup java -jar spring-test-1.0-SNAPSHOT.jar -Xms4g -Xmx4g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=32M -XX:ActiveProcessorCount=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/jmeter/heapdump.hprof -XX:+PrintCommandLineFlags -Xlog:gc=info:file=/usr/local/jmeter/portal_gc.log:utctime,level,tags:filecount=50,filesize=100M &

insert image description hereinsert image description here

When the heap memory is set to 4G, the overall throughput increases to 76%, 504 occurs in Young GC, and no Full GC occurs.

  • Set initial heap memory and maximum heap memory to 6G, pressure test
nohup java -jar spring-test-1.0-SNAPSHOT.jar -Xms6g -Xmx6g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=32M -XX:ActiveProcessorCount=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/jmeter/heapdump.hprof -XX:+PrintCommandLineFlags -Xlog:gc=info:file=/usr/local/jmeter/portal_gc.log:utctime,level,tags:filecount=50,filesize=100M &

insert image description hereinsert image description here

When the heap memory is set to 6G, the overall throughput reaches 87%, Yong GC occurs 196 times, and Full GC occurs 0 times.

Summary: Through the adjustment of the heap memory, it is found that 4G is the parameter configuration with the highest input-output ratio, so the current configuration can use 4G heap memory.

4. Collector configuration for JVM performance optimization

Through the configuration of the heap memory above, we can conclude that 4G is the best heap memory for the current machine and application configuration. Here we do not change the size of the heap memory, but use 4G of the heap memory and change the garbage collector to see the impact on the interface throughput.

Here we use ParallelGC. At present, the G1 garbage collector is the best choice for applications with a large amount of concurrency. Here we mainly use ParallelGC for a comparison.

nohup java -jar spring-test-1.0-SNAPSHOT.jar -Xms4g -Xmx4g -XX:+UseParallelGC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=32M -XX:ActiveProcessorCount=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/jmeter/heapdump.hprof -XX:+PrintCommandLineFlags -Xlog:gc=info:file=/usr/local/jmeter/portal_gc.log:utctime,level,tags:filecount=50,filesize=100M &

insert image description here
insert image description here

Guess you like

Origin blog.csdn.net/weixin_47533244/article/details/130582772