diff --git a/docker-compose.yml b/docker-compose.yml index ca64613..5b5eac5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -184,8 +184,7 @@ services: REDIS_HOST: redis REDIS_PORT: 6379 JAVA_OPTS: -Xms256m -Xmx512m - # 租户元数据 - 共享实例(无特定租户组,所有租户可用) - TENANT_ID: "1" + # 租户组 - 共享实例(空值,所有租户可用) TENANT_GROUP: "" ports: - "8100:8100" @@ -228,8 +227,7 @@ services: REDIS_HOST: redis REDIS_PORT: 6379 JAVA_OPTS: -Xms256m -Xmx512m - # 租户元数据 - VIP_001 专属实例 - TENANT_ID: "1001" + # 租户组 - VIP_001 专属实例 TENANT_GROUP: "TENANT_VIP_001" ports: - "8101:8101" @@ -272,8 +270,7 @@ services: # REDIS_HOST: redis # REDIS_PORT: 6379 # JAVA_OPTS: -Xms256m -Xmx512m - # # 租户元数据 - VIP_002 专属实例 - # TENANT_ID: "1002" + # # 租户组 - VIP_002 专属实例 # TENANT_GROUP: "TENANT_VIP_002" # ports: # - "8102:8102" diff --git a/fund-common/src/main/java/com/fundplatform/common/nacos/NacosMetadataConfig.java b/fund-common/src/main/java/com/fundplatform/common/nacos/NacosMetadataConfig.java index 4c0a208..aca6d9f 100644 --- a/fund-common/src/main/java/com/fundplatform/common/nacos/NacosMetadataConfig.java +++ b/fund-common/src/main/java/com/fundplatform/common/nacos/NacosMetadataConfig.java @@ -8,19 +8,27 @@ import org.springframework.cloud.client.serviceregistry.Registration; import org.springframework.context.annotation.Configuration; import jakarta.annotation.PostConstruct; -import java.util.HashMap; import java.util.Map; /** * Nacos 服务注册元数据配置 * - *

服务启动时自动注册租户标签到 Nacos,支持租户感知的负载均衡

+ *

服务启动时自动注册租户组标签到 Nacos,支持租户感知的负载均衡

* - *

支持两种配置方式:

- * + *

租户组配置规则:

+ *
+ * 共享实例: tenant-group 为空(或不配置)→ 所有租户都可使用
+ * VIP实例:  tenant-group = "TENANT_VIP_001" → 仅该租户组可用
+ * 
+ * + *

配置方式:

+ *
+ * # 方式1: 环境变量(Docker/K8s 推荐)
+ * TENANT_GROUP=TENANT_VIP_001
+ * 
+ * # 方式2: 配置文件
+ * spring.cloud.nacos.discovery.metadata.tenant-group=TENANT_VIP_001
+ * 
*/ @Configuration @ConditionalOnProperty(name = "tenant.routing.enabled", havingValue = "true", matchIfMissing = true) @@ -32,73 +40,37 @@ public class NacosMetadataConfig { private String applicationName; /** - * 租户 ID,优先级:环境变量 > 配置文件 > 默认值 - */ - @Value("${TENANT_ID:${spring.cloud.nacos.discovery.metadata.tenant-id:1}}") - private String tenantId; - - /** - * 租户组,优先级:环境变量 > 配置文件 > 自动生成 + * 租户组,优先级:环境变量 > 配置文件 * 为空表示共享实例,供所有租户使用 */ @Value("${TENANT_GROUP:${spring.cloud.nacos.discovery.metadata.tenant-group:}}") private String tenantGroup; - /** - * Nacos Registration Bean,用于动态添加元数据 - */ private final Registration registration; public NacosMetadataConfig(Registration registration) { this.registration = registration; } - /** - * 初始化 Nacos 元数据 - */ @PostConstruct public void init() { - logger.info("[Nacos Metadata] 应用名:{}", applicationName); - logger.info("[Nacos Metadata] 租户 ID: {}, 租户组:{}", tenantId, tenantGroup); - - // 动态添加租户元数据到服务注册信息 if (registration != null && registration.getMetadata() != null) { Map metadata = registration.getMetadata(); - // 添加租户 ID - if (tenantId != null && !tenantId.isEmpty()) { - metadata.put("tenant-id", tenantId); - } - - // 添加租户组(VIP 专属实例才有值,共享实例为空) + // 添加租户组元数据 if (tenantGroup != null && !tenantGroup.isEmpty()) { metadata.put("tenant-group", tenantGroup); - logger.info("[Nacos Metadata] 注册为 VIP 专属实例,租户组:{}", tenantGroup); + logger.info("[Nacos] {} 注册为 VIP 专属实例,租户组:{}", applicationName, tenantGroup); } else { - logger.info("[Nacos Metadata] 注册为共享实例,供所有租户使用"); + logger.info("[Nacos] {} 注册为共享实例,供所有租户使用", applicationName); } - - logger.info("[Nacos Metadata] 服务元数据:{}", metadata); } } - /** - * 获取当前租户 ID - */ - public String getTenantId() { - return tenantId; - } - - /** - * 获取当前租户组 - */ public String getTenantGroup() { return tenantGroup; } - /** - * 判断是否为 VIP 专属实例 - */ public boolean isVipInstance() { return tenantGroup != null && !tenantGroup.isEmpty(); } diff --git a/fund-common/target/classes/com/fundplatform/common/nacos/NacosMetadataConfig.class b/fund-common/target/classes/com/fundplatform/common/nacos/NacosMetadataConfig.class index a9c6cf2..8a993c0 100644 Binary files a/fund-common/target/classes/com/fundplatform/common/nacos/NacosMetadataConfig.class and b/fund-common/target/classes/com/fundplatform/common/nacos/NacosMetadataConfig.class differ diff --git a/fund-sys/src/main/resources/application.yml b/fund-sys/src/main/resources/application.yml index 73ec11a..c38e6e5 100644 --- a/fund-sys/src/main/resources/application.yml +++ b/fund-sys/src/main/resources/application.yml @@ -13,10 +13,10 @@ spring: group: DEFAULT_GROUP username: nacos password: nacos - # 租户元数据(一库一租户模式时配置) + # 租户路由元数据 + # tenant-group: 空值=共享实例,有值=VIP专属实例 metadata: - tenant-id: ${TENANT_ID:1} - tenant-group: TENANT_${TENANT_ID:DEFAULT} + tenant-group: ${TENANT_GROUP:} datasource: driver-class-name: com.mysql.cj.jdbc.Driver diff --git a/fund-sys/target/classes/application.yml b/fund-sys/target/classes/application.yml index 73ec11a..c38e6e5 100644 --- a/fund-sys/target/classes/application.yml +++ b/fund-sys/target/classes/application.yml @@ -13,10 +13,10 @@ spring: group: DEFAULT_GROUP username: nacos password: nacos - # 租户元数据(一库一租户模式时配置) + # 租户路由元数据 + # tenant-group: 空值=共享实例,有值=VIP专属实例 metadata: - tenant-id: ${TENANT_ID:1} - tenant-group: TENANT_${TENANT_ID:DEFAULT} + tenant-group: ${TENANT_GROUP:} datasource: driver-class-name: com.mysql.cj.jdbc.Driver diff --git a/logs/fund-sys-shared-8100.log b/logs/fund-sys-shared-8100.log index 715d6da..56db073 100644 --- a/logs/fund-sys-shared-8100.log +++ b/logs/fund-sys-shared-8100.log @@ -1120,3 +1120,21 @@ java.lang.NullPointerException: Cannot invoke "com.zaxxer.hikari.HikariPoolMXBea at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) at java.base/java.lang.Thread.run(Thread.java:1583) +2026-02-19 21:21:06.988 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - === HikariCP 连接池状态 === +2026-02-19 21:21:06.988 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - 连接池名称: FundSysHikariPool +2026-02-19 21:21:06.989 [scheduling-1] [] ERROR o.s.s.support.TaskUtils$LoggingErrorHandler - Unexpected error occurred in scheduled task +java.lang.NullPointerException: Cannot invoke "com.zaxxer.hikari.HikariPoolMXBean.getActiveConnections()" because the return value of "com.zaxxer.hikari.HikariDataSource.getHikariPoolMXBean()" is null + at com.fundplatform.sys.config.HikariMonitorConfig.monitorHikariPool(HikariMonitorConfig.java:38) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.scheduling.support.ScheduledMethodRunnable.runInternal(ScheduledMethodRunnable.java:130) + at org.springframework.scheduling.support.ScheduledMethodRunnable.lambda$run$2(ScheduledMethodRunnable.java:124) + at io.micrometer.observation.Observation.observe(Observation.java:499) + at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:124) + at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) + at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572) + at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:358) + at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305) + at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) + at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) + at java.base/java.lang.Thread.run(Thread.java:1583) diff --git a/logs/fund-sys-tenant-vip001-8101.log b/logs/fund-sys-tenant-vip001-8101.log index 32c1d24..a21e5d3 100644 --- a/logs/fund-sys-tenant-vip001-8101.log +++ b/logs/fund-sys-tenant-vip001-8101.log @@ -1084,3 +1084,39 @@ java.lang.NullPointerException: Cannot invoke "com.zaxxer.hikari.HikariPoolMXBea at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) at java.base/java.lang.Thread.run(Thread.java:1583) +2026-02-19 21:19:07.541 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - === HikariCP 连接池状态 === +2026-02-19 21:19:07.541 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - 连接池名称: FundSysHikariPool +2026-02-19 21:19:07.541 [scheduling-1] [] ERROR o.s.s.support.TaskUtils$LoggingErrorHandler - Unexpected error occurred in scheduled task +java.lang.NullPointerException: Cannot invoke "com.zaxxer.hikari.HikariPoolMXBean.getActiveConnections()" because the return value of "com.zaxxer.hikari.HikariDataSource.getHikariPoolMXBean()" is null + at com.fundplatform.sys.config.HikariMonitorConfig.monitorHikariPool(HikariMonitorConfig.java:38) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.scheduling.support.ScheduledMethodRunnable.runInternal(ScheduledMethodRunnable.java:130) + at org.springframework.scheduling.support.ScheduledMethodRunnable.lambda$run$2(ScheduledMethodRunnable.java:124) + at io.micrometer.observation.Observation.observe(Observation.java:499) + at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:124) + at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) + at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572) + at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:358) + at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305) + at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) + at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) + at java.base/java.lang.Thread.run(Thread.java:1583) +2026-02-19 21:24:07.541 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - === HikariCP 连接池状态 === +2026-02-19 21:24:07.541 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - 连接池名称: FundSysHikariPool +2026-02-19 21:24:07.541 [scheduling-1] [] ERROR o.s.s.support.TaskUtils$LoggingErrorHandler - Unexpected error occurred in scheduled task +java.lang.NullPointerException: Cannot invoke "com.zaxxer.hikari.HikariPoolMXBean.getActiveConnections()" because the return value of "com.zaxxer.hikari.HikariDataSource.getHikariPoolMXBean()" is null + at com.fundplatform.sys.config.HikariMonitorConfig.monitorHikariPool(HikariMonitorConfig.java:38) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.scheduling.support.ScheduledMethodRunnable.runInternal(ScheduledMethodRunnable.java:130) + at org.springframework.scheduling.support.ScheduledMethodRunnable.lambda$run$2(ScheduledMethodRunnable.java:124) + at io.micrometer.observation.Observation.observe(Observation.java:499) + at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:124) + at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) + at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572) + at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:358) + at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305) + at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) + at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) + at java.base/java.lang.Thread.run(Thread.java:1583) diff --git a/logs/fund-sys/error.log b/logs/fund-sys/error.log index 8e96c1f..97aa294 100644 --- a/logs/fund-sys/error.log +++ b/logs/fund-sys/error.log @@ -1470,3 +1470,51 @@ java.lang.NullPointerException: Cannot invoke "com.zaxxer.hikari.HikariPoolMXBea at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) at java.base/java.lang.Thread.run(Thread.java:1583) +2026-02-19 21:19:07.541 [scheduling-1] [] ERROR o.s.s.support.TaskUtils$LoggingErrorHandler - Unexpected error occurred in scheduled task +java.lang.NullPointerException: Cannot invoke "com.zaxxer.hikari.HikariPoolMXBean.getActiveConnections()" because the return value of "com.zaxxer.hikari.HikariDataSource.getHikariPoolMXBean()" is null + at com.fundplatform.sys.config.HikariMonitorConfig.monitorHikariPool(HikariMonitorConfig.java:38) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.scheduling.support.ScheduledMethodRunnable.runInternal(ScheduledMethodRunnable.java:130) + at org.springframework.scheduling.support.ScheduledMethodRunnable.lambda$run$2(ScheduledMethodRunnable.java:124) + at io.micrometer.observation.Observation.observe(Observation.java:499) + at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:124) + at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) + at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572) + at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:358) + at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305) + at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) + at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) + at java.base/java.lang.Thread.run(Thread.java:1583) +2026-02-19 21:21:06.989 [scheduling-1] [] ERROR o.s.s.support.TaskUtils$LoggingErrorHandler - Unexpected error occurred in scheduled task +java.lang.NullPointerException: Cannot invoke "com.zaxxer.hikari.HikariPoolMXBean.getActiveConnections()" because the return value of "com.zaxxer.hikari.HikariDataSource.getHikariPoolMXBean()" is null + at com.fundplatform.sys.config.HikariMonitorConfig.monitorHikariPool(HikariMonitorConfig.java:38) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.scheduling.support.ScheduledMethodRunnable.runInternal(ScheduledMethodRunnable.java:130) + at org.springframework.scheduling.support.ScheduledMethodRunnable.lambda$run$2(ScheduledMethodRunnable.java:124) + at io.micrometer.observation.Observation.observe(Observation.java:499) + at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:124) + at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) + at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572) + at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:358) + at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305) + at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) + at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) + at java.base/java.lang.Thread.run(Thread.java:1583) +2026-02-19 21:24:07.541 [scheduling-1] [] ERROR o.s.s.support.TaskUtils$LoggingErrorHandler - Unexpected error occurred in scheduled task +java.lang.NullPointerException: Cannot invoke "com.zaxxer.hikari.HikariPoolMXBean.getActiveConnections()" because the return value of "com.zaxxer.hikari.HikariDataSource.getHikariPoolMXBean()" is null + at com.fundplatform.sys.config.HikariMonitorConfig.monitorHikariPool(HikariMonitorConfig.java:38) + at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + at java.base/java.lang.reflect.Method.invoke(Method.java:580) + at org.springframework.scheduling.support.ScheduledMethodRunnable.runInternal(ScheduledMethodRunnable.java:130) + at org.springframework.scheduling.support.ScheduledMethodRunnable.lambda$run$2(ScheduledMethodRunnable.java:124) + at io.micrometer.observation.Observation.observe(Observation.java:499) + at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:124) + at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) + at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572) + at java.base/java.util.concurrent.FutureTask.runAndReset(FutureTask.java:358) + at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305) + at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) + at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) + at java.base/java.lang.Thread.run(Thread.java:1583) diff --git a/logs/fund-sys/info.log b/logs/fund-sys/info.log index 369e7d4..4362c22 100644 --- a/logs/fund-sys/info.log +++ b/logs/fund-sys/info.log @@ -328,3 +328,9 @@ 2026-02-19 21:14:07.550 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - 连接池名称: FundSysHikariPool 2026-02-19 21:16:06.988 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - === HikariCP 连接池状态 === 2026-02-19 21:16:06.991 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - 连接池名称: FundSysHikariPool +2026-02-19 21:19:07.541 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - === HikariCP 连接池状态 === +2026-02-19 21:19:07.541 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - 连接池名称: FundSysHikariPool +2026-02-19 21:21:06.988 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - === HikariCP 连接池状态 === +2026-02-19 21:21:06.988 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - 连接池名称: FundSysHikariPool +2026-02-19 21:24:07.541 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - === HikariCP 连接池状态 === +2026-02-19 21:24:07.541 [scheduling-1] [] INFO com.fundplatform.sys.config.HikariMonitorConfig - 连接池名称: FundSysHikariPool