俗不知,学一个工具首先需要知道它可以解决什么问题……然后不假思索的灵活的运用到我们的项目中
mycat官网:http://www.mycat.io/
当我们的应用只需要一台数据库服务器的时候我们并不需要MyCAT,当涉及到分库分表、跨库关联查询、读写分离、跨机房容灾时MyCat必不可少。
在我管理的项目中,涉及到一个分库操作:
- ems-uic 用户信息中心
- ems-cic 企业信息中心
- ems-oic 开放信息中心
在真实场景中,cic中有些场景中需要使用uic用户昵称,这种情况已经怎么办?
实现“冗余字段”还是选择“冗余表”?
那如果数据发生修改了怎么办?
冗余表可以使用mysql单表同步来解决,可是冗余字段怎么解决?数据量大n条数据参与修改会不会影响性能?
今天我们不采用数据同步的功能解决问题,因为今天的主题是mycat!
其它方案:
- mysql主从同步
- canal数据同步
将来接下来的日子告诉大家,敬请期待……
跨库关联查询
全局表
一个真实的业务系统中,往往存在大量的类似字典表的表,这些表基本上很少变动,字典表具有以下几个特性:
- 变动不频繁
- 数据量总体变化不大
- 数据规模不大,很少有超过数十万条记录。
对于这类的表,在分片的情况下,当业务表因为规模而进行分片以后,业务表与这些附属的字典表之间的关联,就成了比较棘手的问题,所以Mycat中通过数据冗余来解决这类表的join,即所有的分片都有一份数据的拷贝,所有将字典表或者符合字典表特性的一些表定义为全局表。
数据冗余是解决跨分片数据join的一种很好的思路,也是数据切分规划的另外一条重要规则。以上官方介绍,意思就是只需要把需要关联查询的表设置成为全局表就可以解决此类问题
//schema.xml
<schema name="integral_db" checkSQLschema="false" sqlMaxLimit="10000">
<table name="integral_quantify" primaryKey="quantify_id" dataNode="integralDN1,integralDN2" rule="company-by-murmur" />
<table name="integral_quantify_info" primaryKey="quantify_id" dataNode="integralDN1,integralDN2" rule="company-by-murmur" />
<table name="integral_quantify_record" primaryKey="id" dataNode="integralDN1,integralDN2" rule="company-by-murmur" />
<table name="integral_quantify_modify_record" primaryKey="id" dataNode="integralDN1,integralDN2" rule="company-by-murmur" />
<table name="integral_op" primaryKey="id" dataNode="integralDN1,integralDN2" rule="company-by-murmur" />
<table name="integral_prize" primaryKey="id" dataNode="integralDN1,integralDN2" rule="company-by-murmur" />
<table name="integral_prize_setting" primaryKey="id" dataNode="integralDN1,integralDN2" rule="company-by-murmur" />
<table name="integral_quantify_setting" primaryKey="id" dataNode="integralDN1,integralDN2" rule="company-by-murmur" />
<!--type="global" 指定表为全局表-->
<table name="sys_param_cemp_addscore" type="global" primaryKey="id" dataNode="jifenzhiDN" />
<table name="sys_employee_ext" type="global" primaryKey="id" dataNode="jifenzhiDN" />
<table name="sys_employee_organization" type="global" primaryKey="id" dataNode="jifenzhiDN" />
<table name="sys_organization" type="global" primaryKey="id" dataNode="jifenzhiDN" />
<table name="sys_company" type="global" primaryKey="id" dataNode="jifenzhiDN" />
<table name="sys_employee" type="global" primaryKey="id" dataNode="jifenzhiDN" />
<table name="sys_employee_wechat" type="global" primaryKey="id" dataNode="jifenzhiDN" />
<table name="sys_employee_contact" type="global" primaryKey="id" dataNode="jifenzhiDN" />
<table name="sms_msg_send" type="global" primaryKey="id" dataNode="jifenzhiDN" />
</schema>
读写分离
<dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"writeType="0" dbType="mysql" dbDriver="native" switchType="1" slaveThreshold="100">
<heartbeat>select user()</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM1" url="172.16.2.10:3306" user="web" password="123456">
<!-- can have multi read hosts -->
<readHost host="hostS1" url="172.16.2.10:3307" user="web" password="123456" />
</writeHost>
</dataHost>
容灾机制
//hostM2恢复后需要保持数据一致性
<!-- 使用MyCat托管MySQL主从切换 -->
<!-- 定义数据主机dtHost2,连接到MySQL读写分离集群,并配置了读写分离和主从切换 -->
<dataHost name="dtHost2" maxCon="500" minCon="20" balance="1" writeType="0" dbType="mysql" dbDriver="native" switchType="2" slaveThreshold="100">
<!-- 通过show slave status检测主从状态,当主宕机以后,发生切换,从变为主,原来的主变为从,这时候show slave
status就会发生错误,因为原来的主没有开启slave,不建议直接使用switch操作,而是在DB中做主从对调。 -->
<heartbeat>show slave status</heartbeat>
<!-- can have multi write hosts -->
<writeHost host="hostM2" url="192.168.1.205:3306" user="root" password="www.roncoo.com" />
<writeHost host="hostS2" url="192.168.1.206:3306" user="root" password="www.roncoo.com" />
</dataHost>
<!-- 参数balance决定了哪些MySQL服务器参与到读SQL的负载均衡中 -->
<!-- balance="0",为不开启读写分离,所有读操作都发送到当前可用的writeHost上-->
<!-- balance="1",全部的readHost与stand by writeHost参与select语句的负载均衡-->
<!-- balance="2",所有读操作都随机的在writeHost、readHost上分发-->
<!-- MyCat1.4版本中,若想支持MySQL一主一从的标准配置,并且在主节点宕机的情况下,从节点还能读取数据,则需要在MyCat里配置为两个writeHost并设置balance="1" -->
<!-- writeType="0",所有写操作都发送到可用的writeHost上 -->
<!-- writeType="1",仅仅对于galera for mysql集群这种多主多节点都能写入的集群起效,此时Mycat会随机选择一个writeHost并写入数据,对于非galera for mysql集群,请不要配置writeType=1,会导致数据库不一致的严重问题 -->
分库分表
//在我们真实的项目中,我们拥有16个分片
//dataNode:分片所在的库、rule:分片规则
<table name="integral_quantify" primaryKey="quantify_id" dataNode="integralDN1,integralDN2" rule="company-by-murmur" />
<table name="integral_quantify_info" primaryKey="quantify_id" dataNode="integralDN1,integralDN2" rule="company-by-murmur" />
//dataNode
<dataNode name="integralDN1" dataHost="localhost1" database="integral_db" />
<dataNode name="integralDN2" dataHost="localhost1" database="integral_db2" />
//rule.xml
<tableRule name="company-by-murmur">
<rule>
<columns>company_id</columns>
<algorithm>murmur</algorithm>
</rule>
</tableRule>
<function name="murmur" class="io.mycat.route.function.PartitionByMurmurHash">
<property name="seed">0</property><!-- 默认是0 -->
<property name="count">2</property><!-- 要分片的数据库节点数量,必须指定,否则没法分片 -->
<property name="virtualBucketTimes">160</property><!-- 一个实际的数据库节点被映射为这么多虚拟节点,默认是160倍,也就是虚拟节点数是物理节点数的160倍 -->
<!-- <property name="weightMapFile">weightMapFile</property> 节点的权重,没有指定权重的节点默认是1。以properties文件的格式填写,以从0开始到count-1的整数值也就是节点>索引为key,以节点权重值为值。所有权重值必须是正整数,否则以1代替 -->
<!-- <property name="bucketMapPath">/etc/mycat/bucketMapPath</property>
用于测试时观察各物理节点与虚拟节点的分布情况,如果指定了这个属性,会把虚拟节点的murmur hash值与物理节点的映射按行输出到这个文件,没有默认值,如果不指定,就不
会输出任何东西 -->
</function>
小福利
在项目中涉及到16个分片,指定数据迁移使用的方法
- 判断数据存在那个分片中:
EXPLAIN SELECT * FROM integral_quantify WHERE company_id="***";
- MySQL导出指定条件的数据
//mysqldump参数说明:http://www.cnblogs.com/qq78292959/p/3637135.html
//-c 使用完整的insert语句(包含列名称)。这么做能提高插入效率,但是可能会受到max_allowed_packet参数的影响而导致插入失败
//-t 只导出数据,而不添加CREATE TABLE 语句。
//--skip-add-locks 取消LOCK语句
mysqldump -uax -p123456 -t -c --skip-add-locks integral_db integral_quantify_record -w "record_date>='2017-03-01'" > /root/20170301/integral_db_01_integral_quantify_record_201703_0309.sql
- 登录MyCAT
mysql -uroot -h127.0.0.1 -p8066 -Dintegral_db
- 导入数据
source /root/integral_db_01_integral_prize.sql
很高兴认识你,我们都一样,有过迷茫却从未放弃;害怕孤独可从不寂寞。