Mycat 学习(四)

Mycat实战

image.png

我们用一个mini电商系统数据库表来实战一下。我们的现在mysql的架构是,两个服务器,A服务器上准备承载3个用户信息库,B服务器准备承载2个订单信息库,同时B服务器上启用了主从复制。

原始的库表说明如下:

区域表: image.png

邮编表: image.png

用户信息表: image.png

订单表: image.png

注,通过观察阿里等电商网站,可以发现,这些电商网站会把一个订单编号下只有一个商家的产品,所以我们也照此设计。

订单明细表: image.png

现在业务发展,用户信息和订单信息都已经很庞大,我们需要进行分库分表了,怎么做呢?

我们已经确定了,我们要把用户信息和订单信息进行业务拆分,这样就进行了一次业务上的垂直拆分的分库。

业务拆库后,对用户信息和订单信息进入分库分表,其中最重要的一步,即分片字段(sharding column)的选取,分片字段选择的好坏将直接决定整个分库分表方案最终是否成功。而分片字段的选取跟业务强相关,选择分片字段的方法最主要分析你的API流量,优先考虑流量大的API,将流量比较大的API对应的SQL提取出来,将这些SQL共同的条件作为分片字段。

我们考察业务和用户信息表中的字段,用户登录属于高频和必须操作,表中牵涉到登录的字段有nicky_name和phone_name,那这两个字段我们考虑作为分片字段,而用户的id也是我们业务上经常要用的字段,也应该作为分片字段。现在有三个字段需要成为分区字段了,那么这种情况下应该怎么办呢?我们其实可以考虑将用户信息表进行拆表,nicky_name和phone_name统称为登录字段,用户登录后通过登录字段找到用户的id。所以用户信息表变为: image.png

image.png

订单业务从业务角度来说,有三个column作为三个独立的sharding column,即:order本身的id,buyer_user_id,merchant_user_id。因为订单业务中买家和卖家的查询流量都比较大。而根据order_id进行分库分表,应该是根据order_id的查询也比较多。本次实战中,这个order_id我们不予处理,因为方法和buyer_user_id,merchant_user_id是一样的。

这里还有一点需要提及,多个sharding-column的分库分表是全量冗余还是只冗余关系索引表。

冗余全量的情况如下--每个sharding列对应的表的数据都是全量的,这样做的优点是不需要二次查询,性能更好,缺点是比较浪费存储空间。我们本次采用这种方式,那么表会变为: image.png

image.png

注:采用冗余关系索引表分区,表结构可以这样设计,订单表保持不变,分区字段为order本身的id,新建两张表,分区字段分别为buyer_user_id,merchant_user_id,即

分区字段为merchant_user_id:

merchant_user_id order_id

sharding column为buyer_user_id:

buyer_user_id order_id

这样做的优点是节省空间,缺点是除了第一个sharding column的查询,其他sharding column的查询都需要二次查询:

而订单明细表和订单表是个典型的主从明细表,从Mycat的提供的表类型来说,属于ER表类型,为了分片后,让明细记录和订单记录落在同一个节点上,所以这个表也要有两个,但是表结构一样。 image.png

image.png

表结构确定后,那就是分区算法的选择了,对用户信息表因为是id分片,所以我们直接用id取模就行,而登录表的分区字段是字符串,所以我们选择截取一部分字符串做hash求模。订单表,我们选择算法“取模范围约束”。

至于post,因为用的很少,所以我们把它只放在一个节点上,而区域表完美的符合mycat中全局表的定义,所以区域表我们把它定义为全局表,那么mycat中配置文件就应该是这个样子: image.png

image.png

image.png

image.png

Mycat架构剖析和实现分析

主体架构 

image.png

Mycat在逻率持上由几个模块组成:通信协议、路由解析、结果集处理、数据库连接、监控等模块。

1.通信协议模块

通信协议模块承担底层的收发数据、线程回调处理工作,主要采用 Reactor、 proactor模式来提高效率。目前, Mycat通信模块默认釆用 Reactor模式,在协议层采用 MySQL协议。

2.路由解析模块

路由解析模块负责对传入的SL语句进行语法解析,解析从 MySQL协议中解析出来并进入该模块的SQL语句的条件、语句类型、携带的关键字等,对符合要求的SQL语句进行相关优化,最后根据这些路由计算单元进行路由计算。

3.结果集处理模块

结果集处理模块负责对跨分片的结果进行汇聚、排序、截取等。由于数据存储在不同的数据库中,所以对跨分片的数据需要进行汇聚。

4.数据库连接模块

数据库连接模块负责创建、管理、维护后端的连接池。为了诚少每次建立数据库连接的开销,数据库使用连接池机制对连接生命周期进行管理

5.监控管理模块

监控管理模块负责对 Mycat中的连接、内存等资源进行监控和管理。监控主要是通过管理命令实时地展现一些监控数据,例如连接数、缓存命中数等;管理则主要通过轮询事件来检测和释放不使用的资源。

6.SQL执行模块

SQL执行模块负责从连接池中获取相应的目标连接,对目标连接进行信息同步后,再根据路由解析的结果,把SQL语句分发到相应的节点执行。

总体执行流程

主要流程:由通信协议模块的读写事件通知发起。读写事件通知具体的回调代码进行这次读写事件的处理。管理模块的执行流程由定时器事件进行资源检查和资源释放时发起

由客户端发送过来的数据通过协议解析、路由解析等流程进入执行组件。通过执行组件把数据发送到通信协议模块,最终数据被写入目标数据库。

由后端数据库返回数据,通过协议解析后发送至回调模块。如果是涉及多节点的数据,则执行流程将会先进入结果集汇聚、排序等模块中,然后将处理后的数据通过通信协议模块返回到客户端。

路由

从原理上来看,可以把mycat 看成一个sql 转发器。mycat 接收到前端发来的sql,然后转发到后台的mysql 服务器上去执行。但是后面有很多台mysql 节点(如dn1,dn2,dn3),该转发到哪些节点呢?这就是路由解析该做的事情了。

路由能保证sql 转发到正确的节点。转发的范围是刚刚好,不多发也不少发。在选型上,mycat使用的是druidparser。

跨库join的实现

全局表

任何一个企业级的系统都会有很多基础信息表,它们的数据结构相对比较简单,类似于字典表,它们和业务表之间有关系,但是这种关系肯定不会是主从关系,大多数是一种属性关系,相当于配置信息,比如省份、城市、区域等。

当业务的数据量达到一定的规模,我们需要对业务表进行分片时,业务表和相关的基础信息之间的关系就变得非常麻烦,而这些基础信息表有如下一些特点

l 数据的变化不频繁

l 数据量的规模也比较小,在一般情况下为几万条记录,很少超过几十万条记录

鉴于这些特点, Mycat定义了一种特殊的表,叫作全局表。在全局表中进行插入操作时,每个节点同时并发插入和更新数据,而在读取数据的时候,因为任意节点的数据都是相同的,所以任意节点都可以读,这样在提升读性能的同时解决了跨节点Join的效率。

全局表的重要特性如下。

l 全局表的插入、更新、删除操作会实时地在所有节点同步执行,保持各个分片的数据的一致性

l 全局表的查询操作会从任意节点执行,因为所有节点的数据都一致全局表可以和任意表进行Join操作

将基础信息表和字典表定义成全局表,从业务上来看,业务表分片后,不会影响它们之间的Join操作,这是解决跨库Join的一种实现,通过全局表再加上ER关系的分片规则, Mycat可以满足大部分企业级的应用系统。

ER分片

数据库的ER关系模型是目前应用系统中经常使用到的, Mycat参考了 NewSQL领域的新秀 Foundation dB的设计思路。 Foundation DB创新性地提出了 Table Group的概念,子表的存储位置依赖于主表,并且在物理上紧邻存放,因此彻底解决了 Join的效率和性能问题,并根据这一思路,提出了基于E-R关系的数据分片策略,子表的记录与所关联的父表记录存放在同个数据分片上。

存在关联关系的父、子表在数据插入的过程中,子表会被 Mycat路由到与其相关的父表记录的节点上,从而使父、子表的Join査询可以下推到各个数据库节点完成,这是最高效的跨节点Join处理技术,也是 Mycat的首创,如图7-12所示。   image.png

Customer表采用了按范围分片的策略,每个范围内的 Customer在一个分片上, Customer和 Customer100分片在 host 1、host2上。从图7-12可以知道, Customer1的 Orderl和 Order2订单在host分片上, Customer100的Oder3和 Order100订单在host2分片上,所以 orders表的记录依赖父表进行分片,两个表的关联关系为 orders customer id= customer id。

按照这样的分片规则,host1分片上的 customer与 orders就可以进行局部的Join操作,在host2分片上也一样,就是在各自的分片上先做Join,然后在 Mycat内部合并两个节点的数据,这样就完成了跨分片的Join。试想一下,每个分片上 orders表有100万条,所以10个分片就有1亿条,基于ER映射的数据分片模式基本上解决了比较多的应用所面临的问题。

但是有很多业务存在多层ER关系,对于这种情况,其实有种非常简单的方法,就是用空间换时间的概念,简单地说就是多层E-R关系如第二、三层的E-R关系,通过增加冗余字段来解决这个问题。比如,在上面的例子中还有个 Orders的子表 Order items,只要这个表新增一个字段customer id就可以了,也就是把第二、三层的ER关系转化为第一层的ER关系进行分片。

ShareJoin 是Catlet 的一个实现,把解析出的SQL 分次执行,并存结果集,合并结果集。

汇聚和排序

把解析出的SQL 分次执行,并存结果集,合并结果集,如果有排序则是用的将结果集在mycat中进行了堆排序。

Guess you like

Origin juejin.im/post/7069414729550135333