13

Database Partitioning_系统设计笔记10

 4 years ago
source link: http://www.ayqy.net/blog/database-partitioning/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

写在前面

为了提升数据库的处理能力,我们把单库扩展成多库,并通过更新同步机制(即Replication)来保证多份数据的一致性。如此这般,数据库的扩展难题似乎已经顺利解决了

然而,在 Replication 方案下,每个数据库都持有一份完整数据,基于全量数据提供增删改查服务, 单库的性能瓶颈仍然存在 ,并将成为限制系统扩展性的关键因素

一.单库的性能瓶颈

单机的硬件资源是有限的,因此单库的处理能力也是有限的:

  • 容量有限:数据量可能大到单库无法容纳

  • 性能有限:单库的读写性能同样受数据量影响,查询/更新越来越慢

单靠加机器/加库显然无法直接解决单机/单库的性能问题, 除非进一步打破库的边界,把单库拆分成多库 (而不只是复制多份)

P.S.理论上,Web 应用层也面临同样的问题,却不曾听说过一个 Web 服务庞大到单机无法部署,这是因为 Web 服务在设计之初就会考虑职责划分与解耦 ,以便各部分能够独立部署、独立扩展,从 20 年前的 SOA(即面向服务架构,包括 微服务架构(Microservices) 等变体)起便是如此

二.分区(Partitioning)

为了避免单库性能成为系统可扩展性的瓶颈,通常把逻辑数据库(或其组成元素,例如数据表)拆分成各个独立部分,这种做法称为 分区(Partitioning)

A partition is a division of a logical database or its constituent elements into distinct independent parts.

(摘自 Partition (database)

就像微服务架构中把单体应用(Monolithic application)拆分成一组小型服务一样,我们通过分区把单库拆分成一组(数据规模)更小的库,各自处理一部分数据,共同分担流量,主要优势体现在:

  • 可扩展性:把单库数据拆分到多库后,系统的可扩展性不再受限于单库性能,数据库层“无限”扩展成为了可能

  • 性能:单库数据量减少,数据操作更快,甚至允许多库并行操作

  • 安全性:可以针对(拆出去的)敏感数据,采取更强的安全控制

  • 灵活性:可以对不同的库(比如按数据重要性)采用不同的监控、备份策略,以缩减成本,提升管理效率。或者对不同类型的数据选用不同的存储服务,比如大型二进制内容放到 blob 存储中,更复杂的数据可以存放在文档数据库中

  • 可用性:把数据分散放到多个篮子里,能够避免单点故障,并且单库故障仅影响一部分数据

具体的,有 3 种拆分策略:

  • 水平分区(Horizontal partitioning,也叫 Sharding):按行拆分,把不同的行放入不同的表中

  • 垂直分区(Vertical partitioning):按列拆分,把一些列放到其它表中

  • 按功能分区(Functional partitioning,有时也叫 Federation):按业务功能拆分,把业务领域中属于相同界限上下文(Bounded Context)的数据放在一起

当然,这 3 种策略并不冲突,可以结合使用

P.S.关于领域驱动设计(Domain-Driven Design),以及界限上下文的更多信息,见 去中心化数据管理(Decentralized Data Management)

三.水平分区

ZFvMruY.png!web

水平分区,即 分片(Sharding) 。每片(shard)都是原数据的一个子集,共同构成完整的数据集:

A database shard is a horizontal partition of data in a database or search engine. Each individual partition (or server) acts as the single source for this subset of data.

(摘自 Shard (database architecture)

与垂直分区相比,水平分区最大的特点是 schema 保持不变

Each partition is a separate data store, but all partitions have the same schema.

就像把一张表横向切几刀,分成几段小表,它们的表结构(字段等)完全一致

这种横向切分减少了单库所需存储的数据量,以及所需承载的流量/操作,另一方面,还减少了资源争用(contention),有助于提升性能

shard key 的选取

具体操作上, 关键在于如何选取 shard key (按哪个字段的什么特征来分片),尽可能保证负载被均匀地分散到每一片上

注意,均匀并不意味着要求每一片的数据量均等,重点是均分流量(有些片可能数据量很大,但访问量却很低)

同时还要避免产生“热点”,比如按姓氏首字母对用户信息进行分片实际上是不均匀的,因为有些字母更常见,此时按用户 ID 哈希值来分片可能更均匀些

四.垂直分区

另一种拆分方式是垂直分区,将一些列(字段)拆分到其它表中:

nyEFziv.png!web

多用于减少 I/O、降低性能成本,比如,按使用频率把常用字段和不常用的字段分开

比起水平分区,垂直分区的关键优势在于 把信息拆的更细,进而允许一些针对性的优化 ,比如把不经常变化的数据拆分出来,丢到缓存中,把照片等大型二进制内容拆出去单独存放,或者对部分敏感数据进行针对性的安全控制,另一方面,细粒度的数据划分也能够消除一些并发访问,降低并发访问量

五.按功能分区

此外,还可以结合具体应用场景,按业务功能拆分:

ABRJzur.png!web

把不相干的数据剔除出去(把紧密相关的数据放到一起),有助于加强数据隔离,提升数据访问性能,比如把客户信息和商品库存信息分开

六.分区的代价

把单库拆成多库,虽然能够解决数据库的扩展性难题,但也引发了一些新问题:

  • 连表查询慢:尽量避免跨分区 join、或者考虑并行查询

  • 全表查询慢:对于需要扫描全量数据的查询操作,即便有并行优化也慢,可以通过垂直分区、按功能分区来定位目标分区,避免全表查询,至于水平分区,可以在应用层维护一张映射表,加快分区定位

  • 不支持事务操作:将事务操作交由应用层来处理

  • 负载不匀导致分区效果大打折扣:考虑增加监控,并根据分析预测定期调整

诚然,其中有些问题没有非常漂亮的解决方案,实际应用中更多的是面向特定场景的权衡取舍

参考资料


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK