双活与多活架构
双活与多活架构
同城双活架构
同城双活是在同一城市部署两个数据中心,通过低延迟专线(通常 < 2ms)连接。两个数据中心同时对外提供服务,数据通过同步复制保持一致。
┌─────────────────────────────────────────┐
│ 全局负载均衡 (GSLB) │
└─────────────┬───────────┬───────────────┘
│ │
┌─────────────▼──┐ ┌────▼─────────────┐
│ 数据中心 A │ │ 数据中心 B │
│ (主写) │ │ (主读/从写) │
│ ┌─────────┐ │ │ ┌─────────┐ │
│ │ 应用层 │◄─┼───┼─►│ 应用层 │ │
│ └─────────┘ │ │ └─────────┘ │
│ ┌─────────┐ │ │ ┌─────────┐ │
│ │ 数据库 │◄─┼───┼─►│ 数据库 │ │
│ └─────────┘ │ │ └─────────┘ │
└────────────────┴───┴───────────────────┘
同步复制 (专线 < 2ms)
同城双活的关键挑战是数据一致性。常用方案包括:
- 双写模式:请求同时写入两个数据中心,需要分布式事务保证一致性
- 主从模式:一个数据中心主写,另一个从写,通过数据库复制同步
- 分区模式:按用户或业务将流量分配到不同数据中心
异地多活架构
异地多活在不同地理区域部署独立数据中心,每个区域可独立处理请求。由于网络延迟较高(通常 > 50ms),通常采用异步复制。
// 异地多活流量路由策略
@Component
public class GeoRoutingService {
private final Map<String, RegionConfig> regions = new HashMap<>();
public String routeRequest(HttpServletRequest request) {
String userRegion = detectUserRegion(request);
String preferredRegion = regions.get(userRegion).getPrimaryRegion();
// 检查首选区域健康状态
if (isRegionHealthy(preferredRegion)) {
return preferredRegion;
}
// 故障时路由到其他健康区域
return regions.values().stream()
.map(RegionConfig::getName)
.filter(this::isRegionHealthy)
.filter(r -> !r.equals(preferredRegion))
.findFirst()
.orElseThrow(() -> new ServiceUnavailableException("所有区域不可用"));
}
private String detectUserRegion(HttpServletRequest request) {
String ip = request.getRemoteAddr();
// 基于 IP 地理位置判断用户区域
return geoIpService.getRegion(ip);
}
}
数据同步策略
多活架构的核心难题是跨区域数据同步。常见策略包括:
- 最终一致性:允许短暂数据不一致,通过消息队列异步同步
- 冲突解决:使用时间戳或向量时钟解决写冲突
- 读写分离:读操作就近访问,写操作路由到主区域
多活架构适合对可用性要求极高的场景,但会显著增加系统复杂度和运维成本。需要根据业务特点权衡选择。