AICon 上海站|90%日程已就绪,解锁Al未来! 了解详情
写点什么

从 eBay 购物车丢失看处理网络 I/O

  • 2017-07-20
  • 本文字数:2527 字

    阅读完需:约 8 分钟

eBay 的购物车信息存储依赖于两个不同的数据存储介质,MongoDB 存储用户完整的购物车信息,Oracle 仅存储购物车的大致信息,但是可以通过关键信息查找所有的购物车信息。在 eBay 的这套系统里,MongoDB 更多被用来充当“缓存”,Oracle 数据库作为存储副本。如果数据在 MongoDB 里面找不到了,服务会从 Oracle 里面重新抽取(恢复)数据,然后重新计算用户的购物车。

所有的购物车数据都是 JSON 格式的,JSON 数据在 Oracle 里被存储在 BLOB 格式的字段里。这些 Oracle 里面的数据只能被用于 OLTP 交易。

这篇文章并不是讨论数据库技术的选择(Oracle vs MongoDB,或者其他数据),而是希望能够让大家在巨量访问系统(每天上百万次调用)中找到技术债,理解如何解决问题。

问题描述

2016 年秋天开始,购物车服务出现了缓存层丢失数据的情况,同时,运维团队报告 MongoDB 的备份机制多次出现失败(MongoDB 运行在主从模式)。eBay 的这个服务已经运行了 5 年时间,一直没有出现问题,没有做过任何架构调整和大规模代码改变,需要尽快找到原因和防治办法。针对实际问题进行反复检查,发现 MongoDB 的 oplog(实时性要求极高的写日志记录)正在达到网络 I/O 限制。每一次的数据丢失,都会触发保护措施(再次从 Oracle 读取数据后重复计算),并进一步加长用户的等待时间。

解决方案

在我们具体讨论特定的解决方案前,我们希望去尽可能多地讨论解决方案。例如,一旦备份机制没有启用,是否可以通过隐藏一些副本方式让系统能够正常运行,而不要在系统特别繁忙的时候去尝试重新备份。我们可以尝试超时机制和阶段性副本方式,但是这些方式并不会引起我们本文说的问题发生。

方案一:切片(MongoDB)

团队成员提出对 JSON 数据进行切分,即对原先存储在 MongoDB 里的原子化的购物车信息(一个 JSON 字符串),切分为多个字符串,这样做的好处是可以减少单一 MongoDB 中心节点的写入次数和网络开销。

对于数据切分后的关联方式,远比数据切分、负载均衡复杂,因此,第 1 种方案的选择会引入其他技术难点,需要我们自己能够寻找被切分后的数据的关联性,这就是为什么 eBay 放弃了这个方案。

方案二:有选择的写入

使用 MongoDB 的 set 命令,只针对当特定值发生更改后,才启动写入操作。这种方式理论上也是可行的。

但是如果你真正考虑一下,这种做法没有从根本上确保减少 oplogs 写入次数,但是它很有可能会造成整个文档的更新。

了解一下 MongoDB 的 Set 操作模式。Set 操作可以用于使用特定值替换字段值:

{$Set{:,…}}

假如你考虑一下描述产品的文档如下所示:

{
_id:100, sku:”abc123”, quantity:250, instck:true, reorder:false, details:{model:”14Q2”,make:”xyz”}, tags:[“appeal”,”clothing”],
ratings:[{by:”ijk”,rating:4}] }

对于满足 _id 等于 100 的文档,执行 set 操作更新 quantity 字段、details 字段和 tags 字段的值。

db.products.update( {_id:100}, {$set:
{
quantity:500,
details:{model:”14Q3”,make:”xyz”},
tags:[“coats”,”outerwear”,”clothing”]
} } )

以上这个操作替换 quantity 的值为 500,details 字段的值为一个新的嵌入式文档,tags 值为一个数组。

方案三:客户端压缩

考虑到需要尽快解决问题,所以需要尽量避免重写业务逻辑,压缩方式看起来是比较好的一中了。减少进入 MongoDB 的 Master 节点的数据量,这样可以减少写入 oplog 的数据规模。但是,这种方式会将 JSON 字符串转变为二进制文章,操作时也需要解压缩。

常用的压缩算法主要有:deflate、gzip、bzip2、lzo、snappy 等。差别如下所示:

  1. deflate、gzip 都是基于 LZ77 算法与哈夫曼编码的无损数据压缩算法,gzip 只是在 deflate 格式上增加了文件头和文件尾;
  2. bzip2 是 Julian
    Seward 开发并按照自由软件 / 开源软件协议发布的数据压缩算法,Apache 的 Commons-compress 库中进行了实现;
  3. LZO 致力于解压速度,并且该算法也是无损算法;
  4. LZ4 是一种无损数据压缩算法,着重于压缩和解压缩速度;
  5. Snappy 是 Google 基于 LZ77 的思路用 C++ 语言编写的快速数据压缩与解压程序库,2011 年开源。它的目标并非最大程度地压缩,而是针对最快速度和合理的压缩率。

目标和考虑

在我们开始做这一功能性测试之前,我们需要明确几个目标。

  • 允许购物车被压缩并持久化到 MongoDB(数据不会有改变)。
  • 允许压缩编码方式的选择,支持采用一种编码方式读取,另一种编码方式写入。
  • 允许读到老的、新的、中间状态的购物车信息,新老前后可以互相兼容。
  • 压缩和解压缩的操作可以同时进行。
  • 确保没有针对 MongoDB 数据库的实时 JSON 数据检索查询请求。

JSON 字符串例子

这是老的 JSON 字符串:

{ “_id” : ObjectId(“560ae017a054fc715524e27a”), “user” : “9999999999”,
“site” : 0, “computeMethod” : “CCS_V4.0.0”, “cart” : “…JSON cart
object…”, “lastUpdatedDate” : ISODate(“2016-09-03T00:47:44.406Z”) }

这是压缩之后的 JSON 字符串:

{ “_id” : ObjectId(“560ae017a054fc715524e27a”), “user” : “9999999999”,
“site” : 0, “computeMethod” : “CCS_V4.0.0”, “cart” : “…JSON cart
object…”, “compressedData” : { “compressedCart” : “…Compressed
cart object…” “compressionMetadata” : { “codec” : “LZ4_HIGH”,
“compressedSize” : 3095, “uncompressedSize” : 6485 }, },
“lastUpdatedDate” : ISODate(“2016-09-03T00:47:44.406Z”) }

测试结果

通过使用相同的购物车数据进行测试,观察 CPU 或者 I/O 情况,数据如图所示:


结论

oplog 的写入速率,从 150GB/ 小时下降为大约 11GB/ 小时,下降了 1300%!文档的平均对象大小从 32KB 下降为 5KB,600% 的下降。此外,服务的响应时间也有所改善。数据如图所示:

下面这张图显示的是 MongoDB 的 Ops Manager UI 工具信息,特别标注了压缩和解压缩数据的耗时,以及文档的平均对象大小的下降数据。

最终,对于生产环境下的随机一小时数据压缩,eBay 团队也收集了一些指标图,用于更多的深入观察。


感谢杜小芳对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2017-07-20 19:003870
用户头像

发布了 50 篇内容, 共 29.7 次阅读, 收获喜欢 40 次。

关注

评论

发布
暂无评论
发现更多内容

【ELT.ZIP】OpenHarmony啃论文俱乐部——多维探秘通用无损压缩

ELT.ZIP

OpenHarmony 压缩算法

三级等保是最高的吗?有什么用?

行云管家

网络安全 等保 等保2.0

ICASSP 2022 | 前沿音视频成果分享:基于可变形卷积的压缩视频质量增强网络

阿里云CloudImagine

阿里云 计算机视觉 音视频 视频编码 视频云

如何保持系统的整洁

蜜糖的代码注释

设计原则 项目开发 3月月更

人工智能开源录 | 对话OpenI启智社区:智能无处不在,AI开源创新的发展与探索

OpenI启智社区

软件工程 大模型 东数西算 人工智能开源

Java基础系列文章---异常

NoLongerConfused

3月月更

浏览器工作原理和V8引擎

CRMEB

HertzBeat赫兹节拍 v1.0.beta.5 发布,易用友好的监控告警系统

TanCloud探云

Java angular 告警 应用监控 开源监控系统

java培训:SpringBoot高频面试考点分享

@零度

JAVA开发 springboot

【直播回顾】OpenHarmony知识赋能第四期直播——标准系统HDF开发

OpenHarmony开发者

直播 HDF OpenHarmony

AI语音处理-文字合成语音功能

DS小龙哥

3月月更

Java面向对象知识点拆分(一)

逆锋起笔

面向对象 java基础 3月月更 Java面向对象

小白入门HarmonyOS Connect设备开发的“芯”路历程

HarmonyOS开发者

芯片 HarmonyOS 设备

JavaScript深入理解之闭包

锋享前端

基于CREATE TYPE语法自定义新数据类型

华为云开发者联盟

数据库 数据类型 CREATE TYPE 复合类型

昇思MindSpore全场景AI框架 1.6版本,更高的开发效率,更好地服务开发者

Geek_32c4d0

mindspore 昇思 全场景AI框架

低代码实现探索(三十七)业务的流程,开发的框架

零道云-混合式低代码平台

大数据培训:Hadoop和MPP有什么区别

@零度

hadoop MPP 大数据开发

数据预处理和特征选择

云智慧AIOps社区

数据挖掘 机器学习 算法 特征选择 数据预处理

Redis二三事之事前预防和事中恢复

NoLongerConfused

3月月更

web前端培训:react高频面试题分享

@零度

前端开发 React

N个技巧,编写更高效 Dockerfile|云效工程师指北

阿里云云效

阿里云 云原生 Dockerfile 部署与维护 构建工具

教你如何解决JS/TS里特定String进行拆分然后遍历各个元素

华为云开发者联盟

JavaScript string 遍历 字符串 元素

虎符交易所HOO持续创造今年新高,你的HOO囤够了吗?

区块链前沿News

加密资产 Hoo 虎符交易所 平台币

【IT运维】多台海外主机运维用什么工具好?

行云管家

服务器 IT运维 服务器运维 海外主机

TiDB 可观测性方案落地探索 | “我们这么菜评委不会生气吧”团队访谈

PingCAP

程序员最讨厌的四件事,它能解决!

博文视点Broadview

轻松应对1亿+月活,《迷你世界》背后有啥黑科技

华为云开发者联盟

分布式数据库 中间件 RDS 迷你世界

RocketMQ系列文章---RocketMQ整体架构

NoLongerConfused

RocketMQ

MySQL系列文章---初识MySQL中的锁

NoLongerConfused

3月月更

【51单片机】室友用一把王者时间,学会了去使用数码管

謓泽

3月月更

从eBay购物车丢失看处理网络I/O_语言 & 开发_麦克周_InfoQ精选文章