本文首发于泊浮目的专栏: https://segmentfault.com/blog...
ZStack是下一代开源的云计算IaaS(基础架构即服务)软件。它主要面向的是将来的智能数据中心,经过提供的API来管理包括计算、存储和网络在内的数据中心的各类资源。跟OpenStack相比,ZStack具备易用、稳定、灵活、超高性能等特色。其单管理节点能够管理1万台物理机规模集群,多个管理节点构建的集群能够作到使用一个数据库、一套消息总线管理10万台物理机、数百万个虚拟机节点、并发处理数万个API。java
如下是ZStackV2.2的服务架构图
![]()
官网地址: http://www.zstack.io/核心开源引擎ZStack GitHub:https://github.com/zstackio/z...git
ZStack-Utility GitHub:https://github.com/zstackio/z...github
阅读源码若是不想使用IDE,建议配合https://github.com/buunguyen/...。web
本文将对核心引擎-ZStack的源码进行剖析。在ZStack官网上咱们能够看到其每一个版本的发布都是携带了许多的新特性。在笔者看来,可以快速迭代的缘由首先是来自于每位工程师的辛勤付出。除此以外,因其还有些软件工程领域中沉淀下来的最佳实践:算法
Iaas的核心应该作的是管控层,而不是数据层。故ZStack仅仅也是作出一些“决策”而已——在设计系统的时候,应不考虑在这些决策的执行上消耗大量的资源。在面对大量请求或者“决策”的时候,若是使用多线程来处理阻塞式IO模型时会遇到一些问题:数据库
而非阻塞、异步的消息驱动系统能够只运行少许的线程,而且不阻塞这些线程,只在须要计算资源时才使用它们。这大大提升了系统的响应速度,而且可以更高效地利用系统资源。segmentfault
故,ZStack采用了异步架构,分别由三个部分组成:设计模式
若是在系统中的一部分采用异步设计,是不行的。这样仍是会由于同步而无法享受异步带来的“福利”。故此整个系统都得采用异步架构。网络
扩展连接 : ZStack--可拓展性的秘密武器1:异步架构
在ZStack
中,每个服务都是独立存在的。为了方便的管理更多的物理机,ZStack
推荐采用集群部署MN。但这样就会遇到一个问题,不一样MN下面有着不一样的几个服务存在,在这里咱们设其为X个服务。在10个MN部署的状况下,可能就是10X个服务。那么在一个资源须要操做时,我须要发送向对应的MN。那么如何找到那个MN呢?最直观的想法就是在各个MN中保存相应的“服务表”,这便是一种状态。那么在分布式系统中,采用有状态的服务绝对不是一个好的选择,它会严重影响系统的扩展性。ZStack
巧妙的采用了一致性哈希算法+MQ解决了这个问题。多线程
扩展连接: ZStack—可拓展性秘密武器2:无状态的服务
解决并发的问题不必定要用显式的锁,也能够对同一资源作操做的任务作成队列使其串行执行。
注意:并发 != 并行
扩展连接: ZStack--可拓展性秘密武器3:无锁架构
在Intellij
中打开ZStack的代码,会发现大多数目录底下都会有一个pom.xml
文件,ZStack采用了模块化项目。模块化的好处在工程实践中不言而喻的,好比:
下面来看一下ZStack
中代码的结构:
截图于2017.9.22
名称 | 简介 |
---|---|
build | 用于Java部分的编译、打包、部署等 |
conf | 配置文件及SQL文件的放置;Spring Service配置存放;持久化文件配置 |
core | 核心模块。实现系统的核心功能——包括数据库、消息总线、工做流实现等等 |
coregroovy | ZStack的最新测试采用了Groovy,这里是对测试库作的支持 |
header | 消息以及Entity的定义 |
plugin | 顾名思义。其中很多组件都以插件化开发,提供较高的灵活性 |
sdk | 测试库使用的SDK |
simulator | 对于测试库支持的又一模块,主要用户simulator agent的行为 |
testlib | 测试库 |
test | 测试模块 |
工具类 | 工具包。目前仅仅支持了doc生成 |
utils | 代码中使用的工具类 |
其余 | 功能实现模块 |
在ZStack
中,每一个功能实现模块都会被称为服务——一个独立的服务。各个服务之间的通讯由MQ来承担。这就像是传统的CSE,C和E是不耦合的,经过S来交互。一样的,一个服务须要向另外一个服务发起调用,只需往消息总线发送消息,并指定这个服务ID(Service ID)便可。若是某个服务的代码须要大量重构或者作成微服务,只要提供相同的服务并注册到MQ上就能够了。这就是事件驱动架构(Event Driven Architecture)的一种典型实现。
CSE:Controller、Service、Entity。注:称做Domain或者Model都是不专业的。Domain是一个领域对象,每每咱们再作传统Java软件web开发中,这些Domain都是贫血模型,是没有行为的,或是没有足够的领域模型的行为的,因此,以这个理论来说,这些Domain都应该是一个普通的entity对象,并不是领域对象,因此请把包名改成:com.xxx.entity。
举个简单明了的例子。若是每一个对象的行为都是经过消息来决定的(好比一个方法须要message获得回复后才能do something...),那么这个对象仅仅对消息总线产生了依赖。在测试中,将会发挥巨大的威力——咱们只须要改变handle message处的行为,就可使一个对象行为作出相应的变化。这样可使mock的单位变得更小,同时也能够变得更加灵活。
试想若是经过函数调用:
//方法a中的代码 xxService.method1(); xx2Service.method2();
在测试中该如何解耦?但若是经过MQ——即一个消息来调用xxService.method1()
,那么方法a对xxService就没有了直接的依赖。
不了解Spring的人能够看: 看起来很长但仍是有用的Spring学习笔记
在代码中,每当咱们New出一个对象时,这个模块便对这个对象产生了依赖。当咱们须要测试的时候就不得不去Mock它。当依赖的对象or Field 有成千上万个的时候,这就是一场灾难了。代码变得愈发不可测,坑就越多,开发者在扩展or维护项目的时候就会愈发的乏力。这就像是咱们以前提到的MQ,服务1->MQ->服务2
,因为中间隔了一个MQ,因而服务1和服务2没有必然的关系。一样的,从对象1->调用->对象2
到对象1->调用->Spring提供的IOC容器->对象2
,这样使对象与对象之间也没有了直接调用关系,对象1只要知道它要调用的对象实现了其须要的Interface
就是能够调用的。
除了Autowired
的正确使用姿式。在ZStack中,还有一类颇有意思的代码,通常称之为xxxExtensionPoint
。其本质就是定义一个接口,而后其实现类做为Bean经过XML注册到IOC中。在须要使用的时候,经过Spring获取到全部实现该接口的对象,调用其函数。这样就会使代码变得很是的灵活。
例如,ZStack
分为多个版本——开源版、企业版、混合云版等。若是一个服务在不一样版本中的处理逻辑须要稍许不一样,那么就能够在开源版的代码中注册一个接口,在另外一个版本的服务中实现该接口。这样也不会影响到开源版的原有逻辑。从模块上看咱们代码的是松耦合而且没法直接调用的,可是在内存中,倒是能够调用获得的。
在ZStack
中
因为ZStack
源码作到了必定的解耦合(上述提到)与无状态,使得集成测试得以进行。
其首席架构师Frank.Zhang曾说过:咱们开发者在写代码的时候每每就应该考虑该怎么写测试了。想了解ZStack的测试框架,能够看: ZStack WiKi :管理节点基于模拟器的Integration Test框架
在ZStack
中,设计模式有较为良好的实践。笔者有机会将会在以后的系列文章分析其中的典型案例以及在代码中使用极其频繁的核心工具。