1.非分片字段查问
Mycat中的路由后果是通过分片字段和分片办法来确定的。例如下图中的一个Mycat分库计划:
- 依据 tt_waybill 表的 id 字段来进行分片
- 分片办法为 id 值取 3 的模,依据模值确定在DB1,DB2,DB3中的某个分片
如果查问条件中有 id 字段的状况还好,查问将会落到某个具体的分片。例如:
mysql>select * from tt_waybill where id = 12330;
此时Mycat会计算路由后果
12330 % 3 = 0 –> DB1
并将该申请路由到DB1下来执行。
如果查问条件中没有 分片字段 条件,例如:
mysql>select * from tt_waybill where waybill_no =88661;
此时Mycat无奈计算路由,便发送到所有节点上执行:
DB1 –> select * from tt_waybill where waybill_no =88661;
DB2 –> select * from tt_waybill where waybill_no =88661;
DB3 –> select * from tt_waybill where waybill_no =88661;
如果该分片字段抉择度高,也是业务罕用的查问维度,个别只有一个或极少数个DB节点命中(返回后果集)。示例中只有3个DB节点,而理论利用中的DB节点数远超过这个,如果有50个,那么前端的一个查问,落到MySQL数据库上则变成50个查问,会极大耗费Mycat和MySQL数据库资源。
如果设计应用Mycat时有非分片字段查问,请思考放弃!
2.分页排序
先看一下Mycat是如何解决分页操作的,如果有如下Mycat分库计划:
一张表有30份数据分布在3个分片DB上,具体数据分布如下
DB1:[0,1,2,3,4,10,11,12,13,14]
DB2:[5,6,7,8,9,16,17,18,19]
DB3:[20,21,22,23,24,25,26,27,28,29]
(这个示例的场景中没有查问条件,所以都是全分片查问,也就没有假设该表的分片字段和分片办法)
当利用执行如下分页查问时
mysql>select * from table limit 2;
Mycat将该SQL申请散发到各个DB节点去执行,并接管各个DB节点的返回后果
DB1: [0,1]
DB2: [5,6]
DB3: [20,21]
但Mycat向利用返回的后果集取决于哪个DB节点最先返回后果给Mycat。如果Mycat最先收到DB1节点的后果集,那么Mycat返回给利用端的后果集为 [0,1],如果Mycat最先收到DB2节点的后果集,那么返回给利用端的后果集为 [5,6]。也就是说,雷同状况下,同一个SQL,在Mycat上执行时会有不同的返回后果。
在Mycat中执行分页操作时必须显示加上排序条件能力保障后果的正确性,上面看一下Mycat对排序分页的解决逻辑。
如果在后面的分页查问中加上了排序条件(如果表数据的列名为id)
mysql>select * from table order by id limit 2;
Mycat的解决逻辑如下图:
在有排序呢条件的状况下,Mycat接管到各个DB节点的返回后果后,对其进行最小堆运算,计算出所有后果集中最小的两条记录 [0,1] 返回给利用。
然而,当排序分页中有 偏移量 (offset)时,解决逻辑又有不同。如果利用的查问SQL如下:
mysql>select * from table order by id limit 5,2;
如果依照上述排序分页逻辑来解决,那么处理结果如下图:
Mycat将各个DB节点返回的数据 [10,11], [16,17], [20,21] 通过最小堆计算后返回给利用的后果集是 [10,11]。可是,对于利用而言,该表的所有数据明明是 0-29 这30个数据的汇合,limit 5,2 操作返回的后果集应该是 [5,6],如果返回 [10,11] 则是谬误的解决逻辑。
所以Mycat在解决 有偏移量的排序分页 时是另外一套逻辑——改写SQL 。如下图:
Mycat在下发有 limit m,n 的SQL语句时会对其进行改写,改写成 limit 0, m+n 来保障查问后果的逻辑正确性。所以,Mycat发送到后端DB上的SQL语句是
mysql>select * from table order by id limit 0,7;
各个DB返回给Mycat的后果集是
DB1: [0,1,2,3,4,10,11]
DB2: [5,6,7,8,9,16,17]
DB3: [20,21,22,23,24,25,26]
通过最小堆计算后失去最小序列 [0,1,2,3,4,5,6] ,而后返回偏移量为5的两个后果为 [5,6] 。
尽管Mycat返回了正确的后果,然而认真斟酌发现这类操作的解决逻辑是及其耗费(节约)资源的。利用须要的后果集为2条,Mycat中须要解决的后果数为21条。也就是说,对于有 t 个DB节点的全分片 limit m, n 操作,Mycat须要解决的数据量为 (m+n)*t 个。比方理论利用中有50个DB节点,要执行limit 1000,10操作,则Mycat解决的数据量为 50500 条,返回后果集为10,当偏移量更大时,内存和CPU资源的耗费则是数十倍减少。
如果设计应用Mycat时有分页排序,请思考放弃!
3.任意表JOIN
先看一下在单库中JOIN中的场景。假如在某单库中有 player 和 team 两张表,player 表中的 team_id 字段与 team 表中的 id 字段相关联。操作场景如下图:
JOIN操作的SQL如下
mysql>select p_name,t_name from player p, team t where p.no = 3 and p.team_id = t.id;
此时能查问出后果
p_name
t_name
Wade
Heat
如果将这两个表的数据分库后,相关联的数据可能散布在不同的DB节点上,如下图:
这个SQL在各个独自的分片DB中都查不出后果,也就是说Mycat不能查问出正确的后果集。
设计应用Mycat时如果要进行表JOIN操作,要确保两个表的关联字段具备雷同的数据分布,否则请思考放弃!
4.分布式事务
Mycat并没有依据二阶段提交协定实现 XA事务,而是只保障 prepare 阶段数据一致性的 弱XA事务 ,实现过程如下:
利用开启事务后Mycat标识该连贯为非主动提交,比方前端执行
mysql>begin;
Mycat不会立刻把命令发送到DB节点上,等后续下发SQL时,Mycat从连接池获取非主动提交的连贯去执行。
Mycat会期待各个节点的返回后果,如果都执行胜利,Mycat给该连贯标识为 Prepare Ready 状态,如果有一个节点执行失败,则标识为 Rollback 状态。
执行实现后Mycat期待前端发送 commit 或 rollback 命令。发送 commit 命令时,Mycat检测以后连贯是否为 Prepare Ready 状态,若是,则将 commit 命令发送到各个DB节点。
然而,这一阶段是无奈保障一致性的,如果一个DB节点在 commit 时故障,而其余DB节点 commit 胜利,Mycat会始终期待故障DB节点返回后果。Mycat只有收到所有DB节点的胜利执行后果才会向前端返回 执行胜利 的包,此时Mycat只能始终 waiting 直至_TIMEOUT_,导致事务一致性被毁坏。
设计应用Mycat时如果有分布式事务,得先看是否得保障事务得强一致性,否则请思考放弃!