task-80: 补充 JVM 堆、直接内存、临时磁盘和连接池容量配置说明
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
package com.nanri.aiimage.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "aiimage.capacity-plan")
|
||||
public class CapacityPlanProperties {
|
||||
|
||||
/** JVM 堆上限(-Xmx),0 表示交由启动参数决定。 */
|
||||
private long heapMaxBytes = 6L * 1024 * 1024 * 1024;
|
||||
|
||||
/** JVM 直接内存上限(-XX:MaxDirectMemorySize),0 表示交由启动参数决定。 */
|
||||
private long directMaxBytes = 1L * 1024 * 1024 * 1024;
|
||||
|
||||
/** 临时磁盘(./data/tmp)为一次大任务预留的字节上限,0 会触发警告。 */
|
||||
private long tempDiskReserveBytes = 4L * 1024 * 1024 * 1024;
|
||||
|
||||
/** 数据库连接池(Hikari maximum-pool-size)。 */
|
||||
private int dbPoolMaxSize = 30;
|
||||
|
||||
/** 外部 HTTP 客户端(Coze/品牌/紫鸟)连接池容量。 */
|
||||
private int httpClientPoolMaxSize = 32;
|
||||
|
||||
/** RustFS/MinIO OkHttp 连接池容量。 */
|
||||
private int rustfsPoolMaxSize = 56;
|
||||
|
||||
/** 三个连接池之和的上限:超过视为配置异常,启动时警告。 */
|
||||
private int poolTotalMax = 150;
|
||||
|
||||
/** 堆上限占机器物理内存的最大比例(超过触发警告)。 */
|
||||
private double heapRatioWarn = 0.70;
|
||||
|
||||
/** 直接内存上限占机器物理内存的最大比例(超过触发警告)。 */
|
||||
private double directRatioWarn = 0.15;
|
||||
|
||||
/** 临时磁盘预留占机器物理内存的最大比例(超过触发警告)。 */
|
||||
private double tempDiskRatioWarn = 0.50;
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package com.nanri.aiimage.config;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Task 80:JVM 堆、直接内存、临时磁盘和连接池容量配置说明。把所有容量边界
|
||||
* 收敛为一个可校验、可记录的 CapacityPlan:启动时打印摘要,配置越限时输出
|
||||
* 明确警告(不吞配置、不改默认行为),方便按机器内存调整 -Xmx/-XX:
|
||||
* MaxDirectMemorySize 与三个连接池。
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CapacityPlanService implements CommandLineRunner {
|
||||
|
||||
private final CapacityPlanProperties properties;
|
||||
private final long machineMaxMemoryBytes;
|
||||
|
||||
/** 供测试注入机器内存字节数;生产构造时取 Runtime.maxMemory()。 */
|
||||
public CapacityPlanService(CapacityPlanProperties properties) {
|
||||
this(properties, maxMemoryBytes());
|
||||
}
|
||||
|
||||
CapacityPlanService(CapacityPlanProperties properties, long machineMaxMemoryBytes) {
|
||||
this.properties = properties;
|
||||
this.machineMaxMemoryBytes = machineMaxMemoryBytes;
|
||||
}
|
||||
|
||||
private static long maxMemoryBytes() {
|
||||
try {
|
||||
return Runtime.getRuntime().maxMemory();
|
||||
} catch (Exception ex) {
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
public CapacityPlan buildPlan() {
|
||||
if (properties.getDbPoolMaxSize() < 0 || properties.getHttpClientPoolMaxSize() < 0
|
||||
|| properties.getRustfsPoolMaxSize() < 0 || properties.getPoolTotalMax() < 0) {
|
||||
throw new IllegalArgumentException("连接池容量不能为负值: db=" + properties.getDbPoolMaxSize()
|
||||
+ " http=" + properties.getHttpClientPoolMaxSize()
|
||||
+ " rustfs=" + properties.getRustfsPoolMaxSize());
|
||||
}
|
||||
List<String> warnings = new ArrayList<>();
|
||||
if (machineMaxMemoryBytes > 0) {
|
||||
warnRatio(warnings, "堆", properties.getHeapMaxBytes(), properties.getHeapRatioWarn());
|
||||
warnRatio(warnings, "直接内存", properties.getDirectMaxBytes(), properties.getDirectRatioWarn());
|
||||
warnRatio(warnings, "临时磁盘预留", properties.getTempDiskReserveBytes(), properties.getTempDiskRatioWarn());
|
||||
} else {
|
||||
warnings.add("无法取得机器内存,容量比例校验跳过");
|
||||
}
|
||||
if (properties.getTempDiskReserveBytes() <= 0) {
|
||||
warnings.add("临时磁盘预留为 0,大任务可能无界写盘");
|
||||
}
|
||||
int poolTotal = properties.getDbPoolMaxSize()
|
||||
+ properties.getHttpClientPoolMaxSize()
|
||||
+ properties.getRustfsPoolMaxSize();
|
||||
if (poolTotal > properties.getPoolTotalMax()) {
|
||||
warnings.add("连接池总和 " + poolTotal + " 超过上限 " + properties.getPoolTotalMax());
|
||||
}
|
||||
return new CapacityPlan(properties.getHeapMaxBytes(), properties.getDirectMaxBytes(),
|
||||
properties.getTempDiskReserveBytes(), properties.getDbPoolMaxSize(),
|
||||
properties.getHttpClientPoolMaxSize(), properties.getRustfsPoolMaxSize(),
|
||||
poolTotal, machineMaxMemoryBytes, List.copyOf(warnings));
|
||||
}
|
||||
|
||||
private void warnRatio(List<String> warnings, String label, long bytes, double ratioWarn) {
|
||||
if (bytes > 0 && (double) bytes > machineMaxMemoryBytes * ratioWarn) {
|
||||
warnings.add(label + "上限 " + bytes + " 超过机器内存 " + machineMaxMemoryBytes
|
||||
+ " 的 " + (int) (ratioWarn * 100) + "%");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(String... args) {
|
||||
CapacityPlan plan = buildPlan();
|
||||
log.info("[capacity] JVM 堆上限={} 直接内存={} 临时磁盘预留={} 连接池 db={} http={} rustfs={} 总和={} 机器内存={}",
|
||||
plan.heapMaxBytes(), plan.directMaxBytes(), plan.tempDiskReserveBytes(),
|
||||
plan.dbPoolMaxSize(), plan.httpClientPoolMaxSize(), plan.rustfsPoolMaxSize(),
|
||||
plan.poolTotal(), plan.machineMaxMemoryBytes());
|
||||
for (String warning : plan.warnings()) {
|
||||
log.warn("[capacity] {}", warning);
|
||||
}
|
||||
}
|
||||
|
||||
public record CapacityPlan(
|
||||
long heapMaxBytes,
|
||||
long directMaxBytes,
|
||||
long tempDiskReserveBytes,
|
||||
int dbPoolMaxSize,
|
||||
int httpClientPoolMaxSize,
|
||||
int rustfsPoolMaxSize,
|
||||
int poolTotal,
|
||||
long machineMaxMemoryBytes,
|
||||
List<String> warnings
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,6 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties({OssProperties.class, TransientStorageProperties.class, StorageProperties.class, BrandProgressProperties.class, DeleteBrandProgressProperties.class, BrandCheckProperties.class, ZiniaoProperties.class, ModuleCleanupProperties.class, TaskPressureProperties.class, TaskImageCacheCleanupProperties.class, AppearancePatentProperties.class, SimilarAsinProperties.class, ImageVideoProperties.class, InstanceRoutingProperties.class})
|
||||
@EnableConfigurationProperties({OssProperties.class, TransientStorageProperties.class, StorageProperties.class, BrandProgressProperties.class, DeleteBrandProgressProperties.class, BrandCheckProperties.class, ZiniaoProperties.class, ModuleCleanupProperties.class, TaskPressureProperties.class, TaskImageCacheCleanupProperties.class, AppearancePatentProperties.class, SimilarAsinProperties.class, ImageVideoProperties.class, InstanceRoutingProperties.class, CapacityPlanProperties.class})
|
||||
public class PropertiesConfig {
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user