前言
在中心化管理的存储系统中,当系统内的数据出现个别副本损坏的情况时,作为中心控制中心,它需要能够感知系统内的这个情况,并且能够快速的进行副本的拷贝恢复。我们姑且称此类服务为ReplicationManager,或者叫做类似于ReplicationMonitor的服务。此类服务在分布式存储系统中扮演的功能为定期检查系统内所有数据的副本情况,并进行必要的修复工作或者其它类似操作。本文笔者来聊聊Ozone系统中的这个服务,名称就叫做ReplicationManager。
Ozone ReplicationManager的任务要求
提到ReplicationManager,首先要说的就是ReplicationManager的核心任务要求。
因为Ozone是基于Container做replication的,因此它的一大核心要求:
保证集群内的所有Container达到规定副本数的数量,不存在Container数少于或多于其设置副本数的数量。
基于这个大的原则前提,它还可以做额外的一些对Container副本数据的优化处理,这里包括但不仅限于:
1) Container副本的placement策略放置,保证数据更高的容错性。
2) 非健康Container副本的检查处理。
另外一点需要注意的是,做Replication的Container的状态必须是closed状态,不能是处于可进行写的open状态的Container。
ReplicationManager的处理过程逻辑
下面我们结合具体代码逻辑,来了解下ReplicationManager的具体处理过程。
ReplicationManager在Ozone SCM内启动后,作为一个后台线程服务,其执行的run方法如下:
/**
* ReplicationMonitor thread runnable. This wakes up at configured
* interval and processes all the containers in the system.
*/
private synchronized void run() {
try {
while (running) {
final long start = Time.monotonicNow();
// 1.获取集群内所有Container的ID信息
final Set<ContainerID> containerIds =
containerManager.getContainerIDs();
// 2.遍历每个Container,检查其Replica情况是否达到预期的Replica数量
containerIds.forEach(this::processContainer);
LOG.info("Replication Monitor Thread took {} milliseconds for" +
" processing {} containers.", Time.monotonicNow() - start,
containerIds.size());
wait(conf.getInterval());
}
} catch (Throwable t) {
// When we get runtime exception, we should terminate SCM.
LOG.error("Exception in Replication Monitor Thread.", t);
ExitUtil.terminate(1, t);
}
}
我们可以看到,它在每个检查周期内是拿到所有ContainerID信息,然后逐个进行Container副本的判断处理的。
然后我们进入processContainer方法,这个方法里面是针对每个独立唯一的Container,进行副本的检查处理。
这部分逻辑如下:
private void processContainer(ContainerID id) {
lockManager.lock(id);
try {
final ContainerInfo container = containerManager.getContainer(id);
// 1). 获取当前汇报上来的最新副本信息
final Set<ContainerReplica> replicas = containerManager
.getContainerReplicas(container.containerID());
final LifeCycleState state = container.getState();
//..副本状态的逻辑处理...
// 2). 更新inflight的Replication信息,如果当前副本节点包含于inflight中时,
// 则进行对应ContainerId的inflight节点移除,意为此inflight的replication已成功
updateInflightAction(container, inflightReplication,
action -> replicas.stream()
.anyMatch