云计算·大数据 频道

这7个问题难以解决!分库分表也没吹的那么神……

  为什么需要分库分表?是因为MySQL等数据库单库单表能支撑的系统并发量和数据存储量存在瓶颈。

  中国有超过 10 亿的网民,单日交易量超过百万、千万单的交易场景越来越多。按照一行数据 1K ,每日订单量 500 万计算,一年需要的数据存储为 1700G,行数1.7亿。

  显然此种情况MySQL 单库单表难以保证查询写入性能。一张表一年的数据量恐怖如斯,交易场景成百上千张表,年复一年,所带来的存储和并发量压力何其巨大呢?业务牵引技术的发展,分库分表技术应运而生。

  目前分库分表技术似乎成为行业标准,站在鄙视链上游。不分库分表的系统似乎都是毫无亮点的垃圾系统,然而真的如此吗?

  分库分表技术是完美的解决方案吗?它有哪些不足之处?

  为什么单库单表存在系统瓶颈,就选择分库分表呢?有其他更好的方案吗?

  接下来我将分享自己在电商交易场景实际遇到的痛点:

  一、分库分表难以解决分布式事务问题

  一般情况下通过选择合适的分片属性,可以保证业务在一个数据库内完成事务操作。

  如用户领券场景,用户一次领取 3 张优惠券,系统写入 3 条优惠券记录和一条领券流水,使用 UserId 进行分库分表,可以保证同一个用户的 4 条记录路由到同一数据库,可使用 MySQL 本地事务即可保证数据一致性。

  然而**当同一个事务中多张表的分片属性不同时,难以保证这些表在同一个数据库内完成事务操作,势必会出现难以解决的分布式事务难题**。

  如优惠券存在库存,在发券时需同时扣减券库存,库存粒度为券模版ID,用户可同时领取多个券模版的券。如何保证库存扣减、用户发券、领取流水等在同一个数据库内完成呢?难以实现

  优惠券和领券流水,基于 UserId 拆分数据库,但库存表无用户属性,只能使用券模版 ID分库。然而不同的分片属性,无法保证在同一个数据库完成事务操作,难以保证数据强一致性。

  因此 当同一个事务中多张表的分片属性不同时,难以保证这些表在同一个数据库内完成事务操作,势必会出现难以解决的分布式事务难题。即便业务侧使用复杂的业务架构也难以实现强一致性,作出妥协后,可实现最终一致性。

  分库分表技术把数据库解决不了的问题推到业务侧,“胁迫” 业务侧使用复杂方案参与解决,要求业务侧在数据一致性上作出妥协

  二、分库分表难以实现非分片属性的索引查询能力

  电商交易场景一般使用 UserId 作为分片属性,联合索引的前缀都是UserId,但这并不绝对,交易场景中存在品牌、门店、司机、配送等其他维度。

  如订单表使用UserId 作为分片属性进行分库分表,查询商家在最近 1 小时的订单如何实现呢?由于使用 UserId 分库分表,当使用商家 ID 查询时,需要查询所有的分库分表,这显然不现实。

  业务侧有几种实现方案,1)使用商家 ID分库分表,异构另一份 MySQL存储 2)基于 ElasticSearch,异构另一种存储支撑其他维度的检索场景。

  无论哪一种方案都会导致,数据一致性降低,但系统复杂度增加。

  查询商家最近1 小时的订单,业务上如此简单清晰的需求,在分库分表后,实现方案竟如此复杂。此外还要求业务在数据准确性上作出妥协。

  正是因为分库分表技术的先天不足,所以极大地增加了业务系统架构的复杂性。(甚至很多人以架构复杂为荣,错误的认为系统越复杂越能体现架构能力)

  此外还有其他更加 tricky的方案,如为了实现订单 Id 查询,在生成的订单Id中存放UserId后四位(大概意思),用于定位订单在哪个分片。

  三、分库分表导致的全局主键问题

  MySQL 主键支持自增 ID,但是这一特性在分库分表后沦为鸡肋功能,系统需要分布式方式的 ID 生成器。

  如优惠券系统在分库分表后,优惠券 ID 需要借助分布式ID生成器生成全局唯一 ID。常见的实现方式包括 UUID、雪花算法、美团 Leaf、百度 UidGenerator等。除维护业务系统外,还需要维护其他纯技术类系统。

  毫无疑问,这再次增加架构的复杂性。

  四、分库分表难以建立全局唯一键约束

  除全局主键问题,全局唯一键也难以实现。当全局唯一键的前缀是非分片属性时,难以实现全局唯一键。

  例如订单在履约完成后,会生成一笔履约单。系统明确一笔订单只能有一笔履约单,因此履约单上的订单 ID 字段应该增加唯一键约束。然而履约单在基于 UserID 分库分表后,OrderId建立的唯一键约束只在本表内唯一,不能保证在所有的分片内实现全局唯一。

  因此 分库分表后,数据库无法对 OrderId等非分片属性建立全局的唯一性约束。

  除以上具体场景外,分库分表面临的难题依然有很多,如扩容难问题、存储成本高、运维成本高、高可用难等等问题。

  五、分库分表需要持续造轮子

  选择分库分表后,需要业务系统开发和接入很多轮子,包括

  ShardingSphere、mycat等方便客户端接入分库分表。如果使用 ShardingSphere需考虑多种语言多套轮子,使用 Mycat代理层方案又会面临性能风险。

  分布式 ID 生成器生成全局 ID

  为了支持非分片查询,需要 DTS 消费binlog,异构存储For 查询。

  使用 ElasticSearch用于其他维度检索。

  分库分表管理后台支持查询数据、修改数据

  分库分表管理工具支持高效建表、修改表、加索引等 DDL 操作。(1000 张表后,手动建表不现实)

  ……

  层出不穷的问题,需要层出不穷的轮子,有些轮子需要自己造,如分库分表管理工具等。

  不禁要问,互联网大厂能承受如此复杂架构方案,所有的公司都能承受吗?导致架构如此复杂的根源是什么呢?分库分表方案上的先天不足

  六、分库分表后面临老大难的扩容问题

  在系统建设之初,一个合格的架构师必须考虑到:未来数据量庞大后的存储扩容问题。这往往让人很难抉择,因为要权衡当下的硬件成本和未来扩容成本。

  使用分库分表后,扩容非常困难。如8 个数据库,想继续拆分为 16 个数据库,一定会对业务造成影响,停机迁移是难以避免的问题,需要极多的运维工具保障扩容过程的安全性和快速性,做到对业务影响程度最低。因此扩容成本和风险都极高。

  如果在系统建设初期就拆分为 16 个库,又会面临硬件和运维成本过高的问题。如果每一个业务在系统建设初期都如此铺张浪费,那么公司的硬件成本将极高。

  七、大量分库分表导致运维成本激增

  仅一个业务团队就16 个数据库,公司那么多业务将会有多么庞大规模的数据库实例。有 DBA 曾分享经历,他一天新部署了120 套 mysql实例,可想而知,DBA 们面临了多么庞大的运维压力。

  研发视角和 DBA视角不同,结论不同。业务研发更多考虑容量不足和并发度不足风险,会倾向于设置较大的分库分表规模,而 DBA 会考虑运维成本、硬件成本,希望数据库规模在可控范围内。两者站在不同的视角,各有理由,这是一个矛盾。

  我相信大多数业务研发不清楚,自家公司MySQL单库单实例的最高并发度,最高容量,在设置分片规模时往往是拍脑袋决定。只要研发定的分片方案不离谱,往往 DBA也就接受了。

  这些决策中,往往还掺杂历史问题。如团队已经有了 10 个库,无论业务规模如何,新表默认拆分10 个库,而不会考虑是否真的需要 10 个库。

  八、为什么业务系统要替数据库负重前行?

  分库分表技术把数据库解决不了的问题推到业务侧,“胁迫” 业务侧使用复杂方案参与解决,要求业务侧在数据一致性上作出妥协。

  为什么单库单表存在系统瓶颈,就选择分库分表呢?有其他更好的方案吗?分布式数据库。

  分布式数据库继承了传统单机数据库的核心特性,同时还拥有分布式系统的处理能力。虽然起步较晚,可以预见的是它将是数据库下一个发展方向。

0
相关文章