数据库中间件cobar调研笔记

13年底负责数据库中间件设计时的调研笔记,拿出来和大家分享,轻拍。文章很长,可提前收藏,转发。

一,cobar是什么

  • 开源的mysql的中间件服务
  • 使用mysql协议
  • 对上游,cobar就是传统mysql数据库
  • 对上游,它屏蔽后端分布式mysql集群

画外音:数据库中间件有基于服务端的,也有基于客户端的,cobar属于前者。

二,cobar应用场景举例

逻辑上:

  • 数据库dbtest(虚拟的)
  • 表tb1和tb2

物理上:

  • tb1表的数据在dbtest1(物理的)的tb1上
  • tb2表的一部分数据在dbtest2(物理的)的tb2上,另外一部分在dbtest3(物理的)的tb2上

三,cobar使用方式

命令行:连dbtest虚拟库

JDBC:也是连dbtest虚拟库

查看db

可看到dbtest1、dbtest2、dbtest3对用户透明。

查看table

可看到有tb1和tb2两张表。

插入一些数据,对用户而言,后端的分布式mysql是透明的:

  • 对tb1,数据实际上存在dbtest1的tb1中
  • 对tb2,数据实际上存储在dbtest2和dbtest3的tb2中

画外音:从其官网上看,自12年12月之后,cobar就没有再更新过,官方微博也非常不活跃,不清楚现在它在阿里的使用情况,知道的同学请说一说。

四,cobar不支持什么

  • 不支持夸库join,分页,排序,子查询
  • set语句会被忽略(事务和字符集设置除外)
  • 如果分库,insert必须包含patition key(否则麻烦大了)
  • 如果分库,patition key不能被update
  • 不支持读写分离
  • 不支持存储过程
  • 如果使用JDBC,rewriteBatchedStatements,useServerPrepStmts,BLOB, BINARY, VARBINARY字段不能使用setBlob()或setBinaryStream()

五,cobar支持什么

分布式数据库:通过分库实现

  • 支持一张表放到不同的库
  • 支持不同的表放入不同的库

需要注意:不支持将test拆分成test_1,test_2,test_3并放入同一个库中这样的拆分方式。

画外音:后者正是360的atals的做法(atlas只支持单实例单库分表)。

HA:通过到mysql的心跳实现

  • 主机挂了会自动切换回备机,但主机恢复,需要手动切回
  • 只检测主备异常,不关心主备数据同步(需要dba手动配)

画外音:需要注意,cobar是需要用户自己来实现负载均衡的,方式有三种:

  • 自己使用软件例如LVS
  • 自己使用硬件例如F5
  • cobar提供了命令获取集群信息,用户可以根据这些信息做负载均衡;当然,淘宝已经实现了一个具有负载均衡功能的cobar客户端产品-cobar.driver

SQL路由

在分库的情况下,cobar会从sql中提取partition key列,来判断SQL被路由到哪一个分库进行执行;如果没有带partition key,则会将SQL分发到所有分库执行。

示例

tb1(id INT)

假设以id切分数据,后端分了N个库:

  • insert into tb1 values(1); => N个库都会执行插入,因为没有带partition key;
  • insert into tb1(id) values(1); => 只会路由到1个库,带了partition key;
  • update tb1 set id=2 where id=1; => 不支持,不能修改partition key;

画外音:SQL带上partition key对cobar来说,非常非常重要,并且partition key不支持修改(修改了库就不对了哟)。

cobar不允许在同一个连接中切换库。

画外音:数据库连接和库是绑定关系。

不建议通过cobar来执行DDL语句。

画外音:所以建库,建索引什么的,还是直连mysql自己搞吧。

COBAR自定义语句

  • 查询cobar节点的状态

cobar允许管理员通过管理命令上线和下线cobar节点。

  • 查询cobar集群的状态

被定义在一个cobar集群中的cobar节点之间都会发送心跳,所谓的心跳就是上面提到的show cobra_status; 这样的话,就为每一个cobar节点提供了知道同一个集群内的所有cobar信息的机会。当然,被下线,或者心跳超时的cobar节点的信息不会被显示出来。

  • 查询SQL语句的路由情况

SQL语句前加上explain即可知道SQL语句的路由情况。

事务的支持

cobar对单库保持事务的强一致性。

对分库保持事务的弱一致性。

分库后事务提交包含两个阶段:

  • 执行阶段:SQL按照规则被路由到多个分库,此时发生错误,还能回滚
  • 提交阶段:提交阶段出错,无法正确回滚

两个阶段之间,执行与提交串行处理,阶段内部各个分库并行处理。

画外音:额,基本就是不支持分布式事务。

六,cobar系统架构

系统模块图

画外音:从模块图来看,cobar的结构还是挺清晰的:

  • 前端对上游的连接池
  • 后端对下游mysql的连接池
  • 对每一个请求,会经过: SQL分析 SQL路由 SQL执行 投递给后端mysql
  • 对每一个响应,需要做结果合并

数据流图

数据流图和上述模块图对应:

网络模型

采用异步网络模型:

结果合并

会把多个物理库的结果集合并,再返回给上游:

八,cobar路由算法

partition key是int时

好办,直接取模

partition key是string时

f(string) = hash(string) % 1024

假设分4个库:

  • 哈希结果0-255 -> 库1
  • 哈希结果256-511 -> 库2
  • 哈希结果512-767 -> 库3
  • 哈希结果768-1024 -> 库4

如何扩容:

  • 哈希结果0-255 -> 库1

拆分后:

  • 哈希结果0-127 -> 库1.1
  • 哈希结果128-255 -> 库1.2

数据非均匀分布路由:

  • 哈希结果0-511(513范围) -> 库1
  • 哈希结果512-767(256范围) -> 库2
  • 哈希结果768-895(128范围) -> 库3
  • 哈希结果896-1023(128范围) -> 库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就是这样的处理方式:

  • 根据字段的一致性hash分布数据
  • 多维拆分
  • 根据where中的partition key分发查询
  • SQL语句变换,分发至各个分库执行,对结果进行合并

十,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列建立夸库索引。

  • 直接JOIN查询:建立了夸库索引后,对于JOIN的直接查询,就是idx索引表内的数据的合并就是结果
  • JOIN后带WHERE条件

SELECT * FROM tb1 INNER JOIN tb2

ON tb1.MEMBER_ID=tb2.NAME

WHEREtb1.id=5

此时需要改写SQL语句,直接在索引表上进行查询:

SELECT * FROM idx WHERE id1=5

此处需要注意:

  • 索引表的partition key:WHERE条件所在表的partition key,作为索引表的partition key
  • 索引必须包含参与JOIN相关表的主键,JOIN字段,包含WHERE条件的字段
  • 索引的更新:需要分布式事务的支持

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结果,归并一遍后即得到最终结果。

小结

对于复杂语句,可以这样处理:

  • 对于JOIN,可以迭代查询,或者使用分布式索引
  • 对于GROUP BY,需要增加查询列,以及ORDER BY

13年底的调研笔记,文中的“画外音”是我当时的批注,希望能让大家对cobar能有一个初步的认识,有疑问之处,欢迎交流。

原文发布于微信公众号 - 架构师之路(road5858)

原文发表时间:2017-11-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏杂烩

mycat安装使用 原

    github地址:https://github.com/MyCATApache/Mycat-Server/wiki

1402
来自专栏MYSQL轻松学

MySQL 8.0.11 (2018-04-19, General Availability)

仅支持通过使用 in-place 方式从 MySQL 5.7 升级到 MySQL 8.0 升级; 不支持从 MySQL 8.0 降级到 MySQL 5....

962
来自专栏吴伟祥

为什么子查询比连接查询(LEFT JOIN)效率低

MySQL从4.1版本开始支持子查询,使用子查询进行SELECT语句嵌套查询,可以一次完成很多逻辑上需要多个步骤才能完成的SQL操作。子查询虽然很灵活,但是执行...

1572
来自专栏编程心路

语言小知识-MySQL数据库引擎

MySQL 作为全世界广受欢迎的数据库,被用于很多中小型的项目中,但是你对 MySQL 数据库的存储引擎了解多少呢?

1394
来自专栏james大数据架构

微软官方提供的用于监控MS SQL Server运行状况的工具及SQL语句

Microsoft SQL Server 2005 提供了一些工具来监控数据库。方法之一是动态管理视图。动态管理视图 (DMV) 和动态管理函数 (DMF) 返...

2977
来自专栏Python

MySQL常见的库操作,表操作,数据操作集锦及一些注意事项

一 库操作(文件夹) 1 数据库命名规则 可以由字母、数字、下划线、@、#、$ 区分大小写 唯一性 不能使用关键字如 create select 不能单独使用数...

2609
来自专栏idba

漫谈死锁

一 前言 死锁是每个MySQL DBA 都会遇到的技术问题,本文是自己针对死锁学习的一个总结,了解死锁是什么,MySQL如何检测死锁,处理死锁,死锁的案例,...

1604
来自专栏蓝天

高性能高可用的分布式唯一ID服务——mooon-uniq-id

源码位置:https://github.com/eyjian/mooon/tree/master/application/uniq_id。

792
来自专栏Java进阶架构师

「mysql优化专题」单表查询优化的一些小总结,非索引设计(3)

(0)可以先使用 EXPLAIN 关键字可以让你知道MySQL是如何处理你的SQL语句的。这可以帮我们分析是查询语句或是表结构的性能瓶颈。

702
来自专栏Netkiller

数据库进程间通信解决方案

数据库进程间通信解决方案 数据库与其他第三方应用程序进程间通信解决方案 摘要 你是否想过当数据库中的数据发生变化的时候出发某种操作?但因数据无法与其他进程通信(...

3976

扫码关注云+社区

领取腾讯云代金券