MySQL:硬盘在24 * 7工作中罢工了,我该怎么办?
收藏

来自:码农翻身(微信号:coderising)

虽然他们不承认, 但我还是这个系统的核心, 因为我保存着这个系统最最重要的东西:数据。 


为了能让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叹了一口气:“唉,你们这些家伙啊, 只会推卸责任! 这我可管不了, 我们看看张大胖主人会怎么办吧!”


对于这种数据复制延迟的问题, 你会怎么办呢? 欢迎留言讨论!  


作者简介:

刘欣,前IBM架构师,近20年从业经验,"码农翻身"公众号作者,畅销书《码农翻身》作者,用故事讲解技术是拿手好戏。 拨开技术迷雾,轻松了解技术本质,从"码农翻身"开始。



●编号587,输入编号直达本文

●输入m获取文章

推荐↓↓↓

Web开发

更多推荐25个技术类公众微信

涵盖:程序人生、算法与数据结构、黑客技术与网络安全、大数据技术、前端开发、Java、Python、Web开发、安卓开发、iOS开发、C/C++、.NET、Linux、数据库、运维等。

    公众号