Ozone OM服务HA原理分析

本文探讨了Ozone对象存储系统中OzoneManager(OM)的高可用性(HA)设计,通过采用基于Raft协议的2N+1模式实现HA,确保在服务切换时保持强一致性。OM HA利用Apache Ratis库实现状态同步,通过StateMachine处理请求并进行读写请求区别处理。此外,还介绍了OM服务的定期Snapshot和Checkpoint行为,以及DoubleBuffer+Table Cache的请求处理机制,以提高效率。
摘要由CSDN通过智能技术生成

前言


在分布式系统中,为了避免中心服务节点存在单点问题,我们往往会有HA(High Availability)的防御措施。比如一个简单的HA部署方案,额外在另一个机器上部署一个完全一样的服务。当当前的这个服务出现问题时,能够快速切换到这个用来做HA的服务。HA服务切换本身并不是重点,这里的重点是如何保持HA服务间的状态同步。这点在分布式系统的HA设计实现中尤其之关键。本文笔者来聊聊Ozone对象存储系统中核心服务OzoneManager的HA的设计实现原理。

OzoneManager HA的目标


在之前Ozone的alpha版本中,OM服务都是以单点服务部署的方式来处理外部请求的。显然这种缺乏HA的运行模式在运用到实际生产环境中将会存在风险。于是Ozone社区在JIRA[HDDS-505: OzoneManager HA]下设计实现了OM HA的特性。同样是作为分布式存储系统的HA实现,OzoneManager的HA实现和HDFS NameNode HA实现有许多异同之处。

在官方社区的OM HA的设计文档中,列出了以下几点目标实现要点:

  • 底层使用Raft协议来实现OM服务的HA特性。换句话说,这里将不是只有1个Active,另1个Standby服务这样的模式。而是2N+1的模式,1个OM Leader服务,2N个OM Follower服务。OM Follwer间通过投票选举出Leader服务。中间投票选举的过程遵从的就是Raft协议。这点即OM HA服务实现基于的一大核心要点。
  • 有了OM Leader,OM Follower服务之后,另外一个要点是Leader/Follower间的状态同步控制,以此保证服务在角色切换后,还能保证完全一致的服务状态,就是我们所说的Strong Consistency。
  • OM HA服务对于用户的透明性。用户理应对于OM HA完全透明,它在配置了给定的多OM服务地址后,就可以进行服务的请求了了。不管背后的服务处于什么角色状态,客户端用户都无须做任何调整。换言之,客户端始终能找到正确的OM服务,进行请求的发送,而不是单一定向的定点服务发送。

OM HA的Raft方式实现


OM HA中使用了Raft做HA的底层实现,那么它是如何工作的呢?以及它是如何做服务状态的同步的呢?

OM HA在这里使用了Raft的Java实现库Apache Ratis,里面实现了基于Raft协议的Leader选举以及Leader/Follower的状态一致性的控制。不过今天笔者并不准备展开篇幅阐述Raft中一致性同步控制的具体机理,我们还是着重谈谈OM HA本身。

因为有了Raft库Ratis的底层一致性的实现保证后,在上层OM中,它需要做的事情就变得清晰,明了了。在Apache Ratis中,是通过定义StateMachine状态机的方式来表示一个服务的当前状态。外界的每次请求就是此StateMachine即将要apply的一个新的State,每次apply完这个State后,整个状态机就会变为下一个State。因此,多个服务初始拥有相同初始State的StateMachine,在经历了若干次顺序一致的状态改变后,StateMachine的最终状态必然是一致的。这就是基于StateMachine的保证状态同步的核心原理。

这里我们将StateMachine的抽象概念定义转化为更为具体化的概念定义:

  • 每次外界而来的待apply的State即为外界的request请求。
  • 服务的StateMachine为OM服务的metadata信息,包括volume, bucket,key信息等各种表信息。

在Leader/Follower的HA模式下,请求状态的处理流程如下:
1)客户端发送请求给Leader处理
2)Leader接收到客户端请求,然后将请求复制分发到其它Follower上
3)Leader服务获取到超过半数以上Follower收到请求信息的ack回复之后,apply用户请求到内部状态机。
4)Leader会通知其它Follower去apply它们接收到的请求。

上述请求我们可以理解为是Transaction,从StateMachine的角度来看,概念叫做log entry。Leader复制请求到其它Follower的过程为log的write过程, 如果log被其它Follower成功接收到了,则意为此log为committed的log。

因此在这里StateMachine的实现异常关键,Ozone在这里实现了其内部使用的状态机类OzoneManagerStateMachine,对应的2个核心方法,log entry的写入,和log entry的状态apply方法:

  /**
   * Validate/pre-process the incoming update request in the state machine.
   * @return the content to be written to the log entry. Null means the request
   * should be rejected.
   * @throws IOException thrown by the state machine while validating
   */
  @Override
  public TransactionContext startTransaction(
      RaftClientRequest raftClientRequest) throws IOException {
   
    ByteString messageContent = raftClientRequest.getMessage().getContent();
    OMRequest omRequest = OMRatisHelper.convertByteStringToOMRequest(
        messageContent);

    Preconditions.
Ozone是一个开源的数据处理库,通常用于Apache Flink流处理框架中。如果你想使用Ozone读取数据曲线,首先你需要了解几个关键步骤: 1. **环境配置**:确保你的项目已经添加了Ozone的相关依赖,并且在运行环境中配置好了Ozone存储。 2. **创建Ozone Client**:使用Ozone SDK提供的API创建一个Ozone客户端实例,这个实例会连接到Ozone存储集群。 ```java OzoneConfig ozoneConf = new OzoneConfig(); ZooKeeperClientConfiguration zookeeperConf = new ZooKeeperClientConfiguration.Builder() .setZkQuorum("your_zookeeper_quorum") .build(); Ozone ozone = new Ozone(zookeeperConf, ozoneConf); ``` 3. **访问FileSystem**:通过Ozone client获取一个FileSystem对象,然后你可以使用这个对象去操作存储的数据。 ```java FileSystem fs = ozone.getFileSystem(); ``` 4. **读取数据曲线**:假设数据是以时间序列的形式存储的,可以使用`getData()`或`getRange()`方法从特定路径读取数据。例如,如果你的数据存储在一个目录下,每个文件代表一个时间段的数据点: ```java List<Located ozoneData = fs.getData("/data/curve/path", new Range(startTimestamp, endTimestamp)); ``` 这里,`startTimestamp`和`endTimestamp`是你想要查询的时间范围。 5. **解析数据**:最后,从`Located`对象中获取实际的数据,这通常是字节数组,需要你自己将其转换成适合的结构,如CSV、JSON等,以便解析成数据曲线。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值