美文网首页ZStack博客集
ZStack源码剖析之设计模式鉴赏——三驾马车

ZStack源码剖析之设计模式鉴赏——三驾马车

作者: 泊浮目 | 来源:发表于2018-01-19 12:13 被阅读40次

    本文首发于泊浮目的专栏:https://segmentfault.com/blog/camile

    前言

    随着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是一个接口,在此基础上有各式各样的实现:如LocalCephNFS等。

    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,如APIListPrimaryStorageMsgAPIGetPrimaryStorageMsgAPIGetPrimaryStorageTypesMsg等。

    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发送了事件,实现了下层往上层的通信。

    小结

    在大型软件工程中,我们通常会给这样的应用划分层次。分别在每层中进行设计,使其具有内聚性并且只依赖于它的下层,而下层与上层也只有松散的耦合。这使得模型含义丰富,结构清晰。也使得整个应用架构更加茁壮。

    相关文章

      网友评论

        本文标题:ZStack源码剖析之设计模式鉴赏——三驾马车

        本文链接:https://www.haomeiwen.com/subject/oaxwwxtx.html