【JVM】亿级流量调优(二)

2024-08-25 13:52
文章标签 java jvm 流量 调优 亿级

本文主要是介绍【JVM】亿级流量调优(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

亿级流量调优

指针压缩

-XX:-UseCompressedOops指针压缩技术只有64位机器才有。jdk6以后引入的技术,默认是开启的

关闭指针压缩的情况下

在这里插入图片描述
在这里插入图片描述

通过HSDB用Memory Viewer查看该对象在内存中的分配地址发现类型指针占8字节,0x3其实是数组的长度,前面用一行来存储类型指针

开启指针压缩的情况下

在这里插入图片描述
在这里插入图片描述
通过HSDB用Memory Viewer查看该对象在内存中的分配地址发现类型指针占4个字节,开启之后,类型指针和数组长度放在一起了

上面的情况分析如下:

在这里插入图片描述

跟C/C++中的一个联合体有关联

union u {
int i;  // 4B
void p; // 8B
}

该联合体所占大小由最大字节数决定
比如说类型指针:0xffffffff,数组长度为0x00000003,当开启指针压缩时,由于只使用了联合体中的4B,但是联合体本身还是占8B,于是就出现了4B的浪费情况,数组长度占4B,那么把两者拼在一起,就可以节省8B的开销,把数组长度填充到前4B里面,相当于0x0003ffff。

为什么数组对象在关闭指针压缩的情况下有两段填充?不仅要站在学习者的角度去思考问题,更要以设计者的角度去思考

在这里插入图片描述

  • 1.在开启指针压缩的情况下:
    类型指针0xffffffff 8B
    数组长度:0xffff 4B
    用一个8B就存储下了
  • 2.那么在关闭指针压缩的情况下
    类型指针0xffffffff 8B
    数组长度: 0x0000ffff
    由于数组长度只占4B,根据8字节对齐的规范,对于一行内存地址来说,这里就出现了4字节的空间,那么我们知道,数组长度的下一个数据区域就是实例数据,如果说实例数据中正好有一个int类型,那么ok,正好填补到前面的4个字节里面,那如果不是int类型呢?是char类型的呢?虽然说可以存进去,但是作为设计者如何知道这个数据区域存储的实例数据是char类型还是int类型呢?所以说,存进去的话,会比较麻烦,于是需要在对象头的尾部进行对齐填充

指针压缩的底层原理?这个技术能被开发出来归根结底是来自"所有对象大小都必须能被8整除"这条规则。

在这里插入图片描述

8字节对齐的言外之意 8(1 000)
如图所示,现在有三个对象
test1:16B
test2:32B
test3:24B

test1的起始地址: 0B
test2的起始地址:16B
test3的起始地址:48B
他们分别对应的二进制:
test1: 0 000
test2:10 000
test3:110 000
可以看到后三位永远是0,那么JVM在存储的时候,就可以这样存储,向右移3位。>>3
也就是说只存储
test1: 0
test2: 10
test3: 110
然后在使用的时候可以左移3位, << 3,再把它还原回去
根本原因在于"8字节对齐"这条规则

堆内存的32G瓶颈从何而来?

在32位机器中,最大内存可以表示为4G,现在机器普遍已经是64位了,按理说,堆内存可以设置超常的大,为什么还会有32G这个瓶颈之说呢?
原因在于,2的32次方表示的内存为4G,在指针压缩使用时,可以将低位进行左移3位,可表示的最大内存也就是2的35次方=32G.

如何扩容,思路是什么?为什么是8字节对齐?

要突破32G内存瓶颈的话,需要改写8字节对齐这条规则,8字节对齐的话,瓶颈是32G,16字节对齐,瓶颈也会扩大一倍,变成64G.但是这样需要考虑内存的使用率,因为在对齐填充的时候,补充的都是空白地址,也就是说在突破瓶颈的同时,也会带来内存空间的浪费。
现在64位机器,并没有完全使用64位地址来表示,只使用了48位,剩下16位保留。也就是说,64位机器上最大使用的内存是2的48次方,原因在于CPU还没有强大到能处理这么大的内存,受制于CPU的算力

例如:
8字节对齐:17B+7B=24B
16字节对齐:17B +15B= 32B(内存的浪费可能更严重)
另外还有一部分原因是:
32G的内存,那么OOM的Dump文件将会变得非常大,普通机器将没法分析

对于一个正常的GC来说,它的频率应该是
5分钟一次YGC
1天一次FullGC
内存大了,虽然发生FullGC的频率小了,但是单次GC花费的时间更长了

JVM调优

为什么调优?
调优的顺序:避免OOM>FullGC>YGC

  • 1.避免OOM,
  • 2.尽可能减少FullGC,FullGC会引发STW(Stop The World)
    到底调什么?
  • 1.在项目部署到线上之前,基于可能的并发量进行预估调优
  • 2.,在项目运行过程中,部署监控收集性能数据,平时分析日志进行调优
  • 3.线上出现OOM,进行问题排查与调优

实战:亿级流量系统实战

在这里插入图片描述

  • 1.如果每个用户平均访问20个商品详情页,那访客数约定于500w(一亿/20)
  • 2.如果按转化率10%来算,那日均订单约等于50w(500w * 10%)
  • 3.如果30%的订单是在秒杀前两分钟完成的,那么每秒产生1200笔订单(50w*30%/120s)
  • 4.订单支付又涉及到发起支付流程、物流、优惠券、推荐、积分等环节,导致产生大量对象,这里我们假设整个支付流程生成的对象为20K,那么每秒在Eden区生成的对象约等于20M(1200笔 * 20K)
  • 5.在生产环境中,订单模块还涉及到百万商家查询订单、改价、包邮、发货等其他操作,又会产生大量对象,我们放大10倍,即每秒在Eden区生成的对象约等于200M(其实这里就是在大并发时刻可以考虑服务降级的地方,架构其实就是取舍)
    假设响应一个请求的时间为3s(包括付款、扣减库存)
    这里的假设数据都是大部分电商系统的通用概率,是有一定代表性的.如果你作为这个系统的架构师,面对这样的场景,你会如何做JVM调优呢?即将运行该系统的JVM堆区设置成多大呢?

分析:

  • 1.每秒产生200M对象,Eden区的大小为2.2G,相当于11s就会触发YGC(11 x 200 = 2200M对象),由于假设一个请求响应时间为3s,所以发生GC的时候,会有600M(200M * 3 = 600M)对象回收不掉。GC回收的是标记不到的对象,而S0、S1只有270M,放不下这600M对象,进而触发老年代空间担保机制,放入老年代。对于老年代而言,大小为5400M->9次YGC->触发一次FGC.9x11=99s,触发一次FC,这样的频率8G内存不适合的
  • 2.怎么做调优?加内存?怎么加?
    S0、S1的内存区域要大于600M,这样,假设S0/S1都为600M,Eden区为4800M(600 x 8 = 4800),约等于6G,那老年代为12G(6G x 2 = 12G),内存加起来的话,12G+6G=18G,但是内存一般都取2的n次幂,所以取16G即可。

如果不调优,则会出现一直触发FGC,又回收不到可用的内存,进而导致JVM发生崩溃

1.堆到底设置成多大比较合适?堆越大越好吗?

如果堆设置的很小-> GC频率可能很高,GC时间也比较短
设置的很大->GC频率会低,但是GC的时长却增加了
调优不是一蹴而就的,需要逐步调整,并观察JVM的GC情况
2.什么样的系统可以进行JVM调优?
首先要区分出是OLAP(在线分析)系统还是OLTP(在线事务查询)系统,如果是OLAP(在线分析)系统,是没有多大调优空间的,因为一次性要查询大量对象,这个是没有办法做调优的,只能加大内存
3.正常GC单次时长100ms,前端和后端的平衡,不能让前端感到明显卡顿

这篇关于【JVM】亿级流量调优(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1105737

相关文章

Java反转字符串的五种方法总结

《Java反转字符串的五种方法总结》:本文主要介绍五种在Java中反转字符串的方法,包括使用StringBuilder的reverse()方法、字符数组、自定义StringBuilder方法、直接... 目录前言方法一:使用StringBuilder的reverse()方法方法二:使用字符数组方法三:使用自

JAVA封装多线程实现的方式及原理

《JAVA封装多线程实现的方式及原理》:本文主要介绍Java中封装多线程的原理和常见方式,通过封装可以简化多线程的使用,提高安全性,并增强代码的可维护性和可扩展性,需要的朋友可以参考下... 目录前言一、封装的目标二、常见的封装方式及原理总结前言在 Java 中,封装多线程的原理主要围绕着将多线程相关的操

Java进阶学习之如何开启远程调式

《Java进阶学习之如何开启远程调式》Java开发中的远程调试是一项至关重要的技能,特别是在处理生产环境的问题或者协作开发时,:本文主要介绍Java进阶学习之如何开启远程调式的相关资料,需要的朋友... 目录概述Java远程调试的开启与底层原理开启Java远程调试底层原理JVM参数总结&nbsMbKKXJx

Spring Cloud之注册中心Nacos的使用详解

《SpringCloud之注册中心Nacos的使用详解》本文介绍SpringCloudAlibaba中的Nacos组件,对比了Nacos与Eureka的区别,展示了如何在项目中引入SpringClo... 目录Naacos服务注册/服务发现引⼊Spring Cloud Alibaba依赖引入Naco编程s依

java导出pdf文件的详细实现方法

《java导出pdf文件的详细实现方法》:本文主要介绍java导出pdf文件的详细实现方法,包括制作模板、获取中文字体文件、实现后端服务以及前端发起请求并生成下载链接,需要的朋友可以参考下... 目录使用注意点包含内容1、制作pdf模板2、获取pdf导出中文需要的文件3、实现4、前端发起请求并生成下载链接使

Java springBoot初步使用websocket的代码示例

《JavaspringBoot初步使用websocket的代码示例》:本文主要介绍JavaspringBoot初步使用websocket的相关资料,WebSocket是一种实现实时双向通信的协... 目录一、什么是websocket二、依赖坐标地址1.springBoot父级依赖2.springBoot依赖

如何用java对接微信小程序下单后的发货接口

《如何用java对接微信小程序下单后的发货接口》:本文主要介绍在微信小程序后台实现发货通知的步骤,包括获取Access_token、使用RestTemplate调用发货接口、处理AccessTok... 目录配置参数 调用代码获取Access_token调用发货的接口类注意点总结配置参数 首先需要获取Ac

Java逻辑运算符之&&、|| 与&、 |的区别及应用

《Java逻辑运算符之&&、||与&、|的区别及应用》:本文主要介绍Java逻辑运算符之&&、||与&、|的区别及应用的相关资料,分别是&&、||与&、|,并探讨了它们在不同应用场景中... 目录前言一、基本概念与运算符介绍二、短路与与非短路与:&& 与 & 的区别1. &&:短路与(AND)2. &:非短

Java的volatile和sychronized底层实现原理解析

《Java的volatile和sychronized底层实现原理解析》文章详细介绍了Java中的synchronized和volatile关键字的底层实现原理,包括字节码层面、JVM层面的实现细节,以... 目录1. 概览2. Synchronized2.1 字节码层面2.2 JVM层面2.2.1 ente

什么是 Java 的 CyclicBarrier(代码示例)

《什么是Java的CyclicBarrier(代码示例)》CyclicBarrier是多线程协同的利器,适合需要多次同步的场景,本文通过代码示例讲解什么是Java的CyclicBarrier,感... 你的回答(口语化,面试场景)面试官:什么是 Java 的 CyclicBarrier?你:好的,我来举个例