Default Changelist

LCR001.java
LeetCode11.java
LeetCode277.java
LeetCode279.java
LeetCode322.java
LeetCode713.java
LeetCode1049.java
Tc.md
This commit is contained in:
whaifree 2024-09-27 20:42:08 +08:00
parent 61d92b60d5
commit 574e99f373
8 changed files with 397 additions and 175 deletions

175
Tc.md
View File

@ -1,175 +0,0 @@
```java
public List<Instance> findInstanceList(List<Instance> instanceList, TsfBaseEntity entity) {
if (CollectionUtils.isEmpty(instanceList)) {
return new ArrayList<>();
}
List<Instance> instanceRunList = new ArrayList<>();
//虚机节点
long start, end;
start = System.currentTimeMillis();
List<Instance> instanceCVMList = instanceList.stream().filter(item ->
ClusterConstant.CLUSTER_TYPE.CVM.equals(item.getClusterType())).collect(Collectors.toList());
List<String> instanceIdList = instanceCVMList.stream().map(Instance::getInstanceId).collect(Collectors.toList());
List<InstanceAgent> instanceAgentList = instanceAgentJpaRepository.findByInstanceIdIn(instanceIdList);
Map<String, InstanceAgent> instanceAgentMap = TsfMapUtil.list2HashMap(instanceAgentList, "getInstanceId");
if (!CollectionUtils.isEmpty(instanceAgentMap)) {
for (Instance ins : instanceCVMList) {
InstanceAgent instanceAgent = instanceAgentMap.get(ins.getInstanceId());
if (instanceAgent != null) {
Long currentTimestamp = System.currentTimeMillis();
Long heartbeatTimestamp = instanceAgent.getUpdateTime() != null ? instanceAgent.getUpdateTime().getTime() : 0L;
if (heartbeatTimestamp + 18 * 60 * 1000 > currentTimestamp) {
instanceRunList.add(ins);
}
}
}
}
end = System.currentTimeMillis();
logger.info("call cvm clusterInstances cost {}ms", (end - start));
//容器节点
start = System.currentTimeMillis();
List<Instance> instanceCCSList = instanceList.stream().filter(item ->
ClusterConstant.CLUSTER_TYPE.CCS.equals(item.getClusterType())).collect(Collectors.toList());
Map<String, List<Instance>> instanceCcsMap = instanceCCSList.stream().collect(Collectors.groupingBy(Instance::getClusterId));
instanceCcsMap.forEach((clusterId,instanceCcsList) -> {
Cluster cluster = new Cluster();
cluster.transferBase(entity);
cluster.setClusterId(clusterId);
List<Instance> ccsRunInstanceList = commonContainerInstanceService.findRunInstanceList(cluster, instanceCcsList);
instanceRunList.addAll(ccsRunInstanceList);
});
end = System.currentTimeMillis();
logger.info("call ccs clusterInstances cost {}ms", (end - start));
return instanceRunList;
}
```
117789438
CountDownLatch 的使用
```java
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
final int numberOfTasks = 3; // 假设有3个任务需要完成
CountDownLatch latch = new CountDownLatch(numberOfTasks);
for (int i = 0; i < numberOfTasks; i++) {
new Thread(() -> {
System.out.println("任务 " + Thread.currentThread().getName() + " 开始执行...");
// 模拟任务执行需要一些时间
try {
Thread.sleep((long) (Math.random() * 1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任务 " + Thread.currentThread().getName() + " 执行完成");
latch.countDown(); // 任务完成计数减1
}).start();
}
System.out.println("主线程等待所有任务完成...");
latch.await(); // 主线程等待所有任务完成
System.out.println("所有任务已完成,主线程继续执行...");
}
}
```
**使用AtomicInteger、CountDownLatch、线程池的并发方式优化查询集群数量接口和实例数量资源接口的性能解决超时问题。在查询实例或集群数量过多时查询DB还需要查询容器平台、会导致查询时延达到15s秒**
使用redis封装避免短时间缓存击穿
线程工厂
```java
package com.tencent.tsf.resource.common.util;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
public class CustomThreadFactory implements ThreadFactory {
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix;
public CustomThreadFactory(String prefix) {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
namePrefix = prefix + "-thread-";
}
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
```
线程池
```java
private ExecutorService overviewResourceUsageExecutor =
new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors() * 2, Runtime.getRuntime().availableProcessors() * 2,0, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(2048),
new CustomThreadFactory("overviewResourceUsageThreadPool"),
new ThreadPoolExecutor.AbortPolicy());
```
固定线程数量的线程池我是8核的cpu此时能用8个cpu处理16个线程当线程满了时就进入阻塞队列ArrayBlockingQueue
1. 核心线程数corePoolSizeRuntime.getRuntime().availableProcessors() * 2。这意味着线程池会创建一个核心线程数等于当前系统可用处理器的两倍。这样的设置通常是为了确保线程池能够充分利用系统资源同时避免线程过多导致上下文切换开销过大。
2. 最大线程数maximumPoolSize同样设置为Runtime.getRuntime().availableProcessors() * 2。这意味着线程池允许存在的最大线程数也是系统可用处理器的两倍。由于核心线程数和最大线程数相等这个线程池实际上是一个固定大小的线程池它不会根据任务的多少动态地增加或减少线程数量。
3. 线程空闲时间keepAliveTime设置为0秒。这意味着线程一旦空闲下来就会被立即回收不会等待其他任务的到来。这个设置适用于任务持续不断地到来的场景可以节省资源。
4. 时间单位unit设置为TimeUnit.SECONDS表示线程空闲时间的单位是秒。
5. 工作队列workQueue使用ArrayBlockingQueue作为工作队列容量为2048。这意味着当线程池中的线程都在忙碌时新来的任务会进入这个队列等待执行。队列的容量较大可以容纳较多的待执行任务有助于减少线程创建和销毁的频率。
6. 线程工厂threadFactory使用CustomThreadFactory自定义线程工厂来创建线程。这样可以自定义线程的名称、优先级等属性便于管理和调试。
7. 拒绝策略RejectedExecutionHandler使用ThreadPoolExecutor.AbortPolicy()作为拒绝策略。当线程池和工作队列都满时新提交的任务会导致抛出RejectedExecutionException异常。这种策略比较直接可以让调用者感知到任务无法执行的情况并进行相应处理。
接口超时超过15s了
【此接口内部有一个循环查询逻辑循环里面需要查询DB还需要查询容器平台故性能会随着用户集群的增多而下降】
两个接口超时的原因基本是一样的:
1、DescribeGroupResourceUsage 首先会查询出所有的集群,包括虚拟机集群和容器集群,之后再将所有的集群进行遍历:
如果是容器集群先根据集群ID在DB里面查询出关联的所有group列表然后就会调用apiserver获取所有的pod信息然后累计计算部署组中的pod个数和健康状况。
如果是虚拟机集群先根据集群ID在DB里面查询出关联的所有group列表然后再去调用masterapi的相关接口获取group的实例信息最后再统计。
最终再将所有集群计算出来的数据进行累加,这里的耗时体现在,每个集群的查询耗时是串行累加的,不是并行,所以集群数量越多,累加时间肯定越大。
2、DescribeInstanceResourceUsage 首先会查询出所有的集群,包括虚拟机集群和容器集群,之后再将所有的集群进行遍历:
如果是容器集群先根据集群ID在DB里面查询出关联的所有group列表然后就会调用apiserver获取所有的pod信息然后累计计算部署组中的pod个数。
如果是虚拟机集群根据clusterID去调用masterapi的相关接口获取集群下面的instance列表然后再统计各个维度的instance个数。
然后再将所有集群计算出来的数据进行累加,这里的耗时体现在,每个集群的查询耗时是串行累加的,不是并行,所以集群数量越多,累加时间肯定越大。
最后还需要统计所有容器集群的健康状态此时需要调用TKE的接口去批量查询容器集群健康状态。
- 优化策略:将串行查询优化为并行查询
- 问题: 在查询实例或集群数量过多时查询DB还需要查询容器平台、会导致查询时延达到15s秒
- 原因查询出所有的集群包括虚拟机集群和容器集群之后再将所有的集群进行遍历如果是容器集群先根据集群ID在DB里面查询出关联的所有group列表然后就会调用apiserver获取所有的pod信息然后累计计算部署组中的pod个数和健康状况
如果是虚拟机集群先根据集群ID在DB里面查询出关联的所有group列表然后再去调用masterapi的相关接口获取group的实例信息最后再统计。
最终再将所有集群计算出来的数据进行累加,这里的耗时体现在,每个集群的查询耗时是串行累加的,不是并行,所以集群数量越多,累加时间肯定越大。
- 解决引入线程池来并发处理查询请求使用AtomicInteger来安全地统计实例数量并利用CountDownLatch确保所有并发任务完成后才返回结果从而提高了接口的并发处理能力并解决了超时问题。

View File

@ -0,0 +1,61 @@
package cn.whaifree.redo.redo_all_240924;
import org.junit.Test;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/9/27 11:25
* @注释
*/
public class LCR001 {
@Test
public void test() {
System.out.println(new Solution().divide(-2147483648, 1));
}
class Solution {
/**
* 17/3
* 17 << 3<<2 = 5 5 << 0 余数2
* 2^2+2^0 // 向上取整
*
* @param a
* @param b
* @return
*/
public int divide(int a, int b) {
// 特殊情况2, b=-1
if (b == -1) {
return a == Integer.MIN_VALUE ? Integer.MAX_VALUE : -a;
}
long A = a;
long B = b;
boolean reverse = false;
if ((A <= 0 && B <= 0) || (A >= 0 && B >= 0)) {
reverse = true;
}
A = Math.abs(A);
B = Math.abs(B);
long base = A;
long res = 0;
while (base >= B) {
long tmpPoint = 1;
long item = B;
while ((item << 2) < base) {
item <<= 1;
tmpPoint <<= 1;
}
base -= item;
res += tmpPoint;
}
return (int) (reverse ? res : -res);
}
}
}

View File

@ -0,0 +1,75 @@
package cn.whaifree.redo.redo_all_240924;
import org.junit.Test;
import java.util.Arrays;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/9/27 11:01
* @注释
*/
public class LeetCode1049 {
@Test
public void test() {
int[] stones = {2,7,4,1,8,1};
System.out.println(new Solution1().lastStoneWeightII(stones));
}
class Solution {
/**
* 0 - 1 背包
* <p>
* 背包容量sumStones/2
* <p>
* dp[i][j] 表示 从0-i任意选择石头放入容量为j的背包的最大价值
* 剩余的石头就是sumStones/2- dp[i][j]
*
* @param stones
* @return
*/
public int lastStoneWeightII(int[] stones) {
int sumStones = Arrays.stream(stones).sum();
int pkgSize = sumStones / 2;
int[][] dp = new int[stones.length][pkgSize + 1];
for (int i = stones[0]; i <= pkgSize; i++) {
dp[0][i] = stones[0];
}
for (int i = 1; i < stones.length; i++) {
for (int j = 0; j <= pkgSize; j++) {
// 放得下
if (stones[i] <= j) {
dp[i][j] = Math.max(dp[i - 1][j - stones[i]] + stones[i], dp[i - 1][j]);
} else {
dp[i][j] = dp[i - 1][j];
}
}
}
return sumStones - 2 * dp[stones.length - 1][pkgSize];
}
}
class Solution1 {
public int lastStoneWeightII(int[] stones) {
int sum = 0;
for (int i : stones) {
sum += i;
}
int pkgSize = sum / 2;
int[] dp = new int[pkgSize + 1];
for (int i = 0; i < stones.length; i++) {
for (int j = pkgSize; j >= stones[i]; j--) {
dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]);
}
}
return sum - 2 * dp[pkgSize];
}
}
}

View File

@ -0,0 +1,35 @@
package cn.whaifree.redo.redo_all_240924;
import org.junit.Test;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/9/27 14:46
* @注释
*/
public class LeetCode11 {
@Test
public void test() {
int[] height = {1, 8, 6, 2, 5, 4, 8, 3, 7};
System.out.println(new Solution().maxArea(height));
}
class Solution {
public int maxArea(int[] height) {
int left = 0;
int right = height.length - 1;
int max = Integer.MIN_VALUE;
while (left < right) {
max = Math.max(max, (right - left) * Math.min(height[left], height[right]));
if (height[left] < height[right]) {
left++;
} else {
right--;
}
}
return max;
}
}
}

View File

@ -0,0 +1,54 @@
package cn.whaifree.redo.redo_all_240924;
import org.junit.Test;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/9/27 16:04
* @注释
*/
public class LeetCode277 {
@Test
public void test() {
int[] nums = {1, 2, 3};
int target = 4;
System.out.println(new Solution().combinationSum4(nums, target));
}
class Solution {
/**
* 物品 nums
* 容量 target
* <p>
* 0 1 2 3 4
* 1 1 1 1 1 1
* 2 1 1 2 2 2
* 3 1 1 2 3 3
*
* @param nums
* @param target
* @return
*/
public int combinationSum4(int[] nums, int target) {
int[] dp = new int[target + 1];
dp[0] = 1;
// 先遍历背包再遍历物品 排列有排序
// 先遍历物品再遍历背包组合无排序
for (int j = 0; j < target + 1; j++) {
for (int i = 0; i < nums.length; i++) {
if (nums[i] <= j) {
dp[j] = dp[j - nums[i]] + dp[j];
// dp[j] 原来的可能性
// dp[j-nums[i]] 使用容量j-nums的可能性
}
}
}
return dp[target];
}
}
}

View File

@ -0,0 +1,50 @@
package cn.whaifree.redo.redo_all_240924;
import org.junit.Test;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/9/27 15:04
* @注释
*/
public class LeetCode279 {
@Test
public void test() {
Solution solution = new Solution();
int i = solution.numSquares(13);
System.out.println(i);
}
class Solution {
/**
* 背包容量n
*
* 物品 1 4 9 16
*
* 任意背包
* @param n
* @return
*/
public int numSquares(int n) {
int sqrt = (int) Math.sqrt(n);
int[] dp = new int[n + 1];
for (int i = 1; i < dp.length; i++) {
dp[i] = i;
}
for (int i = 2; i <= sqrt; i++) {
for (int j = 0; j <= n; j++) {
int size = i * i;
if (size <= j) {
dp[j] = Math.min(dp[j], dp[j - size] + 1);
}
}
}
return dp[n];
}
}
}

View File

@ -0,0 +1,59 @@
package cn.whaifree.redo.redo_all_240924;
import org.junit.Test;
import java.util.Arrays;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/9/27 15:35
* @注释
*/
public class LeetCode322 {
@Test
public void test() {
int[] coins = new int[]{2,5,10,1};
int amount = 27;
System.out.println(new Solution().coinChange(coins, amount));
}
class Solution {
/**
* 从0-i中任意选择凑满amount的最少硬币数量
* 0 1 2 3 4 5 6 7 8 9 10 11
* 2 1 - 1 - 2 - 3 - 4 - 4 -
* 1 1 1 1
* 5
*
* @param coins
* @param amount
* @return
*/
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
for (int i = coins[0]; i <= amount; i += 1) {
if (i % coins[0] == 0) {
dp[i] = i / coins[0];
}
}
dp[0] = 0;
for (int i = 1; i < coins.length; i++) {
for (int j = coins[i]; j <= amount; j++) {
int X = dp[j - coins[i]];
if (X != Integer.MAX_VALUE) {
dp[j] = Math.min(dp[j], X + 1);
}
}
}
return dp[dp.length - 1] == Integer.MAX_VALUE ? -1 : dp[dp.length - 1];
}
}
}

View File

@ -0,0 +1,63 @@
package cn.whaifree.redo.redo_all_240924;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/9/27 12:12
* @注释
*/
public class LeetCode713 {
@Test
public void test() {
int[] nums = {10,5,2,6};
int k = 100;
System.out.println(new Solution().numSubarrayProductLessThanK(nums, k));
}
class Solution {
public int numSubarrayProductLessThanK(int[] nums, int k) {
int left = 0;
int right = 0;
int sum = 1;
int res = 0;
while (right < nums.length) {
sum *= nums[right];
while (left < right && sum >= k) {
// 大了就收缩
sum /= nums[left];
left++;
}
right++;
if (sum < k) {
res += right - left; // 一共有right-left个数字所以有right-left种可能以right结尾的
/**
* 如果一个子串的乘积小于k那么他的每个子集都小于k而一个长度为n的数组他的所有连续子串数量是1+2+...n但是会和前面的重复
* 比如例子中[10, 5, 2, 6]第一个满足条件的子串是[10]第二个满足的是[10, 5]但是第二个数组的子集[10]和前面的已经重复了
* 因此我们只需要计算包含最右边的数字的子串数量就不会重复了也就是在计算[10, 5]这个数组的子串是只加入[5][10, 5]
* 而不加入[10]这部分的子串数量刚好是r - l + 1
*/
/**
* 每次 j 增加时 j 结尾的满足乘积小于 k 的子数组数量为 j - i + 1
* 因为以 j 结尾的子数组可以从 i j 的任意一个位置作为起点都满足乘积小于 k
*/
}
}
return res;
}
}
}