目录导引
mycat 概述
mycat 原则及限制
构建 mycat docker 镜像
mycat 概述
Mycat基于阿里开源的Cobar产品而研发,Cobar的稳定性、可靠性、优秀的架构和性能以及众多成熟的使用案例使得Mycat一开始就拥有一个很好的起点;Mycat是一个彻底开源的,面向企业应用开发的大数据库集群,支持事务、ACID、可以替代MySQL的加强版数据库,支持MySQL、Oracle、DB2、SQL Server、PostgreSQL等DB的常见SQL语法,遵守Mysql原生协议,跨语言,跨平台,跨数据库的通用中间件代理。
我们使用mycat主要是因为其支持Mysql等数据库,且具有分库分表的功能,下文会先介绍Mycat的使用原则,以及mycat目前具有的一些限制,具体在实际运用业务场景中的缺陷等。
mycat 原则及限制
分库分表原则:
能不分就不分,1000 万以内的表,不建议分片,通过合适的索引,读写分离等方式,可以很好的解决性能问题。
分片数量尽量少,分片尽量均匀分布在多个 DataHost 上,因为一个查询 SQL跨分片越多,则总体性能越差,虽然要好于所有数据在一个分片的结果,只在必要的时候进行扩容,增加分片数量。
分片规则需要慎重选择,分片规则的选择,需要考虑数据的增长模式,数据的访问模式,分片关联性问题,以及分片扩容问题,最近的分片策略为范围分片,枚举分片,一致性 Hash 分片,这几种分片都有利于扩容。
尽量不要在一个事务中的 SQL 跨越多个分片,分布式事务一直是个不好处理的问题。
查询条件尽量优化,尽量避免 Select * 的方式,大量数据结果集下,会消耗大量带宽和 CPU 资源,查询尽量避免返回大量结果集,并且尽量为频繁使用的查询语句建立索引。
数据拆分原则:
达到一定数量级才拆分(800 万)
不到 800 万但跟大表(超 800 万的表)有关联查询的表也要拆分,在此称为大表关联表
大表关联表如何拆:小于 100 万的使用全局表;大于 100 万小于 800 万跟大表使用同样的拆分策略;无法跟大表使用相同规则的,可以考虑从 java 代码上分步骤查询,不用关联查询,或者破例使用全局表。
破例的全局表:如 item_sku 表250万,跟大表关联了,又无法跟大表使用相同拆分策略,也做成了全局表。破例的全局表必须满足的条件:没有太激烈的并发 update,如多线程同时 update 同一条 id=1 的记录。虽有多线程 update,但不是操作同一行记录的不在此列。多线程 update 全局表的同一行记录会死锁。批量 insert没问题。
拆分字段是不可修改的
拆分字段只能是一个字段,如果想按照两个字段拆分,必须新建一个冗余字段,冗余字段的值使用两个字段的值拼接而成(如大区+年月拼成 zone_yyyymm 字段)。
拆分算法的选择和合理性评判:按照选定的算法拆分后每个库中单表不得超过 800 万
能不拆的就尽量不拆。如果某个表不跟其他表关联查询,数据量又少,直接不拆分,使用单库即可
DataNode 的分布问题:
DataNode 代表 MySQL 数据库上的一个 Database,因此一个分片表的 DataNode 的分布可能有以下几种:
所有 DataNode 都在一个 DataHost 上
在几个 DataHost 上,但有连续性,比如 dn1 到 dn5 在 Server1 上,dn6 到 dn10 在 Server2 上,依次类推
在几个 DataHost 上,但均匀分布,比如 dn1,dn2,d3 分别在 Server1,Server2,Server3 上,dn4 到 dn5 又重复如此
一般情况下,不建议第(1)种;第(2)种适合范围分片;在大多数情况下,最后一种情况最理想,因为当一个表的数据均匀分布在几个物理机上的时候,跨分片查询或者随机查询,都是到不同的机器上去执行,并行度最高,IO 竞争也最小,因此性能最好。
Mycat 目前存在的限制:
除了分片规则相同、ER 分片、全局表、以及 SharedJoin,其他表之间的 Join 问题目前还没有很好的解决,需要自己编写 Catlet 来处理。
不支持 Insert into 中不包括字段名的 SQL
insert into x select from y 的 SQL,若 x 与 y 不是相同的分片规则,则不被支持,此时会涉及到跨分片转移。
跨分片的事务,目前只是弱 XA 模式,还没完全实现 XA 模式。
分片的 Table,目前不能执行 Lock Table 这样的语句,因为这种语句会随机发到某个节点,也不会全部分片锁定,经常导致死锁问题,此类问题常常出现在 sqldump 导入导出 SQL 数据的过程中。
目前 sql 解析器采用 Druid,在某些 sql 例如 order,group,sum ,count 条件下,这类操作会出现兼容问题,如:select t.name as name1 from test order by t.name,这条语句 select 列的别名与 order by 不一致解析器会出现异常,所以在对列加别名时候要注意这类操作
异常,特别是由 jpa 等类似的框架生成的语句会有兼容问题开发框架方面,虽然支持 Hibernate,但不建议使用 Hibernate,而是建议 Mybatis 以及直接 JDBC 操作,原因 Hibernat 无法控制 SQL 的生成,无法做到对查询 SQL 的优化,导致大数量下的性能问题。此外,事务方面,建议自己手动控制,查询语句尽量走自动提交事务模式,这样 Mycat 的读写分离会被用到,提升性能很明显。
构建mycat的docker镜像
将mycat源码打成docker镜像,是为了部署方便,减少对JDK环境变量的配置,因为mycat是使用java代码编写的,部署java项目会涉及到JDK等环境变量的配置,而构建成docker镜像后,会方便很多,不只是减少了环境变量的配置,也是为了部署简单方便,配置修改容易;后续会使用docker和k8s运行mycat服务,都是需要将mycat的docker镜像。
在linux服务器上按照步骤完成下列操作,即可将mycat打成docker镜像,下列是使用mycat的1.6.7.4-release版本,因为后续会涉及到单库分表和多库分表的批量插入测试,而单库分表的批量插入,只在1.6.7.4-release版本及以后才支持
1、下载官网tar.gz包
1.6.
2、解压
1.6.
3、编写Dockerfile文件
8
在Dockerfile文件中添加VOLUME /mycat/conf/
,主要是因为mycat运行需要配置schema.xml、rule.xml、server.xml等配置文件,这些配置文件会经常变化,不想在变化之后重新打docker镜像,就需要将配置文件通过挂载的方式传入到docker镜像中
4、此时linux服务器中的目录结构如下,mycat源码和Dockerfile处于统一目录下
5、执行命令,将mycat打成docker镜像
1.6.
6、运行mycat,将端口8066和9066映射出来
-d -p
上面说过,mycat的配置文件会经常变动,所以需要将mycat配置文件通过 -v
命令挂载到容器中
sudo docker run -d -p 8066:8066 -p 9066:9066 -v /home/schema.xml:/mycat/conf/schema.xml -v /home/server.xml:/mycat/conf/server.xml --name mycat mycat:1.6.7.4
7、如果自己搭建了docker镜像仓库,可以将自己打的mycat docker镜像推到docker镜像仓库中
# 先打tag
参考:http://www.mycat.org.cn/document/mycat-definitive-guide.pdf
后续文章规划:
1、用k8s部署mycat构建成的docker镜像
2、测试mycat单库分表、多库分表、创建表和rename表、批量插入、跨库join等功能