在MySQL界,一个存在很久的话题,就是:哪个中间件实现的分库分表方案比较好啊?当然对于同一个问题,不同人有不同的理解,也都具有两面性的特征,有人说好,也有人说不好,我们首先看一下这种方案是如何实现的。
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的配置复杂吗?上手容易么?
我们只需要看一个图片就行了。你能想象这是它的配置文件么?看了之后我估计你也没有任何使用它的欲望了,很多人在使用之后,是这样评价的:
,配置文件如下:
竟然是一个XML文件,这个产品经理当时是如何想的?后面也没有想着做个优化?
最后一个问题,现在做分库分表做得好的有哪些?
还有哪些?一个都没有,这是一条不归路啊。因为说白了,他是一种伪分布式方案,基础是不好的,上层就做不好,所以永远是在补各种坑,走得很累,累人累己。现在可以回过头来想一想,为什么一些很强大知名的公司做的中间件产品,并没有做这些事情,比如ProxySQL、Maxscale、MySQL Router等,为什么呢?难道他们的技术不好?或者是没有这样的需求?我还是觉得,需求是有的,人与人、业务与业务的需求,是一样的,但解决方法可能就不一样了,他们可能早就认为,这是一条错误的道路,所以就不会去选择走,而MyCat这种方案,可能就要回过头来想想未来的路了。