- 浏览: 220911 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
dysking:
SWT 和 JFace -
wangyuhfut:
东西不少啊。学习中。。。
一个比较好、中文说明的emacs配置文件 1 -
pacocai:
呵呵!学习,学习~~~不过要说编辑器的话个人更喜欢用VIM,比 ...
一个比较好、中文说明的emacs配置文件 1 -
zhf1zhf2:
这两百多个记起来也不容易啊
英国人是这样背的! -
regex:
试了两次,都是乱码,版本是23.1.1,看来不适合
汉化 Emacs 菜单
Tango Clusters中文翻译
原文:[url]http://joyfire.spaces.live.com/blog/cns!502060A314B1A145!1601.entry
[/url]
这是占位贴。最近在玩D语言,我手头马上面临的工作又和集群运算有关,所以自然对Tina格外关注。因此准备把Tango库文档的Clusters这一节翻成中文,每天逐步翻译一点。这是件需要毅力的事,所以预先昭告天下,断自己的后路。
向不太熟悉的朋友简单介绍一下:D语言的官方标准运行时库是phobos,而Tango是目前比较完善的第三方类库,Tina是后者集群部分中QOS的一个参考实现(你也可以继承有关interface,自己实现QOS组件,见下文)。你还可以到dsource.org上查找更多D语言的类库、代码实例、开发工具和开源项目。除了phobos和Tango两个类库,dsource.org上另一个常用项目是dsss工具包,它用于配置、编译、安装D语言的整套开发环境,自动处理phobos和Tango并存的兼容性问题。刚结束的D Conference 2007上有Tina(ppt和pdf)、dsource.org(ppt)和dsss(pdf)的专题讲座可供参考。
Tango Clusters
(原文地址:http://www.dsource.org/projects/tango/wiki/ChapterClustering,版权属于原作者)
(中文译文转载,请保留http://joyfire.spaces.live.com地址)
Clusters就是电脑集群,我们认为,所谓“集群”是指,同处局域网内,分布执行关联任务的一组电脑。很多种应用都能从分布式获得好处;具体来说,相比于单机架构,分布式的设计将给应用程序带来更好的可拓展性。
例如,集群常常用于高性能计算:通过把大块的计算量分解到网络上的多个从机,一个计算密集性的应用能相当有效地提高计算量,或减少计算时间。按需求情况可以把更多从机加入集群。如果原有硬件脱离了集群,其他从机可以分担它的任务。
另一个例子是分布式保存某些需要频繁读取的数据,通过集群向一组客户端提供快速读取服务。这种设计的典型意图是缓解对关键单点(例如数据库)的抢占,以提高系统整体的计算能力。
再进一步的例子,是设计能力不可能应付请求的极端峰值的应用系统。这些系统需要一种机制来缓冲请求,而不是即时响应处理。在某些特定情况下,应用系统会把请求持久化存储起来,等到更合适的时机再去真正处理。虽然这可以通过数据库或类似方式实现,但更轻量分散的方式也许更适当。尤其是当吞吐量很敏感的情况下,数据库本身就可能会成为瓶颈。工作流系统就倾向于这种风格的缓冲方式。
以上所有场景,集群都有用武之地。Tango库支持很有吸引力和灵活性的集群模型,以帮助你不费太多事就可以构建这种应用,
作为使用体验,这里有一段在集群上执行expression任务的D语言代码示例:
real add (real x, real y) {return x + y;}
void main (char[][] args)
{
scope add = new NetCall!(add);
Stdout.formatln ("cluster expression of 3.0 + 4.0 = {}", add(3, 4));
}
可适用性
Tango工具包把集群的常用行为归纳成4种类型加以支持:消息队列,消息缓存,消息执行和消息广播。对应这4种行为的实现机制分别是queue, cache, task和bulletin。
基本概念为,你在一台或更多联网的计算机上启动一个或更多cache、queue、task服务器端实例,通过一个或多个集群客户端来调用它们。这些客户端链接入(link)你的应用程序,使其可以使用各种集群功能——它帮你的应用管理集群通讯,提供各种失败情况下的强大容错能力。总之,若干客户端会与潜在的若干cache、queue、task服务器端通话。
衡量集群应用是否成功的一个关键因素,就是看它对以下情况的鲁棒性:瞬时的传输拥塞,变化的反应延时,集群成员节点的增减(包括潜在的硬件错误)。评价因素还包括效率,既有选择的通讯中介的效率,也有应用实体在集群中转移的传输效率。
模型和QOS
Tango集群用由D语言的interface和工具class组成的模型来描述。这种设计的目的是,使不同的集群实现方式都拥有一个相同的模型,稍做微小改动就能切换到另一种不同的实现方式。为什么要有多种不同的实现方式?因为不同的应用有不同的需要——有的认为吞吐量是绝对重要的,有的认为数据的复制更需要重视,还有的可能需要某种特殊行为。
也就是说,该模型打算跨越各种不同需要和实现。不同的需要和实现要用到不同的服务质量或QOS。若一个集群应用程序同时使用多种QOS实现,以满足不同的目标,也是完全可行的。
为了加入集群,应用程序需要一个QOS客户端实例。通过这一点,所有活动都能被模型的工具class纳入管理。也就是说,QOS是一个单独的、公平的、简洁的、几乎透明的组件。模型的工具class在此之上提供附加行为。
该模型本身受到了一些现存系统的影响,包括hints的发布和订阅、Linda、JavaSpaces等,还有其它一些你可能已经熟悉的系统。
接触Tina
类库提供的一组服务就是一个内置QOS实现,以便快速开发集群应用。它主要由三个服务器端构成,这三个服务器端分别支持cache、 queue、task三种集群服务方式。另外它还包括与服务器端相关的集群客户端的实现。前者(服务器端)是独立的、有自己权限的应用程序。而后者(客户端)要链接到你的应用程序里,以使集群对它可见。Bulletins是彻底由客户端实例操作的,在对等(P2P)方式下不存在bulletin服务器。
Tango用D语言源码module来描述服务器端,同时提供完整而简洁的代码作为构造相应服务器的例子。客户端通过一个class暴露给用户调用,应用程序实例化这个class就可以了。两者结合,让你快速简单地构建出应用系统的专用集群。
这个内置的QOS是面向高效连接的,其重点是避免任何堆积行为(除在cache hosting这种必要情况下)。它既平衡了传输中的TCP/IP和多播,也平衡了序列存储中的磁盘文件。它有个爱称叫Tina,应用程序使用Tina,需要import tango.net.cluster.tina.Cluster
关键概念
无论任何工具包,为了发挥它最大的功效,都需要熟悉一些关键概念。这些概念不多,我们会在这一节里专门解释。首先从频道(channel)开始。
频道(Channel)
如果使用过发布/订阅系统,对频道的概念应该比较熟悉。频道是消息传输和交付所通过的实体的名字。集群应用订阅(或监听)频道,发布(或写入)频道。没有它就无法与集群进行通讯。你向QOS提出要求,由它代表你创建一个频道,此后就开始使用。实际上,模型里有很多躲在后台的工具 class为你实现频道的创建。然而,你可以在需要时自由使用频道。
有了频道,应用就可以发送或请求集群消息,监听异步行为,在网络里执行任务。模型里的很多工具class在此基础上提供出一个结构化的框架,在适当的地方添加进一步价值。
当一个消息(message)被一个命名频道送出,只有监听同一个频道的候选者才接收到这个消息。频道的名字必须在所有通讯地点保持一致:这样就提供了隔离不同目的的不同类型消息的基础。实践中我们发现,使用点分隔符号的频道名字(例如 employee.contact.information)非常方便,易于对消息类型区分和聚合。实际上频道是描述D语言class的好方法——每个频道对应一个独立的class——它非常精细地隔离了彼此不一致的内容,显著简化了集群自身相互间聚合数据的传输。刚好,接下来要提到的概念就是消息。
消息(Message)
消息是所有集群上下文的基础。你向queue存入东西,是以消息形式发送的;从cache恢复内容,其实也是接收一个消息;当在集群中执行task,它表达为消息;当异步多播的bulletin在集群中分布式交互时,它们就是消息的实例。总之集群里的一切都是消息。
当用D编程语言,每个集群消息都被实现为一个class。进一步的,所有消息或继承于NetworkMessage工具class,或实现了IMessage接口(interface)。消息实例被转换成网络协议包,在集群之间传输。
有一个模板能用来为你很方便地生成一小段代码,负责消息和网络协议包之间的相互转换;另一种办法是通过实现两个简单的消息方法来明确控制转换行为。如果你使用模板,所有本地数据都被加入用于发送和恢复的消息;如果只处理消息的一部分,就要通过两个预订(译者注:回调或委托)方法对如何转换进行干预。
所有消息变量默认都要注册。也就是说,为了让集群客户端能正确重建输入消息,每种消息类型都必须在应用启动时提交给 NetworkRegistry。有一种特殊情况不需要注册——task不要求客户端注册,如果你明确提供了输入消息的主机,就不用注册了。然而,注册你应用中用到的所有消息类型是种好习惯。消息的静态构造函数是个适于注册的位置。例如:
import tango.net.cluster.NetworkMessage,
tango.net.cluster.NetworkRegistry;
class MyMessage : Message
{
static this()
{
NetworkRegistry.shared.enroll (new MyMessage);
}
}
除要求注册以外,每个消息就是一个标准的D语言class,可以以一般形式进行操作。它仅仅是拥有了一种附加能力:可以在集群上的其他机器出现并随意行动。
队列(Queue)
queue是消息的贮藏。每个queue都有自己的频道,即被队列化的频道会有单独的queue实例。消息通过频道行为存入 queue,再以相同方式从queue恢复。这些操作是同步方式。与此不同,消息的消费者(频道的订阅者)能以异步方式监听消息行为,当queue存在变动,就把消息提供给它们。两种方法都有自己的优势,由你自己选择。
queue内的消息不单独设定地址;当你查找一个消息,不能指定与请求有关的特殊值。queue把单独的频道名字隔离起来的,没有任何其他元数据。
queue消息既可以在无进一步动作的情况下被消费,也可以有返回。典型的返回通过另一个频道发送(对原始频道的名字做修改),在始发者接收前,返回消息经常被队列化。始发者要监听返回,监听方式与订阅其他队列化消息一样。
queue是持久化的,可以经受电力故障和重启。
缓存(Cache)
Cache主机以非常类似联合数组或哈希表的方式存储消息。消息用频道名隔开,以键值进行检索。在Tango里,这个键值是char类型的数组。
放在集群cache里的消息会被同一频道中拥有相同key的实体替代。进一步,用有条件的时间戳来控制对"新"的检验。后者在分布式环境下是重要有用的。这种环境下,也许会出现cache更新冲突。cache实例会自动清除旧的实体,以便为新的内容释放必要空间。
通过使用模型工具,集群的cache可以进行部分本地复制。这个机制模拟了经典的level1/level2 combination,这会对很多应用程序都有用。模型工具还使保持一组cache实例的一致变得容易。
Cache实例仅仅打算临时驻留在内存里,即Tina的实现不对它们进行持久化保存。
任务(Task)
task是可执行的消息,在调用进程以外执行。通常,task会发送到集群中的某个能执行该任务的服务器端上去,执行后把运行结果返回给调用者。这是一个同步方式的执行模型。对于去耦(decoupled)执行模型(译者注:异步方式),任务可以先发送到一个queue上挂起,直到有订阅者恢复并执行它。这种模型下的返回一般通过另外一个queue发送,和一般的queue消息返回方式一样(参考前文的queue)。
相比其它消息类型task有些独特性,因为它是主动消息,不是被动的。和queue或cache里面躺在那里等待相比,task消息是打算要在集群里面干点什么。这意味着,task消息为了这个目的必须实现execute()方法。有一种被称为expression的task,仅由一个简单的函数构成。这种任务可以被NetCall模板转化成一个真正的task实例,这个模板吧函数当作参数,返回一个task实例。这篇文章的开头演示了这种用法。
task消息另一个独特之处在于,它应该在集群上被注册。这就意味着task消息是每个task服务器端的主要组成部分,以便可以在服务器端被执行。实际上,有两种主要的可选方式:把task消息静态链接到每个task服务器端,或动态发布并链接到每个task服务器端。请注意,现在D语言并没有在所有平台上都实现动态链接,所以默认Tina实现task是采用前者——注册task服务器,注册的内容是端口和方法调用。
公告(Bulletin)
这是一种发送给对所有集群成员的通知消息类型,它调用能用到的最有效的底层机制。这种消息的大小尺寸受到限制(一般小于1K),它本质上就打算简单和轻量级。Tina QOS使用bulletins来进行cluster发现,queue活动通知,cache同步,用广播作为分布式机制。当一个bulletin被发送,所有同一频道的监听者都会接收到。
bulletins的应用层潜在用途是通知所有监听者关机。这种方法用来确保所有服务器端实例在相同版本下运行——新版本被写入中心位置,然后批处理任务通知服务器端重启,无论它是否已经被停止过(以改用新版)。
推 Vs. 拉(Push versus Pull)
Tango集群支持两种访问内容的形式。cache或queue内容的请求是同步调用,也就是常说的拉(pull)模型;另一方面,创建queue活动或bulletin的监听者使用异步通知,就是所谓推(push)模型,若没有明确订阅某种特殊消息,内容就不会被推给的该接收者。
类似同步要求,异步的push通知在特定的频道上进行传输:你得到你想要的,没有其他多余的。push和pull的主要区别在于,前者可能出现在一个独立的执行线程中,所以你必须了解一般多线程情况下可能碰到的潜在问题(例如对共享资源的同时访问)。
当通知出现时,到达的内容和输入的消息通过变量形式传送给监听者。大多数情况下,到达的消息是描述一个通知内容的单独实体。然而,queue通知会集中传输一个或多个序列消息。
客户端使用
在这一节我们通过代码例子看看如何使用集群功能。首先需要import适当的集群。在以下这些例子里我们会一直使用Tina QOS,但对其他实现要import对应的包取而代之。注意这里主要关注客户端,服务器端在后一节介绍。
Cache客户端
这个例子演示如何把cluster作为分布式cache使用。这里仅仅演示了主要概念,还有其他很多可用的操作。注意我们把命令行参数传输给join()方法:为cache设置一组有效可用的cache实例。和其他设施不同,cache实例不是自发现的(self- discovering)。
import tango.net.cluster.NetworkCache;
import tango.net.cluster.tina.Cluster;
void main (char[][] args)
{
if (args.length > 1)
{
// hook into the cluster
auto cluster = (new Cluster).join (args[1..$]);
// hook into the Cache layer
auto cache = new NetworkCache (cluster, "my.cache.channel");
// add a cache entry to the cluster
cache.put ("key", cache.EmptyMessage);
// retrieve it from the cluster
auto msg = cache.get ("key");
}
else
Stdout.formatln ("usage: cache cachehost:port ...");
}
Bulletin客户端
怎样通过集群发送和接受通知。这些通知被发送给某个特殊广播频道的每个监听者。注意我们创建了一个回调函数,传给集群作为bulletin的消费者。
private import tango.net.cluster.NetworkAlert;
private import tango.net.cluster.tina.Cluster;
void main (char[][] args)
{
// hook into the cluster
auto cluster = (new Cluster).join;
// hook into the Alert layer
auto alert = new NetworkAlert (cluster, "my.kind.of.alert");
// declare a listener
void listen (IEvent event)
{
event.log.info ("Received alert on channel " ~ event.channel.name);
}
// listen for the broadcast (on this channel)
alert.createConsumer (&listen);
// and send everyone an empty alert (on this channel)
alert.broadcast;
// wait for it to arrive ...
Thread.sleep(1);
}
Queue拉客户端
下文演示怎样在同步模型下安装和使用queue。我们把一些东西放入queue,然后再恢复出来。
private import tango.net.cluster.NetworkQueue;
private import tango.net.cluster.tina.Cluster;
void main (char[][] args)
{
// join the cluster
auto cluster = (new Cluster).join;
// access a queue of the specified name
auto queue = new NetworkQueue (cluster, "my.queue.channel");
// stuff something into the queue
queue.put (queue.EmptyMessage);
// retrieve it synchronously
auto msg = queue.get;
}
Queue推客户端
这里演示如何在异步模式下安装和使用queue。我们把监听者委托(delegate)给集群,当订阅的内容从集群任何地方到达queue,监听者就会被调用。
private import tango.net.cluster.NetworkQueue;
private import tango.net.cluster.tina.Cluster;
void main (char[][] args)
{
// join the cluster
auto cluster = (new Cluster).join;
// access a queue of the specified name
auto queue = new NetworkQueue (cluster, "my.queue.channel");
// declare a listener
void listen (IEvent event)
{
while (event.get)
event.log.info ("received msg on channel " ~ event.channel.name);
}
// listen for messages placed in my queue, via a delegate
queue.createConsumer (&listen);
// stuff something into the queue
queue.log.info ("sending three messages to the queue");
queue.put (queue.EmptyMessage);
queue.put (queue.EmptyMessage);
queue.put (queue.EmptyMessage);
// wait for asynchronous msgs to arrive ...
Thread.sleep (1);
}
Queue返回客户端
在这个不同的版本中,我们把消息存入集群中的queue,通过监听者接收到它,再从另一个不同的频道发送对该消息的返回,最后接收返回值。这个例子用到了两个监听者。
private import tango.net.cluster.NetworkQueue;
private import tango.net.cluster.tina.Cluster;
void main (char[][] args)
{
// open the cluster and a queue channel. Note that the queue has
// been configured with a reply listener ...
auto cluster = (new Cluster).join;
auto queue = new NetworkQueue (cluster, "message.channel",
(IEvent event){event.log.info ("Received reply");}
);
void recipient (IEvent event)
{
auto msg = event.get;
event.log.info ("Replying to message on channel "~msg.reply);
event.reply (event.replyChannel(msg), queue.EmptyMessage);
}
// setup a listener to receive and reply
queue.createConsumer (&recipient);
// toss a message out to the cluster
queue.put (queue.EmptyMessage);
// wait for completion ...
Thread.sleep (1);
}
Task客户端
集群task的执行一般由三个参与者组成。首先,我们需要创建task自己,它一般在一个单独的模块里。在下面案例中,我们示范前面提到的expression task。
module Add;
real add (real x, real y)
{
return x + y;
}
第二步,我们需要在客户端应用程序里import这个task并使用它。我们用NetCall()模板来外覆自己的expression task,把它转化成一个集群消息。
import Add,
tango.net.cluster.tina.ClusterTask;
void main (char[][] args)
{
scope add = new NetCall!(add);
Stdout.formatln ("cluster expression of 3.0 + 4.0 = {}", add(3, 4));
}
第三步,我们需要把同样的task加入task服务器端,以便其可以在集群中被执行。这里演示怎么创建并配置可执行的task服务器端。
import Add,
tango.net.cluster.tina.TaskServer;
void main (char[][] args)
{
// handle command-line
auto arg = new CmdParser ("task.server");
// create ourselves a task server
auto server = new TaskServer (new InternetAddress(arg.port), arg.log);
// and configure it with our task(s)
server.enroll (new NetCall!(add));
// start the server
server.start;
}
Tina
Tina 是默认的QOS实现,为处理queue、cache和task请求提供了三种不同的服务器端。它的源代码以工具包的形式提供,用户针对具体需要对每种服务器端进行配置。当然也有示例程序的支持,通过这些例子,可以单独编译构造各种工作服务器端。这些示例代码都是服务器端功能性的一些琐碎的前端处理,所以上手有些困难。例如这是qserver.d全文:
import tango.io.Console;
import tango.net.InternetAddress;
import tango.net.cluster.tina.CmdParser,
tango.net.cluster.tina.QueueServer;
void main (char[][] args)
{
auto arg = new CmdParser ("queue.server");
if (args.length > 1)
arg.parse (args[1..$]);
if (arg.help)
Cout ("usage: qserver -port=number -log[=trace, info, warn, error, fatal, none]").newline;
else
(new QueueServer(new InternetAddress(arg.port), arg.log)).start;
}
每种服务器端都有一套命令行参数,以配置所有日志数据和服务器端口数目。如果不指定这两个参数,就按照默认进行设定。所有集群的示例都放在tango/example/cluster文件夹,其中引用的module会在接下来讨论。
Queue服务器端
queue的配置简洁明了:编译示例qserver.d模块然后启动它。每个queue被写入服务启动的目录中的独立文件里。这意味着两个独立的queue服务器端不能存放在同一个目录下,因为queue文件不能被共享。想在同一台机器上实例化多个queue服务器端,必须在不同的目录启动它们。
Cache服务器端
cache的配置也很简单:编译示例cserver.d模块然后启动它。当使用Tina时,cache客户端需要一组“服务器地址:端口号”对,作为一组有效cache服务器端的唯一标识。这种标识是必须的,这是由分布式算法的基本属性决定的。例如,若客户端启动时,所有cache实例并未全部运行,那么在整个集群范围内就有可能存在这种潜在问题:各个客户端看到的cache不一样。这意味着,当每个cache服务器启动后,必须记录它选择的端口号,或者直接给它配置指定的端口号。记录的标识列表应该在cache的客户端启动时提供给它们。
Task服务器端
Task服务器端采用一种不同的机制。由于目前D语言对编译后模块的动态链接的支持还很有限,还不能通过集群实现task代码的动态发布。
目前,我们必须在每个server上都import各自的task代码,以便调用。这意味着,每个task应该位于单独的 pachage或module里,与客户端和服务器端都分开,以便后两者都能import。在Tina QOS中,使用task类的全名作为关键字来匹配集群里的执行请求。这里说的“全名”包括module名,也就是说客户端和服务器端必须import完全相同的task modules以便名字完全匹配。
一般情况下,若没有特殊原因,在独立的module里实现每个(组)task是一种易于代码维护的好习惯。
日志
Tina里的服务器端都用到了Tango的日志系统以报告行动。默认情况下,日志内容仅在控制台输出,但通过调整服务器设置,可以把日志导向文件等各种其他目标。主机应用会为每个服务器端提供一个logger实例用于存放配置信息。更多细节请查看有关日志的文档。
技术注释
下面这些编程关键点可以帮你发挥集群工具包的最大功效。
线程
集群的监听器天然就是异步的,是与主程序分离的一个独立线程。当一个bulletin通知到达(推),监听器唤醒委托的客户端,传入必要的信息,以便客户端读取输入消息。
当消息到达时,由客户端采取必要措施以确保后续动作的正确性,这本质上就是一个多线程应用。若要连接一个事件子系统,我们也可以加入一个模块,把异步的通知转化为事件。后一种情况下,所有异步通知都被有效转化为同步通知。
消息分割
Tina的输入输出是多线程的,各个频道实例不共享缓冲区,而是拥有各自独立的输入输出。这种方式避免了线程抢占和同步问题,也让 Tina完全避免了所有网络活动的堆分配。这明显地节省了你应用程序的内存空间,避免线程的争夺共享资源,消除了集群中潜在的垃圾回收工作,一般情况下会减轻电脑主机的负载。
IO within Tina is multi-threaded. Rather than share a single set of IO buffers, each channel instance has its own set. This sidesteps any issues regarding thread-contention & synchronization, and enables Tina to avoid heap-allocation entirely for all network activity. This significantly reduces the memory footprint of your applications, avoids a common point of thread contention, removes clustering as a potential instigator of garbage collection, and generally limits the load placed upon the host computer.
然而当集群信息到达客户端时,传入的消息是引用别名,而不是拷贝。也就是说到达客户端的消息都是临时的。
However, when a cluster message arrives at a client, array-attributes of the message are aliased rather than being copied into the heap. In short, messages arriving at a client are transient.
如果客户端打算在一段时间内储存消息,而不是立刻处理,这就可能成为一个问题。目前设计的选择是尽量减少消息复制带来的垃圾回收压力;需要时,也可以复制输入消息,使这个消息不再被当作临时对象。消息类针对这种目的有个专门的clone()方法,可以在这种情况下使用。
This may becomes an issue where a client intends to store the message locally for a period of time, rather than process it immediately. The design trades-off a large savings in GC pressure for the potential of some message cloning as and when necessary – the act of copying an incoming message such that it is no longer considered transient. The message class has a clone() method specifically for this purpose, and it should be used accordingly.
对消息的约束
要成功发送某个消息,它应该有一定的自我约束。也就是说,无论何时,消息被重新初始化,都不需要任何第三方施加影响——它应该支持默认构造函数。
In order to successfully send a message it should generally be self-contained. That is – wherever a message is re-instantiated, the representation of it should not require the influence of any third party - it should support what's known as a default-constructor.
举个例子,如果我们发送的消息内嵌有一个数据库连接,这意味着在消息被重建的任何地方,该连接必须都是可用的。实际情况中这类行为相当罕见,大多数消息本质上都是很简单的。进一步讲,cache和queue的实现很少考虑对消息进行重新初始化,因为它们更倾向于存储原始的网络报文格式。然而task实例需要在集群内远程执行,就必须考虑这种情况。
For example, if we send a message which embeds a database connection, an equivalent connection must be made available (and assigned) wherever that message is brought back into existence. In practice, this type of behavior is only rarely needed since large subsets of message types are usually quite simplistic in nature. In addition, implementations of cache and queue would rarely need (if ever) to instantiate a message since they would tend to store the message in raw network format instead. However, task instances are executed remotely within the cluster, and this is where consideration must be applied.
Tina QOS使用消息克隆(message-cloning)以满足这种需求。首先,task消息应该在每台task服务器端注册;第二步,注册的消息要实现 read()方法,以便通过必要的环境参数建立集群实例。换句话说,每个注册实例都有个可选项,利用自己的参数,通过构造函数复制出相同对象。在实践下很少需要第二步,但必要时仍然要支持它。绝大多数task只需注册,因为实际处理代码本身就在场,可以直接执行。
In order to satisfy these requirements, the Tina QOS uses a form of directed message-cloning to achieve it. First, task messages should be enrolled with each task server and second, the registered message should implement the read() method in order to establish the cluster instance with the environment it needs. In other words, the registered instance of each message has the option of establishing the equivalent of ctor arguments for each incoming message, potentially based upon it's own ctor arguments. In practice, the need for this second step is rare but the support is there when necessary. The vast majority of tasks require registration only, since the actual executable code itself must be present and available for execution.
如果试图发送执行集群中没注册过的task,会引发一个远程异常返回给调用者。不过,我们打算添加一个动态安装和注册的机制,以解决潜在的安全问题。
Shipping and executing unregistered tasks on the cluster will result in a remote exception, returned to the caller. However we expect to add a facility to install and register tasks dynamically, subject to potential security concerns.
注册和收容
接收消息后,集群的客户端需要一个类的实例来收容(host)这些内容。大多数情况下,收容类通过消息的注册挑选,前面提过,应用程序中所有的消息类型都要预先注册。但是task消息不需要预先注册,因为输出的消息实例本省同时也就是收容类。对其他类型的消息都需要专门的收容类,除了依赖注册表以外,应用程序也可以手工支持定制的收容类,作为调用集群的参数的一部分。这就能对某些高级用途提供方便,尤其是在频道名直接映射专门的消息类型的情况下(频道和消息类一一映射)。
Upon receipt of each incoming message, a cluster client requires a class instance to host the content. In most cases, the host is selected from the message registry where all your application message types were previously enrolled. This is not required for task messages, since the outgoing message instance is used to host the result also. For other message types though, the host is required. Instead of depending upon the registry, an application may manually supply an appropriate host as part of a cluster request. This can be convenient in some advanced uses, especially where the channel name maps directly to a specific message type (a one-to-one mapping between the channel and a message class).
原文:[url]http://joyfire.spaces.live.com/blog/cns!502060A314B1A145!1601.entry
[/url]
这是占位贴。最近在玩D语言,我手头马上面临的工作又和集群运算有关,所以自然对Tina格外关注。因此准备把Tango库文档的Clusters这一节翻成中文,每天逐步翻译一点。这是件需要毅力的事,所以预先昭告天下,断自己的后路。
向不太熟悉的朋友简单介绍一下:D语言的官方标准运行时库是phobos,而Tango是目前比较完善的第三方类库,Tina是后者集群部分中QOS的一个参考实现(你也可以继承有关interface,自己实现QOS组件,见下文)。你还可以到dsource.org上查找更多D语言的类库、代码实例、开发工具和开源项目。除了phobos和Tango两个类库,dsource.org上另一个常用项目是dsss工具包,它用于配置、编译、安装D语言的整套开发环境,自动处理phobos和Tango并存的兼容性问题。刚结束的D Conference 2007上有Tina(ppt和pdf)、dsource.org(ppt)和dsss(pdf)的专题讲座可供参考。
Tango Clusters
(原文地址:http://www.dsource.org/projects/tango/wiki/ChapterClustering,版权属于原作者)
(中文译文转载,请保留http://joyfire.spaces.live.com地址)
Clusters就是电脑集群,我们认为,所谓“集群”是指,同处局域网内,分布执行关联任务的一组电脑。很多种应用都能从分布式获得好处;具体来说,相比于单机架构,分布式的设计将给应用程序带来更好的可拓展性。
例如,集群常常用于高性能计算:通过把大块的计算量分解到网络上的多个从机,一个计算密集性的应用能相当有效地提高计算量,或减少计算时间。按需求情况可以把更多从机加入集群。如果原有硬件脱离了集群,其他从机可以分担它的任务。
另一个例子是分布式保存某些需要频繁读取的数据,通过集群向一组客户端提供快速读取服务。这种设计的典型意图是缓解对关键单点(例如数据库)的抢占,以提高系统整体的计算能力。
再进一步的例子,是设计能力不可能应付请求的极端峰值的应用系统。这些系统需要一种机制来缓冲请求,而不是即时响应处理。在某些特定情况下,应用系统会把请求持久化存储起来,等到更合适的时机再去真正处理。虽然这可以通过数据库或类似方式实现,但更轻量分散的方式也许更适当。尤其是当吞吐量很敏感的情况下,数据库本身就可能会成为瓶颈。工作流系统就倾向于这种风格的缓冲方式。
以上所有场景,集群都有用武之地。Tango库支持很有吸引力和灵活性的集群模型,以帮助你不费太多事就可以构建这种应用,
作为使用体验,这里有一段在集群上执行expression任务的D语言代码示例:
real add (real x, real y) {return x + y;}
void main (char[][] args)
{
scope add = new NetCall!(add);
Stdout.formatln ("cluster expression of 3.0 + 4.0 = {}", add(3, 4));
}
可适用性
Tango工具包把集群的常用行为归纳成4种类型加以支持:消息队列,消息缓存,消息执行和消息广播。对应这4种行为的实现机制分别是queue, cache, task和bulletin。
基本概念为,你在一台或更多联网的计算机上启动一个或更多cache、queue、task服务器端实例,通过一个或多个集群客户端来调用它们。这些客户端链接入(link)你的应用程序,使其可以使用各种集群功能——它帮你的应用管理集群通讯,提供各种失败情况下的强大容错能力。总之,若干客户端会与潜在的若干cache、queue、task服务器端通话。
衡量集群应用是否成功的一个关键因素,就是看它对以下情况的鲁棒性:瞬时的传输拥塞,变化的反应延时,集群成员节点的增减(包括潜在的硬件错误)。评价因素还包括效率,既有选择的通讯中介的效率,也有应用实体在集群中转移的传输效率。
模型和QOS
Tango集群用由D语言的interface和工具class组成的模型来描述。这种设计的目的是,使不同的集群实现方式都拥有一个相同的模型,稍做微小改动就能切换到另一种不同的实现方式。为什么要有多种不同的实现方式?因为不同的应用有不同的需要——有的认为吞吐量是绝对重要的,有的认为数据的复制更需要重视,还有的可能需要某种特殊行为。
也就是说,该模型打算跨越各种不同需要和实现。不同的需要和实现要用到不同的服务质量或QOS。若一个集群应用程序同时使用多种QOS实现,以满足不同的目标,也是完全可行的。
为了加入集群,应用程序需要一个QOS客户端实例。通过这一点,所有活动都能被模型的工具class纳入管理。也就是说,QOS是一个单独的、公平的、简洁的、几乎透明的组件。模型的工具class在此之上提供附加行为。
该模型本身受到了一些现存系统的影响,包括hints的发布和订阅、Linda、JavaSpaces等,还有其它一些你可能已经熟悉的系统。
接触Tina
类库提供的一组服务就是一个内置QOS实现,以便快速开发集群应用。它主要由三个服务器端构成,这三个服务器端分别支持cache、 queue、task三种集群服务方式。另外它还包括与服务器端相关的集群客户端的实现。前者(服务器端)是独立的、有自己权限的应用程序。而后者(客户端)要链接到你的应用程序里,以使集群对它可见。Bulletins是彻底由客户端实例操作的,在对等(P2P)方式下不存在bulletin服务器。
Tango用D语言源码module来描述服务器端,同时提供完整而简洁的代码作为构造相应服务器的例子。客户端通过一个class暴露给用户调用,应用程序实例化这个class就可以了。两者结合,让你快速简单地构建出应用系统的专用集群。
这个内置的QOS是面向高效连接的,其重点是避免任何堆积行为(除在cache hosting这种必要情况下)。它既平衡了传输中的TCP/IP和多播,也平衡了序列存储中的磁盘文件。它有个爱称叫Tina,应用程序使用Tina,需要import tango.net.cluster.tina.Cluster
关键概念
无论任何工具包,为了发挥它最大的功效,都需要熟悉一些关键概念。这些概念不多,我们会在这一节里专门解释。首先从频道(channel)开始。
频道(Channel)
如果使用过发布/订阅系统,对频道的概念应该比较熟悉。频道是消息传输和交付所通过的实体的名字。集群应用订阅(或监听)频道,发布(或写入)频道。没有它就无法与集群进行通讯。你向QOS提出要求,由它代表你创建一个频道,此后就开始使用。实际上,模型里有很多躲在后台的工具 class为你实现频道的创建。然而,你可以在需要时自由使用频道。
有了频道,应用就可以发送或请求集群消息,监听异步行为,在网络里执行任务。模型里的很多工具class在此基础上提供出一个结构化的框架,在适当的地方添加进一步价值。
当一个消息(message)被一个命名频道送出,只有监听同一个频道的候选者才接收到这个消息。频道的名字必须在所有通讯地点保持一致:这样就提供了隔离不同目的的不同类型消息的基础。实践中我们发现,使用点分隔符号的频道名字(例如 employee.contact.information)非常方便,易于对消息类型区分和聚合。实际上频道是描述D语言class的好方法——每个频道对应一个独立的class——它非常精细地隔离了彼此不一致的内容,显著简化了集群自身相互间聚合数据的传输。刚好,接下来要提到的概念就是消息。
消息(Message)
消息是所有集群上下文的基础。你向queue存入东西,是以消息形式发送的;从cache恢复内容,其实也是接收一个消息;当在集群中执行task,它表达为消息;当异步多播的bulletin在集群中分布式交互时,它们就是消息的实例。总之集群里的一切都是消息。
当用D编程语言,每个集群消息都被实现为一个class。进一步的,所有消息或继承于NetworkMessage工具class,或实现了IMessage接口(interface)。消息实例被转换成网络协议包,在集群之间传输。
有一个模板能用来为你很方便地生成一小段代码,负责消息和网络协议包之间的相互转换;另一种办法是通过实现两个简单的消息方法来明确控制转换行为。如果你使用模板,所有本地数据都被加入用于发送和恢复的消息;如果只处理消息的一部分,就要通过两个预订(译者注:回调或委托)方法对如何转换进行干预。
所有消息变量默认都要注册。也就是说,为了让集群客户端能正确重建输入消息,每种消息类型都必须在应用启动时提交给 NetworkRegistry。有一种特殊情况不需要注册——task不要求客户端注册,如果你明确提供了输入消息的主机,就不用注册了。然而,注册你应用中用到的所有消息类型是种好习惯。消息的静态构造函数是个适于注册的位置。例如:
import tango.net.cluster.NetworkMessage,
tango.net.cluster.NetworkRegistry;
class MyMessage : Message
{
static this()
{
NetworkRegistry.shared.enroll (new MyMessage);
}
}
除要求注册以外,每个消息就是一个标准的D语言class,可以以一般形式进行操作。它仅仅是拥有了一种附加能力:可以在集群上的其他机器出现并随意行动。
队列(Queue)
queue是消息的贮藏。每个queue都有自己的频道,即被队列化的频道会有单独的queue实例。消息通过频道行为存入 queue,再以相同方式从queue恢复。这些操作是同步方式。与此不同,消息的消费者(频道的订阅者)能以异步方式监听消息行为,当queue存在变动,就把消息提供给它们。两种方法都有自己的优势,由你自己选择。
queue内的消息不单独设定地址;当你查找一个消息,不能指定与请求有关的特殊值。queue把单独的频道名字隔离起来的,没有任何其他元数据。
queue消息既可以在无进一步动作的情况下被消费,也可以有返回。典型的返回通过另一个频道发送(对原始频道的名字做修改),在始发者接收前,返回消息经常被队列化。始发者要监听返回,监听方式与订阅其他队列化消息一样。
queue是持久化的,可以经受电力故障和重启。
缓存(Cache)
Cache主机以非常类似联合数组或哈希表的方式存储消息。消息用频道名隔开,以键值进行检索。在Tango里,这个键值是char类型的数组。
放在集群cache里的消息会被同一频道中拥有相同key的实体替代。进一步,用有条件的时间戳来控制对"新"的检验。后者在分布式环境下是重要有用的。这种环境下,也许会出现cache更新冲突。cache实例会自动清除旧的实体,以便为新的内容释放必要空间。
通过使用模型工具,集群的cache可以进行部分本地复制。这个机制模拟了经典的level1/level2 combination,这会对很多应用程序都有用。模型工具还使保持一组cache实例的一致变得容易。
Cache实例仅仅打算临时驻留在内存里,即Tina的实现不对它们进行持久化保存。
任务(Task)
task是可执行的消息,在调用进程以外执行。通常,task会发送到集群中的某个能执行该任务的服务器端上去,执行后把运行结果返回给调用者。这是一个同步方式的执行模型。对于去耦(decoupled)执行模型(译者注:异步方式),任务可以先发送到一个queue上挂起,直到有订阅者恢复并执行它。这种模型下的返回一般通过另外一个queue发送,和一般的queue消息返回方式一样(参考前文的queue)。
相比其它消息类型task有些独特性,因为它是主动消息,不是被动的。和queue或cache里面躺在那里等待相比,task消息是打算要在集群里面干点什么。这意味着,task消息为了这个目的必须实现execute()方法。有一种被称为expression的task,仅由一个简单的函数构成。这种任务可以被NetCall模板转化成一个真正的task实例,这个模板吧函数当作参数,返回一个task实例。这篇文章的开头演示了这种用法。
task消息另一个独特之处在于,它应该在集群上被注册。这就意味着task消息是每个task服务器端的主要组成部分,以便可以在服务器端被执行。实际上,有两种主要的可选方式:把task消息静态链接到每个task服务器端,或动态发布并链接到每个task服务器端。请注意,现在D语言并没有在所有平台上都实现动态链接,所以默认Tina实现task是采用前者——注册task服务器,注册的内容是端口和方法调用。
公告(Bulletin)
这是一种发送给对所有集群成员的通知消息类型,它调用能用到的最有效的底层机制。这种消息的大小尺寸受到限制(一般小于1K),它本质上就打算简单和轻量级。Tina QOS使用bulletins来进行cluster发现,queue活动通知,cache同步,用广播作为分布式机制。当一个bulletin被发送,所有同一频道的监听者都会接收到。
bulletins的应用层潜在用途是通知所有监听者关机。这种方法用来确保所有服务器端实例在相同版本下运行——新版本被写入中心位置,然后批处理任务通知服务器端重启,无论它是否已经被停止过(以改用新版)。
推 Vs. 拉(Push versus Pull)
Tango集群支持两种访问内容的形式。cache或queue内容的请求是同步调用,也就是常说的拉(pull)模型;另一方面,创建queue活动或bulletin的监听者使用异步通知,就是所谓推(push)模型,若没有明确订阅某种特殊消息,内容就不会被推给的该接收者。
类似同步要求,异步的push通知在特定的频道上进行传输:你得到你想要的,没有其他多余的。push和pull的主要区别在于,前者可能出现在一个独立的执行线程中,所以你必须了解一般多线程情况下可能碰到的潜在问题(例如对共享资源的同时访问)。
当通知出现时,到达的内容和输入的消息通过变量形式传送给监听者。大多数情况下,到达的消息是描述一个通知内容的单独实体。然而,queue通知会集中传输一个或多个序列消息。
客户端使用
在这一节我们通过代码例子看看如何使用集群功能。首先需要import适当的集群。在以下这些例子里我们会一直使用Tina QOS,但对其他实现要import对应的包取而代之。注意这里主要关注客户端,服务器端在后一节介绍。
Cache客户端
这个例子演示如何把cluster作为分布式cache使用。这里仅仅演示了主要概念,还有其他很多可用的操作。注意我们把命令行参数传输给join()方法:为cache设置一组有效可用的cache实例。和其他设施不同,cache实例不是自发现的(self- discovering)。
import tango.net.cluster.NetworkCache;
import tango.net.cluster.tina.Cluster;
void main (char[][] args)
{
if (args.length > 1)
{
// hook into the cluster
auto cluster = (new Cluster).join (args[1..$]);
// hook into the Cache layer
auto cache = new NetworkCache (cluster, "my.cache.channel");
// add a cache entry to the cluster
cache.put ("key", cache.EmptyMessage);
// retrieve it from the cluster
auto msg = cache.get ("key");
}
else
Stdout.formatln ("usage: cache cachehost:port ...");
}
Bulletin客户端
怎样通过集群发送和接受通知。这些通知被发送给某个特殊广播频道的每个监听者。注意我们创建了一个回调函数,传给集群作为bulletin的消费者。
private import tango.net.cluster.NetworkAlert;
private import tango.net.cluster.tina.Cluster;
void main (char[][] args)
{
// hook into the cluster
auto cluster = (new Cluster).join;
// hook into the Alert layer
auto alert = new NetworkAlert (cluster, "my.kind.of.alert");
// declare a listener
void listen (IEvent event)
{
event.log.info ("Received alert on channel " ~ event.channel.name);
}
// listen for the broadcast (on this channel)
alert.createConsumer (&listen);
// and send everyone an empty alert (on this channel)
alert.broadcast;
// wait for it to arrive ...
Thread.sleep(1);
}
Queue拉客户端
下文演示怎样在同步模型下安装和使用queue。我们把一些东西放入queue,然后再恢复出来。
private import tango.net.cluster.NetworkQueue;
private import tango.net.cluster.tina.Cluster;
void main (char[][] args)
{
// join the cluster
auto cluster = (new Cluster).join;
// access a queue of the specified name
auto queue = new NetworkQueue (cluster, "my.queue.channel");
// stuff something into the queue
queue.put (queue.EmptyMessage);
// retrieve it synchronously
auto msg = queue.get;
}
Queue推客户端
这里演示如何在异步模式下安装和使用queue。我们把监听者委托(delegate)给集群,当订阅的内容从集群任何地方到达queue,监听者就会被调用。
private import tango.net.cluster.NetworkQueue;
private import tango.net.cluster.tina.Cluster;
void main (char[][] args)
{
// join the cluster
auto cluster = (new Cluster).join;
// access a queue of the specified name
auto queue = new NetworkQueue (cluster, "my.queue.channel");
// declare a listener
void listen (IEvent event)
{
while (event.get)
event.log.info ("received msg on channel " ~ event.channel.name);
}
// listen for messages placed in my queue, via a delegate
queue.createConsumer (&listen);
// stuff something into the queue
queue.log.info ("sending three messages to the queue");
queue.put (queue.EmptyMessage);
queue.put (queue.EmptyMessage);
queue.put (queue.EmptyMessage);
// wait for asynchronous msgs to arrive ...
Thread.sleep (1);
}
Queue返回客户端
在这个不同的版本中,我们把消息存入集群中的queue,通过监听者接收到它,再从另一个不同的频道发送对该消息的返回,最后接收返回值。这个例子用到了两个监听者。
private import tango.net.cluster.NetworkQueue;
private import tango.net.cluster.tina.Cluster;
void main (char[][] args)
{
// open the cluster and a queue channel. Note that the queue has
// been configured with a reply listener ...
auto cluster = (new Cluster).join;
auto queue = new NetworkQueue (cluster, "message.channel",
(IEvent event){event.log.info ("Received reply");}
);
void recipient (IEvent event)
{
auto msg = event.get;
event.log.info ("Replying to message on channel "~msg.reply);
event.reply (event.replyChannel(msg), queue.EmptyMessage);
}
// setup a listener to receive and reply
queue.createConsumer (&recipient);
// toss a message out to the cluster
queue.put (queue.EmptyMessage);
// wait for completion ...
Thread.sleep (1);
}
Task客户端
集群task的执行一般由三个参与者组成。首先,我们需要创建task自己,它一般在一个单独的模块里。在下面案例中,我们示范前面提到的expression task。
module Add;
real add (real x, real y)
{
return x + y;
}
第二步,我们需要在客户端应用程序里import这个task并使用它。我们用NetCall()模板来外覆自己的expression task,把它转化成一个集群消息。
import Add,
tango.net.cluster.tina.ClusterTask;
void main (char[][] args)
{
scope add = new NetCall!(add);
Stdout.formatln ("cluster expression of 3.0 + 4.0 = {}", add(3, 4));
}
第三步,我们需要把同样的task加入task服务器端,以便其可以在集群中被执行。这里演示怎么创建并配置可执行的task服务器端。
import Add,
tango.net.cluster.tina.TaskServer;
void main (char[][] args)
{
// handle command-line
auto arg = new CmdParser ("task.server");
// create ourselves a task server
auto server = new TaskServer (new InternetAddress(arg.port), arg.log);
// and configure it with our task(s)
server.enroll (new NetCall!(add));
// start the server
server.start;
}
Tina
Tina 是默认的QOS实现,为处理queue、cache和task请求提供了三种不同的服务器端。它的源代码以工具包的形式提供,用户针对具体需要对每种服务器端进行配置。当然也有示例程序的支持,通过这些例子,可以单独编译构造各种工作服务器端。这些示例代码都是服务器端功能性的一些琐碎的前端处理,所以上手有些困难。例如这是qserver.d全文:
import tango.io.Console;
import tango.net.InternetAddress;
import tango.net.cluster.tina.CmdParser,
tango.net.cluster.tina.QueueServer;
void main (char[][] args)
{
auto arg = new CmdParser ("queue.server");
if (args.length > 1)
arg.parse (args[1..$]);
if (arg.help)
Cout ("usage: qserver -port=number -log[=trace, info, warn, error, fatal, none]").newline;
else
(new QueueServer(new InternetAddress(arg.port), arg.log)).start;
}
每种服务器端都有一套命令行参数,以配置所有日志数据和服务器端口数目。如果不指定这两个参数,就按照默认进行设定。所有集群的示例都放在tango/example/cluster文件夹,其中引用的module会在接下来讨论。
Queue服务器端
queue的配置简洁明了:编译示例qserver.d模块然后启动它。每个queue被写入服务启动的目录中的独立文件里。这意味着两个独立的queue服务器端不能存放在同一个目录下,因为queue文件不能被共享。想在同一台机器上实例化多个queue服务器端,必须在不同的目录启动它们。
Cache服务器端
cache的配置也很简单:编译示例cserver.d模块然后启动它。当使用Tina时,cache客户端需要一组“服务器地址:端口号”对,作为一组有效cache服务器端的唯一标识。这种标识是必须的,这是由分布式算法的基本属性决定的。例如,若客户端启动时,所有cache实例并未全部运行,那么在整个集群范围内就有可能存在这种潜在问题:各个客户端看到的cache不一样。这意味着,当每个cache服务器启动后,必须记录它选择的端口号,或者直接给它配置指定的端口号。记录的标识列表应该在cache的客户端启动时提供给它们。
Task服务器端
Task服务器端采用一种不同的机制。由于目前D语言对编译后模块的动态链接的支持还很有限,还不能通过集群实现task代码的动态发布。
目前,我们必须在每个server上都import各自的task代码,以便调用。这意味着,每个task应该位于单独的 pachage或module里,与客户端和服务器端都分开,以便后两者都能import。在Tina QOS中,使用task类的全名作为关键字来匹配集群里的执行请求。这里说的“全名”包括module名,也就是说客户端和服务器端必须import完全相同的task modules以便名字完全匹配。
一般情况下,若没有特殊原因,在独立的module里实现每个(组)task是一种易于代码维护的好习惯。
日志
Tina里的服务器端都用到了Tango的日志系统以报告行动。默认情况下,日志内容仅在控制台输出,但通过调整服务器设置,可以把日志导向文件等各种其他目标。主机应用会为每个服务器端提供一个logger实例用于存放配置信息。更多细节请查看有关日志的文档。
技术注释
下面这些编程关键点可以帮你发挥集群工具包的最大功效。
线程
集群的监听器天然就是异步的,是与主程序分离的一个独立线程。当一个bulletin通知到达(推),监听器唤醒委托的客户端,传入必要的信息,以便客户端读取输入消息。
当消息到达时,由客户端采取必要措施以确保后续动作的正确性,这本质上就是一个多线程应用。若要连接一个事件子系统,我们也可以加入一个模块,把异步的通知转化为事件。后一种情况下,所有异步通知都被有效转化为同步通知。
消息分割
Tina的输入输出是多线程的,各个频道实例不共享缓冲区,而是拥有各自独立的输入输出。这种方式避免了线程抢占和同步问题,也让 Tina完全避免了所有网络活动的堆分配。这明显地节省了你应用程序的内存空间,避免线程的争夺共享资源,消除了集群中潜在的垃圾回收工作,一般情况下会减轻电脑主机的负载。
IO within Tina is multi-threaded. Rather than share a single set of IO buffers, each channel instance has its own set. This sidesteps any issues regarding thread-contention & synchronization, and enables Tina to avoid heap-allocation entirely for all network activity. This significantly reduces the memory footprint of your applications, avoids a common point of thread contention, removes clustering as a potential instigator of garbage collection, and generally limits the load placed upon the host computer.
然而当集群信息到达客户端时,传入的消息是引用别名,而不是拷贝。也就是说到达客户端的消息都是临时的。
However, when a cluster message arrives at a client, array-attributes of the message are aliased rather than being copied into the heap. In short, messages arriving at a client are transient.
如果客户端打算在一段时间内储存消息,而不是立刻处理,这就可能成为一个问题。目前设计的选择是尽量减少消息复制带来的垃圾回收压力;需要时,也可以复制输入消息,使这个消息不再被当作临时对象。消息类针对这种目的有个专门的clone()方法,可以在这种情况下使用。
This may becomes an issue where a client intends to store the message locally for a period of time, rather than process it immediately. The design trades-off a large savings in GC pressure for the potential of some message cloning as and when necessary – the act of copying an incoming message such that it is no longer considered transient. The message class has a clone() method specifically for this purpose, and it should be used accordingly.
对消息的约束
要成功发送某个消息,它应该有一定的自我约束。也就是说,无论何时,消息被重新初始化,都不需要任何第三方施加影响——它应该支持默认构造函数。
In order to successfully send a message it should generally be self-contained. That is – wherever a message is re-instantiated, the representation of it should not require the influence of any third party - it should support what's known as a default-constructor.
举个例子,如果我们发送的消息内嵌有一个数据库连接,这意味着在消息被重建的任何地方,该连接必须都是可用的。实际情况中这类行为相当罕见,大多数消息本质上都是很简单的。进一步讲,cache和queue的实现很少考虑对消息进行重新初始化,因为它们更倾向于存储原始的网络报文格式。然而task实例需要在集群内远程执行,就必须考虑这种情况。
For example, if we send a message which embeds a database connection, an equivalent connection must be made available (and assigned) wherever that message is brought back into existence. In practice, this type of behavior is only rarely needed since large subsets of message types are usually quite simplistic in nature. In addition, implementations of cache and queue would rarely need (if ever) to instantiate a message since they would tend to store the message in raw network format instead. However, task instances are executed remotely within the cluster, and this is where consideration must be applied.
Tina QOS使用消息克隆(message-cloning)以满足这种需求。首先,task消息应该在每台task服务器端注册;第二步,注册的消息要实现 read()方法,以便通过必要的环境参数建立集群实例。换句话说,每个注册实例都有个可选项,利用自己的参数,通过构造函数复制出相同对象。在实践下很少需要第二步,但必要时仍然要支持它。绝大多数task只需注册,因为实际处理代码本身就在场,可以直接执行。
In order to satisfy these requirements, the Tina QOS uses a form of directed message-cloning to achieve it. First, task messages should be enrolled with each task server and second, the registered message should implement the read() method in order to establish the cluster instance with the environment it needs. In other words, the registered instance of each message has the option of establishing the equivalent of ctor arguments for each incoming message, potentially based upon it's own ctor arguments. In practice, the need for this second step is rare but the support is there when necessary. The vast majority of tasks require registration only, since the actual executable code itself must be present and available for execution.
如果试图发送执行集群中没注册过的task,会引发一个远程异常返回给调用者。不过,我们打算添加一个动态安装和注册的机制,以解决潜在的安全问题。
Shipping and executing unregistered tasks on the cluster will result in a remote exception, returned to the caller. However we expect to add a facility to install and register tasks dynamically, subject to potential security concerns.
注册和收容
接收消息后,集群的客户端需要一个类的实例来收容(host)这些内容。大多数情况下,收容类通过消息的注册挑选,前面提过,应用程序中所有的消息类型都要预先注册。但是task消息不需要预先注册,因为输出的消息实例本省同时也就是收容类。对其他类型的消息都需要专门的收容类,除了依赖注册表以外,应用程序也可以手工支持定制的收容类,作为调用集群的参数的一部分。这就能对某些高级用途提供方便,尤其是在频道名直接映射专门的消息类型的情况下(频道和消息类一一映射)。
Upon receipt of each incoming message, a cluster client requires a class instance to host the content. In most cases, the host is selected from the message registry where all your application message types were previously enrolled. This is not required for task messages, since the outgoing message instance is used to host the result also. For other message types though, the host is required. Instead of depending upon the registry, an application may manually supply an appropriate host as part of a cluster request. This can be convenient in some advanced uses, especially where the channel name maps directly to a specific message type (a one-to-one mapping between the channel and a message class).
发表评论
-
英国人是这样背的!
2010-03-11 23:34 1561原文:http://ckwn.iteye.com/blog/6 ... -
GtkD 1.3 is out! Download it now!
2009-10-27 16:25 1243what is new on GtkD: * fully a ... -
llvm 简介
2009-10-25 21:54 3504原标题: llvm/clang将把Free ... -
Cristian Vlasceanu 和.NET上的D语言编译器
2009-05-24 01:50 1017原文:http://www.infoq.com/cn/news ... -
节气歌
2008-11-27 02:14 0立春阳气转,雨水淹河边,惊蛰乌鸦叫,春分地皮干,清明种小麦,谷 ... -
GTK+, Qt, wxWidgets 比较简评
2008-11-04 01:58 17478http://yuanmuqiuyu2000.blog.soh ... -
转换 c 库到 d
2008-06-26 00:14 1312------编写Ruby扩展 原文:http://qiezi. ... -
让D访问其他应用程序
2008-06-25 23:56 1689原文:http://ideage.iteye.com/blog ... -
嵌入式数据库典型技术―SQLite和Berkeley DB的研究 论文
2008-06-09 04:18 0http://www.lunwentianxia.com/pr ... -
D语言的陷阱
2008-06-08 17:47 1141原文:http://colorful1982.blog.soh ... -
D 2.0 Const/Final/Invariant 概念简介
2008-06-08 17:43 1189原文:http://oldrev.iteye.co ...
相关推荐
Tango Control System是一种用于控制和监控实验室仪器、望远镜、粒子加速器等复杂设备的控制系统。该系统被广泛应用于科研与工业领域,特别是在物联网及系统集成方面扮演着重要角色。 在搭建Tango Control System时...
《Tango:电路设计软件的历史与应用》 Tango,这款被誉为古老的电路板设计软件,是电子工程领域中的一颗璀璨明星。它以其强大的功能和在DOS操作系统下的独特运行方式,为电路设计者提供了丰富的工具,使得在早期的...
“TANGO的最爱”可能意味着这个主题是对Tango设计风格的一种致敬或特别优化,是Tango风格的忠实体现,因此深受Tango风格爱好者的喜欢。 【标签解析】 “tango”标签直接关联了设计风格,指明了主题的视觉特征。...
- 选择自定义安装路径,避免使用包含中文的路径。 - 安装完成后,可以通过命令行输入`python`命令验证安装是否成功。 ##### 5. 配置Python环境变量 - 在系统环境变量中添加Python的安装路径。 - 同样是在“高级...
### Project Tango: 一个概述 #### 1.0 引言 本文档旨在提供关于Project Tango的概览。Project Tango是Sun Microsystems推出的一个开源实现,它涵盖了关键的企业Web服务规范(通常称为WS-*),并提供了与.NET 3.0...
Tango SDK---The latest version of the Unity SDK is Ikariotikos (Version 1.54, June 2017).
Tango视频电话3.13.127894 Tango Video Calls 大小:26.18MB 更新时间:2015-01-12 Tango为您带来免费的高品质视频通话,在3G和Wi-Fi网络上都运行如飞!全世界数百万用户都在使用妙趣横生又简单易用的Tango视频...
谈客视频电话 Tango v3.13.128111 更新时间:2015-01-14 版本:3.13.128111 软件语言:多语言 软件类别:网络语音 软件大小:26.18 MB 适用固件:2.1及更高固件 内置广告:没有广告 适用平台:Android Tango为您...
《Tango Patcher 2600 8.06:打造个性化桌面美学》 "Tango_Patcher_2600_8_06"是一个专为提升桌面应用视觉效果的工具,它引入了一套源自deviantart的艺术风格——Tango图标包。这套图标以其简洁而优雅的设计,为...
在本章中,我们将深入探讨D语言的基础知识,特别是与Tango库的结合使用。D语言是一种现代化的、高效的编程语言,它具有静态类型的特性,同时又具备动态语言的便捷性。Tango库是D语言的一个重要组成部分,提供了丰富...
"Grey Tango 指针"是一套为台式电脑用户设计的鼠标指针主题,它融合了简洁与优雅,为用户的桌面环境增添了独特的风格。在IT领域,个性化和定制化是许多用户追求的一种体验,而指针作为操作系统交互的重要元素之一,...
Go-Tango是一个专门为Go语言设计的微内核Web框架,其核心设计理念是模块化和注入式,这使得它在灵活性和可扩展性方面表现出色。作为一个专业的IT大师,我将详细解析这个框架的关键特性和使用场景,以及如何利用它...
tango, 微型&可以插入网络框架 Tango 软件包探戈是一个微型&可以插入的网页框架。当前版本:v0.5.0 版本的历史记录。正在启动要安装 Tango:go get github.com/lunny/tango
《Tango PC版:连接你我,跨越设备的视频通讯工具》 Tango,这款源自移动设备的视频通讯工具,以其强大的功能和便捷的操作,在全球范围内赢得了广大用户的喜爱。如今,随着科技的发展,Tango已经推出了PC版,使得...
TangoSDK_Eisa_Unity5.unitypackage
tango core apk - eisa
Tango With Django 1.9 1.10最新版。完整版,非sample。缺陷是是扫描版
TANGO电路原理图库文件的数据结构分析 引言: TANGO软件是一个广泛使用的绘图软件,在我国尤其流行。它能绘制电路原理图和印刷电路板图,其数据文件的结构在相关文献中有介绍,但关于库文件的数据结构信息却很少。...
《深入剖析"Tango with Django"源代码》 "Tango with Django"是一份针对Django框架的教程项目,其源代码存放在名为“tango_with_django-master”的压缩包中。这个项目旨在帮助开发者通过实践来学习Django,理解其...