微服务存储实现3—分库分表

分库分表

1 查询分离利用Elasticserach作为查询库,可以解决业务数据没终止状态,不方便进行冷热分离时,数据量的缓存与查询效率低的问题。但是ES存在一定的延时,深度分页不能自由跳页,会有丢失数据的可能性。此外,当主库的数据量非常大时,写操作会变慢。同时由于需要将主库更新后的数据同步到查询库,在采用异步完成数据的同步更新时,存在一定的延时
针对于主库写操作越来越慢,我们这里介绍另外一种方案,分库分表。关于分库分表将从拆分存储时的技术选型、分表分库的实现思路、分表分库存在哪些不足为切入点进行介绍。

拆分存储的技术选型:
拆分存储常用的技术解决方案目前主要分为4种:MySQL的分区技术、NoSQL、NewSQL、基于MySQL的分表分库。

MySQL的分区技术主要体现在文件存储层File System,它可以将一张表中的不同行放到不同的存储文件,但是有以下几个缺陷:
Mysql的实例只有一个,分区技术仅仅分摊了存储,但是无法分摊请求的负载。分区对于用户来说是透明的,用户在实际操作时可能会跨分区,进而导致系统性能受到影响。

NoSQL数据库比较典型的就是MongoDB. MongoDB的分片功能从并发性和数据量可以满足一般大数据量的需求。但是需要注意下面三点:
1 约束考量:MongoDB 不是关系型数据库而是文档型数据库,它的每一行数据记录是一个结构灵活可变的JSON. 对于存储非常重要的字段就不能使用这种关系型数据库,比如要存储的一行记录涉及到金额,那么这行数据缺少了该字段在mongoDB 中也是可以存储的。
当然MongoDB 3.2版之后可以支持schema Validation(模式验证),可以制定一些约束规则。
2 业务功能考量: 涉及到支持事务与并发控制这些不是MongoDb的强项。而这些在MySQL上进行了多年的实践。且大部分的Nosql存在类似复杂功能支持的问题。
3 稳定性考量:MySQl的运维已被人们熟悉,稳定性也没有问题。MangoDB的稳定性无法保证。

NewSQL是一款比较新型的数据库,比如TiDB,但是稳定性和扩展性不如MySQL优秀。

从上面的介绍来看,选则基于MySQL的分库分表比较稳妥。

MYSQL的分库是将一个大的数据库拆分成多个小数据库。分表是将一张大的表拆分成几张表。分库分表对于第三方的依赖较少,逻辑灵活可控。它本身不需要非常复杂的底层处理,也不需要重新做数据库,只是根据不同逻辑使用不同SQL语句和数据源而已。
关于分库分表有三个通用技术需要实现:
1 SQL组合:因为关联的表名是动态的,所以需要根据逻辑组装动态的SQL。比如要根据订单ID获取相关的详细数据,select 语句应该针对From哪一张表。
2 数据库路由:因为数据库名也是动态的,所以需要通过不同的逻辑使用不同的数据库。比如根据订单ID获取数据时,需要直到连接哪个数据库.
3 执行结果合并,有些需求需要通过多个分库执行后再合并数据集。
关于以上问题,可以通过一些中间件进行解决,这些中间件大体上分为了两种模式,Proxy模式,Client模式

Proxy模式是将SQL组合,数据库路由,执行结果合并等功能全部放在了一个代理服务中。将分库分表的逻辑放在了其它服务中,对业务代码来说无侵入。比较常用的中间件有MyCat、KingShard、Atlas、cobar.
Client模式是客户端一边实现分库分表的逻辑,另一边通过引用一个jar, 在jar中处理SQL组合、数据库路由,执行结果合并。zebra、Sharding-JDBC、TSharding.

模式 中间件 厂家 语言 优点 缺点
Proxy MyCat   Java

多语言

资源消耗解耦,不需要消耗客户端的资源

升级方便

多一层服务调用,线上调试困难

增加了运维成本

Proxy KingShard   Go
Proxy Atlas 360 C
Proxy cobar 阿里 JAva
Client zebra 美团 Java

少一层服务调用,代码灵活可控

减少了运维成本

单语言,升级不方便
Client Sharding-JDBC ApacheShardingSphere Java
Client TSharding 蘑菇街 Java

 

分表分库实现思路一般需要考虑如下五点:
使用什么字段分片?
选择分片字段时,需要考虑所选字段的值不会变,让数据尽可能均匀分布在不同的表或者库、跨库查询尽可能少
分片的策略是什么?
目前通用的分片策略有三种:根据范围分片、根据Hash值分片(进行取模值,模一般为2的n次方)、根据Hash值和范围分片。
业务代码如何修改?
针对于微服务的分表分库,其影响面基本只为该表所在的服务,而单体架构涉及很多关联查询,如果需要进行分库分表则修改的代码会非常多。
互联网架构中基本不使用外键(外键用于建立表与表之间的关系,以保证数据的完整性和一致性)
分库分表之后,尽量避免跨库和跨表查询。
历史数据如何迁移?
基本思路:旧架构保持执行,存量数据直接迁移,binlog监听增量数据, 通过canal通知迁移程序迁移数据,等到新的数据库拥有全量数据并且校验通过后切换流量到新架构。
未来的扩容方案?
1)分片策略是否可以让新表数据的迁移源只有一个旧表,而不是多个旧表?这就是前面建议使用2n分表的原因——以后每次扩容都能扩为2倍,都是把原来一张表的数据拆分到两张表中。
2)数据迁移。需要把旧分片的数据迁移到新的分片上。

 

分库分表的缺点:

1 复杂查询慢:很多查询需要跨订单数据库进行,然后再组合结果集,这样的查询比较慢。业界的普遍做法是前面提到的查询分离。

2 短时流量大爆发:分表分库可以解决数据量大的问题,但是如果瞬时流量非常大,数据库可能撑不住。

 

posted @ 2024-02-05 17:08  小兵要进步  阅读(42)  评论(0编辑  收藏  举报