选择适合您应用的数据库

2020-03-11 Shopee 互联网

行业:电子商务

作者:刘春辉,洪超(商派数据库管理员)

杂种:Caitin陈编辑:汤姆德湾

为应用程序选择正确的数据库

Shopee在东南亚和台湾地区领先的电子商务平台。这是该地区量身定制的平台,为客户提供通过强大的支付和后勤支持一种简单,安全,快速的网上购物体验。

随着我们的业务蓬勃发展,我们的团队面临着缩放后端系统以满足需求的严峻挑战。我们的前面的文章介绍我们的使用方式TiDB,开源,MySQL兼容,混合事务和分析处理(HTAP)数据库,来扩展我们的系统,这样我们就可以不用担心数据库容量提供为我们的用户提供更好的服务。

市场上有很多数据库。你如何选择正确的?在这篇文章中,我会与你分享我们的想法。我希望这篇文章可以帮助您在您比较多个数据库并寻找适合您的应用程序的适用权时帮助您。

在本文中,我将讨论:

我们在商店使用哪些数据库?

在Shopee,我们使用以下数据库:

  • MySQL和TiDB是我们的关系数据库。MySQL存储了我们的大部分数据,我们正在部署越来越多的TiDB集群。
  • 复述,广泛应用于各种Shopee应用。
  • 一些应用程序和团队还使用其他数据库,如HBase的和鼠兔.但我们不会在本文中讨论这些数据库。

数据库选择的重要性

我们的业务正在快速增长。今年,我们每周创造10倍的数据库,而不是我们一两年前的数据库。每年,生产环境中的逻辑数据库的数量大约需要三到五次。2019年,这个数字增加了五次以上。

在数据库进入生产环境之前,数据库管理员(dba)和研发团队会对其物理和逻辑设计进行粗略评估。

根据我们的经验,如果我们在设计阶段做了一个错误的决定,我们会在以后花费大量的时间和精力去纠正它。因此,我们必须制定一个简洁高效的数据库选择策略,以确保在大多数情况下能够做出正确的决策。

我们的数据库选择策略

在Shopee,我们使用此常规数据库选择策略:

  • 我们使用了MySQL默认,但我们尽量减少TB级规模的MySQL实例。
  • 如果可能的话,我们试图用TiDB。我们使用TiDB自2018年,我们尤其是大量的数据是不适合分片推荐它的场景。
  • 必要时,我们引入Redis来平滑一些关系数据库的峰值流量。稍后我会详细解释。

选择数据库时要考虑的因素

当我们从各种产品中选择数据库时,我们会问自己:

  • 我们新数据库的数据大小将在未来12-18个月内超过1结核吗?

    如果是,我们应该考虑MySQL分片或TiDB。

  • 单个MySQL表是否有超过1000万行或10 GB的数据?

    如果是,我们可以使用MySQL分片或采用TIDB实现水平可伸缩性并避免慢慢分配。这是因为我们发现,当单个MySQL表包含超过1000万行数据时,或单个表占用超过10 GB的磁盘空间时,数据库可能会慢且难以维护。例如,一些SQL查询难以优化,并且在线数据定义语言(DDL)成为一个大挑战。

  • 单个MySQL节点的每秒写查询(QPS)是否超过每秒1,000写入?

    如果是,我们可以尝试以下方法:

    • 应用MySQL分片将写流量分配给多个MySQL主服务器。

    • 使用TiDB将写分散到更多节点。

    • 考虑将Redis或Message队列引入写入缓存以实现异步写入。

      您可能认为每秒1,000次写入太低了阈值。我们将其设置为1,000,因为:

    • 在我们把一个应用程序投入生产,我们估计可能是不准确的。在正常情况下,我们有每秒1000个写入。但是,当我们正在运行一个大的促销活动,写QPS可以跳转到每10,000个写入。最好是设置一个保守的参考价值。

    • 我们允许研发团队使用较大的文本字段。当单个行长度增加到某一点时,主数据库的写性能和辅助数据库的复制性能可能会大大降低。因此,我们不能期望单个节点有很高的写速率。

  • 该应用程序是否要求第99百分位数响应时间在一个毫秒(MS)内?

    如果是的话,我们最好不要直接读取或写入到数据库。我们可以使用Redis的缓冲层。前端直接读取和写入到Redis的,以确保高速的I / O。

    根据我们与MySQL的经验,在大多数情况下,经过我们优化的MySQL服务器选项,表架构设计,SQL语句和应用程序代码,第99百分位数响应时间可以在10毫秒。

    TIDB的计算和存储层是分开的,多个组件一起工作以执行SQL语句。因此,我们预计TIDB中的第99百分位数响应时间约为100毫秒。

碎片或不碎片?

在Shopee,我们有一个包含数十个检查点的列表,以帮助我们评估一个新的数据库设计,其中“是否进行分片”是一个重要的问题。很长一段时间以来,MySQL分片是我们横向扩展数据库的唯一方法。在我们将TiDB引入Shopee之后,我们得到了一个新的“无分片”选项。

根据我们的经验,在某些情况下,MySQL分片弊大于利。我们不得不承担日常开发、运营和维护的额外费用。在数据库选择阶段,dba和r&d需要识别以下场景,并找到具体的解决方法:

  • 当我们无法准确估计数据库的容量

    例如,过去三个月在过去三年中,在线日志数据库的增量数据的大小超过了过去三年。如果我们实施分片,我们需要一次又一次地重新使用这种数据库。每个分片过程都很复杂,需要很多努力。

    根据我们的经验,TiDB是一个理想的日志存储解决方案。目前,在Shopee,在TiDB中存储日志是一种常见的做法。

  • 当我们使用一个数据库来运行多维复杂的查询

    拍摄电子商务订单数据库作为示例。每个子系统需要通过买方,卖方,订单状态和付款方式过滤数据。如果我们被买方汇总,那么难以查询卖家的信息,反之亦然。

    一方面,我们为最重要的查询维度创建了单独的异构索引数据库。另一方面,我们在TIDB上实现了订单聚合表,以聚合各种分片中分散到单个TIDB表中的订单数据。这使得在TIDB的聚合表上直接运行完整表扫描的复杂的SQL查询。

  • 当数据在数据库中分布不均匀时

    对于这样的“顶”和“跟随”,社交应用数据,如果我们进行分片由用户数据库,数据可能会分布不均。对于碎片少数数据量可能会比其他碎片显著较高。这些碎片有大量的数据也为热点读取和写入。这很容易招致性能瓶颈。

    一种常见的做法是重新分片:将数据分成更多的分区,以减少每个分片的数据大小和读写流量。

    最近,我们已经开始了一些数据迁移到TiDB。理论上,如果TiDB表主键稀疏分散,热数据可以被均匀地TiKV之间分布地区(TiKV中数据存储的基本单元)。

    就整体而言,MySQL的分片可以解决对数据库的横向扩展的问题,但它会导致一些痛点在开发,运营和维护。我们试图减轻和解决了MySQL拆分框架下的问题。同时,我们试图建立一个能使我们不必分片数据库基础TiDB的解决方案。在这方面,我们已经取得了进展。

在数据库选择中汲取的经验教训

到目前为止,我已经描述了Shopee的数据库选择和相关关键指标的基本策略。在本节中,我会与你分享我们所学到的内容。

使用MySQL作为内存数据库

在Shopee,我们有时会使用MySQL作为内存数据库。后的应用程序进入生产环境中,R&d团队可以首先集中在应用程序逻辑,而数据库访问层的代码可能不是最佳的。

因此,在项目的早期阶段,缓慢的查询和频繁的读写是常见的问题。为了解决这些问题,我们试图确保内存空间足够大,以便将所有热数据加载到MySQL缓冲池中。这有助于缓解一些应用程序性能问题。

根据我们的统计数据,80%的Shopee的生产数据库有少于50 GB的数据。由于我们的数据库服务器的内存大小大于50 GB,因此我们可以通过应用程序试验和错误时段进行。当我们输入数据突出阶段时,我们可以要求研发团队优化数据库。

减少Terabyte-Scale数据库

在我们所有的生产数据库中,2.5%有超过1 TB的数据。这些Terabyte级数据库的平均数据大小为2 TB。最大的数据有超过4 TB。DBA的首要任务是连续减少那些Terabyte级数据库的数据量。

为了解决数据库数据量激增的问题,我们可以尝试MySQL分片和TiDB。我们还可以归档旧数据和升级硬件资源。

归档旧数据

旧数据占用了大量磁盘空间,但它们并不经常被读写。这意味着它们可能不是“热门数据”。如果应用程序所有者允许,我们通常会将旧数据归档到一个单独的MySQL实例。应用程序需要将读写迁移到新实例。新实例将旧数据按年或月存储在不同的表中,以避免单个表太大。对于新实例,我们还可以启用InnoDB透明页面压缩,以减少磁盘占用。

TIDB是数据存档的好选择。从理论上讲,TIDB集群可以无限扩展,用户不需要担心有限的磁盘容量。TIDB在计算和存储层中具有弹性水平可扩展性。因此,我们可以根据数据增长和应用程序读写服务逐步添加服务器。这有助于确保有效的硬件使用,并防止许多资源在归档数据库的早期生产阶段空闲。

扩大

你可能不知道,当MySQL的数据大小命中1个TB和磁盘空间有限,会发生什么。我们可以双击磁盘空间,增加内存容量赢得工程师有更多的时间分片数据库?

实际上,当数据库拥有tb级的数据时,可能很难为已经存在很长时间的应用程序实现数据库分片。如果可以对旧数据进行归档以保持稳定的数据量(但数据库仍然存储tb级的数据),我们还可以升级硬件以提高数据库性能。

使用REDIS将峰值流量平稳

我们有两种使用Redis来处理高并发读写的方法:

  • 写信给缓存然后数据库
  • 先写入数据库,然后写入缓存

写信给缓存然后数据库

应用前端直接读取并写入Redis。应用程序后端平滑,并将数据持续到MySQL或TIDB。在这种情况下,MySQL和TIDB用作Redis数据的持久层。当我们设计一个系统时,如果我们在生产环境中预测高并发读取和写入时,它可以使用REDIS作为缓冲层。

对于Shopee的一些社交相关应用程序来说,它们在大型促销活动期间的峰值流量是平时的数十倍甚至数百倍。这些应用程序是典型的性能关键应用程序。如果研发团队没有预料到,应用程序仍然直接对数据库进行读写,那么当推广活动中流量激增时,数据库就会崩溃。在这种情况下,Redis是缓解后端数据库流量高峰的理想解决方案。

如果整个Redis的集群降?我们有两个解决方案:

  • 使应用程序直接读取和写入数据库。这可能会影响性能,但它保持大多数数据的完整性。一些数据关键应用程序倾向于采用此解决方案。
  • 将流量切换到新的redis群集以恢复服务,然后开始累积数据。此外,可以运行另一个应用程序将一些旧数据从数据库加载到Redis。某些应用程序具有高并发操作,但可以容忍数据丢失。他们可以采用这个解决方案。

先写入数据库,然后写入缓存

我们依然用读取应用程序,并写入到数据库。我们可以使用Shopee的数据事件中心(DEC),连续解析MySQL的二进制日志,整理结果,然后写入Redis的中间件。这样一来,密集的只读流量可移至Redis的。这大大降低了数据库的负载。

当我们将数据重新建立到Redis时,我们可以为特定查询模式自定义数据结构。SQL不适合实现一些查询。有时,使用REDIS运行这些查询更有效。

此外,与应用程序与数据库和redis的应用程序写入数据相比,通过解析MySQL Binlog更有益的重建Redis中的重建数据。它的应用实现很容易,因此开发人员不需要了解数据库中的数据复制逻辑到Redis。

但它的缺点是写入延迟。数据被写入MySQL Minight然后发送到Redis。在此过程中,可能存在几十毫秒的延迟。如果我们想以这种方式使用REDIS,我们需要知道应用程序是否接受此类延迟。

当我们实时查询新订单时,我们通常通过这种方式避免在MySQL原初上的高频只读查询。为避免辅助复制延迟的影响,我们必须向MySQL原文中向Shopee Order表的某些关键列路由查询。在一个大的促销活动中,主要可能不堪重负。因此,我们改变了我们的方法,首先将新订单数据写入MySQL,然后将Binlog解析结果转换为Redis。这样,我们有效地减轻了MySQL原初级的压力。

重构数据结构和代码而不是直接迁移

当开发人员将数据从MySQL迁移到TiDB时,dba经常提醒开发人员调整数据结构和代码到TiDB。

这是一个例子。系统先前与MySQL分片实施。该解决方案的所有数据均分为1000个表。当我们迁移到TiDB,我们停止了拆分和合并这些表到一个表。

我们完成迁移和应用恢复服务后,我们发现一个SQL查询的性能严重抖动。在高并发流量,这个查询甚至带动了整个TiDB集群挂。

我们分析这个查询,结果发现:

  • 查询运行得相当频繁。在高峰期,它占所有只读查询的90%。

  • 查询是一个复杂的SQL查询,需要完整的表扫描。通过添加索引很难优化查询。在迁移到TIDB之前,MySQL有1000个表。当我们执行查询时,只扫描一张小表,我们有超过20个MySQL Subnaries来服务查询。即便如此,随着数据尺寸的增加并且热数据量超过内存大小,所有MySQL Substies都被淹没了。

    数据迁移到TIDB和1,000个表合并为1时,查询必须扫描更大的表格。从TIKV节点传递大量的中间结果集到SQL节点。因此,性能是不希望的。

基于上述分析,研发团队介绍了Redis。当他们将Binlog解析结果转换为Redis时,他们为查询定制了数据结构。他们将90%的Redis切换了90%的只读查询。结果,查询变得更快,更稳定,并且TIDB的存储和计算节点显着降低。

TiDB是高度兼容MySQL语法.这简化了从MySQL到TiDB的迁移。但是TiDB是一个新的数据库,它的实现与MySQL完全不同。所以我们需要根据TiDB的特点和具体的应用场景,制定一个定制的解决方案。

如何我们使用TiDB在Shopee

TiDB是一个支持HTAP工作负载的开源NewsQL数据库。它是MySQL兼容的,具有水平可扩展性,强大的一致性和高可用性。看其架构

本节概述了Shopee上的TiDB集群状态以及我们使用TiDB的场景。

群集状态

  • 截至2019年年底,Shopee已部署到生产环境20+ TiDB集群。有400多个节点。
  • 数据大小是200 + TB。
  • 我们主要使用TIDB 2.1在生产环境,并开始尝试TIDB 3.0.在某些应用中。
  • 最大的集群有40多个节点,数据容量约为30 TB。
  • 这些TIDB集群在用户,项目,订单和风险控制等多个系统中运行。

应用场景

在Shopee,我们在三个场景中使用TiDB:

  • 日志存储

    • 用例:审计日志和风险控制系统
    • 前端应用程序将日志数据写入Kafka..后端应用程序异步消耗Kafka消息并将它们转换为TIDB。管理后端网站等应用程序可以直接从TIDB读取日志。
    • 我们可以根据需要添加存储和计算节点。操作和维护比MySQL分片简单。
  • MySQL分片的数据聚合

    • 用例:订单数据聚合和项数据聚合
    • 应用数据写入MySQL分片。我们开发了一个名为Data Event Center (DEC)的中间件来解析MySQL binlog并异步复制数据到TiDB。商业智能(BI)和管理后端系统等应用程序在TiDB上运行复杂的查询。他们不需要考虑分片规则,直接读取TiDB中的聚合表。
  • 应用程序直接读取和写入TiDB

    • 用例:Shopee聊天系统
    • 应用程序直接读取和写入TIDB。我们不需要碎片。这使得更容易实现应用程序。我们有设置TiDB BINLOG为一些集群和解析的binlog Kafka组件。然后,其他应用程序可以订阅数据更改。

结论

这篇文章涵盖了商店关于如何选择关系数据库的想法以及使用MySQL,TIDB和Redis的经验。

简而言之,如果您的数据大小很小,您的申请处于早期阶段,MySQL对您来说是一个不错的选择。您也不需要损害您的应用程序设计进行分片。那是因为随着您的业务发展和数据量的增长,您可以将从MySQL顺利迁移到TIDB。当应用程序开发仍然灵活时,您的应用程序将是水平扩展的。同时,您可以利用REDIS加快查询并缓解数据库的压力,以便您可以更关注吞吐量和强的一致性。

我们选择TiDB是因为它是开源的,水平扩展的,并且与MySQL兼容的特性。在过去的两年里,我们见证了TiDB的快速发展和显著进步。TiDB是Shopee最重要的数据库基础设施之一,我们正在越来越多的场景中使用它。未来,TiDB将为Shopee提供更多流量。

我们要感谢PingCAP成员和TiDB社区建设TiDB,为我们提供了有效的支持。

关于商店

Shopee是东南亚及台湾地区领先的电子商务平台。它于2015年在7个市场推出,以连接该地区的消费者、卖家和企业。

Shopee报价由数以百万计的人们每天享受方便,安全,和引人入胜的体验。它提供了广泛的产品种类,通过集成支付和物流,以及流行的娱乐支持的功能定制为每个市场。Shopee也是一个关键因素,该地区的数字经济与帮助品牌和企业家在电子商务取得成功的坚定承诺。

Shopee是一家领先的全球消费互联网公司Sea Limited(纽约证券交易所:SE)的一部分。除了Shopee,Sea的其他核心业务还包括其数字娱乐ARM,Garena和Digital Financial Services Arm,Seamoney。海上的使命是为了更好地获得消费者和小企业的技术。

准备开始用TIDB开始吗?