为什么需要读写分离
至于为什么需要读写分离, 在我之前的文章有介绍过了, 相信看到这篇文章的人也知道为什么需要读写分离了, 当然如果你也需要了解一下, 那么欢迎查看我之前的文章 SpringBoot Mybatis 读写分离配置 , 顺便也可以了解一下怎么通过代码进行读写分离的
MySQL 主从复制
主从复制是读写分离的关键, 不管通过什么方式进行读写分离, 前提就是 MySQL 有主从复制, 当前双机主从也行, 但是关键的关键, 是要能保证 2 个库的数据能一致 (出掉刚写入主库从库还未能及时反应过来的情况), 如果 2 个库的数据不一致, 那么读写分离也有没有任何意义了, 具体 MySQL 怎么做主从复制可以查看我之前的文章 MySQL 主从复制搭建, 基于日志 (binlog)
Mycat 是什么
一个彻底开源的, 面向企业应用开发的大数据库集群
支持事务 ACID 可以替代 MySQL 的加强版数据库
一个可以视为 MySQL 集群的企业级数据库, 用来替代昂贵的 Oracle 集群
一个融合内存缓存技术 NoSQL 技术 HDFS 大数据的新型 SQL Server
结合传统数据库和新型分布式数据仓库的新一代企业级数据库产品
一个新颖的数据库中间件产品
以上内容来自 Mycat 官网 , 简单来说, Mycat 就是一个数据库中间件, 对于我们开发来说, 就像是一个代理, 当我们需要使用到多个数据库和需要进行分库分表的时候, 我们只需要在 mycat 里面配置好相关规则, 程序无需做任何修改, 只是需要将原本的数据源链接到 mycat 而已, 当然如果以前有多个数据源, 需要将数据源切换为单个数据源, 这样有个好处就是当我们的数据量已经很大的时候, 需要开始分库分表或者做读写分离的时候, 不用修改代码 (只需要改一下数据源的链接地址)
Mycat 读写分离设置
配置 Mycat 用户
Mycat 的用户就跟 MySQL 用户是同一个意思, 主要配置链接到 Mycat 的用户名以及密码, 以及能使用的逻辑库, 用户信息主要在 server.xml 中配置的, 具体如下
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- - - Licensed under the Apache License, Version 2.0 (the "License");
- - you may not use this file except in compliance with the License. - You
- may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0
- - - Unless required by applicable law or agreed to in writing, software -
- distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT
- WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the
- License for the specific language governing permissions and - limitations
- under the License. -->
- <!DOCTYPE mycat:server SYSTEM "server.dtd">
- <mycat:server xmlns:mycat="http://io.mycat/">
- <system>
- <property name="defaultSqlParser">druidparser</property>
- <!-- <property name="useCompression">1</property>--> <!--1 为开启 mysql 压缩协议 -->
- <!-- <property name="processorBufferChunk">40960</property> -->
- <!--
- <property name="processors">1</property>
- <property name="processorExecutor">32</property>
- -->
- <!-- 默认是 65535 64K 用于 sql 解析时最大文本长度 -->
- <!--<property name="maxStringLiteralLength">65535</property>-->
- <!--<property name="sequnceHandlerType">0</property>-->
- <!--<property name="backSocketNoDelay">1</property>-->
- <!--<property name="frontSocketNoDelay">1</property>-->
- <!--<property name="processorExecutor">16</property>-->
- <!--
- <property name="mutiNodeLimitType">1</property> 0: 开启小数量级 (默认) ;1: 开启亿级数据排序
- <property name="mutiNodePatchSize">100</property> 亿级数量排序批量
- <property name="processors">32</property> <property name="processorExecutor">32</property>
- <property name="serverPort">8066</property> <property name="managerPort">9066</property>
- <property name="idleTimeout">300000</property> <property name="bindIp">0.0.0.0</property>
- <property name="frontWriteQueueSize">4096</property> <property name="processors">32</property> -->
- </system>
- <user name="raye">
- <property name="password">rayewang</property>
- <property name="schemas">separate</property>
- </user>
- </host>
- </mycat:server>
其中 <user name="raye"> 定义了一个名为 raye 的用户, 标签 user 中的
<property name="password">rayewang</property>
定义了用户的密码,
<property name="schemas">separate</property>
定义了用户可以使用的逻辑库
配置 Mycat 逻辑库
Mycat 的配置有很多, 不过因为我们只是使用 Mycat 的读写分类的功能, 所以用到的配置并不多, 只需要配置一些基本的, 当然本文也只是会介绍到读写分离相关的配置, 其他配置建议读者自己查看一下文档, 或者通过其他方式了解, 逻辑库是在 schema.xml 中配置的
首先介绍 Mycat 逻辑库中的一些配置标签
schema
schema 标签是用来定义逻辑库的, schema 有四个属性 dataNode , checkSQLschema , sqlMaxLimit , name
dataNode 标签属性用于绑定逻辑库到某个具体的 database 上, 1.3 版本如果配置了 dataNode, 则不可以配置分片表, 1.4 可以配置默认分片, 只需要配置需要分片的表即可
name 是定义当前逻辑库的名字的, 方便 server.xml 中定义用户时的引用
checkSQLschema 当该值设置为 true 时, 如果我们执行语句 select * from separate.users; 则 MyCat 会把语句修改 为 select * from users; 即把表示 schema 的字符去掉, 避免发送到后端数据库执行时报 (ERROR 1146 (42S02): Table separate.users doesnt exist) 不过, 即使设置该值为 true , 如果语句所带的是并非是 schema 指定的名字, 例如: select * from db1.users; 那么 MyCat 并不会删除 db1 这个字段, 如果没有定义该库的话则会报错, 所以在提供 SQL 语句的最好是不带这个字段
sqlMaxLimit 当该值设置为某个数值时每条执行的 SQL 语句, 如果没有加上 limit 语句, MyCat 也会自动的加上所对应的值例如设置值为 100, 执行 select * from users; 的效果为和执行 select * from users limit 100; 相同设置该值的话, MyCat 默认会把查询到的信息全部都展示出来, 造成过多的输出所以, 在正常使用中, 还是建议加上一个值, 用于减少过多的数据返回当然 SQL 语句中也显式的指定 limit 的大小, 不受该属性的约束需要注意的是, 如果运行的 schema 为非拆分库的, 那么该属性不会生效需要手动添加 limit 语句
schema 标签中有标签 table 用于定义不同的表分片信息, 不过我们只是做读写分离, 并不会用到, 所以这里就不多介绍了
dataNode
dataNode dataNode 标签定义了 MyCat 中的数据节点, 也就是我们通常说所的数据分片一个 dataNode 标签就是一个独立的数据分片, dataNode 有 3 个属性: name , dataHost , database
name 定义数据节点的名字, 这个名字需要是唯一的, 此名字是用于 table 标签和 schema 标签中引用的
dataHost 该属性用于定义该分片属于哪个数据库实例的, 属性值是引用 dataHost 标签上定义的 name 属性
database 该属性用于定义该分片属性哪个具体数据库实例上的具体库, 因为这里使用两个纬度来定义分片, 就是: 实例 + 具体的库因为每个库上建立的表和表结构是一样的所以这样做就可以轻松的对表进行水平拆分
dataHost
dataHost 是定义真实的数据库连接的标签, 该标签在 mycat 逻辑库中也是作为最底层的标签存在, 直接定义了具体的数据库实例读写分离配置和心跳语句, dataHost 有 7 个属性: name , maxCon , minCon , balance , writeType , dbType , dbDriver , 有 2 个标签 heartbeat , writeHost , 其中 writeHost 标签中又包含一个 readHost 标签
name 唯一标识 dataHost 标签, 供 dataNode 标签使用
maxCon 指定每个读写实例连接池的最大连接也就是说, 标签内嵌套的 writeHostreadHost 标签都会使用这个属性的值来实例化出连接池的最大连接数
minCon 指定每个读写实例连接池的最小连接, 初始化连接池的大小
balance 读取负载均衡类型
balance="0", 不开启读写分离机制, 所有读操作都发送到当前可用的 writeHost 上
balance="1", 全部的 readHost 与 stand by writeHost 参与 select 语句的负载均衡, 简单的说, 当双主双从模式 (M1->S1,M2->S2, 并且 M1 与 M2 互为主备), 正常情况下, M2,S1,S2 都参与 select 语句的负载均衡
balance="2", 所有读操作都随机的在 writeHostreadhost 上分发
balance="3", 所有读请求随机的分发到 wiriterHost 对应的 readhost 执行, writerHost 不负担读压力
writeType 写入负载均衡类型, 目前的取值有 3 种:
writeType="0", 所有写操作发送到配置的第一个 writeHost, 第一个挂了切到还生存的第二个 writeHost, 重新启动后已切换后的为准, 切换记录在配置文件中: dnindex.properties .
writeType="1", 所有写操作都随机的发送到配置的 writeHost
dbType 指定后端连接的数据库类型, 目前支持二进制的 mysql 协议, 还有其他使用 JDBC 连接的数据库例如: mongodboraclespark 等
dbDriver 指定连接后端数据库使用的 Driver, 目前可选的值有 native 和 JDBC 使用 native 的话, 因为这个值执行的 是二进制的 mysql 协议, 所以可以使用 mysql 和 maridb 其他类型的数据库则需要使用 JDBC 驱动来支持从 1.6 版本开始支持 postgresql 的 native 原始协议 如果使用 JDBC 的话需要将符合 JDBC 4 标准的驱动 JAR 包放到 MYCATlib 目录下, 并检查驱动 JAR 包中包括如下目录结构的文件: META-INFservicesjava.sql.Driver 在这个文件内写上具体的 Driver 类名, 例如: com.mysql.jdbc.Driver
heartbeat 这个标签内指明用于和后端数据库进行心跳检查的语句例如, MYSQL 可以使用 select user(),Oracle 可以使用 select 1 from dual 等 这个标签还有一个 connectionInitSql 属性, 主要是当使用 Oracla 数据库时, 需要执行的初始化 SQL 语句就这个放到这里面来例如: alter session set nls date format='yyyy-mm-dd hh24:mi:ss'
writeHost , readHost 这两个标签都指定后端数据库的相关配置给 mycat, 用于实例化后端连接池唯一不同的是, writeHost 指定写实例 readHost 指定读实例, 组着这些读写实例来满足系统的要求 在一个 dataHost 内可以定义多个 writeHost 和 readHost 但是, 如果 writeHost 指定的后端数据库宕机, 那么这个 writeHost 绑定的所有 readHost 都将不可用另一方面, 由于这个 writeHost 宕机系统会自动的检测到, 并切换到备用的 writeHost 上去, 这 2 个标签属性都一致, 拥有 host , url , password , user , weight , usingDecrypt 等属性
host 用于标识不同实例, 一般 writeHost 我们使用 M1,readHost 我们用 S1
url 真实数据库的实例的链接地址, 如果是使用 native 的 dbDriver, 则一般为 address:port 这种形式用 JDBC 或其他的 dbDriver, 则需要特殊指定当使用 JDBC 时则可以这么写: jdbc:mysql://localhost:3306/
user 真实数据库实例的链接用户名
password 真实数据库实例的链接密码
weight 权重 配置在 readhost 中作为读节点的权重, 主要用于多台读取的数据库实例机器配置不同的情况, 可以根据权重调整访问量
usingDecrypt 是否对密码加密默认 0 否 如需要开启配置 1, 同时使用加密程序对密码加密
注意, readHost 是在 writeHost 标签内的, 不是单独的
以下是我的读写分离配置文件
- <?xml version="1.0"?>
- <!DOCTYPE mycat:schema SYSTEM "schema.dtd">
- <mycat:schema xmlns:mycat="http://io.mycat/">
- <schema name="separate" checkSQLschema="false" sqlMaxLimit="100" dataNode="dn1"/>
- <dataNode name="dn1" dataHost="localhost1" database="test" />
- <dataHost name="localhost1" maxCon="1000" minCon="10" balance="3"
- writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
- <heartbeat>select user()</heartbeat>
- <!-- can have multi write hosts -->
- <writeHost host="hostM1" url="192.168.1.126:3307" user="root"
- password="123456">
- <!-- can have multi read hosts -->
- <readHost host="hostS2" url="192.168.1.126:3308" user="root" password="123456" />
- </writeHost>
- </dataHost>
- </mycat:schema>
前面已经差不多都解释清楚了, 因为我只是用的基本的主从复制, 所以我的将 dataHost 的 balance 设置成了 3
启动 mycat, 然后用数据库连接工具连接到 mycat, 可以测试是否配置成功, 最简单的就是通过修改从库的数据, 这样方便查看到底是运行到哪个库上面了, 另外由于我是基于 docker 启动的 mycat, 所以如果是直接在系统中运行的 mycat 的, 可以去看官方文档, 看看到底怎么启动 mycat
来源: https://www.thinksaas.cn/group/topic/838999/