CloudFoundry DEA运作源码分析

长平狐 发布于 2012/08/24 10:07
阅读 396
收藏 0

解读下一代网络:算力网络正从理想照进现实!>>>

本文是对Cloud Foundry中的DEA组件源码的一些分析。有点流水帐的感觉,就事论事吧,同时因为本人能力有限,而且研究不深,错误在所难免。诸位就随便看看,希望大家能获得些帮助。有关Cloud Foundry的基础知识可以参考:http://qing.weibo.com/2294942122/88ca09aa330004r8.html, http://qing.weibo.com/2294942122/88ca09aa33000975.html

和其他模块一样,DEA也是使用ROR的目录组织方式,主要代码均集中在lib文件夹中,而在config文件夹下面有一个yaml配置文件。

yaml配置文件:

可以看到文件里面的注释相当完善了,配置的项基本上都可以看懂的。

1. lib文件夹中的代码:

精简版:这是下面所有内容的简单描述:

DEA通过dea.rb来启动,dea.rb调用agent.run来启动DEA服务。DEA启动时会向NATS订阅所有自己需要的消息,然后当消息传来时,进行相应的处理,包括status、start、stop、discover、heartbeat等各种处理。droplet在DEA中的运作主要是:首先将staged file拿过来,然后解压至instance目录,最后执行其中的startup脚本,停止则执行stop脚本。

接下来是比较详细的介绍:

1.1 dea.rb

dea.rb相当于一个启动dea的脚本,里面内容相当简单。主要就是负责config,这些config可以来自于config文件,比如yaml文件,或者传入的opts。然后就new了一个agent对象,调用run函数。这个agent就会负责处理所有的DEA承担的任务。

其中EM就是Event Machine,简单讲就是一个基于事件的工具,可以用来网络编程和并发编程。它主要的特色是免去了并发编程的繁杂,同时提供了易用的网络通讯接口。可以看这里:http://www.infoq.com/cn/news/2008/08/eventmachine

然后看lib文件夹,总共有三个文件,其中一个就是agent,另外两个是secure和directory。

1.2 secure:

暂时没有深入研究secure问题,所以DEA中的所有的secure环节会被略去。从大致的功能上讲,secure就负责划分user和group,每次的操作会验证用户所在的组的权限。同时创建的app也会chown给特定的group。

1.3 directory:

directory利用Rack::File提供了一个对root目录的定制访问功能,在agent中只有一个地方用到,就是start_file_viewer函数,这个函数的注释表示:This is for general access to the file system for the staged droplets。也说的很明白了。在DEA start时,会让EM去不断地启动droplets的文件访问,Periodically try to start the file viewer in case of port contention。

1.4 agent:

这个文件非常长,但是结构其实比较简单。各种参数大部分也能了解其含义了,这里也不说了。主要看agent类的结构。

首先当然有构造函数,主要就是设置参数,就是DEA环境的各种配置,没有其他好说的。

1.4.1 run函数

然后是run函数,我们知道了dea.rb文件中就是调用了这个run函数,那么说明这个函数可以把DEA启动起来,开始为CF提供服务了。这里是整篇文章的一个重点了,我们仔细的看下去:

  1. 创建一个pid file,就是创建一个process id,当前这个DEA就是使用这个id标注了。
  2. 配置了一些参数,这个就略去了。
  3. 在180行创建了所有需要的路径,有兴趣可以全部用log打出来看看。
  4. 将staged dir清除干净,这个dir就是用来存放被打包(staged)的droplet。
  5. 然后可以看到上面提到的start_file_viewer,开启staged dir的文件访问
  6. ['TERM', 'INT', 'QUIT'].each { |s| trap(s) { shutdown() } }

     如果EM捕捉到这些信号,就shutdown
  7. 然后就是最重要的开启NATS服务了,大部分的CF模块都通过NATS交互,NATS是一个消息中间件,用来订阅和发布JSON格式的消息。首先将自己注册到Component中,然后可以获得Component提供的uuid。然后就向NATS订阅了一堆的消息,每个消息都是DEA可以提供的一个功能,其他组件如果需要使用DEA的某个功能,就只需要向NATS发布一个相对应的消息即可。文章后面会对其中几个复杂的功能做一些介绍。
  8. 由于是启动,所以要恢复已经存在的droplets删除不需要的instances
  9. 向EM添加了定时运行的事件,比如heartbeat之类的。
  10. 最后向NATS发布一个dea start消息就算启动完成了

2. DEA的各个主要功能

接下来是DEA向NATS订阅的一些消息以及处理函数

2.1 dea.uuid.start:启动一个droplet的instance

就是让dea启动一个droplet,对应函数是process_dea_start,start函数也比较长,慢慢看。

  1. 从message里面解析出n多的参数,基本上就是droplet和app的一些参数。
  2. 做一些mem和fs usage的判断,是否有足够的mem和disk
  3. 接下来可以看到:
          tgz_file = File.join(@staged_dir, "#{sha1}.tgz")
          instance_dir = File.join(@apps_dir, "#{name}-#{instance_index}-#{instance_id}")
    这个tgz_file就是staged droplet。sha1当初研究了很久,不解其意,这里可以看到其实就是droplet的一个标识,目前手头没有实例可以验证,但是app的目录名称应该也和这个sha1相关。
  4. 然后创建了一个instance的map,这个map包含了instance的所有信息,然后处理了一下DEA自己的域。
  5. 然后可以看到一个lambda: start_operation。顾名思义就是用来start一个instance的。前面都是一些特殊的配置,暂时不研究了,看主要部分:line 669,这里将DEA项目的bin目录下的close_fds文件拷贝至instance目录下,然后执行,看字面意思是prepare。line697: 获得一个app_env数组,就是instance的一些环境变量,后面会把每个值都export。line 719,就是启动instance的代码了,可以看到只是简单的调用了startup脚本而已,这个脚本就是在stage的时候由stager加入的启动脚本。
  6. 然后启动了一个纤程Fiber,首先将staged文件放置到staged dir中(如果有cache最好,否则会去shared folder取,或者会HTTP去读),然后调用start_operation lambda。

2.2 dea.status&droplet.status:查看状态

这两个比较简单,就是把一些状态的字段(name, host, port, mem, disk, uri...)返回回去。

2.3 dea.discover:发现DEA

意思就是当一个droplet需要一个instance时,cloud controller会向NATS广播dea.discover消息,那么DEA收到之后,会根据自己情况选择是否回复此消息。当CC受到第一个回复时,就是用发送这个消息的DEA创建instance。

我们可以看到process_dea_discover这个函数首先主要判断是否能够跑这个app,包括mem、disk、runtime等限制条件。然后会根据DEA当前的情况计算一个delay,然后在delay之后发送response。这个delay相当于在做balance,比如:一般mem使用量大的DEA会delay比较长,所以比较难以被选中。

2.4 dea.find.droplet:查找droplet

很简单,就是通过droplet id查找对应的droplet信息

2.5 dea.update:更改droplet的URI

就是message中包含了droplet id,然后一个uri,那么DEA会修改droplet当前的uri,然后去router做修改

2.6 dea.stop:停止droplet的instance

通过message中指定的droplet id找到droplet,然后根据其余的信息(version, instance id, index, state)filter instance,将这些filter出来的instances停掉。 stop instance流程:首先从router unregister,然后向NATS发布本instance stop的消息,然后调用instance目录下的stop脚本来停止instance,最后将instance目录清理干净

2.7 router.start:向router注册

这里涉及到router的运作方式,router也是通过NATS和其他组件协作的,也就是发布router.start来告诉别人router已经就位,你们可以来注册了。为了应付任何时候可能加入的组件,router会不断地发送router.start消息。而dea中也会每次都傻傻的接受到router.start信息,同时做出处理。所以可以看到dea.log里面会有大量的“DEA received router start message”字段。恩,看起来这么做还是有必要的。我们设想重启了router,那么router必须重新要求所有app来注册,那么他也只能发一个router.start,如果dea做过一次就不做了,那么新的router就无法更新了。

然后处理router.start的过程很简单,就是将所有running的组件注册到router中去。

其他的就不提了,也比较简单,什么heartbeat之类的,大家都懂的

(这里还有一块内容需要补充,就是定期执行的一些操作,比如app状态(CPU,内存等)的update等,还是有一定学习意义的)


原文链接:http://blog.csdn.net/cherry_sun/article/details/7696482
加载中
返回顶部
顶部