当前位置: 首页 > news >正文

开源Pravega架构解析:如何通过分层解决流存储的三大挑战?

当前的大数据处理系统无论是何种架构都面临一个共同的问题,即:“计算是原生的流计算,而存储却不是原生的流存储” 。Pravega 团队重新思考了这一基本的数据处理和存储规则,为这一场景重新设计了一种新的存储类型,即原生的流存储,命名为”Pravega”,取梵语中“Good Speed”之意。本文是“分布式流存储 Pravega 系列文章”第二篇,第一篇文章回顾《为什么你需要开源分布式流存储 Pravega?》。

流行大数据存储存在的三大问题

如图1是目前大数据处理平台最常见的Lambda架构,它的优势在于满足了实时处理与批处理需求,但是,正如前一篇文章《实时流处理统一批处理的最后一块拼图:Pravega》的观点,从存储的角度看其缺点也很明显,可以总结为如下三点:

  1. 实时处理、批处理不统一,不同的处理路径采用了不同的存储组件,增加了系统的复杂度,导致了开发人员的额外学习成本和工作量。
  2. 数据存储多组件化、多份化,如下图,同样的数据会被存储在Elastic Search 、S3对象存储系统、Kafka等多种异构的系统中,而且考虑到数据的可靠性,数据还都是多份冗余的,这就极大的增加了用户的存储成本。而往往对于企业用户来说,0.1%的存储冗余都意味着损失。
  3. 系统里存储的组件太多太复杂,也增加了使用的运维成本。并且大部分现有的开源项目还处于“强运维”的产品阶段,对于企业用户来说又是很大的开销。

\"image\"

图1. Lambda架构

为了解决如上提出的三个问题:降低开发成本、减少存储成本与减少运维成本,在这篇文章中,我们将从Pravega的架构角度出发,挖掘流存储的具体需求,并且通过架构的设计解决这三个问题。

第四种存储类型:流存储

存储的视角来说,存储架构的设计需要首先明确存储的特点。每种类型的数据都有其原生的属性和常用访问模式,对应有最佳的适用场景以及最合适的存储系统。

在物联网、金融等实时应用场景中,所需要存储的数据一般被称之为“流数据”,流数据一般被定义为:

流数据是一组顺序、大量、快速、连续到达的数据序列,一般情况下,数据流可被视为一个随时间延续而无限增长的动态数据集合。

\"image\"

图2. 四大存储类型

上图所示,我们将流数据定义为第四种数据类型。从左到右分布着四种最常见的的存储类型,依次从传统批数据转变成流数据。传统数据库这类基于事务的程序适合采用块存储系统。文件共享场景下需要在用户间共享文件进行读写操作,因此适合采用分布式文件(NAS)存储系统。而需要无限扩展并支持REST接口读写的非结构化的的图像/音视频文件则非常适合采用对象存储系统。

流数据存储针对流数据的应用场景需要满足以下需求:

  • 低延时:在高并发条件下 \u0026lt;10ms的读写延时。

  • 仅处理一次:即使客户端、服务器或网络出现故障,也确保每个事件都被处理且只被处理一次。

  • 顺序保证:可以提供严格有序的数据访问模式

  • 检查点:确保每个读客户端/上层应用能保存和恢复原来的使用状态

从访问模式角度看,Pravega需要统一传统批数据和流数据,因此不仅需要实时到达数据的低延时(low latency)读和写,还要满足对于历史数据的高吞吐(high throughput)的读。

技术在某种程度上一定是来自此前已有技术的新的组合。 --《技术的本质》,布莱恩·阿瑟

Pravega也并不是凭空发明出来的,它是以前的成熟技术与新技术的组合。Pravega团队拥有着基于日志存储的设计经验,也拥有Apache ZooKeeper/BookKeeper的项目历史,加之大量实时系统同样也采用日志存储的方式来完成实时应用的消息队列,想要满足这三种数据访问模式,自然想到了使用仅附加(Append only)的日志作为存储原语。

\"image\"

图3. 日志结构的三种数据访问机制

如图3所示:在Pravega里,日志是作为共享存储原语而存在的,数据以事件(event)的形式以仅附加的方式写入日志当中。

所有写入操作以及大部分读取操作都发生在日志的尾部(tail read/write)。写操作将事件附加到日志中,而大量读客户端希望以到达日志的速度读取数据。这两种数据访问机制主要是需要低延迟。

对于历史数据的处理,读客户端不从日志的尾部读取,而是从日志中的任意位置开始读。这些读取称为追赶读(catch-up read)。我们可以采用和尾部数据一样的高性能存储(例如SSD)来存储历史数据,但这会非常昂贵并迫使用户通过删除历史数据来节省成本。这就需要Pravega架构提供一种机制,允许客户在日志的历史部分使用经济高效,高度可扩展的高吞吐量存储,这样他们就能够保留所有的历史数据,来完成对一个完整数据集的读取。

Pravega逻辑架构

\"image\"

图4. Pravega架构

为了实现上述的三种访问模式的性能需求,Pravega采用了如上图所示的分层存储架构。事件可以存储在低延迟/高IOPS的存储(第一层存储)和更高吞吐量的存储(第二层存储)中。通过这种方式,冷热数据分离有效降低了数据存储成本。上层使用Apache ZooKeeper作为分布式协调器,并提供统一的Stream抽象。

第一层存储用于快速持久地将数据写入stream,并确保从stream的尾读尽可能快。第一层存储基于开源Apache BookKeeper项目。BookKeeper是一种底层的日志服务,具有高扩展、强容错、低延迟等特性。许多Apache开源项目,例如Apache Pulsar,Apache DistributedLog都是基于这一项目实现。BookKeeper对于复制、持久性、一致性、可用性、低延时的承诺也正是Pravega所需要的第一层存储的需求。为达到高性能的读写延迟需求,我们建议第一层存储通常在更快的SSD或甚至非易失性存储(non-volatile RAM)上实现。

第二层存储考虑到经济效益,选用高度可扩展,高吞吐量的云存储,目前Pravega支持HDFS,NFS和S3协议的二级存储,用户可以选用支持这些协议的大规模存储进行扩展。Pravega提供了两种数据降层(retention)的模式,一种基于数据在stream中保留的时间,另一种基于数据在stream中存储的容量大小。Pravega会异步将事件从第一层迁移到第二层,而读写客户端将不会感知到数据存储层级的变化,依然使用同样的Stream抽象操作数据的读写。

正是基于这样的分层模型,文章开头提到的三大问题被一次性解决。

  1. 对于开发者而言,只需要关心Stream抽象的读写客户端的操作。实时处理和批处理不再区分对数据访问方式。
  2. 数据仅在第一层存储有三份拷贝,在第二层存储则可以通过商业分布式/云存储自身拥有的高可用、分布式数据恢复机制(如Erasure Coding)进一步降低存储系数,达到比公有云存储更便宜的总拥有成本(TCO)。
  3. 所有的存储组件归结为统一的Pravega,组件仅包括Apache ZooKeeper,Apache BookKeeper以及可托管的第二层存储,运维复杂程度大大降低。Pravega还提供了额外的“零运维”自动弹性伸缩特性,进一步减轻了数据高峰期的运维压力。

Pravega的基本概念

本章节将简要介绍一些Pravega的基本概念。

Stream:Pravega存储的抽象,类似于Kafka的topic,是一种可持久化、可伸缩、仅附加、字节大小无限制的序列,具有高性能和强一致性的特性。在同一个scope内stream具有命名唯一性,stream由一个或多个segment组成。用户可以在创建stream时配置降层策略(RetentionPolicy)和伸缩策略(ScalingPolicy)。

Scope:scope是stream的命名空间,将stream进行分类和隔离。在多租户场景下,每一个租户拥有一个scope。例如,具体应用、商业部门等可以划分scope。

Segment:Pravega最底层的存储单元,对应BookKeeper中的ledger。stream由segment组成,segment是stream的分片,类似但不局限于Kafka的partition。事件(event)存储在segment里。一个stream的segment的数量可以根据到达数据量和伸缩策略改变,同时也是该stream读取时的最大并行度。

事件(event):Pravega IO操作的最小单位,类似于Kafka的message。事件是stream中的可以表示为一组字节的任何事物。例如:来自温度传感器的读数,网站点击和日志数据等。

Stream,segment和事件的关系如下图所示。

\"image\"

图5 Stream, segment, event关系示意图

路由键(Routing key):事件所拥有的属性,路由键会通过一致性散列算法(consistent hashing)将事件读写到对应的segment,因此相同的路由键会将事件路由到相同的segment,由相同的读客户端读取。路由键是Pravega许多读写语义特性的基础。

写客户端(Writer):写客户端是一个可以创建事件并将事件写入一个或多个stream中的应用,所有的事件数据都通过附加到stream的尾部来写入。

读客户端(Reader):读客户端是一个可以从一个或多个stream中读取事件的应用。Pravega会以负载均衡方式分配stream中的segment给指定的Reader。读客户端可以从stream中的任何一点读取,比如头部、尾部、中间任何一点。

读者组(Reader Group):读者组由读客户端组成,读者组本质上是为了实现同一个组内读客户端的并行化以及不同组的stream读取扇出,类似于Kafka的Consumer Group。同一个读者组内的读客户端可以一起并行读取给定的一组segment内的事件。读者组由name字符串唯一标识。

Pravega产品定位和与kafka的对比

前面我们已经提到过Pravega是从存储的视角来看待流数据,而Kafka本身的定位是消息系统而不是存储系统,它是从消息的视角来看待流数据。消息系统与存储系统的定位是不同的,简单来说,消息系统是消息的传输系统,关注的是数据传输与生产消费的过程。Pravega的定位就是企业级的分布式流存储产品,除了满足流的属性之外,还需要满足数据存储的持久化、安全、可靠性、一致性、隔离等属性,关注数据的生产、传输、存放、访问等整个数据的生命周期。作为企业级的产品,一些额外的特性也有支持,例如:数据安全、多租户、自动扩缩容、状态同步器、事务支持等,部分特性将在后续文章详述。

这里我们把Pravega与Kafka做了对比,大体在功能上的差异如下表所示。功能上的差异也只是说明各个产品针对的业务场景不同,看待数据的视角不同,并不是说明这个产品不好,另外每个产品自身也在演进,因此本对比仅供参考。

名称Kafka 2.1.0Pravega 0.4
自动扩容缩容部分支持支持
完全不丢数据不支持支持
多协议可入支持支持
无限个流不支持支持
事务支持支持
恰好一次支持支持
顺序保证支持支持
兼容Kafka API支持支持
与主流处理平台集成支持部分支持
多种二层存储支持(HDFS,S3,etc)不支持支持
安全与加密支持支持
无限多租户不支持部分支持
服务质量保证部分支持部分支持
流计算应用集成支持支持
数据治理不支持支持

总结

本文从商业痛点出发,分析了分布式流存储Pravega的需求,重点介绍了Pravega的关键架构以及关键特性,另外还与Kafka做了简要对比。有关Pravega的更多详细信息,请参阅官方网站以及关注我们的后续文章。

Pravega系列文章计划

Pravega根据Apache 2.0许可证开源,我们欢迎对流式存储感兴趣的大咖们加入Pravega社区,与Pravega共同成长。下一篇文章将会从Pravega的应用实例出发,阐述如何使用Pravega。本篇文章为Pravega系列第二篇,后面的文章标题如下(标题根据需求可能会有更新):

  1. 实时流处理(Streaming)统一批处理(Batch)的最后一块拼图:Pravega
  2. Pravega设计原理与基本架构介绍
  3. Pravega应用实例
  4. Pravega动态弹性伸缩特性
  5. Pravega的仅一次语义及事务支持
  6. 分布式一致性解决方案:状态同步器
  7. 与Apache Flink集成使用

作者简介

  • 滕昱:就职于 DellEMC 非结构化数据存储部门 (Unstructured Data Storage) 团队并担任软件开发总监。2007 年加入 DellEMC 以后一直专注于分布式存储领域。参加并领导了中国研发团队参与两代 DellEMC 对象存储产品的研发工作并取得商业上成功。从 2017 年开始,兼任 Streaming 存储和实时计算系统的设计开发与领导工作。

  • 吴长平,现就职于DellEMC,10年+ 存储、分布式、云计算开发以及架构设计经验,现从事流存储和实时计算系统的设计与开发工作;

  • 周煜敏,复旦大学计算机专业研究生,从本科起就参与 DellEMC 分布式对象存储的实习工作。现参与 Flink 相关领域研发工作。

参考链接

  1. https://www.pravega.io

相关文章:

  • Android AutoCompleteTextView和MultiAutocompleteTextView实现动态自动匹配输入的内容
  • socketserver
  • Python Revisited Day 04 (控制结构与函数)
  • 开源引路人:我的Apache Mentor之路
  • 一次性能优化:吞吐量从1提升到2500
  • Eureka自我保护机制与Eureka服务发现(Discovery)
  • __proto__ 和 prototype的关系
  • 这道js题你会吗?
  • java B2B2C源码电子商城系统-Spring Cloud Eureka自我保护机制
  • 基于 React TypeScript Webpack 的微前端应用模板
  • xgboost回归损失函数自定义【一】
  • Java null最佳实践
  • 36氪首发|「优仕美地医疗」获亿元级B轮融资,要打造日间手术机构的连锁服务网络...
  • 阿里云联合8家芯片商推“全平台通信模组”,加速物联网生态建设
  • MySQL设置主从复制
  • 【剑指offer】让抽象问题具体化
  • CentOS7简单部署NFS
  • IIS 10 PHP CGI 设置 PHP_INI_SCAN_DIR
  • passportjs 源码分析
  • Three.js 再探 - 写一个跳一跳极简版游戏
  • tweak 支持第三方库
  • 初识 webpack
  • 官方新出的 Kotlin 扩展库 KTX,到底帮你干了什么?
  • 利用DataURL技术在网页上显示图片
  • 使用权重正则化较少模型过拟合
  • 问:在指定的JSON数据中(最外层是数组)根据指定条件拿到匹配到的结果
  • 在weex里面使用chart图表
  • ​七周四次课(5月9日)iptables filter表案例、iptables nat表应用
  • #我与Java虚拟机的故事#连载09:面试大厂逃不过的JVM
  • $emit传递多个参数_PPC和MIPS指令集下二进制代码中函数参数个数的识别方法
  • (+4)2.2UML建模图
  • (C语言)输入自定义个数的整数,打印出最大值和最小值
  • (ZT)一个美国文科博士的YardLife
  • (笔试题)分解质因式
  • (第一天)包装对象、作用域、创建对象
  • (附源码)springboot教学评价 毕业设计 641310
  • (官网安装) 基于CentOS 7安装MangoDB和MangoDB Shell
  • (黑马出品_高级篇_01)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式
  • (简单) HDU 2612 Find a way,BFS。
  • (全部习题答案)研究生英语读写教程基础级教师用书PDF|| 研究生英语读写教程提高级教师用书PDF
  • (一)Thymeleaf用法——Thymeleaf简介
  • (转载)OpenStack Hacker养成指南
  • .NET 4.0中使用内存映射文件实现进程通讯
  • .NET CF命令行调试器MDbg入门(三) 进程控制
  • .NET delegate 委托 、 Event 事件
  • .NET 使用 ILRepack 合并多个程序集(替代 ILMerge),避免引入额外的依赖
  • .NET 中 GetHashCode 的哈希值有多大概率会相同(哈希碰撞)
  • .NET4.0并行计算技术基础(1)
  • .NET命令行(CLI)常用命令
  • [3D基础]理解计算机3D图形学中的坐标系变换
  • [AIGC] MySQL存储引擎详解
  • [Angular 基础] - 指令(directives)
  • [AX]AX2012开发新特性-禁止表或者表字段
  • [BJDCTF2020]The mystery of ip1
  • [C++] sqlite3_get_table 的使用