• MySQL主从复制读写分离


    目录

    准备工作

    读写分离原理

    配置主从

    配置主机MySQL Master

     配置从机MySQL Slave

     读写分离

    案例:


    准备工作

    Centos7系统:192.168.127.128 xiaoying1 (当主机 Master)

    Centos7系统:192.168.127.131 xiaoying2 (当从机 Slave)

    在这两台操作系统安装MySQL,建议MySQL版本一致(本案例使用的是MySQL8.X )


    读写分离原理

    MySQL要做到主从复制,其实依靠的是二进制日志。

    举例:假设主服务器叫A,从服务器叫B;主从复制就是B跟着A学,A做什么,B就做什么。那么B怎么同步A的动作呢﹖现在A有一个日志功能,把自己所做的增删改(Insert、Delete、Update)的动作,全都记录在日志中,B只需要拿到这份日志,照着日志上面的动作施加到自己身上就可以了。这样就实现了主从复制。


    配置主从

    配置主机MySQL Master

    1.修改MySQL my.cnf 文件或my.ini

     vim /etc/my.cnf
    1. [mysqld]
    2. log-bin=mysql-bin #[必须]启用二进制日志
    3. binlog_format=mixed #二进制日志的格式,有三种
    4. server_id=128 #[必须]服务器唯一id,默认是1,一般取ip最后一段
    5. expire-logs-days=10 # [可选]binlog日志保留的天数,清除超过10天的日志 防止日志文件过大,导致磁盘空间不足

     2.重启MySQL服务

    systemctl restart mysqld 

    3.在主服务器上为从服务器分配一个账号,就像一把钥匙,从服务器拿着这个钥匙,才能到主服务器来共享主服务器的日志文件。此命令也可以在Navicat中执行

    1. mysql> create user 'slave'@'%' identified by 'Slave123.'; -- 创建用户
    2. mysql> grant REPLICATION SLAVE on *.* to slave@'%' with grant option; -- 授权
    3. # 如果授权出现异常:Access denied; you need (at least one of) the SYSTEM_USER privilege(s) for this operation
    4. mysql> grant system_user on *.* to 'root'; #则先执行给root,SYSTEM_USER权限然后在执行授权
    5. mysql> grant REPLICATION SLAVE on *.* to slave@'%' with grant option;
    • replication slave:分配的权限
    • *.*:可操作的数据库
    • 'slave': 用户名
    • '%':可以在那台电脑登录
    • '1234':密码

    4.查看配置状态

    mysql> show master status;

     


     配置从机MySQL Slave

    1.修改MySQL my.cnf或my.ini

    vim /etc/my.cnf
    1. [mysqld]
    2. log-bin=mysql-bin #[不是必须]启用二进制日志
    3. binlog-do-db=test #同步的数据库
    4. server_id=131 #服务器唯一id,默认是1,一般取ip最后一段

     2.重启MySQL服务

    systemctl restart mysqld

    3.关闭slave(一定要先关闭)

    mysql> stop slave

    4.开始配置

    1. mysql> change master to
    2. master_host='192.168.127.128',
    3. master_user='slave',
    4. master_password='Slave123.',
    5. master_log_file='mysql-bin.000003',
    6. master_log_pos=1135;
    • master_host:要连接的主服务器ip地址
    • master_user:要连接主服务器用户名
    • master_password:要连接主服务器密码
    • master_log_file:要连接的主服务器的bin日志的日志名称,即配置master第四步可得到该信息
    • master_log_pos:要连接的主服务器的bin日志的记录位置,即配置master第四步可得到该信息

     

     5.启动slave同步

    mysql> start slave

    6.检查从服务器复制功能状态

    mysql> show slave status;

    结果如下即成功:

    • Slave_IO_Running=Yes
    • Slave_SQL_Running=Yes

     7.创建一个只读账号

    1. #创建用户用户名:reader 密码:Reader123.
    2. create user 'reader'@'%' identified by 'Reader123.';
    3. #赋予SELECT权限
    4. grant SELECT on *.* to 'reader'@'%' with grant option;
    5. #刷新权限
    6. flush privileges;

    实验结果:

    主服务器(xiaoying1) 中创建 "test" 数据库,再看从服务器(xiaoying2 )也多了个 "test" 数据库

    在 xiaoying1中创建表并插入数据、修改数据 ,在xiaoying2已刷新就会发现同步了

    不会实现同步的情况:

    • 从服务器(xiaoying2)使用root账号,增删改

     读写分离

    主从复制完成后,还需要实现读写分离,Master负责写入数据,Slave负责读取数据, 本文采用Sharding-JDBC定位为轻量级Java框架实现。

    Sharding-JDBC定位为轻量级Java框架,在Java的DBC层提供的额外服务。它使用客户端直连数据库,以jar包形式提供服务,无需额外部署和依赖,可理解为增强版的DBC驱动,完全兼容JDBC和各种ORM框架。使用Sharding-JDBC可以在程序中轻松的实现数据库读写分离。

    • 适用于任何基于JDBC的ORM框架,如:JPA,Hibernate,.Mybatis,Spring JDBC Template或直接使用DBC。
    • 支持任何第三方的数据库连接池,如:DBCP,C3PO,BoneCP,Druid,HikariCP等。
    • 支持任意实现DBC规范的数据库。目前支持MySQL,Oracle,SQLServer,PostgreSQL以及任何遵循SQL92标准的数据库

    案例:

    主库(Master)用来增删改、从库(Slave)用来查询

     1.导入相关依赖

    1. mysql
    2. mysql-connector-java
    3. 8.0.24
    4. com.alibaba
    5. druid
    6. 1.1.22
    7. com.baomidou
    8. mybatis-plus-boot-starter
    9. 3.4.3
    10. org.projectlombok
    11. lombok
    12. org.apache.shardingsphere
    13. sharding-jdbc-spring-boot-starter
    14. 4.1.1
    15. org.springframework.boot
    16. spring-boot-starter-web

    2.在Master的test数据库创建User表

     3.创建项目结构:

     Mapper、Service、ServiceImpl配置

    1. Mapper:
    2. public interface UserMapper extends BaseMapper {
    3. }
    4. Service:
    5. public interface UserService extends IService {
    6. }
    7. Impl:
    8. @Service
    9. public class UserServiceImpl extends ServiceImpl implements UserService {
    10. }

    Controller:

    1. /**
    2. * @author 小影
    3. * @create: 2022/9/9 14:05
    4. * @describe
    5. */
    6. @RestController
    7. public class UserController {
    8. @Autowired
    9. private DataSource dataSource;
    10. @Autowired
    11. private UserService userService;
    12. /**
    13. * 新增用户
    14. *
    15. * @param user
    16. * @return
    17. */
    18. @PostMapping
    19. public User save(User user) {
    20. userService.save(user);
    21. return user;
    22. }
    23. /**
    24. * 根据id删除
    25. *
    26. * @param id
    27. */
    28. @DeleteMapping("/{id}")
    29. public void delete(@PathVariable("id") Long id) {
    30. userService.removeById(id);
    31. }
    32. /**
    33. * 根据id修改用户
    34. *
    35. * @param user
    36. * @return
    37. */
    38. @PutMapping
    39. public User update(User user) {
    40. userService.updateById(user);
    41. return user;
    42. }
    43. /**
    44. * 根据id查询用户
    45. *
    46. * @param id
    47. * @return
    48. */
    49. @GetMapping("/{id}")
    50. public User getById(@PathVariable("id") Long id) {
    51. return userService.getById(id);
    52. }
    53. /**
    54. * 条件查询
    55. *
    56. * @param user
    57. * @return
    58. */
    59. @GetMapping("/list")
    60. public List list(User user) {
    61. QueryWrapper queryWrapper = new QueryWrapper<>();
    62. queryWrapper.eq(user.getId() != null, "id", user.getId());
    63. queryWrapper.eq(user.getName() != null,"name", user.getName());
    64. return userService.list(queryWrapper);
    65. }
    66. }

    YML:

    1. server:
    2. port: 8080
    3. mybatis-plus:
    4. configuration:
    5. log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    6. map-underscore-to-camel-case: true
    7. global-config:
    8. db-config:
    9. id-type: ASSIGN_ID
    10. spring:
    11. shardingsphere:
    12. datasource:
    13. names: master,slave01 #因为我就配置了一个从机,多个从机使用逗号隔开 master,slave01,slave02...
    14. # 主数据源Master
    15. master:
    16. type: com.alibaba.druid.pool.DruidDataSource
    17. url: jdbc:mysql://192.168.127.128:3306/test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
    18. driver-class-name: com.mysql.cj.jdbc.Driver
    19. username: root
    20. password: 123456
    21. # 从数据源slave
    22. slave01:
    23. type: com.alibaba.druid.pool.DruidDataSource
    24. url: jdbc:mysql://192.168.127.131:13306/test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
    25. driver-class-name: com.mysql.cj.jdbc.Driver
    26. username: reader
    27. password: Reader123.
    28. masterslave:
    29. # 读写分离设置【负载均衡策略】
    30. load-balance-algorithm-type: round_robin
    31. # 最终的数据源名称
    32. name: dataSource
    33. # 主数据源名称【与上面对应】
    34. master-data-source-name: master
    35. # 从数据源名称【与上面对应】
    36. slave-data-source-names: slave01 #多个从机使用逗号隔开
    37. props:
    38. sql:
    39. show: true # 开启SQL显示,默认false
    40. main:
    41. allow-bean-definition-overriding: true # 允许bean覆盖

    在配置项中设置允许bean定义覆盖配置项如果不进行设置就会出现启动项目报错,主要的原因是引两个jar包都会创建数据源对象,导致报错,开启bean配置覆盖就可以解决问题了

    启动项目控制台输出:

     发送请求查看日志或DBug方式查看是谁操作了数据源

    测试添加:

     查询测试:

     

    缺点:

    尽管主从复制、读写分离能很大程度保证MySQL服务的高可用和提高整体性能,但是问题也不少:

    • 从机是通过binlog日志从master同步数据的,如果在网络延迟的情况,从机就会出现数据延迟。那么就有可能出现master写入数据后,slave读取数据不一定能马上读出来。

    事务问题:

      这是小编在开发学习使用和总结的小Demo,  这中间或许也存在着不足,希望可以得到大家的理解和建议。如有侵权联系小编!

  • 相关阅读:
    速码!!!BGP最全学习笔记:BGP选路原则实验配置
    如何知道是否有人正在进行网络攻击
    [运维|数据库] mysql的charset与PostgreSQL的encoding
    【LeetCode】每日一题:相交链表
    Https中间人攻击
    Matplotlib绘图-快速上手可视化工具
    tesserocr识别图片
    Spring-bean实例化三种方式
    volatile-日常使用场景
    [第一章 web入门]粗心的小李
  • 原文地址:https://blog.csdn.net/weixin_46522803/article/details/126783200