本文目录导读:

我为您整理了一个完整的Java双活架构案例,包含架构设计、核心代码实现和关键考虑点。
双活架构概述
架构拓扑图
graph TB
subgraph "数据中心A"
LB1[负载均衡器]
APP1[应用集群A]
DB1[(数据库A)]
MQ1[消息队列A]
CACHE1[(缓存A)]
end
subgraph "数据中心B"
LB2[负载均衡器]
APP2[应用集群B]
DB2[(数据库B)]
MQ2[消息队列B]
CACHE2[(缓存B)]
end
GSLB[全局负载均衡] --> LB1
GSLB --> LB2
APP1 <--> |同步| APP2
DB1 <--> |双向同步| DB2
MQ1 <--> |消息复制| MQ2
CACHE1 <--> |缓存同步| CACHE2
核心架构代码实现
多数据中心配置管理
@Component
public class DataCenterConfig {
@Value("${data.center.id:DC1}")
private String currentDataCenter;
@Value("${data.center.peer:DC2}")
private String peerDataCenter;
@Value("${data.center.routing.strategy:priority}")
private String routingStrategy;
public boolean isPrimary() {
return "DC1".equals(currentDataCenter);
}
public String getCurrentDataCenter() {
return currentDataCenter;
}
}
读写分离与路由实现
public class DataSourceRouter extends AbstractRoutingDataSource {
@Resource
private DataCenterConfig dataCenterConfig;
@Override
protected Object determineCurrentLookupKey() {
// 根据请求类型和当前数据中心状态决定路由
String requestType = RequestContextHolder.getRequestType();
boolean isWrite = "WRITE".equals(requestType);
if (isWrite) {
// 写操作路由到主数据中心
return dataCenterConfig.getCurrentDataCenter() + "_MASTER";
} else {
// 读操作可以在本数据中心完成
return dataCenterConfig.getCurrentDataCenter() + "_SLAVE";
}
}
}
分布式ID生成器(跨数据中心)
@Component
public class DistributedIdGenerator {
@Resource
private DataCenterConfig dataCenterConfig;
private static final long SEQUENCE_BITS = 12;
private static final long MACHINE_BITS = 5;
private static final long DATA_CENTER_BITS = 5;
public synchronized long nextId() {
// 数据中心ID(保证跨数据中心唯一)
long dataCenterId = dataCenterConfig.getDataCenterId();
// 机器ID(本数据中心内唯一)
long machineId = getMachineId();
// 序列号
long sequence = getNextSequence();
// 组合成分布式ID
return (dataCenterId << (MACHINE_BITS + SEQUENCE_BITS))
| (machineId << SEQUENCE_BITS)
| sequence;
}
}
数据同步实现
@Component
public class DataSyncService {
@Resource
private JdbcTemplate jdbcTemplate;
@Resource
private KafkaTemplate<String, String> kafkaTemplate;
/**
* 跨数据中心数据同步
*/
public void syncDataToPeerCenter(String tableName, Object data) {
// 构建同步消息
SyncMessage syncMessage = SyncMessage.builder()
.tableName(tableName)
.data(data)
.sourceCenter(dataCenterConfig.getCurrentDataCenter())
.timestamp(System.currentTimeMillis())
.build();
// 发送到对等数据中心
String topic = "data-sync-" + dataCenterConfig.getPeerDataCenter();
kafkaTemplate.send(topic, JSON.toJSONString(syncMessage));
}
@KafkaListener(topics = "data-sync-#{@dataCenterConfig.currentDataCenter}")
public void handleSyncData(String message) {
SyncMessage syncMessage = JSON.parseObject(message, SyncMessage.class);
// 使用分布式锁防止并发问题
String lockKey = "sync:" + syncMessage.getTableName() + ":" + syncMessage.getId();
RLock lock = redissonClient.getLock(lockKey);
try {
if (lock.tryLock(10, TimeUnit.SECONDS)) {
// 执行数据同步
jdbcTemplate.update(
"INSERT INTO " + syncMessage.getTableName() +
" (id, data, sync_time) VALUES (?, ?, ?) " +
"ON DUPLICATE KEY UPDATE data = VALUES(data), sync_time = VALUES(sync_time)",
syncMessage.getId(),
JSON.toJSONString(syncMessage.getData()),
new Date(syncMessage.getTimestamp())
);
// 发布本地消息
publishLocalEvent(syncMessage);
}
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
}
分布式锁服务
@Component
public class DistributedLockService {
@Resource
private RedissonClient redissonClient;
/**
* 跨数据中心分布式锁
*/
public boolean tryLock(String lockKey, long timeout, TimeUnit unit) {
RLock lock = redissonClient.getLock(lockKey);
try {
return lock.tryLock(timeout, unit);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return false;
}
}
/**
* 幂等性检查
*/
public boolean checkIdempotent(String idempotentKey) {
String key = "idempotent:" + idempotentKey;
return redissonClient.getBucket(key).trySet("1", 24, TimeUnit.HOURS);
}
}
健康检查与故障转移
@Component
public class HealthCheckService {
@Resource
private DataCenterConfig dataCenterConfig;
@Resource
private ApplicationContext applicationContext;
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
@PostConstruct
public void startHealthCheck() {
// 每5秒检查一次健康状态
scheduler.scheduleAtFixedRate(this::checkHealth, 0, 5, TimeUnit.SECONDS);
}
public void checkHealth() {
boolean isHealth = true;
// 检查数据库连接
if (!checkDatabaseHealth()) {
isHealth = false;
}
// 检查缓存服务
if (!checkCacheHealth()) {
isHealth = false;
}
// 检查消息队列
if (!checkMQHealth()) {
isHealth = false;
}
if (!isHealth) {
handleFailover();
}
}
private void handleFailover() {
// 更新路由策略
dataCenterConfig.setRoutingStrategy("HOT_STANDBY");
// 启动本数据中心的完整服务
applicationContext.publishEvent(new FailoverEvent(this, dataCenterConfig.getCurrentDataCenter()));
}
}
双活应用入口配置
@Configuration
public class DualActiveConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.slave")
public DataSource slaveDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public DataSource dataSource() {
Map<Object, Object> targetDataSources = new HashMap<>();
// 注册数据中心A和数据中心B的数据源
targetDataSources.put("DC1_MASTER", masterDataSource());
targetDataSources.put("DC1_SLAVE", slaveDataSource());
targetDataSources.put("DC2_MASTER", peerMasterDataSource());
targetDataSources.put("DC2_SLAVE", peerSlaveDataSource());
DataSourceRouter router = new DataSourceRouter();
router.setTargetDataSources(targetDataSources);
router.setDefaultTargetDataSource(masterDataSource());
return router;
}
}
事务管理(分布式事务)
@Component
public class DistributedTransactionService {
@Resource
private TransactionTemplate transactionTemplate;
@Resource
private KafkaTemplate<String, String> kafkaTemplate;
/**
* 分布式事务处理
*/
public void handleTransaction(TransactionRequest request) {
String transactionId = UUID.randomUUID().toString();
// 1. 准备阶段 - 记录事务日志
saveTransactionLog(transactionId, request, "PREPARED");
// 2. 执行本地事务
try {
transactionTemplate.execute(status -> {
// 业务操作
processBusinessLogic(request);
// 记录事务状态
updateTransactionStatus(transactionId, "COMMIT");
return true;
});
// 3. 发送同步消息到对等数据中心
sendTransactionSyncMessage(transactionId, request);
} catch (Exception e) {
// 4. 失败回滚
updateTransactionStatus(transactionId, "ROLLBACK");
handleTransactionFailure(transactionId, e);
}
}
/**
* 接收对等数据中心的同步请求
*/
@KafkaListener(topics = "transaction-sync")
public void handleTransactionSync(TransactionSyncMessage message) {
String localTransactionId = generateLocalTransactionId(message);
// 幂等检查
if (checkIdempotent(localTransactionId)) {
// 执行本地事务
transactionTemplate.execute(status -> {
processSyncedBusinessLogic(message);
return true;
});
}
}
}
应用配置示例
# application-dc1.yml
spring:
datasource:
master:
url: jdbc:mysql://dc1-core-mysql:3306/business_db
username: admin
password: ${DB_PASSWORD}
slave:
url: jdbc:mysql://dc1-backup-mysql:3306/business_db
username: admin
password: ${DB_PASSWORD}
kafka:
bootstrap-servers: dc1-kafka:9092
producer:
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
consumer:
group-id: dc1-group
redis:
cluster:
nodes: dc1-redis-1:6379,dc1-redis-2:6379,dc1-redis-3:6379
data:
center:
id: DC1
peer: DC2
routing:
strategy: priority # priority / hot_standby / load_balanced
sync:
mode: async # async / sync
retry:
max-attempts: 3
delay: 1000
# application.yml
spring:
profiles:
active: dc1 # 根据部署环境选择
redis:
redisson:
config: classpath:redisson.yaml
Redis配置
# redisson.yaml
singleServerConfig:
address: "redis://dc1-redis:6379"
connectionMinimumIdleSize: 10
connectionPoolSize: 50
timeout: 3000
retryAttempts: 3
retryInterval: 1500
codec: !<org.redisson.codec.JsonJacksonCodec> {}
关键实现要点
数据一致性保证
- 使用分布式锁确保同一数据在同一时间只在一个数据中心被修改
- 采用最后写入胜出(LWW)或版本向量机制处理冲突
- 实现事务日志和补偿机制
故障转移策略
- 健康检查失败自动切换到备机
- 会话保持和用户重定向
- 数据同步断点续传
性能优化
- 本地读写优先,减少网络开销
- 异步批量数据同步
- 缓存优化和预热
监控与告警
@Component
public class DualActiveMonitor {
@Autowired
private MeterRegistry meterRegistry;
@Scheduled(fixedDelay = 60000)
public void collectMetrics() {
// 记录数据中心状态指标
Gauge.builder("data.center.status",
() -> dataCenterConfig.isPrimary() ? 1 : 0)
.register(meterRegistry);
// 记录同步延迟
Gauge.builder("data.sync.latency",
() -> getSyncLatency())
.register(meterRegistry);
}
}
最佳实践建议
- 分区策略:明确哪些数据需要在数据中心间同步,哪些可以本地分区
- 冲突解决:定义清晰的冲突解决策略,如时间戳优先、版本号优先等
- 可观测性:完善日志、指标和链路追踪,便于问题排查
- 灰度发布:支持流量灰度,逐步切换流量到新数据中心
- 定期演练:定期进行故障转移演练,确保双活机制的有效性
这个双活架构案例提供了完整的实现框架,您可以根据实际业务需求和基础设施进行调整和优化。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播