OTP应用与监督机制的了解与应用

在上一篇文章中我们说过,RPC应用部署到线上服务器上会造成一个安全漏洞,那么下面我们简单介绍一下OTP应用与监督机制,并把上一篇文章中的代码优化一下。

整个Erlang/OTP生态系统的目的就在于构建稳定、容错的系统。首先介绍两个新的基本概念:

应用:应用是Erlang对相关模块进行打包的一种手段。打包的目的并不在于发布,而在于是这些模块称为一个整体。

监督者:监督者是OTP最为重要的一个特性。他们负责监控其他进程,并在出问题时重启故障进程或向上汇报侦测到的问题。

应用

创建OTP应用时的主要工作集中于标准目录结构的建立和应用元数据的编写。元数据的作用在于让系统获悉应该如何启动停止应用,还可用于指定应用的依赖项,也就是在应用启动前预先安装或启动哪些其他应用。

            <application-name>[-<version>]

                               |

                               |- ebin

                               |- include

                               |- src

其中<application-name>显然应该写你自己的应用名,此处是tcp_rpc。[-<version>]是可选项:开发时用不到它,但是在交付时通常采用tcp_rpc-1.0.2这样的目录名,这样做可以简化今后的代码升级工作,不过目前我们这里用不到。ebin文件夹内存放的是编译过后的.beam文件,还放有应用元数据.app文件。include用于存放公共头文件,也就是公用的API部分.hrl文件。src下存放的就是我们编写代码的文件还有一些内部的.hrl文件等。

下面为应用添加元数据,在ebin文件夹下创建tcp_rpc.app文件,文件内容如下:

 

这个.app文件的作用就是告诉OTP如何启动应用,以及该应用该如何与系统中的其他应用相融合。.app文件很简单,除了注释就剩下一个erlang项式三元组:第二个参数是应用名称所对应的原子,此处为tcp_rpc。第三个元素是一个参数列表,以键值对的形式排列,有的是必须的,有的是可选的。

下面编写应用行为模式,简单来说这是一个主动应用,每个主动应用都配有一个application行为模式的实现模块。该模块用于实现系统启动逻辑。它至少负责根监督者的启动,该监督者会成为应用中所有监督者的鼻祖。根据系统需要,应用行为模式模块还可以完成一些其他任务。下面是行为模式模块代码:

 

应用结构到这里基本上就结束了,当然咱们这只是一个比较简单的rpc服务,也没有那么多的要求。

监督者

监督者是Erlang/OTP的核心之一。主动OTP应用由一个或多个进程组成,它们相互协作共同完成任务。监督者间接启动这些进程,对这些进程负责,并在必要时重启它们。

你可以通过编写supervisor行为模式的实现模块来创建监督者,如果工作进程本身就是基于OTP行为模式的(tr_server就是),为其设置监督者将会很容易。下面我们来编写监督者模块,创建文件命名为tr_sup.erl,代码如下:

 

start_link()API函数仅负责监督者的启动,具体来说就是以模块名为参数调用库函数supervisorLstart_link/3。真正有意思的内容都集中在init/1函数里。子进程的启动策略、管理策略以及监督者进程本身的行为都是经由该函数的返回值告知给OTP监督者库的。

子进程规范:(基于tr_server模块)

子进程规范是一个用于描述受监督者管理的进程的元组。对于大多数监督者而言,子进程会随监督者的启动而启动并在监督者的生命周期结束时退出。对于单个需要监督的进程,init/1函数给出如下描述:

Server = {ID, Start, Restart, Shutdown, Type, Modules}。第一个元素ID,是一个用于在系统内部表示各规范的项式。简单起见可以采用模块名,即原子tr_server。

第二个元素Start,是一个用于启动进程的三元组{MOdule, Function, Arguments}。与调用内置函数spawn/3时一样,第一个元素是模块名,第二个元素是函数名,第三个元素是函数的调用参数列表。在这个例子中,监督者应调用tr_server:start_link()来启动子进程(也就是tr_server)。

第三个元素Restart,用于指明子进程发生故障时是否需要重启。此处指定为permanent,因为你搭建的是需要长期运行的服务器,不论出于什么原因导致的进程终止都应重启进程(该选项还能取值为表示永不重启进程的temporary,以及仅在进程意外终止时重启进程的transient)。

第四个元素Shutdown,用于指明如何终止进程。此处取值为整数(2000),表示终止进程时应采用软关闭策略,给进程留出一段自我了断的时间(毫秒为单位),如果进程未能在指定时间内自行退出,将被无条件终止(该选项还可取值为brutal_kill,表示在关闭监督进程时立即终止子进程;以及infinity,主要用于子进程本身也同为监督者的情况,表示应给予子进程充分的时间自行退出)。

第五个元素Type,用于表示进程时监督者还是工作者。在整个监督树中,除了实现了supervisor行为模式的监督者进程以外,剩下的都是工作进程。监督者可以通过Type字段识别子进程是否同为监督者。

第六个选项列出了该进程所依赖的模块。这部分信息仅用于在代码热升级时告知系统该以何种顺序升级各个模块。一般来说,只需列出子进程的主模块,在这里也就是tr_server。

到这里咱们的代码就编写完成了,下面运行一下这个小项目。记得运行之前先编译文件,编译完成之后,如果你的.beam文件不在ebin目录下,自行把他们移入到ebin目录下,然后启动Erlang shell,启动后只需要一个命令便可启动应用:以应用名tcp_rpc为参数调用标准库函数application:start/1,如下:

 

看来咱们的代码没有什么问题,启动很成功。你可能很奇怪,shell是怎么找到各个模块的,你让它启动tcp_rpc应用,但实际上根本没有叫这个名字的模块。还记得.app文件吧?正如Erlang会在代码路径中搜索.beam文件来加载模块,application:start/1函数也会在代码路径中搜索.app文件,由于ebin目录已经位于代码路径之中,shell便可以很顺利找到元数据文件,该文件中包含了所需的一切信息。

转载于:https://my.oschina.net/u/3395699/blog/872395

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值