Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1906358
  • 博文数量: 217
  • 博客积分: 4362
  • 博客等级: 上校
  • 技术积分: 4180
  • 用 户 组: 普通用户
  • 注册时间: 2009-09-20 09:31
文章分类

全部博文(217)

文章存档

2017年(1)

2015年(2)

2014年(2)

2013年(6)

2012年(42)

2011年(119)

2010年(28)

2009年(17)

分类: Python/Ruby

2011-11-10 08:52:25

最近在学习《Erlang And OTP in Action》,其中一些部分英文的看的不是很懂,为了能够弄懂,我试着翻译了:

Chapter 4 OTP的应用程序和监督
这章包括:
■OTP应用程序的介绍
■OTP管理程序的容错
■使用EDoc自成文档

Eralng/OTP循环系统最终的目的是构建一个可靠、容错的系统。在第三章中,我们介绍了这个循环系统的核心概念,建立了一个简单的RPC服务器;我们现在更深入一些,来教你如何正确地把这个打包,把它做成一个容错的、高产品质量的服务。在做这个之前,我们先来介绍两个基本的概念:

■把Erlang中有关联的模块打成包就是应用程序。这里关注的重点不是为分布的代码打包,而是能够把一堆的模块当作一个实体来对待。尽管OTP应用程序仅仅是可以被其他程序调用的一些库代码,但是通常它们更像一个拥有生命的生物:它们自已开始,干它们自已喜欢的事情,之后死亡。
■监督程序是OTP重要特性之一。它们监视着其它进程,如果某些事情出现错误,就会立刻采取行动,重新启动失败的进程,或者可能会升级这个问题到一个更高的水平。监督树中的分层监督程序可以让你建立高容错系统。

在这一章中,我们不会过分深入到应用程序和监督程序的理论和实践环节。我们更多地关注如何充实在第三章中所写的模块,包装它成为一个OTP应用程序并且为它建立一个监督程序。我们将仔细检查这些任务的最基本方面,解释你在每一步所干的事情。之后,在本书的第二部分,我们将会深入下去,讨论所有可用的观点,这些观点对高级应用程序,处理应用程序内部代码,将各种应用程序打包成一个大结构的版本都是可用的。

4.1 OTP应用程序
我们将从如何组织你的代码,让它能够更好地适应一个正常的Erlang/OTP系统开始。由于各种原因,那些不熟悉这个系统的人,这个主题对他们来说会有许多的迷惑。我们第一次用Erlang进行工作的时候,由于比较少的文档和例子,OTP是比较神奇的。我们都是通过相似路径来掌握这个强有力的系统的,包括许多尝试和错误,甚至包括Erlang邮件列表中各个老前辈那里的暗示。幸运的是,当你把你的思想从基本观点扩展开来之后,它将会相当简单。
    术语:applications
在OTP的上下文中,“application”有一个特殊意思:一个application是软件的一部分,它是由若干个模块和一些附加的元数据文件组成,根据一定约定组织在磁盘上的。这样的话,可以让系统知道哪些应用程序当前已经安装,例如,可以让你通过名字来启动或关闭一个application。
从现在开始,你假设我们讨论的是OTP中的应用程序中,除非你已经很清楚了上下文。

很明显,OTP应用程序仅仅是一些有关联的代码。它们就是我们据说的库应用程序:就是可以被其它应用程序可以调用的模块的集合(Erlang/OTP中的“stdlib”就是库应用程序的一个例子)。OTP应用程序通常是有生命的东西,它们可以启动,运行一段时间,到最后关闭。我们所说的这些可以看成工作应用程序(active applications)。一个工作应用程序有一个根监督程序(root supervisor),它的主要职责就是管理这些应用程序的进程。我们在4.2章节中会更加深入地介绍监督程序。
4.1.1 OTP应用程序的组织
工作应用程序VS库应用程序:
        不管工作应用程序,还是库应用程序都是使用相同的目录分层和元数据文件,并且两个都符合所有应用程序的框架。它们之间的主要区别是工作应用程序有一个循环的生命,而且是在有用的情况下去启动它。刚好相反的是,库应用程序是由其它应用程序把有用的模块被动收集在一起的集合,它们没必要启动和关闭。因为本书重点是在写工作应用程序,当我们提到应用程序的时候,你就可以把它当作工作应用程序,除非上下文已经很明显。
创建一个OTP应用程序主要包括安装一个标准的目录结构和写一些元数据。这些元数据告诉系统在它启动和关闭的时候应该知道哪些东西。它也指定应用程序的依赖关系,比如,其它应用程序在开始和启动之前应该需要什么。对于工作应用程序来说,还需要一定的编码,这些知识我们会在4.1.3中说到。
 
图4.1 OTP应用程序目录分层,这些目录名包括一个版本号。这些标准的子
目录是doc,ebin,include,priv,src。其中,只有ebin目录是必需的。

Erlang/OTP应用程序采用一个简单的目录分层,如图4.1所示。大多数熟悉Erlang,知道OTP的人为他们的应用程序使用的仍然是这种的目录结构,但是没有元数据。
你应该替换“”为你自已应用程序的名字;在这里,它是“tcp_rpc”。“-”是一个可选的:在修改的过程当中,它是没用的,但当你发送你的应用程序的时候,你通常使用像这样的目录结构“      tcp_rpc-1.0.2”会更容易些。图4.1中的子目录的名字没有什么可多说的,而表4.1则更详细地描述了各个子目录。

表4.1 应用程序的子目录
目录 描述
doc 文档。如果你从EDoc中产生新的文档,你就要修改你的概述文档(.edoc),其它的文件都是自动产生的。
ebin 编译所产生的代码(.beam文件)。.app文件也在这个目录下,它里面包括了应用程序的元数据。
include 公开的头文件。所有公共API中所用到的.hrl文件都要放在这个目录下。仅在代码中使用,不打算作为公共资源的私有文件应放在src目录下,和你的代码在一起。
priv 你的应用程序所需要的二进制位。这些可以是模板文件,共享对象,或者是共享的链接库。一个应用程序的priv目录是很容易找到的:调用函    code:priv_dir(),可以将priv目录的全路径当作一个字符串返回。
src 你的应用程序的源代码。也就是Erlang的.erl文件和你内部全用的.hrl文件,也包括任何ASN.1,YECC,MIB和其它源文件(如果你的应用程序没有源代码,在你所交付的东西中,这个目录可以省略或者可以置为空)。

让我们继续前进,现在创建一个目录结构把你第三章中的代码移到这个src目录中。
4.1.2 添加应用程序的元数据
既然你已经有了应用程序预期的目录分层,接下来就是添加OTP所需要的元数据。存放在ebin目录下的.app文件是一个文件文件,它记录的是Erlang中无格式的项。ebin/tcp_rpc.app文件清单如下,它就展示了你的tcp_rpc应用程序的元数据。
 

这个.app文件是用来理解应用程序是如何被启动的,在系统中,是如何与其它应用程序协同工作的。重复之前我们所说的,这里首先关注的不是制作发布的包,而是制作具有启动、关闭、监督和升级功能的单元。
.app(发音是“doc app”)文件的格式是很容易理解的。除了规范的Erlang备注外,它包括一个单一的Erlang项来结束:一个具有三个元素的元组“{application,...,...}..”。第二个元素是应用程序的名字,它是一个原子,在这里是“tcp_rpc”。第三个元素是一个列表,这个参数是由“{Key,Value}”这样的键值对组成,其中一些键值对是需要的,而另外一些是不需要的。这里包括进来的是大多数应用程序最主要的。在本书的第二部分,我们将再次详细地讨论这些参数。

表4.2描述的是这里所使用的参数,之前在清单4.1中出现过的。
部分 描述
description 应用程序的简短描述。通常是一个或者两个句子,只要你喜欢就行。
vsn 你的应用程序的版本。这个版本字符串可以你任何你喜欢的,但是我们建议你能够尝试规范的数字模式:<主要>.<次要>.<补丁>。哪怕你所使用的字符串对Erlang/OTP没有任何干扰,一些程序在分列这些字符串的时候还会遇到问题。
modules 在你的应用程序中所有的模块的列表。这个列表不好维护,但是有一些工具可以帮助你来完成。列表的顺序没有关系,但如果你能够按照字母顺序表进行维护的话,会很容易进行维护的。
registered 回调已经注册的Erlang进程(2.13.3部分中有所提到)时,可以使用它们的名字来唯一确定。这个通常是为了解决系统服务和与之相似的服务中。尽管包含在.app文件中的这个实体的注册名字是列表,但这可以让OTP系统知道应用程序应该注册什么名字,帮助系统升级,如果发生重复命名可以提出警告。
applications 在整个应用程序开始之前,所有的内部应用程序都要被启动。应用程序通常情况下之间是有依赖关系的。因为这些都是活着的系统,所以只有这些所依赖的应用程序可以使用并且已经启动的情况下,这些工作应用程序才可以使用。
mod 告诉OTP系统如何启动你的应用程序。这个值是由一个元组包含模块名称的,其中的启动参数是可以变化的(不要使用这些参数来作为常规的配置信息,而要使用专门的配置文件)。给这里的模块起名字要使用应用程序的特性,这在4.3.1中会作解释。

到目前为止,你已经创建了目录结构并且把对应的元数据放到了适当的位置(如果你还没有创建/ebin/tcp_rpc.app文件,那请你创建之后再继续下面的内容),但你还没有做一个完整应用程序所需要的一切东西。就像表4.2中提到“mod”参数的描述,你也应该找一个着手点来开始你的应用程序,一个模块的表单中会体现一个应用程序的特性。这将是下一章的任务。
4.1.3 应用程序的特性
给应用程序的监督模块命名:
使用_app是应用程序的监督模块的一般命名习惯。
每一个应用程序都需要一个模块来体现它的特性,这个模块为整个系统提供启动逻辑。至少它可以提供根监督程序是从哪里启动的,监督程序是所有进程的父进程,也是应用程序的一部分。特性模块也可以根据系统的需求,干一些其它事情。我们会在4.2中介绍管理程序。“src/tr_app.erl”文件实现了应用程序特性,现在我们把主要精力集中在它上面,请看下面的列表(去掉了备注)。
 


这个小的模块应该很容易被理解,你可以复习一下第2章的内容来加深对特性实现模块的理解。这个时候,你正在实现应用程序的特性,需要你导出start/2和stop/1这样的回调函数(除了这些回调函数,这个模块没有使用其它的用户API,因此没有其它的导出)。
在这里,stop/1这个回调函数是比较简单的,除了关闭之外,你不需要干其它的事情了,因此你可以忽略参数,直接返回一个ok原子。你真正应该做的事情是在start/2这个函数中。当OTP系统启动你的应用程序的时候,这个函数会被调用。但是它必须执行实际的启动程序,这样会返回一个{ok, PID}的值作为根监督程序的进程ID。你也可以在这里启动其它你想启动的任何任务,比如读取一个配置文件,初始化ETS表等等。在这个简单的tcp_rpc例子当中,你所需要干的就是启动根监督程序,在里你所调用的是tr_sup:start_link(),这个函数我们还没有见到(你将很快在4.2中看到实现监督程序的模块tr_sup)。然后,你检查一下start_link()返回值的组成,如果有问题的话就发一个错误的信号。start()的输入参数暂时可以忽略,如果你感兴趣的话,可以看一下:Type通常是normal,但也可以是{failover,...}或者是{takeover,...},StateArgs参数是你在.app文件中mod参数所指定的。
4.1.4 应用程序结构的小结
总结一下,在创建OTP应用程序之前,你需要干三件事情:
1 遵守标准的目录结构;
2 在.app文件中添加应用程序的元数据;
3 创建一个模块来实现应用程序的特性,对于启动你的应用程序是很有帮助的。
我们留下了一个细节,就是按照start/2函数的要求,如何启动一个根监督程序。一个工作应用程序的目的就是能够运行一个或者多个进程来完成一些工件。为了控制那些进程,它们需要被监督程序来创建和管理,创建的这些进程要能够实现监督应用程序的特性。
阅读(2865) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~