共计 5258 个字符,预计需要花费 14 分钟才能阅读完成。
本文次要分享腾讯智慧批发团队优码业务在 MongoDB 中的利用,采纳腾讯云 MongoDB 作为主存储服务给业务带来了较大收益,次要包含:高性能、快捷的 DDL 操作、低存储老本、超大存储容量等收益,极大的升高了业务存储老本,并进步了业务迭代开发效率。
一. 业务场景
腾讯优码从连贯消费者到连贯渠道终端,实现以货的数字化为根底的企业数字化降级,蕴含营销能力降级和动销能力降级。腾讯优码由副品通、门店通和会员通三个子产品组成。
腾讯优码整体视图
1.1 副品通
腾讯优码副品通提供防伪鉴真能力,实现一物一码全流程副品追溯,全链路数据存储至区块链,确保真实可信;更可中转品牌私域,实现流量进一步转化;同时副品通提供微信域内的品牌爱护能力,阻断品牌伪冒网站流传、帮忙消费者辨认混充商品。
产品次要蕴含如下外围个性:
1.2 门店通
腾讯优码门店通是服务品牌方、经销商、业代员以及终端门店四大批发链路外围角色实现基于终端销售门店的销售管理手段降级与销售额晋升。
产品次要蕴含如下外围个性:
1.3 会员通
腾讯优码会员通是面向批发品牌商提供的 SaaS+ 定制化服务的产品,以扫码为切入点,连接线上线下场景。提供丰盛的扫码 / 互动流动模型、流动评估体系助力品牌连贯消费者。
产品次要蕴含如下外围个性:
二. 码存储选型
腾讯智慧批发优码业务存储批发商品二维码信息,该信息为智慧批发最外围的数据信息,提供“从连贯消费者到连贯渠道终端,实现以货的数字化为根底的企业数字化降级”相干服务。因而码数据存储问题是我的项目最外围的问题。
2.1 需要和计划
要解决码存储问题,首先须要剖析码存储的特色。通过剖析码存储问题的次要特色是:
海量数据:腾讯优码做的商品二维码,随着越来越多的商品应用腾讯优码业务,二维码数据开始出现指数级增长。
关联存储:码与码之间存在 1:1 和 1:N:N 的关联关系,须要存储这种关系,并且提供相应的关联查问。
多维度查问:针对不同的利用场景须要提供不同维度的条件查问。
在获取到码存储特色之后,通过多方调研和排查之后,初步选取了 2 种存储计划:
- MySQL + ES:MySQL 分库分表存储码元数据,提供须要高性能的读写场景;而后依据需要将局部数据同步 ES 以应答各种简单的查问场景。
- MongoDB:MongoDB 是全球排名最高的分布式 NoSQL 数据库,其外围个性是 No Schema、高可用和分布式,非常适合分布式存储。
2.2 计划剖析
2.2.1 MySQL + ES 计划剖析
MySQL + ES 是一个比拟常见的存储解决方案,并且在很多畛域内被广泛应用,如会员或商品信息贮存畛域。此计划的劣势是可能提供十分多的查问形式和不同的性能保障,能够应答各种各样简单的业务查问需要。
MySQL + ES 的常见架构是写操作间接作用于 MySQL,而后通过 canal + Kafka 的形式将数据变更同步到 ES,而后再依据不同的查问场景从 MySQL 或者 ES 查问数据。下图是在腾讯优码业务场景下可能的架构图:
从架构图能够看出,本计划存在几个问题:
数据同步和一致性问题:这个问题在数据量不大的状况下不会有影响。然而如果数据量百亿甚至千亿时就是一个十分重大的问题。
数据容量问题:个别状况下 MySql 的单表数据最好维持在百万级一下,如果单表数据量过大之后读写都是个问题。那么如果要存储千亿数据就要几千上万张表,如此多的分表须要业务本人保护时开发运维都是简直不可行的。
老本问题:数据冗余存储,会减少额定的存储老本。同时 ES 为了保证数据可靠性和查问性能,须要更多的机器和内存。而且 ES 存在数据收缩问题,对于同样的数据,须要相当 MySql 来说更大的磁盘。
DDL 运维问题:MySql 在分库散布之后,因为 DDL 语句须要操作大量的库表,因而十分耗时,同时也容易出错。依据咱们以前的我的项目教训来说,当有几百张表,单表几十万数据时,一个简略的减少字段的 DDL 语句也须要 1 小时甚至更久能力实现。
开发成本问题:此计划须要业务本人保护分库分表、数据同步和依据需要选取不同的查问引擎。不仅整个架构简单,同时在做业务需要时须要慎重考虑,稍不留神应用错的存储引擎就可能导致性能问题。
程度扩容问题:MySql 分库分表要扩容须要业务手动 rehash 搬迁数据,老本十分高,而且很难解决扩容过程中的数据读写问题。
2.2.2 MongoDB 计划剖析
MongoDB 是十分闻名的分布式存储引擎,具备 No Schema、高可用、分布式、数据压缩等多方面的劣势。尽管 MongoDB 是 NoSQL 存储引擎,然而其 Wired Tiger 存储引擎和 innerdb 一样底层应用的是 B + 树,因而 MongoDB 在提供分布式存储的前提下同时可能提供大部分 MySql 反对的查问形式。因而,在应用 MongoDB 时,咱们不须要 MySql 冗余表或者 ES 来反对大部分的分布式查问。在腾讯优码的利用场景下,基于 MongoDB 的存储架构如下图所示:
从图中能够看出,MongoDB 能够防止冗余存储带来的数据同步和一致性问题、存储老本问题、资源 / 运维 / 开发成本。而且在进一步测试和剖析 MongoDB 的性能和性能之后,咱们发现 MongoDB 还具备如下劣势:
无 DDL 问题:因为 MongoDB 是 No Schema 的,因而能够防止 MySql 的 DDL 问题。
数据主动平均:MongoDB 有主动 rebalance 性能,能够在数据分布不平均的时候,主动搬迁数据,保障各个分片间的负载平均。
更低的老本:MongoDB 自带数据压缩,在等同数据下,MongoDB 需要的磁盘更少。
更高的性能:MongoDB 最大化的利用了内存,在大部分场景下领有靠近内存数据库的性能。通过测试 MongoDB 的单分片读性能约为 3 万 QPS。
更多的读写形式:尽管 MongoDB 没有 ES 的倒排索引,其反对的查问形式略逊于 ES。然而,MongoDB 在领有大部分 ES 的查问能力的同时,其性能远高与 ES;而且绝对 MySql 来说 MongoDB 的字段类型反对内嵌对象和数组对象,因而能满足跟多的读写需要。
2.3 计划比照
通过后面的剖析,咱们初步判断 MongoDB 领有更好的体现。因而为了进一步确定 MongoDB 的劣势,咱们深刻比照了 MySQL + ES 与 MongoDB 在各方面的体现。
2.3.1 存储老本比照
MongoDB 在存储上的劣势次要体现在两个方面:数据压缩和无冗余存储。
为了更加直观的看出磁盘应用状况,咱们模仿了在腾讯优码业务场景下,MySQL + ES 和 MongoDB 下的理论存储状况。
一方面,在 MySQL+ES 的计划下,为了满足需要咱们须要将冗余一份 ES 数据和 MySQL 的冗余表。其中码的外围数据存储在 MySQL 中,其磁盘总量仅占总的 38.1%。后面说过 MongoDB 的计划是不须要冗余存储的,因而应用 MongoDB 能够缩小这 61.9% 的总数据容量。
另一方面,通过测试同样的码数据,MongoDB snappy 压缩算法的压缩率约 3 倍,zlib 压缩算法的压缩率约 6 倍。因而,尽管业务为了保证系统的稳定性而抉择 snappy 压缩算法,但 MongoDB 依然只须要 MySQL 三分之一的磁盘耗费。
2.3.2 开发运维老本
无数据同步链路:应用 MongoDB 不须要数据同步,因而就不须要保护 canal 服务和 kafka 队列,大大减少开发和运维难度。
人力老本收益:在 MySQL+ES 架构下每次对 MySQL 集群做增加字段变更,都需运维 肯定的人日投入,并且存在业务抖动危险,同时影响业务迭代公布进度,迭代公布耗时且危险大。
开发保护老本:MongoDB 存储架构简略,一份存储,无数据一致性压力。
动静扩容:MongoDB 反对随时动静扩容,根本不存在容量下限问题,而 MySQL 在扩容时须要业务手动 rehash 变迁数据,并本人保证数据一致性和完整性。
2.3.3 性能比照
通过压测,同样的 4C8G 的机器配置下,MySQL 和 MongoDB 在大数据量下写性能基本一致。MySQL 的读性单分片约 6000QPS 左右,ES 的性能只有 800QPS 左右。而 MongoDB 单分片地读性能在 3 万 QPS 左右,远高于 MySQL 和 ES 的性能。
2.3.4 总结
通过下面的剖析和比照之后,能够显著看出 MongoDB 在各方面都有劣势。为了更加直观的看出不同计划的差别,这里列出了从性能、性能、老本、可扩展性和可维护性等 5 个方面的比照数据:
综上所述,MongoDB 不仅能齐全满足业务需要,同时在性能、老本、可维护性等各方面都优于其它两种计划,因而腾讯优码最终选用的是 MongoDB 作为业务外围数据码的存储计划。
三.MongoDB 分片集群优化过程
批发优码业务对老本要求较高、数据量较大,线上实在读写流量不是太高 (读 3W QPS 要求),因而采纳低规格 4C8G 规格(单节点规格) 分片模式集群部署。
3.1 分片集群片建抉择 + 预分片
批发优码数据查问都是通过码 id 查问,因而抉择码 id 作为片建,这样能够最大化查问性能,索引查问都能够通过同一个分片获取数据。此外,为了防止分片间数据不平衡引起的 moveChunk 操作,因而抉择 hashed 分片形式,同时提前进行预分片,MongoDB 默认反对 hashed 预分片,以优码详情表为例,预分片形式如下:
use db_code_xx
sh.enableSharding("db_code_xx")
// n 为理论分片数
sh.shardCollection("db_code_xx.t_code_xx", {"id": "hashed"}, false,{numInitialChunks:8192*n})
3.2 低峰期滑动窗口设置
因为 MongoDB 实例节点规格低(4C8G),当分片间 chunks 数据不平衡的状况下,会触发主动 balance 平衡,因为实例规格低,balance 过程存在如下问题:
CPU 耗费过高,迁徙过程甚至耗费 90% 左右 CPU
业务拜访抖动,耗时减少
慢日志减少
异样告警增多
以上问题都是因为 balance 过程进行 moveChunk 数据搬迁过程引起,为了疾速实现数据从一个分片迁徙到另一个分片,MongoDB 外部会不停的把数据从一个分片移动到另一个分片,这时候就会耗费大量 CPU,从而引起业务抖动。
MongoDB 内核也思考到了 balance 过程对业务有肯定影响,因而默认反对了 balance 窗口设置,这样就能够把 balance 过程和业务高峰期进行错峰,这样来最大化躲避数据迁徙引起的业务抖动。例如设置凌晨 0 - 6 点低峰期进行 balance 窗口设置,对应命令如下:
use config
db.settings.update({"_id":"balancer"},{"$set":{"activeWindow":{"start":"00:00","stop":"06:00"}}},true)
3.3 写多数派优化
因为优码二维码数据十分外围,为了防止极其状况下的数据失落和数据回归等危险,因而客户端采纳 writeConcern={w:“majority”}配置,确保数据写入到正本集大多数成员后才向客户端发送确认。
链式复制的概念:假如节点 A(primary)、B 节点(secondary)、C 节点(secondary),如果 B 节点从 A 节点同步数据,C 节点从 B 节点同步数据,这样 A ->B->C 之间就造成了一个链式的同步构造,如下图所示:
MongoDB 多节点正本集能够反对链式复制,能够通过如下命令获取以后正本集是否反对链式复制:
cmgo-xx:SECONDARY> rs.conf().settings.chainingAllowed
true
cmgo-xx:SECONDARY>
此外,能够通过查看正本集中每个节点的同步源来判断以后正本集节点中是否存在有链式复制状况,如果同步源为 secondary 从节点,则阐明正本集中存在链式复制,具体查看如下正本集参数:
cmgo-xx:SECONDARY> rs.status().syncSourceHost
xx.xx.xx.xx:7021
cmgo-xx:SECONDARY>
因为业务配置为写多数派,鉴于性能思考能够敞开链式复制性能,MongoDB 能够通过如下命令操作进行敞开:
cfg = rs.config()
cfg.settings.chainingAllowed = false
rs.reconfig(cfg)
链式复制益处:能够大大加重主节点同步 oplog 的压力。
链式复制有余:当写策略为 majority 时,写申请的耗时变大。
基于写性能思考,当业务采纳“写大多数”策略时,间接敞开链式复制性能,确保写链路过长引起的写性能降落。
对于作者:
CSIG 腾讯优码团队、腾讯 MongoDB 团队
社区招募
为了让社区组委会成员和志愿者敌人们灵便参加,同时咱们为想要深度参加社区建设的搭档们开设了“招募通道”,如果您想要在社区外面结交气味相投的技术搭档,想要通过在社区积淀有价值的干货内容,想要一个展现本人的舞台,晋升本身的技术影响力,即刻退出社区奉献队伍~ 点击链接提交申请:
http://mongoingmongoing.mikec…