feat: Docker Compose配置多租户混合模式负载均衡
## 主要改动 ### 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租户请求路由到专属实例
This commit is contained in:
parent
109ae29474
commit
5843cc050e
@ -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:
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -15,9 +15,15 @@ import java.util.Map;
|
||||
* Nacos 服务注册元数据配置
|
||||
*
|
||||
* <p>服务启动时自动注册租户标签到 Nacos,支持租户感知的负载均衡</p>
|
||||
*
|
||||
* <p>支持两种配置方式:</p>
|
||||
* <ul>
|
||||
* <li>环境变量:TENANT_ID, TENANT_GROUP(Docker 环境推荐)</li>
|
||||
* <li>配置文件:spring.cloud.nacos.discovery.metadata.tenant-id/tenant-group</li>
|
||||
* </ul>
|
||||
*/
|
||||
@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<String, String> 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";
|
||||
public String getTenantId() {
|
||||
return tenantId;
|
||||
}
|
||||
return "TENANT_" + tenantId.toUpperCase();
|
||||
|
||||
/**
|
||||
* 获取当前租户组
|
||||
*/
|
||||
public String getTenantGroup() {
|
||||
return tenantGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为 VIP 专属实例
|
||||
*/
|
||||
public boolean isVipInstance() {
|
||||
return tenantGroup != null && !tenantGroup.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user