领域修炼之路

如何快速构建大规模应用集群(开篇)

俗话说,聚沙成塔,又说,一沙一世界。在软件开发人员的世界中,一个软件应用可以从一体两面进行分析:技术和业务。软件的粒度在微观和宏观两个方向延伸,不同的粒度层面代表着不一样的思考纬度。

在技术方向上,随着软硬件技术的不断发展,信息技术在生产活动中的不断深化应用,技术实践积累不断提高,技术抽象不断完善, 技术关注点的层次也不断提高。

从最初的二进制指令,经过抽象提升到汇编、IL,再进一步到达了过程、方法和数据结构; 随着抽象层次继续提升,粒度继续放大,发展到基于类抽象和接口定义契约的面向对象层面,人们总结出各种设计模式; 在开始面向组件,服务的设计建模时,EJB、Spring框架/IOC容器、SOA服务等技术体系出现并主导这一层面。

这一切看上去阐述的很粗糙,但从中仍可以看到,领域研究的粒度是不断放大的,随着某一层次的研究经过长时间的实践积累,量变引发质变,就开始 向更高一层进行突破,新的技术开始出现,而容器技术,正是可以看做是又一次质变的结果。

移动互联网的飞速发展使得移动APP成为业务交互的入口,海量数据跨越时空限制,被互联网高速公路快速汇集, 单一系统的服务再也无法满足处理性能要求,人们开始寻找新的替代方案,在不断的探索,研究,实践和修正过程中,分布式集群、微服务设计理论与实践逐渐成熟,云计算、大数据处理开始主导当前技术潮流,这也成为容器技术得以成长的土壤。

微服务

业务系统随着单机应用,内部互联到INTERNET,移动互联,单一进程中承载所有功能的技术架构被复杂度,可维护性和海量用户带来的负载压力所击溃。应对之法就是拆分,如何拆分,何处着手,怎么控制,带来哪些新的问题,下面我们从一个典型的应用系统进行分析。

上图是一个典型的应用系统,它需要为用户提供外部访问接口,处理内部各种业务逻辑,将数据存储到数据库系统,在处理业务的过程中,系统可能需要与第三方系统或设备交换数据,并且为管理用户提供WEB管理入口。

如何对上述应用系统进行拆分?典型的方法是按业务功能。当然,既可以纵向拆分也可以横向拆分,或者两者结合。在实践过程中,仍需要结合项目实际情况具体把握。

下图是按功能拆分微服务后的系统结构图,从图上可以看出,基于微服务的新系统功能模块结构清晰,但额外引入了服务间调用的复杂性,同时,也需要一个新的API Gateway来聚合对外提供服务的接口。

微服务真的如此简单?答案当然不是。一种新的解决方案需要在各个层面,各个角度做出权衡和决策,下面我们以一个服务单元为视角,看一下需要面对哪些问题:

如图中所示,对于一个微服务实例,我们至少需要考虑以下问题:

  • 接口如何定义?采用REST还是其他?

  • 采用何种通信模型?RPC,消息,同步/异步,响应式还是事件驱动?

  • 服务是按何种粒度切分的?纵向,横向,有无其他更好的方案?

  • 服务如何被调用?其他服务如何发现此服务的存在?内部服务和外部服务如何区分?

  • 服务处理的数据如何存储?

  • 服务如何部署?单实例,多实例,如何支持负载均衡?

  • 服务如何治理?是否公开了测量指标,怎么监控这些指标?日志是否需要归集?如何控制服务的安全?

针对这些问题,每一个都有多种不同的候选方案,此处暂不展开详细的探讨。

容器

传统的单进程应用系统在部署时通常会独占物理主机的所有硬件资源。在应用系统被拆分成微服务后,单个服务占用整机物理资源会造成很大的闲置浪费,一种方案是通过虚拟机进行隔离,当部署数十甚至上百个虚拟机时,虚拟机本身的资源消耗也会造成巨大的资源浪费。

当前,解决微服务之间资源竞争的最佳方案是通过容器隔离。相比于虚拟机技术,容器技术的优势在于它包含应用及其所有依赖,与其它容器共享系统内核,在主机系统的用户空间内以隔离进程方式运行,并且仅依赖操作系统,不再依赖其他基础设施。而Docker已经成为容器技术的事实标准。

DC/OS

随着业务系统规模的不断扩大,微服务数量迅速增加,而为了确保服务的可靠性,单一服务需要多实例提供容错和负载,整个系统的服务实例以乘积的规模扩张,很快服务关系将变得错综复杂而难以维护,如下图所示:

如何管理、调度和运维如此复杂的服务拓扑?这对架构设计者来说是一个巨大的挑战。

下面,让我们先抛却服务内部及服务之间复杂的业务逻辑关系,视野从高空投射,我们会看到下面这张图谱。众多服务实例被混杂安置在一组硬件集群中。

如同服务实例扩张所带来的管理问题,硬件集群的扩张同样需要管理,因此我们需要增加一个管理的主节点,通过它我们可以查看主机节点的状态,主机上微服务的部署信息以及微服务的状态与管理。于是我们有了如下的方案:

在这种拓扑下,单个Master主节点是无法承载生成环境对高可靠性的要求的,因此,我们需要为主节点添加HA,当前提供服务发现,一致性和Leader选举的基础服务有zookeeper,etcd,consul等,这里暂不管这些服务的差别,我们采用zookeeper实现Master主节点的Quorum,如下图所示:

从上述架构可以看出,主节点对服务节点主机集群了如指掌,因此它可以及时掌控所有服务节点的资源状态,并与Slave主机节点互通消息。既然如此,我们的想法可以更进一步,通过主节点与Slave节点之间的通道,我们可以将服务部署到各个Slave节点。

如何部署有多种实现策略,其中的一种是由主节点告诉应用服务当前有多少资源可用,由应用服务根据自身特点决定需要多少资源,如果资源需求满足,应用服务锁定资源,并通过Master主节点将服务包分发到提供资源的Slave主机,并在Slave主机上启动服务。这里有两个概念:与Master主节点沟通分配资源的称为调度器,在Slave主机启动服务的称为执行器

如上所述,经过Master主节点和应用调度器的协调配合,服务可以动态部署到主机集群中,而不需要直接一个一个手动部署服务。这里的调度策略称之为“两级调度”。

前述过程完成了服务在集群中动态部署,这些服务最终是要向外部用户提供服务的,因此需要有网络入口。外部用户如何从INTERNET访问到我们提供的服务?常用的解决方案是以云端SLB、ELB、DNS等为入口提供接入负载。在内部集群之前用Nginx、HAProxy等提供内部负载调度,解决方案如下图所示:

为了进一步提升安全和可控性,我们需要将内部主机集群与外部INTERNET之间架设一层缓冲区,位于缓冲区内的主机通常有公网IP地址,称之为Public Agents,而内部隔离区内的主机无法被外部直接访问,称之为Private Agents。负责内部负载调度和服务发现的Nginx和HAProxy等通常部署在缓冲区内的Public Agents上。因此,新的调整方案的架构图如下:

至此,我们揭开了DC/OS即数据中心操作系统的面纱一角。

DC/OS即数据中心操作系统,是一个架构于现有单机操作系统之上为上层应用提供CPU、内存、磁盘和网络等规模化集群资源的分配调度的分布式操作系统。DC/OS是Mesos、Marathon、Docker及其它相关技术的一个框架整合,适用于快速构建大规模异构应用集群。

结论

本文是一时之乘兴之作,疏漏之处难免,欢迎指正。在后续文章中,将继续围绕DC/OS探讨快速构建可靠的大规模应用集群详细过程。更多信息请关注我的新书《DC/OS修炼之路》

chrisrc wechat
更多信息请订阅我的微信订阅号