腾讯云后端15连问!(四)
11. JVM调优
11.1 一般什么时候考虑JVM调优呢?
• Heap内存(老年代)持续上涨达到设置的最大内存值;
• Full GC 次数频繁;
• GC 停顿时间过长(超过1秒);
• 应用出现OutOfMemory 等内存异常;
• 应用中有使用本地缓存且占用大量内存空间;
• 系统吞吐量与响应性能不高或下降。
11.2 JVM调优的目标
• 延迟:GC低停顿和GC低频率;
• 低内存占用;
• 高吞吐量;
11.3 JVM调优量化目标
• Heap 内存使用率 <= 70%;
• Old generation内存使用率<= 70%;
• avgpause <= 1秒;
• Full gc 次数0 或 avg pause interval >= 24小时 ;
11.4 JVM调优的步骤
• 分析GC日志及dump文件,判断是否需要优化,确定瓶颈问题点;
• 确定JVM调优量化目标;
• 确定JVM调优参数(根据历史JVM参数来调整);
• 依次调优内存、延迟、吞吐量等指标;
• 对比观察调优前后的差异;
• 不断的分析和调整,直到找到合适的JVM参数配置;
• 找到最合适的参数,将这些参数应用到所有服务器,并进行后续跟踪。
11.5 常见的JVM参数
堆栈配置相关
-Xmx3550m -Xms3550m -Xmn2g -Xss128k
-XX:MaxPermSize=16m -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxTenuringThreshold=0
• -Xmx3550m:最大堆大小为3550m。
• -Xms3550m:设置初始堆大小为3550m。
• -Xmn2g:设置年轻代大小为2g。
• -Xss128k:每个线程的堆栈大小为128k。
• -XX:MaxPermSize: 设置持久代大小为16m
• -XX:NewRatio=4: 设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。
• -XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6
• -XX:MaxTenuringThreshold=0:设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。
垃圾收集器相关
-XX:+UseParallelGC
-XX:ParallelGCThreads=20
-XX:+UseConcMarkSweepGC
-XX:CMSFullGCsBeforeCompaction=5
-XX:+UseCMSCompactAtFullCollection:
-XX:+UseConcMarkSweepGC
• -XX:+UseParallelGC:选择垃圾收集器为并行收集器。
• -XX:ParallelGCThreads=20:配置并行收集器的线程数
• -XX:+UseConcMarkSweepGC:设置年老代为并发收集。
• -XX:CMSFullGCsBeforeCompaction:由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间以后会产生“碎片”,使得运行效率降低。此值设置运行多少次GC以后对内存空间进行压缩、整理。
• -XX:+UseCMSCompactAtFullCollection:打开对年老代的压缩。可能会影响性能,但是可以消除碎片
• -XX:+UseConcMarkSweepGC 使用CMS垃圾收集器
辅助信息
-XX:+PrintGC
-XX:+PrintGCDetails
11.6 常用调优策略
• 选择合适的垃圾回收器
• 调整内存大小(垃圾收集频率非常频繁,如果是内存太小,可适当调整内存大小)
• 调整内存区域大小比率(某一个区域的GC频繁,其他都正常。)
• 调整对象升老年代的年龄(老年代频繁GC,每次回收的对象很多。)
• 调整大对象的标准(老年代频繁GC,每次回收的对象很多,而且单个对象的体积都比较大。)
• 调整GC的触发时机(CMS,G1 经常 Full GC,程序卡顿严重。)
• 调整 JVM本地内存大小(GC的次数、时间和回收的对象都正常,堆内存空间充足,但是报OOM)
12. 数据库分库分表的缺点是啥?
1.事务问题,已经不可以用本地事务了,需要用分布式事务。
2.跨节点Join的问题:解决这一问题可以分两次查询实现
3.跨节点的count,order by,group by以及聚合函数问题:分别在各个节点上得到结果后在应用程序端进行合并。
4.ID问题:数据库被切分后,不能再依赖数据库自身的主键生成机制啦,最简单可以考虑UUID
5.跨分片的排序分页问题(后台加大pagesize处理?)
13. 分布式事务如何解决?TCC 了解?
分布式事务:
就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。简单来说,分布式事务指的就是分布式系统中的事务,它的存在就是为了保证不同数据库节点的数据一致性。
聊到分布式事务,需要知道这两个基本理论哈。
• CAP 理论
• BASE 理论
CAP 理论
• 一致性(C:Consistency):一致性是指数据在多个副本之间能否保持一致的特性。例如一个数据在某个分区节点更新之后,在其他分区节点读出来的数据也是更新之后的数据。
• 可用性(A:Availability):可用性是指系统提供的服务必须一直处于可用的状态,对于用户的每一个操作请求总是能够在有限的时间内返回结果。这里的重点是"有限时间内"和"返回结果"。
• 分区容错性(P:Partition tolerance):分布式系统在遇到任何网络分区故障的时候,仍然需要能够保证对外提供满足一致性和可用性的服务。
BASE 理论
它是对CAP中AP的一个扩展,对于我们的业务系统,我们考虑牺牲一致性来换取系统的可用性和分区容错性。BASE是Basically Available,Soft state,和 Eventually consistent三个短语的缩写。
• Basically Available(基本可用):通过支持局部故障而不是系统全局故障来实现的。如将用户分区在 5 个数据库服务器上,一个用户数据库的故障只影响这台特定主机那 20% 的用户,其他用户不受影响。
• Soft State(软状态):状态可以有一段时间不同步
• Eventually Consistent(最终一致):最终数据是一致的就可以了,而不是时时保持强一致。
分布式事务的几种解决方案:
• 2PC(二阶段提交)方案、3PC
• TCC(Try、Confirm、Cancel)
• 本地消息表
• 最大努力通知
• seata事务
TCC(补偿机制)
TCC 采用了补偿机制,其核心思想是:针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作。TCC(Try-Confirm-Cancel)包括三段流程:
• try阶段:尝试去执行,完成所有业务的一致性检查,预留必须的业务资源。
• Confirm阶段:该阶段对业务进行确认提交,不做任何检查,因为try阶段已经检查过了,默认Confirm阶段是不会出错的。
• Cancel 阶段:若业务执行失败,则进入该阶段,它会释放try阶段占用的所有业务资源,并回滚Confirm阶段执行的所有操作。
下面再拿用户下单购买礼物作为例子来模拟TCC实现分布式事务的过程:
假设用户A余额为100金币,拥有的礼物为5朵。A花了10个金币,下订单,购买10朵玫瑰。余额、订单、礼物都在不同数据库。
TCC的Try阶段:
• 生成一条订单记录,订单状态为待确认。
• 将用户A的账户金币中余额更新为90,冻结金币为10(预留业务资源)
• 将用户的礼物数量为5,预增加数量为10。
• Try成功之后,便进入Confirm阶段
• Try过程发生任何异常,均进入Cancel阶段
TCC的Confirm阶段:
• 订单状态更新为已支付
• 更新用户余额为90,可冻结为0
• 用户礼物数量更新为15,预增加为0
• Confirm过程发生任何异常,均进入Cancel阶段
• Confirm过程执行成功,则该事务结束
TCC的Cancel阶段:
• 修改订单状态为已取消
• 更新用户余额回100
• 更新用户礼物数量为5
• TCC的优点是可以自定义数据库操作的粒度,降低了锁冲突,可以提升性能
• TCC的缺点是应用侵入性强,需要根据网络、系统故障等不同失败原因实现不同的回滚策略,实现难度大,一般借助TCC开源框架,ByteTCC,TCC-transaction,Himly。
大家有兴趣可以看下我之前这篇文章哈:
14, RocketMQ 如何保证消息的准确性和安全性?
我个人理解的话,这道题换汤不换药,就是为如何保证RocketMQ 不丢消息,保证不重复消费,消息有序性,消息堆积的处理。
消息不丢失的话,即从生产者、存储端、消费端去考虑
大家可以看下我之前这篇文章哈:
15. 三个数求和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组
实例1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
实例2:
输入:nums = [0]
输出:[]
思路:
这道题可以先给数组排序,接着用左右双指针。
完整代码如下:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new LinkedList<>();
if(nums==null||nums.length<3){ //为空或者元素个数小于3,直接返回
return result;
}
Arrays.sort(nums); //排序
for(int i=0;i<nums.length-2;i++){ //遍历到倒数第三个,因为是三个数总和
if(nums[i]>0){ //大于0可以直接跳出循环了
break;
}
if(i>0&&nums[i]==nums[i-1]){ //过滤重复
continue;
}
int left = i+1; //左指针
int right = nums.length-1; //右指针
int target = - nums[i]; //目标总和,是第i个的取反,也就是a+b+c=0,则b+c=-a即可
while(left<right){
if(nums[left]+ nums[right]==target){ //b+c=-a,满足a+b+c=0
result.add(Arrays.asList(nums[i],nums[left],nums[right]));
left++; //左指针右移
right--; //右指针左移
while(left<right&&nums[left]==nums[left-1]) left++; //继续左边过滤重复
while(left<right&&nums[right]==nums[right+1]) right--; //继续右边过滤重复
}else if(nums[left]+ nums[right]<target){
left++; //小于目标值,需要右移,因为排好序是从小到大的
}else{
right--;
}
}
}
return result;
}
}
参考与感谢
• Callable/Future 使用及原理分析[1]
• 【JVM进阶之路】十:JVM调优总结[2]
• 分布式理论(五) - 一致性算法Paxos[3]
• 这一定是全网讲的最好的Paxos一致性算法