赞
踩
如今随着互联网的发展,数据的量级也是成指数的增长,从GB到TB到PB。对数据的各种操作也是愈加的困难,传统的关系性数据库已经无法满足快速查询与插入数据的需求。
阿里数据中心内景( 阿里、百度、腾讯这样的互联网巨头,数据量据说已经接近EB级)
解决方案1: 使用NoSQL数据库, 通过降低数据的安全性,减少对事务的支持,减少对复杂查询的支持,来获取性能上的提升。
解决方案2: NoSQL并不是万能的,就比如有些使用场景是绝对要有事务与安全指标的, 所以还是要用关系型数据库, 这时候就需要搭建MySQL数据库集群,为了提高查询性能, 将一个数据库的数据分散到不同的数据库中存储, 通过这种数据库拆分的方法来解决数据库的性能问题。
简单来说,就是指通过某种特定的条件,将我们存放在同一个数据库中的数据分散存放到多个数据库(主机)上面,以达到分散单台设备负载的效果。
注意:
分库分表包括: 垂直分库、垂直分表、水平分库、水平分表 四种方式。
针对数据量巨大的单张表(比如订单表),按照规则把一张表的数据切分到多张表里面去。 但是这些表还是在同一个库中,所以库级别的数据库操作还是有IO瓶颈。
总结
◇ 垂直分表: 将一个表按照字段分成多表,每个表存储其中一部分字段。
◇ 垂直分库: 根据表的业务不同,分别存放在不同的库中,这些库分别部署在不同的服务器.
◇ 水平分库: 把一张表的数据按照一定规则,分配到不同的数据库,每一个库只有这张表的部分数据.
◇ 水平分表: 把一张表的数据按照一定规则,分配到同一个数据库的多张表中,每个表只有这个表的部分数据.
当数据库进行分库分表后,数据由一个数据库分散到多个数据库中。此时系统要查询时需要切换不同的数据库进行查询,那么系统如何知道要查询的数据在哪个数据库中?当添加一条记录时要向哪个数据库中插入呢?这些问题处理起来都是非常的麻烦。
这种情况下可以使用一个数据库中间件==mycat==来解决相关的问题。
MyCat 是目前最流行的基于 java 语言编写的数据库中间件,是一个实现了 MySQL 协议的服务器,前端用户可以把它看作是一个数据库代理,用 MySQL 客户端工具和命令行访问,而其后端可以用MySQL 原生协议与多个 MySQL 服务器通信,也可以用 JDBC 协议与大多数主流数据库服务器通信,其核心功能是分库分表和读写分离,即将一个大表水平分割为 N 个小表,存储在后端MySQL服务器里或者其他数据库里。
MyCat对于我们Java程序员来说,就是一个近似等于 MySQL 的数据库服务器,你可以用连接 MySQL的方式去连接 Mycat(除了端 口不同,默认的 Mycat 端口是 8066 而非 MySQL 的 3306,因此需要在连接字符串上增加端口信息)
我们可以像使用MySQL一样使用MyCat,Mycat 可以管理若干 MySQL 数据库,同时实现数据的存储和操作
分片表:
是指那些原有的很大数据的表,需要切分到多个数据库的表,这样,每个分片都有一部分数据,所有分片构成了完整的数据。 总而言之就是需要进行分片的表。
非分片表:
一个数据库中并不是所有的表都很大,某些表是可以不用进行切分的,非分片是相对分片表来说的,就是那些不需要进行数据切分的表。
第一步: 搭建3台虚拟机
第二步: server01与server02 安装MySQL数据库服务器,保证版本一致
server01 192.168.52.10
server02 192.168.52.11
第三步: 创建数据库
注意: 提前安装好JDK
#启动命令:
./mycat start
#停止命令:
./mycat stop
#重启命令:
./mycat restart
#查看状态:
./mycat status
./mycat console
schema标签
Schema.xml作为MyCat中重要的配置文件之一,管理着MyCat的逻辑库、表、分片规则、DataNode以及DataSource。弄懂这些配置,是正确使用MyCat的前提。这里就一层层对该文件进行解析。
<!-- 逻辑库 -->
<schema name="lagou" checkSQLschema="true" sqlMaxLimit="100" >
</schema>
table标签
table标签定义了 Mycat 中的逻辑表,所有需要拆分的表都需要在这个标签中定义
<schema name="lagou" checkSQLschema="true" sqlMaxLimit="100" >
<table name="pay_order" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" primaryKey="id" autoIncrement="true" ></table>
</schema>
dataNode标签
dataNode标签定义了 MyCat 中的分片节点,也就是我们通常说所的数据分片。
<dataNode name="dn1" dataHost="localhost1" database="lagou1" />
<dataNode name="dn2" dataHost="localhost2" database="lagou2" />
<dataNode name="dn3" dataHost="localhost2" database="lagou3" />
dataHost标签
dataHost标签在 Mycat 逻辑库中也是作为最底层的标签存在,直接定义了具体的数据库实例、读写分离配置和心跳语句
<!-- 节点主机 -->
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="192.168.52.10:3306" user="root" password="QiDian@666">
</writeHost>
</dataHost>
<dataHost name="localhost2" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM2" url="192.168.52.11:3306" user="root" password="QiDian@666">
</writeHost>
</dataHost>
heartbeat标签
heartbeat标签内指明用于和后端数据库进行心跳检查的语句。例如:MySQL 可以使用 select user()、Oracle 可以 使用 select 1 from dual 等
<heartbeat>select user()</heartbeat>
writeHost和readHost标签
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="0" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<writeHost host="hostM1" url="192.168.52.10:3306" user="root" password="QiDian@666">
</writeHost>
</dataHost>
server.xml几乎保存了所有 mycat 需要的系统配置信息。
这个标签主要用于定义登录 mycat 的用户和权限。
<user name="root" defaultAccount="true">
<property name="password">123456</property>
<property name="schemas">lagou</property>
<property name="defaultSchema">lagou</property>
</user>
./mycat start
./mycat status
mysql -uroot -p123456 -h127.0.0.1 -P8066
此配置文件可以不用修改,使用默认即可。
<mycat:rule xmlns:mycat="http://io.mycat/">
<tableRule name="sharding-by-intfile">
<rule>
<columns>sharding_id</columns>
<algorithm>hash-int</algorithm>
</rule>
</tableRule>
</mycat:rule>
<function name="hash-int" class="io.mycat.route.function.PartitionByFileMap">
<property name="mapFile">partition-hash-int.txt</property>
</function>
name:指定算法的名字。
class:制定路由算法具体的类名字。
property: 为具体算法需要用到的一些属性。
Mycat常用分片配置示例:
<tableRule name="auto-sharding-long">
<rule>
<columns>id</columns>
<algorithm>rang-long</algorithm>
</rule>
</tableRule>
<function name="rang-long" class="io.mycat.route.function.AutoPartitionByLong">
<property name="mapFile">autopartition-long.txt</property>
</function>
autopartition-long.txt文件:
0-200000=0
200000-400000=1
0-200000范围分配给节点0
200000-400000范围分配给节点1
<!-- 枚举分片 -->
<tableRule name="sharding-by-intfile">
<rule>
<columns>sharding_id</columns>
<algorithm>hash-int</algorithm>
</rule>
</tableRule>
<function name="hash-int" class="io.mycat.route.function.PartitionByFileMap">
<property name="mapFile">partition-hash-int.txt</property>
</function>
beijing=0
wuhan=1
shanghai=2
<tableRule name="mod-long">
<rule>
<columns>id</columns>
<algorithm>mod-long</algorithm>
</rule>
</tableRule>
<function name="mod-long" class="io.mycat.route.function.PartitionByMod">
<!-- how many data nodes -->
<property name="count">3</property>
</function>
<!-- schema 逻辑库 --> <schema name="lagou" checkSQLschema="true" sqlMaxLimit="100" > <table name="pay_order" dataNode="dn1,dn2,dn3" rule="auto-sharding-long" primaryKey="id" autoIncrement="true" > </table> </schema> ========================================================================================= <!-- 自动分片 --> <tableRule name="auto-sharding-long"> <rule> <columns>id</columns> <algorithm>rang-long</algorithm> </rule> </tableRule> <function name="rang-long" class="io.mycat.route.function.AutoPartitionByLong"> <property name="mapFile">autopartition-long.txt</property> </function>
# range start-end ,data node index
# K=1000,M=10000.
0-1k=0
1k-2k=1
2k-3k=2
#停止命令:
./mycat stop
#重启命令:
./mycat restart
DROP TABLE IF EXISTS pay_order;
CREATE TABLE pay_order (
id BIGINT(20) PRIMARY KEY,
user_id INT(11) NOT NULL ,
product_name VARCHAR(128) ,
amount DECIMAL(12,2)
);
INSERT INTO pay_order(id,user_id,product_name,amount) VALUES(2001,1,"面试宝典",15.8);
在实现分库分表的情况下,数据库自增主键已无法保证自增主键的全局唯一。为此,Mycat 提供了全局sequence,并且提供了包含本地配置和数据库配置等多种实现方式。
server.xml文件中
<system>
<property name="sequnceHandlerType">0</property>
</system>
0 表示是表示使用本地文件方式。
1 表示的是根据数据库来生成
2 表示时间戳的方式 ID= 64 位二进制 (42(毫秒)+5(机器 ID)+5(业务编码)+12(重复累加)
此方式 Mycat 将 sequence 配置到文件中,当使用到 sequence 中的配置后,Mycat 会更新 classpath中的 sequence_conf.properties 文件中 sequence 当前的值。
PAY_ORDER.HISIDS=
PAY_ORDER.MINID=101
PAY_ORDER.MAXID=10000000
PAY_ORDER.CURID=100
其中 HISIDS 表示使用过的历史分段(一般无特殊需要可不配置),MINID 表示最小 ID 值,MAXID 表示最大ID 值,CURID 表示当前 ID 值
重启MyCat, 插入一条数据,不用指定id.
INSERT INTO pay_order(user_id,product_name,amount) VALUES(1,"xiao",12.8);
在实际的生产环境中, 数据的读写操作如果都在同一个数据库服务器中进行, 当遇到大量的并发读或者写操作的时候,是没有办法满足实际需求的,数据库的吞吐量将面临巨大的瓶颈压力.
读写分离的数据节点中的数据内容是一致。
MyCat的读写分离是建立在MySQL主从复制基础之上实现的,所以必须先搭建MySQL的主从复制架构。
主从复制的用途
主从部署必要条件
主从复制的原理
Mysql的主从复制至少是需要两个Mysql的服务,当然Mysql的服务是可以分布在不同的服务器上,也可以在一台服务器上启动多个服务。
-- 创建数据库
CREATE DATABASE test CHARACTER SET utf8;
-- 创建表
CREATE TABLE users (
id INT(11) PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20) DEFAULT NULL,
age INT(11) DEFAULT NULL
);
-- 插入数据
INSERT INTO users VALUES(NULL,'user1',20);
INSERT INTO users VALUES(NULL,'user2',21);
INSERT INTO users VALUES(NULL,'user3',22);
vim /etc/my.cnf
插入下面的内容
lower_case_table_names=1
log-bin=mysql-bin
server-id=1
binlog-do-db=test
binlog_ignore_db=mysql
service mysqld restart
-- 创建账号
GRANT REPLICATION SLAVE ON *.* TO 'slave'@'192.168.52.11' IDENTIFIED BY 'Qwer@1234';
-- 执行以下命令锁定数据库以防止写入数据。
FLUSH TABLES WITH READ LOCK;
unlock tables;
server-id=2
#重启
service mysqld restart
STOP SLAVE;
CHANGE MASTER TO MASTER_HOST='192.168.52.10',
MASTER_USER='slave',
MASTER_PASSWORD='Qwer@1234',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=0,
MASTER_CONNECT_RETRY=10;
#编辑auto.cnf
vim /var/lib/mysql/auto.cnf
#修改UUID的值
server-uuid=a402ac7f-c392-11ea-ad18-000c2980a208
#重启
service mysqld restart
start slave;
#查看状态
SHOW SLAVE STATUS;
#命令行下查看状态 执行
SHOW SLAVE STATUS \G;
注意: 这两个参数的值,必须是 Yes,否则就要进行错误的排查.
-- 在主库插入一条数据,观察从库是否同步
INSERT INTO users VALUES(NULL,'user4',23);
数据库读写分离对于大型系统或者访问量很高的互联网应用来说,是必不可少的一个重要功能。对于MySQL来说,标准的读写分离是主从模式,一个写节点Master后面跟着多个读节点,读节点的数量取决于系统的压力,通常是1-3个读节点的配置
在schema.xml文件中配置Mycat读写分离。使用前需要搭建MySQL主从架构,并实现主从复制,Mycat不负责数据同步问题。
<user name="root" defaultAccount="true">
<property name="password">123456</property>
<property name="schemas">test</property>
<property name="defaultSchema">test</property>
</user>
<schema name="test" checkSQLschema="true" sqlMaxLimit="100">
<table name="users" dataNode="dn4" ruleRequired="false" primaryKey="id" autoIncrement="true" >
</table>
</schema>
<!-- 读写分离 -->
<dataNode name="dn4" dataHost="localhost3" database="test" />
<!-- 读写分离 -->
<dataHost name="localhost3" maxCon="1000" minCon="10" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- 主 -->
<writeHost host="M1" url="192.168.52.10:3306" user="root" password="QiDian@666">
<!-- 从 -->
<readHost host="S1" url="192.168.52.11:3306" user="root" password="QiDian@666" weight="1" />
</writeHost>
</dataHost>
balance参数:
writeType参数:
重启MyCat
./mycat restart
执行查询和插入操作
INSERT INTO users(NAME,age) VALUES('测试abc',26);
SELECT * FROM users;
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。