Shopee的分布式数据库选型思路漫谈

作者:刘春辉,ShopeeDBAManager,TUGManagementCommittee成员。

Shopee于年底上线,是东南亚地区领先的电子商务平台,覆盖东南亚和台湾等多个市场,在深圳和新加坡分别设有研发中心。

本文系Shopee的分布式数据库选型思路漫谈。因为是『漫谈』,可能不成体系;会着重介绍一些经验以及踩过的坑,提供给大家参考。

Shopee的数据库使用情况

Shopee在用哪些数据库?

先说一下当前Shopee线上在用的几种数据库:

在Shopee,我们只有两种关系数据库:MySQL和TiDB。目前大部分业务数据运行在MySQL上,TiDB集群的比重过去一年来快速增长中。

Redis在Shopee各个产品线使用广泛。从DBA的角度看,Redis是关系数据库的一种重要补充。

内部也在使用诸如HBase和Pika等多种NoSQL数据库,使用范围多限于特定业务和团队。不在本次讨论范围内。

数据库选型策略

过去的一年里,我们明显感觉到数据库选型在DBA日常工作中的占比越来越重了。随着业务快速成长,DBA每周需要创建的新数据库较之一两年前可能增加了十倍不止。我们每年都会统计几次线上逻辑数据库个数。上图展示了过去几年间这个数字的增长趋势(纵轴表示逻辑数据库个数,我们把具体数字隐去了)。历史数据显示,逻辑数据库个数每年都有三到五倍的增长,过去的年增长倍数甚至更高。每个新数据库上线前,DBA和开发团队都需要做一些评估以快速决定物理设计和逻辑设计。经验表明,一旦在设计阶段做出了不当决定,后期需要付出较多时间和人力成本来补救。因此,我们需要制定一些简洁高效的数据库选型策略,确保我们大多数时候都能做出正确选择。我们的数据库选型策略可以概括为三点:默认使用MySQL。积极尝试TiDB。在必要的时候引入Redis用于消解部分关系数据库高并发读写流量。在使用MySQL的过程中我们发现,当单数据库体量达到TB级别,开发和运维的复杂度会被指数级推高。DBA日常工作会把消除TB级MySQL数据库实例排在高优先级。“积极尝试TiDB”不是一句空话。年初开始,我们把TiDB引入了到Shopee。过去两年间TiDB在Shopee从无到有,集群节点数和数据体积已经达到了可观的规模。对于一些经过了验证的业务场景,DBA会积极推动业务团队采用TiDB,让开发团队有机会获得第一手经验;目前,内部多数业务开发团队都在线上实际使用过一次或者多次TiDB。关于借助Redis消解关系数据库高并发读写流量,后面会展开讲一下我们的做法。

分布式数据库选型参考指标

在制定了数据库选型策略之后,我们在选型中还有几个常用的参考指标:

1TB:对于一个新数据库,我们会问:在未来一年到一年半时间里,数据库的体积会不会涨到1TB?如果开发团队很确信新数据库一定会膨胀到TB级别,应该立即考虑MySQL分库分表方案或TiDB方案。

万行或10GB:单一MySQL表的记录条数不要超过万行,或单表磁盘空间占用不要超过10GB。我们发现,超过这个阈值后,数据库性能和可维护性上往往也容易出问题(部分SQL难以优化,不易做表结构调整等)。如果确信单表体积会超越该上限,则应考虑MySQL分表方案;也可以采用TiDB,TiDB可实现水平弹性扩展,多数场景下可免去分表的烦恼。

每秒次写入:单个MySQL节点上的写入速率不要超过每秒次。大家可能觉得这个值太低了;许多开发同学也常举例反驳说,线上MySQL每秒写入几千几万次的实际案例比比皆是。我们为什么把指标定得如此之低呢?首先,上线前做估算往往有较大不确定性,正常状况下每秒写入次,大促等特殊场景下可能会陡然飙升到每秒0次,作为设计指标保守一点比较安全。其次,我们允许开发团队在数据库中使用Text等大字段类型,当单行记录长度增大到一定程度后主库写入和从库复制性能都可能明显劣化,这种状况下对单节点写入速率不宜有太高期待。因此,如果一个项目上线前就预计到每秒写入速率会达到上万次甚至更高,则应该考虑MySQL分库分表方案或TiDB方案;同时,不妨根据具体业务场景看一下能否引入Redis或消息队列作为写缓冲,实现数据库写操作异步化。

P99响应时间要求是1毫秒,10毫秒还是毫秒?应用程序要求99%的数据库查询都要在1毫秒内返回吗?如果是,则不建议直接读写数据库。可以考虑引入Redis等内存缓冲方案,前端直接面向Redis确保高速读写,后端异步写入数据库实现数据持久化。我们的经验是,多数场景下,MySQL服务器、表结构设计、SQL和程序代码等方面做过细致优化后,MySQL有望做到99%以上查询都在10毫秒内返回。对于TiDB,考虑到其存储计算分离和多组件协作实现SQL执行过程的特点,我们通常把预期值调高一个数量级到毫秒级别。以线上某TiDB2.x集群为例,上线半年以来多数时候P99都维持在20毫秒以内,偶尔会飙升到毫秒,大促时抖动则更频繁一些。TiDB执行SQL查询过程中,不同组件、不同节点之间的交互会多一些,自然要多花一点时间。

要不要分库分表?

内部的数据库设计评估清单里包含十几个项目,其中“要不要分库分表”是一个重要议题。在相当长时间里,MySQL分库分表方案是我们实现数据库横向扩展的唯一选项;把TiDB引入Shopee后,我们多了一个“不分库分表”的选项。

从我们的经验来看,有几种场景下采用MySQL分库分表方案的副作用比较大,日常开发和运维都要付出额外的代价和成本。DBA和开发团队需要在数据库选型阶段甄别出这些场景并对症下药。

难以准确预估容量的数据库。举例来讲,线上某日志数据库过去三个月的增量数据超过了之前三年多的存量体积。对于这类数据库,采用分库分表方案需要一次又一次做Re-sharding,每一次都步骤繁琐,工程浩大。Shopee的实践证明,TiDB是较为理想的日志存储方案;当前,把日志类数据存入TiDB已经是内部较为普遍的做法了。

需要做多维度复杂查询的数据库。以订单数据库为例,各子系统都需要按照买家、卖家、订单状态、支付方式等诸多维度筛选数据。若以买家维度分库分表,则卖家维度的查询会变得困难;反之亦然。一方面,我们为最重要的查询维度分别建立了异构索引数据库;另一方面,我们也在TiDB上实现了订单汇总表,把散落于各个分片的订单数据汇入一张TiDB表,让一些需要扫描全量数据的复杂查询直接运行在TiDB汇总表上。

数据倾斜严重的数据库。诸如点赞和


转载请注明:http://www.xcqg58.com/lsqy/lsqy/26842017.html

  • 上一篇文章:
  •   
  • 下一篇文章: 没有了