8000 字讲透 OBSA 原理与应用实践
文章作者:存储服务产品部开发者支持团队
1.1 OBS 存储服务概述
华为云 OBS 存储服务提供了 “对象存储服务” 和” 并行文件系统服务”。
1. 对象存储服务:提供传统的对象存储语义。
2. 并行文件系统服务:简称文件桶,基于对象存储服务提供了一种经过优化的高性能文件系统,其实现了追加写,文件截断,目录重命名原子操作等一系列特性,并和对象存储服务一样提供了毫秒级别访问时延,TB 级别带宽和百万级别的 IOPS,因此非常适用于大数据分析等场景,华为云的 MRS,DLI 等大数据分析服务均已支持 OBS 服务作为其底层的存储服务。
1.2 OBSA 项目概述
1.OBSA 项目是围绕 OBS 建立的大数据和 AI 生态,其在不断的发展和完善中,目前有如下子项目:
(1)hadoop-obs 项目:基于华为云 OBS 存储服务实现了 hadoop 文件系统抽象;
(2)flink-obs 项目:基于华为云 OBS 存储服务实现了 Flink 文件系统抽象;
2.OBSA 官方文档:https://support.huaweicloud.cn/bestpractice-obs/obs_05_1501.html
3.OBSA 社区地址:https://github.com/huaweicloud/obsa-hdfs
1.3 hadoop-obs 原理和实践建议
1.3.1 简述
1.hadoop-obs 项目基于 OBS 并行文件系统服务 / 对象存储服务实现了 hadoop 的 FileSystem 抽象 (即 HDFS 协议) OBSFileSystem,可以像使用 HDFS 分布式文件系统一样访问 OBS 中的数据,实现大数据计算引擎 Spark、MapReduce、Hive 等与 OBS 存储服务的对接,为大数据计算提供 “数据湖” 存储。
2.OBSFileSystem 继承实现了 FileSystem 抽象类,适配为对 OBS http/https rest API 接口的访问,下述章节将详细剖析 OBSFileSystem 的实现和实践。
3.hadoop-obs 以 jar 包的形式对外发布,hadoop-huaweicloud-x.x.x-hw-y.jar 包含义:前三位 x.x.x 为配套 hadoop 版本号;最后一位 y 为 hadoop-obs 版本号;如:hadoop-huaweicloud-3.1.1-hw-40.jar,3.1.1 是配套 hadoop 版本号,40 是 hadoop-obs 的版本号。
1.3.2认证和鉴权机制
在了解 OBSFileSystem 的认证和鉴权机制之前,我们先对 OBS 服务的认证和鉴权机制做一个简单的介绍。其主要支持两种认证鉴权机制:
1. 桶策略:桶拥有者通过桶策略可为 IAM 用户或其他帐号授权桶及桶内对象精确的操作权限,桶策略有 20KB 的大小限制,超出此限制可以选择 IAM 策略
2.IAM 策略:IAM 权限是作用于云资源的,IAM 权限定义了允许和拒绝的访问操作,以此实现云资源权限访问控制
不管上述哪种机制,访问 OBS 时均需要 IAM 用户对应的永久 aksk 或是临时 aksk(其包含 ak,sk,securityToken 三部分,其是有时效限制的,一般为 24 小时)
在通过 OBSFileSystem 访问 OBS 时首先需要配置永久 aksk 或是临时 aksk,OBSFileSystem 支持如下几种方式获取 aksk:(优先级由高到低排序)
1. 从 core-site 配置文件中获取:通过 fs.obs.access.key 和 fs.obs.secret.key 和 fs.obs.session.token 配置项获取。其支持 hadoop 的 CredentialProvider 机制,即通过 CredentialProvider 机制对 aksk 进行保护,避免 aksk 的明文暴露,注意不能将其保存在 OBSFileSystem 存储系统的路径上因为循环依赖问题 https://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-common/CredentialProviderAPI.html
附:关于 CredentialProvider 机制相关配置项:
hadoop.security.credential.provider.path:存放机密信息的 keystore 文件路径,例如 aksk 可以存储在其中
hadoop.security.credential.clear-text-fallback:当从 keystore 文件中获取不到机密信息时回落到配置项的明文中去获取 hadoop.security.credstore.java-keystore-provider.password-file:keystore 被加密时,其密码文件的路径
2. 从 URL 中获取:其格式为 obs://{ak}:{sk}@obs-bucket/
3. 从 Provider 中获取:自定义 aksk 提供器,通过 fs.obs.security.provider 配置项进行配置 Provider 需要继承 com.obs.services.IObsCredentialsProvider 接口,目前支持的 Provider:
(1)com.obs.services.EnvironmentVariableObsCredentialsProvider:从环境变量里寻找 aksk,需要在环境变量中定义 OBS_ACCESS_KEY_ID 和 OBS_SECRET_ACCESS_KEY 分别代表永久的 AK 和 SK
(2)com.obs.services.EcsObsCredentialsProvider:从 ECS 元数据中自动获取临时 aksk 并进行定期自动刷新
(3)com.obs.services.OBSCredentialsProviderChain:以链式的形式依次从环境变量,ECS 服务器上进行搜索以获取对应的访问密钥,且会以第一组成功获取到的访问密钥访问 obs
也可以自定义 Provider 完成符合您架构和安全要求的实现。
(MRS 和 DLI 等华为云服务有自己的 provider 实现)
注意事项:
(1)对于类似 mapreduce 的分布式任务,因为分布式任务通过 OBSFileSystem 访问 OBS 且分布式任务被不确定的分配到集群节点上,所以需要能在集群的每一个节点上都能够获取 aksk,例如如果通过 EnvironmentVariableObsCredentialsProvider 方式获取,则需要在每一个节点上都进行环境变量设置
(2)当通过临时 aksk 机制访问 OBS 时注意临时 aksk 的时效性
(3)注意 EcsObsCredentialsProvider 机制中访问 ECS 元数据时的流控,即访问 ECS 元数据获取 aksk 是有频次限制的
1.4写相关流程
1.4.1覆盖写
当调用 OBSFileSystem 的 create 相关方法时将获取 FSDataOutputStream,通过该流写数据到 OBS 中。此流程总的实现思路是通过 “缓存” 和 “并发多段上传” 来实现较高的写性能:
(1)通过 FSDataOutputStream 写入数据时,数据首先将被缓存然后并发多段上传到 OBS
(2)通过参数 fs.obs.multipart.size 设置缓存的大小,当数据写入量达到此阈值时将对应产生一次 range 上传请求,且是异步发起的 range 上传请求,当异步 range 上传任务完成时将及时清理其对应的缓存,例如当缓存机制为 disk 时,将及时清理本地磁盘中的缓存文件;
(3)当调用 FSDataOutputStream 的 close 方法时将等待所有的 range 上传异步任务完成,并发起多段合并请求完成文件的真正写入;并发多段上传线程池相关配置参数:
附 obs java sdk 多段上传:https://support.huaweicloud.cn/sdk-java-devg-obs/obs_21_0607.html
实践建议:
(1)当缓存 fs.obs.fast.upload.buffer 设置为 disk 时(默认),建议使用高性能存储介质(例如 SSD 盘)承载,且当集群中有大量并行任务时,确保缓存盘的空间足够(可以配置多个目录)
(2)当缓存 fs.obs.fast.upload.buffer 设置为 array 或 bytebuffer 时,生产环境谨慎使用,计算任务的内存分配时请注意此机制占用的内存空间
1.4.2追加写
当调用 OBSFileSystem 的 append 方法时将获取 FSDataOutputStream,通过该流追加写数据到 OBS 中,其依赖于 OBS 服务的追加写特性:
(1)通过流 write 数据时当达到缓存阈值 fs.obs.multipart.size 时将立刻写入数据到 OBS;
(2)OBS 的追加写特性不支持 “并发 range 追加写”,所以其失去了 “并发 range 写” 的优势,相对覆盖写性能将会有所下降;
(3)OBS 的追加写特性在频繁小数据追加写的场景其性能表现并不是很好
1.4.3 flush/hflush/hsync/sync
OBSFileSystem 的 create 或是 append 相关方法将返回 FSDataOutputStream,其实现了 flush/hflush/hsync/sync 等相关方法。
文件桶场景:
对象桶场景:
注意:hadoop-obs 46 版本才开始支持 fs.obs.outputstream.hflush.policy 策略,之前的版本实现机制等同于 fs.obs.outputstream.hflush.policy=Sync 的行为。
1.4.4 截断
OBSFileSystem 真正实现了 FileSystem 定义的截断接口 truncate,其依赖于 OBS 文件桶的截断特性。
(1)此接口将可以很好的支撑 flink 的 StreamingFileSink 的 exactly once 场景或是其他场景
(2)普通对象桶不具备截断特性;
1.4.5 读相关流程
当调用 OBSFileSystem 的 open 相关方法时将获取 FSDataInputStream,通过该流读取 OBS 中的数据。此流程总的实现思路是通过 obs 的 “range 读取” 特性进行实现,相关配置项如下:
配置项 |
默认值 |
含义 |
fs. obs.readahead policy |
primary |
读策略,取值范围 |
fs.obs.readahead. range |
1024 *1024字节 |
primary和 advance策略通用参数 |
fs.obs.readahead nax. nunber |
4 |
当fs.obs. readahead policy为advance时并发预 |
附 OBS range 读:当读取一个较大的文件时例如 1000MB,可以将其分为 0-100MB,100MB-200MB。。。10 个段并发读取以提升性能。https://support.huaweicloud.cn/sdk-java-devg-obs/obs_21_0703.html
实践建议:
(1)对于需要顺序读取文件的场景:例如 hdfs 命令下载文件,DistCp,sql 查询文本文件
• 在 primary 策略下:可以大幅度提高 fs.obs.readahead.range 的值(默认 1MB),例如可以设置为 100MB
例如 hadoop fs -Dfs.obs.readahead.range=104857600 -get obs://obs-bucket/xxx
• 在 advance 策略下:可以适度提高 fs.obs.readahead.range 和 fs.obs.readahead.max.number 的值或是保持默认值不变
(2)对于大量随机访问的场景:例如 orc 或 parquet 文件读取
在 primary 策略和 advance 策略下均保持默认值即可,或是针对你的场景进行调优测试。
1.5 list 相关流程
因为对象存储的特点,其逻辑模型是 KV 模型,因此其 list 操作是耗时的,其每次最多只能返回 1000 条数据,类似分页查询。因此在超大目录场景,OBSFileSystem 中的 listXXX 接口其性能是相对低的,因为其要发起多次 list 请求才能获取完整的列表。
并行文件桶场景下 OBSFileSystem 对于 list 的优化:
1. 根据目录结构尝试并发 list。
2. 例如当要列举 A 目录时,A 目录下有 B,C,D 目录,将会并发列举 B,C,D 目录以提升列举性能。
实践建议:
1. 对于超大目录的 list 或是 getContentSummary(即 hdfs du 命令):
(1)不要在前台列举或是 du 一个超大目录
(2)可以精确到某一个分区目录以避免超大目录场景下前台进行列举或是 du 操作时出现的长时间等待
1.6. 删除相关流程
目录删除操作在 OBSFileSystem 中不是 O (1) 操作,其实现分为两个步骤:
1. 先递归列举出目录下的所有文件
2. 利用对象存储的批量删除特性将其删除,批量删除的最大条数 1000,对于文件桶必须先删除目录下的文件才能删除父目录
hadoop-obs 的快速删除机制:即将删除操作转为 rename 操作,rename 到指定目录,目的是利用文件桶 rename 的高效性解决删除性能
实践建议:
1. 对于超大目录的删除:建议可以采用 OBS 服务的生命周期特性,通过 OBS 后台任务进行删除。
2. 快速删除机制:开启后需要配合 OBS 服务的生命周期特性,定期删除 fs.obs.trash.dir 目录中的数据
1.7rename 相关流程
1.8垃圾回收机制
在大数据应用场景中,往往存在防止数据误删除的诉求,通过 OBSFileSystem 的垃圾回收机制实现。
1. 在相关组件的 core-site.xml 文件中配置如下内容:
<property>
<name>fs.trash.interval</name>
<value>1440</value>
<description>垃圾回收机制开关,设置为大于0 的值即可</description>
</property>
2. 配置 OBS 服务的生命周期策略:垃圾目录中的文件无法自动清除,需通过 OBS 生命周期策略进行定期清除
3. 场景:
(1)hdfs 命令:
hadoop fs -rm obs://obs-bucket/test.txt;
会将 test 目录转移到 obs://obs-bucket/user/${username}/.Trash/Current 垃圾目录下
(2)hive 语句:
drop table obstable;
如果 obstable 是一张内表,会将 obstable 表对应的目录转移到 obs://obs-bucket/user/${username}/.Trash/Current 垃圾目录下
1.9日志机制
1.hadoop-obs 项目对应的 jar 包放置于 hadoop,hive,spark 等组件的目录下,受这些组件的日志机制控制;例如对于 hadoop 组件,在 ${HADOOP_HOME}/etc/hadoop/log4j.properties 文件中增加如下配置项以避免产生大量 info 级别的日志:
log4j.logger.com.obs=ERROR或是WARN
log4j.logger.org.apache.hadoop.fs.obs=INFO
2. 关于 warn 级别的 404 状态码:OBSFileSystem 在实现一些 FileSystem 的接口时为了语义的准确实现,在一些流程中会去探测文件是否存在,例如在实现 create 接口时会先获取文件的状态用以判断是文件还是目录,当为目录时则抛出异常,当为文件或是文件不存在时则正常创建文件,在此过程中会打印 warn 级别的带 404 状态码的日志(当日志级别调整为 info 或是 warn 时),此 warn 级别的日志属于正常现象。
1.10 重试机制
1. 访问 OBS 服务时可能会因为网络短暂抖动,服务突发故障,服务突发流控等瞬时故障导致访问失败,hadoop-obs 为了应对上述瞬时故障进行了必要的重试机制;
注:对于 OBS 服务处于长期故障状态重试机制是无力解决的
2. 重试策略:采取退让重试策略,即随着失败次数的增加重试间隔梯次增加
1.hadoop-obs的通用重试策略:
fs.obs.retry.maxtime:默认值180000ms,控制最大重试时间,重试间隔为max(fs.obs.retry.sleep.basetime*2的重试次数次方,fs.obs.retry.sleep.maxtime)
fs.obs.retry.sleep.basetime:默认值50ms,重试间隔的基数
fs.obs.retry.sleep.maxtime:默认值30000ms,重试间隔最大等待时间
2.hadoop-obs的流控重试策略:您可视您的业务情况独立配置
fs.obs.retry.qos.maxtime:默认值180000ms
fs.obs.retry.qos.sleep.basetime:默认值1000ms
fs.obs.retry.qos.sleep.maxtime:默认值30000ms
3.什么情况下会进行重试:
(1)尚未与obs服务建立连接或是IO中断,例如ConnectException,SocketTimeoutException等
(2)obs服务返回5xx:obs服务指示服务状态不正常
注:
(1)50.1版本开始才实现了独立的流控重试策略
(2)50.1版本开始写入流程才被施加重试机制
1.11 flink-obs 原理和实践建议(待完善)
1.11.1 大数据各组件优化
1.12 其他
1.12.1 OBS 带宽评估
在基于 OBS 的大数据存算分离解决方案中 OBS 侧 QOS(主要是读写带宽)的评估没有一个准确的计算公式,也因业务场景的复杂性导致难有一个一以贯之的公式。根据经验和理论的沉淀现阶段能够采用的 OBS QOS 评估方法如下:
算法一:根据 CPU 核数估算
此算法的依据是现网观察后的经验估算。
算法二:根据 POC 估算
此算法的依据是根据客户在 POC 测试时的真实业务场景观测到的 OBS 侧的实际带宽消耗峰值,然后依据计算集群的规模进行推算。
例如:POC 时搭建了 10 个计算节点,对 OBS 的读带宽需求峰值能达到 200Gb,写带宽需求峰值能达到 15Gb;
商用时需要搭建 120 个计算节点,OBS 的读带宽 = 200Gb/8*(120/10)=300GB; OBS 的读带宽 = 15Gb/8*(120/10)=22.5GB;
1.12.2 HDFS-OBS 映射
通过 HDFS 地址映射到 OBS 地址的方式,支持将 HDFS 中的数据迁移到 OBS 后,不需要变动业务逻辑中的数据地址,即可完成数据访问。
https://support.huaweicloud.cn/usermanual-mrs/mrs_01_0769.html
1.12.3 附:hadoop-obs 约束与限制
hadoop-obs 不支持以下 HDFS 语义:
• Lease
• Symbolic link operations
• Proxy users
• File concat
• File checksum
• File replication factor
• Extended Attributes(XAttrs) operations
• Snapshot operations
• Storage policy
• Quota
• POSIX ACL
• Delegation token operations
1.12.4 附:hadoop-obs 常见问题
0. 大数据场景强烈建议使用并行文件系统,即文件桶
1.hadoop-obs 性能基准测试
可以通过开源的 DFSIO 和 NNbench 基准测试工具进行大数据场景的性能基准测试
注:OBS 服务是基于 HDD 存储介质,请不要和基于 ssd 的 HDFS 服务进行性能对比
2.OBS 服务流控问题
(1)每个 region 可以独立设置租户级别和桶级别的流控阈值
(2)OBS 服务流控相关阈值:主要包含读写带宽 Gb/s,读写 TPS,并发连接数三个阈值
(3)流控准则:
当达到带宽 / TPS 阈值时 HTTP 请求依然会成功返回 200 状态码,但访问时延会增大;
当达到并发连接数阈值时 OBS 服务将拒绝访问返 503/GetQosTokenException
3.hadoop-obs 权限问题
通过 hadoop-obs 访问 OBS 时需要 aksk / 临时 aksk 才能访问 OBS 服务,OBSFileSystem 支持如下几种方式获取 aksk:(优先级由高到低排序)
• (1)通过 core-site.xml 的 fs.obs.access.key 和 fs.obs.secret.key 和 fs.obs.session.token 配置项获取。 其支持 hadoop 的 CredentialProvider 机制,即通过 CredentialProvider 机制对 aksk 进行保护,避免 aksk 的明文暴露
• (2)从 provider 中获取:自定义 aksk 提供器,通过 fs.obs.security.provider 配置项进行配置。 provider 实现需要继承 com.obs.services.IObsCredentialsProvider 接口,目前 hadoop-obs 内置的 provider 如下: com.obs.services.EnvironmentVariableObsCredentialsProvider:从环境变量里寻找 aksk,需要在环境变量中定义 OBS_ACCESS_KEY_ID 和 OBS_SECRET_ACCESS_KEY 分别代表永久的 AK 和 SK
• com.obs.services.EcsObsCredentialsProvider:从 ECS 元数据中自动获取临时 aksk 并进行定期自动刷新 com.obs.services.OBSCredentialsProviderChain:以链式的形式依次从环境变量,ECS 服务器上进行搜索以获取对应的访问密钥,且会以第一组成功获取到的访问密钥访问 obs 也可以自定义 provider 实现完成符合您架构和安全要求的实现,例如 MRS 服务提供了自己的 provider 实现
4. 写入操作缓存盘注意事项
当通过 hadoop-obs 写数据到 obs 时,其通过缓存机制提升写入性能,当缓存介质 fs.obs.fast.upload.buffer 设置为 disk 时(默认),可以通过 fs.obs.buffer.dir 配置项设置缓存目录(默认与 hadoop.tmp.dir 相同目录),可以设置多目录以逗号分隔;建议使用高性能存储介质(例如 SSD 盘)承载,且当集群中有大量并行任务时,确保缓存盘的空间足够(可以配置多个目录)
5. 读取操作实践建议:
(1)对于需要顺序读取文件的场景:例如 hdfs 命令下载文件,DistCp,sql 查询文本文件
o 在 primary 策略下:可以大幅度提高 fs.obs.readahead.range 的值(默认 1MB),例如可以设置为 100MB
例如 hadoop fs -Dfs.obs.readahead.range=104857600 -get obs://obs-bucket/xxx
o 在 advance 策略下:可以适度提高 fs.obs.readahead.range 和 fs.obs.readahead.max.number 的值或是保持默认值不变
(2)对于大量随机访问的场景:例如 orc 或 parquet 文件读取
在 primary 策略和 advance 策略下均保持默认值即可,或是针对你的场景进行调优测试。
配置项 |
默认值 |
含义 |
fs. obs.readahead policy |
primary |
读策略,取值范围 |
fs.obs.readahead. range |
1024 *1024字节 |
primary和 advance策略通用参数 |
fs.obs.readahead nax. nunber |
4 |
当fs.obs. readahead policy为advance时并发预 |
6. 快速删除特性实践建议
因为 hadoop-obs 的删除操作不是 O (1) 操作,其操作耗时和目录大小成正比例,即随着目录结构的增大其操作耗时将持续增长;如果您的应用场景存在频繁的删除操作,且删除的是超大目录,建议可以开启快速删除特性。相关配置项:
注:文件桶才支持快速删除特性,普通对象桶不支持,因为快速删除是利用文件桶的 rename 性能优势实现的
注:快速删除开启后需要配合 OBS 服务的生命周期特性,定期删除 fs.obs.trash.dir 目录中的数据
7.OBS 服务监控
通过华为云的云监控服务 CES,其是华为云资源的监控平台,提供了实时监控、及时告警、资源分组、站点监控等能力。
8. 问题排查
通过客户端日志和服务端日志进行问题排查,通常以客户端日志为问题排查的优先手段。
(1)客户端日志: OBS 服务两层返回码用于指示访问状态: 状态码:符合 HTTP 规范的 HTTP 状态码,例如 2xx,4xx,5xx 错误码:在状态码之下又细分了错误码,例如 403 状态码 / InvalidAccessKeyId 错误码表示 注:错误码描述 https://support.huaweicloud.cn/api-obs/obs_04_0115.html
(2)服务端日志:开启桶日志功能,OBS 会自动对这个桶的访问请求记录日志,并生成日志文件写入用户指定的桶中,可用于进行请求分析或日志审计 6. 问题反馈渠道 华为云工单系统
9. 跨云访问 obs 问题(待完善)
附:hadoop-obs 完整配置项
见 https://clouddevops.huawei.cn/domains/2301/wiki/8/WIKI2021080300343
13.%2 附:存算分离解决方案
- 点赞
- 收藏
- 关注作者
评论(0)