栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

一文入门数据库中间件(ShardingSphere,Sharding-JDBC),从理论到实战,完成数据库主从复制,读写分离,分库分表!!!

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

一文入门数据库中间件(ShardingSphere,Sharding-JDBC),从理论到实战,完成数据库主从复制,读写分离,分库分表!!!

注:
大家好我是妈妈的好大儿,
笔者联系方式
QQ:3302254385
微信:yxc3302254385
交个朋友!
创作不易,三连十分感谢!!!

文章篇幅过长,有很多理论如果没有耐心!!!可以直接通过目录找到需要的配置文件!!!

1.基本介绍

详细内容见:
https://shardingsphere.apache.org/document/current/cn/overview/

ShardingSphere是什么?

Apache ShardingSphere 是一套开源的分布式数据库解决方案组成的生态圈,它由 JDBC、Proxy 和 Sidecar(规划中)这 3 款既能够独立部署,又支持混合部署配合使用的产品组成。 它们均提供标准化的数据水平扩展、分布式事务和分布式治理等功能,可适用于如 Java 同构、异构语言、云原生等各种多样化的应用场景。
Apache ShardingSphere 旨在充分合理地在分布式的场景下利用关系型数据库的计算和存储能力,而并非实现一个全新的关系型数据库。 关系型数据库当今依然占有巨大市场份额,是企业核心系统的基石,未来也难于撼动,我们更加注重在原有基础上提供增量,而非颠覆。
Apache ShardingSphere 5.x 版本开始致力于可插拔架构,项目的功能组件能够灵活的以可插拔的方式进行扩展。 目前,数据分片、读写分离、数据加密、影子库压测等功能,以及对 MySQL、PostgreSQL、SQLServer、Oracle 等 SQL 与协议的支持,均通过插件的方式织入项目。 开发者能够像使用积木一样定制属于自己的独特系统。Apache ShardingSphere 目前已提供数十个 SPI 作为系统的扩展点,而且仍在不断增加中。

三种接入服务 1.ShardingSphere-JDBC
  • ​定位为轻量级 Java 框架,在 Java 的 JDBC 层提供的额外服务。 它使用客户端直连数据库,以 jar 包形式提供服务,无需额外部署和依赖,可理解为增强版的 JDBC 驱动,完全兼容 JDBC 和各种 ORM 框架。
  • 适用于任何基于 JDBC 的 ORM 框架,如:JPA, Hibernate, Mybatis, Spring JDBC Template 或直接使用 JDBC。
  • 支持任何第三方的数据库连接池,如:DBCP, C3P0, BoneCP, Druid, HikariCP 等。
  • 支持任意实现 JDBC 规范的数据库,目前支持 MySQL,Oracle,SQLServer,PostgreSQL 以及任何遵循 SQL92 标准的数据库。
2.ShardingSphere-Proxy
  • (定位为透明化的数据库代理端,提供封装了数据库二进制协议的服务端版本,用于完成对异构语言的支持。 目前提供 MySQL 和 PostgreSQL 版本,它可以使用任何兼容 MySQL/PostgreSQL 协议的访问客户端(如:MySQL Command Client, MySQL Workbench, Navicat 等)操作数据,对 DBA 更加友好。)可以吧ShardingSphere-Proxy当做是中间的那一层 整合了全部数据库,并通过注册中心的地址直接访问
  • 向应用程序完全透明,可直接当做 MySQL/PostgreSQL 使用。
  • 适用于任何兼容 MySQL/PostgreSQL 协议的的客户端。
3.ShardingSphere-Sidecar(TODO)
  • (定位为 Kubernetes 的云原生数据库代理,以 Sidecar 的形式代理所有对数据库的访问。 通过无中心、零侵入的方案提供与数据库交互的啮合层,即 Database Mesh,又可称数据库网格。Database Mesh 的关注重点在于如何将分布式的数据访问应用与数据库有机串联起来,它更加关注的是交互,是将杂乱无章的应用与数据库之间的交互进行有效地梳理。 使用 Database Mesh,访问数据库的应用和数据库终将形成一个巨大的网格体系,应用和数据库只需在网格体系中对号入座即可,它们都是被啮合层所治理的对象。)
能解决什么问题? 数据分片
  • 分库 & 分表
  • 读写分离
  • 分片策略定制化
  • 无中心化分布式主键

​

分布式事务
  • 标准化事务接口
  • XA 强一致事务
  • 柔性事务

​

数据库治理
  • 分布式治理
  • 弹性伸缩
  • 可视化链路追踪
  • 数据加密

​

​

2.读写分离 1.读写分离是什么?有什么好处?会带来什么

是什么:
写数据写入到主机,读数据去从机读,读和写分开,对于读操作为主的应用,使用读写分离是最好的场景,因为可以确保写的服务器压力更小,而读又可以接受点时间上的延迟。

好处:

  • 增加了机器的处理能力,主从只负责各自的写和读,极大程度的缓解X锁和S锁争用
  • 从库可配置myisam引擎,提升查询性能以及节约系统开销
  • 读写分离架构出现的原因是因为在读远远比写多的情况下(一般读写比至少大于9:1),为了缓解主库的压力,将大多数读请求压力均摊到多个从库上。首先在遇到读多写少的情况,优先上缓存(如redis)。之后,如果仍然还是扛不住,可以上读写分离。
  • 部分服务down了也可以保证数据库的高可用性

​

​

问题:

  • 主从结构最大的缺点在于主从延迟,导致往主库写入的数据跟从库读出来的数据不一致。尤其是在高并发状态往主库写入的数据量很多的时候,延迟会很严重。最重要区别在于1.主库向从库发送binlog是异步的2.从库恢复数据也是异步的

​

​

​

2.什么是主从复制?

实现读写分离的前提是主从复制!
master服务器负责写入操作,master服务器通过binlog日志文件将数据复制到从机slave上!!!

3.mysql的主从复制有三种方式 1.异步复制

MYSQL默认使用的就是异步复制模式。
异步复制的过程如下:

  1. master client thread 写undo log,binlog成功,然后通知master dump thread,然后提交事务,返回响应。
  2. master dump thread收到通知,然后读取binlog和相关位置信息,发送给slave。
  3. slave IO thread 接收到binlog和相关位置数据,写relay log,通知slave sql thread,同时记录binlog位置。
  4. slave sql thread读取relay log,然后执行sql。

流程图如下:

​

2.半同步复制
  1. master client thread 写undo log,binlog成功,然后通知master dump thread。
  2. master dump thread收到通知,然后读取binlog和相关位置信息,发送给slave。
  3. slave IO thread 接收到binlog和相关位置数据,写relay log,通知slave sql thread,同时记录binlog位置。同时返回ACK响应给master。
  4. slave sql thread读取relay log,然后执行sql。
  5. master收到ACK响应,提交事务,返回成功给客户端。

​


​

3.全同步复制。

全同步复制跟半同步复制的区别在于,半同步复制只需要一个slave确认已经接收到事务并写入relay log的ACK,就回提交本地的事务并返回成功给客户端。而全同步则需要所有的slave的确认ACK。一般很少使用全同步复制,因为性能太差。

4.配置mysql主从复制 一.安装mysql常用命令
#查看服务状态
service mysqld status;

#启动
service mysqld start

#关闭 
service mysqld stop

#进入命令行登录 然后输入密码 --->(密码)520LoveYou
mysql -u root -p

#退出mysql命令行  
exit;

#查看安装了哪些mysql服务
rpm -qa |grep -i mysql
-mysql-common-8.0.21-1.module_el8.2.0+493+63b41e36.x86_64
-mysql-libs-8.0.21-1.module_el8.2.0+493+63b41e36.x86_64
-bt-mysql80-8.0.20-1.el8.x86_64

#删除mysql
rpm ev [上面的服务名称]

#删除mysql目录 
rm -rf /var/lib/mysql/
rm -rf /etc/my.cnf.d
rm /usr/my.cnf
rm -rf /usr/bin/mysql*

#查看服务器是多少位的 
uname -m

#查看mysql安装好的默认密码 
grep "password" /var/log/mysqld.log

#设置mysql的密码 
set password for root@localhost =password('123456');

#启动mysql 并加入开机自启
systemctl  start mysqld
systemctl  stop mysqld
systemctl  enable mysqld

#重启mysql
systemctl restart mysqld

#为mysql某个ip的某个用户赋予全部权限
grant all privileges on *.* to root@101.88.56.121 identified by 'root';

#刷新权限
flush privileges;

​

二.配置mysql主从复制 主机配置文件:
#编辑mysql配置文件 
vim /etc/my.cnf

#设置server_id,同一局域网内注意要唯一 
server-id=100

#开启二进制日志功能,可以随便取
log-bin=cc-mysql-bin

#复制过滤:不需要备份的数据库,不输出(mysql库一般不同步)
binlog-ignore-db=mysql

#为每个session分配的内存,在事务过程中用来存储二进制日志的缓存 
binlog_cache_size=1M

#主从复制的格式 (mixed,statement,row  默认格式statement)
binlog_format=mixed


​

从机配置文件:
#编辑mysql配置文件 
vim /etc/my.cnf

#设置server_id,同一局域网内注意要唯一 
server-id=101

#开启二进制日志功能,已备slave作为其他slave的master时使用 
log-bin=cc-mysql-slave-bin

#relay_log配置中继日志
relay_log=edu-mysql-relay-bin

#复制过滤:不需要备份的数据库,不输出(mysql库一般不同步)
binlog-ignore-db=mysql

#如果需要同步函数或者存储过程 
log_bin_trust_function_creators=true

#为每个session分配的内存,在事务过程中用来存储二进制日志的缓存 
binlog_cache_size=1M

#主从复制的格式 (mixed,statement,row  默认格式statement)
binlog_format=mixed

#跳过主从复制之后遇到的所有错误或指定类型的错误,避免slave端复制中断 
#如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
在master服务器授权给slave服务器可以同步的权限(Master节点执行)
#授予slave服务器可以同步master服务
grant replication slave, replication client on *.* to 'root'@'从服务器地址' identified by '从服务器密码';
grant replication slave, replication client on *.* to 'root'@'39.98.123.78' identified by 'chenqi123123.';
#建议使用这个命令
#账号为root 密码为root的用户 在ip地址39.98.123.78连接  拥有全部权限(记得刷新权限哦)
GRANT ALL PRIVILEGES ON *.* TO root@'39.98.123.78' IDENTIFIED BY 'root' WITH GRANT OPTION;
#账号为root 密码为root的用户 在任意ip地址连接  拥有全部权限(记得刷新权限哦)
GRANT ALL PRIVILEGES ON *.* TO root@'%' IDENTIFIED BY 'root' WITH GRANT OPTION;


#重新加载权限表
flush privileges;

#查询从机用户 
select user,host from mysql.user;
 
#查询二进制日志文件的位置  (记住Position位置)
show master status;
+---------------------------+----------+--------------+------------------+-------------------+
| File                      | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+---------------------------+----------+--------------+------------------+-------------------+
| cc-mysql-slave-bin.000002 |      154 |              | mysql            |                   |
+---------------------------+----------+--------------+------------------+-------------------+



​

在slave服务器连接master服务器(slave执行)
#配置从服务器连接主服务器
change master to master_host='master服务器ip',master_user='root',master_password='master密码',master_port=3306,master_log_file='master服务器日志文件名称',master_log_pos=同步的位置;
change master to master_host='139.224.130.10',master_user='root',master_password='root',master_port=3306,master_log_file='cc-mysql-slave-bin.000002',master_log_pos=154;

#启动主从复制 
start slave;

#查看主从复制的状态 
show slave statusG;

#关闭主从复制 (从机执行)
stop slave;


#-------------------------------排错环节------------------------------------
#ping 其他服务器查看是否能连接上  
ping [ip地址]

#判断 其他服务的端口是否通畅 
ssh -v -p3306 [ip地址]
成功--->
OpenSSH_7.4p1, OpenSSL 1.0.2k-fips  26 Jan 2017
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 58: Applying options for *
debug1: Connecting to 139.224.130.10 [139.224.130.10] port 3306.
debug1: Connection established.
debug1: permanently_set_uid: 0/0
debug1: key_load_public: No such file or directory
debug1: identity file /root/.ssh/id_rsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file /root/.ssh/id_rsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file /root/.ssh/id_dsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file /root/.ssh/id_dsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file /root/.ssh/id_ecdsa type -1
debug1: key_load_public: No such file or directory
debug1: identity file /root/.ssh/id_ecdsa-cert type -1
debug1: key_load_public: No such file or directory
debug1: identity file /root/.ssh/id_ed25519 type -1
debug1: key_load_public: No such file or directory
debug1: identity file /root/.ssh/id_ed25519-cert type -1
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_7.4
debug1: ssh_exchange_identification: N
debug1: ssh_exchange_identification: 5.7.34-log
ssh_exchange_identification: Connection closed by remote host

#远程连接mysql服务!!
mysql -h 139.224.130.10 -uroot -proot
#报错(账号密码不对)
Access denied for user 'root'@'39.98.123.78' (using password: YES)
#确定主服务器 是可以根据账号:root,密码:root进行登录的 那么就考虑其他服务器连接的权限问题
select host,user from  user;
+---------------+---------------+
| host          | user          |
+---------------+---------------+
| %             | root          |
| 101.88.56.121 | root          |
| 39.98.123.78  | root          |
| localhost     | mysql.session |
| localhost     | mysql.sys     |
+---------------+---------------+
#之前只配置了部分权限,现在给全部权限!!
GRANT ALL PRIVILEGES ON *.* TO root@'39.98.123.78' IDENTIFIED BY 'root' WITH GRANT OPTION;
#连接成功!!!解决



三.常见错误: 1.Slave_IO_Running:Connecting(连接失败)
  • 检查网络
  • ip
  • 端口
  • 密码
  • 权限

​

2.Slave_SQL_Running:No(Mysql镜像服务器因错误停止的恢复)
#关闭主从
stop slave;
#设置 (来跳过导致复制错误的SQL.)但是不建议这样去做
set global sql_slave_skip_counter=1;
5.如何判断主从延迟?

在从库上,可以查看show slave status查看如下参数:
1.seconds_behind_master是否为0。如果不为0,则表示有延迟。
2.read_master___log_pos
​

​

6.配置读写分离 1.导入pom倚赖:
 				
            org.springframework.boot
            spring-boot-starter
        
        
            org.springframework.boot
            spring-boot-starter-web
        
  		 
            org.springframework.boot
            spring-boot-starter-test
            test
        

        
            org.projectlombok
            lombok
        
        
            mysql
            mysql-connector-java
            runtime
        

        
            org.mybatis.spring.boot
            mybatis-spring-boot-starter
            2.1.4
        

      	

        
        
            com.alibaba
            druid-spring-boot-starter
            1.1.21
        

    		
        
            org.apache.shardingsphere
            sharding-jdbc-spring-boot-starter
            4.0.0-RC1
        
2.配置yaml文件(不完整版本)

只配置了多个数据源,还没配置读写分离

server:
  port: 9999


mybatis:
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath*:/mapper/xml
public class OrderTableShardingAlgorithm  implements PreciseShardingAlgorithm {

    
    @Override
    public String doSharding(Collection collection, PreciseShardingValue preciseShardingValue) {

        //1.获取分片键的分片值
        Date value = preciseShardingValue.getValue();

        //2.获取逻辑表名
        StringBuilder realTableName = new StringBuilder(preciseShardingValue.getLogicTableName());

        //3.计算出真实表
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy_MM");
        String format = simpleDateFormat.format(value);
        realTableName.append('_').append(format);

        //4.return的值 就是去操作的表
        return realTableName.toString();
    }
}

4.分布式事务(未实现)

博客参考地址:
https://zhuanlan.zhihu.com/p/183753774
​

​

1.导入此倚赖

       
            io.shardingsphere
            sharding-transaction-spring-boot-starter
            3.1.0
        

2.配置主启动类

@SpringBootApplication(exclude = JtaAutoConfiguration.class)
@EnableTransactionManagement
public class ShardingSphereJdbcApplication {

    public static void main(String[] args) {
        SpringApplication.run(ShardingSphereJdbcApplication.class, args);
    }

}

3.配置接口

   @GetMapping("/xaTransaction")
    @Transactional(rollbackFor = Exception.class)
    @ShardingTransactionType(TransactionType.XA)//分布式事务注解  xa强一致性
    public String xaTransaction(){
        //订单1 路由到db0.order_2021_01  (插入到数据源1)
        Order order = new Order();
        order.setId(10L);
        order.setMoney(10L);
        order.setName("订单1");
        Calendar calendar = Calendar.getInstance();
        calendar.set(2021,0,1);
        order.setTime(calendar.getTime());
        orderMapper.insert(order);

        //订单2 路由到db1.order_2021_02  (插入到数据源2)
        String remoteResult = restTemplate.getForObject("http://127.0.0.1:10000/order/insert", String.class);
        System.out.println("remoteResult---》"+remoteResult);


        //主动抛出异常 (服务C 调用失败)
        System.out.println(1/0);


        return "success";
    }
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/270040.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号