原文链接:http://www.programmer.com.cn/14472/

历经一年多的发展,Cloud Foundry的架构设计和实现有了众多改进和优化。为了便于大家了解和深入研究首个开源PaaS平台——Cloud Foundry,《程序员》杂志携手Cloud Foundry社区开设了“深入Cloud Foundry”专栏,旨在从架构组成、核心模块功能、源代码分析等角度来全面剖析Cloud Foundry,同时会结合各行业的典型案例来讲解Cloud Foudry在具体应用场景中的表现。

架构设计及核心组件

从总体上看,Cloud Foundry的架构如图1所示。

图1 Cloud Foundry架构图

经过一年多的发展,Cloud Foundry的组件增加了很多。但核心组件并没有变化,增加的组件是原架构基础上的细化和专门化。Stager组件解决了打包(Stage)过程需要操作大量文件且操作时间长的问题,所以它作为独立进程,使打包工作异步进行,不阻塞作为核心组件的Cloud Controller。

下面是对Cloud Foundry核心组件的描述。

Router。顾名思义,Router组件在Cloud Foundry中是对所有进来的请求进行路由。进入Router的请求主要有两类。

  • 第一类是来自VMC Client或者STS的,由Cloud Foundry使用者发出,叫做管理请求。这类请求会被路由到Cloud Controller组件处理。
  • 第二类是对所部署的App的访问请求。这部分请求会被路由到App execution,即DEA组件中。简单地说,所有进入Cloud Foundry系统的请求都会经过Router组件。Router组件是可扩展的,由多个 Router共同处理进来的请求。但如何对Router做负载均衡不属于Cloud Foundry的实现范围。Cloud Foundry只须保证所有Router都可以处理任何请求,而管理员可用DNS实现负载均衡,也可部署专用硬件来实现,或者简单点,弄个Nginx做负载均衡。

在第一个版本中,Router工作由router.rb来做,所有请求都必须经过Ruby代码处理转发。这个设计简单直接,只是容易引起性能问题,新版中做了如下改进,如图2所示(左侧为第一版本,右侧为新版)。

图2 Router工作过程(新旧版对比)

  • 使用Nginx的Lua扩展,在Lua中加入URL查询和统计的逻辑。
  • 如果Lua不知道当前的URL应该路由给哪一个DEA,则会发一个查询请求到router_uls_server.rb(也就是图2中的“Upstream Locator SVC”)。
  • router_uls_server.rb是一个简单的Sinatra应用,它存储了所有URL与DEA IP:Port对应关系。另外,它也管理了请求的Session数据。

这样一来,大量的业务请求在Lua查询过并保存位置后,都由Nginx直接转发,不再经过Router,性能和稳定性都大幅提高。

Router的设计中有个难点:我们知道HTTP请求是有上下文的,那如何保证请求的上下文完整呢?简单来说,就是如何保证有上下文的请求每次都可以找到同一个DEA处理?Cloud Foundry是支持Session的,当Router发现用户请求中带了Cookie信息,它会在Cookie里暗藏一个应用实例的id。当有新请求时,Router通过解析Cookie得到上次的应用实例,然后转发到同一台DEA上。这信息与上面的查询类似,会先存在于Upstream Locator SVC中,当Lua知道后会保存在Nginx内部提高效率。

DEA (Droplet Execution Agency)。首先要解释下什么叫做Droplet。在Cloud Foundry中,Droplet指把提交的源代码及Cloud Foundry配置好的运行环境(如Java Web就是一个Tomcat),再加一些控制脚本,如start/stop等,全部打包在一起的tar文件。Staging App是指制作Droplet,然后把它存储起来的过程。Cloud Foundry会保存这个Droplet,直到启动(start)一个App时,一台部署了DEA模块的服务器会来拿这个Droplet的副本去运行。因此,如果将App扩展到10个实例(instance),那么这个Droplet就会被复制10份,供10台DEA服务器运行。

图3是DEA模块的架构图(左侧为第一版本,右侧为新版)。

图3 DEA模块架构图(新旧版对比)

Cloud Foundry刚推出时,用户部署的应用可以在内网畅通无阻,跑满CPU,占尽内存,写满磁盘。因此,Cloud Foundry开发出了Warden,用这个程序运行容器解决这一问题。这个容器提供了一个隔绝环境,Droplet只可以获得受限的CPU、内存、磁盘访问权限和网络权限。

Warden在Linux上的实现是将Linux 内核的资源分成若干个namespace加以区分,底层的机制是CGROUP。这样的设计比虚拟机性能好,启动更快,也能够获得足够的安全性。

DEA的运行原理没有发生根本改变:Cloud Controller模块会发送start/stop等基本的App管理请求给DEA,dea.rb接收这些请求,然后从blobstore下载合适的Droplet。前面说到Droplet是一个带有运行脚本和运行环境的tar包,DEA只需要把它拿过来解压,并执行里面的start脚本,就可让应用运行起来,App也就可以被访问了。换句话说,就是这台服务器的某一个端口已经在待命,只要有request从这个端口进来,这个App就可以接收并返回正确的信息。

接着,dea.rb要做以下一些善后的工作。

把这个信息告诉Router模块(前面说到,所有进入Cloud Foundry的请求都是由Router模块处理并转发的,包括用户对App的访问请求。一个App运行起来后,需要告诉Router,让它根据负载均衡等原则把合适的请求转进来,使这个App的实例能够干活)。

  • 一些统计性的工作。例如要把这个用户又新部署了一个App告诉Cloud Controller,以作quota控制等。
  • 把运行信息告诉Health Manager模块,实时报告该App的实例运行情况。

另外,DEA还要负责部分对Droplet的查询工作。例如,如果用户想通过Cloud Controller查询一个App的log信息,那么DEA需要从该Droplet里取到log返回等。

Cloud Controller。Cloud Foundry的管理模块。简单来说,就是与VMC和STS交互的服务器端,它收到指令后发消息到各模快,管理整个云的运行,相当于Cloud Foundry的大脑。

以部署一个App到Cloud Foundry为例。在输入push命令后,VMC开始工作。在做完一轮用户鉴权、查看所部署的App数量是否超过预定数额、问了一堆相关App的问题后,需要发4个指令。

  • 发一个POST到“apps”,创建一个App;
  • 发一个PUT到“apps/:name/application”,上传App;
  • 发一个GET到“apps/:name/”,取得App状态,查看是否已启动;
  • 如果没有启动,发一个PUT到“apps/:name/”,使其启动。

第一版的Cloud Controller是基于Ruby on Rails的,新版的Cloud Controller用Sinatra进行了重写,并把部分工作独立成组件, 使Cloud Controller变得更轻。另一个重要的改进是,第一个版本的Droplet是通过NFS共享的,这样会带来安全、性能等方面的问题,新版中采用了自己开发的blobstore存放Droplet。

随着Cloud Foundry逐渐成熟,权限管理功能在新版本中逐渐完善。在原有的用户模型基础上,加入了组织和用户空间等概念,细化了管理模型。用户模型的认证是由UAA模块实现的。在企业环境中,如果用Cloud Foundry的开源代码搭建私有云,那么它可以与企业已有的认证系统进行整合,例如LDAP、CAS等。权限控制是由ACM模块实现的。图4给出了用户访问Cloud Controller某个API的过程。

图4 用户访问Cloud Controller某个API的过程

Health Manager。它做的事情不复杂,简单地说,是从各个DEA获得运行信息,然后进行统计分析、报告、发出告警等。

Services。服务应属于PaaS的第三层。Cloud Foundry把Service模块设计成一个独立的、插件式的模块,便于第三方方便地把自己的服务整合成Cloud Foundry服务。在GitHub上有以下两个相关的子项目值得关注。

  • vcap-services-base:顾名思义,它包括Cloud Foundry服务的框架及核心类库。如果开发自定义服务,需要引用到里面的类。
  • vcap-services:目前Cloud Foundry支持的,包括官方及大部分第三方贡献的服务。这个项目的根文件目录是根据服务名称划分的,可以选择其中自己感兴趣的来研究。

由此可见,Service模块十分方便为第三方提供自定义服务。从架构来说, Cloud Foundry服务部分使用了模板方法设计模式,可通过重写钩子方法来实现自己的服务。如果不需要特别逻辑则可以使用默认方法。

现实情况中,种种原因使有些系统服务难以或不愿意迁移到云端,为此Cloud Foundry 引入了Service Broker模块。

Service Broker可以使部署在Cloud Foundry上的应用能访问本地服务。Service Broker的使用方法如下。

  • 准备被访问的服务。以PostgreSQL为例,配置好程序和防火墙,让其可以通过类似 postgres://xyzhr:secret@db.xyzcorp.com:5432/xyz_hr_db的URI访问。
  • 注册以上URI到Service Broker。

使用Service Broker暴露的服务与使用Cloud Foundry的系统服务无异,准备被访问的服务中的访问服务的URI通过环境变量传给App。App通过URI访问暴露出来的服务,这过程不必通过Service Broker。这个过程如图5所示,与使用系统服务类似,此处不再赘述。

图5 使用Service Broker所暴露的服务的过程

NATS (Message bus)。 Cloud Foundry的架构是基于消息发布和订阅的。联系各模块的是一个叫NATS的组件。NATS是由Cloud Foundry开发的一个基于事件驱动的、轻量级的消息系统。它基于EventMachine实现。第一版本Cloud Foundry被人诟病的一个问题就是NATS服务器是单节点的,让人不大放心。新版NATS能支持多服务器节点,NATS服务器间通过THIN来做通信。NATS的GitHub开源地址是:https://github.com/derekcollison/nats。代码量不多但设计很精妙,推荐研究它的源代码。

Cloud Foundry各种优秀特性均源于消息通信架构。每台服务器上的各模块会根据当前的行为,向对应主题发布消息,同时也按照需要监听多个主题,彼此以消息进行通信。

可以说,Cloud Foundry的核心是一套消息系统,如果想了解Cloud Foundry的来龙去脉,跟踪它里面复杂的消息机制是非常好的方法。举个最简单的例子,一个装有DEA组件的服务器为加强云的计算能力,被加入到Cloud Foundry集群中。它首先需要表明已准备好随时提供服务,Cloud Controller可将App部署到它这里,Router也可将相关的请求交给它处理;Health Manger可定时为它体检等,它会发布一条消息到主题“dea.start”:

NATS.publish(‘dea.start’, @hello_message_json)

@hello_message_json包括DEA的UUID、ip、 port、版本信息等内容。Cloud Controller、Router、Health Manger及其他模块会监听这个主题,得到通知,各自干活。

理解Cloud Foundry的最好方法其实是选定某一操作,如部署一个App、创建服务等,以消息为线索,跟踪到各模块,看其如何处理。这样就可以观察到整个Cloud Foundry的工作流程。本专栏第2篇文章将专门介绍如何以NATS为主线理解Cloud Foundry原理,这里就不做过多叙述了。

总结

在过去的一年中,Cloud Foundry发生了很多改变,足可看出Cloud Foundry社区的活跃。非常希望本文已把Cloud Foundry的原理讲得足够明白,但请不要把本文作为参考手册使用,在VMware中国开发者关系团队的努力下,Cloud Foundry的文档相当完善,强烈推荐以其作为参考(网址:www.cloudfoundry.cn)。

Cloud Foundry技术全貌及核心组件分析的更多相关文章

  1. Cloud Foundry技术资料汇总

    来自:http://cnblog.cloudfoundry.com/2012/05/ 本文是Cloud Foundry的一个简单上手指南和资料汇总,内容将根据产品的发布定期更新. Cloud Foun ...

  2. Cloud Foundry和微服务Meetup重磅来袭

    CF 同学们: Cloud Foundry 2016 上海 Meetup 将在10月22日在上海港汇广场进行! 想要参会的小伙伴,请直戳  ~ 在过去的一年,CF 的技术有很多进展,微服务也是2016 ...

  3. 【Cloud Foundry】Could Foundry学习(二)——核心组件分析

    在阅读的过程中有不论什么问题,欢迎一起交流 邮箱:1494713801@qq.com    QQ:1494713801 Cloud Foundry核心组件架构图例如以下: 主要组件:     Clou ...

  4. Cloud Foundry中 JasperReports service集成

    Cloud Foundry作为业界第一个开源的PaaS解决方案,正越来越多的被业界接受和认可.随着PaaS的发展,Cloud Foundry顺应潮流,充分发挥开源项目的特点,到目前为止,已经支持了大批 ...

  5. Cloud Foundry warden container 安全性探讨

    本文将从Cloud Foundry中warden container的几个方面探讨warden container的安全性. 1. warden container互訪 1.1.  互訪原理· 在Cl ...

  6. Cloud Foundry中warden的网络设计实现——iptable规则配置

    在Cloud Foundry v2版本号中,该平台使用warden技术来实现用户应用实例执行的资源控制与隔离. 简要的介绍下warden,就是dea_ng假设须要执行用户应用实例(本文暂不考虑ward ...

  7. Cloud Foundry中DEA启动应用实例时环境变量的使用

    在Cloud Foundry v2中,当应用用户须要启动应用的实例时.用户通过cf CLI向cloud controller发送请求,而cloud controller通过NATS向DEA转发启动请求 ...

  8. 12月2日,上海Cloud Foundry Summit, Azure Cloud Foundry 团队期待和你见面!

    12月2日,上海Cloud Foundry Summit, Azure Cloud Foundry 团队期待和你见面! 12日2日对中国Cloud Foundry的用户和开源社区来说,是极有意义的一天 ...

  9. Cloud Foundry中gorouter对StickySession的支持

    Cloud Foundry作为业界出众的PaaS平台,在应用的可扩展性方面做得很优秀. 详细来讲,在一个应用须要横向伸展的时候,Cloud Foundry能够轻松地帮助用户做好伸展工作,也就是创建出一 ...

随机推荐

  1. elasticsearch安装与使用(5)-- search guard安装与配置

    一.安装search guard插件必须要安装两部分: ①search-guard-xx ②search-guard-ssl (XX指的是与elasticsearch引擎对应的版本) github地址 ...

  2. WPF教程六:布局之Grid面板

    Grid:网格面板 Grid顾名思义就是“网格”,以表格形式布局元素,对于整个面板上的元素进行布局,它的子控件被放在一个一个事先定义好的小格子里面,整齐配列. Grid和其他各个Panel比较起来,功 ...

  3. 网络配置br0 brtcl

    1.brctl addbr br0        如果根据第3步,那这里不用写 2.brctl addif br0 eth0    如果第3步写了,这里也不用 这时候用ssh应该会断网... 3.设置 ...

  4. Spring下获取项目根路径--good

    Spring 在 org.springframework.web.util 包中提供了几个特殊用途的 Servlet 监听器,正确地使用它们可以完成一些特定需求的功能.比如某些第三方工具支持通过 ${ ...

  5. android jni aotf 错误

    在jni中希望将字符串转成浮点型数据,使用了atof函数.出现错误: failed: Cannot load library: soinfo_relocate(linker.cpp:975): can ...

  6. C++ 基本的输入输出

    C++ 基本的输入输出C++ 标准库提供了一组丰富的输入/输出功能,我们将在后续的章节进行介绍.本章将讨论 C++ 编程中最基本和最常见的 I/O 操作. C++ 的 I/O 发生在流中,流是字节序列 ...

  7. Android camera 竖直拍照 获取竖直方向照片

    竖直拍照 if (Integer.parseInt(Build.VERSION.SDK) >= 8) {     camera.setDisplayOrientation(90); } else ...

  8. 在VS中写js的同学注意了。。。。。。。。。。。。。。。。。。。

    在vs中安装扩展jsdoc就可以实现这个功能

  9. write solid code 零散(原文)

    整理下目录,看了这个文件,幸好未删除. 以下是<write solid code>中的原文摘录. 1.How could I have prevented this bug? 2.How ...

  10. sql 字符串操作

    SQL Server之字符串函数   以下所有例子均Studnet表为例:  计算字符串长度len()用来计算字符串的长度 select sname ,len(sname) from student ...