一,cobar是什么
画外音:数据库中间件有基于服务端的,也有基于客户端的,cobar属于前者。 二,cobar应用场景举例 逻辑上:
物理上:
三,cobar使用方式 命令行:连dbtest虚拟库 JDBC:也是连dbtest虚拟库 查看db: 可看到dbtest1、dbtest2、dbtest3对用户透明。 查看table: 可看到有tb1和tb2两张表。 插入一些数据,对用户而言,后端的分布式mysql是透明的:
画外音:从其官网上看,自12年12月之后,cobar就没有再更新过,官方微博也非常不活跃,不清楚现在它在阿里的使用情况,知道的同学请说一说。 四,cobar不支持什么
五,cobar支持什么 分布式数据库:通过分库实现
需要注意:不支持将test拆分成test_1,test_2,test_3并放入同一个库中这样的拆分方式。 画外音:后者正是360的atals的做法(atlas只支持单实例单库分表)。 HA:通过到mysql的心跳实现
画外音:需要注意,cobar是需要用户自己来实现负载均衡的,方式有三种:
SQL路由 在分库的情况下,cobar会从sql中提取partition key列,来判断SQL被路由到哪一个分库进行执行;如果没有带partition key,则会将SQL分发到所有分库执行。 示例 tb1(id INT) 假设以id切分数据,后端分了N个库:
画外音:SQL带上partition key对cobar来说,非常非常重要,并且partition key不支持修改(修改了库就不对了哟)。 cobar不允许在同一个连接中切换库。 画外音:数据库连接和库是绑定关系。 不建议通过cobar来执行DDL语句。 画外音:所以建库,建索引什么的,还是直连mysql自己搞吧。 COBAR自定义语句
cobar允许管理员通过管理命令上线和下线cobar节点。
被定义在一个cobar集群中的cobar节点之间都会发送心跳,所谓的心跳就是上面提到的show cobra_status; 这样的话,就为每一个cobar节点提供了知道同一个集群内的所有cobar信息的机会。当然,被下线,或者心跳超时的cobar节点的信息不会被显示出来。
SQL语句前加上explain即可知道SQL语句的路由情况。 事务的支持 cobar对单库保持事务的强一致性。 对分库保持事务的弱一致性。 分库后事务提交包含两个阶段:
两个阶段之间,执行与提交串行处理,阶段内部各个分库并行处理。 画外音:额,基本就是不支持分布式事务。 六,cobar系统架构系统模块图 画外音:从模块图来看,cobar的结构还是挺清晰的:
数据流图 数据流图和上述模块图对应: 网络模型 采用异步网络模型: 结果合并 会把多个物理库的结果集合并,再返回给上游: 八,cobar路由算法 partition key是int时 好办,直接取模 partition key是string时 f(string) = hash(string) % 1024 假设分4个库:
如何扩容:
拆分后:
数据非均匀分布路由:
九,cobar对于SQL的转发 带partition key单记录查询 直接根据partition key路由。 带partition key的IN查询 将IN进行拆分,请求发到对应多个分库,然后将结果集合并。 不带partition key的where查询 假设partition key是user字段,在product字段上的where查询,会将请求广播到所有分库,然后将结果集合并。 二维partition key 一张表的多个字段同时作为定位库的拆分字段,仍以上图的visit(product, user, info)为例,可以以product和user两个字段来同时来定位库。 横坐标product属性取hash,纵坐标user属性取hash。 SELECT * FROM visit WHERE product=‘ColaCola’ AND user=‘A’ 对于上述业务需求,同时带有两个列作为查询条件,可以直接定位到库7。 但是,此时如果只有其中的一个字段作为查询条件,反而得查询多个库,再做聚合: SELECT * FROM visit WHERE product=‘ColaCola’ 对于上述业务需求,就必须查询库3,7,11,15了。 画外音:不懂为什么要按照双key来做路由,单key路由,对于双key的查询,也没有增加多少数据扫描量啊,加入双key反而使得某些情况下策略复杂了,带来的收益也不高。 小结 对的,对于where,cobar就是这样的处理方式:
十,cobar的高级特性 JOIN有限的处理 如上,两个表都进行了分库,JOIN需求如下: SELECT * FROM tb1 INNER JOIN tb2 ON tb1.MEMBER_ID=tb2.NAME 结果集理应如下: 方案一:迭代查询 FOR row1 IN select * FROM tb1{ ADD( SELECT* FROM tb2 WHERE tb2.name = row1.member_id )TO RESULT } 画外音:我去,外层循环是对tb1中的所有记录,在tb2来一遍扫描,bt1数据量大的情况下,这哪里受得了? 方案二:夸库索引 对于tb1和tb2存在的潜在JOIN需求,对JOIN列建立夸库索引。
SELECT * FROM tb1 INNER JOIN tb2 ON tb1.MEMBER_ID=tb2.NAME WHEREtb1.id=5 此时需要改写SQL语句,直接在索引表上进行查询: SELECT * FROM idx WHERE id1=5 此处需要注意:
GROUP BY的处理 以上表为例,patition key是ID,要在C1上进行GROUP BY操作: SELECT SUM(price) FROM tb1 GROUP BY c1; 改写SQL语句,先在各个分库上GROUP BY一次,并将sum计算出来: SELECT SUM(price), c1 FROM tb1 GROUP BY c1 ORDER BY c1; 各分库进行GROUP BY + ORDER BY + sum之后,根据排序后的c1及对应sum结果,归并一遍后即得到最终结果。 小结 对于复杂语句,可以这样处理:
|
|