Shopee的数据库是如何做选型的_第1页
Shopee的数据库是如何做选型的_第2页
Shopee的数据库是如何做选型的_第3页
已阅读5页,还剩9页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Word文档 Shopee的数据库是如何做选型的 Shopee在上线了5年后,已经成为了东南亚(跨境电商)的领头羊,该平台的数据库,值得不少的跨境电商平台方学习,他们是如何做选型的?Hishang在这里跟大家来讲解一下吧。 Shopee于2021年底上线,是东南亚地区领先的电子商务平台,掩盖东南亚和台湾等多个市场,在深圳和新加坡分别设有研发中心。本文系Shopee的分布式数据库选型思路漫谈。由于是漫谈,可能不成体系,但会着重介绍一些阅历以及踩过的坑,供应给大家参考。 1 Shopee的数据库使用状况 Shopee在用哪些数据库? 先说一下当前Shopee线上在用的几种数据库: 在Shopee,

2、我们只有两种关系数据库:MySQL和TiDB。目前大部分业务数据运行在MySQL上,TiDB集群的比重过去一年来快速增长中。 Redis在Shopee各个产品线使用广泛。从DBA的角度看,Redis是关系数据库的一种重要补充。 内部也在使用诸如HBase和Pika等多种NoSQL数据库,使用范围多限于特定业务和团队。不在本次争论范围内。 数据库选型策略 过去的一年里,我们明显感觉到数据库选型在DBA日常工作中的占比越来越重了。随着业务快速成长,DBA每周需要创建的新数据库较之一两年前可能增加了十倍不止。我们每年都会统计几次线上规律数据库个数。上图展现了过去几年间这个数字的增长趋势(纵轴表示规律

3、数据库个数,我们把详细数字隐去了)。 历史数据显示,规律数据库个数每年都有三到五倍的增长,过去的2021年增长倍数甚至更高。每个新数据库上线前,DBA和开发团队都需要做一些评估以快速打算物理设计和规律设计。阅历表明,一旦在设计阶段做出了不当打算,后期需要付出较多时间和人力成原来补救。因此,我们需要制定一些简洁高效的数据库选型策略,确保我们大多数时候都能做出正确选择。 我们的数据库选型策略可以概括为三点: 默认使用MySQL。 乐观尝试TiDB。 在必要的时候引入Redis用于消解部分关系数据库高并发读写流量。 在使用MySQL的过程中我们发觉,当单数据库体量达到TB级别,开发和运维的简单度会被

4、指数级推高。DBA日常工作会把消退TB级MySQL数据库实例排在高优先级。 乐观尝试TiDB不是一句空话。2021年初开头,我们把TiDB引入了到Shopee。过去两年间TiDB在Shopee从无到有,集群节点数和数据体积已经达到了可观的规模。对于一些经过了验证的业务场景,DBA会乐观推动业务团队采纳TiDB,让开发团队有机会获得第一手阅历;目前,内部多数业务开发团队都在线上实际使用过一次或者多次TiDB。 关于借助Redis消解关系数据库高并发读写流量,后面会绽开讲一下我们的做法。 分布式数据库选型参考指标 在制定了数据库选型策略之后,我们在选型中还有几个常用的参考指标: 1TB:对于一个新

5、数据库,我们会问:在将来一年到一年半时间里,数据库的体积会不会涨到1TB?假如开发团队很确信新数据库肯定会膨胀到TB级别,应当马上考虑MySQL分库分表方案或TiDB方案。 1000万行或10GB:单一MySQL表的记录条数不要超过1000万行,或单表磁盘空间占用不要超过10GB。我们发觉,超过这个阈值后,数据库性能和可维护性上往往也简单出问题(部分SQL难以优化,不易做表结构调整等)。假如确信单表体积会超越该上限,则应考虑MySQL分表方案;也可以采纳TiDB,TiDB可实现水平弹性扩展,多数场景下可免去分表的苦恼。 每秒1000次写入:单个MySQL节点上的写入速率不要超过每秒1000次。

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

7、能否引入Redis或消息队列作为写缓冲,实现数据库写操作异步化。 P99响应时间要求是1毫秒,10毫秒还是100毫秒?应用程序要求99% 的数据库查询都要在1毫秒内返回吗?假如是,则不建议直接读写数据库。可以考虑引入Redis等内存缓冲方案,前端直接面对Redis确保高速读写,后端异步写入数据库实现数据长久化。我们的阅历是,多数场景下,MySQL服务器、表结构设计、SQL和程序代码等方面做过细致优化后,MySQL有望做到99% 以上查询都在10毫秒内返回。对于TiDB,考虑到其存储计算分别和多组件协作实现SQL执行过程的特点,我们通常把预期值调高一个数量级到100毫秒级别。以线上某TiDB 2

8、.x集群为例,上线半年以来多数时候P99都维持在20毫秒以内,间或会飙升到200毫秒,大促时抖动则更频繁一些。TiDB执行SQL查询过程中,不同组件、不同节点之间的交互会多一些,自然要多花一点时间。 要不要分库分表? 内部的数据库设计评估清单里包含十几个项目,其中要不要分库分表是一个重要议题。在相当长时间里,MySQL分库分表方案是我们实现数据库横向扩展的唯一选项;把TiDB引入Shopee后,我们多了一个不分库分表的选项。 从我们的阅历来看,有几种场景下采纳MySQL分库分表方案的副作用比较大,日常开发和运维都要付出额外的代价和成本。DBA和开发团队需要在数据库选型阶段甄别出这些场景并对症下

9、药。 难以精确预估容量的数据库。举例来讲,线上某日志数据库过去三个月的增量数据超过了之前三年多的存量体积。对于这类数据库,采纳分库分表方案需要一次又一次做Re-sharding,每一次都步骤繁琐,工程浩大。Shopee的实践证明,TiDB是较为抱负的日志存储方案;当前,把日志类数据存入TiDB已经是内部较为普遍的做法了。 需要做多维度简单查询的数据库。以订单数据库为例,各子系统都需要根据买家、卖家、订单状态、支付方式等诸多维度筛选数据。若以买家维度分库分表,则卖家维度的查询会变得困难;反之亦然。一方面,我们为最重要的查询维度分别建立了异构索引数据库;另一方面,我们也在TiDB上实现了订单汇总表

10、,把散落于各个分片的订单数据汇入一张TiDB表,让一些需要扫描全量数据的简单查询直接运行在TiDB汇总表上。 数据倾斜严峻的数据库。诸如点赞和关注等偏社交类业务数据,根据用户维度分库分表后常消失数据分布不匀称的现象,少数分片的数据量可能远大于其他分片;这些大分片往往也是读写的热点,进而简单成为性能瓶颈。一种常用的解法是Re-sharding,把数据分成更多片,尽量稀释每一片上的数据量和读写流量。最近我们也开头尝试把部分数据搬迁到TiDB上;理论上,假如TiDB表主键设计得高度分散,热点数据就有望匀称分布到全体TiKV Region上。 总体来说,MySQL分库分表方案在解决了主要的数据库横向扩

11、展问题的同时,也导致了一些开发和运维方面的痛点。一方面,我们努力在MySQL分库分表框架内解决和缓解各种问题;另一方面,我们也尝试基于TiDB构建不分库分表的新型解决方案,并取得了一些进展。 2 MySQL在Shopee的使用状况 Shopee的母公司SEA Group成立于2021年。我们从一开头就使用MySQL作为主力数据库,从早期的MySQL 5.1渐渐进化到现在的MySQL 5.7,我们已经用了十年MySQL。 我们使用Percona分支,当前存储引擎以InnoDB为主。 一主多从是比较常见的部署结构。我们的应用程序比较依靠读写分别,线上数据库可能会有多达数十个从库。一套典型的数据库部

12、署结构会分布在同城多个机房;其中会有至少一个节点放在备用机房,主要用于定时全量备份,也会供应给数据团队做数据拉取等用途。 假如应用程序需要读取Binlog,从库上会安装一个名为GDS(General DB Sync)的Agent,实时解析Binlog,并写入Kafka。 应用程序透过DNS入口连接主库或从库。 我们自研的数据库中间件,支持简洁的分库分表。何为简洁的分库分表?只支持单一分库分表规章,可以按日期、Hash或者某个字段的取值范围来分片;一条SQL最终只会被路由到单一分片上,不支持聚合或Join等操作。 如何解决TB级MySQL数据库的使用? 依据我们的统计,Shopee线上数据库中8

13、0% 都低于50GB;此外,还有2.5% 的数据库体积超过1TB。上图列出了部分TB级别数据库的一个统计结果:平均体积是2TB,最大的甚至超过4TB。 采纳MySQL分库分表方案和迁移到TiDB是我们削减TB级MySQL数据库实例个数的两种主要途径。除此之外,还有一些方法能关心我们对抗MySQL数据库体积膨胀带来的负面效应。 旧数据归档。许多旧数据库占据了大量磁盘空间,读写却不频繁。换言之,这些旧数据很可能不是热数据。假如业务上许可,我们通常会把旧数据归档到单独的MySQL实例上。当然,应用程序需要把读写这些数据的流量改到新实例。新实例可以按年或按月把旧数据存入不同的表以避开单表体积过大,还可

14、以开启InnoDB透亮页压缩以削减磁盘空间占用。TiDB是特别抱负的数据归档选项:理论上,一个TiDB集群的容量可以无限扩展,不必担忧磁盘空间不够用;TiDB在计算层和存储层皆可水平弹性扩展,我们得以依据数据体积和读写流量的实际增长循序渐进地增加服务器,使整个集群的硬件使用效率保持在较为抱负的水平。 硬件升级(Scale-up)。假如MySQL数据体积涨到了1TB,磁盘空间开头吃紧,是不是可以先把磁盘空间加倍,内存也加大一些,为开发团队争取多一些时间实现数据库横向扩展方案?有些数据库体积到了TB级别,但业务上可能不太简单分库分表。假如开发团队能够通过数据归档等手段使数据体积保持在一个较为稳定(

15、但仍旧是TB级别)的水准,那么适当做一下硬件升级也有助于改善服务质量。 3 Redis和关系型数据库在Shopee的的协作使用 前文中我们提到,使用Redis来解决关系数据库高并发读写流量的问题,下面我们就来讲讲详细的做法。 先写缓存,再写数据库 比较常用的一种做法是:先写缓存,再写数据库。应用程序前端直接读写Redis,后端匀速异步地把数据长久化到MySQL或TiDB。这种做法一般被称之为穿透式缓存,其实是把关系数据库作为Redis数据的长久化存储层。假如一个系统在设计阶段即判明线上会有较高并发读写流量,把Redis放在数据库前面挡一下往往有效。 在Shopee,一些偏社交类应用在大促时的峰

16、值往往会比平常高出数十上百倍,是典型的性能优先型应用(Performance-critical Applications)。假如开发团队事先没有意识到这一点,根据常规做法让程序直接读写关系数据库,大促时不行避开会消失一促就倒的状况。其实,这类场景很适合借助Redis平缓后端数据库读写峰值。 假如Redis集群整体挂掉,怎么办?一般来说,有两个解决方法: 性能降级:应用程序改为直接读写数据库。性能上可能会打一个大的折扣,但是能保证大部分数据不丢。一些数据较为关键的业务可能会更倾向于采纳这种方式。 数据降级:切换到一个空的Redis集群上以尽快恢复服务。后续可以选择从零开头渐渐积累数据,或者运行另

17、一个程序从数据库加载部分旧数据到Redis。一些并发高但允许数据丢失的业务可能会采纳这种方式。 先写数据库,再写缓存 还有一种做法也很常见:先写数据库,再写缓存。应用程序正常读写数据库,Shopee内部有一个中间件DEC(Data Event Center)可以持续解析Binlog,把结果重新组织后写入到Redis。这样,一部分高频只读查询就可以直接打到Redis上,大幅度降低关系数据库负载。 把数据写入Redis的时候,可以为特定的查询模式定制数据结构,一些不太适合用SQL实现的查询改为读Redis之后反而会更简洁高效。 此外,相较于双写方式(业务程序同时把数据写入关系数据库和Redis),

18、通过解析Binlog的方式在Redis上重建数据有明显好处:业务程序实现上较为简洁,不必分心去关注数据库和Redis之间的数据同步规律。Binlog方式的缺点在于写入延迟:新数据先写入MySQL主库,待其流入到Redis上,中间可能有大约数十毫秒延迟。实际使用上要论证业务是否能接受这种程度的延迟。 举例来讲,在新订单实时查询等业务场景中,我们常采纳这种先写数据库,再写缓存的方式来消解MySQL主库上的高频度只读查询。为规避从库延迟带来的影响,部分关键订单字段的查询须打到MySQL主库上,大促时主库很可能就不堪重负。历次大促的实践证明,以这种方式引入Redis能有效缓解主库压力。 4 TiDB在

19、Shopee的使用状况 讲完MySQL和Redis,我们来接着讲讲TiDB。 我们从2021年初开头调研TiDB,到2021年6月份上线了第一个TiDB集群(风控日志集群,版本1.0.8)。2021年10月份,我们把一个核心审计日志库迁到了TiDB上,目前该集群数据量约7TB,日常QPS约为10K15K。总体而言,2021年上线的集群以日志类存储为主。 2021年开头我们尝试把一些较为核心的线上系统迁移到TiDB上。3月份为买家和卖家供应谈天服务的Chat系统部分数据从MySQL迁移到了TiDB。最近的大促中,峰值QPS约为30K,运行平稳。今年也有一些新功能选择直接基于TiDB做开发,比如店

20、铺标签、直播弹幕和选品服务等。这些新模块的数据量和查询量都还比较小,有待持续观看验证。 TiDB 3.0 GA后,新的Titan(/tikv/titan) 存储引擎吸引了我们。在Shopee,我们允许MySQL表设计中使用Text等大字段类型,通常存储一些半结构化数据。但是,从MySQL迁移到TiDB的过程中,大字段却可能成为绊脚石。一般而言,TiDB单行数据尺寸不宜超过64KB,越小越好;换言之,字段越大,性能越差。Titan存储引擎有望提高大字段的读写性能。目前,我们已经着手把一些数据迁移到TiKV上,并打开了Titan,盼望能探究出更多应用场景。 集群概况 目前Shopee线上部署了二十

21、多个TiDB集群,约有400多个节点。版本以TiDB 2.1为主,部分集群已经开头试水TiDB 3.0。我们最大的一个集群数据量约有30TB,超过40个节点。到目前为止,用户、商品和订单等电商核心子系统都或多或少把一部分数据和流量放在了TiDB上。 TiDB在Shopee的使用场景 我们把TiDB在Shopee的使用场景归纳为三类: 日志存储场景 MySQL分库分表数据聚合场景 程序直接读写TiDB的场景 第一种使用场景是日志存储。前面讲到过,我们接触TiDB的第一年里上线的集群以日志类存储为主。通常的做法是:前端先把日志数据写入到Kafka,后端另一个程序负责把Kafka里的数据异步写入Ti

22、DB。由于不用考虑分库分表,运营后台类业务可以便利地读取TiDB里的日志数据。对于DBA而言,可以依据需要线性增加存储节点和计算节点,运维起来也较MySQL分库分表简洁。 其次种使用场景是MySQL分库分表数据聚合。Shopee的订单表和商品表存在MySQL上,并做了细致的数据分片。为了便利其他子系统读取订单和商品数据,我们做了一层数据聚合:借助前面提到的DEC解析MySQL Binlog,把多个MySQL分片的数据聚合到单一TiDB汇总表。这样,类似BI系统这样的旁路系统就不必关注分库分表规章,直接读取TiDB数据即可。除此之外,订单和商品子系统也可以在TiDB汇总表上运行一些简单的SQL查

23、询,省去了先在每个MySQL分片上查一次最终再汇总一次的麻烦。 第三种就是程序直接读写TiDB。像前面提到的Chat系统,舍弃了MySQL,改为直接读写TiDB。优势体现在两个方面:不必做分库分表,应用程序的实现相对简洁、直接;TiDB理论上容量无限大,且便利线性扩展,运维起来更简单。 前面提到过,在Shopee内部使用GDS(General DB Sync)实时解析MySQL Binlog,并写入Kafka供应给有需要的客户端消费。TiDB上也可以接一个Binlog组件,把数据变化持续同步到Kafka上。需要读取Binlog的应用程序只要适配了TiDB Binlog数据格式,就可以像消费MySQL Binlog一样消费TiDB Binlog了。 从MySQL迁移到TiDB:要适配,不要平移 把数据库从MySQL搬到TiDB的过程中,DBA常常提示开发同学:要适配,不要平移。关于这点,我们可以举一个案例来说明一下。 线上某系统最初采纳MySQL分表方案,全量数据均分到1000张表;迁移到TiDB后我们去掉了分表,1000张表合为了一张。应用程序上线后,发觉

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论