本篇主要有两部分:

  • 1、使用docker部署mysql主从 实现主从复制

  • 2、springboot项目多数据源配置,实现读写分离

一、使用docker部署mysql主从 实现主从复制

此次使用的是windows版本docker,mysql版本是5.7

  • 1、使用docker获取mysql镜像

docker pull mysql:5.7.23 #拉取镜像文件

docker images #查看镜像文件

  • 2、使用docker运行mysql master

docker run --name mysql-master --privileged=true -v F:\dockerV\mysql:/var/lib/mysql -p 3307:3306 -e MYSQL_ROOT_PASSWORD=654321 -d mysql:5.7.23

    • --name 容器名称mysql-master

    • --privileged 指定了当前容器是否真正的具有root权限,所谓的root权限是指具有宿主机的root权限,而不仅仅只是在容器内部有root权限

    • -v 将系统的F:\dockerV\mysql挂载到容器的/var/lib/mysql,注意是将宿主机 挂载到 容器内部,而不是将容器内部挂载到宿主机

    • -p 表示宿主机上的某个端口映射到docker容器内的某个端口,这里也就是将宿主机的3307端口映射到容器内部的3306端口

    • -e 表示指定当前容器运行的环境变量,该变量一般在容器内部程序的配置文件中使用,而在外部运行容器指定该参数。这里的MYSQL_ROOT_PASSWORD表示容器内部的MySQL的启动密码

    • -d 后台运行,镜像文件为mysql:5.7.23

  • 接下来进入容器内部,修改配置,使其作为mysql master运行

docker exec -it mysql-master bash #进入容器内部

  • 配置mysql master,修改mysql.cnf

  • 使用vim修改mysql.cnf,没有安装vim会提示bash: vi: command not found 则需要安装vim

apt-get install vim

apt-get update

apt-get install vim

vim mysqld.cnf #修改cnf文件,添加 server-id 表示master服务标识,同一局域网内注意要唯一 和 log-bin=mysql-bin 开启二进制日志功能,可以随便取,用来完成主从复制

  • 修改完成mysql的配置后,需要重启服务生效

service MySQL restart # 重启mysql服务时会使得docker容器停止,我们还需要docker start mysql-master启动容器

docker start mysql-master #启动容器

  • 连接mysql客户端,创建用来完成主从复制的账号

mysql -uroot -p654321 #连接mysql

  • 为从服务器创建一个可以用来操作master服务器的账户,也就是创建一个专门用来复制binlog的账号,并且赋予该账号复制权限,其命令如下

grant replication slave on *.* to 'slaveaccount'@'%' identified by '654321'; #账号slaveaccount 密码654321

flush privileges; #刷新用户权限表

show master status #查看mysql master的状态

记录下上的position和file 在创建MySQL slave配置时会用到

到这里mysql master 已经配置完成了

  • 3、使用docker运行mysql slave

docker run --name mysql-slave --privileged=true -v F:\dockerV\mysql-slave:/var/lib/mysql -p 3308:3306 --link mysql-master:master -e MYSQL_ROOT_PASSWORD=654321 -d mysql:5.7.23

mysql slave 的参数主要和master有两点不同

  • 所映射的宿主机的端口号不能与master容器相同,因为其已经被master容器占用;

  • 必须加上--link参数,其后指定了当前容器所要连接的容器,mysql-master表示所要连接的容器的名称,master表示为该容器起的一个别名,通俗来讲,就是slave容器通过这两个名称都可以访问到master容器。这么做的原因在于,如果master与slave不在同一个docker network中,那么这两个容器相互之间是没法访问的。

docker exec -it mysql-slave /bin/bash #进入mysql salve容器

vim mysqld.cnf #修改cnf文件,添加 server-id 表示slave服务标识,如果此salve需要作为其他mysql的主,那么就需要配置log-bin=mysql-bin

service MySQL restart # 重启mysql服务时会使得docker容器停止,我们还需要docker start mysql-slave启动容器

docker start mysql-master #启动容器

mysql -uroot -proot #连接mysql服务

配置mysql slave 使其以slave模式运行

change master to master_host='172.17.0.2', master_user='slaveaccount', master_password='654321', master_port=3306, master_log_file='mysql-bin.000001', master_log_pos=2272, master_connect_retry=30;

注意:这一步主要在slave是配置master的信息,包括 master的 地址、端口、账号、密码、log文件、log文件偏移量、重试。下面介绍这些参数值从何获取

  • 获取master_host,使用docker inspect mysql-master查看master容器元数据。其中 IPAdress是master_host

  • 获取master_port,是运行master映射容器内部的端口,这里就是3306

  • 获取master_user和master_password,是第一步中在master中创建的slave账号

  • 获取master_log_file和master_log_pos,是配置master中最后一步使用show master status获取的文件和偏移量

  • 获取master_connect_retry,是slave重试连接master动作前的休眠时间,单位s,默认60s

start slave; #以slave模式运行

show salve status \G; #查看slave的状态

可以看到,Slave_IO_Running:YES和Slave_SQL_Running:YES 证明此时主从复制已经就绪,slave配置到此完成

  • 4、验证主从复制效果

    • 这里我们在连接master,并创建一张表,添加数据,在从库查看数据是否同步。
    • 在主库创建数据,并在从库查看数据是否同步成功。
  1. mysql> create database test;
  2. Query OK, 1 row affected (0.01 sec)
  3. mysql> use test;
  4. Database changed
  5. mysql> create table t_user(id bigint, name varchar(255));
  6. Query OK, 0 rows affected (0.02 sec)
  7. mysql> insert into t_user(id, name) value (1, 'cgg');
  8. Query OK, 1 row affected (0.01 sec)
  1. mysql> select * from test.t_user;
  2. +------+------+
  3. | id | name |
  4. +------+------+
  5. | 1 | cgg |
  6. +------+------+
  7. 1 row in set (0.00 sec)
  • 5、mysql主从复制原理

  • 主库db的更新事件(update、insert、delete)被写到binlog
  • 主库创建一个binlog dump thread,把binlog的内容发送到从库
  • 从库启动并发起连接,连接到主库
  • 从库启动之后,创建一个I/O线程,读取主库传过来的binlog内容并写入到relay log
  • 从库启动之后,创建一个SQL线程,从relay log里面读取内容,从Exec_Master_Log_Pos位置开始执行读取到的更新事件,将更新内容写入到slave的db

二、springboot项目多数据源配置,实现读写分离

  • 1、主从多数据源配置

    • yml配置
  1. server:
  2. port: 8888
  3. servlet:
  4. encoding:
  5. charset: UTF-8
  6. force: true
  7. enabled: true
  8. spring:
  9. datasource:
  10. driver-class-name: com.mysql.cj.jdbc.Driver
  11. type: com.alibaba.druid.pool.DruidDataSource
  12. url: jdbc:mysql://127.0.0.1:3307/test?serverTimezone=GMT%2B8&characterEncoding=utf-8&autoReconnect=true&failOverReadOnly=false&useSSL=false
  13. username: root
  14. password: 654321
  15. slave:
  16. datasource:
  17. driver-class-name: com.mysql.cj.jdbc.Driver
  18. type: com.alibaba.druid.pool.DruidDataSource
  19. url: jdbc:mysql://127.0.0.1:3308/test?serverTimezone=GMT%2B8&characterEncoding=utf-8&autoReconnect=true&failOverReadOnly=false&useSSL=false
  20. username: root
  21. password: 654321
  • 数据源配置
  1. /**
  2. * @author cgg
  3. **/
  4. @Configuration
  5. @EnableTransactionManagement
  6. public class DynamicDataSourceConfig {
  7. @Bean(name = "slaveDatasource")
  8. @ConfigurationProperties(prefix = "slave.datasource")
  9. public DataSource dbSlave() {
  10. return DruidDataSourceBuilder.create().build();
  11. }
  12. @Bean(name = "dataSource")
  13. @ConfigurationProperties(prefix = "spring.datasource")
  14. public DataSource dbMaster() {
  15. return DruidDataSourceBuilder.create().build();
  16. }
  17. @Bean
  18. @Primary
  19. public DataSource multipleDataSource(@Qualifier("dataSource") DataSource db,
  20. @Qualifier("slaveDatasource") DataSource slaveDatasource) {
  21. DynamicDataSource dynamicDataSource = new DynamicDataSource();
  22. Map<Object, Object> targetDataSources = new HashMap<>(16);
  23. targetDataSources.put("dataSource", db);
  24. targetDataSources.put("slaveDatasource", slaveDatasource);
  25. dynamicDataSource.setTargetDataSources(targetDataSources);
  26. //设置默认数据源为从库,如果写操作业务多,可以默认设置为主库
  27. dynamicDataSource.setDefaultTargetDataSource(slaveDatasource);
  28. return dynamicDataSource;
  29. }
  30. @Bean("sqlSessionFactory")
  31. public SqlSessionFactory sqlSessionFactory() throws Exception {
  32. MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
  33. sqlSessionFactory.setDataSource(multipleDataSource(dbSlave(), dbMaster()));
  34. MybatisConfiguration configuration = new MybatisConfiguration();
  35. configuration.setJdbcTypeForNull(JdbcType.NULL);
  36. configuration.setMapUnderscoreToCamelCase(true);
  37. configuration.setCacheEnabled(false);
  38. sqlSessionFactory.setConfiguration(configuration);
  39. sqlSessionFactory.setMapperLocations((new PathMatchingResourcePatternResolver()).getResources(DEFAULT_MAPPER_LOCATION));
  40. PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
  41. paginationInterceptor.setOverflow(false);
  42. paginationInterceptor.setLimit(-1);
  43. paginationInterceptor.setCountSqlParser(tenantSqlParserCountOptimize());
  44. Interceptor[] plugins = new Interceptor[]{new ShardTableInterceptor(), paginationInterceptor};
  45. sqlSessionFactory.setPlugins(plugins);
  46. return sqlSessionFactory.getObject();
  47. }
  48. }
  49. /**
  50. * 动态数据源
  51. *
  52. * @author cgg
  53. **/
  54. @Slf4j
  55. public class DynamicDataSource extends AbstractRoutingDataSource {
  56. @Override
  57. protected Object determineCurrentLookupKey() {
  58. return DbContextHolder.getDbType();
  59. }
  60. }
  • 2、配置切面控制主从数据源切换、读从库写主库,实现读写分离

    • aop切面
  1. /**
  2. * @author cgg
  3. **/
  4. @Component
  5. @Order(value = -100)
  6. @Slf4j
  7. @Aspect
  8. public class DataSourceSwitchAspect {
  9. //master 包下的操作都是操作主库业务
  10. @Pointcut("execution(* com.master..*.*(..))")
  11. private void db1Aspect() {
  12. }
  13. //slave 包下的操作都是操作从库业务
  14. @Pointcut("execution(* com.slave.*.*(..))")
  15. private void db2Aspect() {
  16. }
  17. @Before("db1Aspect()")
  18. public void dbMaster() {
  19. log.debug("切换到Master 数据源...");
  20. DbContextHolder.setDbType("dataSource");
  21. }
  22. @Before("db2Aspect()")
  23. public void dbSlave() {
  24. log.debug("切换到Slave 数据源...");
  25. DbContextHolder.setDbType("slaveDatasource");
  26. }
  27. }
  28. /**
  29. * @author cgg
  30. **/
  31. public class DbContextHolder {
  32. private static final ThreadLocal contextHolder = new ThreadLocal<>();
  33. /**
  34. * 设置数据源
  35. * @param dbType
  36. */
  37. public static void setDbType(String dbType) {
  38. contextHolder.set(dbType);
  39. }
  40. /**
  41. * 取得当前数据源
  42. * @return
  43. */
  44. public static String getDbType() {
  45. return (String) contextHolder.get();
  46. }
  47. /**
  48. * 清除上下文数据
  49. */
  50. public static void clearDbType() {
  51. contextHolder.remove();
  52. }
  53. }
  • 3、验证读写分离效果

    • 使用接口调用不同接口,切点会自动切换数据源,这里写库接口只会操作主库,读库接口会操作从库。实现读写分离

springboot多数据源配合docker部署mysql主从实现读写分离的更多相关文章

  1. 使用docker 实现MySQL主从同步/读写分离

    1. 利用 docker 实现 mysql 主从同步 / 读写分离 为了保证数据的完整和安全,mysql 设计了主从同步,一个挂掉还可以用另个.最近重构论坛,想来改成主从吧.担心失误,就先拿 dock ...

  2. Docker容器启动Mysql,Docker实现Mysql主从,读写分离

    Docker容器启动Mysql,Docker实现Mysql主从,读写分离 一.Docker文件编排 二.配置主从复制 2.1 配置master 2.2 配置slave 三.验证主从复制 3.1 mas ...

  3. 聊聊Mysql主从同步读写分离配置实现

    Hi,各位热爱技术的小伙伴您们好,好久没有写点东西了,今天写点关于mysql主从同步配置的操作日志同大家一起分享.最近自己在全新搭建一个mysql主从同步读写分离数据库简单集群,我讲实际操作步骤整理分 ...

  4. Mysql主从配置+读写分离

    Mysql主从配置+读写分离     MySQL从5.5版本开始,通过./configure进行编译配置方式已经被取消,取而代之的是cmake工具.因此,我们首先要在系统中源码编译安装cmake工具. ...

  5. Mysql主从配置+读写分离(转)

       MySQL从5.5版本开始,通过./configure进行编译配置方式已经被取消,取而代之的是cmake工具.因此,我们首先要在系统中源码编译安装cmake工具. 注:安装前须查看是否已经安装了 ...

  6. mysql 主从同步-读写分离

    主从同步与读写分离测试 一.  实验环境(主从同步) Master                   centos 7.3              192.168.138.13 Slave     ...

  7. docker-compose.yml样例(mysql主从+mycat读写分离)

    Docker-compose.yml文件示例 1.mysql主从复制的docker-compose.yml文件 # cat docker-compose.yml version: '2' # 这个ve ...

  8. mysql主从同步--读写分离。

    1.mysql 安装参考 https://www.cnblogs.com/ttzzyy/p/9063737.html 2. 主mysql,从mysql 指定配置文件启动 mysqld --defaul ...

  9. 利用oneproxy部署mysql数据库的读写分离

    实验系统:CentOS 6.6_x86_64 实验前提:防火墙和selinux都关闭 实验说明:本实验共有4台主机,IP分配如拓扑 实验软件:mariadb-10.0.20 oneproxy-rhel ...

随机推荐

  1. etcd学习(6)-etcd实现raft源码解读

    etcd中raft实现源码解读 前言 raft实现 看下etcd中的raftexample newRaftNode startRaft serveChannels 领导者选举 启动并初始化node节点 ...

  2. 我这三年被kafka坑惨了

    前言 我的上家公司是做餐饮系统的,每天中午和晚上用餐高峰期,系统的并发量不容小觑.为了保险起见,公司规定各部门都要在吃饭的时间轮流值班,防止出现线上问题时能够及时处理. 我当时在后厨显示系统团队,该系 ...

  3. 记面试的一道JS题

    给一个数组arr=[1,2,3,4,5],索引第二位插入'z',设计一个函数change,调用change(arr, 2, 'z')返回一个新数组[1,2,'z',3,4,5] 我想了两种办法: 第一 ...

  4. 一个tomcat配置多个不同端口的项目

    1.将要同时启动的项目放入不同的webapps文件夹中 2.修改tomcat安装目录下的conf-->setting.xml文件 <?xml version="1.0" ...

  5. BeautifulSoup4的使用

    一.介绍 Beautiful Soup 主要是用来解析提取 HTML 和 XML 文件中的数据. 现在官网推荐使用 Beautiful Soup 4 ,已经被移植到了BS4中. 安装 Beautifu ...

  6. 配置之XML--读取XML文件 转存为Key-Value

    将XML文件读取 绑定数据至Dictionary Eg: Xml文件 <?xml version="1.0" encoding="utf-8" ?> ...

  7. 使用git下载码云仓库文件步骤总结

    从码云下载文件的两种方式(私服时) 1.让私服管理者复制链接,然后你加入私服: 2.生成公钥,让私服管理者添加你的公钥. 在eclipse中找到git,输入自己的登录账号和密码,下载文件到本地仓库,然 ...

  8. 七:使用Session进行会话管理

    一.Session简单介绍 在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下).因此,在需要保存用户数据时,服务 ...

  9. Spring中常用重要的接口

    Spring (ApplicationContext 初始化Bean的方法 refresh()) public void refresh() throws BeansException, Illega ...

  10. 设计模式<一>

    设计原则1.找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起. 2.针对接口编程,而不是针对实现编程. 3.多用组合,少用继承. 一:策略模式,定义了算法族,分别封装起来 ...