资源描述
入门篇 1
MYCAT开源宣言 1
概述 3
数据库切分概述 3
垂直切分 5
水平切分 6
Mycat前世今生 9
序章 9
Cobar的十个秘密 10
Mycat闪耀登场 14
Mycat概述 18
Mycat中的概念 21
数据库中间件 21
逻辑库(schema) 21
逻辑表(table) 22
分片节点(dataNode) 23
节点主机(dataHost) 23
分片规则(rule) 23
全局序列号(sequence) 23
多租户 23
快速入门 25
10分钟入门 25
快速镜像方式体验MyCAT 26
服务安装与配置 26
服务启动与启动设置 28
demo使用 29
日志分析 30
warpper日志: 30
mycat日志 31
debug模式下分析sql执行。 33
异常日志 35
Mycat的配置 37
搞定schema.xml 37
schema标签 37
table标签 39
childTable标签 41
dataNode标签 42
dataHost标签 42
heartbeat标签 44
server.xml 46
优化配置 46
user标签 46
服务降级: 46
system标签 47
rule.xml 50
tableRule标签 50
function标签 50
quarantine标签 50
Mycat的join 51
分片join 51
全局序列号 58
全局序列号介绍 58
本地文件方式 58
数据库方式 58
本地时间戳方式 60
其他方式 61
自增长主键 61
Mycat 分片规则 64
分片规则概述 64
Mycat常用的分片规则 65
权限控制 75
多租户支持 75
常见问题与解决方案 77
常见问题与解答 77
高级进阶篇 85
读写分离 85
MySQL主从复制的几种方案 85
MySQL主从复制的几个问题 87
Mycat支持的读写分离 89
高可用与集群 91
MySQL高可用的几种方案 91
Mycat高可用方案 95
事务支持 97
Mycat里的数据库事务 97
XA事务原理 98
XA事务的问题和MySQL的局限 100
SQL拦截 102
Mycat SQL拦截机制 102
Mycat注解 104
注解原理 104
注解使用示例 105
Mycat Catlet 106
MyCAT支持的Catlet实现 107
jdbc多数据库支持 107
JDBC概述 107
JDBC 体系结构 108
JDBC API 108
JDBC 4.0 109
Mycat对JDBC 的支持 110
NoSQL支持(MongoDB) 110
MongoDB 111
Oracle 118
SQL Server 119
DB2 120
Spark SQL/Hive 120
PostgreSQL 123
管理命令与监控 124
压缩协议支持 132
压缩协议支持 132
配置说明 132
压缩性能测试 132
mysql压缩协议 132
Mycat-Web 134
Mycat-Web简介 134
Mycat-web架构及原理 134
Mycat-Web使用篇 134
Mycat-Web安装 134
Mycat-Web功能介绍 136
配置DEMO篇 140
垂直切分 140
读写分离 140
默认节点配置 141
生产实践篇 142
生产实践案例 142
Mycat读写分离案例 142
分表分库案例 144
SAAS多租户案例 144
每天2亿数据的实时查询案例 145
物联网26亿数据的案例 146
大型分布式零售系统案例 146
生产环境部署 148
单节点mycat部署 148
mycat的高可用与负载均衡 148
Mycat最佳实践 158
Mycat 如图所述通过后端接入不同的后端解决业务的完整需求。 158
Mycat实施指南 159
Mycat项目实施步骤 159
数据迁移与扩容实践 165
案例一:使用一致性Hash进行分片 165
案例二:使用范围分片 170
数据迁移的注意点 171
load data批量导入 172
使用mysqldump进行数据迁移 173
迁移一个表中的部分数据 174
版本选择与升级指南 175
版本选择 175
mycat1.2中的功能: 175
mycat1.3中的功能: 175
mycat1.4中的功能: 176
小结 176
性能调优 178
主机调优 178
JVM调优 178
MyCAT调优 182
MySQL通用调优 183
开发篇 185
加入Mycat 185
Mycat开发基础 185
Mycat架构分析 187
MyCAT和TDDL、Amoeba、Cobar的架构比较 187
框架比较 187
点评 189
其它资料 190
MyCAT线程模型分析 191
MyCAT线程模型 191
Mycat线程介绍 191
Cobar线程介绍 193
Cobar为什么那么多个线程池? 195
MyCAT与Cobar的比较 197
mycat的连接池 199
Mycat连接池模型 199
Mycat的网络通信框架 203
先从一个测试说起 203
测试环境 203
MyCAT网络框架 205
与Cobar原有NIO细节比较 219
MyCAT的AIO实现 221
Mycat的路由与分发流程 228
路由的作用 228
路由解析器 228
druid路由解析的两种方式 230
路由计算 232
路由计算的核心要素 236
单个表的路由计算 236
多个表的路由计算 237
全局表的路由计算 238
or语句的路由计算 238
系统语句的路由计算 241
相关类图和序列图 242
路由解析过程中的一些控制变量 245
Mycat的JDBC后端框架 246
JDBC方式访问后端数据库 246
JDBC相关类图 246
JDBCDatasource 246
JDBCConnection 248
JDBCHeartbeat 251
Mycat的事务管理机制 253
Mycat事务源码分析 253
Mycat的分页和跨库Join 255
多数据库支持的分页机制 255
ShareJoin代码分析 262
Mycat缓存 269
缓存介绍及代码分析 269
SQLRouteCache 270
TableID2DataNodeCache 272
ER_SQL2PARENTID 275
Mycat 的分片规则设计 279
分片规则设计架构 279
分片规则自定义实现 281
Mycat Load Data源码 284
load data代码分析 284
mysql压缩协议代码分析 287
Mycat外传 292
群英会 292
入门篇
MYCAT开源宣言
随着技术的不断进步,是否应该有一种比公司形态更有效的组织来支撑经济的进一步发展?
这种新型组织在以有形资产为核心的,以农业经济和工业经济为主导的社会是不可能取得成功的,而在以无形资产逐渐成为核心的,以知识经济为主导的信息社会将会成为可能。如国内崛起的分布式数据库中间件产品Mycat并不是由任何一家公司主导开发的,而是由民间自发组织的由那些喜爱它的不知名的程序员共同开发,如今该产品的发展速度极快其影响力也逐渐扩大。
国内外类似的开源组织和产品还有很多,这些开源产品潜力无限,无论开发效率和质量都逐渐超越任何一家公司的产品。这也导致了一些公司试图通过收购等手段遏制开源产品的发展。那么这些开源产品爱好者和贡献者获得了什么呢?在「无私奉献」的过程中他们获得了知识——信息社会最有价值的资产,他们可以用这些知识以任何形式换来不可估量的财富,信息社会的开源组织使「按劳分配」达到了前所未有的公平与公正。
企业所采取的期权激励、扁平化管理、自由工作时间等模式,正是对公司这种生产关系「自顶向下」的改良,以适应持久技术进步带来的生产力的高速发展。但公司的本质:追求股东利益最大化,使其不可能实现真正意义的去中心化。
信息社会的开源组织形态是对原有公司模式「自底向上」的一次颠覆式创新,他们将带来生产力的极速发展。这种组织先天具有开放、共享、敏捷、去中心化等等这些可以带来高效率的特性,可以想像拥有杰出技术与高效团队的开源组织可以创造出超越一切公司的更优秀的产品。
「每一个人为改变他的状况而自然做出的努力,当其具有施展的自由和安全时,就是一个十分强有力的原则,不需要借助其他,这种个人的努力,就能给社会带来财富和繁荣」亚当斯密的这段话是工业革命中的小公司向拥有国家特许经营权的垄断企业发出的呐喊。没有工业革命就没有现代公司存在的必要性;没有现代公司的存在和发展,工业革命的快速进程也无法出现。历史总在重演,信息社会的开源组织将亚当斯密这段话原封不动的回赠给了现代公司制度。它让知识经济不再只是少数资本家的游戏,而成为普通人登台表演的机会。技术不再高高在上,而是落地生根。开源组织将成为引领信息社会进步的发动机,接下来的竞争,就看谁能在无限的数字世界里更好的发挥开源组织的能量了,一个新的时代即将到来!
随着信息技术的持续快速发展和中国经济实力的不断加强,以Mycat为代表的中国开源组织和产品的价值和发展前景不可限量!
概述
数据库切分概述
OLTP和OLAP
在互联网时代,海量数据的存储与访问成为系统设计与使用的瓶颈问题,对于海量数据处理,按照使用场景,主要分为两种类型:联机事务处理(OLTP)和联机分析处理(OLAP)。
联机事务处理(OLTP)也称为面向交易的处理系统,其基本特征是原始数据可以立即传送到计算中心进行处理,并在很短的时间内给出处理结果。
联机分析处理(OLAP)是指通过多维的方式对数据进行分析、查询和报表,可以同数据挖掘工具、统计分析工具配合使用,增强决策分析功能。
对于两者的主要区别可以用下表来说明:
OLTP
OLAP
系统功能
日常交易处理
统计、分析、报表
DB 设计
面向实时交易类应用
面向统计分析类应用
数据处理
当前的, 最新的细节的, 二维的分立的
历史的, 聚集的, 多维的集成的, 统一的
实时性
实时读写要求高
实时读写要求低
事务
强一致性
弱事务
分析要求
低、简单
高、复杂
关系型数据库和NoSQL数据库
针对上面两类系统有多种技术实现方案,存储部分的数据库主要分为两大类:关系型数据库与NoSQL数据库。
关系型数据库,是建立在关系模型基础上的数据库,其借助于集合代数等数学概念和方法来处理数据库中的数据。主流的oracle、DB2、MS SQL Server和mysql都属于这类传统数据库。
NoSQL数据库,全称为Not Only SQL,意思就是适用关系型数据库的时候就使用关系型数据库,不适用的时候也没有必要非使用关系型数据库不可,可以考虑使用更加合适的数据存储。主要分为临时性键值存储(memcached、Redis)、永久性键值存储(ROMA、Redis)、面向文档的数据库(MongoDB、CouchDB)、面向列的数据库(Cassandra、HBase),每种NoSQL都有其特有的使用场景及优点。
Oracle,mysql等传统的关系数据库非常成熟并且已大规模商用,为什么还要用NoSQL数据库呢?主要是由于随着互联网发展,数据量越来越大,对性能要求越来越高,传统数据库存在着先天性的缺陷,即单机(单库)性能瓶颈,并且扩展困难。这样既有单机单库瓶颈,却又扩展困难,自然无法满足日益增长的海量数据存储及其性能要求,所以才会出现了各种不同的NoSQL产品,NoSQL根本性的优势在于在云计算时代,简单、易于大规模分布式扩展,并且读写性能非常高。
下面分析下两者的特点,及优缺点:
关系型数据库
1) 关系数据库的特点是:
- 数据关系模型基于关系模型,结构化存储,完整性约束。
- 基于二维表及其之间的联系,需要连接、并、交、差、除等数据操作。
- 采用结构化的查询语言(SQL)做数据读写。
- 操作需要数据的一致性,需要事务甚至是强一致性。
2) 优点:
- 保持数据的一致性(事务处理)
- 可以进行join等复杂查询。
- 通用化,技术成熟。
3) 缺点:
- 数据读写必须经过sql解析,大量数据、高并发下读写性能不足。
- 对数据做读写,或修改数据结构时需要加锁,影响并发操作。
- 无法适应非结构化存储。
- 扩展困难。
- 昂贵、复杂。
NoSQL数据库
1) NoSQL数据库的特点是:
- 非结构化的存储。
- 基于多维关系模型。
- 具有特有的使用场景。
2) 优点:
- 高并发,大数据下读写能力较强。
- 基本支持分布式,易于扩展,可伸缩。
- 简单,弱结构化存储。
3) 缺点:
- join等复杂操作能力较弱。
- 事务支持较弱。
- 通用性差。
- 无完整约束复杂业务场景支持较差。
虽然在云计算时代,传统数据库存在着先天性的弊端,但是NoSQL数据库又无法将其替代,NoSQL只能作为传统数据的补充而不能将其替代,所以规避传统数据库的缺点是目前大数据时代必须要解决的问题。如果传统数据易于扩展,可切分,就可以避免单机(单库)的性能缺陷,但是由于目前开源或者商用的传统数据库基本不支持大规模自动扩展,所以就需要借助第三方来做处理,那就是本书要讲的数据切分,下面就来分析一下如何进行数据切分。
何为数据切分?
简单来说,就是指通过某种特定的条件,将我们存放在同一个数据库中的数据分散存放到多个数据库(主机)上面,以达到分散单台设备负载的效果。
数据的切分(Sharding)根据其切分规则的类型,可以分为两种切分模式。一种是按照不同的表(或者Schema)来切分到不同的数据库(主机)之上,这种切可以称之为数据的垂直(纵向)切分;另外一种则是根据表中的数据的逻辑关系,将同一个表中的数据按照某种条件拆分到多台数据库(主机)上面,这种切分称之为数据的水平(横向)切分。
垂直切分的最大特点就是规则简单,实施也更为方便,尤其适合各业务之间的耦合度非常低,相互影响很小,业务逻辑非常清晰的系统。在这种系统中,可以很容易做到将不同业务模块所使用的表分拆到不同的数据库中。根据不同的表来进行拆分,对应用程序的影响也更小,拆分规则也会比较简单清晰。
水平切分于垂直切分相比,相对来说稍微复杂一些。因为要将同一个表中的不同数据拆分到不同的数据库中,对于应用程序来说,拆分规则本身就较根据表名来拆分更为复杂,后期的数据维护也会更为复杂一些。
垂直切分
一个数据库由很多表的构成,每个表对应着不同的业务,垂直切分是指按照业务将表进行分类,分布到不同的数据库上面,这样也就将数据或者说压力分担到不同的库上面,如下图:
系统被切分成了,用户,订单交易,支付几个模块。
一个架构设计较好的应用系统,其总体功能肯定是由很多个功能模块所组成的,而每一个功能模块所需要的数据对应到数据库中就是一个或者多个表。而在架构设计中,各个功能模块相互之间的交互点越统一越少,系统的耦合度就越低,系统各个模块的维护性以及扩展性也就越好。这样的系统,实现数据的垂直切分也就越容易。
但是往往系统之有些表难以做到完全的独立,存在这扩库join的情况,对于这类的表,就需要去做平衡,是数据库让步业务,共用一个数据源,还是分成多个库,业务之间通过接口来做调用。在系统初期,数据量比较少,或者资源有限的情况下,会选择共用数据源,但是当数据发展到了一定的规模,负载很大的情况,就需要必须去做分割。
一般来讲业务存在着复杂join的场景是难以切分的,往往业务独立的易于切分。如何切分,切分到何种程度是考验技术架构的一个难题。
下面来分析下垂直切分的优缺点:
优点:
· 拆分后业务清晰,拆分规则明确。
· 系统之间整合或扩展容易。
· 数据维护简单。
缺点:
· 部分业务表无法join,只能通过接口方式解决,提高了系统复杂度。
· 受每种业务不同的限制存在单库性能瓶颈,不易数据扩展跟性能提高。
· 事务处理复杂。
由于垂直切分是按照业务的分类将表分散到不同的库,所以有些业务表会过于庞大,存在单库读写与存储瓶颈,所以就需要水平拆分来做解决。
水平切分
相对于垂直拆分,水平拆分不是将表做分类,而是按照某个字段的某种规则来分散到多个库之中,每个表中包含一部分数据。简单来说,我们可以将数据的水平切分理解为是按照数据行的切分,就是将表中的某些行切分到一个数据库,而另外的某些行又切分到其他的数据库中,如图:
拆分数据就需要定义分片规则。关系型数据库是行列的二维模型,拆分的第一原则是找到拆分维度。比如:从会员的角度来分析,商户订单交易类系统中查询会员某天某月某个订单,那么就需要按照会员结合日期来拆分,不同的数据按照会员ID做分组,这样所有的数据查询join都会在单库内解决;如果从商户的角度来讲,要查询某个商家某天所有的订单数,就需要按照商户ID做拆分;但是如果系统既想按会员拆分,又想按商家数据,则会有一定的困难。如何找到合适的分片规则需要综合考虑衡量。
几种典型的分片规则包括:
· 按照用户ID求模,将数据分散到不同的数据库,具有相同数据用户的数据都被分散到一个库中。
· 按照日期,将不同月甚至日的数据分散到不同的库中。
· 按照某个特定的字段求摸,或者根据特定范围段分散到不同的库中。
如图,切分原则都是根据业务找到适合的切分规则分散到不同的库,下面用用户ID求模举例:
既然数据做了拆分有优点也就优缺点。
优点:
· 拆分规则抽象好,join操作基本可以数据库做。
· 不存在单库大数据,高并发的性能瓶颈。
· 应用端改造较少。
· 提高了系统的稳定性跟负载能力。
缺点:
· 拆分规则难以抽象。
· 分片事务一致性难以解决。
· 数据多次扩展难度跟维护量极大。
· 跨库join性能较差。
前面讲了垂直切分跟水平切分的不同跟优缺点,会发现每种切分方式都有缺点,但共同的特点缺点有:
· 引入分布式事务的问题。
· 跨节点Join的问题。
· 跨节点合并排序分页问题。
· 多数据源管理问题。
针对数据源管理,目前主要有两种思路:
A. 客户端模式,在每个应用程序模块中配置管理自己需要的一个(或者多个)数据源,直接访问各个数据库,在模块内完成数据的整合;
B. 通过中间代理层来统一管理所有的数据源,后端数据库集群对前端应用程序透明;
可能90%以上的人在面对上面这两种解决思路的时候都会倾向于选择第二种,尤其是系统不断变得庞大复杂的时候。确实,这是一个非常正确的选择,虽然短期内需要付出的成本可能会相对更大一些,但是对整个系统的扩展性来说,是非常有帮助的。
Mycat 通过数据切分解决传统数据库的缺陷,又有了NoSQL易于扩展的优点。通过中间代理层规避了多数据源的处理问题,对应用完全透明,同时对数据切分后存在的问题,也做了解决方案。下面章节就分析,mycat的由来及如何进行数据切分问题。
由于数据切分后数据Join的难度在此也分享一下数据切分的经验:
第一原则:能不切分尽量不要切分。
第二原则:如果要切分一定要选择合适的切分规则,提前规划好。
第三原则:数据切分尽量通过数据冗余或表分组(Table Group)来降低跨库Join的可能。
第四原则:由于数据库中间件对数据Join实现的优劣难以把握,而且实现高性能难度极大,业务读取尽量少使用多表Join。
什么是mycat,maycat从哪里来,又是如何解决这些问题的,下一章让我们来作分析。
Mycat前世今生
序章
如果我有一个32核心的服务器,我就可以实现1个亿的数据分片,我有32核心的服务器么?没有,所以我至今无法实现1个亿的数据分片。——Mycat’s Plan
上面这句话是Mycat 1.0快要完成时候的一段感言,而当发展到Mycat 1.3的时候,我们又有了一个新的Plan:
如果我们有10台物理机,我们就可以实现1000亿的数据分片,我们有10台物理机么?没有,所以,Mycat至今没有机会验证1000亿大数据的支撑能力——Mycat’s Plan 2.0
“每一个成功的男人背后都有一个女人”。自然Mycat也逃脱不了这个法则。Mycat背后是阿里曾经开源的知名产品——Cobar。Cobar的核心功能和优势是MySQL数据库分片,此产品曾经广为流传,据说最早的发起者对Mysql很精通,后来从阿里跳槽了,阿里随后开源的Cobar,并维持到2013年年初,然后,就没有然后了。
Cobar的思路和实现路径的确不错。基于Java开发的,实现了MySQL公开的二进制传输协议,巧妙地将自己伪装成一个MySQL Server,目前市面上绝大多数MySQL客户端工具和应用都能兼容。比自己实现一个新的数据库协议要明智的多,因为生态环境在哪里摆着。
Cobar使用起来也非常方便。由于是基于Java语言开发的,下载下来解压,安装JDK,然后配置几个不是很复杂的配置文件,猛击鼠标,就能启动Cobar。因此这个开源产品赢得了很多Java粉丝以及PHP用户的追捧。当然,笨人(Leader us)也跟着进入,并且在某个大型云项目中——“苦海无边”的煎着熬,良久。
爱情就像是见鬼。只有撞见了,你才会明白爱情是怎么回事。TA是如此神秘,欲语还羞。情窦初开的你又玩命将TA的优点放大,使自己成为一只迷途的羔羊。每个用过Cobar的人就像谈过一段一波三折、荡气回肠的爱情,令你肝肠寸断。就像围城:里面的人已经出不来了,还有更多的人拼命想挤进去。
仅以此文,献给哪些努力在IT界寻求未来的精英和小白们,还有更多被无视的,正准备转行的同仁,同在江湖混,不容易啊,面试时候就装装糊涂,放人家一马,说不定,以后又是一个Made in China的乔布斯啊。
如果我有一个32核心的服务器,我就可以实现1个亿的数据分片,我有32核心的服务器么?没有,所以我至今无法实现1个亿的数据分片。——Mycat ‘s Plan
曾经的TA
曾经的TA,长发飘飘,肤若凝脂,国色天香,长袖善舞,所以,一笑倾城。
那已成传说,一如您年少时的坚持:“书中自有黄金屋…”
Cobar曾是多少IT骚年心中的那个TA,有关Cobar的这段美好的描述(不能说是广告)俘虏了众多程序猿躁动纯真的心:
Cobar是阿里巴巴研发的关系型数据的分布式处理系统,该产品成功替代了原先基于Oracle的数据存储方案,目前已经接管了3000+个MySQL数据库的schema,平均每天处理近50亿次的SQL执行请求。
50亿有多大?99%的普通人类看到这个数字,已经不能呼吸。当然,我指的是**RMB**。99%的程序猿除了对工资比较敏感,其实对数字通常并不感冒。上面这个简单的数字描述,已立刻让我们程序型的大脑短路。恨不得立刻百度Cobar,立刻Download,立刻熬夜研究。做个简单的推算,50亿次请求转换为每个schema每秒的数据访问请求即TPS,于是我们得到一个让自己不能相信的数字:20TPS,每秒不到20个访问。
Cobar最重要的特性是分库分表。Cobar可以让你把一个MySQL的Table放到10个甚至100个位于不同物理机上的MySQL服务器上去存储,而在用户看来是一张表(逻辑表)。这样功能很有价值。比如:我们有1亿的订单,则可以划分为10个分片,存储到2-10个物理机上。每个MySQL服务器的压力减少,而系统的响应时间则不会增加。看上去很完美的功能,而且潜意识里,执行这句SQL:
select count(*) from order
100%的人都会认为:会返回1条数据,但事实上,Cobar会返回N条数据,N=分片个数。
接下来我们继续执行SQL:
select count(*) from order order by order_date
你会发现奇怪的乱序现象,而且结果还随机,这是因为,Cobar只是简单的把上述SQL发给了后端N个分片对应的MySQL服务器去执行,然后把结果集直接输出….
再继续看看,我们常用的Limit分页的结果…可以么?答案是:不可以。
这个问题可以在客户端程序里做些工作来解决。所以随后出现了Cobar Client。据我所知,很多Cobar的使用者也都是自行开发了类似Cobar Client的工具来解决此类问题。从实际应用效果来说,一方面,客户端编程方式解决,困难度很高,Bug率也居高不下;另一方面,对于DBA和运维来说,增加了困难度。
当你发现这个问题的严重性,再回头看看Cobar的官方文档,你怅然若失,四顾茫然。
接下来,本文将隐藏在Cobar代码中那些不为人知的秘密逐一披漏,你洞悉了这些秘密,就会明白Mycat为什么会横空出世。
Cobar的十个秘密
第一个秘密:Cobra会假死?
是的,很多人遇到这个问题。如何来验证这点呢?可以做个简单的小实验,假如你的分片表中配置有表company,则打开mysql终端,执行下面的SQL:
select sleep(500) from company;
此SQL会执行等待500秒,你再努力以最快的速度打开N个mysql终端,都执行相同的SQL,确保N>当前Cobra的执行线程数:
show @@threadpool
的所有Processor1-E的线程池的线程数量总和,然后你再执行任何简单的SQL,或者试图新建立连接,都会无法响应,此时
show @@threadpool
里面看到TASK_QUEUE_SIZE已经在积压中。
不可能吧,据说Cobra是NIO的非阻塞的,怎么可能阻塞!别激动,去看看代码,Cobra前端是NIO的,而后端跟Mysql的交互,是阻塞模式,其NIO代码只给出了框架,还未来得及实现。真相永远在代码里,所以,为了发现真相,还是转行去做码农吧!貌似码农也像之前的技术工人,越来越稀罕了。
第二个秘密:高可用的陷阱?
每一个秘密的背后,总是隐藏着更大的秘密。Cobra假死的的秘密背后,还隐藏着一个更为“强大”的秘密,那就是假死以后,Cobra的频繁主从切换问题。我们看看Cobra的一个很好的优点——“高可用性”的实现机制,下图解释了Cobra如何实现高可用性:
分片节点dn2_M1配置了两个dataSource,并且配置了心跳检测(heartbeat)语句,在这种配置下,每个dataNode会定期对当前正在使用的dataSource执行心跳检测,默认是第一个,频率是10秒钟一次,当心跳检测失败以后,会自动切换到第二个dataSource上进行读写,假如Cobra发生了假死,则在假死的1分钟内,Cobra会自动切换到第二个节点上,因为假死的缘故,第二个节点的心跳检测也超时。于是,1分钟内Cobra频繁来回切换,懂得MySQL主从复制机制的人都知道,在两个节点上都执行写操作意味着什么?——可能数据一致性被破坏,谁也不知道那个机器上的数据是最新的。
还有什么情况下,会导致心跳检测失败呢?这是一个不得不说的秘密:当后端数据库达到最大连接后,会对新建连接全部拒绝,此时,Cobar的心跳检测所建立的新连接也会被拒绝,于是,心跳检测失败,于是,一切都悄悄的发生了。
幸好,大多数同学都没有配置高可用性,或者还不了解此特性,因此,这个秘密,一直在安全的沉睡。
第三个秘密:看上去很美的自动切换
Cobar很诱人的一个特性是高可用性,高可用性的原理是数据节点DataNode配置引用两个DataSource,并做心跳检测,当第一个DataSource心跳检测失败后,Cobar自动切换到第二个节点,当第二个节点失败以后,又自动切换回第一个节点,一切看起来很美,无人值守,几乎没有宕机时间。
在真实的生产环境中,我们通常会用至少两个Cobar实例组成负载均衡,前端用硬件或者HAProxy这样的负载均衡组件,防止单点故障,这样一来,即使某个Cobar实例死了,还有另外一台接手,某个Mysql节点死了,切换到备节点继续,至此,一切看起来依然很美,喝着咖啡,听着音乐,领导视察,你微笑着点头——No problem,Everything is OK!直到有一天,某个Cobar实例果然如你所愿的死了,不管是假死还是真死,你按照早已做好的应急方案,优雅的做了一个不是很艰难的决定——重启那个故障节点,然后继续喝着咖啡,听着音乐,轻松写好故障处理报告发给领导,然后又度过了美好的一天。
你忽然被深夜一个电话给惊醒,你来不及发火,因为你的直觉告诉你,这个问题很严重,大量的订单数据发生错误很可能是昨天重启cobar导致的数据库发生奇怪的问题。你努力排查了几个小时,终于发现,主备两个库都在同时写数据,主备同步失败,你根本不知道那个库是最新数据,紧急情况下,你做了一个很英明的决定,停止昨天故障的那个cobar实例,然后你花了3个通宵,解决了数据问题。
这个陷阱的代价太高,不知道有多少同学中枪过,反正我也是躺着中枪过了。若你还不清楚为何会产生这个陷阱,现在我来告诉你:
1. Cobar启动的时候,会用默认第一个Datasource进行数据读写操作;
2. 当第一个Datasource心跳检测失败,会切换到第二个Datasource;
3. 若有两个以上的Cobar实例做集群,当发生节点切换以后,你若重启其中任何一台Cobar,就完美调入陷阱;
那么,怎么避免这个陷阱?目前只有一个办法,节点切换以后,尽快找个合适的时间,全部集群都同时重启,避免隐患。为何是重启而不是用节点切换的命令去切换?想象一下32个分片的数据库,要多少次切换?
MyCAT怎么解决这个问题的?很简单,节点切换以后,记录一个properties文件( conf目录下),重启的时候,读取里面的节点index,真正实现了无故障无隐患的高可用性。
第四个秘密:只实现了一半的NIO
NIO技术用作JAVA服务器编程的技术标准,已经是不容置疑的业界常规做法,若一个Java程序员,没听说过NIO,都不好意思说自己是Java人。所以Cobar采用NIO技术并不意外,但意外的是,只用了一半。
Cobar本质上是一个“数据库路由器”,客户端连接到Cobar,发生SQL语句,Cobar再将SQL语句通过后端与MySQL的通讯接口Socket发出去,然后将结果返回给客户端的Socket中。下面给出了SQL执行过程简要逻辑:
SQL->FrontConnection->Cobar->MySQLChanel->MySQL
FrontConnection 实现了NIO通讯,但MySQLChanel则是同步的IO通讯,原因很简单,指令比较复杂,NIO实现有难度,容易有BUG。后来最新版本Cobar尝试了将后端也NIO化,大概实现了80%的样子,但没有完成,也存在缺陷。
由于前端NIO,后端BIO,于是另一个有趣的设计产生了——两个线程池,前端NIO部分一个线程池,后端BIO部分一个线程池。各自相互不干扰,但这个设计的结果,导致了线程的浪费,也对性能调优带来很大的困难。
由于后端是BIO,所以,也是Cobar吞吐量无法太高、另外也是其假死的根源。
MyCAT在Cobar的基础上,完成了彻底的NIO通讯,并且合并了两个线程池,这是很大一个提升。从1.1版本开始,MyCAT则彻底用了JDK7的AIO,有一个重要提升。
第五个秘密:阻塞、又见阻塞
Cobar本质上类似一个交换机,将后端Mysql 的返回结果数据经过加工后再写入前端连接并返回,于是前后端连接都存在一个“写队列”用作缓冲,后端返回的数据发到前端连接FrontConnection的写队列中排队等待被发送,而通常情况下,后端写入的的速度要大于前端消费的速度,在跨分片查询的情况下,这个现象更为明显,于是写线程就在这里又一次被阻塞。
解决办法有两个,增大每个前端连接的“写队列”长度,减少阻塞出现的情况,但此办法只是将问题抛给了使用者,要是使用者能够知道这个写队列的默认值小了,然后根据情况进行手动尝试调整也行,但Cobar的代码中并没有把这个问题暴露出来,比如写一个告警日志,队列满了,建议增大队列数。于是绝大多数情况下,大家就默默的排队阻塞,无人知晓。
MyCAT解决此问题的方式则更加人性化,首先将原先数组模式的固定长度的队列改为链表模式,无限制,并且并发性更好,此外,为了让用户知道是否队列过长了(一般是因为SQL结果集返回太多,比如1万条记录),当超过指定阀值(可配)后,会产生一个告警日志。
<system><property name="frontWriteQueueSize">1024</property></system>
第六个秘密:又爱又恨的SQL 批处理模式
正如一枚硬币的正反面无法分离,一块磁石怎样切割都有南北极,爱情中也一样,爱与恨总是纠缠着,无法理顺,而Cobar的 SQL 批处理模式,也恰好是这样一个令人又爱又恨的个性。
通常的SQL 批处理,是将一批SQL作为一个处理单元,一次性提交给数据库,数据库顺序处理完以后,再返回处理结果,这个特性对于数据批量插入来说,性能提升很大,因此也被普遍应用。JDBC的代码通常如下:
String sql = "insert into travelrecord (id,user_id,traveldate,fee,days) values(?,?,?,?,?)";
ps = con.prepareStatement(sql);
for (Map<String, String> map : list) {
ps.setLong(1, Long.parseLong(map.get("id")));
ps.setString(2, (String) map.get("user_id"));
ps.setString(3, (String) map.get("traveldate"));
ps.setString(4, (String) map.get("fee"));
ps.setString(5, (String) map.get("days"));
ps.addBatch();
}
ps.executeBatch();
mit();
ps.clearBatch();
但Cobar的批处理模式的实现,则有几个地方是与传统不同的:
· 提交到cobar的批处理中的每一条SQL都是单独的数据库连接来执行的
· 批处理中的SQL并发执行
并发多连接同时执行,则意味着Batch执行速度的提升,这是让人惊喜的一个特性,但单独的数据库连接并发执行,则又带来一个意外的副作用,即事务跨连接了,若一部分事务提交成功,而另一部分失败,则导致脏数据问题。看到这里,你是该“爱”呢还是该“恨”?
先不用急着下结论,我们继续看看Cobar的逻辑,SQL并发执行,其实也是依次获取独立连接并执行,因此还是有稍微的时间差,若某一条失败了,则cobar会在会话中标记”事务失败,需要回滚“,下一个没执行的SQL就抛出异常并跳过执行,客户端就捕获到异常,并执行rollback,回滚事务。绝大多数情况下,数据库正常运行,此刻没有宕机,因此事务还是完整保证了,但万一恰好在某个SQL commit指令的时候宕
展开阅读全文