【ZStack】4.进程内服务

为了应对诸如惊人的操作开销、重复的努力、可测试性等微服务通常面临的挑战,以及获得诸如代码解耦,易于横向扩展等微服务带来的好处,ZStack将所有服务包含在单个进程中,称为管理节点,构建一个进程内的微服务架构。

动机

构建一个IaaS软件是很难的,这是一个已经从市场上现存的IaaS软件获得的教训。作为一个集成软件,IaaS软件通常需要去管理复杂的各种各样的子系统(如:虚拟机管理器hypervisor,存储,网络,身份验证等)并且需要组织协调多个子系统间的交互。例如,创建虚拟机操作将涉及到虚拟机管理模块,存储模块,网络模块的合作。由于大多数IaaS软件通常对架构考虑不够全面就急于开始解决一个具体问题,它们的实现通常会演变成:

随着一个软件的不断成长,这个铁板一块的架构(monolithic architecture)将最终变为一团乱麻,以至于没有人可以修改这个系统的代码,除非把整个系统从头构建。这种铁板一块的编程问题是微服务可以介入的完美场合。通过划分整个系统的功能为一个个小的、专一的、独立的服务,并定义服务之间交互的规则,微服务可以帮助转换一个复杂笨重的软件,从紧耦合的、网状拓扑架构,变成一个松耦合的、星状拓扑的架构。


因为服务在微服务中是编译独立的,添加或者删除服务将不会影响整个系统的架构(当然,移除某些服务会导致功能的缺失)。
微服务远比我们已经讨论的内容更多:微服务的确有很多引入注目的优点,尤其是在一个的开发运维 流程(DevOps process)中,当涉及到一个大机构的很多团队时。我们不打算讨论微服务的所有支持和反对意见,我们确定你可以在网上找到大量的相关文章,我们主要介绍一些我们认为对IaaS软件影响深远的特性。

问题

虽然微服务可以解耦合架构,但这是有代价的。阅读Microservices - Not A Free Lunch!和Failing at Microservices会对这句话有更深的理解。在这里,我们重点强调一些我们认为对IaaS软件影响重大的事情。

1. 难以定义服务的边界和重复做功

创建Microservices架构的挑战之一是决定应该把哪一部分的代码定义为服务,一些是非常明显的,比如说,处理主机部分的逻辑代码可以被定义为一个服务。然而,管理数据库交互的代码非常难以决定应不应该被定义为服务。数据库服务可以使得整个架构更加清晰明了,但是这样会导致严重的性能下降。通常,类似于这样的代码可以被定义为库,库可以被各个服务调用。鉴于所有服务一般在互相隔离的目录下开发和维护,创建一个给不同的单一的软件提供接口的虚拟的库,要求开发者必须具有良好的和各个不同组的开发者沟通协调的能力。综上,服务很容易重复造轮子和导致不必要的重复做功。

2. 软件难以部署、升级和维护

服务,尤其是那些分散在不同进程和机器上的,是难以部署和升级的。用户通常必须去花费几天甚至几周去部署一个完整的可运行的系统,并害怕升级一个已经构建好的稳定的系统。尽管一些类似puppet的配置管理软件一定程度上缓解了这个问题,用户依旧需要克服陡峭的学习曲线去掌握这些配置工具,仅仅是为了部署或者升级一个软件。管理一个云是非常困难的,努力不应该被浪费在管理这些原本应该使生活更轻松的软件上。
服务的数量确实很重要:IaaS软件通常有许许多多的服务。拿著名的openstack举个例子,为了完成一个基础的安装你将需要:Nova, Cinder, Neutron, Horizon, Keystone, Glance。除了nova是在每台主机都需要部署的,如果你想要4个实例(instances),并且每个服务运行在不同机器上,你需要去操纵20台服务器。虽然这种人造的案例将不太可能真实地发生,它依旧揭示了管理相互隔离的服务的挑战。

3. 零散的配置

运行在不同服务器上的服务,分别维护着它们散乱在系统各个角落的配置副本。在系统范围更新配置的操作通常由临时特定的脚本完成,这会导致由不一致的配置产生的令人费解的失败。

4. 额外的监控努力

为了跟踪系统的健康状况,用户必须付出额外的努力去监控每一个服务实例。这些监控软件,要么由第三方工具搭建,要么服务自身维护,仍然受到和微服务面临的问题所类似的问题的困扰,因为它们仍然是以分布式的方式工作的软件。

5. 插件杀手

插件这个词在微服务的世界中很少被听到,因为每个服务都是运行在不同进程中一个很小的功能单元(function unit);传统的插件模式(参考The Versatile Plugin System)目标是把不同的功能单元相互挂在一起,这在微服务看来是不可能的,甚至是反设计模式的。然而,对于一些很自然的,要在功能单元间强加紧密依赖的业务逻辑,微服务可能会让事情变得非常糟糕,因为缺乏插件支持,修改业务逻辑可能引发一连串服务的修改。

所有的服务都在一个进程

意识到上述的所有问题,以及这么一个事实,即一个可以正常工作的IaaS软件必须和所有的编排服务一起运行之后,ZStack把所有服务封装在单一进程中,称之为管理节点。除去一些微服务已经带来的如解耦架构的优点外,进程内的微服务还给了我们很多额外的好处:

1. 简洁的依赖

因为所有服务都运行在同一进程内,软件只需要一份支持软件(如:database library, message library)的拷贝;升级或改变支持库跟我们对一个单独的二进制应用程序所做的一样简单。

2. 高可用,负载均衡和监控

服务可以专注于它们的业务逻辑,而不受各种来自于高可用、负载均衡、监控的干扰,这一切只由管理节点关心;更进一步,状态可以从服务中分离以创建无状态服务,详见ZStack's Scalability Secrets Part 2: Stateless Services。

3. 中心化的配置

由于在一个进程中,所有的服务共享一份配置文件——zstack.properties;用户不需要去管理各种各样的分散在不同机器上的配置文件。

4. 易于部署、升级、维护和横向扩展

部署,升级或者维护一个单一的管理节点跟部署升级一个单一的应用程序一样容易。横向扩展服务只需要简单的增加管理节点。

5. 允许插件

因为运行在一个单一的进程中,插件可以很容易地被创建,和给传统的单进程应用程序添加插件一样。
进程内的微服务并不是一个新发明: 早在90年代,微软在COM(Component Object Model)中把server定义为远程、本地和进程内三种。这些进程内的server是一些DLLs,被应用程序在同一进程空间内加载,属于进程内的微服务。Peter Kriens在四年前就声称已经定义了一种总是在同一进程内通信的服务,OSGi µservices。

服务样例

在微服务中,一个服务通常是一个可重复的业务活动的逻辑表示,是无关联的、松耦合的、自包含的,而且对服务的消费者而言是一个“黑盒子”。简单来说,一个传统的微服务通常只关心特定的业务逻辑,有自己的API和配置方法,并能像一个独立的应用程序一样运行。尽管ZStack的服务共享同一块进程空间,它们拥有这些特点中的绝大多数。ZStack很大程度上是一个使用强类型语言java编写的项目,但是在各个编排服务之间没有编译依赖性,例如:计算服务(包含VM服务、主机服务、区域服务、集群服务)并不依赖于存储服务(包含磁盘服务、基础存储服务、备份存储服务、磁盘快照服务等),虽然这些服务在业务流程中是紧密耦合的。
在源代码中,一个ZStack的服务并不比一个作为一个独立的jar文件构建的maven模块多任何东西。每一个服务可以定义自己的APIs、错误码、全局配置,全局属性和系统标签。例如KVM的主机服务拥有自己的APIs(如下所示)和各种各样的允许用户自己定义配置的方式。

<?xml version="1.0" encoding="UTF-8"?>
<service xmlns="http://zstack.org/schema/zstack">
    <id>host</id>
    <message>
        <name>org.zstack.kvm.APIAddKVMHostMsg</name>
        <interceptor>HostApiInterceptor</interceptor>
        <interceptor>KVMApiInterceptor</interceptor>
    </message>
</service>

通过全局配置来配置

备注:这里只简单展示一小部分,用户可以使用API去更新/获取全局配置,在这里展示一下全局配置的视图。

<?xml version="1.0" encoding="UTF-8"?>
<globalConfig xmlns="http://zstack.org/schema/zstack">
    <config>
        <category>kvm</category>
        <name>vm.migrationQuantity</name>
        <description>A value that defines how many vm can be migrated in parallel when putting a KVM host into maintenance mode.(当一个KVM主机变成维护模式的时候,这里的值定义了可以被并发迁移的虚拟机的数量)</description>
        <defaultValue>2</defaultValue>
        <type>java.lang.Integer</type>
    </config>

    <config>
        <category>kvm</category>
        <name>reservedMemory</name>
        <description>The memory capacity reserved on all KVM hosts. ZStack KVM agent is a python web server that needs some memory capacity to run. this value reserves a portion of memory for the agent as well as other host applications. The value can be overridden by system tag on individual host, cluster and zone level(所有的KVM主机预留的内存容量。ZStack中的KVM代理运行时是一个需要一部分内存容量去运行的python的web服务器,这个值为代理和其他主机应用程序预留了一部分内存,在单一主机上的、集群上的、区域上的系统标签可以覆盖这个值)</description>
        <defaultValue>512M</defaultValue>
    </config>
</globalConfig>

通过全局属性配置

备注:以下代码对应zstack.properties文件夹中相应的属性

@GlobalPropertyDefinition
public class KVMGlobalProperty {
    @GlobalProperty(name="KvmAgent.agentPackageName", defaultValue = "kvmagent-0.6.tar.gz")
    public static String AGENT_PACKAGE_NAME;
    @GlobalProperty(name="KvmAgent.agentUrlRootPath", defaultValue = "")
    public static String AGENT_URL_ROOT_PATH;
    @GlobalProperty(name="KvmAgent.agentUrlScheme", defaultValue = "http")
    public static String AGENT_URL_SCHEME;
}

通过系统标签配置

备注:以下代码对应数据库中相应的系统标签。

@TagDefinition
public class KVMSystemTags {
    public static final String QEMU_IMG_VERSION_TOKEN = "version";
    public static PatternedSystemTag QEMU_IMG_VERSION = new PatternedSystemTag(String.format("qemu-img::version::%s", QEMU_IMG_VERSION_TOKEN), HostVO.class);

    public static final String LIBVIRT_VERSION_TOKEN = "version";
    public static PatternedSystemTag LIBVIRT_VERSION = new PatternedSystemTag(String.format("libvirt::version::%s", LIBVIRT_VERSION_TOKEN), HostVO.class);

    public static final String HVM_CPU_FLAG_TOKEN = "flag";
    public static PatternedSystemTag HVM_CPU_FLAG = new PatternedSystemTag(String.format("hvm::%s", HVM_CPU_FLAG_TOKEN), HostVO.class);
}

载入服务

服务在Spring的bean的xml文件中声明自身,例如,kvm的部分声明类似于:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:zstack="http://zstack.org/schema/zstack"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    http://zstack.org/schema/zstack
    http://zstack.org/schema/zstack/plugin.xsd"
    default-init-method="init" default-destroy-method="destroy">

    <bean id="KvmHostReserveExtension" class="org.zstack.kvm.KvmHostReserveExtension">
        <zstack:plugin>
            <zstack:extension interface="org.zstack.header.Component" />
            <zstack:extension interface="org.zstack.header.allocator.HostReservedCapacityExtensionPoint" />
        </zstack:plugin>
    </bean>

    <bean id="KVMHostFactory" class="org.zstack.kvm.KVMHostFactory">
        <zstack:plugin>
            <zstack:extension interface="org.zstack.header.host.HypervisorFactory" />
            <zstack:extension interface="org.zstack.header.Component" />
            <zstack:extension interface="org.zstack.header.managementnode.ManagementNodeChangeListener" />
            <zstack:extension interface="org.zstack.header.volume.MaxDataVolumeNumberExtensionPoint" />
        </zstack:plugin>
    </bean>

    <bean id="KVMSecurityGroupBackend" class="org.zstack.kvm.KVMSecurityGroupBackend">
        <zstack:plugin>
            <zstack:extension interface="org.zstack.network.securitygroup.SecurityGroupHypervisorBackend" />
            <zstack:extension interface="org.zstack.kvm.KVMHostConnectExtensionPoint" />
        </zstack:plugin>
    </bean>  

    <bean id="KVMConsoleHypervisorBackend" class="org.zstack.kvm.KVMConsoleHypervisorBackend">
        <zstack:plugin>
            <zstack:extension interface="org.zstack.header.console.ConsoleHypervisorBackend"/>
        </zstack:plugin>
    </bean>  

    <bean id="KVMApiInterceptor" class="org.zstack.kvm.KVMApiInterceptor">
        <zstack:plugin>
            <zstack:extension interface="org.zstack.header.apimediator.ApiMessageInterceptor"/>
        </zstack:plugin>
    </bean>  
</beans>

管理节点,作为所有服务的容器,将在启动阶段读取它们的XML配置文件,载入每一个服务。

总结

在这篇文章中,我们演示了ZStack的进程内微服务架构。通过使用它,ZStack拥有一个非常干净的,松耦合的代码结构,这是创建一个强壮IaaS软件的基础。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • 转载本文需注明出处:微信公众号EAWorld,违者必究。 微服务架构现在是谈到企业应用架构时必聊的话题,微服务之所...
    72a1f772fe47阅读 3,476评论 0 38
  • 微服务最近非常流行,各大互联网公司纷纷采用微服务架构体系,微服务架构模式正在为敏捷部署以及复杂企业应用实施提供巨大...
    Sting阅读 9,069评论 0 57
  • “微服务架构”这一术语在前几年横空出世,用于描述这样一种特定的软件设计方法,即以若干组可独立部署的服务的方式进行软...
    ThoughtWorks阅读 16,904评论 1 71
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,637评论 18 139
  • 一、微服务将变得轻量级 架构需要由人去设计,这些人被称为架构师。或许很多人并未授予架构师的头衔,但自己却从事着架构...
    justmilkrain阅读 5,420评论 10 109