文档库 最新最全的文档下载
当前位置:文档库 › 编写分布式的Erlang程序:陷阱和对策

编写分布式的Erlang程序:陷阱和对策

编写分布式的Erlang程序:陷阱和对策
编写分布式的Erlang程序:陷阱和对策

编写分布式的Erlang程序:陷阱和对策

Hans Svensson

Dept. of Computer Science and Engineering

Chalmers University of Technology

Gothenburg, Sweden

hanssv@cs.chalmers.se

Lars- ?ke Fredlund*

Facultad de Informatica, Universidad Politecnica de

Madrid, Spain

fred@babel.ls.fi.upm.es

摘要

为了在Erlang运行时系统基础上开发更可靠的分布式系统和算法,我们研究了Erlang编程语言中分布式的部分。使用Erlang,把一个运行在单个节点上的程序转换成完全分布式(运行在多个节点上)的应用程序可谓易如反掌(只需要修改对spawn函数的调用,使之在不同节点上产生进程);但尽管如此,Erlang语言和API中仍然有一些阴暗的角落可能在引入分布式运算时带来问题。在本文中,我们将介绍几个这样的陷阱:在这些地方,取决于进程是否运行在同一个节点上,进程间通信的语义会有显著的差异。我们同时还提供了一些关于“编写安全的分布式系统”的指导原则。

分类和主题描述 D.3.3【编程语言】:语言构造和特性

关键字:可靠性

1. 简介

我们希望能够编写和调试用到Erlang的分布式进程通信机制的分布式算法,为此我们必须清楚Erlang的分布机制对进程间通信提供了哪些保障——要判断这些保障是否与我们的分布式算法的各种需求相符,首先必须了解它们。很大部分的研究工作都是在为Erlang编程语言(包括分布机制)开发形式化语义[CS05]。在实现“分布式Erlang”的模型检查器[FS07]时,我们有几处无法完全肯定形式化语义是否精确描述了Erlang分布层的行为。但由于并非所有关于分布式支持的重要部分都有文档记录1,做一些试探工作自然是必不可少的。我们编写了大量程序来测试运行时系统的各种基本特性,同时对运行时系统的源代码也做了检验,从而逐渐勾勒出Erlang语言中分布式部分的真实行为。

我们得到的成果是另一篇关于精化Erlang分布式语义的论文[SF07],以及本文:我们将在文中着重关注Erlang目前提供的分布式支持带来的实际效果——我们将展示哪些代码会出错,并就“如何借助Erlang的分布机制编写可靠的分布式应用”提出我们的建议。

* 该作者由西班牙教育与科学部提供的拉蒙卡哈基金(Ramón y Cajal grant)和

DESEFIOS(TIN2006-15660-C02-02)、PROMESAS(S-0505/TIC/0407)等项目共同资助。

1 当然了,有源代码,如果那也算文档的话……

2. 节点内编程

Erlang节点内编程的基本工具可说是人所共知了:用send和receive来实现通信;用链接(link)和监视器(monitor)来构造健壮的、在单个进程失败时也不会崩溃的应用程序。

正如前文所说,链接(link)和监视器(monitor)是编写具有高容错性的Erlang程序的基本工具:借助这两种语言特性,当一个进程终止时,它可以向另一个进程发送失败信息。在分布式应用开发中有一个常见的抽象机制叫做失败侦测器(failure detector),其用途跟Erlang的链接和监视器毫无二致。

请注意,“链接和监视器”机制——监视同一节点上的另一个进程——并不保证被监视的进程在语义上正确:被监视的进程有可能在等待一个永远不会到来的消息,这时它实际上等于已经死掉了,但监视它的进程永远也不会收到“进程终止”的消息。为此(以及其他一些原因)有必要用计时器(timer)来限制进程通信的等待时间,即便各个进程都在同一节点内。

下面我们将逐一展示节点内通信能够得到的基本保障。

2.1 基本消息传递保障:流语义

节点内消息传递的基本保障是:由一个进程发送给另一个进程的消息,只要消息能够送达而没有丢失或重复,就必定是按发送顺序送达的。在这里,“将一条消息送达进程P”意味着这条消息被放入进程P的收件箱;同时只要消息m被送达P,我们就说P收到了消息m的值——这并不代表P 在此时用receive语句从收件箱中取出的一定是消息m,只代表消息m一定是在收件箱里。

在实际编程中,这项保障意味着:如果进程Q先后发送两条消息(m1和m2)给进程P,那么消息送达的情况必定是下列三种情况之一:

?两条消息按发送顺序送达P

?只有m1被送达P(等效于P在收到m1之后崩溃)

?两条消息都不被送达

这种消息发送和接收的顺序保障类似与TCP/IP通道所提供的通信保障——后者常被用于连接多个分布的Erlang节点。我们把这种通信保障称作流保障(streaming guarantee)。

请注意,这个保障与接收进程的语义无关:该进程是否确实处理收到的消息、是否作出反应,都不在保障之内。譬如说,进程P可能有个bug,会导致它在收到m1之后立即崩溃;而进程Q则希望P对自己发送的消息作出响应,并且两者已经建立了双向协议。在这种情况下,前面介绍的通信保障唯一能保证的事情是:如果P没有首先收到并处理m1,它绝不会收到(当然更不会处理)m2。

当然,这里所说的“处理m1”需要在更广泛的意义上来理解:包括忽略m1、不把m1从收件箱中取出(而是等m2送达后先取出后者)、使用“选择性的”receive语句等都应该算作对m1进行了处理。

2.2 多方通信

在节点内通信的情况下,还可以对通信模式做更强的假设。Claessen和Svensson[CS05]给出了一个例子,三个进程(P1、P2和P3)通信如下:

?P1发送消息m1给P2

?P1发送消息m2给P3

?P3把消息m2转发给P2

如果上述进程都位于同一节点,那么消息m1必定会在m2之前被送达P2,因为运行时系统只有在P1完成发送之后才会把消息放入接收进程的收件箱。换句话说,只要各个进程都位于同一节点,应用协议就可以放心地假设m2不会在m1之前被送达P2;但同样的假设在Erlang/OTP将来的版本中可能会有问题2。

3. 跨节点编程

当Erlang程序涉及不同节点上的进程时,情况将迥异于单节点编程:不再有一个“大一统”的运行时系统了解当进程崩溃时作出明智决策所需的全部信息。在一个分布式、多节点的应用中,节点可能在地理上彼此远离,因此一般而言没有办法区分与远端进程(位于另一节点)的通信失败究竟是由于:(1)该节点与发送节点被暂时隔离(例如因为网络故障),还是(2)远端节点的运行时系统崩溃从而终止了其上的所有进程。为了找出(尽管有可能错误)发生故障的节点,Erlang运行时系统会定期在节点之间发送消息(节拍信号,tick)。如果N1节点没有收到来自N2节点的tick,那么N2节点就会被认为已经崩溃,N1上所有“链接或者监视N2上进程”的进程就会收到错误通知。但这时的通信失败有可能只是暂时的:远端节点并未崩溃,稍后可以重新与之建立通信。

尽管分布情况下的通信实现与节点内编程时差异很大,但Erlang承诺通信本身并无不同。以下文字出自(老的那本)《Concurrent Programming in Erlang》:

消息可以被发送给远端进程,本地进程和远端进程之间也可以建立链接,这一切都好像所有进程都运行在同一个节点一样。远端Pid的另一个特点是:不论从语法上还是语义上,“向远端进程发送消息”都与“向本地进程发送消息”完全一样。这也就是说,发送给远端进程的消息始终以发送时的顺序送达,不会损坏也不会丢失。

4. 跨节点编程的陷阱

为了厘清Erlang的分布语义,我们做了一系列实验来验证这个“节点内编程与跨节点编程无差异”的承诺究竟在多大程度上有效。

作为总结,我们发现两处显著的差异,它们都会在跨节点编程中破坏流保障——这是节点内编程的基本通信保障。在某些情况下,先发送的消息会丢失,而后发送的消息则会顺利送达。也就是说,进程Q先后发送m1和m2两条消息给远端节点上的进程P,却有可能发现只有m2被送达,m1则丢

2 据我们推测,即便在当前的Erlang/OTP实现下,垃圾收集机制的存在也会使上述假设不能成立;但我们尚未实际观察到这样的情况。

失了。第一种可能出错的情况是遇到了重复的进程标识符(Pid):在发送m1的过程中进程P所在的节点可能崩溃,然后重启,此时m2就可能被送达重启之后的节点上新生的进程。

第二种情况源自节点之间暂时性的通信故障,这会导致Erlang错误地判定节点已经崩溃,从而悄

无声息地抛弃已经发送的消息。

在本节里,我们还会指出另外一些分布式通信的特质(陷阱3和陷阱4),忽视它们也可能导致应用程序出错。

4.1 陷阱1:重复的Pid

进程标识符通常被认为是全局唯一的,但它们遵循同一个有穷的结构,因此有可能不是唯一的。不过只要这个有穷结构足够大,在实际应用中应该可以不用担心会用到重复的进程标识符。

所以,要是你知道在节点崩溃之后创建一个相同Pid的进程有多容易,你肯定会大吃一惊。在下面的例子中,我们将生成一个进程,确保将它弄死,然后再次与它通信!

我们用图1所示的shell脚本来运行这个例子:它一旦发现一个Erlang节点被杀死,就立即重启它。#!/bin/sh

NODE=$1

while [ 1 -lt 2 ]; do

erl -sname $NODE

sleep 1

done

图1.代码示例:重启节点的脚本

这个例子(源代码如图2所示)的原理如下:首先在节点N1上生成一个进程,它负责执行run函数启动实验。我们假设节点N2已经用图1所示的脚本启动起来。N1上的进程首先注册退出陷阱(trapping exit),然后把下列指令执行三遍:在N2上创建一个进程并链接到它,然后让它杀死节点N2(调用halt函数),最后等待2秒(以确保N2重启)。这样一来,我们总共会生成三个进程,它们的Pid都被保存在Pids变量里。然后我们就等待三条退出消息,以确定所有在N2节点(的不

同实例)上生成的进程都已经被杀死了。最后我们再在N2上生成一个进程,让它执行echo函数。随后,在N1上调用communicator函数,并传入此前收集到的三个Pid作为参数。communicator

函数会尝试与已经死去的进程通信,而正如我们在图3所示的执行日志中看到的,其中一个被认为早已死去的进程竟然回复了!显然N2上正在执行echo函数的那个新进程有着与之前某个进程相同的标识符。

-module(pidReuse).

-export([start/0,run/0,echo/0,communicator/1]).

-define(N1,’n1@localhost’).

-define(N2,’n2@localhost’).

start() ->

spawn(?N1,?MODULE,run,[]).

run() ->

erlang:process_flag(trap_exit,true),

Pids =

lists:map

(fun(N) ->

Pid1 = spawn_link(?N2,erlang,self,[]),

spawn(?N2,erlang,halt,[]),

timer:sleep(2000),

Pid1

end, lists:seq(1,3)),

lists:foreach(fun(Pid) ->

receive {’EXIT’,Pid,_} -> ok end

end,Pids),

spawn(?N2,?MODULE,echo,[]),

communicator(Pids).

echo() ->

receive {From,N} -> From!{self(),(N+1)} end.

communicator(Pids) ->

lists:foreach(fun(Pid) ->

io:format("Trying to communicate with: ~w\n(~w)\n",

[Pid,term_to_binary(Pid)]),

Pid!{self(),5},

receive {Pid2,N} ->

io:format("Recieved ~w from ~w\n(~w)\n",

[N,Pid2,term_to_binary(Pid2)])

after 2000 ->

io:format("No reply!\n")

end

end, Pids).

图2. 代码示例:Pid被重复使用

Trying to communicate with: <4888.40.0>

(<<131,103,100,0,12,...,49,49,56,0,0,0,40,0,0,0,0,3>>)

Recieved 6 from <4888.40.0>

(<<131,103,100,0,12,...,49,49,56,0,0,0,40,0,0,0,0,3>>)

Trying to communicate with: <4888.40.0>

(<<131,103,100,0,12,...,49,49,56,0,0,0,40,0,0,0,0,1>>)

No reply!

Trying to communicate with: <4888.40.0>

(<<131,103,100,0,12,...,49,49,56,0,0,0,40,0,0,0,0,2>>)

No reply!

图3. 输出:Pid被重复使用

4.1.1 分析

显然当节点崩溃并重启之后,很快Pid就出现了重复。这样一来,在与远端进程通信时就不能那么放心地用Pid来唯一标识另一个进程了。因此在分布式协议中,人们往往会用别的方式来准确地标

识通信的另一端,例如给每个消息加上实例计数器,并在节点重启时递增这个计数器(这也是很多分布式协议中的标准做法)。

也许有些读者已经注意到了:我们在上面的例子中生成并杀死了三个进程,这个数字并非随便选择的。在节点内部有一个incarnation计数器,它的值可以是1、2和3,重启超过3次则从头再来。

为预防此类问题,我们认为应该强烈建议对当前的Erlang/OTP实现加以修改,至少避免如此之快就重复使用Pid(可以在Pid的结构中预留一块较大的空间用作节点重启计数器)。

4.2 陷阱2:分布环境下被误解的基本通信保障

很多人对此坚信不疑:两个Erlang进程之间的信道绝不会悄无声息地丢失消息。在第二个例子中,我们将做一个实验:如果两个节点在通信过程中被断开、然后又重新连接,信道的可靠性就不那么可靠了。

图4的Erlang程序揭示了问题所在:这段程序在节点N1上生成一个进程,它不断地发送递增的自然数;位于节点N2的接收进程则只管把收到的数字打印出来。

-module(comm).

-export([start/0,snd/2,rcv/0]).

-define(N1,’n1@https://www.wendangku.net/doc/2012765633.html,’).

-define(N2,’n2@https://www.wendangku.net/doc/2012765633.html,’).

start() ->

Pid = spawn(?N1,?MODULE,rcv,[]),

spawn(?N2,?MODULE,snd,[Pid,1]).

rcv() ->

receive

N -> io:format("got ~p~n",[N]), rcv()

end.

snd(Pid,N) ->

Pid!N,

timer:sleep(1000),

snd(Pid,N+1).

图4. 基本的Erlang通信

在一次运行之后,接收进程打印出的日志信息如图5所示。

...

got 71

got 72

got 73

got 74

got 146

got 147

got 148

...

图5. 输出:进程间通信

在日志里我们看到,一开始数列如我们预期地递增,然后突然从74跳到了146,中间的数都被丢

掉了,这显然与“消息永不丢失”的特性不符。原因是什么?没什么,只是我们拔掉了其中一个节点的网线,等了一小会又重新插上了。这个操作具有时间敏感性:如果拔网线的时间太短(小于发送tick消息的间隔3),就可能不会有消息丢失。

显然如果节点间通信出现故障,我们也不能依赖普通的TCP/IP通道语义来传递消息。所以结论是:在分布式Erlang信道基础上构造分布式算法时,必须假设消息是可能悄无声息地丢失的;否则就

得用代码来监视每一条进程间通信的信道,侦测所有可能的节点间通信故障(本文稍后会给出例子)。

研读更多Erlang文献之后就能发现,这种现象在Barklund和Virdings精心写就的Erlang的自然语

言语义[BV99]中其实就已经被提到过了。引用原文如下:

10.6.2 信号的顺序

……可以保证的是,如果进程P1先后向进程P2发出两个信号S1和S2,那么信号S1绝不会

在S2之后到达P2。这也就确保了只要有可能,发送给一个进程的信号最终应该抵达目的地。

在有些情况下,无法要求所有信号都能抵达目的地,特别是向位于另一个节点的进程发送

信号、并且节点间的通信暂时断开的时候。

请注意这里的讨论的“消息”是信号实例。换句话说,没有任何办法承诺信号在不改变顺序的前提下安全送达,尤其是当通信链路可能出现故障时。

4.2.1 分析

既然不能靠TCP通道语义来进行分布式通信,要想构建可靠的分布式应用程序,我们的选择也就

不多了:

?只采用对信息丢失不敏感的进程间通信协议。这个要求并不难满足,只要在每次通信中都携带整个协议的状态就行了;但在实际应用中这常常会给消息流量和时间造成过大的开销。

另一种方案是给所有消息都加上顺序的计数器,并且抛弃(或者推迟发送)顺序不对的消

息;此外这种方案还需要实现消息的重发,换句话说就是在Erlang分布机制的基础上重新

实现一个具备TCP特质的应用协议。

?在构造协议时假设:每次节点间通信失败时,都(可能)有不可恢复的通信故障发生。只要始终链接或者监视通信的远端进程,就可以侦测到这类故障。当故障发生时,任何来自

该远端进程的消息都将不被信任,因为其中可能有消息丢失。也就是说,不再与可疑的进

程做任何通信。

此外还有两种仅存在于我们设想中的替代方案,它们都要求改变Erlang的分布机制:

3 参见Erlang中关于设置net_ticktime的介绍。

?实现一个有效的的Erlang传输协议,它具有类似于TCP的通信保障,同时能够从TCP通道失败中恢复(记录发送和接收的顺序号,以及发出但没有收到应答的信息)。也就是说,如果一条TCP通道出现故障、又新建了另一条通道,节点会记得哪些消息已经被发送、哪些尚未被接收,于是就可以进行重发。换句话说,在Erlang运行时系统内部实现一个具有TCP特质的分布式协议,取代现在的Erlang分布式协议。

?禁止节点间重建连接。一旦两个节点之间的连接断掉,就不允许在它们之间重建连接。从效果上来说,这就要求(至少)其中之一重启。这看来似乎有些太过严酷,但对于某些应

用场景来说会有所帮助。

4.2.2 改进后的消息传递保障

如果让进程Q来监视(不管是用链接还是监视器)接收消息的进程P的状态,就可以换种方式来

表述2.1节谈到的流保障:

如果进程Q先后向进程P发送消息m1和m2,并且将Q链接到(或者监视)P,并且Q没有收到来自P的退出消息4,那么就可以保证两条消息会按照发送顺序被送达。

如果Q收到来自P的退出消息,那么P有可能收到下列消息序列之一:P: ∈, , ,

4.3 陷阱3:更弱的多方通信保障

在2.2节我们已经看到,当所有进程都位于同一节点时,多方通信的行为是相当确定的,消息的顺序能够得到保障。不过大家知道,跨节点通信时情况就不再如此理想了。

?P1发送消息m1给P2

?P1发送消息m2给P3

?P3把消息m2转发给P2

如果在上面的例子中三个进程分别位于不同的节点上,那么就有可能出现消息m2在m1之前被送达进程P2的情况。

有趣的是,在目前的Erlang实现中,只要P2和P3(或者P1和P3,或者P1和P2)位于同一节点,那么更强的通信保障(确保m1在m2之前送达P2)仍然有效。这是因为Erlang从根本上是用同一

个流来处理一对节点之间的所有通信的(而不是针对每对进程通信创建一个专用的流),所以当上例中m1被发送给P2时,它一定会在m2之前被处理和送达(除非出现之前讨论过的网络连接断开

的情况),因为m1和m2是在同一个流上发送的,它们的顺序不会改变。不过,让应用程序的行为依赖于如此晦暗的保障,显然是颇可置疑的:Erlang分布机制的实现稍有改动,就有可能改变这一行为特质。

4 等待退出消息多久取决于net_ticktime的设置。

4.4 陷阱4:失败侦测器并不完美

在节点内编程时,如果一个进程死亡,与其链接或者对其监视的进程会得知这一情况。由于所有进程都在同一个运行时系统中运行,对终止进程的侦测当然是完美无缺的。换句话说,只要一个进程被报告已经终止,你就可以确信它再也不会出现。

但在跨越节点时,如果一个进程监视(或者链接到)另一个节点上的进程,远端进程就有可能在实际上并未死亡时谎报自己已经死亡。譬如说当两个节点被隔离(网络tick算法超时),就会导致远端被监视或者被链接的进程被报告为“已死亡”。但如果稍后节点间的连接又重新建立起来,这些已经被判定死亡的远端进程又可以进入通信了。

同样,只要允许在被隔离的节点之间重建连接,失败侦测器就不可能完美,因为一般而言不可能判断究竟是发生了网络连接故障(这种情况下可以重建连接)还是节点本身失败(不可恢复)。

5. 分布式应用编程原则

从图4和图5所示的例子可以看出,如果需要可靠的通信,我们就必须对进行通信的进程加以监管。并没有提供这一功能的内建机制,但我们可以在通用的链接和监视器基础上建立自己的编程原则。在本节中我们将展示这组编程原则的一个简化版本,从中可以看出重点所在。此外我们还将介绍一些理论上可行的对于Erlang分布机制的补充,我们认为这些扩充能让开发可靠的分布式应用变得

更容易。

5.1 简单的编程原则

在图6所示的经过改进的例子中,我们增加了一些代码来确保消息不会丢失。(请注意:出错的可能性有千万种,这个例子只解决了通信故障的问题。)在例子中,发送消息的进程对接收消息的进程进行监视。一旦发送方收到错误信息,就停止发送消息,转入“同步模式”:继续监视接收方,直到接收方再次出现(在这里,我们重新插上网线);然后两个进程开始同步,接收方把失去连接时的状态告知发送方,发送方则接着失去连接之前的状态继续发送消息。这个简单的方案存在缺陷(例如它所采用的半忙等待循环,以及发送方必须保存自己发送的所有东西),设计出更复杂的方案也是完全可能的。但这个例子足以阐明重点,在图7里我们看到了它运行的输出:尽管中间发生了通信故障,但传输序列并没有被破坏。

-module(commFixed).

-export([init/0,rcv/1,snd/2,sync/1]).

-define(N1,’n1@https://www.wendangku.net/doc/2012765633.html,’).

-define(N2,’n2@https://www.wendangku.net/doc/2012765633.html,’).

init() ->

Rcv = spawn(?N2,?MODULE,rcv,[none]),

spawn(?N1,?MODULE,snd,[Rcv,1]).

rcv(N) ->

receive

{sync,Snd} ->

Snd ! {sync,N},

N1 = N;

X ->

io:format("got ~p\n",[X]),

N1 = X

end,

rcv(N1).

snd(Rcv,N) ->

erlang:monitor(process,Rcv),

snd_(Rcv,N).

snd_(Rcv,N) ->

receive

{’DOWN’,_,_,_,noconnection} ->

N = sync(Rcv)

after 1000 ->

ok

end,

Rcv ! N,

snd_(Rcv,N+1).

sync(Rcv) ->

erlang:monitor(process,Rcv),

Rcv ! {sync,self()},

receive

{’DOWN’,_,_,_,noconnection} ->

timer:sleep(5000),

sync(Rcv);

{sync,N} ->

snd_(Rcv,N+1)

end.

图6. 基本的Erlang通信——有监视器的情况

...

got 71

got 72

=ERROR REPORT==== 4-Jul-2007::15:14:06 ===

** Node ’n2@https://www.wendangku.net/doc/2012765633.html,’ not responding **

** Removing (timedout) connection **

got 73

got 74

...

图7. 输出:进程间通信——有监视器的情况

5.2 扩展Erlang的可能性

既然我们已经看到分布式程序可能造成的各种麻烦,想象一下能对Erlang运行时系统做怎样的扩展会是一个有趣的思想实验。可以在几个层面进行修改,其中一种可能性是新增一组Erlang API,

用于显式处理节点重连的情况,从而能够禁止或者允许(可能需要首先告知本地节点上的进程,让它们做好准备)重连。

另一种可能性是让进程在与远端节点通信时能够获得更多的信息。一个(在非分布式系统中)很常用的OTP构造就是监管结构(supervisor structure),如果在跨越几个运行时系统通信时能有类似的进程结构那就好了。不过,具体的实现方案有好几种。一个貌似合理的办法是用链接和监视器来构造一个节点监管结构,这样就可以根据事件(连接到节点,失去连接,重连,等等)指定不同的行为。这个办法主要的问题在于:当事件发生时,如何确保监管器是最先开始/停止通信的。另一个办法是给每个节点分配一个监管器,进程可以把自己注册在上面。这时当进程与位于另一节点的进程通信时,它就可以在节点监管器上注册这次通信,同时告诉监管器在错误出现时应该采取什么行动(例如崩溃、重启、忽略或者通知其他节点)。

还有一种对Erlang API较少侵入的扩展是:不仅在节点消失时发出通知(由monitor_node函数发出nodedown消息),而且还报告节点重连(或者重启)——让monitor_node也发出nodeup消息。

6. 结论

本文展示了一些实验的结果,其目的是帮助读者更好地理解Erlang的分布式行为。在研究Erlang 的模型检查器(McErlang[FE06, FS07])和分布式Erlang的精确语义[SF07]时,我们发现了一些从前——由于缺乏实验——没有发现的运行时系统的工作机制。简而言之,我们发现,在节点失去连接、稍后又恢复连接的情况下,文档中含糊的承诺与实际的运行时系统之间存在两处显著而有趣的差异:(1)Pid很快被重复使用,(2)某些消息悄无声息地丢失了。

Pid的重复使用问题可能主要是技术问题,但可能造成严重的后果,如果关键性的系统依赖于Pid 的全局唯一性的话。为了预防问题发生,我们认为应该提议修改当前的Erlang/OTP实现,至少避免如此之快就重复使用Pid(可以在Pid的结构中预留一块较大的空间用作节点重启计数器)。

经常被误解的关于分布式通信的保障则可能造成更多的困扰。这个问题源自更普遍的(并且众所周知难以解决的)网络分割问题。因此我们尝试给出一些安全处理类似情况的指导,并且考虑了如何修改/扩充Erlang以便更轻松地解决这一问题。

最后我们要说,尽管大部分应用程序不会受这些问题的困扰,但在开发大部分分布式应用时都应该将它们考虑在内。很可能你不需要写任何额外的代码来处理Pid重复之类的事情,也许你的应用协议根本就不在乎这些问题,但在作出决策时你应该清楚这些问题的存在,这是很重要的。

致谢

感谢Joe Armstrong对本文初稿提出了颇具价值的评注。

参考文献

[BV99] J. Barklund and R. Virding. Erlang 4.7.3 reference manual. Draft (0.7), Ericsson Computer Science Laboratory, 1999.

[CS05] K. Claessen and H. Svensson. A semantics for distributed Erlang. In Proceedings of the ACM SIPGLAN 2005 Erlang Workshop, 2005.

[FE06] L- ?. Fredlund and C. Benac Earle. Model checking Erlang programs: The functional approach. In Proceedings of the ACM SIPGLAN 2006 Erlang Workshop, 2006.

[FS07] L- ?. Fredlund and H. Svensson. McErlang: A model checker for a distributed functional programming language. In Proc. Of International Conference on Functional Programming (ICFP). ACM SIGPLAN, 2007.

[SF07] H. Svensson and L- ?. Fredlund. A more accurate semantics for distributed Erlang. In Proceedings of the ACM SIPGLAN 2007 Erlang Workshop, 2007.

Erlang入门手册

Erlang/OTP R11B 文档Erlang/OTP R11B documentation v0.1a2

目录 第1部分 入门 (1) 1.1 简介 (1) 1.1.1 简介 (1) 1.1.2 其它方面 (1) 1.2 顺序编程 (1) 1.2.1 Erlang Shell (1) 1.2.2 模块和函数 (3) 1.2.3 元子(Atoms) (6) 1.2.4 元组 (7) 1.2.5 列表 (8) 1.2.6 标准模块及用户手册 (11) 1.2.7 将输出写到终端上 (11) 1.2.8 一个更大的例子 (12) 1.2.9 变量的匹配、守卫和作用域 (14) 1.2.10 更多关于列表 (16) 1.2.11 If和Case (21) 1.2.12 内建函数(BIFs) (25) 1.2.13 复杂函数 (27) 1.3 并行编程 (29) 1.3.1 进程 (29) 1.3.2 信息传递 (31) 1.3.3 进程名称注册 (35) 1.3.4 分布式编程 (36) 1.3.5 一个更大的例子 (40) 1.4 [#1]健壮性(Robustness 鲁棒性) (49) 1.4.1 超时(Timeouts) (49) 1.4.2 错误处理 (51) 1.4.3 增强健壮性之后的大型例子 (54) 1.5 [#1]记录和宏(Records and Macros) (59) 1.5.1 将大型的例子分割在多个文件中 (59) 1.5.2 头文件(Header Files) (64) 1.5.3 记录(Records) (64)

1.5.4 宏(Macros) (65) 第2部分 OTP设计原则 (66) 2.1 概述 (66) 2.1.1 监督树 (66) 2.1.2 Behaviour (66) 2.1.3 应用 (70) 2.1.4 发布 (71) 2.1.5 发布控制 (71) 2.2 Gen_Server Behaviour(文档缺失) (71) 2.3 Gen_Fsm Behaviour (71) 2.3.1 有限状态机 (71) 2.3.2 实例 (72) 2.3.3 启动一个Gen_Fsm (73) 2.3.4 事情通知 (74) 2.3.5 超时 (74) 2.3.6 All状态事件 (75) 2.3.7 停止函数 (75) 2.3.7.1 在监督树中 (75) 2.3.7.2 独立Gen_Fsm (76) 2.3.8 处理其它消息 (76) 2.4 Gen_Event Beheaviour (77) 2.4.1 事件处理原则 (77) 2.4.2 实例 (77) 2.4.3 启动一个事件管理器 (78) 2.4.4 加入一个事件处理器 (78) 2.4.5 事件通知 (79) 2.4.6 删除一个事件处理函数 (80) 2.4.7 停止 (80) 2.4.7.1 在监督树中 (80) 2.4.7.2 独占式事件管理器 (80)

通信基础知识

基础知识 GSM:全球移动通信系统(Global System for Mobile communications.) ITU: 国际电信同盟(International Telecommunication Union) ETSI:欧洲电信标准学会(European Telecommunication Standards Institute)TDMA:时分多址(Time Division Multi Address) CDMA:码分多址(Code Division Multi Address) FDMA:频分多址(Frequency Division Multi Address) 帧中继:FR(FRAME RELAY) GPRS:通用无线分组业务(GENERAL PACKET RADIO SERVICE) CCITT:国际电报与电话咨询委员会 移动用户国际ISDN码:MSISDN=CC+NDC+SN(CC=国家代码、NDC=国内目的地代码、SN=用户号码) 国际移动用户标识:IMSI=MCC+MNC+MSIN(MCC=移动网国家代码(三位)、MNC=移动网代码(两位)、MSIN=移动用户识别码(十位)) 移动台漫游号:MSRN=CC+NDC+SN(CC=国家代码(被访问国家)、NDC=国内目的地代码(服务的网络)、SN=用户号码(临时与IMSI相关的内部号)) 位置区标识:LAI=MCC+MNC+LAC(MCC=移动网国家代码(被访问国家)、MNC=移动网代码(服务的PLMN)、LAC=位置区代码(四位十六进制)) 全球小区标识CGI=MCC+MNC+LAC+CI 切换号HON=CC+NDC+SN 位置更新类型:1、位置登记(开机)2、一般性的3、周期性的 位置登记时,成功登记后,网络向移动台发送两个号码:LAI和TMSI 执行切换两个原因:1.由于测量结果引起的切换2.由于话务量的原因引起的切换 由于测量结果引起的切换由所在BSC控制,由于通信量的原因引起的切换由MSC控制四种不同类型的切换:1.小区内——BSC内切换2.小区间——BSC内切换3.小区间——BSC间切换4.MSC间切换切换优先级:干扰〉上行质量〉下行质量〉上行电平〉下行电

编写分布式的Erlang程序:陷阱和对策

编写分布式的Erlang程序:陷阱和对策 Hans Svensson Dept. of Computer Science and Engineering Chalmers University of Technology Gothenburg, Sweden hanssv@cs.chalmers.se Lars- ?ke Fredlund* Facultad de Informatica, Universidad Politecnica de Madrid, Spain fred@babel.ls.fi.upm.es 摘要 为了在Erlang运行时系统基础上开发更可靠的分布式系统和算法,我们研究了Erlang编程语言中分布式的部分。使用Erlang,把一个运行在单个节点上的程序转换成完全分布式(运行在多个节点上)的应用程序可谓易如反掌(只需要修改对spawn函数的调用,使之在不同节点上产生进程);但尽管如此,Erlang语言和API中仍然有一些阴暗的角落可能在引入分布式运算时带来问题。在本文中,我们将介绍几个这样的陷阱:在这些地方,取决于进程是否运行在同一个节点上,进程间通信的语义会有显著的差异。我们同时还提供了一些关于“编写安全的分布式系统”的指导原则。 分类和主题描述 D.3.3【编程语言】:语言构造和特性 关键字:可靠性 1. 简介 我们希望能够编写和调试用到Erlang的分布式进程通信机制的分布式算法,为此我们必须清楚Erlang的分布机制对进程间通信提供了哪些保障——要判断这些保障是否与我们的分布式算法的各种需求相符,首先必须了解它们。很大部分的研究工作都是在为Erlang编程语言(包括分布机制)开发形式化语义[CS05]。在实现“分布式Erlang”的模型检查器[FS07]时,我们有几处无法完全肯定形式化语义是否精确描述了Erlang分布层的行为。但由于并非所有关于分布式支持的重要部分都有文档记录1,做一些试探工作自然是必不可少的。我们编写了大量程序来测试运行时系统的各种基本特性,同时对运行时系统的源代码也做了检验,从而逐渐勾勒出Erlang语言中分布式部分的真实行为。 我们得到的成果是另一篇关于精化Erlang分布式语义的论文[SF07],以及本文:我们将在文中着重关注Erlang目前提供的分布式支持带来的实际效果——我们将展示哪些代码会出错,并就“如何借助Erlang的分布机制编写可靠的分布式应用”提出我们的建议。 * 该作者由西班牙教育与科学部提供的拉蒙卡哈基金(Ramón y Cajal grant)和 DESEFIOS(TIN2006-15660-C02-02)、PROMESAS(S-0505/TIC/0407)等项目共同资助。 1 当然了,有源代码,如果那也算文档的话……

erlang b公式的理解

Erlang B 公式的理解

目录 1 对Erlang B公式的理解 (4) 附录A Erlang B公式的推导 (6)

图目录 图A-1 系统状态转移图 (8)

表目录 表A-1 各种方式发生的概率 (7)

1 对Erlang B 公式的理解 问; 用Erlang B 计算出的话务量,它的具体含义是什么?为什么提供35个信道,有时却可以提供超过35个Erlang 的话务量。 答:首先,应用Erlang B 表计算话务量是有前提条件的,它基于一下两个假设: 1 用户数远远大于提供的信道数,相对于信道数来说,可以认为用户数是无穷大。 2 用户如果被阻塞后不重新发起呼叫。 基于这两点假设,可以认为:用户的呼叫到达服从泊松分布,在某一时刻同时有k 个用户通话的概率为: ∑== N i i k k i k p 0 ! /)/(! /)/(μλμλ 其中λ为单位时间内平均到达的呼叫次数,T /1=μ,T 为呼叫平均持续时长(注:有的书把μ叫做平均离开率,个人认为是不太确切的说法,因为平均离开率和平均到达率只相差被阻塞的那部分用户,而实际计算时阻塞率很小,平均离开率和平均到达率的比值应该接近于1;所以还是应该直接理解为平均持续时长的倒数为好);N 为提供的信道数。当所有的信道都被占用的时候,认为系统阻塞,而所有的信道都被占用的概率为: ∑== =N i i N N i N p B 0 ! /)/(! /)/(μλμλ 上式就是Erlang B 公式,T A λμλ==/ 即为我们所求的,它表示平均的话务量(注:此处实际是话物流量,在不引起误会的情况,所说的话务量即为话务流量),需要注意的是:在这里λ是平均到达率,它没有区分到达的用户是被服务还是被拒绝,所以Erlang B 公式计算出来的话务量μλ/=A 即包括两部分:被服务的用户呼叫的话务量(实际的话务量)和被阻塞的用户呼叫的话务量。而被阻塞的用户是不产生实际的话务量的,在这里事先已经求出了每次用户呼叫的平均持续时长T ,即每次用户呼叫的平均话务量已经求出来了,再把被阻塞的用户呼叫折算成话务量。正是因为把被阻塞的用户呼叫折算成了话务量,当阻塞率比较大时,话务量就有可能大于提供的信道数。实际的话务量(被服务的用户呼叫产生的话务量)可以用下式计算:

Erlang-C公式

Erlang-c 公式解析: 公式 M代表现有坐席人员 U代表话务强度 Ec呼叫等待概率 下面将分步骤介绍ErLang.C计算公式,所用例子为:360话务量/半小时,平均每个话务持续4分钟,呼叫中心可用客服人员55个。服务水平的目标应答(等待)时间是15秒。 第1个参数计算话务请求率 λ=average arrival rate (来电频率/密度)=360通/半小时÷1800秒=0.2通/秒 第2个参数平均通话时长 Ts=average call duration(平均每通电话时长)=240秒/通 第3个参数已有座席数

m=numbers of agents(坐席数)=55人 第4个参数流量密度(话务强度) traffic intensify(话务强度)= λ×TS =0.2通/秒×240秒/通=48秒/秒 为每秒需要处理48秒的工作量,即每秒需要48个人 换另一种工作量算法可能大家更容易懂,即360通电话,每通240秒,那么处理这些电话共需 86400秒,而每个座席员每半小时有1800秒,在最理想化的状态下我们也需要360×240÷1800=48 人 第5个参数计算代理的占用率 代理占用率,也就是代理的使用率,用代理数目除以流量密度来计算。代理占用率在0到1之间。如果它超过了1,就说明当前代理超负荷了。 P= agent occupancy(占用率) = 48人÷55人 =87.3% 接下来就开始代入Erlang C公式 第6个参数计算可能等待的概率 Ec(m,u)参数表示了一个话务不能马上被处理而必须等待的概率。它在 0到l之间,也可以乘以100%后用百分比来表示。 m!即m的阶乘,这里即1*2*3*4*.....*54*55 Excel中可用 =fact(55)

Erlang_Programming_导读

《Programming Erlang导读》 前言 如果你没有学习过C语言,我建议先去学C,并学习计算机的编译原理。因为那才是真正意义上的计算机程序设计。否则,如果把erlang作为你开始学习计算机的第一门语言,你将感到非常困惑,而且对程序的理解将停留在应用层面,很难有所底层技术的突破。 本导读的作用是帮助你快速理解Erlang,并基于该理解去考虑Erlang语言是否适合您的应用开发。要对Erlang全面了解,包括语法的各个方面,库函数的各个方面,以及Socket编程,文件操作等,你还是需要去仔细研读Erlang的官方著作——《Programming Erlang》。不过,当我看完这本书的时候,还是认为其中的某些章节,作者并没有写清楚,尤其是在一些例子方面,因此,如果时间充裕,我接下来会尝试给大家提供一份更容易理解的Erlang例程,并基于这些例程详细说明Erlang的用法和作用。 2008-11-27(北京)

第一、 Erlang是什么? 首先,Erlang包括一个Erlang虚拟机,Erlang编译器,以及Erlang语法。 什么是虚拟机(Vitual Machine)呢?其实虚拟机可以理解是一个软件,如果你在windows操作系统上安装了Erlang的虚拟机,那么从进程的角度来讲,VM 的地位可你计算器上其他软件的地位是一样的,比如Office Word, 金山词典,Photoshop等。只是VM所提供的功能和其他应用软件有所不同罢了。 Erlang编译器是一个exe可执行程序,当然,在Window下的编译器和UNIX 下的编译器有所不同,然而,所完成的功能都是把一个.erl文件转换为.beam文件。.erl文件是用所谓的erlang语言编写的程序代码,而.beam文件是一个可以在Erlang VM环境下运行的“程序”。 Erlang语法就是规定好的Erlang编译器可以理解的一种程序设计语言。然而,erlang语言和C语言还是两种不同层次的语言。Erlang语言更应该定义为一种应用语言,因为它并不是面向CPU编程的语言,相比之下,C语言基本上是直接面向CPU编程的(这不是严格意义上的,实际上C语言会被编译为汇编语言,并再次编译为CPU能够执行的二进制指令)。 了解java的人可以把Erlang虚拟机理解为java虚拟机,对erlang语言和java 的语言则是对等的。 说的更通俗一点,相信你用过office word吧,首先你安装了Microsoft的Office 软件,然后编辑了一个.doc文档。Office提供了你一种图形化编写.doc文档的功能,你可以通过输入法输入文字,你可以点击“文件”里面的“保存”菜单,把输入的文字保存在硬盘里,你还可以插入一个表格,当然,还包括照片等。然而,要知道,最终生成的.doc文件不只是这些,它还包含了很多其他信息,比如图片在文件中的位置,文本的页面信息等。好了,让我们把Erlang和office对比一下吧。 Erlang的虚拟机就好像Office程序,是独立的一个进程(独立的程序),.erl 文件就好像你所编写的.doc文件,erlang编译器把.erl文件编译为.beam文件,.beam文件是Erlang虚拟机能理解的程序文件,相比之下,office更高级,它可以直接理解.doc文件,而不需要再把.doc文件编译为其它格式。 Erlang提供了自己的语法,可以进行数据处理,数据的输入或者输出。Office word也提供了数据处理以及数据输入、输出的接口,只是用法不同而已。Erlang 生成自己对多线程的并发式应用很擅长,当然Office却声称自己对文字处理很擅长,的确是这个样子。 我之所以把Erlang和Office word对比,为的是让大家理解,Erlang不是一个纯粹的程序语言,它是为了面向某种应用而设计的语言,这就是为什么总有新的语言层出不穷。你是否问过自己,为什么CPU只有一个,然而却又无数种计算机语言,比如Ruby,java, php,erlang…,未来可能会有新的语言产生。实际上,计算机语言只有一种,那就是汇编语言,c,以及c++只是汇编语言的一种高级呈现方式,都是面向机器的语言,这种语法基本上代表了CPU的执行方式。然后,那种基于虚拟机VM上的语言,大多数则是由于应用的需求而人为设计的一种语言,这种语言则是面向应用的,而不是面向机器的。当然,erlang就是一种,它面向的应用就是并发程序。举个例子,对于Web服务器,要求同时能够提供多个连接,而且彼此的连接要求并发,那么如何设计一个Web服务器,并发需求显得额外突出,因此,如果能有一些更好用的接口,那么的确是一件很美好的事情,就好像在office word里面,我们可以很容易的输入不同字体的文字,

erlang基础知识集锦

Erlang基础知识集锦 声明:此文档只作为对erlang的认知之用,如果需要学习并使用erlang 请系统学习介绍erlang的书。 1.简介 ●Erlang是一个并行编程语言和运行时系统,最初由爱立信(Ericsson)于1987年 为电信行业所开发。1998年爱立信在改良的MPL(Mozilla Public License)许可 下将Erlang发布于开源社区。 ●Erlang是: a)一种“小众”语言。 b)一种函数式语言(变量只能赋值一次)。 c)一种动态类型语言(变量类型在运行时决定,代码需要编译后才能执行,与 Python,Ruby等不一样)。 d)一种强类型语言。 e)一种面向并发(Concurrency Oriented)的语言。 2.特性 ●并发性 - Erlang支持超大量级的并发线程,并且不需要操作系统具有并发机制。 ●分布式 - 一个分布式Erlang系统是多个Erlang节点组成的网络(通常每个处理 器被作为一个节点)。 ●健壮性 - Erlang具有多种基本的错误检测能力,它们能够用于构建容错系统。 ●软实时性- Erlang支持可编程的“软”实时系统,使用了递增式垃圾收集技术。 ●热代码升级-Erlang允许程序代码在运行系统中被修改。旧代码能被逐步淘汰而后 被新代码替换。在此过渡期间,新旧代码是共存的。 ●递增式代码装载-用户能够控制代码如何被装载的细节。 ●外部接口-Erlang进程与外部世界之间的通讯使用和在Erlang进程之间相同的消 息传送机制。 3.数据类型 3.1.变量 3.1.1.在erlang中的变量只能被赋值一次,变量第一个字母要是大写的。 3.1.2.符号”=”是值类型匹配操作(带有赋值的意思)。(pattern matching) 3.1.3.在erlang中变量是不可变的,也没有共享内存的概念,也没有锁。 3.2.浮点数 3.2.1.整数除法示例: 4 div 2。 3.2.2.求余示例: 5 rem 2。 3.2.3.“/”永远返回浮点数。 3.3.Atoms(原子) 3.3.1.Atoms表示不同的非数字常量值。 3.3.2.示例:Xss = 'Asss'。

ErlangC计算公式

Erlang C计算公式 在呼叫中心摸爬滚打4年了,主要从事排班工作,近来发现很多同行跪求Erlang C公式,身边很多同事都不知Erlang C为何物。想想当年刚入行时自己搜遍yahoo、google也没搜索到多少国外有价值的资料,最多只是个30天试用版的软件,更别提国内的信息了,走了很多弯路,耗费了不少青春在资料收集上。 今天就把它作为我开博的第一篇文章,给大家简单地讲讲,如有不足还望海涵Erlang 全名:Agner Krarup Erlang (1878~ 1929),丹麦人,数学家,电气工程师 其发明的Erlang B 和Erlang C公式在金融、电信、运输、网络、呼叫中心等领域得到广泛运用 呼叫中心主要利用这个公式来计算满足服务水平目标所需要的人员数量以及中 继线数量即通常所说的根据每小时电话量要求20秒达到80%的接通率需要多少人? 目前绝大部分排班软件都采用Eralng C+ Abandon Rate模型,两大产品Aspect 和Blue Pumpkin均以此为模型。 接下来进入正题 : Erlang C的公式

第一反应是不是和我当初一样“晕,虾米东西!” 呵呵! 这也算是当初网上能搜索到的最详尽资料了 别害怕,我可不会写到此就结束的先从各个参数说起: 假设呼叫中心每半个小时进线量360通、平均处理时长4分钟、一共有55个客服人员、服务水平目标为15秒 第1个参数 λ=average arrival rate (来电频率/密度)=360通/半小时÷1800秒=0.2通/秒 第2个参数 Ts=average call duration(平均每通电话时长)=240秒/通

why_choose_Erlang

我为什么选择了Erlang? 许式伟 2007-10-10

面向的受众 ?我们不解释Erlang基础文法。假设读者已经对Erlang进行过了解。如果你期望入门资料,那么它并不适合你。 ?本文谨献给那么已经初步了解Erlang,仍然赶到迷茫与困惑的人。

Erlang推荐资料 ?Programming Erlang ?Course.pdf ?Joes thesis 2003 –面对软件错误构建可靠的分布式系统(段先德译)

纲要 ?Erlang为什么广受关注? –业界趋势 –Erlang的问题域 ?Erlang的哲学 ?Erlang的困惑 ?Erlang流行的困难之处 –如何应对 ?Erlang的不足(非设计缺陷)

Erlang为什么广受关注??2007 has been a good year for Erlang –Amazon ?Joe's book (Programming Erlang) is ranked #86 on the https://www.wendangku.net/doc/2012765633.html, bestseller list (category: computers & internet) –Google Trends ?https://www.wendangku.net/doc/2012765633.html,/trends?q=smalltalk %2C+erlang ?https://www.wendangku.net/doc/2012765633.html,/trends?q=erlang%2 C+ocaml

并行、分布式的趋势 ?多核(并行) –让我们假设Intel是正确的:让我们假设 Keifer 项目会获得成功。如果是这样,那么 32个核心 的处理器在2009/2010年就将会出现在市场上。 –这毫不奇怪,Sun已经制造出了Niagara,它拥 有8 个核,每个核运行4个超线程(这相当于32 个核)。 –《What's all this fuss about Erlang?》 ?by Joe Armstrong (Erlang创始人)

爱尔朗(Erlang)分布

爱尔朗分布(Erlang Distribution ) 在概率与统计相关学科中,爱尔朗分布(Erlang Distribution )是一种连续型概率分布。Erlang 分布的译名较多,如爱尔兰分布,埃朗分布,埃尔朗分布,爱尔朗分布,厄朗分布等等;此外在不同学科间,Erlang 分布的习惯译法也可能不同。 该分布与指数分布一样多用来表示独立随机事件发生的时间间隔。相比于指数分布,爱尔朗分布能更好地对现实数据进行拟合(更适用于多个串行过程,或无记忆性假设不显著的情况下)。除非退化为指数分布,爱尔朗分布不具有无记忆性(或马尔可夫性质),因此对其进行分析相对困难一些。一般通过将爱尔朗过程分解为多个指数过程的技巧来对爱尔朗分布进行分析。 遵循爱尔朗分布的随机变量可以被分解多个同参数指数分布随机变量之和,该性质使得爱尔朗分布被广泛用于排队论中。 参数与公式爱尔朗分布有两个参数,阶数(stage )k 和均值μ(也有用来代替的)。具有阶数k 的爱尔朗过程被称为k 阶爱尔朗(k-stage Erlang ),对应的随机变量可被视为k 个同参数指数分布随机变量之和。依据上下文环境不同,均值参数μ可以指整个爱尔朗分布的均值μ0也可以指每个指数分布的均值μi 。两者的关系 是:[编辑]与其他概率分布的关系爱尔朗分布是一种Phase-Type 分布。它是亚指数分布的一个特例(各阶指数过程均值都相等的k 阶亚指数分布即为k 阶爱尔朗分布);而指数分布则是爱尔朗分布的一个特例(阶数k= 1的爱尔朗分布即为指数分布)。[编辑]Speical Erlang“Speical Erlang”分布 是亚指数分布的一个别名。需要注意的是,Special Erlang 并非爱尔朗分布(Erlang )的特例。正好相反,爱尔朗(Erlang )分布是Special Erlang 的一个特例。 爱尔朗分布模型: 设V 1,V 2,…,V k 相互独立,V i ~E(0 ,k μ),则,T=V 1+V 2+…+V k 的概率密度为 ?????<>-=-.0,0,0,)!1()()(1 t t k kt k t f k k μμ 称T 服从k 阶爱尔朗分布。 例:串列的k 个服务台,每个服务台的服务时间相互独立,服从相同的指数分布,则k 个服务台的总服务时间服从k 阶爱尔朗分

【ctoroad】Erlang十分钟快速入门

Erlang概述 Erlang不但是一种编程语言,而且它具有比编程语言更加贴近操作系统的一些特性:并发线程、作业调度、内存管理、分布式、网络化等。据说使用Erlang 编写的Yaws Web服务器,其并发性能是apache的15倍! 这个Erlang初始开源版本包含了Erlang的实现,同时它也是用于构建分布式高可用性系统的Ericsson中间件的最大组成部分。 Erlang具有以下特性: 并发性 - Erlang具有超强的轻量级进程,这种进程对内存的需求是动态变化的,并且它没有共享内存和通过异步消息传送的通讯。Erlang支持超大量级的并发线程,并且不需要操作系统具有并发机制。 分布式 - Erlang被设计用于运行在分布式环境下。一个Erlang虚拟机被成为Erlang节点。一个分布式Erlang系统是多个Erlang节点组成的网络(通常每个处理器被作为一个节点)。一个Erlang节点能够创建运行在其它节点上的并行线程,而其它节点可以使用其它操作系统。线程依赖不同节点之间的通讯,这完全和它依赖于单一节点一样。 健壮性 - Erlang具有多种基本的错误检测能力,它们能够用于构建容错系统。例如,进程能够监控其它进程的状态和活动,甚至这些进程是在其它节点上执行。在分布式系统中的线程能够配置为在其它节点故障的情况下自动进行故障恢复,并在故障节点恢复时自动迁移回到恢复节点。 软实时性 - Erlang支持可编程的“软”实时系统,这种系统需要反应时间在毫秒级。而在这种系统中,长时间的垃圾收集(garbage collection)延迟是无法接受的,因此Erlang使用了递增式垃圾收集技术。 热代码升级 - 一些系统不能够由于软件维护而停止运行。Erlang允许程序代码在运行系统中被修改。旧代码能被逐步淘汰而后被新代码替换。在此过渡期间,新旧代码是共存的。这也使得安装bug补丁、在运行系统上升级而不干扰系统操作成为了可能。 递增式代码装载 - 用户能够控制代码如何被装载的细节。在嵌入式系统中,所有代码通常是在启动时就被完全装载。而在开发系统中,代码是按需装载的,甚至在系统运行时被装载的。如果测试到了未覆盖的bug,那么只有具有bug的代码需要被替换。 外部接口 - Erlang进程与外部世界之间的通讯使用和在Erlang进程之间相同的消息传送机制。这种机制被用于和操作系统通讯、与其它语言编写的程序交互。如果出于高效率的需要,这种机制的一个特殊版本也允许例如C程序这样的代码

erlang-c

呼叫中心主要利用这个公式来计算满足服务水平目标所需要的人员数量以及中继线数量即通常所说的根据每小时电话量要求20秒达到80%的接通率需要多少人? 目前绝大部分排班软件都采用Eralng C+ Abandon Rate模型,两大产品Aspect和Bl ue Pumpkin均以此为模型。 接下来进入正题 : Erlang C的公式 第一反应是不是和我当初一样“晕,虾米东西!” 呵呵! 这也算是当初网上能搜索到的最详尽资料了 别害怕,我可不会写到此就结束的先从各个参数说起: 假设呼叫中心每半个小时进线量360通、平均处理时长4分钟、一共有55个客服人员、服务水平目标为15秒 第1个参数 λ=average arrival rate (来电频率/密度)=360通/半小时÷1800秒=0.2通/秒第2个参数

Ts=average call duration(平均每通电话时长)=240秒/通 第3个参数 m=numbers of agents(坐席数)=55人 第4个参数 traffic intensify(话务强度)= λ×TS =0.2通/秒×240秒/通=48秒/秒 我理解为每秒需要处理48秒的工作量,即每秒需要48个人 换另一种工作量算法可能大家更容易懂,即360通电话,每通240秒,那么处理这些电话共需 86400秒,而每个座席员每半小时有1800秒,在最理想化的状态下我们也需要3 60×240÷1800=48 人 第5个参数 P= agent occupancy(占用率) = 48人÷55人 =87.3%

好了,接下来就开始代入Erlang C公式 m!即m的阶乘,这里即1*2*3*4*.....*54*55 Excel中可用=fact(55)计算 这个呐就是加总从K=0开始一直算到k=m-1为止,这里即算到k=54为止因此得出最终结果0.239 当然死算也是可以算出来的,可是我们有这个世纪最强大便捷的工具Excel,作为跨时代的接班人就要好好掌握利用(不是广告,呵呵) 因为Erlang方程是由泊松方程(poisson)推出来的,excel中也有该函数什么?泊松方程(poisson)是什么?这个就要从概率讲起,在此略过这个强大的过程,各位勤奋好学的自己搜索,哈! 那么该公式Ec(m,u)在Excel中可表达为=poisson(m,u,false)/(poisson(m,u,false) +(1-P)*poisson(m-1,u,true)) prob(call has to wait)呼叫等待的概率=23.9%

Verilog基础

Verilog基础 一基本要素 (1)Verilog HDL与VHDL 1.它于1995年成为IEEE标准,即standard 1364-1995。VHDL于1987年成为IEEE标准。 2.类C语言,不允许自定义数据类型(VHDL可以)。 3.可描述开关级电路模型,但信号初值不确定,必须由程序初始化;VHDL系统数据定义后没有赋值则默认为0,对系统级支持能力要强一些。 (2)IC设计流程: 系统结构设计与仿真——>HDL设计——>TestBench功能模拟测试、逻辑仿真——>综合成逻辑门(工艺库、约束文件)——>初步时序分析(静态、电压、温度)——>自动布线布局——>后端报告(布局布线后增加的电阻、电容)——>动态(布局后)时序仿真,任何的建立例外都必须通过优化产生该例外的路径,以减小延迟;任何保持例外都必须通过在产生例外的路径上增加缓存,来增加延迟——>逻辑验证——>投片生产。 (3)标识符与关键字命名 1.标识符首字不能为数字或$,可以为字母和下划线, 2.命名长度不能超过1024, 3.区分大小写(与VHDL不同); 4.系统任务和系统函数前必须在标识符前加上$。 5.转义标识符\ 开头,以空格、制表符(tab键)或换行符结尾,可显示打印ASCII字符。 (4)系统任务和系统函数 1.display(信息输出到标准输出设备,带行结束符)和write(输出信息不带行结束符)。用于显示输出的特殊字符: \\n 换行 \\t 制表符 \\\\ 字符\\\

\\" 字符" \\ddd 值为十六进制字符 %% 字符% 格式定义: %h或%H: 十六进制 %d或%D: 十进制 %o或%O: 八进制 %b或%B: 二进制 %c或%C: ASCII字符 %v或%V: 线网信号长度 %m或%M: 层次名 %s或%S: 字符串 %t或%T: 当前时间格式 缺省如$displayb: 显示二进制数, 2.monitor 监控和显示指定任务的参数值, 3.strobe 显示数据,保证数据只在所有赋值语句执行完毕时才被显示;(而$display()任务执行通常是确定的)。 4.文件输入输出 a.文件打开和关闭:系统函数$fopen()和$fclose(), b.输出值到文件:$fdisplay,$fwrite,$fstrobe,$fmonitor,这些任务的第一个参数都是文件指针,其余参数为带有从参数表的格式定义序列。 c.从文件中读出数据并载入存储器:$readmemb,$readmenh用于指定文件中读取并载入数据到指定的存储器。可在模拟时间的任何时刻执行,读取的文件只能包含如下内容: 空格、换行符、制表符(tab键)、换页;注释;二进制和十六进制;

史上最完整的erlang环境配置

Erlang环境配置 1.安装erlang运行时。直接双击运行otp_win32_R16B0 2.exe,按照提示一步步安装即可。 2.安装java运行时。直接双击运行jre-7u5-windows-i586.exe,安装提示一步步安装即可。 3.安装eclipse。将压缩包eclipse-standard-kepler-SR1-win32.zip解压到任意目录下即可。 4.安装erlide插件。将erlide目录下的所有文件拷贝到eclipse解压所在目录,并修改link 目录下的.link文件里面的路径名,使指向plus目录下的插件(注:路径中不能有中文出现), ok. 5.配置erlide。在菜单上依次选择[Window]->[preference],在左边选择栏找到 [Erlang]->[Installed runtimes],然后点击右边的[add]按钮,选择你安装Erlang的路径,如果你有多个Erlang安装版本可以依次设置。 6.新建工程。在菜单上依次选择[File]->[New]->[Project],然后选择[Erlang]->[Erlang Project]。 填写Project Name,比如“ElTest”,余下的按默认设置,点击[Next],最后是[Finish]。 7.新建module。 在左边新建的project里右键点击[src],选择[new module],在弹出的窗口里填入以下信息。 Module name:Test Container:/ElTest/src (默认) Application name:None (默认) Skeleton:None (默认) 在最下面的两个输入框里输入say(这个是方法名)和0(参数个数),然后点击[Apply]按钮。最后点击[finish]按钮。 编辑新生成的module如以下代码 1.%% Author: WQF 2.%% Created: 2008-11-9 3.%% Description: TODO: Add description to test 4.-module(test). 5. 6.%% 7.%% Include files 8.%% 9. 10.%% 11.%% Exported Functions 12.%% 13.-export([say/0]). 14. 15.%% 16.%% API Functions 17.%% 18.

erlang中文基础教程

Erlang 编程(第一部分) 1 顺序编程 1.1 The Erlang Shell 大多数操作系统都有一个命令行交互环境或者一个shell,对于UNIX和LINUX尤其是这样。Windows也有自己的命令行模式。Erlang也同样有自己的shell,我们可以直接在里面编写代码和运行我们编写的程序,并在其中看到我们的输出情况。我们能够在多种操作系统上运行Erlang的shell,一般来说在我们所使用的操作系统的命令行中输入erl就可以了,我们将可能看到下面的提示: % erl Erlang (BEAM) emulator version 5.2 [source] [hipe] Eshell V5.2 (abort with ^G) 1> 现在我们输入“2 + 5.”,(注意最后有一个英文句号,并不包括引号哈) 1> 2 + 5. 7 2> 在Windows中,我们还可以通过双击Erlang shell的图标来启动Erlang shell。 你现在注意到了Erlang shell的命令行前面都有一个标号(例如1> 2>),并且下面正确的输出了我们的答案“7”!同样我们注意到我们的输入的最后有一个英文的句号,这是在我们最终按下回车之前的最后一个字符。如果我们写在shell中的东西有什么错误,我们可以使用退格键进行删除,于是,我们推想我们可以使用其他shell下的一些常用的编辑命令,而事实上确实是这样的,以后我们使用到的时候再介绍。现在我们尝试一下稍微复杂一点的运算: 2> (42 + 77) * 66 / 3. 2618.00 我们现在使用了一些“复杂一点”的运算符号“*”和“/”,分别表示乘法运算和除法运算。除此之外还支持其他一些运算符号,我们在以后使用到的时候再介绍。 我们打算关闭Elrang系统,则需要在Erlang shell中键入Ctrl+C,我们将看到下面的输出: BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded (v)ersion (k)ill (D)b-tables (d)istribution a % 我们这时候键入“a”就会退出Erlang系统。 另一个方法就是键入 halt(),也可以实现退出Erlang系统的目的: 3> halt(). % 1.2 Modules 和 Functions (模块和函数) 一个编程语言如果只能让我们从shell中运行代码,那么可以说这个语言的用处受到了很大的限制,至少我会感觉到不爽。这里有一个小的Erlang程序。我们将下面的内容键入一个叫做tut.erl的文件(这里需要注意到的是我们的tut.erl文件应该放在erl程序的同一个目录下,文件名应该和模块名相同,这样Erlang才能很好的找到我们的模块,至于编辑器随便一个支持纯文本的就可以哈)。如果我们的编辑器有一个Erlang模式就可能编写起来更加方便,并且代码的格式也会变得更加规范,但是我们也许也会产生对这些编辑器或者IDE的强烈依赖性。下面就是我们要键入的代码: -module(tut). -export([double/1]). double(X) -> 2 * X.

Erlang_C推算方法

Erlang-C公式推算方法 推导Erlang-C公式的计算方法,使用的案例为:半小时来电数量为360通,平均通话时长为4分钟,坐席数量为55人,对应服务水平的目标应答时间为15秒。 (1)定义来电率: 第一项定义是客户平均来电率。无论用什么时间单位定义来电率,都必须要与平均通话时长的时间单位相一致,并与要推导出的等待时间的时间单位一致。 λ=平均来电率 = (360个来电/半个小时)/(1800秒/半个小时) = 0.2来电/秒 (2)定义通话时长: 第二项定义是平均通话时长,应与来电率用同样的时间单位。 Ts=平均通话时长 = 4分钟 = 240秒 (3)定义坐席数量: 第三项定义为可使用的坐席数量。m=坐席数量 = 55名坐席 (4)计算话务量强度: 术语“话务量强度”来源于最初对Erlang-C的使用,对电话网络来说,来电数量被称为“话务量”,我们需要计算话务量强度,以做为下面计算的第一步。 u=λ·Ts =话务量强度 = (0.2来电/秒)·(240秒/每个来电)= 48 (5)计算坐席使用率: 坐席使用率或利用率,是用话务量强度除以坐席数量计算得出的。坐席使用率在0到1之间。如果它大于等于1则表示坐席工作已超负荷了,Erlang-C的计算就没有意义了,并可能得出负的等待时间。 ρ=u m =坐席使用率 = 48/55 = 0.873 或(0.873)·100% = 87.3% (6)计算Erlang-C公式: 现在,我们可以计算Erlang-C的主要公式。这个公式看起来有点复杂,但可以用几行程序直接计算。值就是我们需要计算的结果。 = 0.239 (7)计算等待概率: 是一个来电没有被及时应答而不得不等待的概率。此概率在0到1之间,当我们乘以100%时就表示来电等待的百分比。 Prob(需要等待的通话) = =0.239 或 0.239× 100% = 23.9%

RabbitMQ基础概念详细介绍

RabbitMQ基础 你是否遇到过两个(多个)系统间需要通过定时任务来同步某些数据? 你是否在为异构系统的不同进程间相互调用、通讯的问题而苦恼、挣扎? 如果是,那么恭喜你,消息服务让你可以很轻松地解决这些问题。 消息服务擅长于解决多系统、异构系统间的数据交换(消息通知/通讯)问题,你也可以把它用于系统间服务的相互调用(RPC)。本文将要介绍的RabbitMQ就是当前最主流的消息中间件之一。 RabbitMQ简介 AMQP(Advanced Message Queuing Protocol高级消息队列协议),是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。 AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。 RabbitMQ是一个开源的AMQP实现,服务器端用Erlang语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP等,支持AJAX。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。 ConnectionFactory、Connection、Channel ConnectionFactory、Connection、Channel都是RabbitMQ对外提供的API中最基本的对象。 ●Connection是RabbitMQ的socket链接,它封装了socket协议相关部分逻辑; ●ConnectionFactory为Connection的制造工厂; ●Channel是我们与RabbitMQ打交道的最重要的一个接口,我们大部分的业务操作是在Channel这个接口中 完成的,包括定义Queue、定义Exchange、绑定Queue与Exchange、发布消息等; Queue Queue(队列)是RabbitMQ的内部对象,用于存储消息,用下图表示。 RabbitMQ中的消息都只能存储在Queue中,生产者(下图中的P)生产消息并最终投递到Queue中,消费者(下图中的C)可以从Queue中获取消息并消费。 多个消费者可以订阅同一个Queue,这时Queue中的消息会被平均分摊给多个消费者进行处理,而不是每个消费者都收到所有的消息并处理。

相关文档