← 返回首页
🛡️

数据复制架构

📂 architecture ⏱ 2 min 219 words

数据复制架构

主从复制

主从复制是最常见的数据复制模式。一个主节点处理写操作,多个从节点复制数据并处理读操作。

-- MySQL 主从复制配置示例
-- 主节点配置
[mysqld]
server-id = 1
log-bin = mysql-bin
binlog-format = ROW

-- 从节点配置
[mysqld]
server-id = 2
relay-log = relay-bin
read-only = ON

-- 创建复制用户
CREATE USER 'repl'@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
// 主从路由的数据源配置
@Configuration
public class DataSourceConfig {
    
    @Bean
    @Primary
    public DataSource dataSource() {
        ReadWriteSplittingDataSource dataSource = new ReadWriteSplittingDataSource();
        
        // 写数据源(主节点)
        Map<Object, Object> writeDataSources = new HashMap<>();
        writeDataSources.put("write", writeDataSource());
        
        // 读数据源(从节点)
        Map<Object, Object> readDataSources = new HashMap<>();
        readDataSources.put("read1", readDataSource1());
        readDataSources.put("read2", readDataSource2());
        
        dataSource.setWriteDataSourcesMap(writeDataSources);
        dataSource.setReadDataSourcesMap(readDataSources);
        dataSource.setDefaultTargetDataSource(writeDataSource());
        
        return dataSource;
    }
}

多主复制

多主复制允许在多个节点上进行写操作,提高了写入可用性,但需要处理写冲突。

// 冲突检测与解决
@Component
public class ConflictResolver {
    
    // 使用最后写入者胜出策略
    public Record resolve(Record record1, Record record2) {
        if (record1.getTimestamp().after(record2.getTimestamp())) {
            return record1;
        } else if (record2.getTimestamp().after(record1.getTimestamp())) {
            return record2;
        }
        // 时间戳相同时使用节点ID排序
        return record1.getNodeId().compareTo(record2.getNodeId()) < 0 
            ? record1 : record2;
    }
    
    // 使用向量时钟检测因果关系
    public boolean isConcurrent(Record record1, Record record2) {
        VectorClock clock1 = record1.getVectorClock();
        VectorClock clock2 = record2.getVectorClock();
        return !clock1.happensBefore(clock2) && !clock2.happensBefore(clock1);
    }
}

无主复制

无主复制(如 Dynamo 风格)将数据复制到多个节点,客户端负责协调读写操作。使用 Quorum 机制保证一致性:W + R > N。

// Quorum 写入实现
public void write(String key, Value value) {
    List<Node> nodes = getPreferenceNodes(key);
    int successCount = 0;
    
    for (Node node : nodes) {
        try {
            node.write(key, value);
            successCount++;
        } catch (Exception e) {
            log.warn("写入节点失败: {}", node.getId());
        }
    }
    
    if (successCount < writeQuorum) {
        throw new QuorumNotMetException("写入 quorum 未满足");
    }
}

一致性模型选择

不同应用场景需要不同的一致性模型。强一致性适合金融交易等场景,最终一致性适合社交媒体等对延迟敏感的场景。选择时需要权衡一致性、可用性和性能。