refactor(系统设置): UID生成器优化

This commit is contained in:
fit2-zhao 2024-02-04 13:30:40 +08:00 committed by Craftsman
parent 5e1b480510
commit 1b3712492c
4 changed files with 16 additions and 151 deletions

View File

@ -9,6 +9,7 @@ import io.metersphere.sdk.util.CommonBeanFactory;
import io.metersphere.sdk.util.LogUtils; import io.metersphere.sdk.util.LogUtils;
import io.metersphere.system.service.BaseScheduleService; import io.metersphere.system.service.BaseScheduleService;
import io.metersphere.system.service.PluginLoadService; import io.metersphere.system.service.PluginLoadService;
import io.metersphere.system.uid.impl.DefaultUidGenerator;
import io.minio.MinioClient; import io.minio.MinioClient;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationArguments;
@ -26,9 +27,13 @@ public class AppStartListener implements ApplicationRunner {
@Resource @Resource
private BaseScheduleService baseScheduleService; private BaseScheduleService baseScheduleService;
@Resource
private DefaultUidGenerator defaultUidGenerator;
@Override @Override
public void run(ApplicationArguments args) throws Exception { public void run(ApplicationArguments args) throws Exception {
LogUtils.info("================= 应用启动 ================="); LogUtils.info("================= 应用启动 =================");
defaultUidGenerator.afterPropertiesSet();
// 初始化MinIO配置 // 初始化MinIO配置
((MinioRepository) FileCenter.getRepository(StorageType.MINIO)).init(minioClient); ((MinioRepository) FileCenter.getRepository(StorageType.MINIO)).init(minioClient);

View File

@ -1,13 +1,13 @@
package io.metersphere.system.uid; package io.metersphere.system.uid;
import io.metersphere.system.uid.impl.CachedUidGenerator;
import io.metersphere.sdk.util.CommonBeanFactory; import io.metersphere.sdk.util.CommonBeanFactory;
import io.metersphere.system.uid.impl.DefaultUidGenerator;
public class IDGenerator { public class IDGenerator {
private static final CachedUidGenerator DEFAULT_UID_GENERATOR; private static final DefaultUidGenerator DEFAULT_UID_GENERATOR;
static { static {
DEFAULT_UID_GENERATOR = CommonBeanFactory.getBean(CachedUidGenerator.class); DEFAULT_UID_GENERATOR = CommonBeanFactory.getBean(DefaultUidGenerator.class);
} }
/** /**

View File

@ -1,147 +0,0 @@
package io.metersphere.system.uid.impl;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.system.uid.BitsAllocator;
import io.metersphere.system.uid.buffer.BufferPaddingExecutor;
import io.metersphere.system.uid.buffer.RejectedPutBufferHandler;
import io.metersphere.system.uid.buffer.RejectedTakeBufferHandler;
import io.metersphere.system.uid.buffer.RingBuffer;
import io.metersphere.sdk.util.LogUtils;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import java.util.ArrayList;
import java.util.List;
/**
* from {@link DefaultUidGenerator}, based on a lock free {@link RingBuffer}<p>
*/
@Service
public class CachedUidGenerator extends DefaultUidGenerator implements DisposableBean, InitializingBean {
private static final int DEFAULT_BOOST_POWER = 3;
/**
* Spring properties
*/
private int boostPower = DEFAULT_BOOST_POWER;
private Long scheduleInterval;
private RejectedPutBufferHandler rejectedPutBufferHandler;
private RejectedTakeBufferHandler rejectedTakeBufferHandler;
/**
* RingBuffer
*/
private RingBuffer ringBuffer;
private BufferPaddingExecutor bufferPaddingExecutor;
@Override
public void afterPropertiesSet() {
// initialize workerId & bitsAllocator
super.afterPropertiesSet();
// initialize RingBuffer & RingBufferPaddingExecutor
this.initRingBuffer();
LogUtils.info("Initialized RingBuffer successfully.");
}
@Override
public long getUID() {
try {
return ringBuffer.take();
} catch (Exception e) {
LogUtils.error("Generate unique id exception. ", e);
throw new MSException(e);
}
}
@Override
public String parseUID(long uid) {
return super.parseUID(uid);
}
@Override
public void destroy() throws Exception {
bufferPaddingExecutor.shutdown();
}
/**
* Get the UIDs in the same specified second under the max sequence
* * @return UID list, size of {@link BitsAllocator#getMaxSequence()} + 1
*/
protected List<Long> nextIdsForOneSecond(long currentSecond) {
// Initialize result list size of (max sequence + 1)
int listSize = (int) bitsAllocator.getMaxSequence() + 1;
List<Long> uidList = new ArrayList<>(listSize);
// Allocate the first sequence of the second, the others can be calculated with the offset
long firstSeqUid = bitsAllocator.allocate(currentSecond - epochSeconds, workerId, 0L);
for (int offset = 0; offset < listSize; offset++) {
uidList.add(firstSeqUid + offset);
}
return uidList;
}
/**
* Initialize RingBuffer & RingBufferPaddingExecutor
*/
private void initRingBuffer() {
// initialize RingBuffer
int bufferSize = ((int) bitsAllocator.getMaxSequence() + 1) << boostPower;
int paddingFactor = RingBuffer.DEFAULT_PADDING_PERCENT;
this.ringBuffer = new RingBuffer(bufferSize, paddingFactor);
LogUtils.info("Initialized ring buffer size:{}, paddingFactor:{}", bufferSize, paddingFactor);
// initialize RingBufferPaddingExecutor
boolean usingSchedule = (scheduleInterval != null);
this.bufferPaddingExecutor = new BufferPaddingExecutor(ringBuffer, this::nextIdsForOneSecond, usingSchedule);
if (usingSchedule) {
bufferPaddingExecutor.setScheduleInterval(scheduleInterval);
}
LogUtils.info("Initialized BufferPaddingExecutor. Using schdule:{}, interval:{}", usingSchedule, scheduleInterval);
// set rejected put/take handle policy
this.ringBuffer.setBufferPaddingExecutor(bufferPaddingExecutor);
if (rejectedPutBufferHandler != null) {
this.ringBuffer.setRejectedPutHandler(rejectedPutBufferHandler);
}
if (rejectedTakeBufferHandler != null) {
this.ringBuffer.setRejectedTakeHandler(rejectedTakeBufferHandler);
}
// fill in all slots of the RingBuffer
bufferPaddingExecutor.paddingBuffer();
// start buffer padding threads
bufferPaddingExecutor.start();
}
/**
* Setters for spring property
*/
public void setBoostPower(int boostPower) {
Assert.isTrue(boostPower > 0, "Boost power must be positive!");
this.boostPower = boostPower;
}
public void setRejectedPutBufferHandler(RejectedPutBufferHandler rejectedPutBufferHandler) {
Assert.notNull(rejectedPutBufferHandler, "RejectedPutBufferHandler can't be null!");
this.rejectedPutBufferHandler = rejectedPutBufferHandler;
}
public void setRejectedTakeBufferHandler(RejectedTakeBufferHandler rejectedTakeBufferHandler) {
Assert.notNull(rejectedTakeBufferHandler, "RejectedTakeBufferHandler can't be null!");
this.rejectedTakeBufferHandler = rejectedTakeBufferHandler;
}
public void setScheduleInterval(long scheduleInterval) {
Assert.isTrue(scheduleInterval > 0, "Schedule interval must positive!");
this.scheduleInterval = scheduleInterval;
}
}

View File

@ -8,13 +8,15 @@ import io.metersphere.system.uid.worker.WorkerIdAssigner;
import io.metersphere.sdk.util.LogUtils; import io.metersphere.sdk.util.LogUtils;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Date; import java.util.Date;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@Service @Service
public class DefaultUidGenerator { public class DefaultUidGenerator implements DisposableBean, InitializingBean {
/** /**
* Bits allocate * Bits allocate
*/ */
@ -176,4 +178,9 @@ public class DefaultUidGenerator {
this.epochSeconds = TimeUnit.MILLISECONDS.toSeconds(TimeUtils.parseByDayPattern(epochStr).getTime()); this.epochSeconds = TimeUnit.MILLISECONDS.toSeconds(TimeUtils.parseByDayPattern(epochStr).getTime());
} }
} }
@Override
public void destroy() throws Exception {
LogUtils.info("Shutdown UidGenerator...");
}
} }