谁说 Facebook 弃用 Cassandra?相反 Facebook 拥有全世界最大的单个 Cassandra 集群部署,并且他们对 Cassandra 作了不少性能优化,包括 Cassandra on RocksDB 以提高 Cassandra 的响应时间。git
在 Instagram (Instagram是Facebook公司旗下一款免费提供在线图片及视频分享的社交应用软件,于2010年10月发布。)上,咱们拥有世界上最大的 Apache Cassandra 数据库部署。咱们在 2012 年开始使用 Cassandra 取代 Redis ,在生产环境中支撑欺诈检测,Feed 和 Direct inbox 等产品。起初咱们在 AWS 环境中运行了 Cassandra 集群,可是当 Instagram 架构发生变化时,咱们将 Cassandra 集群迁移到Facebook 的基础架构中。咱们对 Cassandra 的可靠性和可用性有了很是好的体验,可是在读取数据延迟方面咱们以为他须要改进。github
去年 Instagram 的 Cassandra 团队开始着手这个项目,以显着减小 Cassandra 的读取延迟,咱们称之为 Rocksandra。 在这篇文章中,我将描述该项目的动机,咱们克服的挑战以及内部和公共云环境中的性能指标。算法
在 Instagram 上,咱们大量使用 Apache Cassandra 做为通用键值存储服务。Instagram 的大多数 Cassandra 请求都是在线的,所以为了向数亿 Instagram 用户提供可靠且响应迅速的用户体验,咱们有很高的 SLA 要求。数据库
Instagram 可靠性 SLA 保持为5-9s,这意味着在任何给定时间,请求失败率应小于0.001%。为了提升性能,咱们主动监控不一样 Cassandra 集群的吞吐量和延迟,尤为是 P99 读取延迟。apache
下面的图显示了一个生产 Cassandra 集群的客户端延迟。蓝线是平均读取延迟(5ms),橙色线是 P99 读取延迟(在25ms到60ms的范围内)。性能优化
通过调查,咱们发现 JVM 垃圾收集器(GC)对延迟峰值作出了很大贡献。咱们定义了一个称为 GC 停滞百分比的度量,用于衡量Cassandra 服务器执行 GC(Young Gen GC)而且没法响应客户端请求的时间百分比。结果显示咱们生产 Cassandra 服务器上的 GC 停滞百分比。在最低请求流量时间窗口期间为1.25%,在高峰时段可能高达2.5%。服务器
这代表 Cassandra 服务器实例在垃圾收集上花费 2.5% 的运行时间,而这段时间是不能服务客户端请求的。GC 开销显然对咱们的 P99 延迟有很大影响,所以若是咱们能够下降 GC 停顿百分比,咱们将可以显着下降P99延迟。数据结构
Apache Cassandra 是一个分布式数据库,并用 Java 编写了基于 LSM 树的存储引擎。 咱们发现存储引擎中的组件,如memtable,压缩,读/写路径等,在 Java 堆中建立了不少对象,并为 JVM 产生了大量开销。为了减小来自存储引擎的GC影响,咱们考虑了不一样的方法,并最终决定开发C++存储引擎来替换现有的引擎。架构
咱们不想从头开始构建新的存储引擎,所以咱们决定在 RocksDB 之上构建新的存储引擎。框架
RocksDB 是一个开源的,高性能嵌入式键值数据库。它是用 C++ 编写的,并为 C++,C 和 Java 提供官方 API。RocksDB 针对性能进行了优化,尤为是在 SSD 等快速存储方面。它在业界普遍用做 MySQL,mongoDB 和其余流行数据库的存储引擎。
在 RocksDB 上实现新的存储引擎时,咱们克服了三个主要挑战:
第一个挑战是 Cassandra 尚未可插拔的存储引擎架构,这意味着现有的存储引擎与数据库中的其余组件耦合在一块儿。为了在大规模重构和快速迭代之间找到平衡点,咱们定义了一个新的存储引擎 API,包括最多见的读/写和流接口。这样咱们就能够在 API 后面实现新的存储引擎,并将其注入 Cassandra 内部的相关代码路径。
其次,Cassandra 支持丰富的数据类型和表模式,而 RocksDB 提供纯粹的键值接口。咱们仔细定义了编码/解码算法,使得咱们使用 RocksDB 数据结构来构建 Cassandra 数据模型,并支持与原始 Cassandra 相同的查询语义。
第三个挑战是关于 streaming。 Streaming 在 Cassandra 这样的分布式数据库是很重要组件。每当咱们从 Cassandra 集群加入或删除节点时,Cassandra 都须要在不一样节点之间传输数据以平衡集群中的负载。现有的 streaming 实现基于当前存储引擎的。所以,咱们必须将它们彼此分离,建立一个抽象层,并使用 RocksDB API 从新实现 streaming 传输。对于高 streaming 吞吐量,咱们如今首先将数据流式传输到临时 sst 文件,而后使用 RocksDB 提取文件 API 当即将它们批量加载到 RocksDB 实例中。
通过大约一年的开发和测试,咱们已经完成了第一个版本的实现,并成功将其推广到 Instagram 中的几个生产 Cassandra 集群。在咱们的一个生产集群中,P99读取延迟从60ms降至20ms。 咱们还观察到该集群上的GC停滞从2.5%降低到0.3%,这减小了10倍!
咱们还想验证 Rocksandra 在公共云环境中是否表现良好。咱们在 AWS 环境中使用三个 i3.8 xlarge EC2 实例部署了一个 Cassandra 集群,每一个实例具备 32 个核,244GB内存和 带有4个nvme闪存盘的raid0。
咱们使用 NDBench 做为基准测试,并使用这个框架中的默认表模式:
TABLE emp ( emp_uname text PRIMARY KEY, emp_dept text, emp_first text, emp_last text )
咱们将 250M 6KB 行数据预先加载到数据库中(每一个服务器在磁盘上存储大约500GB的数据)。咱们在 NDBench 中配置了128个读客户端和128个写客户端。
咱们测试了不一样的工做负载并测量了 avg/P99/P999 读/写延迟。如咱们所见,Rocksandra 提供了更低且一致的读/写延迟。
咱们还测试了一个只读工做负载并观察到,在相似的P99读取延迟(2ms)下,Rocksandra 读取吞吐量提升了10倍(Rocksandra为300K/s,C * 3.0为 30K/s)。
咱们开源了 Rocksandra 代码库和基准框架,您能够从Github下载(https://github.com/Instagram/cassandra/tree/rocks_3.0),在您本身的环境中试用!
下一步,咱们正在积极开发更多 C 功能,如二级索引,修复等。咱们还在开发一个 C 可插拔存储引擎架构,以便将咱们的工做贡献给Apache Cassandra 社区。
原文连接 本文为云栖社区原创内容,未经容许不得转载。