MySQL: MyCat middleware dynamic data sources, separate read and write, sub-libraries sub-table

A, MyCat Introduction

1.1 What is MyCat

From Ali's support for database read and write separation, sub-table sub-library distributed middleware.

Official website: http://www.mycat.io/

1.2, MyCat principle

SQL mainly through interception, and then after a certain rule (e.g., fragment analysis, route analysis, analysis of separate read and write, the cache analysis, etc.), the SQL engine to the rear end of the real data block, and return the results to make the appropriate treatment returned to the client.

Somewhat similar to Nginx reverse proxy, it can hide the real IP address database, you can read and write separation, sub-sub-table library (Note: MySQL master-slave replication is own implementation)

1.3, the actual use of MyCat how to write SQL execution

Note: select * on the graph are the actual conditions with no, if conditional, as follows:

(1) query field with a fragment, such as ID (high efficiency, only a check table):

If too is select * from user_info where id = 1,1% 3 = 1,1 in DB2, you MyCat will send a command to check a DB2 (see mycat.log can view the log information in Linux).

(2) non-fragmented query field, if the table has three name = "small Swiss" (inefficiency, may check multiple tables):

select * from user_info where name="小瑞"

(3) the query page: MyCat will send three statements to check three tables, view the logs to know, and returns a random result, there may be (3,6), (1,4), (2,5), poor performance

select * from user_info limit 0,2;

(4) If Paging added sort: it will also check the three tables, and then returns myCat, see who two largest or smallest return to the client, such as (1,2), (4,5)

select * from user_info order by id desc limit 0,2 ;

1.4 What are separate read and write

Separation is to separate read and write read and write operations of the database to correspond to various database services. Master database provides a write operation, a read operation provided from the database. After the main data write operation, data is synchronized in time to read the database, as far as possible to ensure that reading and writing database consistency.

For 1.5, L inux environment installed MyCat implemented separate read and write

1、上传安装Mycat-server-1.6.5-release-20180122220033-linux.tar
2、解压安装包tar –zxvf  
3、配置schema.xml 和server.xml
4、客户端连接端口号: 8066

Profile Introduction:

file

Explanation

server.xml

Mycat profiles, account settings, parameters, etc.

schema.xml

Mycat corresponding physical configuration database and database tables

rule.xml

Mycat slicing (sub-library sub-table) RULES

5、进入bin目录 
  启动MyCat ./mycat start 
  停止MyCat ./mycat stop
6、查看/usr/local/mycat/logs wrapper.log日志 如果是为successfully 则启动成功

关闭防火墙:systemctl stop firewalld.service
只可读的账号      user  user  端口号8066
可读可写的账号    root  123456  端口号8066

Two, S P ringBoot project integration dynamic data sources

 

Most dynamic data sources and data sources differences:

  • Multiple Data Sources --- to subcontract form
  • Dynamic data jvm be constantly switching

2.1, a plurality of data sources mode:

Configuring multiple data sources, depending on the volume of business needs to access data, specify the corresponding strategies: add, delete, modify operation corresponding data access, query and access to additional data, different databases to do data processing consistency.

2.2 Dynamic mode switching data sources:

The dynamic switching service profile database access, through this scheme SpringAOP implemented using AspactJ to achieve the weaving, is achieved by programming inheritance Spring in AbstractRoutingDataSource , to realize dynamic switching database access.

principle:

(1) First, in the project, there are two data sources, each data source is read and a write data source;

(2)使用AOP技术拦截业务逻辑层方法的前缀,如前缀为select、get、find等,判断方法是否做读或者写操作;

(3)如果写操作的时候,传递一个key给RoutingDataSource指明使用写的数据源。

使用AOP技术判断业务逻辑层的方法,判断方法的前缀是否为读或者写的操作。

(4)如果为写操作的时候,会给RountingDataSource传递key为updateDataSource

原理图:

步骤:

  • (1)创建读和写数据源
  • (2)读和写数据源注册到RoutingDataSource
  • (3)使用AOP技术拦截业务层方法,判断方法的前缀是否需要做读或者写

 

Maven依赖信息:

application.yml:

spring:
  datasource:
    ###可读数据源
    select:
      jdbc-url: jdbc:mysql://192.168.212.204:8066/TESTDB1
      driver-class-name: com.mysql.jdbc.Driver
      username: user
      password: user
    ####可写数据源  
    update:
      jdbc-url: jdbc:mysql://192.168.212.204:8066/TESTDB1
      driver-class-name: com.mysql.jdbc.Driver
      username: user
      password: user
    type: com.alibaba.druid.pool.DruidDataSource

 

 DataSourceContextHolder:

@Component
@Lazy(false)
public class DataSourceContextHolder {
	// 采用ThreadLocal 保存本地多数据源
	private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
	// 设置数据源类型
	public static void setDbType(String dbType) {
		contextHolder.set(dbType);
	}
	public static String getDbType() {
		return contextHolder.get();
	}
	public static void clearDbType() {
		contextHolder.remove();
	}
}

 DataSourceConfig:

@Configuration
public class DataSourceConfig {

	// 创建可读数据源
	@Bean(name = "selectDataSource")
	@ConfigurationProperties(prefix = "spring.datasource.select") // application.properteis中对应属性的前缀
	public DataSource dataSource1() {
		return DataSourceBuilder.create().build();
	}

	// 创建可写数据源
	@Bean(name = "updateDataSource")
	@ConfigurationProperties(prefix = "spring.datasource.update") // application.properteis中对应属性的前缀
	public DataSource dataSource2() {
		return DataSourceBuilder.create().build();
	}

}

 DynamicDataSource:

//在Spring 2.0.1中引入了AbstractRoutingDataSource, 该类充当了DataSource的路由中介, 能有在运行时, 根据某种key值来动态切换到真正的DataSource上。

@Component
@Primary
public class DynamicDataSource extends AbstractRoutingDataSource {
	@Autowired
	@Qualifier("selectDataSource")
	private DataSource selectDataSource;

	@Autowired
	@Qualifier("updateDataSource")
	private DataSource updateDataSource;

	/**
	 * 这个是主要的方法,返回的是生效的数据源名称
	 */
	@Override
	protected Object determineCurrentLookupKey() {
		System.out.println("DataSourceContextHolder:::" + DataSourceContextHolder.getDbType());
		return DataSourceContextHolder.getDbType();
	}

	/**
	 * 配置数据源信息
	 */
	@Override
	public void afterPropertiesSet() {
		Map<Object, Object> map = new HashMap<>();
		map.put("selectDataSource", selectDataSource);
		map.put("updateDataSource", updateDataSource);
		setTargetDataSources(map);
		setDefaultTargetDataSource(updateDataSource);
		super.afterPropertiesSet();
	}
}

 SwitchDataSourceAOP:

@Aspect
@Component
@Lazy(false)
@Order(0) // Order设定AOP执行顺序 使之在数据库事务上先执行
public class SwitchDataSourceAOP {
	// 这里切到你的方法目录
	@Before("execution(* com.mayikt.service.*.*(..))")
	public void process(JoinPoint joinPoint) {
		String methodName = joinPoint.getSignature().getName();
		if (methodName.startsWith("get") || methodName.startsWith("count") || methodName.startsWith("find")
				|| methodName.startsWith("list") || methodName.startsWith("select") || methodName.startsWith("check")) {
			DataSourceContextHolder.setDbType("selectDataSource");
		} else {
			// 切换dataSource
			DataSourceContextHolder.setDbType("updateDataSource");
		}
	}
}

 

2.3、MyCat实现读写分离方式:

MyCat连接多个数据库,数据源只需要连接MyCat,对于开发人员而言他还是连接了一个数据库(实际上是mysql的mycat中间件),而且也不需要根据不同业务选择不同的库,这样不会有多余代码产生。

 

 

三、数据库分表分库策略

3.1、数据库集群会产生哪些问题

(1)自增ID问题;

问题:数据库集群如果自动增长ID产生重复,如何解决?

答:

  • a、可以通过UUID形式,但是UUID是无需的,不太适合用String类型做ID,性能不好,但是因为如果用Oracle要设置自动增长要搞个序列比较麻烦,所以oracle数据库环境String类的ID还是比较常见;
  • b、还可以设置数据库步长;
  • c、雪花算法;
  • d、redis。

(2)数据库关联查询问题(水平拆分产生);

(3)数据同步问题(可通过主从复制解决)。

3.2、分表分库原则:垂直拆分和水平拆分

(1)垂直拆分——最基本的,大公司基本都会用

什么是垂直拆分:

根据不同的业务,分为不同的数据库,比如会员数据库、订单数据库、支付数据库等。

优点:

拆分后业务清晰,拆分规则明确,系统之间整合或者扩展容易

缺点:

跨数据库查询只能通过接口形式通讯,比如订单服务和会员服务的数据交流需要编写接口出来给对方调用,工作量比较大。提高了系统复杂度,还会存在分布式事务问题

使用场景:大型互联网项目、电商项目、微服务项目

(2)水平拆分——分表、分库

什么是水平拆分:把同一个表拆分到不同的数据库中。

水平拆分不是将表的数据做分类,而是按照某个字段的某种规则来分散到多个库中,每个表中包含一部分数据。主要是按照数据的行切分,把表的某些行切分到一个数据库,而另外某些行又切分到其他数据库。主要有分表和分库两种模式

优点:

提高了系统稳定性、负载能力

缺点:

跨库关联性能较差较复杂

(3)垂直拆分和水平拆分区别垂直拆分是把不同的表发放在不同数据库;水平拆分是把同一个表拆到不同的数据库,或者把一张表数据拆分到n多个小表。

3.3、使用阿里MyCat实现水平分片策略

(1) MyCat支持10种分片策略

  • 1、求模算法
  • 2、分片枚举
  • 3、范围约定
  • 4、日期指定
  • 5、固定分片hash算法
  • 6、通配取
  • 7、ASCII码求模通
  • 8、编程指定
  • 9、字符串拆分hash解析

详细文档介绍可访问:http://www.mycat.io/document/mycat-definitive-guide.pdf

(2)原理分析(取模算法)

a、MyCat中的路由结果是通过 分片字段和分片方法 来确定的,如果查询条件中有id字段的情况还好,查询将会落到某个具体的分片。

b、如果查询没有分片的字段,会向所有的db都会查询一遍,然后封装结果集给客户端。

(3)环境搭建

a、先定义枚举(比如地区),每个地区指定数据库存放位置;

b、

(2)地区分片环境搭建

各种配置文件百度即可;

分片案例:比如某些业务需要按省份或者区县来保存,而全国的省份区县固定的。配置如下:

案例步骤:
1、创建数据库userdb_1 、 userdb_2、userdb_3 
2、
wuhan=0
shanghai=1
suzhou=2
上面columns 标识是将要分片的表字段,algorithm 分片函数,
其中分片函数配置中,mapFile标识配置文件名称,type默认值为0,0表示Integer,非零表示String,
所有的节点配置都是从0开始,及0代表节点1
3、
defaultNode 默认节点:小于0表示不设置默认节点,大于等于0表示设置默认节点,结点为指定的值
默认节点的作用:
枚举分片时,如果碰到不识别的枚举值,就让它路由到默认节点
                如果不配置默认节点(defaultNode值小于0表示不配置默认节点),碰到
                不识别的枚举值就会报错,
                like this:can't find datanode for sharding column:column_name val:ffffffff 

4、范围约定 此分片适用于提前规划好分片字段某个范围属于哪个分片
5、求摸法 : 根据id进行十进制求摸运算,运算结果为分区索引
注意:数据库节点分片数量无法更改。

 rule.xml 文件新增

<tableRule name="role1">
        <rule>
            <columns>id</columns>
            <algorithm>mod-long</algorithm>
        </rule>
    </tableRule>
 
    <function name="mod-long" class="io.mycat.route.function.PartitionByMod">
        <!--指定分片数量,不可以被更改-->
        <property name="count">3</property>
</function>

schema.xml
<table name="user_info" dataNode="dn1,dn2,dn3" rule="role1"/>

数据库表结构:

CREATE TABLE `user_info` (
  `id` int(11) DEFAULT NULL,
  `name` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

6、日期列分区法 按日期(天)分片

关闭防火墙

systemctl stop firewalld.service
yum -y install net-tools
netstat -tunlp | grep 1984
kill -9  2408

CREATE TABLE `user_info` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

 

发布了52 篇原创文章 · 获赞 116 · 访问量 5万+

Guess you like

Origin blog.csdn.net/RuiKe1400360107/article/details/103971064