From 5843cc050e1a2176d8f8f8c6f4d48f2cedc009e1 Mon Sep 17 00:00:00 2001 From: zhangjf Date: Thu, 19 Feb 2026 20:04:21 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20Docker=20Compose=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=A4=9A=E7=A7=9F=E6=88=B7=E6=B7=B7=E5=90=88=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E8=B4=9F=E8=BD=BD=E5=9D=87=E8=A1=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 主要改动 ### docker-compose.yml - fund-sys 服务改为混合模式部署: - fund-sys-shared: 共享实例(8100端口),供所有租户使用 - fund-sys-vip001: VIP_001专属实例(8101端口) - 预留VIP_002模板(注释状态) - 添加TENANT_ID、TENANT_GROUP环境变量 ### NacosMetadataConfig - 支持从环境变量读取租户元数据(优先级最高) - 动态注册租户标签到Nacos - 区分共享实例和VIP专属实例 ### Prometheus配置 - 监控共享实例和VIP实例 - 添加tenant_mode、tenant_group标签 ## 混合模式说明 - 共享实例(TENANT_GROUP为空): 所有普通租户请求路由到此类实例 - VIP实例(TENANT_GROUP有值): VIP租户请求路由到专属实例 --- docker-compose.yml | 100 +++++++++++++++++- docker/prometheus/prometheus.yml | 17 ++- .../common/nacos/NacosMetadataConfig.java | 85 ++++++++++----- 3 files changed, 170 insertions(+), 32 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index fdc3531..ca64613 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,6 @@ # 资金服务平台 - Docker Compose 编排配置 -# 版本: 1.0 +# 版本: 1.1 +# 支持多租户混合模式:VIP专属实例 + 普通租户共享实例 version: '3.8' @@ -158,14 +159,16 @@ services: networks: - fund-network - # 系统服务 + # ==================== 系统服务(多租户混合模式) ==================== + + # 系统服务 - 共享实例(供所有租户使用) fund-sys: build: context: . dockerfile: Dockerfile args: MODULE: fund-sys - container_name: fund-sys + container_name: fund-sys-shared restart: unless-stopped environment: SERVER_PORT: 8100 @@ -181,6 +184,9 @@ services: REDIS_HOST: redis REDIS_PORT: 6379 JAVA_OPTS: -Xms256m -Xmx512m + # 租户元数据 - 共享实例(无特定租户组,所有租户可用) + TENANT_ID: "1" + TENANT_GROUP: "" ports: - "8100:8100" depends_on: @@ -199,6 +205,94 @@ services: networks: - fund-network + # 系统服务 - VIP_001 专属实例 + fund-sys-vip001: + build: + context: . + dockerfile: Dockerfile + args: + MODULE: fund-sys + container_name: fund-sys-vip001 + restart: unless-stopped + environment: + SERVER_PORT: 8101 + SPRING_PROFILES_ACTIVE: docker + NACOS_SERVER_ADDR: nacos:8848 + NACOS_USERNAME: nacos + NACOS_PASSWORD: nacos + MYSQL_HOST: mysql + MYSQL_PORT: 3306 + MYSQL_DB: fund_platform + MYSQL_USER: root + MYSQL_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root123} + REDIS_HOST: redis + REDIS_PORT: 6379 + JAVA_OPTS: -Xms256m -Xmx512m + # 租户元数据 - VIP_001 专属实例 + TENANT_ID: "1001" + TENANT_GROUP: "TENANT_VIP_001" + ports: + - "8101:8101" + depends_on: + nacos: + condition: service_healthy + mysql: + condition: service_healthy + redis: + condition: service_healthy + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8101/actuator/health"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 120s + networks: + - fund-network + + # 系统服务 - VIP_002 专属实例(可选,按需启用) + # fund-sys-vip002: + # build: + # context: . + # dockerfile: Dockerfile + # args: + # MODULE: fund-sys + # container_name: fund-sys-vip002 + # restart: unless-stopped + # environment: + # SERVER_PORT: 8102 + # SPRING_PROFILES_ACTIVE: docker + # NACOS_SERVER_ADDR: nacos:8848 + # NACOS_USERNAME: nacos + # NACOS_PASSWORD: nacos + # MYSQL_HOST: mysql + # MYSQL_PORT: 3306 + # MYSQL_DB: fund_platform + # MYSQL_USER: root + # MYSQL_PASSWORD: ${MYSQL_ROOT_PASSWORD:-root123} + # REDIS_HOST: redis + # REDIS_PORT: 6379 + # JAVA_OPTS: -Xms256m -Xmx512m + # # 租户元数据 - VIP_002 专属实例 + # TENANT_ID: "1002" + # TENANT_GROUP: "TENANT_VIP_002" + # ports: + # - "8102:8102" + # depends_on: + # nacos: + # condition: service_healthy + # mysql: + # condition: service_healthy + # redis: + # condition: service_healthy + # healthcheck: + # test: ["CMD", "curl", "-f", "http://localhost:8102/actuator/health"] + # interval: 30s + # timeout: 10s + # retries: 5 + # start_period: 120s + # networks: + # - fund-network + # 客户服务 fund-cust: build: diff --git a/docker/prometheus/prometheus.yml b/docker/prometheus/prometheus.yml index 13b897d..b5a58da 100644 --- a/docker/prometheus/prometheus.yml +++ b/docker/prometheus/prometheus.yml @@ -54,18 +54,25 @@ scrape_configs: target_label: instance replacement: 'fund-gateway' - # 系统服务 + # 系统服务 - 多租户混合模式监控 - job_name: 'fund-sys' metrics_path: '/actuator/prometheus' static_configs: + # 共享实例 - targets: ['fund-sys:8100'] labels: application: 'fund-sys' service: 'business' - relabel_configs: - - source_labels: [__address__] - target_label: instance - replacement: 'fund-sys' + tenant_mode: 'shared' + instance: 'fund-sys-shared' + # VIP_001 专属实例 + - targets: ['fund-sys-vip001:8101'] + labels: + application: 'fund-sys' + service: 'business' + tenant_mode: 'vip' + tenant_group: 'TENANT_VIP_001' + instance: 'fund-sys-vip001' # 客户服务 - job_name: 'fund-cust' 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 d4cc5a2..4c0a208 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 @@ -15,9 +15,15 @@ import java.util.Map; * Nacos 服务注册元数据配置 * *

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

+ * + *

支持两种配置方式:

+ * */ @Configuration -@ConditionalOnProperty(name = "tenant.routing.enabled", havingValue = "true") +@ConditionalOnProperty(name = "tenant.routing.enabled", havingValue = "true", matchIfMissing = true) public class NacosMetadataConfig { private static final Logger logger = LoggerFactory.getLogger(NacosMetadataConfig.class); @@ -25,14 +31,27 @@ public class NacosMetadataConfig { @Value("${spring.application.name:unknown}") private String applicationName; - @Value("${spring.cloud.nacos.discovery.metadata.tenant-id:}") + /** + * 租户 ID,优先级:环境变量 > 配置文件 > 默认值 + */ + @Value("${TENANT_ID:${spring.cloud.nacos.discovery.metadata.tenant-id:1}}") private String tenantId; - @Value("${spring.cloud.nacos.discovery.metadata.tenant-group:}") + /** + * 租户组,优先级:环境变量 > 配置文件 > 自动生成 + * 为空表示共享实例,供所有租户使用 + */ + @Value("${TENANT_GROUP:${spring.cloud.nacos.discovery.metadata.tenant-group:}}") private String tenantGroup; - @Value("${tenant.routing.default-tenant-id:1}") - private String defaultTenantId; + /** + * Nacos Registration Bean,用于动态添加元数据 + */ + private final Registration registration; + + public NacosMetadataConfig(Registration registration) { + this.registration = registration; + } /** * 初始化 Nacos 元数据 @@ -40,29 +59,47 @@ public class NacosMetadataConfig { @PostConstruct public void init() { logger.info("[Nacos Metadata] 应用名:{}", applicationName); - - // 如果未配置租户 ID,使用默认值 - if (tenantId == null || tenantId.isEmpty()) { - tenantId = defaultTenantId; - logger.info("[Nacos Metadata] 未配置租户 ID,使用默认值:{}", tenantId); - } - - // 如果未配置租户组,自动生成 - if (tenantGroup == null || tenantGroup.isEmpty()) { - tenantGroup = buildTenantGroup(tenantId); - logger.info("[Nacos Metadata] 自动生成租户组:{}", tenantGroup); - } - 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); + } else { + logger.info("[Nacos Metadata] 注册为共享实例,供所有租户使用"); + } + + logger.info("[Nacos Metadata] 服务元数据:{}", metadata); + } } /** - * 构建租户组名称 + * 获取当前租户 ID */ - private String buildTenantGroup(String tenantId) { - if (tenantId == null || tenantId.isEmpty()) { - return "DEFAULT"; - } - return "TENANT_" + tenantId.toUpperCase(); + public String getTenantId() { + return tenantId; + } + + /** + * 获取当前租户组 + */ + public String getTenantGroup() { + return tenantGroup; + } + + /** + * 判断是否为 VIP 专属实例 + */ + public boolean isVipInstance() { + return tenantGroup != null && !tenantGroup.isEmpty(); } }