大规模视频网站的计费与流量管理
本次分享将会就大规模视频网站的计费与流量管理这个话题,从操作层面细细进行讲解和分析,为系统工程师们揭示平日里我们没有关心的另一些内容。同时也希望本次分享能揭示行业中的一些“潜规则”,让互联网行业的流量与带宽管理更为开放与简洁。
本次演讲视频录制于QCon杭州2011。
该内容已经被标记书签!
标记书签错误,请重试!

作者 Jackie Wheeler 译者 陈义 发布于 2009年8月17日
当谈论整合应用时,消息路由备受关注。当我们确定了各个应用,并选择Mule作为整合平台,也知道在Mule的服务中可以使用哪些Java类和web services处理消息,那么为了让消息正确地在服务间流转,该如何将所有的事情整合在一起,从而确保获得我们所需要的的结果呢?
Mule为您的Mule应用中的服务间的路由消息提供了强大而灵活的可选项。本文描述了Mule的常用消息类型和几种可用的特殊路由器。
下面介绍消息路由器的相关核心概念:
当将Mule的服务结合在一起时,初用Mule的人有时会感到困惑,他们不知何时该使用出站路由器,何时可以最大程度地简化获得回复信息。下面介绍 Mule中可使用的消息类型,可以通过一个列表查看各个传输(transport)所支持的消息类型,详细内容可以查看Mule用户指南中的传输特征矩阵(Transports Feature Matrix)(查看前需要先登录,但注册是免费的,只需花费一点时间就可以完成注册。)
如果只想将消息以“即发即弃(fire and forget)”的方式发送给一个服务,(并不需要给调用者返回响应),那么可使用异步消息类型。如果将入站端点的synchronous属性设置为false,它就不会给调用者返回响应。
例如:
<model name="Asynchronous_Message_Pattern">
<service name="AsynchronousService">
<inbound>
<jms:inbound-endpoint queue="test.in" synchronous="false"/>
</inbound>
<component class="org.myorg.WidgetHandler"/>
<outbound>
<pass-through-router>
<jms:outbound-endpoint queue="test.out">
</pass-through-router>
</outbound>
</service>
</model>
在简单的Request-Response场景中,服务在一个同步的入口端点上接收请求,并处理该请求,然后将它作为回复发送给调用者。例如,如果用户在 HTML表单中输入一个值,想转换该值并将其结果显示在同一个页面上,那么可以在该服务上简单地配置一个同步入站端点,由该服务完成数据转换。这种场景并不需要使用出站端点。这就是request-response消息类型。

例如:
<model name="Request-Response_Message_Pattern">
<service name="SynchronousService">
<!-- 为了返回response将synchronous的值设置为“true”-->
<inbound>
<http:inbound-endpoint host="localhost" port="8080"
path="/mule/services" synchronous="true"/>
</inbound>
<!-- 指定处理该请求的组件 -->
<component class="org.myorg.WidgetHandler"/>
</service>
</model>
如果为了进一步处理消息,需要将消息传递给第二个服务,那么需要在第一个服务上配置一个出站路由器将该消息传递给第二个服务。在第二个服务处理完消息后,第一个服务将它作为回复发送给调用者。值得注意的是将第一个服务设置为同步入口端点就意味着之后的所有服务都会以同步的方式处理该消息,所以无需在第二个服务上设置synchronous属性的值。这就是同步消息类型。
例如:
<model name="Synchronous_Message_Pattern">
<service name="SynchronousService">
<inbound>
<!-- 为了返回response将synchronous的值设置为“true” -->
<jms:inbound-endpoint queue="test.in" synchronous="true"/>
</inbound>
<component class="org.myorg.WidgetHandler"/>
<outbound>
<!-- 使用pass-through路由器时,如果想返回response必须将synchronous的值设置为“true”-->
<pass-through-router>
<!-- 设置出站端点 -->
<jms:outbound-endpoint queue="test.out" synchronous="true"/>
</pass-through-router>
</outbound>
</service>
<!-- 配置第二个服务,并将它的入站端点设置为上一个服务的出站端点的路径。
值得注意的是无需设置synchronous的值,因为在第一个服务中已经将消息设置为synchronous了。
-->
<service>
<inbound>
<jms:inbound-endpoint queue="test.out"/>
</inbound>
<component class="org.myorg.WidgetProcesser"/>
</service>
</model>
注意:在Mule的以往版本中,远程服务需要设置remoteSync属性的值为true用于配置同步处理。从Mule 2.2开始,remoteSync属性已经被删除,只需要设置synchronous属性的值为true就可以创建同步流。
在大多数复杂的场景中,可以使用request-response消息,并使用后端(back-end)流程调用其它的服务,并基于多个服务调用的结果异步地返回一个回复。你可以将入站端点的synchronous属性设置为false,因为异步回复路由器会处理该回复,除非你想给调用者发送响应。这就是异步request-response消息类型。
在下面的例子中,HTTP端点接收一个请求,并使用Multicast路由器将该请求广播到两个端点,再将这些结果以异步的方式发送到一个JMS端点。
<model name="Async_Request-Response_Message_Pattern">
<service name="AsyncRequestResponseService">
<inbound>
<!--
将synchronous设置为“false”,因为response将由异步回复路由器处理 -->
<http:inbound-endpoint host="localhost" port="8080"
path="/mule/services" synchronoussynchronous="false"/>
</inbound>
<component class="org.myorg.WidgetHandler"/>
<!-- 配置异步回复的设置。这个例子使用了收集异步回复路由器,
在发送回复信息之前,它将所有的响应信息收集在一起。 -->
<async-reply timeout="5000>
<collection-async-reply-router/>
<jms:inbound-endpoint queue="reply.queue"/>
</async-reply>
<!--设置负责接收和处理消息的端点以及回复消息的端点 -->
<outbound>
<multicasting-router>
<reply-to address="jms://reply.queue"/>
<jms:outbound-endpoint queue="service1" synchronous="false"/>
<jms:outbound-endpoint queue="service2" synchronous="false"/>
</multicasting-router>
</outbound>
</service>
</model>
关于消息类型的全部内容可以参看Mule用户指南中的Mule的消息类型。
现在我们已经理解了在不同的场景中可以使用哪种消息类型路由消息,下面让我们看看哪些路由器可以很好地控制消息路由。更多消息路由的信息可以参看Mule用户指南中的使用消息路由器。
pass-through路由器是为简化端点间的消息传递而设计的。比如,它对分发消息给一个队列非常有用。
也可以使用pass-through路由器将协议桥接到其它的出站端点。例如:
<service name="HttpProxyService">
<inbound>
<inbound-endpoint address="http://localhost:8888" synchronous="true"/>
</inbound>
<outbound>
<pass-through-router>
<outbound-endpoint
address="http://www.webservicex.net#[header:http.request]"
synchronous="true"/>
</pass-through-router>
</outbound>
</service>
当使用pass-through路由器时,如果想返回一个响应,必须将出站端点的synchronous属性设置为true。其它的路由器,比如 chaining路由器并不需将出站端点的synchronous属性设置为true,该路由器总会在同步的场景中返回一个响应。因此,如果将消费发送给多个服务,可能会用chaining路由器代替pass-through路由器,因为chaining路由器中不需要将每个端点的synchronous 设置为true。
使用过滤器可以控制服务处理哪些消息。选择性消费者路由器(Selective Consumer Router)用于入站端点,它可以控制服务处理哪些消息。过滤路由器(Filtering Router)用于出站端点,可以控制哪些消息发送到下一个服务上。可以组合使用这些过滤器来控制消息流。
例如,如果只想处理不包含错误的消息,那么可以使用选择性消费者以确保只处理结果代码为success的消息。并使用Catch-all策略将其它的消息转发到另外端点上作为错误处理:
<inbound>
<selective-consumer-router>
<mulexml:jxpath-filter expression="msg/header/resultcode = 'success'"/>
</selective-consumer-router>
<forwarding-catch-all-strategy>
<jms:endpoint topic="error.topic"/>
</forwarding-catch-all-strategy>
</inbound>
在服务处理消息时,如果想通过指定的标准决定将消息发送到哪个端点,那么可以在出站端点上使用过滤路由器。在下面的示例中,将包含异常信息的消息发送到系统管理员的email邮箱,将包含特定字符串的消息发送到名为string.queue的队列,并使用forwarding catch-all路由器接收余下的所有消息,并将它们发送到名为error.queue的死信队列:
<outbound>
<filtering-router>
<smtp:outbound-endpoint to="ross@muleumo.org"/>
<payload-type-filter expectedTypeexpectedType="java.lang.Exception"/>
</filtering-router>
<filtering-router>
<jms:outbound-endpoint to="string.queue"/>
<and-filter>
<payload-type-filter expectedType="java.lang.String"/>
<regex-filter pattern="the quick brown (.*)"/>
</and-filter>
</filtering-router>
<forwarding-catch-all-strategy>
<jms:outbound-endpoint queue="error.queue"/>
</forwarding-catch-all-strategy>
</outbound>
与过滤路由器(filtering router)相似的路由器有转发路由器(forwarding router),它可以处理一些消息并可以选择性地将消息转发到其它路由器,还有wiretap router,这种路由器可以处理所有的消息,并将它们发送到端点上,同时也将消息的副本发送到另外一个端点。更多信息可以参看Mule用户指南中的入站路由器(Inbound Routers)。
假设我们有一个验证服务,当消息没有通过验证时,想将该消息以及验证异常转发到另一个服务,并将消息和验证异常返回给调用者。那么可以使用链接路由器(chaining router),它是一个高速的、轻量级的可配置路由器,可用于将消息发送到端点,然后将该端点的输出结果发送到另一个端点。例如:
<chaining-router>
<!-- 首先,将消息发送到这个端点,用于验证。 -->
<vm:outbound-endpoint path="ValidationService" synchronous="true"/>
<!-- 接着将包含表达式的消息发送到这个端点上 -->
<vm:outbound-endpoint path="ValidationError" synchronous="true">
<exception-type-filter expectedType="java.lang.Exception"/>
</vm:outbound-endpoint>
</chaining-router>
消息分解器(message splitter)可用于将输出消息(outgoing message)分解成多个部分,再将他们分发到配置在路由器(router)上的不同端点。例如,在订单处理应用中,如果想将经消息分解后的不同部分分发给不同的服务去处理,那么可以使用下面的路由器:
列表消息分解器(List Message Splitter):接收一个对象列表,这些对象将被路由到不同的端点。例如:
<outbound>
<list-message-splitter-router">
<!-- 将order路由到队列order.queue -->
<jms:outbound-endpoint queue="order.queue">
<payload-type-filter expectedType="com.foo.Order"/>
</jms:outbound-endpoint>
<!-- 将items路由到队列item.queue -->
<jms:outbound-endpoint queue="item.queue">
<payload-type-filter expectedType="com.foo.Item"/>
</jms:outbound-endpoint>
</list-message-splitter-router>
</outbound>
表达式分解路由器(Expression Splitter Router):它与列表消息分解器相似,只是它是基于表达式分解消息,将消息分解成一个或者多个部分。例如:
<outbound>
<expression-splitter-router
evaluator="xpath"
expression="/mule:mule/mule:model/mule:service"
disableRoundRobin="true"
failIfNoMatch="false">
<outbound-endpoint ref="service1">
<expression-filter
evaluator="xpath"
expression="/mule:service/@name = 'service splitter'"/>
</outbound-endpoint>
<outbound-endpoint ref="service2">
<expression-filter
evaluator="xpath"
expression="/mule:service/@name = 'round robin deterministic'"/>
</outbound-endpoint>
</expression-splitter-router>
</outbound>
关于如何配置表达式分解路由器的更多信息,可以参看Mule的用户手册中的表达式配置参考(Expressions Configuration Reference)。
为了提高性能也可以将消息分解成多个部分。轮叫(Round Robin)消息分解器将消息分解成多个部分,并以轮叫(round-robin)的方式将它们发送到端点。Message Chunking Router将消息按固定长度分解成多个部分,并将它们路由到同一个端点。
消息分解之后,可以使用Message Chunking Aggregator重新将消息块聚合在一起。该聚合器(aggregator)通过关联ID(correlation ID)来识别哪些消息块属于同一个消息,关联ID(correlation ID)在出站路由器(outbound router)上设置。
<inbound>
<message-chunking-aggregator-router>
<expression-message-info-mapping
correlationIdExpression="#[header:correlation]"/>
<payload-type-filter expectedType="org.foo.some.Object"/>
</message-chunking-aggregator-router>
</inbound>
幂等接收器(Idempotent Receiver)通过核对输入消息的唯一消息ID来保证只有拥有唯一ID的消息才能被服务所接收。消息ID可以通过使用一个表达式从消息中产生,该表达式在 idExpression属性中定义。#[message:id]是默认的表达式,也就是说如果要实现该功能,端点必须支持唯一性消息ID。在下面的例子中,唯一性ID是由消息ID和消息标头中标签的内容组合而成。所有的消息ID都被记录到一个简单的文本文件中,用于追踪哪些消息已经处理过。
<inbound>
<idempotent-receiver-router idExpression="#[message:id]-#[header:label]">
<simple-text-file-store directory="./idempotent"/>
</idempotent-receiver-router>
</inbound>
除了使用消息路由器控制服务间的消息流之外,也可以通过组件绑定(Component Bindings)调用处理消息的外部服务(External Service)。

在这个方法中,可以将Mule的端点绑定到Java接口方法。该方法的优势在于,在组件仍在处理消息时,你可以使用外部服务,而无需使用Mule的API 或者修改组件的代码。相反,只需要在XML配置文件中配置组件绑定,从而指定外部服务的端点。例如,在下面的绑定例子中,当sayHello方法被调用时,HelloInterface中的sayHello方法会调用外部的HelloWeb服务。
<component class="org.mule.examples.bindings.InvokerComponent">
<binding interface="org.mule.examples.bindings.HelloInterface"
method="sayHello">
<cxf:outbound-endpoint
address="http://myhost.com:81/services/HelloWeb?method=helloMethod"
synchronous="true"/>
</binding>
</component>
更多信息,可以参看Mule用户指南中的组件绑定(Component Bindings)。
Mule为控制应用中的消息如何交换提供了多种方法。本文总体上介绍了Mule的消息路由,以及它所支持的消息类型,一些常用的路由器和组件绑定。关于消息路由的完整信息,可以参看Mule 的用户手册。
查看英文原文:Routing Messages in Mule
译者简介:
陈义,计算机应用技术专业硕士研究生,一直专注于SOA、BPM、ESB、EAI和MOM的研究及应用。热衷于开源SOA项目,有志致力于 Mule、ServiceMix、ODE、ActiveBPEL、ActiveMQ、OpenJMS、Camel、CXF、XFire以及Tuscany 在中文社区的研究和推广工作。您可以通过honnom (at) 163.com联系到他。
感谢胡键对本文的审校。
给InfoQ中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家加入到InfoQ中文站用户讨论组中与我们的编辑和其他读者朋友交流。
本次分享将会就大规模视频网站的计费与流量管理这个话题,从操作层面细细进行讲解和分析,为系统工程师们揭示平日里我们没有关心的另一些内容。同时也希望本次分享能揭示行业中的一些“潜规则”,让互联网行业的流量与带宽管理更为开放与简洁。
本次演讲视频录制于QCon杭州2011。
Jeffrey Richter以其多本Windows核心技术的经典著作而闻名,同时,他深入掌握微软的.NET等一系列核心技术,2012年1月,Jeffrey Richter在北京接受了InfoQ中文站的专访,谈到Windows 8和WinRT编程,并就异步编程、Windows编程中的可扩展性、性能和安全性方面给出自己的建议。
云计算平台的可用性,相比传统互联网服务而言,更加复杂和困难,也更具有挑战性。本文借助新浪SAE云平台为读者讲述了云平台可用性的定义、如何打造高可用的平台,以及对云计算的用户提出了建议。
淘宝高度重视Java平台的健康发展,组建了一个团队专注于Java平台的底层部分的性能、功能与稳定性改进;工作主要基于OpenJDK中的HotSpot VM开展,其中一些通用的功能随后也会逐渐反馈给OpenJDK社区。希望能与使用Java平台开发应用的大家交流经验。
本次演讲视频录制于QCon杭州2011。
2011年4月21日至22日是值得云计算从业者纪念的日子。Amazon的IaaS服务出现故障,导致许多商业网站的服务中断,影响非常严重。作为云计算用户,我们需要思考的是,如何保证即便在云服务不可用的情况,我们的应用架构仍然能够屹立不倒?本文正是站在云计算用户的角度试图探讨这一问题。
12人的技术团队,4组刀片服务器,每月20亿的访问量,每日1次准时部署,99.9%的可用性。这可能吗?当然。想知道如何做的吗?百姓网将与您分享他们在DevOps实践过程中的经验和技巧。
本次演讲视频录制于QCon杭州2011。
篱笆作为一家起源于社区的电子商务公司,反映到技术层面就是同时要面对产品和业务,以及经营战略的变化调整。如何在产品和业务的夹缝之间完成技术架构的抽象与平衡,寻找更有效的价值定位,这当中有些经验教训和个人感悟愿与众人分享。
本次演讲视频录制于QCon杭州2011。
本文将对特性注入以及相关方法做一个扫盲性的介绍。我们会解释这个框架的关键要素,并附上实例来证实它们。为了让文章保持相对较短,我们不会深入到某个工具或方法中,而是会给出一些参考资料,以便大家做进一步的研究。
3 条回复
关注此讨论 回复