分布式.数据库架构

缘起

讲个创业故事,某一天老总想做一个HR的Saas系统,其中员工信息表,但不同员工信息表有一部分是相同的,也有一部分不同的。我们就把不同的放在一个json字段(Mysql 8.0以后支持)中,Dao用的Mybatis,以及MybatisGenerator生成的基础包访问DB,大家知道这个查询就会查询一条完整的数据,没法查几个字段。刚开始没啥,为了赶进度查询一条就一条吧,不用就行。后来试用开始,量上来就慢了,尤其一些扩展的字段都是在更多详情中展示,但基础信息获取也很慢。原因就是查询用户基础信息也用的是按照行全量查询。

为了解决读的问题,我们做了读写分离,后来干脆多高几个Slave从库进行读,可随着业务发展,尤其有些公司扩展字段很多,读取速度就更慢了。

垂直分离,将基本信息和扩展信息拆分为两个表,ID是一致的。这样,基础信息查询用户基础基础信息表,点击更多的时候查询用户的扩展信息表。

因为是Saas多租户架构,用户表数据量也上来了,于是开始分片。这里的分片不同于数据库的那个分片,也指业务上的分片。一般方案有两个,按照某种业务规则拆分,如三个月内+历史数据(时间维度);另一种是根据ID进行Hash,平均分配到不同DB,缺点是当然你查询自己的订单时候就不得不从两个表查询了。Saas多租户,租户ID自然是比较好的拆分依据,就把不同租户的用户拆分到不同的DB中,关于是分库还是分表,建议是分库,实现简单,且两个租户不争夺IO资源,当然也不绝对,看业务。

分库后,刚开始没有进行读写分离,运维成本的考虑。但对于大公司还是比较慢的,于是就添加了从库,进行读写分离,尤其对于报表生成都迁移从库来完成。

业务发展到现在,对于一个租户来说,主库还是单点。畅想一下,一般情况,业务复杂后,数据量再上来,优先考虑纵向根据业务拆分为不同微服务,这样原来一个DB 100张表,可能就拆分为40+60的两个库,能缓解一段时间。

但如果对于一些业务表,单表都能超过kw级别,分表一定不行了,原因是:能达到kw规模存量数据,增速一定很高,写性能和IO性能是瓶颈,即使分表也会争抢IO资源,所以这里就必须进行分库了,这里的分库指的是:同一个表的分库,类似根据ID去Hash分库一样。以此来解决数据量大,单点扛不住问题。

演化到这里,已经很少有业务能到这个程度,如果到了,也只是系统中少有的几个模块,就需要特殊设计了,也不存在什么通用的方案。

数据库架构分解

说起“数据库架构”,包括:数据库表设计和数据持久层架构。下面主要将持久层架构,但也会涉及数据库表设计。

创业初期:一个服务一个库

读瓶颈:读写分离

   

架构:一主多从,主从同步,读写分离

这么一套就是一组,这个架构也成为:分组架构

技术实现:在Service层使用AOP注解标记;多数据源路由的时候根据标记路由;或者配置规则进行路由。

架构特点:

  1. 主从表结构和数据完全一致
  2. 通过binlog同步数据,会有一定的时差
  3. 解决读多写少的场景,或者读费时的问题

表中冷热数据纵向拆分

如下表单,先展示基本信息,点击“更多”后,展开其他详细信息。

 刚开始数据库表设计:

前面的“基本信息”比“扩展信息”更常用,所以可以拆分为两个表: 

单表总数据库大:分片架构

 

根据租户ID进行拆分,即:一个公司的数据独立的放在一个库里边。 

路由的技术实现:Spring的动态数据源;Mycat中间件

分库还是分表:建议分库,拆分数据是为了解决单表数据量问题,数据量大的两个瓶颈是:数据库单表瓶颈和服务器IO,如果分表意味着IO瓶颈会突出出来。

水平分配规则:

  1. 按照业务key分,如:不同租户的数据;不同地点订单;不同类别等
  2. 根据ID按照Hash算法平均分配,这类只是为了解决数据量大的问题

架构特点:

  1. 每个数据库的Schema一样
  2. 数据每个库数据是不同的,区别于主从复制

解决问题:此架构解决单库成为瓶颈问题,通过拆分为多个库存储数据,一次来降低单库的压力,代价就是统计,查询我的历史等功能,需要通过合并数据才可以。

 分片后读写分离

拆分为不同的库后,也有读多写少的问题,于是再对每台DB进行分组架构,添加从库进行读写分离。

如果业务读写并发量很高,数据量也很大,通常需要实施分组+分片的数据库架构:

1.通过分片来降低单库的数据量,线性提升数据库的写性能

2.通过分组来线性提升数据库的读性能,保证读库的高可用

 主库单点问题扩展

此案例先进行根据租户ID分库,但如果一个租户的数据也过大,就需要对这个租户进行分库存储。图跟上面类似,路由的规则却变为根据ID去hash。这个只是扩展,实际业务需要看具体业务,必须分库会带来其他额外的工作,比如获取全部员工信息,需要从多个数据库查询查询。类似这样的功能需要全部重构。

数据库架构总结

  1. 业务初期用单库
  2. 数据量和并发量增加开始可以选择更好好一点的机器
  3. 读写比例差异,可以进行读写分离
  4. 类似报表等查询和统计类功能,又比较好性能的模块就可以迁移到从库
  5. 单库写量上来后,可以进行分片,将压力拆分到多个库中
  6. 高频的信息查询和低频信息可以拆分为两个表

题外话

其实架构就像是打架,为了解决问题手脚会并用的。

读写比例差异场景除了读写分离外,还可以将热点数据放在缓存如redis或者memcache中,只需要保证缓存数据的一致性即可。

数据如果按照冷热字段拆为两个表后,如果要统计或者查询,一般都会合并出一个中间表,在这个中间表进行操作。

如果数据分散到多个数据库中,并需要查询“简历上干过***类项目的员工”场景是,查询则需要专门的组件或者架构支持,如ES的引入,解决关键字查询为。

数据和业务到了一定量,或者一定并发。提交数据,查询,统计等功能都已经不是简简单单的数据库的事情了,需要专门为此设计解决。

补充:数据库分配优化查询速度

比如Saas多租户架构,将一个租户的数据放在一片或者相邻的片来存储,查询速度会快点。能否解决查询速度的问题?可以。

但,这属于战术层面的方法,就是在不跳转架构的情况下,可以做此优化;从战略架构层面,还是要着眼于解决扩展问题。


END

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>