MySQL:硬盘在24 * 7工作中罢工了,我该怎么办?
作者:互联网
虽然他们不承认, 但我还是这个系统的核心, 因为我保存着这个系统最最重要的东西:数据。
为了能让Tomcat他们访问, 我提供了几十个数据库连接——不能提供更多了,因为每个连接都要耗费我不少资源。
这些天Tomcat他们实在不像话,数据库读写的请求像大海的波涛一样汹涌澎湃,不断向我袭来。
996是别想了, 24*7才是残酷人生。
我没办法, 只好拼命地压榨硬盘,看着他的磁头在光滑的盘片上滑来滑去,寻找磁道,定位扇区,读取数据。这小伙子挺不错的, 任劳任怨,但是就是太慢,居然比内存慢几千倍。
很快,连硬盘也招架不住了,他对我说:“MySQL大哥,再这样下去我就要坏掉了。”
果然,没过几天,硬盘病倒了,系统崩溃了。
读写分离
第二天我一觉醒来,就发现系统重启了,但是有点不对劲,这Tomcat发来的SQL怎么这么少啊!还都是些Insert, Update, Delete !
硬盘对我说:“你还不知道吧,昨天晚上我们的主人张大胖做了个数据库的读写分离!”
“读写分离?”
“是啊, 张大胖统计了一下, 我们读和写的比例大概是20:1, 非常适合读写分离,简单来说,就是建立多个数据库,你是主库,主要负责写,还有两个从库,主要负责读。这样我们就没有多少压力了。”
“我这里存了这么多数据, 怎么复制给另外两个小弟呢?” 我问道。
“这你不用担心,张大胖昨天已经给你做了一个快照,他把快照已经复制到了那两个小弟那里。接下来你只需要把今天早上产生的新的数据发过去就行了。”
基于SQL语句的复制
正在这个时候,那个叫旺财的小弟给我打招呼了: “大哥,你把你那里的执行过的Insert, Update, Delete这样的SQL语句都记录下来,然后发给我和小强,我们俩要这些SQL在我们自己的数据库上'重放'一下!”
我看了一下自己的配置,果然如此,我只需要把SQL语句发过去就OK了。
有了两个小弟的承接读操作,我的工作大大减轻,又可以和硬盘喝茶聊天了。
可是没多久,Tomcat气冲冲地来质问我:“你们怎么搞的,数据出现不一致了,Order表, rand_num那一列!”
这是怎么回事? 我可是把所有的SQL语句都发给旺财和小强执行了啊,怎么会不一致?
我们三个不敢怠慢, 赶紧翻看最近执行的SQL, 尤其是更新Order表, rand_num列相关的。
终于发现了罪魁祸首,就是这个函数: RAND() , 它会返回一个随机数, 经过处理后,更新到rand_num这一列。
在不同的数据库执行,这个函数返回的值也就不同,这就会导致我们的数据不一致了。
我感到非常羞愧,因为数据的一致性是我们数据库家族最引以为豪的特性。 在单机的时候,我们自己就可以通过事务来保证了。 但是一旦有多个数据库,形成了分布式的环境,想让大家都保持一致,怎么会这么麻烦?
我们只好请张大胖手工把数据改成一致的, 然后再想新的办法。
基于行的复制
小强说道:“大哥,我提议一个新方法,以后你别记录SQL了,你只记录SQL的所影响的行和相关的值,然后把这些日志发给我们,例如:
对于Insert, 记录下所有列的新值。
对于Delete,记录下到底是哪一行被删除(用主键来标识)
对于Update,记录下哪一行被更新(用主键来标识),以及被更新的列和新值
有了这些日志,我们就可以清楚地知道你那边到底发生了什么变化,我们把这些日志应用到我们的数据库上就可以了!”
鉴于上一次的教训,这次我们仔细分析各种例外情况,确保没有问题才正式采用。
我,旺财和小强通力合作,新的复制方式工作得很好。直到有一天我们遇到了一个Update语句:
update xxx set flag = 0;
这个语句一下子更新了几十万条数据。 在之前使用基于SQL的复制时,记录下这一条语句就行了。 用现在的方式,得记录几十万条数据,这太要命了!
怎么办? 退回到原来的“基于SQL的复制”,肯定不行!
要不默认用SQL复制? 如果SQL执行结果“不确定”,例如有RAND()函数调用,那我们就使用语句复制。
这是一种混合的模式,虽然麻烦,但也只能如此了。
数据延迟
深更半夜Tomcat又来找我:“有个用户在咱们发了一个帖子,我在你这里做了Insert 操作,然后用户刷新页面的时候,我从旺财那里读取数据,却读不到! 现在人家来投诉我们了!”
我心想,这家伙也太快了吧, 居然比我复制数据的速度还快。
我又检查了一下我和旺财之间的复制通道,由于网络原因,确实是有点延迟。
我对Tomcat说:“这是小事情,复制很快完成,他多刷新几次肯定就可以了。”
Tomcat怒道:“这是严重的用户体验问题,怎么是小事?”
“数据复制延迟多正常啊,反正我们三个能保证最终的一致性!”
Tomcat说:“最终一致性? 在我这里可不行! 我给你们出个主意,我在insert数据的时候,你还没有复制完成,怎么就给我说已经insert成功了? 你必需得等到数据复制完成才能说insert成功!! 你的正确次序应该是这样的。”
旺财一看到这个图,大惊失色:“万万不可, 这样一来就是同步复制了,如果网络比较慢, 第2.1和第2.2步迟迟不能完成, 那我们大哥就没法告诉你插入数据成功, 用户连帖子都发表不了!”
“是啊,这种用户体验会更差!” 小强帮腔。
Tomcat说:“我不管,反正是你们的问题!你们数据库得想办法解决!”
我说:“这个问题啊,本质上是数据延迟导致的,但是在分布式环境下这是不可避免的,我们在数据库层面是解决不了的, 你们在应用层面多想想办法吧。”
“能有什么办法?”
我说: “比如,对于不能容忍延迟的操作,都在我这里(主库)来读写,或者用个什么方法判断主库和从库是不是已经一致了。”
“也可以用个取巧的办法, 让用户发表完帖子后等个几秒钟再来刷新......” 旺财补充。
Tomcat叹了一口气:“唉,你们这些家伙啊, 只会推卸责任! 这我可管不了, 我们看看张大胖主人会怎么办吧!”
标签:24,语句,Tomcat,数据库,MySQL,复制,我该,SQL,数据 来源: https://blog.51cto.com/15050718/2633291