Spark in action on Kubernetes - 存储篇(一)
前言
在上篇文章中,我们分析了Spark Operator内部的机制,今天我们会讨论一个在大数据领域中最重要的话题 - 存储。大数据已经无声无息的融入了每个人的生活中。大到旅游买房,小到外卖打车,都可以看到通过大数据提供数据分析、数据推荐、数据决策的使用场景。大数据要想能够更准确地协助决策,需要在数据多维度、数据完备性等方面有较高要求。可预知的在未来,数据的量级会越来越大,特别是随着5G时代的到来,数据的吞吐量级成指数的增长,数据的维度与来源会越来越多,数据的种类也会变得越来越异质化,对大数据平台也带来新的挑战。成本低、存得多、读写快成为大数据存储的三大问题,而今天我们就会针对这三大问题进行探讨。
容器化大数据的计算与存储
计算和存储分离是大数据领域被大家讨论过很多次的问题了,通常我们会通过如下几个角度来看这个问题:
- 硬件限制:机器的带宽成倍数的增长,但是磁盘的速度基本不变,从而造成数据本地读写优势减弱。
- 计算成本:计算和存储的量级不匹配,可能造成算力的大量浪费,独立计算资源可以节约成本。
- 存储成本:集中式存储可以在保证更高SLA的前提下降低存储成本,使得自建数据仓库的优势减少。
这三大问题,随着容器时代的到来也变得愈发的凸显。我们知道在kubernetes中,Pod是运行在底层的资源池上,而Pod所需要的存储是通过PV或者PVC的方式动态分配与挂载的,从某种意义来讲,容器本身的架构就是计算与存储分离的。那么使用了存储与计算分离方式的大数据容器集群会带来哪些变化与优势呢?
- 成本更低
通常在阿里云上建立一个Spark大数据平台的时候,首先会选择D系列的机器,在上面搭建HDFS、Hadoop等一系列的基础组件,然后再将Spark等作业任务通过Yarn进行调度,跑在这个集群之上。D系列的内网带宽范围是3Gbps-20Gbps,默认可以绑定(4-28块) 5.5T的本地盘。因为在云上,云盘的IO和网络的IO是共享的,而本地盘的IO是独立的,因此D系列+本地盘的IO性能会比同规格传统机型+云盘的性能更好。
但是在实际生产中,我们会发现存储的数据对着时间变得越来越多,而由于数据具有一定的时效性,造成单位时间的算力与存储的增长是不相匹配的,这个时候就会带来了成本的浪费。那么如果我们使用计算和存储分离的思想,使用外部存储,例如OSS、Nas或者DFS(阿里云HDFS产品),会有哪些变化呢?
首先,我们屏蔽由于存储的IO差异造成的影响,先都使用远程的DFS作为文件存储。然后我们选择了ecs.ebmhfg5.2xlarge(8C32G6Gbps)和ecs.d1ne.2xlarge (8C32G6Gbps) 两款分别面向计算和大数据场景规格配置相同的热门机型,进行了比对。
ecs.ebmhfg5.2xlarge(8C32G)的测试结果
ecs.d1ne.2xlarge (8C32G)的测试结果
通过Hibench我们可粗略的估算,在假定IO性能基本一致的场景下,ecs.ebmhfg5.2xlarge会比ecs.d1ne.2xlarge计算性能高30%左右,而成本上ecs.ebmhfg5.2xlarge会比ecs.d1ne.2xlarge低25%左右。
也就是说如果单单只看计算的能力,是可以有更高效、更节省的机型选择的。当存储和计算分离后,我们可以从存储和计算两个维度分开去估算所需的用量,在机型上可以更多的考虑高主频计算能力较强ECS,而存储上可以使用OSS或者DFS,存储成本也相较本地存储更为低廉。此外通常D系列的机型都是1:4的CPU内存比,随着大数据作业的场景越来越丰富,1:4的CPU内存比也不完全是最佳的配比,当存储与计算分离后,我们可以根据业务的类型选择合适的计算资源,甚至可以在一个计算资源池中维护多种计算资源,从而提高资源使用率。
数据存储的SLA和计算任务的SLA也是完全不同的,存储上是无法忍受宕机或者中断的,但是对于计算任务而言,本身已经被切割为子任务了,单个子任务的异常只需重试即可,那么进一步就可以使用类似竞价实例这种成本更低的资源来作为计算任务运行时环境,实现成本的进一步优化。
此外容器最大的特点就是弹性,通过弹性的能力,容器可以在短时间内获得超远原本自身几十甚至上百倍的计算资源,而计算任务完成后又自动释放掉。目前阿里云容器服务提供autoscaler进行节点级别的弹性伸缩,可以做到在1分半内伸缩500台节点。传统的计算与存储耦合的场景下,存储是阻碍弹性的一大障碍,而存储和计算分离后,就可以针对近乎无状态的计算来实现弹性的能力,实现真正的按需使用、按量消费。
- 存的更多
使用外部存储后,我们不止存储量级上可以做到近乎无限,而且可以有更多的选择。在本文开头位置,我们已经提到了大数据时代的到来,将引入更多维度、更异质化的数据。而这也对数据存储的方式与类型也带来了更多的挑战。单纯的HDFS、Hbase、Kafka等数据存储与链路将无法满足我们的需求。例如从IoT设备采集的数据更倾向于使用时序存储进行离线、从应用上下游的产生的数据更倾向于存放在结构化数据库中,数据的来源与链路会越来越多,大数据平台的底层基础设施与依赖就会越变越多。在云上,阿里云提供了多种类型的存储服务,可以满足各种大数据处理的场景。除了传统的HDFS、Hbase、kafka、OSS、Nas、CPFS等存储,还包包含MNS、TSDB、OAS(冷数据归档)等等。使用存储服务可以让大数据平台更关注在业务的开发,而不是底层基础架构的运维。不但能够存的更多,还可以存的更好、存的更省。
- 读写更快
从某种角度来讲,读写更快是不可能的,因为独立本地盘可以通过挂足够盘并行的方式进行提升的,但是要注意的问题在于,当我们通过MR进行任务切割后,每个子任务的瓶颈是否还是在磁盘IO上,大部分情况下答案是否定。上面我们测试的ECS规格内网的带宽已经可以到达6Gbps,如果全部网络带宽都换算成磁盘的IO的话,这个量级的数据吞吐IO相比8C32G的算力而言是冗余的,所以此处我们提到的读写更快是指在IO冗余的前提下提升读写速度的方式。OSS是阿里云上提供的对象存储,读取不同单个文件的IO是并行的,也就是说如果你的业务场景是大量中小型文件的并行读取,例如在Spark中读写目录的方式,那么此时IO的读写速度近似是线性增强的。如果依然希望使用HDFS的开发者,阿里云也提HDFS存储服务,提供了大量存储与查询的优化,和传统的自建的HDFS相比有50%左右的提升。
阿里云容器服务的存储方案
阿里云容器服务在多个维度多个层次满足大数据处理中的需求。开发者可以根据不同的业务场景和IO的新更能指标要求,选择合适自己的存储方式。
大量小文件存储
OSS是面向这个场景的最佳使用方式,在容器中可以使用两种方式操作OSS,一种是将OSS挂载为一个文件系统,一种是直接在Spark中使用SDK来操作。第一种方案在大数据的场景下是非常不适用的,特别是文件比较多的场景,如果没有类似SmartFS的优化手段,会带来很大的时延与不一致性。而使用SDK的方式则非常直接简单,只需将相应的Jar放在CLASSPATH下即可,可以参考如下代码,直接处理OSS中的文件内容。
package com.aliyun.emr.example
object OSSSample extends RunLocally {
def main(args: Array[String]): Unit = {
if (args.length < 2) {
System.err.println(
"""Usage: bin/spark-submit --class OSSSample examples-1.0-SNAPSHOT-shaded.jar <inputPath> <numPartition>
|
|Arguments:
|
| inputPath Input OSS object path, like oss://accessKeyId:accessKeySecret@bucket.endpoint/a/b.txt
| numPartitions the number of RDD partitions.
|
""".stripMargin)
System.exit(1)
}
val inputPath = args(0)
val numPartitions = args(1).toInt
val ossData = sc.textFile(inputPath, numPartitions)
println("The top 10 lines are:")
ossData.top(10).foreach(println)
}
override def getAppName: String = "OSS Sample"
}
另外针对Spark SQL的场景,阿里云也提供了https://yq.aliyun.com/articles/593910">oss-select的方式进行支持,可以通过SparkSQL的方式对单文件检索和查询。代码仓库地址。特别注意:当使用Spark Operator的方式进行任务执行是,需要在Driver Pod与Exector Pod的CLASSPATH下预置好相应的Jar包。
OSS的方式主要面向单个文件在百兆之下,文件数目比较多的场景优化较好,数据存储是几种常见存储中最便宜的,支持冷热数据的分离,主要面向读多写少或者不写的场景。
HDFS文件存储
阿里云上新推出了DFS服务,可以像在Hadoop分布式文件系统 (Hadoop Distributed File System) 中管理和访问数据。无需对现有大数据分析应用做任何修改,即可使用具备无限容量及性能扩展、单一命名空间、多共享、高可靠和高可用等特性的分布式文件系统。
DFS服务兼容HDFS协议,开发者只需将相应的调用Jar包放置在Driver Pod与Exector Pod的CLASSPATH中即可,调用时可以如下的方式进行调用。
/* SimpleApp.scala */
import org.apache.spark.sql.SparkSession
object SimpleApp {
def main(args: Array[String]) {
val logFile = "dfs://f-5d68cc61ya36.cn-beijing.dfs.aliyuncs.com:10290/logdata/ab.log"
val spark = SparkSession.builder.appName("Simple Application").getOrCreate()
val logData = spark.read.textFile(logFile).cache()
val numAs = logData.filter(line => line.contains("a")).count()
val numBs = logData.filter(line => line.contains("b")).count()
println(s"Lines with a: $numAs, Lines with b: $numBs")
spark.stop()
}
}
DFS服务的方式主要是面向高IO读写的热数据场景,价格会高于OSS存储,但低于Nas以及其他结构化存储。对于已经习惯了HDFS的开发者而言,是最佳的的方案。在所有的存储方案中,目前IO性能最佳,同容量场景,IO优于本地盘。
常规文件存储
OSS的方式对于某些场景而言,数据的上传与传输依赖SDK,操作会略显不便。那么Nas也是一种备选的方案,Nas的本身的协议是强一致性的,开发者可以像操作本地文件的方式,读写数据。使用方式如下:
- 首先在容器服务控制台创建Nas相关的存储PV与PVC。
- 然后在Spark Operator的定义中声明所使用的PodVolumeClain。
apiVersion: "sparkoperator.k8s.io/v1alpha1"
kind: SparkApplication
metadata:
name: spark-pi
namespace: default
spec:
type: Scala
mode: cluster
image: "gcr.io/spark-operator/spark:v2.4.0"
imagePullPolicy: Always
mainClass: org.apache.spark.examples.SparkPi
mainApplicationFile: "local:///opt/spark/examples/jars/spark-examples_2.11-2.4.0.jar"
restartPolicy:
type: Never
volumes:
- name: pvc-nas
persistentVolumeClaim:
claimName: pvc-nas
driver:
cores: 0.1
coreLimit: "200m"
memory: "512m"
labels:
version: 2.4.0
serviceAccount: spark
volumeMounts:
- name: "pvc-nas"
mountPath: "/tmp"
executor:
cores: 1
instances: 1
memory: "512m"
labels:
version: 2.4.0
volumeMounts:
- name: "pvc-nas"
mountPath: "/tmp"
当然对于Kubernetes比较熟悉的开发者,同样可以使用动态存储的方式直接挂载。具体文档地址如下。
Nas存储的方式在Spark的场景下用途比较少,主要是因为在IO方面与HDFS有一定差距,在存储价格方面比OSS也贵了不少。不过对于需要复用一些data workflow的产生结果,且IO要求要求不是特别高的场景,Nas的使用还是非常简单的。
其他存储结构
在Spark Streaming的场景中,我们还经常使用例如mns或者kafka,有的时候也会使用Elasticsearch与Hbase等等。这些在阿里云上面也都有对应的服务支持,开发者可以通过这些云服务的集成与使用,将精力更多的放在数据开发上。
最后
本文主要和大家探讨了当容器遇到大数据后,改如何通过存储与计算分离的方式,降低资源的使用成本,通过不同的场景,选择合适的存储方式,实现云原生的大数据容器化计算。在下一篇文章中,我们会为大家介绍如何通过弹性的方式,在存储和计算分离的场景下,实现计算资源池的成本节约。
本文作者:莫源
本文为云栖社区原创内容,未经允许不得转载。
Spark in action on Kubernetes - 存储篇(一)的更多相关文章
- Spark in action on Kubernetes - Spark Operator的原理解析
前言 在上篇文章中,向大家介绍了如何使用Spark Operator在kubernetes集群上面提交一个计算作业.今天我们会继续使用上篇文章中搭建的Playground进行调试与解析,帮助大家更深入 ...
- Spring Boot 揭秘与实战(二) 数据存储篇 - ElasticSearch
文章目录 1. 版本须知 2. 环境依赖 3. 数据源 3.1. 方案一 使用 Spring Boot 默认配置 3.2. 方案二 手动创建 4. 业务操作5. 总结 4.1. 实体对象 4.2. D ...
- Spring Boot 揭秘与实战(二) 数据存储篇 - MongoDB
文章目录 1. 环境依赖 2. 数据源 2.1. 方案一 使用 Spring Boot 默认配置 2.2. 方案二 手动创建 3. 使用mongoTemplate操作4. 总结 3.1. 实体对象 3 ...
- Spring Boot 揭秘与实战(二) 数据存储篇 - JPA整合
文章目录 1. 环境依赖 2. 数据源 3. 脚本初始化 4. JPA 整合方案一 通过继承 JpaRepository 接口 4.1. 实体对象 4.2. DAO相关 4.3. Service相关 ...
- Spring Boot 揭秘与实战(二) 数据存储篇 - MyBatis整合
文章目录 1. 环境依赖 2. 数据源3. 脚本初始化 2.1. 方案一 使用 Spring Boot 默认配置 2.2. 方案二 手动创建 4. MyBatis整合5. 总结 4.1. 方案一 通过 ...
- Spark Streaming接收Kafka数据存储到Hbase
Spark Streaming接收Kafka数据存储到Hbase fly spark hbase kafka 主要参考了这篇文章https://yq.aliyun.com/articles/60712 ...
- android之存储篇——SQLite数据库
转载:android之存储篇_SQLite数据库_让你彻底学会SQLite的使用 SQLite最大的特点是你可以把各种类型的数据保存到任何字段中,而不用关心字段声明的数据类型是什么. 例如:可以在In ...
- kubernetes 存储卷
kubernetes 存储卷 数据卷用于实现容器持久化数据,Kubernetes对于数据卷重新定义,提供了丰富强大的功能.在Kubernetes系统中,当Pod重建的时候,数据卷会丢失,Kube ...
- Spring Boot 揭秘与实战(二) 数据存储篇 - 声明式事务管理
文章目录 1. 声明式事务 2. Spring Boot默认集成事务 3. 实战演练4. 源代码 3.1. 实体对象 3.2. DAO 相关 3.3. Service 相关 3.4. 测试,测试 本文 ...
随机推荐
- SPOJ 2916 GSS5 - Can you answer these queries V
传送门 解题思路 和GSS1相似,但需要巨恶心的分类讨论,对于x1<=y1< x2< =y2 这种情况 , 最大值应该取[x1,y1]的右端最大+[y1+1,x2-1]的和+[x2, ...
- mybatis深入理解(八)-----关联表查询
一.一对一关联 1.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数据 创建一张教师表和班级表,这里我们假设一个老师只负责教一个班,那么老师和班级之间的关系就是一种一对一的关 ...
- Java问题解读系列之IO相关---Java深拷贝和浅拷贝
前几天和棒棒童鞋讨论Java(TA学的是C++)的时候,他提到一个浅拷贝和深拷贝的问题,当时的我一脸懵圈,感觉自己学Java居然不知道这个知识点,于是今天研究了一番Java中的浅拷贝和深拷贝,下面来做 ...
- MySQL笔记<一>创建数据库和表
参考博客 https://www.cnblogs.com/sqbk/p/5806797.html https://www.cnblogs.com/tomasman/p/7151962.html
- Elasticsearch入门学习重点笔记
原文:Elasticsearch入门学习重点笔记 必记知识点 Elasticsearch可以接近实时的搜索和存储大量数据.Elasticsearch是一个近实时的搜索平台.这意味着当你导入一个文档并把 ...
- Ubuntu 服务器默认的root账号是没有激活的,需要用初装的用户账号给root设置管理密码
user@ubuntu12:~$ sudo password root //用sudo修改账户 1.根据提示输入当前用户的密码: 2.修改成功之后你就可以使用root账号了,可以使用su root 命 ...
- 【洛谷】P1876 开灯
P1876 开灯 题目背景 该题的题目是不是感到很眼熟呢? 事实上,如果你懂的方法,该题的代码简直不能再短. 但是如果你不懂得呢?那...(自己去想) 题目描述 首先所有的灯都是关的(注意是关!),编 ...
- Vue--由自动获取焦点引出的DOM、mounted、自定义指令
一.自动获取焦点的DOM实现 <!DOCTYPE html> <html lang="en"> <head> <meta charset= ...
- 光(mirror room)
/* 光线只有遇上边界或堵塞的格子才会改变方向,所以改变方向的位置是有限的,光线的方向又最多只有四种,所以光线在循环之前改变方向的次数是O(n+m+k)级别的.我们可以模拟光线的移动.已知光线位置和光 ...
- arcgis信息窗口
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...