AI实践哪家强?来 AICon, 解锁技术前沿,探寻产业新机! 了解详情
写点什么

从 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:003973
用户头像

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

关注

评论

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

任何事物当中的百分之九十都是垃圾?

池建强

互联网 信息噪声

如何成为一名具备产品思维的软件工程师?

顾强

产品 开发者 职场

spring事务原理

年轮

spring 源码分析

如何讲好故事

Bob Jiang

单例模式——独一无二的对象

大头星

Java 面试 设计模式 单例模式

物联网技术栈之通信技术

老任物联网杂谈

物联网 通信

工信部报告显示:电话越打越少 、短信越发越多……这是怎么回事?

赵新龙

短信 工信部

有趣的解谜:Python Challenge

封不羁

Python

【玩转写作社区】Markdown & 快捷键详解

InfoQ写作社区官方

写作平台 markdown 编辑器 快捷键 玩转写作平台

MySQL实战四十五讲基础篇总结(三)

一个有志气的DB

MySQL mysql事务

SQL 找出 100 以内的质数

zero

sql MySQ

为什么window.open只是打开了一个空白页

阡陌r

Java 踩坑 网络协议

干货分享:分布式场景之刚性事务-2PC详解

奈学教育

分布式

你是不是对副业有什么误解?

一尘观世界

程序员 副业 认知提升 思维方式 格局

MySQL实战四十五讲基础篇总结(一)

一个有志气的DB

MySQL

回顾 | Apache Flink Meetup 杭州站圆满结束(附PPT下载)

Apache Flink

大数据 flink 流计算 实时计算

MySQL实战四十五讲基础篇总结(二)

一个有志气的DB

MySQL 日志

程序员的晚餐 | 5 月 19 日 蒜香鸡腿,味道令人惊讶

清远

美食

亲密爱人

Janenesome

爱情

比特币为什么值两万亿?

Haiyung

比特币

Java开发架构篇:初识领域驱动设计DDD落地

小傅哥

设计模式 领域驱动设计 DDD 小傅哥 架构设计

一款Python实用神器,5 行 Python 代码 实现一键批量扣图

狂师

Python 学习 效率工具 开发者工具 开发

使用gitlab ci构建IOS包并发送通知消息到企业微信

Zoe

ios ci gitlab

视频 | 5款免费翻译软件实测对比,从花花董花花的被删微博到北京话“你丫给我站住了”都能翻译

赵新龙

翻译

Flink Weekly | 每周社区动态更新-20200513

Apache Flink

大数据 flink 实时计算

【教你如何写作】参与创作,领取 InfoQ 编辑训练营内训课程

InfoQ写作社区官方

写作平台 投稿 热门活动

编辑距离的计算

zikcheng

算法 编辑距离

Flink 与 Hive 的磨合期

Apache Flink

大数据 flink 实时计算

都在这儿了!5月 Flink 社区发版、更新汇总

Apache Flink

大数据 flink 流计算 实时计算

霸榜 GitHub,一款开源的 Linux 神器!

GitHubDaily

GitHub Linux 编程 开发者工具 计算机网络

识别代码中的坏味道(四)

Page

敏捷开发 面向对象 重构 CleanCode 代码坏味道

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