随着 ZStack 的版本迭代,其可以掌管的资源也越来越多.但新增模块的结构却还是大致相同,此即是 ZStack 的经典设计模式--这套模式也被开发者称为 ZStack 三驾马车.
实例分析
以 PrimaryStorage 为例,其 APIMsg 的真正逻辑处理第一站就是
PrimaryStorageManagerImpl
.
如果是对特定的 PrimaryStorage 进行操作,将会通过相应的 Factory 得出对应类型并转发至相应的 Base:
private void passThrough(PrimaryStorageMessage pmsg) {
PrimaryStorageVO vo = dbf.findByUuid(pmsg.getPrimaryStorageUuid(), PrimaryStorageVO.class);
if (vo == null && allowedMessageAfterSoftDeletion.contains(pmsg.getClass())) {
PrimaryStorageEO eo = dbf.findByUuid(pmsg.getPrimaryStorageUuid(), PrimaryStorageEO.class);
vo = ObjectUtils.newAndCopy(eo, PrimaryStorageVO.class);
}
Message msg = (Message) pmsg;
if (vo == null) {
String err = String.format("Cannot find primary storage[uuid:%s], it may have been deleted", pmsg.getPrimaryStorageUuid());
bus.replyErrorByMessageType(msg, errf.instantiateErrorCode(SysErrors.RESOURCE_NOT_FOUND, err));
return;
}
PrimaryStorageFactory factory = getPrimaryStorageFactory(PrimaryStorageType.valueOf(vo.getType()));
PrimaryStorage ps = factory.getPrimaryStorage(vo);
ps.handleMessage(msg);
}
PrimaryStorageFactory
是一个接口,在此基础上有各式各样的实现:如 Local,Ceph,NFS 等.
public interface PrimaryStorageFactory {
PrimaryStorageType getPrimaryStorageType();
PrimaryStorageInventory createPrimaryStorage(PrimaryStorageVO vo, APIAddPrimaryStorageMsg msg);
PrimaryStorage getPrimaryStorage(PrimaryStorageVO vo);
PrimaryStorageInventory getInventory(String uuid);
}
这就像现实中的模型一样--在 ZStack 中可以有 PrimaryStorage,而且可以有不同类型的 PrimaryStorage:
PrimaryStorage:
Local
Ceph
NFS
这在软件工程中即是一种分离领域(Layered Architecture)的具象.应用层对应 ZStack 的 ManagerImpl,而 Base 更像是领域层.
应用层
应用层的定义应该是:
定义软件要完成的任务,并且指挥表达领域概念的对象来解决问题.这一层负责的工作对业务来说意义重大,也是与其他系统的应用层进行交互的必要渠道.
应用层要尽量简单,不包含业务规则或者知识,而只为下一次的领域对象协调任务,分配工作,使它们互相协作.它没有反映业务情况的状态,但是却可以具有另外一种状态,为用户或程序显示某个任务的进度.
而在 ZStack 中,的确也像上面说的如此.在 源码 中我们可以看到,对实例操作的 API 全部被转发到了 Base 层去,而 Manager 这里 handle 的往往是一些过滤性,Get 型 API,如
APIListPrimaryStorageMsg
,
APIGetPrimaryStorageMsg
,
APIGetPrimaryStorageTypesMsg
等.
Manager 即是 API(这里 API 不仅仅是 APIxxxMsg,同时包含用于通信的内部 Msg.注意,它们都 implements 自 Message 这个接口)的入口,以及用于管理服务的生命周期.
领域层
定义:
负责表达业务概念,业务状态信息以及业务规则.尽管保存业务状态的技术细节由基础设施层(在 ZStack 如 DataBaseFacade 即是),但是反映业务情况的状态是由本层控制并且使用的.注意,领域层是业务软件的核心.
以 PrimaryStorageBase 为例,其本身对应了 DB 中的一条记录,并且在改变状态后也 Refresh 自己.并对操作单独实例的 Msg 进行 handle.
通信
虽然分了层,并且关系是松散的.但是各个层之间也是需要通信的,那么层与层之间只能是单向的.上层可以直接使用或操作下层元素,方法是通过调用下层元素的公共接口,保持对下层元素的引用(至少是暂时的),以及采用常规的交互手段.而如果下层元素需要与上层元素通信,则需要采用另一种通信机制--比如回调或者 Observers 模式(在 ZStack 中即是 ExtensionPoint).
回调
我们还是以 PrimaryStorageBase 为例.在其做链接操作时,逻辑如下:
private void doConnect(ConnectParam param, final Completion completion) {
thdf.chainSubmit(new ChainTask(completion) {
@Override
public String getSyncSignature() {
return String.format("reconnect-primary-storage-%s", self.getUuid());
}
@Override
public void run(SyncTaskChain chain) {
changeStatus(PrimaryStorageStatus.Connecting);
connectHook(param, new Completion(chain, completion) {
@Override
public void success() {
self = dbf.reload(self);
changeStatus(PrimaryStorageStatus.Connected);
logger.debug(String.format("successfully connected primary storage[uuid:%s]", self.getUuid()));
RecalculatePrimaryStorageCapacityMsg rmsg = new RecalculatePrimaryStorageCapacityMsg();
rmsg.setPrimaryStorageUuid(self.getUuid());
bus.makeLocalServiceId(rmsg, PrimaryStorageConstant.SERVICE_ID);
bus.send(rmsg);
tracker.track(self.getUuid());
completion.success();
chain.next();
}
@Override
public void fail(ErrorCode errorCode) {
tracker.track(self.getUuid());
self = dbf.reload(self);
changeStatus(PrimaryStorageStatus.Disconnected);
logger.debug(String.format("failed to connect primary storage[uuid:%s], %s", self.getUuid(), errorCode));
completion.fail(errorCode);
chain.next();
}
});
}
@Override
public String getName() {
return getSyncSignature();
}
});
}
而不同的 connectHook 都有不同的实现.
在抽象等级上,PrimaryStorageBase 是比图中的这些 Base 高的.而这类具象 Base 可以 Message 返回 Success 或者 Fail 使高层 Base 做出不同的决策.
Observers
继续,在 PrimaryStorageBase 中,其中 handle
APIAttachPrimaryStorageToClusterMsg
的地方会做事件发送:
extpEmitter.preAttach(self, msg.getClusterUuid());
其会发送向:
在这里,一个 Base 通过了 Observers 模式向某个 ManagerImpl 发送了事件,实现了下层往上层的通信.
小结
在大型软件工程中,我们通常会给这样的应用划分层次.分别在每层中进行设计,使其具有内聚性并且只依赖于它的下层,而下层与上层也只有松散的耦合.这使得模型含义丰富,结构清晰.也使得整个应用架构更加茁壮.
来源: https://segmentfault.com/a/1190000012903365