一、Kubernetes配置(MySQL主从集群)
- 主库StatefulSet配置(master-mysql.yaml):
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql-master
spec:
serviceName: "mysql-master"
replicas: 1
selector:
matchLabels:
app: mysql-master
template:
metadata:
labels:
app: mysql-master
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
value: "root123"
- name: MYSQL_DATABASE
value: "app_db"
# 主库配置参数
args:
- "--server-id=1"
- "--log-bin=mysql-bin"
- "--binlog_do_db=app_db"
- "--gtid-mode=ON"
- "--enforce-gtid-consistency=ON"
ports:
- containerPort: 3306
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: mysql-data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "standard"
resources:
requests:
storage: 20Gi
- 从库StatefulSet配置(slave-mysql.yaml):
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql-slave
spec:
serviceName: "mysql-slave"
replicas: 2 # 两个从库实例
selector:
matchLabels:
app: mysql-slave
template:
metadata:
labels:
app: mysql-slave
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
value: "root123"
# 从库配置参数
args:
- "--server-id=$HOSTNAME_SLICE" # 动态生成唯一server-id
- "--relay-log=mysql-relay"
- "--read-only=ON"
- "--gtid-mode=ON"
- "--enforce-gtid-consistency=ON"
- "--skip-slave-start" # 等待手动配置主从复制
ports:
- containerPort: 3306
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: mysql-data
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "standard"
resources:
requests:
storage: 20Gi
二、Java读写分离实现(Spring Boot示例)
- 数据源配置(application.yml):
spring:
datasource:
master:
jdbc-url: jdbc:mysql://mysql-master:3306/app_db
username: root
password: root123
driver-class-name: com.mysql.cj.jdbc.Driver
slaves:
- jdbc-url: jdbc:mysql://mysql-slave-0:3306/app_db
username: root
password: root123
- jdbc-url: jdbc:mysql://mysql-slave-1:3306/app_db
username: root
password: root123
- 动态数据源配置类:
/**
* 动态数据源配置
*/
@Configuration
@EnableTransactionManagement
@MapperScan("com.example.mapper")
public class DynamicDataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public DataSource slaveDataSource() {
// 创建从库数据源列表
List<DataSource> slaves = new ArrayList<>();
// 这里需要根据实际配置动态加载从库数据源
// ...(具体实现根据配置加载多个从库)
// 负载均衡策略(轮询)
return new LoadBalancedDataSource(slaves);
}
@Bean
public DataSource dynamicDataSource(
@Qualifier("masterDataSource") DataSource master,
@Qualifier("slaveDataSource") DataSource slave) {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("master", master);
targetDataSources.put("slave", slave);
dynamicDataSource.setTargetDataSources(targetDataSources);
dynamicDataSource.setDefaultTargetDataSource(master);
return dynamicDataSource;
}
}
- 数据源路由实现:
/**
* 动态数据源路由器
*/
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
@Override
protected Object determineCurrentLookupKey() {
return CONTEXT_HOLDER.get();
}
public static void setDataSource(String dataSource) {
CONTEXT_HOLDER.set(dataSource);
}
public static void clearDataSource() {
CONTEXT_HOLDER.remove();
}
}
- 自定义注解实现读写分离:
/**
* 数据源选择注解
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
DataSourceType value() default DataSourceType.MASTER;
}
public enum DataSourceType {
MASTER, SLAVE
}
- AOP切面实现:
@Aspect
@Component
public class DataSourceAspect {
@Before("@annotation(dataSource)")
public void beforeSwitchDS(JoinPoint point, DataSource dataSource) {
DataSourceType value = dataSource.value();
if (value == DataSourceType.MASTER) {
DynamicDataSource.setDataSource("master");
} else {
DynamicDataSource.setDataSource("slave");
}
}
@Before("execution(* com.example.service..*.save*(..)) || " +
"execution(* com.example.service..*.update*(..)) || " +
"execution(* com.example.service..*.delete*(..))")
public void writeOperations() {
DynamicDataSource.setDataSource("master");
}
@AfterReturning("execution(* com.example.service..*.*(..))")
public void afterReturning() {
DynamicDataSource.clearDataSource();
}
}
三、部署说明
- 集群初始化步骤:
# 部署主库
kubectl apply -f kubernetes/mysql/master-mysql.yaml
# 等待主库启动完成后部署从库
kubectl apply -f kubernetes/mysql/slave-mysql.yaml
# 验证Pod状态
kubectl get pods -l app=mysql-master
kubectl get pods -l app=mysql-slave
- 主从复制配置(在从库Pod中执行):
# 进入从库容器
kubectl exec -it mysql-slave-0 -- bash
# 在MySQL中执行
CHANGE MASTER TO
MASTER_HOST='mysql-master',
MASTER_USER='root',
MASTER_PASSWORD='root123',
MASTER_AUTO_POSITION=1;
START SLAVE;
四、架构特点说明
- 数据一致性保障:
- 使用GTID实现事务一致性
- 半同步复制配置(需在MySQL配置中额外添加)
- 自动故障转移机制(建议配合k8s探针使用)
- 读写分离策略:
- 写操作强制路由主库
- 读操作自动负载均衡
- 事务中强制使用主库
- 扩展性设计:
- 从库数量可动态调整(修改StatefulSet replicas)
- 自动水平扩展从库集群
- 支持多可用区部署(需配置亲和性策略)
注意事项:
- 生产环境需配置Secret管理数据库密码
- 建议添加MySQL连接池配置(如HikariCP)
- 需要配置合适的持久化存储方案
- 建议添加监控和报警机制(Prometheus+Granafa)