NWNU-Sun | 技术沉思录

代码是诗,bug是谜

   ::  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
  74 随笔 :: 49 文章 :: 6 评论 :: 40513 阅读

背景

​ HDFS通过把文件系统元数据全部加载到数据节点Namenode内存中,给客户端提供了低延迟的元数据访问。

图片

​ 由于元数据需要全部加载到内存,所以一个HDFS集群能支持的最大文件数,受Java堆内存的限制,上限大概是4亿~5亿个文件。所以HDFS适合大量大文件[几百兆字节(MB)以上]的集群,如果集群中有非常多的小文件,HDFS的元数据访问性能会受到影响。虽然可以通过各种Federation技术来扩展集群的节点规模,但单个HDFS集群仍然没法很好地解决小文件的限制。

什么是Ozone?

官方:Documentation for Apache Ozone

Ozone是一个大数据场景分布式存储,支持百亿到千亿级对象和文件。Ozone提供兼容S3 的对象功能,和兼容Hadoop File System(HCFS)的文件功能,同时通过CSI驱动接入Kubernets生态。Ozone定位于混合云场景存储支持,是面向数据湖的下一代大数据存储系统

  • 支持S3协议以及HDFS RPC协议
  • 专门为Hadoop设计的可扩展的分布式对象存储系统,具有易扩展、冗余存储的特点
  • Hive、Spark、Yarn/MR 的应用无需修改任何代码就可以运行
  • 可以通过命令行直接使用也有java客户端接口,而且接口支持RPC和REST

相比HDFS,Ozone调整:

  • 元数据存储:拆分NameNode,引入第三方存储。将NameNode元数据管理功能拆分成OM(Ozone Manager,用于存储文件的元数据)和SCM(Storage Container Manager,用于存储Container的元数据)。另外,元数据不再是all in memory的,我们引入了RocksDB替代原先的内存存储。通过引入持久化和元数据管理的分层,进而提升了原数据的上限。
  • 增加Container抽象:引入Container作为一组block的抽象逻辑,心跳汇报以Container为单位,降低汇报量,也减少SCM的元数据存储量。
  • 增加对象语义:支持文件协议和S3协议。Ozone的对象路径分为三层,分别为Volume、Bucket和Object (key)。如果需要访问某个Object,可以通过OM地址,找到对应的volume、对应的bucket,再取到对应的key进行访问(http://hostname/volume/bucket/key)。

基本概念

1)Ozone的对象层次

图片

2)概念集合

  • Volume【卷】
    • 只有管理员能够创建、删除,类似账号的概念,一般给某个团队或者组织创建一个Volume
    • Ozone的namespace由多个volume组成
    • volume及相关的元数据可以用过shard的方式水平扩展
  • Bucket【存储桶】
    • Ozone中的最顶层容器,有唯一标识
    • 类似于目录的概念,但是只有一层
    • Bucket下存放对象
  • Object【对象】
    • 基本数据单元,每个 Object 都有唯一的键(Key),通过键可以唯一标识一个 Object
    • Object 可以是用户上传的文件、数据块或其他类似数据。
    • 一个Bucket可以包含几十亿个object
  • Key【键】
    • 唯一标识Object的字符串或者字节数组
    • 由Bucket和Object名称组成
  • SCM【storage Container Manager】
    • Ozone 存储系统的核心组件之一,负责管理物理存储介质(如磁盘)上的存储容器(Storage Container)
    • SCM 负责分配和监控存储容器的使用,跟踪对象的位置、副本和版本信息等。
  • ACLS【访问控制列表】
    • 帮助管理存储资源、限制用户和群组的权限,防止数据泄露和滥用
      • ACLS:授予用户对于Object的权限
      • BCLS:控制用户或者群组对于Bucket的读、写、执行等权限
      • RBAC:支持基于角色的访问控制
    • 支持通过Ranger管理权限

技术架构

1)架构1

图片

Ozone技术构架分为三个部分:

  • Ozone Manager,统一的元数据管理
  • Storage Container Manager,数据块分配和数据节点管理
  • Datanode,数据节点,数据的最终存放处

​ 类比HDFS的构架,可以看到原来的Namenode的功能,现在由Ozone Manager和Storage Container Manage分别进行管理。对象元数据空间和数据分布分开管理,有利于两者的独立按需扩展,避免之前Namenode单节点的压力。

​ HDFS 中的 NameNode HA 需要依赖 ZooKeeper 作为协调和控制中心,来实现集群节点间的状态协调、领导者选举等功能。相比之下,Ozone 的设计则更加简单和轻量级,将对象元数据和数据存储分开,去除了对 ZooKeeper 的依赖,从而提高了 Ozone 的可扩展性和性能。

2)架构2

1575439845208

Ozone Manager
  • Ozone Manager是管理Ozone的命名空间,提供所有的Volume(卷)、Bucket(存储桶)和Key(键)的新建、更新和删除操作。它存储了Ozone的元数据信息,这些元数据信息包括Volumes、Buckets和Keys,底层通过RATIS(实现了RAFT协议)扩展元数据的副本数来实现元数据的HA。

  • Ozone Manager只和Ozone Client和Storage Container Manager通信,并不直接和Datanode通信。Ozone Manager将命名空间的元数据存储在RocksDB中,避免了HDFS中需要将所有元数据都保留在内存,从而经常会受到小文件问题的困扰。

  • RocksDB是Facebook基于LevelDB开发的一个本地Key-Value存储引擎,尤其对于SSD有很多的优化和改进,提供高吞吐量的读写操作。

    Storage Container Manager(SCM)
  • 类似HDFS中的Block Manager,管理Container,写Pipelines和Datanode,为Ozone Manager提供Block和Container的操作和信息。

  • SCM也监听Datanode发来的心跳信息,作为Datanode Manager的角色,保证和维护集群所需的数据冗余级别。

  • SCM和Ozone Client之间没有通信。

Block、Container和Pipeline

​ 1) Datanode Container内部结构

图片

  • Block是数据块对象,真实存储用户的数据,Container中的一条记录是一个Block的信息,每个Block在Container里面有且仅有一条记录。
  • Ozone中,数据是以Container为粒度进行副本复制的。
  • SCM中目前支持2种Pipeline方式:
    • 单Datanode节点组成的Standalone读Pipeline
    • 三个Datanode节点组成的Apache RATIS写Pipeline。
  • Container有2种状态:OPEN和CLOSED,当一个Container是OPEN状态时,可以往里面写入新的Block。当一个Container达到它预定的大小时(默认5GB),它从OPEN状态转换成CLOSED状态。一个Closed Container是不可修改的。

2)RATIS写Pipeline

图片

Ozone使用Popeline的方式写入Container,是复制的数据流,基于Apache Ratis的数据复制。

HDFS数据复制图:

image-20230908164453203

DataNode

​ Datanode是Ozone的数据节点,以Container为基本存储单元维护每个Container内部的数据映射关系,并定时向SCM发送心跳节点、汇报节点的信息、管理Container的信息和Pipeline的信息。当一个Container大小超过预定大小的90%时或者写操作失败时,Datanode会发送Container Close命令给SCM,把Container的状态从OPEN转变成CLOSED。或者当Pipeline出错时,发送Pipeline Close命令给SCM,把Pipeline从OPEN状态转为CLOSED状态。

Recon

​ Recon 充当 Ozone 的管理和监视控制台。它提供了 Ozone 的鸟瞰图,并通过基于 REST 的 API 和丰富的网页用户界面(Web UI)展示了集群的当前状态,从而帮助用户解决任何问题。

img

​ 在较高的层次上,Recon 收集和汇总来自 Ozone Manager(OM)、Storage Container Manager(SCM)和数据节点(DN)的元数据,并充当中央管理和监视控制台。Ozone 管理员可以使用 Recon 查询系统的当前状态,而不会使 OM 或 SCM 过载。

Recon 维护多个数据库,以支持批处理,更快的查询和持久化聚合信息。它维护 OM DB 和 SCM DB 的本地副本,以及用于持久存储聚合信息的 SQL 数据库。

Recon 还与 Prometheus 集成,提供一个 HTTP 端点来查询 Prometheus 的 Ozone 指标,并在网页用户界面(Web UI)中显示一些关键时间点的指标

分层结构

​ Ozone分层结构使得Ozone Manager、Storage Container Manager和Datanode可按需独立扩展。对于Ozone提供的语义,也是分层管理的。

图片

对象写入

当Ozone Client(客户端)需要创建并且写入一个新对象时,客户端需要和Ozone Manager和Datanode直接打交道

图片

1)Ozone客户端链接Ozone Manager,提供需要创建的对象信息,包括对象的名称、数据的大小、备份数和其他用户自定义的对象属性。

2)Ozone Manager收到Ozone客户端的请求后,和SCM通信,请求SCM寻找能够容纳数据的处于OPEN状态的Container,然后在找到的Container中分配足够数量的Block。

3)SCM将新对象数据将要写入的Container、Block和Container所在的Pipeline的三个Datanode的信息列表返回给Ozone Manager。

4)Ozone Manager将收到SCM返回的信息,返回给客户端。

5)客户端得到Datanode列表信息之后,和第一个Datanode(Raft Pipeline Leader)建立通信,将数据写入Datanode的Container。

6)客户端完成数据写入后,连接Ozone Manager,确认数据已经更新完成,Ozone Manager更新对象的元数据,记录对象数据所在的Container和Block的信息。至此,新的对象创建完成。之后,其他的客户端就可以访问这个对象了。

对象读取

类似于HDFS文件读取

图片

1)Ozone Client(客户端)和Ozone Manager通信,制定要读取的对象Key (/volume/bucket/key)。

2)Ozone Manager在元数据库中查找对应的对象,返回对象数据所在的Container和Block信息,包括Container所在的Datanode列表信息给Ozone Client(客户端)。

3)Ozone支持Data locality。如果Ozone Client(客户端)运行在集群中的某个节点上,Ozone Manager会返回按照网络拓扑距离排序的Datanode列表。Ozone Client(客户端)可以选择第一个Datanode节点(本地节点),也是离Client(客户端)最近的节点来读取数据,节省数据读取的网络传输时间。

删除数据

img

image-20231014231252046

OZONE安全

1)Ranger

Apache Ranger 从2.0版本开始支持Ozone鉴权。但由于在2.0中存在一些bug,更推荐使用Apache Ranger 2.1及以后版本。

2)kerberos

Ozone 集群的安全依赖于 Kerberos。过去 HDFS 支持在隔离的安全网络中运行,因此可以不进行安全化的集群部署。

Ozone 在这方面与 HDFS 保持一致,但不久之后将 默认启用安全机制

K8S集成

K8S通过标准的CSI实现容器的持久化,目前很多的存储都有现成的CSI,如NFS,GFS,CEPH等。但是HDFS目前为止没有官方的CSI实现,Apache基于HDFS封装的新的分布式文件系统Ozone可以有HDFS文件系统的属性,同时提供了官方CSI

image-20230908170401835

部署

image-20230908172327315

非HA部署

配置:ozone/hadoop-hdds/common/src/main/resources/ozone-default.xml at master · apache/ozone · GitHub

块删除:https://developer.baidu.com/article/detail.html?id=1977478

1)组件布局

主机 角色
192.168.2.75 SCM,DN
192.168.2.77 OM,DN
192.168.2.46 DN

2)下载安装包并解压

cd /opt
wget https://dlcdn.apache.org/ozone/1.3.0/ozone-1.3.0.tar.gz
tar  -zxvf ozone-1.3.0.tar.gz

3)设置JAVA_HOME

vi ozone-env.sh
export JAVA_HOME=/srv/dstore/1.0.0.0/jdk1.8.0_211

4)设置配置文件

  • SCM服务,不需要依赖其它服务,直接自身启动起来即可,为最底层服务。
  • OM服务,需要依赖SCM服务,要配置SCM的通信地址。
  • Datanode节点服务,需要依赖SCM,OM服务,二者通信地址都得配上
vi ozone-site.xml

<configuration>
    <property>
        <name>ozone.metadata.dirs</name>
        <value>/srv/data01/ozone/metadata</value>
    </property>

    <property>
        <name>ozone.om.http-address</name>
        <value>sun77:19874</value>
    </property>
    <property>
        <name>ozone.om.https-address</name>
        <value>sun77:19875</value>
    </property>
    <property>
        <name>ozone.om.address</name>
        <value>sun77</value>
    </property>
    <property>
        <name>ozone.om.ratis.port</name>
        <value>19873</value>
    </property>
  <property>
    <name>ozone.om.db.dirs</name>
    <value>/srv/data01/ozone/om</value>
  </property>
  <property>
    <name>ozone.om.ratis.storage.dir</name>
    <value>/srv/data01/ozone/om/ratis</value>
  </property>
    <property>
    <name>ozone.om.ratis.snapshot.dir</name>
    <value>/srv/data01/ozone/om/ratis</value>
  </property>
 
 
    <property>
    	<name>ozone.scm.http-address</name>
    	<value>sun75:19876</value>
    </property>
    <property>
    	<name>ozone.scm.https-address</name>
    	<value>sun75:19877</value>
    </property>
    <property>
        <name>ozone.scm.client.address</name>
        <value>sun75:19860</value>
    </property>
    <property>
        <name>ozone.scm.ratis.port</name>
        <value>19894</value>
    </property>
    <property>
    	<name>ozone.scm.datanode.port</name>
    	<value>19861</value>
    </property>
    <property>
    	<name>ozone.scm.block.client.port</name>
    	<value>19863</value>
    </property>
    <property>
        <name>ozone.scm.names</name>
        <value>sun75</value>
    </property>
  <property>
    <name>ozone.scm.db.dirs</name>
    <value>/srv/data01/ozone/scm</value>
  </property>
  <property>
    <name>ozone.scm.ha.ratis.storage.dir</name>
    <value>/srv/data01/ozone/scm/ratis</value>
  </property>
  <property>
    <name>ozone.scm.ha.ratis.snapshot.dir</name>
    <value>/srv/data01/ozone/scm/ratis</value>
  </property>
 
 
  <property>
  	<name>hdds.rest.http-address</name>
  	<value>0.0.0.0:19880</value>
  </property>
  <property>
  	<name>hdds.datanode.http-address</name>
  	<value>0.0.0.0:19882</value>
  </property>
  <property>
  	<name>hdds.datanode.https-address</name>
  	<value>0.0.0.0:19883</value>
  </property>
  <property>
  	<name>dfs.container.ratis.server.port</name>
  	<value>19856</value>
  </property>
  <property>
  	<name>dfs.container.ratis.admin.port</name>
  	<value>19857</value>
  </property>
  <property>
  	<name>dfs.container.ratis.ipc</name>
  	<value>19858</value>
  </property>
  <property>
  	<name>dfs.container.ipc</name>
  	<value>19859</value>
  </property>
  <property>
    <name>hdds.metadata.dir</name>
    <value>/srv/data01/ozone/datanode</value>
  </property>
  <property>
    <name>hdds.datanode.dir</name>
    <value>/srv/data01/ozone/datanode</value>
  </property>
  <property>
    <name>dfs.container.ratis.datanode.storage.dir</name>
    <value>/srv/data01/ozone/datanode/ratis</value>
  </property>
	<property>
    	<name>ozone.recon.http-address</name>
    	<value>sun75:19888</value>
    </property>
    <property>
    	<name>ozone.recon.https-address</name>
    	<value>sun75:19889</value>
    </property>
    <property>
    	<name>ozone.recon.address</name>
    	<value>sun75:19891</value>
    </property>
    <property>
    	<name>ozone.recon.datanode.address</name>
    	<value>sun75:19891</value>
    </property>
  <property>
    <name>ozone.recon.db.dir</name>
    <value>/srv/data01/ozone/recon</value>
  </property>
  <property>
    <name>ozone.recon.om.db.dir</name>
    <value>/srv/data01/ozone/recon/om</value>
  </property>
  <property>
    <name>ozone.recon.scm.db.dirs</name>
    <value>/srv/data01/ozone/recon/scm</value>
  </property>
 
 
  <property>
	<name>ozone.s3g.http-address</name>
	<value>sun75:19878</value>
  </property>
 
</configuration>

5)启动集群

在启动 Ozone 集群之前,需要依次初始化 SCM 和 OM。

ozone scm --init

这条命令会使 SCM 创建集群 ID 并初始化它的状态。 init 命令和 Namenode 的 format 命令类似,只需要执行一次,SCM 就可以在磁盘上准备好正常运行所需的数据结构。

ozone --daemon start scm

SCM 启动之后,我们就可以创建对象存储空间,命令如下:

ozone om --init

OM 初始化完成之后,就可以启动 OM 服务了:

ozone --daemon start om

此时 Ozone 的命名服务 OM 和 块服务 SCM 都已运行。
注意: 如果 SCM 未启动,om --init 命令会失败,同样,如果磁盘上的元数据缺失,SCM 也无法启动,所以请确保 scm --initom --init 两条命令都成功执行了。

接下来启动 Datanode,在每个 Datanode 上运行下面的命令:

ozone --daemon start datanode

现在 SCM、OM 和所有的 Datanode 都已启动并运行。

6)访问webui

OM: 192.168.2.77:9874

image-20230911103028274

SCM: 192.168.2.75:9876

image-20230911103117556

HA部署

Ozone Manager 的高可用

一个 Ozone Manager 使用 RocksDB 在本地持久化元数据(卷、桶和键)。 Ozone Manager 的高可用版本在功能上完全一致,只是所有的数据都借助 RAFT 共识算法复制到 Ozone Manager 的 follower 实例上。

OM HA

客户端连接到 Ozone Manager 上,而 Ozone Manager 负责处理请求并且安排复制。当请求复制到所有的 follower 上后,leader 就可以给客户端回包了。

SCM高可用

当原始 SCM 失效时, 新的 SCM 不能被引导并添加到 HA 节点中。

尚未支持从非 HA 安全集群升级到 HA 安全集群。

⚠️ 注意 ⚠️

SCM HA 目前仅支持新初始化的集群。

SCM HA 必须在 Ozone 服务首次启动前开启。

角色分配

主机 角色
xxx33 SCM、OM、DataNode、S3g、Recon
xxx80 SCM、DataNode
xxx72 OM、DataNode

配置ozone-site.xml

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

<configuration>
    <property>
        <name>ozone.metadata.dirs</name>
        <value>/srv/data01/ozone/metadata</value>
    </property>
    <!--SCM HA开启-->
    <property>
     <name>ozone.scm.ratis.enable</name>
     <value>true</value>
    </property>
     <property>
       <name>ozone.scm.service.ids</name>
       <value>cluster</value>
    </property>
    
    <property>
     <name>ozone.scm.nodes.cluster</name>
     <value>scm1,scm2</value>
    </property>
        
    <property>
       <name>ozone.scm.address.cluster.scm1</name>
       <value>xxx33</value>
    </property>
    <property>
       <name>ozone.scm.address.cluster.scm2</name>
       <value>xxx80</value>
    </property>

      <property>
        <name>ozone.scm.primordial.node.id</name>
        <value>scm1</value>
      </property>
    
    <property>
      <config>ozone.security.enable</config>
      <value>true</value>
    </property>
    
    <property>
      <config>hdds.grpc.tls.enabled</config>
      <value>true</value>
    </property>

  <!--OM HA开启-->
    <property>
     <name>ozone.om.ratis.enable</name>
     <value>true</value>
    </property>
    
    <property>
     <name>ozone.om.service.ids</name>
     <value>cluster</value>
    </property>

  <property>
   <name>ozone.om.nodes.cluster</name>
   <value>om1,om2</value>
  </property>
  
  <property>
     <name>ozone.om.address.cluster.om1</name>
     <value>xxx33</value>
  </property>
  <property>
     <name>ozone.om.address.cluster.om2</name>
     <value>xxx72</value>
  </property>


    <property>
        <name>ozone.om.http-address</name>
        <value>0.0.0.0:19874</value>
    </property>
    
    <property>
        <name>ozone.om.https-address</name>
        <value>0.0.0.0:19875</value>
    </property>
    
      <property>
        <name>ozone.om.address</name>
        <value>0.0.0.0:9862</value>
      </property>
    
    <property>
        <name>ozone.om.ratis.port</name>
        <value>19873</value>
    </property>
    
    <property>
      <name>ozone.om.db.dirs</name>
      <value>/srv/data01/ozone/om</value>
    </property>
    
    <property>
      <name>ozone.om.ratis.storage.dir</name>
      <value>/srv/data01/ozone/om/ratis</value>
    </property>
    
    <property>
      <name>ozone.om.ratis.snapshot.dir</name>
      <value>/srv/data01/ozone/om/ratis</value>
    </property>
 
 
    <property>
    	<name>ozone.scm.http-address</name>
    	<value>0.0.0.0:19876</value>
    </property>
    
    <property>
    	<name>ozone.scm.https-address</name>
    	<value>0.0.0.0:19877</value>
    </property>
    
    <property>
        <name>ozone.scm.client.address</name>
        <value>0.0.0.0:19860</value>
    </property>
    
    <property>
        <name>ozone.scm.ratis.port</name>
        <value>19894</value>
    </property>
    
    <property>
    	<name>ozone.scm.datanode.port</name>
    	<value>19861</value>
    </property>
    
    <property>
    	<name>ozone.scm.block.client.port</name>
    	<value>19863</value>
    </property>
    
    <property>
        <name>ozone.scm.names</name>
        <value>scm1.scm2</value>
    </property>
    
  <property>
    <name>ozone.scm.db.dirs</name>
    <value>/srv/data01/ozone/scm</value>
  </property>
  
  <property>
    <name>ozone.scm.ha.ratis.storage.dir</name>
    <value>/srv/data01/ozone/scm/ratis</value>
  </property>
  
  <property>
    <name>ozone.scm.ha.ratis.snapshot.dir</name>
    <value>/srv/data01/ozone/scm/ratis</value>
  </property>
 
 
  <property>
  	<name>hdds.rest.http-address</name>
  	<value>0.0.0.0:19880</value>
  </property>
  
  <property>
  	<name>hdds.datanode.http-address</name>
  	<value>0.0.0.0:19882</value>
  </property>
  
  <property>
  	<name>hdds.datanode.https-address</name>
  	<value>0.0.0.0:19883</value>
  </property>
  
  <property>
  	<name>dfs.container.ratis.server.port</name>
  	<value>19856</value>
  </property>
  
  <property>
  	<name>dfs.container.ratis.admin.port</name>
  	<value>19857</value>
  </property>
  
  <property>
  	<name>dfs.container.ratis.ipc</name>
  	<value>19858</value>
  </property>
  
  <property>
  	<name>dfs.container.ipc</name>
  	<value>19859</value>
  </property>
  
  <property>
    <name>hdds.metadata.dir</name>
    <value>/srv/data01/ozone/datanode</value>
  </property>
  
  <property>
    <name>hdds.datanode.dir</name>
    <value>/srv/data01/ozone/datanode</value>
  </property>
  
  <property>
    <name>dfs.container.ratis.datanode.storage.dir</name>
    <value>/srv/data01/ozone/datanode/ratis</value>
  </property>
 
 
 
	<property>
    	<name>ozone.recon.http-address</name>
    	<value>xxx33:19888</value>
    </property>
    
    <property>
    	<name>ozone.recon.https-address</name>
    	<value>xxx33:19889</value>
    </property>
    
    <property>
    	<name>ozone.recon.address</name>
    	<value>xxx33:19891</value>
    </property>
    
    <property>
    	<name>ozone.recon.datanode.address</name>
    	<value>xxx33:19891</value>
    </property>
    
    
  <property>
    <name>ozone.recon.db.dir</name>
    <value>/srv/data01/ozone/recon</value>
  </property>
  
  <property>
    <name>ozone.recon.om.db.dir</name>
    <value>/srv/data01/ozone/recon/om</value>
  </property>
  
  <property>
    <name>ozone.recon.scm.db.dirs</name>
    <value>/srv/data01/ozone/recon/scm</value>
  </property>
 
    <property>
    <name>ozone.s3g.default.bucket.layout</name>
    <value>OBJECT_STORE</value>
    <description>默认存储桶的布局</description>
  </property>
  <property>
    <name>ozone.s3g.volume.name</name>
    <value>s3v</value>
    <description>卷的名称</description>
  </property>

  <property>
    <name>ozone.s3g.http-address</name>
    <value>0.0.0.0:9878</value>
    <description>HTTP服务的地址和端口</description>
  </property>
  <property>
    <name>ozone.s3g.http-bind-host</name>
    <value>0.0.0.0</value>
    <description>HTTP服务绑定的主机地址</description>
  </property>
  <property>
    <name>ozone.s3g.http.enabled</name>
    <value>true</value>
    <description>是否启用HTTP服务</description>
  </property>
  <property>
    <name>ozone.s3g.https-address</name>
    <value></value>
    <description>HTTPS服务的地址和端口</description>
  </property>
  <property>
    <name>ozone.s3g.https-bind-host</name>
    <value></value>
    <description>HTTPS服务绑定的主机地址</description>
  </property>
  <property>
    <name>ozone.s3g.list-keys.shallow.enabled</name>
    <value>true</value>
    <description>是否启用浅层列出键(shallow list keys)功能</description>
  </property>
  <property>
    <name>ozone.s3g.secret.http.enabled</name>
    <value>false</value>
    <description>是否启用HTTP密钥(secret)认证</description>
  </property>
  <property>
    <name>ozone.s3g.secret.http.auth.type</name>
    <value>kerberos</value>
    <description>HTTP密钥认证的类型</description>
  </property>
  <property>
    <name>ozone.s3g.http.auth.type</name>
    <value>simple</value>
    <description>HTTP认证的类型</description>
  </property>
  <property>
    <name>ozone.s3g.client.buffer.size</name>
    <value>4KB</value>
    <description>客户端缓冲区的大小</description>
  </property>
  
  <property>
    <name>ozone.block.deleting.container.limit.per.interval</name>
    <value>20</value>
  </property>
  
  <property>
  <name>ozone.scm.container.size</name>
  <value>10GB</value>
</property>

<property>
  <name>ozone.scm.block.size</name>
  <value>256MB</value>
</property>

 <property>
    <name>ozone.block.deleting.service.interval</name>
    <value>1s</value>
  </property>
  
    <property>
    <name>ozone.scm.block.deletion.max.retry</name>
    <value>4090</value>
  </property>
  
    <property>
    <name>ozone.scm.chunk.size</name>
    <value>10MB</value>
  </property>
  
  <property>
    <name>ozone.server.default.replication</name>
    <value>1</value>
  </property>

  <property>
    <name>ozone.server.default.replication.type</name>
    <value>RATIS</value>
  </property>
   <property>
    <name>ozone.block.deleting.limit.per.task</name>
    <value>2000</value>
  </property>
    <property>
    <name>ozone.block.deleting.service.timeout</name>
    <value>400000ms</value>
  </property>
    <property>
    <name>ozone.block.deleting.service.workers</name>
    <value>10</value>
  </property>
</configuration>

启动方式

所有SCM节点执行

ozone scm --init
ozone scm --bootstrap
ozone --daemon start scm

所有OM节点执行(前提是SCM已经启动)

ozone om --init
ozone -daemon start om

所有节点启动

ozone --daemon start datanode

最后启动Recon、S3g

ozone --daemon start recon
ozone --daemon start s3g
S3G适配

Ozone中关于s3g的配置如下

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <property>
    <name>ozone.s3g.default.bucket.layout</name>
    <value>OBJECT_STORE</value>
    <description>默认存储桶的布局</description>
  </property>
  <property>
    <name>ozone.s3g.volume.name</name>
    <value>s3v</value>
    <description>卷的名称</description>
  </property>
  <property>
    <name>ozone.s3g.domain.name</name>
    <value></value>
    <description>指定Ozone S3网关的域名列表。如果有多个域名,则应以逗号分隔。这个参数仅在遵循虚拟主机样式模式时才需要</description>
  </property>
  <property>
    <name>ozone.s3g.http-address</name>
    <value>0.0.0.0:9878</value>
    <description>HTTP服务的地址和端口</description>
  </property>
  <property>
    <name>ozone.s3g.http-bind-host</name>
    <value>0.0.0.0</value>
    <description>HTTP服务绑定的主机地址</description>
  </property>
  <property>
    <name>ozone.s3g.http.enabled</name>
    <value>true</value>
    <description>是否启用HTTP服务</description>
  </property>
  <property>
    <name>ozone.s3g.https-address</name>
    <value></value>
    <description>HTTPS服务的地址和端口</description>
  </property>
  <property>
    <name>ozone.s3g.https-bind-host</name>
    <value></value>
    <description>HTTPS服务绑定的主机地址</description>
  </property>
  <property>
    <name>ozone.s3g.list-keys.shallow.enabled</name>
    <value>true</value>
    <description>是否启用浅层列出键(shallow list keys)功能</description>
  </property>
  <property>
    <name>ozone.s3g.secret.http.enabled</name>
    <value>false</value>
    <description>是否启用HTTP密钥(secret)认证</description>
  </property>
  <property>
    <name>ozone.s3g.secret.http.auth.type</name>
    <value>kerberos</value>
    <description>HTTP密钥认证的类型</description>
  </property>
  <property>
    <name>ozone.s3g.http.auth.type</name>
    <value>simple</value>
    <description>HTTP认证的类型</description>
  </property>
  <property>
    <name>ozone.s3g.client.buffer.size</name>
    <value>4KB</value>
    <description>客户端缓冲区的大小</description>
  </property>
  <!----------Kerberos相关---------->
  <property>
    <name>ozone.s3g.kerberos.keytab.file</name>
    <value>/etc/security/keytabs/s3g.keytab</value>
    <description>Kerberos密钥表文件的路径</description>
  </property>
  <property>
    <name>ozone.s3g.kerberos.principal</name>
    <value>s3g/_HOST@REALM</value>
    <description>Kerberos身份验证的主体(principal)</description>
  </property>
  <property>
    <name>ozone.s3g.http.auth.kerberos.principal</name>
    <value>HTTP/_HOST@REALM</value>
    <description>Kerberos身份验证的HTTP服务主体(principal)</description>
  </property>
  <property>
    <name>ozone.s3g.http.auth.kerberos.keytab</name>
    <value>/etc/security/keytabs/HTTP.keytab</value>
    <description>Kerberos身份验证的密钥表(keytab)文件路径</description>
  </property>
</configuration>

启动

ozone --daemon start s3g

使用jps可以查看到启了一个Gateway的进程,具体操作可以看下面的命令

基本命令

Ozone的对象存储使用方式和亚马逊的S3存储十分类似,也是基于Volume,Bucket,Key的存储模式。

所以在存储key文件对象前,我们需要建好Volume和Bucket。

首先是volume的创建

./ozone sh volume create /sunvolume --quota=1GB -u=sun # 创建一个卷路径为:/sunvolume 配额:1G 所有者为sun的卷

查看volume

[root@sun77 bin]# ./ozone sh volume list -u=sun
[ {
  "metadata" : { },
  "name" : "sunvolume",
  "admin" : "root",
  "owner" : "sun",
  "quotaInBytes" : 1073741824,
  "quotaInNamespace" : -1,
  "usedNamespace" : 0,
  "creationTime" : "2023-09-11T02:36:56.820Z",
  "modificationTime" : "2023-09-11T02:36:56.820Z",
  "acls" : [ {
    "type" : "USER",
    "name" : "sun",
    "aclScope" : "ACCESS",
    "aclList" : [ "ALL" ]
  } ],
  "refCount" : 0

创建bucket

ozone sh bucket create /sunvolume/sunbucket

查看bucket

[root@sun77 bin]# ./ozone sh bucket list /sunvolume/
[ {
  "metadata" : { },
  "volumeName" : "sunvolume",
  "name" : "sunbucket",
  "storageType" : "DISK",
  "versioning" : false,
  "usedBytes" : 0,
  "usedNamespace" : 0,
  "creationTime" : "2023-09-11T02:40:12.074Z",
  "modificationTime" : "2023-09-11T02:40:12.074Z",
  "quotaInBytes" : -1,
  "quotaInNamespace" : -1,
  "bucketLayout" : "LEGACY",
  "owner" : "root",
  "link" : false
} ]

key文件上传

ozone sh key put /sunvolume/sunbucket/test.txt test.txt # 首先得创建文件
测试
 <property>
    <name>ozone.scm.pipeline.creation.auto.factor.one</name>
    <value>true</value>
  </property>
s3客户端测试

启动s3g

ozone --daemon start s3g
 yum -y install epel-release
 yum install python-pip
 yum -y install s3cmd
cat >/root/.s3cfg<<EOF
[default]
access_key = E10OE6MVMMD8SQ9ELRUN
secret_key = aU8LST1vo9SMIENb08ONm3hJpx9ORJ8bW9SQ68rw
host_base = sun75:19878
host_bucket = sun75:19878/%(bucket)
use_https = False
EOF

access_key和secret_key是在本地创建S3用户时获得,host_base是S3服务所使用的ip地址(包括端口 号),host_bucket为S3用户下的一个bucket(可在配置之后再创建,但该字段不能为空)

列举所有 Buckets
s3cmd ls


创建 bucket,且 bucket 名称是唯一的,不能重复。
s3cmd mb s3://my-bucket-name


删除空 bucket
s3cmd rb s3://my-bucket-name


列举 Bucket 中的内容
s3cmd ls s3://my-bucket-name

上传 file.txt 到某个 bucket,
s3cmd put file.txt s3://my-bucket-name/file.txt

上传并将权限设置为所有人可读
s3cmd put --acl-public file.txt s3://my-bucket-name/file.txt

批量上传文件
s3cmd put ./* s3://my-bucket-name/

下载文件
s3cmd get s3://my-bucket-name/file.txt file.txt

批量下载
s3cmd get s3://my-bucket-name/* ./

删除文件
s3cmd del s3://my-bucket-name/file.txt

来获得对应的bucket所占用的空间大小
s3cmd du -H s3://my-bucket-name

设置S3 bucket的Public权限
s3cmd setacl s3://myexamplebucket.calvium.com/ --acl-public --recursive
aws cli测试

下载客户端安装包

wget https://link.zhihu.com/?target=https%3A//s3.amazonaws.com/aws-cli/awscli-bundle.zip
yum -y install unzip 
unzip awscli-bundle.zip

安装

[root@xxx33 awscli-bundle]# ./install
Unsupported Python version detected: Python 2.7
To continue using this installer you must use Python 3.7 or later.
For more information see the following blog post: https://aws.amazon.com/blogs/developer/announcing-end-of-support-for-python-2-7-in-aws-sdk-for-python-and-aws-cli-v1/

报错,不支持Python2.7,本机正好安装了Python3.10,所以可以带上Python路径

[root@xxx33 awscli-bundle]# /srv/dstore/1.0.0.0/base-env-centos/python/bin/python3.10   ./install -i /usr/local/aws -b /usr/local/bin/aws
Running cmd: /srv/dstore/1.0.0.0/base-env-centos/python/bin/python3.10 -m venv /usr/local/aws
Running cmd: /usr/local/aws/bin/python -m pip install --no-binary :all: --no-cache-dir --no-index --find-links file://. setuptools_scm-3.3.3.tar.gz
Running cmd: /usr/local/aws/bin/python -m pip install --no-binary :all: --no-cache-dir --no-index --find-links file://. wheel-0.33.6.tar.gz
Running cmd: /usr/local/aws/bin/python -m pip install --no-binary :all: --no-build-isolation --no-cache-dir --no-index  --find-links file:///root/awscli-bundle/packages awscli-1.30.0.tar.gz
You can now run: /usr/local/bin/aws --version

Note: AWS CLI version 2, the latest major version of the AWS CLI, is now stable and recommended for general use. For more information, see the AWS CLI version 2 installation instructions at: https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html
# 检查版本
[root@xxx33 awscli-bundle]# aws --version
aws-cli/1.30.0 Python/3.10.6 Linux/3.10.0-957.el7.x86_64 botocore/1.32.0

接下来开始配置访问端端点信息,可以配置环境变量或者修改配置

第一种方式,添加环境变量

如果s3g服务没启动安全模式(Kerberos),则设置任何秘钥都可以,如下

export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
export AWS_DEFAULT_REGION=us-west-2

第二种方式,修改配置文件

vi ~/.aws/credentials

[default]
aws_access_key_id = aasas
aws_secret_access_key = asas
aws_default_region = us-west-2

或者使用aws命令配置

aws configure

[root@xxx33 .aws]# aws configure
AWS Access Key ID [****************asas]: xxxxx
AWS Secret Access Key [****************asas]: xxxx
Default region name [None]:
Default output format [None]:
[root@xxx33 .aws]#

配置好后,开始测试

通过指定自定义的 –endpoint 选项,aws 命令行接口可以在 Ozone S3 上使用

aws s3api --endpoint http://localhost:9878 create-bucket --bucket buckettest
或者
aws s3 ls --endpoint http://localhost:9878 s3://buckettest
[root@xxx33 .aws]# aws s3api --endpoint http://192.168.2.177:9878 create-bucket --bucket buckettest
{
    "Location": "http://192.168.2.177:9878/buckettest"
}

aws命令配置 --endpoint

[root@xxx33 .aws]# aws configure set default.s3.endpoint_url http://192.168.2.177:9878
[root@xxx33 .aws]# cat ~/.aws/config
[default]
s3 =
    endpoint_url = http://192.168.2.177:9878
[root@xxx33 .aws]#

虽然配置了,但是测试报错,遗留问题

[root@xxx33 .aws]# aws s3 ls s3://buckettest

An error occurred (InvalidAccessKeyId) when calling the ListObjectsV2 operation: The AWS Access Key Id you provided does not exist in our records.
[root@xxx33 .aws]#
FS文件测试
# 创建文件夹
hdfs dfs -mkdir -p /sun/test1
# 查看
[root@sun46 ~]# hdfs dfs -ls o3fs://bucket.volume/sun
2023-09-20 17:27:37,187 INFO conf.Configuration: Removed undeclared tags:
Found 1 items
drwxrwxrwx   - root root          0 2023-09-20 17:26 o3fs://bucket.volume/sun/test1

# 上传文件
hdfs dfs -put test.txt  o3fs://bucket.volume/sun/test1

# 查看
[root@sun46 ~]# hdfs dfs -cat  test.txt  o3fs://bucket.volume/sun/test1/test.txt
2023-09-20 17:29:31,733 INFO conf.Configuration: Removed undeclared tags:
cat: `test.txt': No such file or directory
2023-09-20 17:29:32,687 INFO impl.MetricsConfig: loaded properties from hadoop-metrics2.properties
2023-09-20 17:29:32,744 INFO impl.MetricsSystemImpl: Scheduled Metric snapshot period at 10 second(s).
2023-09-20 17:29:32,744 INFO impl.MetricsSystemImpl: XceiverClientMetrics metrics system started
hello,world
Yarn测试

首先停止HDFS集群

修改原集群的配置

<property>
  <name>fs.AbstractFileSystem.o3fs.impl</name>
  <value>org.apache.hadoop.fs.ozone.OzFs</value>
</property>
<property>
  <name>fs.defaultFS</name>
  <value>o3fs://bucket.volume</value>
</property>
export HADOOP_CLASSPATH=/opt/ozone/share/ozone/lib/ozone-filesystem-hadoop3-*.jar:$HADOOP_CLASSPATH
ln -s /opt/ozone-1.3.0/etc/hadoop/ozone-site.xml  /srv/dstore/1.0.0.0/hdfs/etc/hadoop/

重启Yarn HA 集群

sbin/stop-yarn.sh
sbin/start-yarn.sh

测试任务执行是否正常

hadoop  jar ./share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.1.jar wordcount 10 100

image-20230920154513252

查看文件以及webui

image-20230920154606186

image-20230920155757826

Hive测试

插入数据

insert into table student values(1,'along');

image-20230920172324790

查看文件系统

[root@sun46 ~]# hdfs dfs -ls o3fs://bucket.volume/data/hive/warehouse
2023-09-20 17:42:32,916 INFO conf.Configuration: Removed undeclared tags:
Found 2 items
drwxrwxrwx   - root root          0 2023-09-20 17:16 o3fs://bucket.volume/data/hive/warehouse/student
drwxrwxrwx   - root root          0 2023-09-20 17:16 o3fs://bucket.volume/data/hive/warehouse/students
[root@sun46 ~]#
Flink测试

开启会话

yarn-session.sh -nm test -d

image-20230920153025316

如图所示正常启动,WebUI:http://sun77:18081

Spark测试

启动过程中,报错Caused by: java.lang.NoClassDefFoundError: [Lorg/apache/hadoop/security/token/DelegationTokenIssuer;,暂未解决。

代码测试
Java Ozone
package com.ozone.demo;

import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.ozone.client.*;
import org.apache.hadoop.ozone.client.io.OzoneOutputStream;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;

public class OzoneDemo {
    static long startTime = 0;
    static long endTime = 0;
    static int fileCounter = 0;

    /**
     * 读取文件内容并返回字节数组
     *
     * @param path 文件路径
     * @return 文件内容的字节数组,若读取失败则返回 null
     */
    public static byte[] readFile(String path) {
        try {
            FileInputStream in = new FileInputStream(new File(path));
            byte[] data = new byte[in.available()];
            in.read(data);
            in.close();
            return data;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 上传指定文件到 Ozone
     *
     * @param client    客户端对象
     * @param bucket    桶对象
     * @param keyName   键名称
     * @param filePath  文件路径
     * @param chunkSize 每次写入的 Chunk 大小
     * @throws IOException 如果上传过程中出现异常,则抛出 IOException
     */
    public static void uploadFile(OzoneClient client, OzoneBucket bucket, String keyName, String filePath, int chunkSize) throws IOException {
        // 读取文件内容
        byte[] data = readFile(filePath);
        if (data == null) {
            System.out.println("文件 " + filePath + " 读取失败");
            return;
        }
        // 创建输出流并写入数据
        OzoneOutputStream stream = bucket.createKey(keyName, data.length);
        int offset = 0;
        while (offset < data.length) {
            int length = Math.min(chunkSize, data.length - offset);
            stream.write(data, offset, length);
            offset += length;
        }
        // 关闭输出流
        stream.close();

        // 统计上传的文件数
        fileCounter++;
    }

    /**
     * 上传指定目录中的所有文件到 Ozone
     *
     * @param client       客户端对象
     * @param bucket       桶对象
     * @param sourceFolder 要上传的本地目录路径
     * @param targetFolder 桶中的目标路径
     * @param chunkSize    每次写入的 Chunk 大小
     * @throws IOException 如果上传过程中出现异常,则抛出 IOException
     */
    public static void uploadFolder(OzoneClient client, OzoneBucket bucket, String sourceFolder, String targetFolder, int chunkSize) throws IOException {
        File folder = new File(sourceFolder);
        if (!folder.exists()) {
            System.out.println("目录 " + sourceFolder + " 不存在");
            return;
        }
        // 获取目录下的所有文件和子目录
        File[] files = folder.listFiles();
        for (File file : files) {
            String fileName = file.getName();
            if (file.isDirectory()) {
                // 处理子目录并递归调用 uploadFolder 方法
                String subDir = targetFolder + "/" + fileName;
                System.out.println("正在上传子目录:" + subDir);
                uploadFolder(client, bucket, file.getAbsolutePath(), subDir, chunkSize);
            } else {
                // 上传文件
                String filePath = file.getAbsolutePath();
                String keyName = targetFolder + "/" + fileName;
                System.out.println("正在上传文件:" + keyName);
                uploadFile(client, bucket, keyName, filePath, chunkSize);
            }
        }
    }
    public static void deletebucket(OzoneClient client, String volume, String bucket) throws IOException {
        ObjectStore store = client.getObjectStore();
        OzoneVolume volumes = store.getVolume(volume);
        if (volumes == null) {
            System.out.println("卷" + volume + "为空");
            return;
        }
        OzoneBucket ozoneBucket = volumes.getBucket(bucket);
        if (ozoneBucket == null) {
            System.out.println("桶" + bucket + "不存在");
            return;
        }
        Iterator<? extends OzoneKey> keys = ozoneBucket.listKeys("");
        while (keys.hasNext()) {
            OzoneKey key = keys.next();
            ozoneBucket.deleteKey(key.getName());
            System.out.println("删除键:" + key.getName());
        }
    }

    public static void deleteAllVolume(OzoneClient client) throws IOException {
        ObjectStore store = client.getObjectStore();
        Iterator<? extends OzoneVolume> listVolumes = store.listVolumes("");

        while (listVolumes.hasNext()) {
            OzoneVolume volume = listVolumes.next();
            Iterator<? extends OzoneBucket> buckets = volume.listBuckets("");
            while (buckets.hasNext()) {
                OzoneBucket next = buckets.next();
                Iterator<? extends OzoneKey> keys = next.listKeys("");
                while (keys.hasNext()) {
                    OzoneKey key = keys.next();
                    next.deleteKey(key.getName());
                    System.out.println("删除键:" + key.getName());
                }
                volume.deleteBucket(next.getName());
                System.out.println("成功删除桶:" + next.getName());
            }
            store.deleteVolume(volume.getName());
            System.out.println("成功删除卷:" + volume.getName());

        }
        client.close();
    }
    public static void deleteVolumeByName(OzoneClient client, String volume) throws IOException {
        ObjectStore store = client.getObjectStore();
        OzoneVolume volumes = store.getVolume(volume);
        if (volumes == null) {
            System.out.println("卷" + volume + "为空");
            return;
        }
        Iterator<? extends OzoneBucket> buckets = volumes.listBuckets("");
        while (buckets.hasNext()) {
            OzoneBucket next = buckets.next();
            Iterator<? extends OzoneKey> keys = next.listKeys("");
            while (keys.hasNext()) {
                OzoneKey key = keys.next();
                next.deleteKey(key.getName());
                System.out.println("删除键:" + key.getName());
            }
        }
        store.deleteVolume(volume);
        System.out.println("成功删除卷:" + volume);
        client.close();
    }
    public static void uploadPathinFIle(String sourceFolder, OzoneClient ozClient, String volumeName, String bucket) throws IOException {
        // "I:\\学习资料\\路飞-爬虫开发+APP逆向超级大神班\\03--爬虫3期:爬虫&逆向3期【完结】";
        int chunkSize = 1048576; // 每次写入的 Chunk 大小
        // 获取 ObjectStore 引用
        ObjectStore objectStore = ozClient.getObjectStore();
        // 获取或创建卷
        OzoneVolume assets = null;
        try {
            assets = objectStore.getVolume(volumeName);
        } catch (Exception e) {
            System.out.println("卷" + volumeName + "不存在");
        }

        if (assets == null) {
            objectStore.createVolume(volumeName);
            assets = objectStore.getVolume(volumeName);
        }
        OzoneBucket video = null;
        // 获取或创建桶
        try {
            video = assets.getBucket(bucket);
        } catch (Exception e) {
            System.out.println("桶不存在");
        }
        if (video == null) {
            assets.createBucket(bucket);
            video = assets.getBucket(bucket);
        }
        // 记录开始时间
        startTime = System.nanoTime();
        System.out.println("开始时间:" + startTime);

        // 上传目录中的所有文件
        uploadFolder(ozClient, video, sourceFolder, bucket, chunkSize);

        // 记录结束时间
        endTime = System.nanoTime();
        System.out.println("结束时间:" + endTime);

        // 显示统计信息
        System.out.println(">>>>>>>上传完成,共上传了 " + fileCounter + " 个文件,耗时 " + TimeUnit.NANOSECONDS.toSeconds(endTime - startTime) + " 秒。");


        //关闭客户端连接
        ozClient.close();
    }

    public static void queryAll(OzoneClient client) throws IOException {
        ObjectStore store = client.getObjectStore();
        Iterator<? extends OzoneVolume> volumes = store.listVolumes("");
        while (volumes.hasNext()) {
            OzoneVolume volume = volumes.next();
            System.out.println("卷:" + volume.getName());
            Iterator<? extends OzoneBucket> buckets = volume.listBuckets("");
            while (buckets.hasNext()) {
                OzoneBucket bucket = buckets.next();
                System.out.println("\t桶:" + bucket.getName());
                Iterator<? extends OzoneKey> keys = bucket.listKeys("");
                while (keys.hasNext()) {
                    OzoneKey key = keys.next();
                    System.out.println("\t\tkey: " + key.getName());
                }
            }
        }
    }

    public static void queryvolumes(OzoneClient client) throws IOException {
        ObjectStore objectStore = client.getObjectStore();
        Iterator<? extends OzoneVolume> iterator = objectStore.listVolumes("");
        System.out.println("============================");
        while (iterator.hasNext()) {
            OzoneVolume volume = iterator.next();
            System.out.println("Volume: " + volume.getName());
        }
        System.out.println("============================");

    }

    public static void main(String[] args) throws IOException {
        OzoneConfiguration conf = new OzoneConfiguration();
        conf.set("ozone.om.address", "192.168.2.177:9862");

        OzoneClient ozClient = null;
        try {
            ozClient = OzoneClientFactory.getRpcClient(conf);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("连接异常");
            return;
        }

        ObjectStore objectStore = ozClient.getObjectStore();
        //删除key
        //deletebucket(ozClient, "sun-volume", "sun-bucket");
        //上传文件
        //uploadPathinFIle("I:\\学习资料\\路飞-爬虫开发+APP逆向超级大神班\\03--爬虫3期:爬虫&逆向3期【完结】", ozClient, "sun-volume1", "sun-bucket");
        //列出所有的key
        //queryAll(ozClient);
        //queryvolumes(ozClient);
        //deleteVolumeByName(ozClient, "myvolume");
        deleteAllVolume(ozClient);
    }
}
AWS Java
package com.ozone.controller;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;

public class AWSClient {
    static AmazonS3 s3;

    private static void init() throws Exception {
        AWSCredentials credentials = new BasicAWSCredentials("access_key",
                "secret_key");

        ClientConfiguration configuration = new ClientConfiguration();
        configuration.setUseExpectContinue(false);

        String endPoint = "http://192.168.2.177:9878";
        AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration(
                endPoint, null);

        s3 = AmazonS3ClientBuilder.standard().withEndpointConfiguration(endpointConfiguration)
                .withClientConfiguration(configuration).withCredentials(new AWSStaticCredentialsProvider(credentials))
                //.withChunkedEncodingDisabled(true)
                .withPathStyleAccessEnabled(true).build();
    }

    public static void deleteObject(String bucket, String object) {
        try {
            s3.deleteObject(bucket, object);
        } catch (AmazonServiceException e) {
            System.out.println("status code:" + e.getStatusCode());
        } catch (AmazonClientException e2) {
            System.out.println("status code:" + e2.getMessage());
        }
    }

    public static void putObject(String bucket, String object) {
        try {
            PutObjectRequest request = new PutObjectRequest(bucket, object,
                    new File("C:\\Users\\C\\Desktop\\files\\testfile.png"));
            s3.putObject(request);
        } catch (AmazonServiceException e) {
            System.out.println("status code:" + e.getStatusCode());
        } catch (AmazonClientException e2) {
            System.out.println("status code:" + e2.getMessage());
        }
    }

    public static void getObject(String bucket, String object) {
        try {
            GetObjectRequest request = new GetObjectRequest(bucket, object, null);
            System.out.println(object.toString());
            S3Object result = s3.getObject(request);

            S3ObjectInputStream s3is = result.getObjectContent();
            FileOutputStream fos = new FileOutputStream(new File("C:\\Users\\C\\Desktop\\files\\" + object));
            byte[] read_buf = new byte[1024 * 34];
            int read_len = 0;
            while ((read_len = s3is.read(read_buf)) > 0) {
                fos.write(read_buf, 0, read_len);
            }
            s3is.close();
            fos.close();
        } catch (AmazonServiceException e) {
            System.err.println(e.getErrorMessage());
        } catch (FileNotFoundException e) {
            System.err.println(e.getMessage());
        } catch (IOException e) {
            System.err.println(e.getMessage());
        }
    }

    public static void listObjects(String bucket) {
        try {
            ListObjectsV2Request request = new ListObjectsV2Request();
            request.setBucketName(bucket);
            ListObjectsV2Result result = s3.listObjectsV2(request);

            List<String> commonPrefix = result.getCommonPrefixes();
            for (int i = 0; i < commonPrefix.size(); i++) {
                System.out.println("commonPrefix:" + commonPrefix.get(i));
            }
            List<S3ObjectSummary> objectList = result.getObjectSummaries();
            for (int i = 0; i < objectList.size(); i++) {
                System.out.println("key:" + objectList.get(i).getKey());
            }
        } catch (AmazonServiceException e) {
            System.out.println("status code:" + e.getStatusCode());
        } catch (AmazonClientException e2) {
            System.out.println("status code:" + e2.getMessage());
        }
    }

    public static void putBucket(String bucket) {
        try {
            s3.createBucket(bucket);
        } catch (AmazonServiceException e) {
            System.err.println(e.getStatusCode());
            System.err.println(e.getErrorCode());
            System.err.println(e.getErrorMessage());
        }
    }

    //运行主函数
    public static void main(String[] args) throws Exception {
        String bucketName = "mybucket";
        String keyName = "example.png";
        //初始化连接
        init();
        //创建桶
        putBucket(bucketName);
//        //添加对象
//        putObject(bucketName, keyName);
//        //获取对象
//        getObject(bucketName, keyName);
//        //删除对象
//        deleteObject(bucketName, keyName);
//        //枚举对象列表
//        listObjects(bucketName);
    }
}

问题

一、org.apache.hadoop.fs.UnsupportedFileSystemException: No FileSystem for scheme "o3fs"

image-20230919163850132

无法加载ozone的客户端包,解决方案是直接将包cp到hadoop库下,然后重启

cp ozone-filesystem-hadoop3*    /srv/dstore/1.0.0.0/hdfs/share/hadoop/common/lib/

二、Tue Sep 19 10:34:29 +0800 2023] Application is added to the scheduler and is not yet activated. Skipping AM assignment as cluster resource is empty. Details : AM Partition = <DEFAULT_PARTITION>; AM Resource Request = <memory:2048, vCores:1>; Queue Resource Limit for AM = <memory:0, vCores:0>; User AM Resource Limit of the queue = <memory:0, vCores:0>; Queue AM Resource Usage = <memory:1024, vCores:1>;

导致job任务提交后,webui一直显示accept状态,无法运行,检查yarn集群nodemanage状态

root@sun46 hadoop]# yarn node -all -list
WARNING: YARN_LOG_DIR has been replaced by HADOOP_LOG_DIR. Using value of YARN_LOG_DIR.
WARNING: YARN_PID_DIR has been replaced by HADOOP_PID_DIR. Using value of YARN_PID_DIR.
2023-09-19 15:00:43,303 INFO client.ConfiguredRMFailoverProxyProvider: Failing over to rm2
Total Nodes:3
         Node-Id             Node-State Node-Http-Address       Number-of-Running-Containers
     sun75:34809              UNHEALTHY        sun75:8042                                  0
     sun46:34042              UNHEALTHY        sun46:8042                                  0
     sun77:36783              UNHEALTHY        sun77:8042                                  0

发现节点状态不健康,查看详细信息

[root@sun46 hadoop]# yarn node -status  sun75:34809
WARNING: YARN_LOG_DIR has been replaced by HADOOP_LOG_DIR. Using value of YARN_LOG_DIR.
WARNING: YARN_PID_DIR has been replaced by HADOOP_PID_DIR. Using value of YARN_PID_DIR.
2023-09-19 15:01:40,479 INFO client.ConfiguredRMFailoverProxyProvider: Failing over to rm2
2023-09-19 15:01:40,549 INFO conf.Configuration: resource-types.xml not found
2023-09-19 15:01:40,549 INFO resource.ResourceUtils: Unable to find 'resource-types.xml'.
Node Report :
        Node-Id : sun75:34809
        Rack : /default-rack
        Node-State : UNHEALTHY
        Node-Http-Address : sun75:8042
        Last-Health-Update : Tue 19/Sep/23 03:00:25:279CST
        Health-Report : 1/1 log-dirs usable space is below configured utilization percentage/no more usable space [ /srv/dstore/1.0.0.0/nfs/sun/sun75/yarn/userlogs : used space above threshold of 90.0% ]
        Containers : 0
        Memory-Used : 0MB
        Memory-Capacity : 8192MB
        CPU-Used : 0 vcores
        CPU-Capacity : 8 vcores
        Node-Labels :
        Resource Utilization by Node : PMem:9942 MB, VMem:9942 MB, VCores:0.15328224
        Resource Utilization by Containers : PMem:0 MB, VMem:0 MB, VCores:0.0

发现磁盘空间超过90%,释放空间,状态为RUNNING即可

三、启动spark-shell

image-20230920144857626

Caused by: java.lang.NoClassDefFoundError: [Lorg/apache/hadoop/security/token/DelegationTokenIssuer;

参考

posted on   匿名者nwnu  阅读(236)  评论(2编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示