架构师眼中的CRUD:分库分表与数据查询那些事(中)

声明

下面的故事,记录的技术要点,是真实发生在我身上的。为了记录下这些知识点,同时让大家以一个放松的心态去进行阅读,将其改编成诙谐幽默的小故事。

故事人物介绍:
S君:我们的产品爸爸,提的需求一般没有商量的余地~
H兄:我们的项目总监、技术负责人,老大哥的形象,一般也是问题的最后裁判员
C大:我们的架构师,技术涉猎面广,考虑问题全面
小L:刚入职公司的应届毕业生开发,对技术有着无比的热情~
KK:喜欢独自研究冷门技术的开发,不太喜欢凑热闹,2年java开发经验~
Q姐:别看是女生,技术上可是独当一面,能独立带项目,5年java开发经验~

如有雷同,纯属巧合。

前情提要

上回飞机

我们说到小L面对一个简单的查询需求,一路做了很多改进:从分表,到分表策略,再到分表键改进,一路迭代了3个版本。
可以说,小L给出的第三版设计,基本上是一般分布式系统数据库的分表方案了。

哪里还有问题

上回的最后,提到了下面这样的设计方案,还存在问题,那么问题在哪里?
第三版
小L有点懵了,这个设计应该算是完美解决了数据不均匀以及app客户端用户数据展示的问题啊,还能有什么问题啊。

C大给了小L一点提示:“回归需求的本质,看看我们的产品经理想要的是什么?”
产品原型
小L突然发现了什么,一拍脑袋!“哎呀,我们使用了基于用户分表的策略以后,后台在统计这些信息的时候,用户id就成了必须输入的选项嘛!

这就是问题所在,分库分表是一把双刃剑,在设计分布式系统时,尤其是有大量用户,大量数据的分布式系统数据库时,对于一些数据总量可能上千万的表,必须要做分表处理
分表以后,我们在查询的时候就要求查询时,必须带上分表键或者能够计算出分表键的字段。试想一下,如果我们不带上分表字段。那么唯一能检索出数据的方法,就是遍历所有表!那几乎在大型系统上是一个灾难。

拓展:关于单表容量

☆ 一般来说开源版的mysql,单表不宜超过500万数据,而在对云数据库进行测试后发现,其承载能力可以达到开源版本的数倍
☆ 但我仍然推荐大家,单表数量预估超过百万级别时,就有必要进行分表
☆ 数据量如何评估,这里不打算展开,如果有感兴趣的,后面我可以写一个专题文章来讲数据量预估的课题

小L想了很久,还是没什么太好的办法,就提出来,那看来只好让产品改一下原型了,让用户id成为必填项了。
话音刚落,突然感觉背后一凉~~产品爸爸正往这边看。
在这里插入图片描述
C大也有点可怜我们的小L同学了,又给了进一步的提示:“转化下思路,数据库索引设计的思想是什么?虽然增加了存储,我们得到了什么呢?”

没错,这里我们需要用空间换取时间的思想,可以通过索引表或者数据双写来解决上面的这个问题

第四个版本

小L带着这个提示,设计出了第四个版本
在这里插入图片描述
“嗯,这个版本,可以说解决了后台查询以及app客户端查询的问题。但是,这样一个数据插入,操作多个数据库记录,是不是存在问题呢?” C大说道。

“确实,如果其中一个操作失败,会影响到其他操作。这个好办,我们异步写入就可以了。”

“不光是这个问题哦,我们做的是app上的一个功能,如果这个时候因为你多个插入导致了主库性能瓶颈,或者后台慢查询导致主库性能问题,该怎么办呢?”

“好吧,我知道该怎么做了。” 小L还是有灵性的,一点就通。

这里,我有必要特别说明一下。因为后台查询,或者跑批,把数据库CPU或者磁盘IO打满,在以前我从事传统行业,很多供应商的系统都存在。他们在数据库中,搞了一堆触发器,存储过程,去做跑批任务。
有一次,我在一次拜访客户时,跟我抱怨说,系统总是在早上7点特别卡,感觉都不能用,然后过一会又好了。在得到客户授权后,在数据库(那个时候基本上都是Oracle数据库)做了个AWR报告,马上找到一条SQL执行耗时接近20分钟,执行中,CPU基本上都是在IO等待,说明磁盘已被打满。后来发现是一个定时触发器跑的SQL批处理,有一个上千万数据的表,没有做分区,也没有做索引,直接查询,而这个SQL正式在7点定时开始。。

第五个版本

第五个设计版本在下班前一刻,终于完成!
在这里插入图片描述
“这个版本,应该是没问题了!我们把数据查询和数据写入的问题都搞定了。而且,其他维度的数据写入是异步写入,不会影响核心业务。即使消息丢了,也只会影响到后台查询的数据。这些我们可以在日终处理统一核对补充,问题不大!” 小L坚定地说。

“嗯,看着已经不错了。但是,有些问题,你不能光以后端的视角去看。对于这次产品的原型,有一块,你得从前端同学的视角去观察。” C大说, “不过呢,你可以先按照这个去搞,等明天你跟前端联调的时候,你就知道问题在哪里了。”

一旁的KK往这边瞄了一眼,然后说了一句:“明天看你跟前端撕逼,哈哈。”

本篇总结

这里,把我们数据库双写解决了,实现的分表后其他维度查询无法实现的问题。但同时带来了业务流程插入过多导致的流程过长以及数据库性能问题。

但后来,通过消息队列异步写入以及拆分数据库实例给解决了。这体现了我们使用空间换时间的思路。一份数据存储多个副本,以不同的维度来实现各个维度查询的要求。

当然,这个方案不是当下分布式系统的唯一(以及最优)解决思路。因为这里我们有一个限制,就是对于数据存储,只能使用关系型数据库mysql。在这个限制下,双写是一个比较常规的解决方案了。

后续

大家一定想要知道,我们业务上云的系统,或者说是可以用一些其他先进技术组件的情况下,面对这种问题,要怎么办。这个课题,我们留到下集再讲了。

发布了4 篇原创文章 · 获赞 1 · 访问量 159

猜你喜欢

转载自blog.csdn.net/m0_37911064/article/details/104867188
今日推荐