掘金 后端 ( ) • 2024-04-02 17:07
CPU

场景

我们的游戏有高并发场景,为了提高系统性能我们把活动和游戏完全解耦。并且通过 CDCD 监听 binlog 方式推送到MQ 异步处理活动进度,在处理的时候 防止并发 对redis 封装了阻塞锁。

cpu高分析

  • 压测机器: 2c4g jvm2g
  • 压测用户100 80个线程组 tps达到400+ 我们在压测的时候 发现cpu很高 通过 arthas 分析一个线程cpu 10%+

image.png

具体分析后发现这段代码 耗时会增加cpu耗时

public boolean lockBlock(String key, String value, long expireTime, long waitTime) throws InterruptedException {
    long startTime = System.currentTimeMillis();
    long endTime = System.currentTimeMillis() + waitTime;
    while (true) {
        if (this.lock(key, value, expireTime)) {
            return true;
        }
        if (startTime >= endTime) {
            return false;
        }
        Thread.sleep(20);
        startTime = System.currentTimeMillis();
    }
}

System.currentTimeMillis() 占用高的原因

如果在代码中频繁地调用System.currentTimeMillis() 方法,就会导致CPU占用率增加,因为每次调用都需要进行系统调用。如果在循环中频繁地调用该方法,就会导致CPU占用率很高

代码优化

使用递增的方式来减少for循环

public boolean lockBlock(String key, String value, long expireTime, long waitTime) throws InterruptedException {
    long endTime = System.currentTimeMillis() + waitTime;
    long attemptInterval = 20; // 初始尝试间隔

    while (System.currentTimeMillis() < endTime) {
        if (this.lock(key, value, expireTime)) {
            return true;
        }
        Thread.sleep(attemptInterval);
        // 指数后退,但有最大间隔限制
        attemptInterval = Math.min(attemptInterval * 2, 500);
    }
    return false;
}