引子

分布式数据库,已经进入了全面快速发展阶段,这种发展,是与时俱进的,与人的需求是分不开的,因为现在信息时代的高速发展,导致数据量和交易量越来越大。这种现象首先导致的就是存储瓶颈,因为MySQL数据库,实质上,还是一个单机版本的数据库,而只要是单机,就必然会遇到的一个问题就是存储问题,因为存储是硬需求,而CPU和内存如果不够的话,只是性能不好,并不会直接否定方案或者架构。

存储问题的解决,其实我们每一家公司或者个人,都一直在努力着。解决方案大概有三个方面

增大磁盘

这种方式,应该是最直接,最简单的方案了,因为磁盘空间不足了,当然加磁盘是手到病除,比如现在是800G,可以增加到2T,这是没问题的,如果现在已经达到了2T,当然,还是可以增加到5T的盘,但实际上,这个时候可能DBA就要捏把汗了,这么大数据量的MySQL实例,如何运维?如果数据坏了,如何恢复呢?时间成本呢?5T的数据量,已经非常吓人了,估计在业内各大公司,没有DBA想要自己运维的MySQL实例达到这个量级吧?其实我个人认为,这个已经是不能接受的量了,最合适的最好保持在1T以下即可。超过这个就要想办法了。当然这个数据量不宜达到这个大小的原因,可能会有人考虑到这是性能的问题,其实不然,或者性能问题很小,因为InnoDB采用的是B+树的存储方案,小表最坏情况下没有查到数据是要找3层,也就是3个页面的IO,而大表需要的是4个页面的IO,影响不大。

数据压缩

为了减少数据对磁盘空间的占用,我们通常也会将数据做压缩处理,通过一个语句即可搞定,是InnoDB原生支持的一种方式,一般情况下,会将数据占用减少到原来的三分之一到一半不等,效果还是足够明显的,不过这样处理之后的数据,在性能上会有所下降,对于响应要求比较高的业务,可能需要谨慎考虑一下,但这种方式,可能还是治标不治本,在数据量继续增长的情况下,过段时间之后,依然面临相同的问题,这种情况下,就不能继续使用这种方式来实现了。

数据分片

数据分片的解决方案,现在业内也用得很多,这种方案已经超出了MySQL本身,包括HBase、Redis等也都在使用这种方案,应该说这种方案是最具扩展性的,并且可以称得上是无限扩展,而上面两种方案,根本谈不上扩展性。所以这种方案在业内成为主流,并且这种方案才能称得上是分布式存储,具体的实现也层出不穷,当然也存在优秀的分布式解决方案,也存在一些“伪”分布式方案了。

分布式解决方案需求

扩展性

使用分布式,其实最主要的就是扩展性,如果空间不足了,可以很方便容易的扩展节点个数,并且将数据做新的平衡处理。这个过程要不影响业务使用,对业务透明。

支持事务

分布式数据库,对于业务本身,使用方面与单机区别不大,也就是对业务透明,因为使用MySQL是支持事务的,那么MySQL变身为分布式之后,事务特性还是不能少的,所以整体上看来,还是要支持分布式事务。

SQL语句无限制

业务需求的多样性,导致在SQL需求上面,都是比较广泛的,针对业务的透明性,如果某些SQL语句不支持,那这样导致的问题是,一方面,限制了业务程序的功能和性能,另一方面,导致业务程序与“分布式数据库”的捆绑问题。

性能足够好

使用分布式数据库,其实基本上是对性能的要求比较低的业务才会这样选择,即使是这样,还是性能越高,越多人才会选择这样的分布式数据库。

元数据变更透明性

元数据变更,在任何数据库中都是存在的,在单点情况下,改表操作我们有多种友好的方法来实现,但到了分布式环境下,可能这种操作就成为了问题,因为数据的分片导致了元数据的变更需要多点修改,进而很多问题就来了,比如原子性、数据可见性、正确性等等,所以这是最基本的问题。

底层数据库的高可用性

话说经济基础决定上层建筑,在分布式数据库中也是一样的,如果底层数据库的不稳定,或者数据复制延迟,亦或出现数据不一致的问题,则上层应用的访问正确性就没法保证,所以底层数据库最基本的就是保证数据一致性(高可用)。

流行分布式数据库解决方案

中间件分库分表(伪分布式)

在MySQL界,一个存在很久的话题,就是:哪个中间件实现的分库分表方案比较好啊?

当然对于同一个问题,不同人有不同的理解,也都具有两面性的特征,有人说好,也有人说不好,我们首先看一下这种方案是如何实现的。

三思!大规模MySQL运维陷阱之基于MyCat的伪分布式架构-LMLPHP

MyCat的实现架构大概上上图所示,其实如果只看图的话,这样的架构真是完美无缺,自动分片,自动聚合,分布均衡都实现的非常好。但事实并非如此。

我们可以通过问答的方式,一步步认清楚这种方式的核心问题:

MyCat如何知道数据分片原理,或者说他是如何决定路由路径的?

这个问题,在图上面是看不出来的,MyCat是如何定义或者决定一条SQL语句的执行方式,或者如何决定去哪里取数据及写入到哪里的?解决这样的问题是需要某一个地方来存储的,它的做法是——schema.xml配置文件,竟然用配置文件来搞定。那这样问题就多了,修改分库分表规则之后,如何保证配置与数据同步更新?即使不使用schema.xml配置文件,而是用数据库存储,那配置规则的变更与数据节节点中数据的迁移,也是没办法保证统一的,势必会对业务造成影响。

如果需要扩展节点了,并且需要做rebalance,如何来做?

很多用户,基本都是重新准备一套集群,或者先把数据一点点手动导出导入,导到目标节点之后,然后去手动修改schema.xml配置文件,然后做一次reload操作,这样就实现了重新路由,但这样同样会导致上面的结果。并且这个过程,需要处理好多数据,处理完成之后各种检查,并且占用空间需要两倍,这样折腾,一个DBA只要干一次,可能就有辞职的冲动。

全局表是什么东西?

MyCat支持一个所谓的全局表,用来解决跨节点数据聚合的问题,实现方法是在每一个分片上面,都创建这样的全局表,它的定义是不怎么修改,查询比较频繁表可以定义为全局表,这样的话在每一个分片节点上,只要用到这个表,就可以实现本地查询连接等操作,是可以解决部分问题,但问题是如果分片多的话(假如分片100个),如何保证数据一致性?这么多节点的XA事务影响是什么?如果出现不一致或者访问错误,引起的问题就是数据结果错误,这样的结果肯定不是业务想要看到的吧?这还不是最关键的,一个数据库集群,搞这么一个特殊处理的东西是何道理?

MyCat究竟做了什么事情?

作为一个中间层,本职工作应该是接收客户端的SQL请求,然后通过语法分析,根据读写原则,然后确定一个集群中一个读写节点即可,然后就等着结果集的返回,对于结果集本身,中间层并不需要去关心,他只需要将结果集(或者异常)原原本本发回给客户端即可。而MyCat做的事情,远比这个多,在语法分析之后,再做语义分析,拿到对应数据库表结构,同时判断这个表的分发路由规则,再找到语句中的数据及涉及到的列,再决定路由到哪个分片中,如果在分发时路由规则配置错误,或者程序计算错误,会导致整个语句的结果出现不可预知的问题。请问这前半部分,是一个中间层应该做的事情么?竟然还要关心语句中涉及到的表结构,主键,数据等信息,这其实都是数据库要做的事情啊,实则是越俎代庖,再请问,所做的这些事情,能比一个专业数据库做得更好么?咱再看后半部分,等收到结果集之后,MyCat为了处理一些结果集的聚合计算,需要把各个节点本来已经封装好的结果集(二进制MySQL协议流数据),解析出来,然后通过需要计算出来(这个计算有可能非常慢,并且不是所有的都可以搞定),计算完成之后,再打包成MySQL协议流数据,传给客户端,请问这样的中间层,做了这么多事情,性能如何保证?而本身这些聚合计算Order By、Group By的处理,本身是数据库的事情,实则还是越俎代庖。

通过SQL语句的变换,实现分布式是不是有点困难?

MyCat这种中间层,代表了宣称分布式数据库的一类使用方式,但这种实现方法实际上都是通过在SQL语句上做文章,从客户端拿到的是SQL语句,给后端数据库的也是SQL语句,但这两个SQL语句是经过变换的,当然这种方法也只能这样,因为后端数据库只接收SQL语句,试问,一个复杂的SQL语句查询操作,通过SQL变换或重写,就能实现对不同分片数据库的分布式查询?想想就清楚了,虽然SQL语句通用灵活,但可扩展性或者重写的逻辑还是有点复杂的吧?当然了,有人可能会说,我们有兜底的啊,大不了把这个语句就改一下库名表名然后其它保持不变分给每一个节点去执行,这样总没问题吧,是的,你说的没错。

在同一个事务中要修改不同节点的数据是如何处理的?

这个问题就是我们通常所说的分布式事务了,究竟是怎么回事呢,MyCat下面对的是MySQL Server,也就是说MyCat只能用SQL语句与MySQL Server交流,这样就是局限于MySQL的SQL语句的功能了,那在分布式实现上面,MySQL XA本身有多少人用,MyCat如果实现一个跨节点的数据更新,不用MySQL XA,还能用其它什么?别无他选,本身依赖一个没有太多人用,并且可能存在很多问题,包括性能,Bug的功能,这样上层MyCat乃至应用程序的可靠性如何保证?当然基于这些问题,有些方案选择不用XA,如果某些节点失败了,选择忽略不解决,这当然也可以,妥协嘛————不需要底线的。

MyCat后端数据库的架构是什么,如何保证稳定可靠高可用?

这个据某些文章宣传说,之前可以选择主从复制,现在可以选择Galera Cluster,或者也可以选择更新的MGR,当然不得不说,从前到后,可能确实保证了更好的可靠性,但有一个很大的问题是,Galera的门槛比较高,遇到问题的话,很少人能解决掉(很自豪的是,去哪儿可以称得上全球为数不多的使用Galera比较多并且使用的比较好的公司),再到MGR,本身还得等,能用还要比较长的时间,这问题还是要回到主从复制,这是老问题了,主从复制的一致性很难保证,MyCat如果通过读写分离策略将读打到从上面,而这个正好有延迟,这样产生的后果可能是整个应用程序的计算结果是错误的,当然可以说有延迟检查,那问题是,延迟检查的话,是不是还有一个参数可以配置呢?如果延迟超过100秒的话就去查主库?没错,不过100秒难道就不是延迟了?那可以设置为0,看到的0,你以为真的是0?其实还是主从复制的劣根性。所以问题还是回到了起点,经济基础决定上层建筑,基础不好,上层如何是好?

分片多了的情况下,性能是如何保证损失最小的?

这个问题,我并不知道MyCat有没有做过优化,比如10个分片,如果一个语句的执行会涉及到这十个分片,那在每个分片上重写语句之后,就要分别在这十个分片上执行对应的语句了,执行时是串行,还是并行?串行的话,性能必然会下降10倍以上,所以做得好点的话,就是并行了,但并行的实现方法是,在MyCat这个连接上面,创建10个线程,去处理这十个节点的执行情况,那这样的连接多了,MyCat产生的对系统的冲击就非常大了,性能还是不行。当然也可以说,这里做了连接池,没错,是可以的,但MyCat是这样做的么?这样做了性能又如何呢?如果有一个超时,整个访问就失败了。

配置文件或者配置库出问题,整个集群会出现什么情况?

前面已经说了,MyCat用的是schema.xml来配置的分库分表策略,这是一个配置文件,MyCat本身的高可用,如果配置多套的话,他们的同步问题,是如何解决的?如果没有同步(或者同步出问题,或者延迟等),某一个MyCat挂了,业务切换到其它的MyCat时,此时的情况就是,故障……故障……。因为数据都乱了。有可能造成的问题是,写入了错误的位置,进而导致整个集群的数据被写坏。感觉比直接被删了还严重。同样的问题,感觉MyCat可能会优化这点,也许会改为将其集中存储在某一个数据库中,这样集中管理的话就不需要同步了,想法是好的,但这相当于是把鸡蛋放在一个篮子里面了,如果这个配置库出问题了,业务何去何从?

DDL如何进行?

这个问题也许是每个人都关心的事情了,MyCat把数据都分而不相关的分片MySQL节点了,这样很多在单点上的改表策略都不能用了,而DDL又是一个必须要保证每个节点同时完成的事情,那在分布式上面是如何保证的呢?根据我的调研,好像现在使用MyCat的人,都是通过“同一时刻启动在每一个节点上更新表结构”这样的方法来做的,当然还得选择是半夜,当然我个人觉得也是可行的,因为毕竟已经使用了它,而没有更好的办法来解决这个问题。当然咱再说后果,如果做不到无缝原子修改,那对业务的影响不是一星半点,可能会有很多SQL会报表不存在的问题。如果一个语句和另一个语句修改完成时间相差比较多的话,两个相减的时间就是故障时间了。

据我调研,MyCat还实现了自动故障切换的功能,请问这个靠谱么?

我们现在讨论的是分布式架构方案,而这个问题讲的情况是,某一个MyCat发现了后端数据库连不上了,会自动切换的功能,这就非常明显了,我们要的是分布式,某“一个”MyCat节点认为的问题就真的是他所认为的吗?也就是说,一个节点并不能保证他判断的或者他看到的现象是真实的,那这种情况下就存在误切换的情况,而如果其它中间层节点还不知道这个情况,或者未及时收到切换的消息,就出现了多点写入的问题,挺可怕的。这不是自相矛盾吗?我们要的是分布式,结果又存在“独断”的环节,可靠性又下降了不少。关于分布式监控切换的问题,因为在去哪儿用的mysql-sentinel对Galera Cluster做的监控,我对这点深有感触,所以不得不在这里讲一下。

在MyCat上面备份是如何做的?能做到恢复一个快照吗?

说起备份,做为数据库使用者,应该没有一个不清楚,没有一个人会觉得他不重要吧?当然,重要是重要,但这种事情属于重要不紧急的工作,但没有是不行的,这个连公司内审这一关都过不了,也许我们每一个人都不会希望能用到他。

言归正传,话说这么重要的备份工作,在MyCat上又是什么情况呢?可能了解一些基本原理的人都比较清楚,Xtrabackup、mysqldump等也都是可以用的,但备份完了之后呢,可能心里还是感觉没底,因为这样的工具,只能对一个MySQL节点做备份,如果分10个分片(10个MySQL节点)的话,可以通过备份十次即可完成,但需要注意的是,备份了十次产生了十个备份集,而并不是一个备份集,这十个备份集之间是完完全全没有关系的,此时我可能就提出一个比较极端的问题来:

如果哪天(当然我们都不希望有这样的一天),整个机房挂了,当然假如“幸运”的是,有备份,那在这种情况下,如何恢复一个可用的数据一致及完整的集群快照呢?

这个时候可能会有人很快地说,将十个备份集都恢复了启动了即可。但问题是这十个没有关系,备份时间又不是同一时刻完成的,同一个表的十个分片,最新数据有的是8点的,有的是9点的,或者有的甚至是昨天的。这样恢复出来的表,能用么?基于这样的表产生的查询结果,靠谱么?可想而知。

当然可能也有人会说,我们的数据不需要一致快照,或者更有甚者只需要备份元数据路由表或者配置文件即可,那这样就没问题了,如果MyCat只是定位于用来存储Zabbix监控数据,或者日志数据,可以丢失不要的数据,一文不值的数据,那我觉得没毛病。

或许有人还会说,我们的机房不会挂,或者我们的存储本来就是跨机房的,挂了的话直接切到另外的机房就行了,那此时又有问题了,如果切换的时候,有复制延迟,丢失了部分数据,那整个集群又会出问题,因为只要有一个分片的数据出问题,整个集群就有问题了。或者另一个问题就是,假设你的机房真的不会挂,但我们经常会遇到的需求是,我要取前几天某时刻的数据,那此时还是需要通过备份然后恢复一个快照,这个时候还有何话可说,你告诉我究竟如何做到?

可能还会有人有疑问,他会说我们是逻辑备份啊,这样备份出来的是整个库或者表的一致性快照,这不就解决问题了么?我很同意这位同学的看法,说得对极了,是可以很完美地解决一致性问题,但只要熟悉一点点MySQL的人都知道,类似mysqldump这样的逻辑备份工具,是何其慢?现在都用分布式存储了,那肯定是数据量非常大,这个时候还在使用这样的逻辑备份?你是想干哈?即使备份完成了,那有没有试过逻辑数据的恢复?几个G的数据要恢复多久,你算过没有?想想都头疼。一条不归路。。。

如果已经在使用MyCat了,发现他的风险确实太大了,我如何能下掉呢?

这个问题非常好,说明你已经在思考做为一个数据负责人,如何保证数据的可靠性和避免风险的问题了,MyCat风险确实高,但如果已经上了“贼船”并且想下掉的话,此时我可能想问一下(做一回事后诸葛亮),上这个架构的时候为什么不多考虑一下呢?公司的数据就是金钱,你这样想上就上,想下就下,来回折腾,能升值么?万一数据写乱了,这个时候可没有人赔你钱,还不如上云呢。

不过既然上了,那咱就聊聊如何下掉的问题,我目前感觉最靠谱最稳妥的办法,貌似只有一个,步骤如下:

先停业务,将所有的写业务都停止(也不用找深夜时间了,因为12小时根本搞不完)。

通过上面所讲的mysqldump做逻辑备份,将所有的库导出来,生成.sql文件。

然后找一个靠谱的MySQL架构(真正的分布式数据库,或者磁盘足够大的话可以不采用分布式,采用Share Nothing的方案即可,也许你需要的并不是分布式,只是被忽悠了),将.sql文件导入进去。

然后就将读业务迁移到新的数据库架构上面去。

将写业务也迁移到新的数据库架构上面去,然后启动他们,这个时候应该是可以提供正常的数据库服务了。

我们可以注意一下这个过程,从第1步,到第5步,需要多少时间?这个当然是硬时间,是要移动数据的,逻辑备份和恢复都那么慢,我觉得时间的单位可以用天来统计了。

这个时候负责人就可以想想,我用MyCat是图什么啊,业务的免战牌挂了好几天,只是为了弥补当年的一个错误决定,追悔莫及。

当然也许有些人也会有其它办法,但因为各个分片都是相互独立的,还是存在上面的所说的在不停止业务的情况下的“一致性快照”的问题。

最后我想说的是,对公司的数据,一定要慎之又慎,要时刻保持负责的态度,折腾数据真的不能升值啊。

MyCat的配置复杂吗?上手容易么?

我们只需要看一个图片就行了。你能想象这是它的配置文件么?看了之后我估计你也没有任何使用它的欲望了,很多人在使用之后,是这样评价的:

三思!大规模MySQL运维陷阱之基于MyCat的伪分布式架构-LMLPHP

,配置文件如下:

三思!大规模MySQL运维陷阱之基于MyCat的伪分布式架构-LMLPHP

竟然是一个XML文件,这个产品经理当时是如何想的?后面也没有想着做个优化?

最后一个问题,现在做分库分表做得好的有哪些?

还有哪些?一个都没有,这是一条不归路啊。因为说白了,他是一种伪分布式方案,基础是不好的,上层就做不好,所以永远是在补各种坑,走得很累,累人累己。现在可以回过头来想一想,为什么一些很强大知名的公司做的中间件产品,并没有做这些事情,比如ProxySQL、Maxscale、MySQL Router等,为什么呢?难道他们的技术不好?或者是没有这样的需求?我还是觉得,需求是有的,人与人、业务与业务的需求,是一样的,但解决方法可能就不一样了,他们可能早就认为,这是一条错误的道路,所以就不会去选择走,而MyCat这种方案,可能就要回过头来想想未来的路了。

互联网处理大规模在线访问数据的做法

解耦思想充斥着互联网技术栈的方方面面,为什么这样做?我想应该是大家都不想拖泥带水,也不想牵一发而动全身罢了。而在MySQL数据库层面,使用了重量级的中间层之后,你会发现,大一统看起来是很不错,但这样牵一发很可能动全身,这其实并不是好事情。

MySQL这种数据库是在互联网领域兴起并被大规模使用的,在比如账务、订单、计费等等关键业务上使用的也不在少数。在大型互联网公司,MySQL的使用一定是分库分表的,通过各种垂直切分和水平切分,把一个数据库变成一堆数据库,也就是所说的数据库集群。但是很少看到在使用的MySQL的时候会在上面架设一层重量级的所谓分布式的中间层,这样导致的就是紧耦合了,与互联网的高效联运相违背,互联网的数据库集群都应该是物理上离散的,每一个实例可以自由的控制和迁移,也就是所谓的解耦。

解耦的好处可以让你自由处理每一个独立的实例或者集群,方便根据实际情况应对业务带来的变数,该升级的升级,该缩容的缩容,为每一个业务或者每一个业务的数据库定义不同的维护等级,灵活掌握,随机而变。

解耦的好处可以提升数据库的绝对性能,数据从业务到磁盘,或者从磁盘到业务,经历的路径越短,其效率也就越高。很多使用MySQL的做法就是用一个简单的中间层分发SQL,这样的中间层功能清晰、结构简单、灵活高效,一般不会损失太多性能,这就像MySQL出品的MySQL Router,MariaDB出品的Maxscale,Percona的ProxySQL,还有国内的正火的极数云舟的Arkproxy,他们的行为,都为选择使用中间层去实现数据架构指明了一个方向。

解耦的好处可以让你的数据库只干数据库最擅长的事情,它能保证你的数据安全存储,它能保证你的数据高效存取,它能保证你数据并发处理,它能保证你的数据灵活接入,这还不够吗?

综上所述,我们再次确信一个真理,MySQL因简单而高效,因高效而流行,不要舍本逐末,听信忽悠,误入歧途。

当然如果不想在业务层做分库分表来适配MySQL数据库的架构,而想通过对业务透明的分布式数据库来提供业务服务的话,我推荐真正意义的分布式数据库解决方案,他能解决的是强大的存储扩展能力、分布式运算、对业务读写透明以及友好的故障转移等问题,这是他们的优势,也是他们的初衷。

真正意义的分布式解决方案

真分布式方案,其实已经不用太多说了,达到上面所述的需求即可。并且目前也有比较成熟的方案,比较有代表性的产品有Google的Spanner&F1、以及国产数据库SequoiaDB、TiDB等等。关于巨杉数据库,之前写了一篇文章,有兴趣的同学可以看看《【原创首发】兼容MySQL的开源分布式数据库SequoiaDB在去哪儿网的实践》

对比之下,这种分布式数据库对业务无侵入,MySQL数据实现了云存储特征,100%兼容MySQL,扩展性非常好,天然支持分布式事务、数据节点及路由节点延迟非常小,通过一致性算法来保证了数据的强一致性,如此种种,都是立足于一个正确的基点之上,来建立起高楼大厦,势必将基于MyCat的伪分布式数据库解决方案推入无人问津的深渊,直至淘汰与消亡。
欢迎工作一到十年的Java工程师朋友们加入Java架构开发:855355016
群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!

总结

使用MyCat的用户其实还是挺多的,现在在了解业界市场的情况下,我也是比较能理解他们,因为需求有,但真的是没有解决方案,选择使用,实则无奈之举,毕竟他是开源的,骂归骂,也无怨言,因为免费嘛,有的用还有什么可言语的呢?我也推荐大家去试用一下,只有知道痛了,才会感觉现在有新的方案出现的美好。

本文所述的关于MyCat的一系列问题,主要目的是考虑到为了让业内同学不要继续采坑,所以做了一些总结,所述内容限于本人目前对MyCat的理解与认识,如果有纰漏或者不足的地方,欢迎私信指正或者给予补充,感谢。

10-06 22:00