高并发系统设计七-写入数据量增加时,如何实现分库分表

1、写入数据量增加时,如何实现分库分表?

数据使用单表存储,但是随着数据的增大,造成数据库查询、写入性能下降,数据库磁盘空间也发生报警,所以要解决这个问题,使得系统可以正常运转下去。

1.1、需要考虑的问题

  • 系统正在持续不断的发展,数据库中存储的数据也越来越多,单个表的数据量超过了千万甚至亿级别。这时即使使用了索引,索引占用的空间也随着数据量的增长而增大,数据库就无法缓存全量的索引信息,那么就需要从磁盘上读取索引数据,就会影响查询性能了,需要提升查询性能
  • 数据量的增加也占据了磁盘空间,数据库在备份和恢复的时间变长,如何让数据库系统支持如此大的数据量
  • 不同模块的数据(比如用户数据和用户关系数据)全部存储在一个主库中,如果主库发生故障,所有的模块都会受到影响,如何做到不同模块的故障隔离
  • 4 核 8G 的云服务器上的MySQL 5.7 大概可以支撑 500 TPS 和 10000QPS,锁着系统下入请求量的增长,系统如何处理更高的并发写入请求

数据库的写入请求量大造成的性能和可用性方面的问题,要解决这些问题,你所采取的措施就是对数据进行分片。这样可以很好地分摊数据库的读写压力,也可以突破单机的存储瓶颈,而常见的一种方式是对数据库做“分库分表”

2、分库分表

将数据进行分片,基本思想是依照某一种策略将数据尽量平均分配到多个数据库节点或者多个表中。

  • 垂直拆分
  • 水平拆分

2.1、如何对数据库做垂直拆分

垂直拆分,对数据库竖着拆分,也就是将数据的表拆分到多个不同的数据库中。

垂直拆分的原则一般是按照业务类型来拆分,核心思想是专库专用,将业务耦合度比较高的表拆分到单独的库中。

2.2、如何对数据库做水平拆分

水平拆分指的是将单一数据表按照某一个规则拆分到多个数据库或者多个数据表中。

拆分的规则

1、按照某一个字段的哈希值做拆分,这种拆分规则比较适合用于实体表,比如用户表中,我们根据 ID 字段进行拆分。比如将用户表拆分成3个表,先对用户 ID 做哈希,哈希的目的地将 ID 尽量打散,然后再对 3 取余,这用就得到了分表后的索引值。

2、按照某一个字段的区间来进行拆分,比较常用的是时间字段,比如可以把一个月的数据放入到一张表中,这样在查询时就可以根据创建时间先来定位数据存储在哪个表中,再按照条件来进行查询。

2.3、分库分表引入了一些问题

问题一:查询时每次都要带分区键

问题描述:

引入分库分表键,也叫做分区键。也就是我们对数据库做分库分表所依赖的字段。这样也就是说,所有的查询都需要带上这个字段,才能找到数据所在的库和表,否则就只能向所有的数据库和数据表发送查询命令。

问题解决:

比如,在用户库中我们使用 ID 作为分区键,这时如果需要按照昵称来查询用户时,你可以按照昵称作为分区键再做一次拆分,但是这样会极大地增加存储成本,如果以后我们还需要按照注册时间来查询时要怎么办呢,再做一次拆分吗?


所以最合适的思路是你要建立一个昵称和 ID 的映射表,在查询的时候要先通过昵称查询到 ID,再通过 ID 查询完整的数据,这个表也可以是分库分表的,也需要占用一定的存储空间,但是因为表中只有两个字段,所以相比重新做一次拆分还是会节省不少的空间的。

问题二:一些数据库的特性在实现是时可能变得困难。

问题描述:

多表的 JOIN 在单库时是可以通过一个 SQL 语句完成的,但是拆分到多个数据库之后就无法跨库执行 SQL 了。未分库分表之前查询数据总数时只需要在 SQL 中执行 count() 即可,现在数据被分散到多个库表中如何解决。

问题解决:

好在我们对于 JOIN 的需求不高,即使有也一般是把两个表的数据取出后在业务代码里面做筛选,复杂是有一些,不过是可以实现的。现在数据被分散到多个库表中,我们可能要考虑其他的方案,比方说将计数的数据单独存储在一张表中或者记录在 Redis 里。

发布了57 篇原创文章 · 获赞 3 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/wmdkanh/article/details/105478018