前言
在前面的文章中,笔者阐述过关于Ozone SCM HA的设计原理,目前这个功能社区还没有完全做完,但是大部分的主要功能已经完善。本文笔者来简单聊聊SCM HA模式下的请求处理过程,它和早期实现的Ozone OM HA的实现略有不同(OM HA实现原理可参考此文:Ozone OM服务HA原理分析)。Ozone在已有OM HA下,再实现SCM HA后,Ozone系统整体的稳定性将会大大增强。
SCM HA和OM HA的区别
SCM服务相对OM服务来说,前者是提供底层Block服务的,它所管理和维护的东西将会更多一些,包括Block,Container和Pipeline。而OM则更完全侧着在K-V的metadata这个层面。
在SCM HA中,要更新的元数据类型包括了上面提到的3种类型的数据。因为Ozone是使用Apache Ratis走数据一致性控制的,因此SCM也同样沿用此机制做Leader SCM和各个Follower SCM的数据同步的。
SCM HA基于InvocationHandler的请求处理
下面笔者来简单介绍SCM HA是如何做请求处理的。
首先,它实现了一个自定义的InvocationHandler类来做方法调用前的一个逻辑处理,大致流程如下:
1)首先SCM接受到一个method的调用,InvocationHandler获取到此方法是否标有@Replicate的注释。
2)如果是Replicate注释的,则走Ratis的通信方式,否则就只走本地更新的逻辑
3)在Ratis的请求更新中,SCM的元数据的更新会首先写入到一个叫SCM Transaction Buffer里,并不会直接写出到磁盘中去。直到SCM take Snapshot的时候,才会触发这个Transaction Buffer的flush写出行为。这点是为了加速SCM元数据更新的速度,这点和OM的table+double buffer有着异曲同工之妙。
相关类代码如下,首先是Replicate注释定义如下,我们以Pipeline更新为例子。
/**
* Manages the state of pipelines in SCM.
*/
public interface PipelineStateManagerV2 {
/**
* Adding pipeline would be replicated to Ratis.
* @param pipelineProto
* @throws IOException
*/
@Replicate
void addPipeline(HddsProtos.Pipeline pipelineProto) throws IOException;
/**
* Removing pipeline would be replicated to Ratis.
* @param pipelineIDProto
* @return Pipeline removed
* @throws IOException
*/
@Replicate
void removePipeline(HddsProtos.PipelineID pipelineIDProto)
throws IOException;
/**
* Updating pipeline state would be replicated to Ratis.
* @param pipelineIDProto
* @param newState
* @throws IOException
*/
@Replicate
void updatePipelineState(HddsProtos.PipelineID pipelineIDProto,
HddsProtos.PipelineState newState)
throws IOException;
...
}
Replicate意味着这些方法的执行需要同步在Follower SCM里执行,以此达到SCM metadata的一致。
然后,对PipelineStateManagerV2类实现动态代理类的设置。
public PipelineStateManagerV2 build() throws IOException {
Preconditions.checkNotNull(pipelineStore);
final PipelineStateManagerV2 pipelineStateManager =
new PipelineStateManagerV2Impl(pipelineStore, nodeManager);
final SCMHAInvocationHandler invocationHandler =
new SCMHAInvocationHandler(SCMRatisProtocol.RequestType.PIPELINE,
pipelineStateManager, scmRatisServer);
return (PipelineStateManagerV2) Proxy.newProxyInstance(
SCMHAInvocationHandler.class.getClassLoader(),
new Class<?>[]{
PipelineStateManagerV2.class}, invocationHandler