题外话
使用Cobar
将近一年了,但对其原理仍旧不是很了解,更没阅读过源码,说起来也是惭愧。趁着最近线上的一次故障,总算说服自己花时间来看看Cobar
的真面目。
我们公司对它的印象很差,因为经常出现各种不稳定。比如Cobar
在执行一条复杂查询的过程中,同时执行一条普通的selectById
都有可能爆出Unsupport Command
。
线上故障
最近的这次线上故障更为严重:因为在底层Mysql
层面捕捉到了锁,并且多个session
长时间的在等待该锁直到超时(锁超时时间是50s)。此时的Cobar
完全就处于一个近似于僵死的状态。当时的场景是一个接口的并发调用,这个并发调用会更新同一个人的账户余额,简化成SQL
类似于
update `user` set balance = balance - 5 where id = 1;
并发度大概在30+左右。Mysql
层面捕捉到的也都是id为1这条记录的行级锁(row-level locking),锁超时时间是50s,当时应用有大量更新这条记录的锁超时爆出。最后,其余访问cobar
的线程也被阻塞。
临时方案
线上故障在无法立即找出原因并解决的情况下,我们必须要有紧急预案或者说是临时方案。当时的问题产生是由于某个定时任务去并行对某个用户的账号做扣罚。于是我们将该扣罚金额参数调整成了0,至此,Cobar
恢复正常。
抛出疑问
当然,临时方案只是为了暂时先恢复正常运营。下面的工作就要找出问题真正的原因。
针对上面的故障场景,当时产生了几点疑问:
- 为什么某条Sql会占用id为1的行锁超过50s甚至更长?
- 为什么id为1的行锁占用会影响到整个
Cobar
的服务?
我们留着这两点疑问先慢慢往下看。
场景还原
故障之后有同事在重现该场景并寻找原因,根据数据源和事务提交方式的不同,在并发度为500的情况下,分别测试了如下几种场景:
数据源
事务提交方式
是否重现
Cobar |
自动 |
否 |
Cobar |
手动 |
是 |
直连Mysql |
自动 |
否 |
直连Mysql |
手动 |
否 |
只有在使用Cobar
并采用手动提交事务的情况下,才会出现Cobar
僵死的情况。这个测试模拟了一个最简单并且足以说明问题的场景,单表一条主键id为1的记录,对其做update
操作。更不用说并发500了,30+的情况也完全能把Cobar
给搞挂。
原理探究
到这里大家可能就开始质疑Cobar
了,真的是Cobar
的并发低到只有30+?
带着这样的质疑,我踏上了一条为Cobar
正名的“不归路”。通过官方文档以及Cobar
的源代码,梳理出了Cobar
的大致结构,下面是简化后的结构图:
可以看到,Cobar
实现了Mysql
协议,伪装成Mysql
服务端与我们的应用进行通讯,这样我们的应用就可以像直连Mysql
一样操作Cobar
了。应用与Cobar
建立连接,然后通过Mysql
协议将请求发到Cobar
,Cobar
解析报文然后根据命令的不同执行不同的操作。其中涉及到两个线程池,如上图所示,在Cobar
中命名这两个线程池为:Handler
和Executor
:Handler
的主要工作是读取数据流,解析报文,处理对应命令,路由计算等。而具体要和底层的Mysql
打交道的工作就交给Executor
来完成了。我们来举个简单的例子,就拿前面的update
语句来简单分析一下(建立连接这块先不说):
update `user` set balance = balance - 5 where id = 1;
假设应用和Cobar
之间已经建立起了连接,那么Cobar
就开始从应用读取数据流,一旦读到数据流,那么Cobar
会简单处理数据包,待获得一个完整的数据包之后将此数据包打包成一个任务丢给Handler
去执行。该任务的内容包含:
- 根据
Mysql
协议来解析数据包(枯燥的过程,例如包头4个字节,第五个字节代表具体的命令类型,诸如此类的东西)
- 通过第一步可以解析出命令类型以及具体的SQL,下面以Query这种命令类型为例,这也是最常用的(这里的查询不局限select,crud都属于Query)
- 根据SQL进行路由计算,针对于单节点和多节点处理略有不同
最后将携带了路由信息的数据包打包成任务丢到Executor
中去执行,这块任务要做的是:
- 根据路由信息关联
Mysql
通道
- 针对该会话绑定
Mysql
通道,主要是为了关联事务
- 发送数据包到
Mysql
并等待返回结果
提出猜想
通过上面的分析,再来想想之前提出过的两点疑问:
- 为什么某条Sql会占用id为1的行锁超过50s甚至更长?
- 为什么id为1的行锁占用会影响到整个
Cobar
的服务?
这边先来简单普及一个知识点,一般的手动事务需要三个步骤:
- set autocommit = 0;
- Query Command
- commit/rollback
在正常情况下根据主键update
肯定不可能超过50s,那么只有一种情况,那就是update
操作之后没有commit
。
为什么会没有commit
呢,是不是Executor
被挤满了?
为什么Executor
满了?因为堵满了update
这看起来像不像一个死锁(DeadLock)问题?
Executor
中的某条线程(ThreadA)获取了锁,其余大多数线程都在等待该锁。假设此时update
线程足够多并且都因为等待锁而阻塞,进而堵满了Executor
。那么那条获得了锁的线程也就没有空余线程来释放锁了(commit/rollback)。DeadLock!
验证猜想
首先,我们来重现场景,和上面写的场景还原一样,采用500个线程来并发更新一条记录:
update `user` set balance = balance - 5 where id = 1;
不出意料,场景又再现了。此时,我们通过Cobar
提供的管理节点来监控线程池,发现Executor
跑满了,并且队列中还堆积了好多请求:
此时再去底层的Mysql
看看,发现此时大量锁超时:
为了证明线程池里堵得全都是update
,又通过修改Cobar
源码打印出了Executor
中任务执行的日志。至此,问题已经非常清晰,并且同时也解释了为什么在自动提交事务的场景下不会发生堵塞。
那么可以开始考虑解决方案了。
解决方案
1、加大Executor
的线程池大小,这应该也是最容易想到的方式。Cobar
会根据CPU
核心数创建N个Executor
,假设将Executor
的线程池大小调整到256,那么理论上可支持对同一条记录的并发操作数可达到 N * 256。
优点:改起来非常方便,本身Cobar
配置文件就有暴露该配置项
缺点:总觉得有点治标不治本的味道,并发量过高还是会有阻塞的危机
当然可以搭配死锁检查或对于线程中执行时间过长的SQL直接Kill并报警等机制
2、再定义一种线程池,单独用来执行commit/rollback命令
优点:将资源隔离,可以从本质上来解决死锁问题
缺点:需要改动Cobar
源代码,可能需要经过一轮全面的测试才能使用到生产环境
3、暂时没想到
对于前两种方案我都实践了并且测试过,都可以达到想要的效果。个人还是倾向于第二种,但是第一种可以作为过渡方案。
结束语
上面说的第一种方案在Cobar
现有的架构下是必不可少的。必须要调到合适的线程数,如果系统瓶颈被卡在这里,那岂不是资源浪费?
感觉这个问题算是Cobar
隐藏的一个BUG吧。可能在设计之初并没有考虑到一些对同一条记录高并发的更新场景。网上也没有太多关于这方面的文章。这篇文章算是一个探路者,为我之后研究开元中间件开一个好头~
<script type="text/javascript">
$(function () {
$('pre.prettyprint code').each(function () {
var lines = $(this).text().split('\n').length;
var $numbering = $('<ul/>').addClass('pre-numbering').hide();
$(this).addClass('has-numbering').parent().append($numbering);
for (i = 1; i <= lines; i++) {
$numbering.append($('<li/>').text(i));
};
$numbering.fadeIn(1700);
});
});
</script>
分享到:
相关推荐
Cobar是分片数据库和表的代理,兼容MySQL protocal和MySQL SQL grama,底层存储只支持MySQL,支持前台业务更简单,稳定,高效和安全。 分片 您可以随着业务的增长添加新的MySQL的的实例。 可用性高 科巴服务器底层...
Cobar,全称是Clustered Bar,由阿里巴巴开源,是一款高性能、高可用的数据库连接器,主要功能是实现对MySQL的分布式管理和分库分表。Cobar Server 1.2.7 是其一个稳定版本,提供了更稳定的性能和更多的特性。 二、...
文档中还提到了Cobar在实施前后的对比,例如从Oracle单点数据库到MySQL集群的替换,以及Cobar引入后的性能问题解决、连接数过多的问题解决、可用性问题(例如Standby切换故障)的解决,以及成本和伸缩性问题的改善。...
阿里巴巴Cobar是一款由阿里巴巴开源的高性能、分布式数据库中间件,其设计目标是为了解决大规模互联网服务中的数据分片、读写分离以及高可用性等问题。Cobar在MySQL协议层之上构建,允许应用透明地访问分布式数据库...
Atlas 是由 Qihoo 360 开发维护的一个基于 MySQL 协议的数据中间层项目,具有负载平衡、读写分离、failover 等功能。Atlas 的架构是位于应用程序与 MySQL 之间,实现了 MySQL 的客户端与服务端协议,作为服务端与...
mysql 中间件研究(Atlas、Cobar、TDDL) mysql 中间件研究是当前数据库系统中一个非常重要的课题,mysql-proxy 是官方提供的 mysql 中间件产品,可以实现负载平衡、读写分离、failover 等,但是它不支持大数据量的...
Cobar服务器是一款基于Java开发的分布式数据库中间件,主要用于解决大规模数据访问的性能问题。它在Linux环境下运行,提供了一种高效、可扩展的解决方案,适用于处理高并发、大数据量的场景。Cobar的主要功能是将...
- **高可用性(HA)**:Cobar可以通过配置MySQL心跳机制来监测后端MySQL数据库的状态,并在出现问题时自动切换到备用服务器继续提供服务。需要注意的是,Cobar的主备切换需要用户手动干预,即使主服务器恢复正常后也是...
它主要用于解决大规模数据处理和高并发访问的问题,通过提供MySQL协议的前端服务器,实现数据库的分片、读写分离、负载均衡等功能,从而提高数据库系统的整体性能和可扩展性。Cobar的主要目标是为大数据量、高并发的...
【MySQL中间件详解:Atlas、cobar、TDDL与Mycat】 MySQL中间件是用于在应用程序和数据库之间提供服务的软件,它们通常用于解决数据库的扩展性、高可用性和读写分离等问题。本文将详细介绍四款知名的MySQL中间件:...
- **高可用性(HA)**:Cobar可以通过配置MySQL心跳机制来实现高可用,自动检测MySQL的运行状态并在故障发生时进行主备切换。需要注意的是,在主服务器恢复正常后,需要手动将其切换回来,除非备用服务器也出现异常...
Home - Cobar - Alibaba Open Sesame 产品文档(未完成) - Cobar - Alibaba Open Sesame_action 路由算法 - Cobar - Alibaba Open Sesame_action rule - Cobar - Alibaba Open Sesame 数据源心跳配置 - Cobar - ...
Cobar作为一个高性能的数据库连接池,主要用于解决大规模数据并发访问的问题,尤其在互联网行业中有着广泛的应用。在这个例子中,我们将深入探讨Cobar Client的创建过程及其相关知识点。 首先,我们需要理解Cobar ...
阿里巴巴cobar分表分库方案,cobar使用详细讲解,教用户手把手快速上手。
cobar Solution 中间件PPT
COBAR架构实践COBAR架构实践COBAR架构实践COBAR架构实践COBAR架构实践COBAR架构实践COBAR架构实践COBAR架构实践COBAR架构实践
Cobar 是一个高性能、分布式的关系型数据库中间件,它的全称是“Clustered MySQL Bar”。在阿里巴巴集团内部,Cobar 曾经被广泛应用于解决大规模数据处理和高并发访问的问题。Cobar 的主要目标是通过分库分表、读写...
**2.1 Cobar 解决的问题** - **分布式处理**:Cobar 是一个面向关系型数据的分布式处理系统,它能够通过将表放置在不同的数据库中来实现数据的分布存储。支持表的水平拆分和垂直拆分,以及两者的混合使用。 - **...
Cobar,全称为“Cloud-Based MySQL Binary Log Applier”,是由阿里巴巴开源的一款高性能数据库中间件,旨在解决大规模分布式数据库系统中的数据访问问题。它作为一个分布式数据库proxy,可以将用户请求分发到后端的...