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

作者 David Dossot 译者 张龙 发布于 2009年11月19日
在过去几年中,REST风格的软件架构获得了越来越多的认可,这主要是因为它减少了系统对动件的需求、同时使系统耦合性更低,弹性更好。
目前越来越多的REST资源出现在企业应用中,因此对这些资源进行编排就显得非常重要了。比方说,典型的业务活动就包含了资源的创建,然后是资源的查找及其他资源的创建等。
本质上来说,与RESTful服务的交互是相当简单的:需要构造并发送适当的请求(请求头和请求体),然后分析返回的响应(响应头和响应体)。完成这个处 理并不需要什么特别的工具或是框架,只要有一个好用的HTTP客户端程序库就足够了。除此之外,由于RESTful交互过程中所涉及到的不同实体是由所谓 的微格式定义的,因此能够轻松解析或是输出这些实体的能力就显得非常重要了。
编排与多个资源的交互是个棘手的问题。我们需要定义编排、处理错误并不断尝试,同时系统必须能够在压力下表现良好。作为一个集成框架,Mule提供了我们所需的一切。
来考虑一个例子吧,某商业系统对新订单的处理需要如下编排:
我们将在本文详细分析上面每一步的交互过程,同时还会介绍为了获得上述交互所需的Mule动件和Groovy特性。
总体的编排包含了一系列通过特定路由、过滤器以及内存消息队列(aka VM队列)连接起来的Mule服务。 最近InfoQ上的这篇文章介绍了Mule中的消息路由,大家不妨移步一观。
Mule提供了一种简单而又强大的方式与RESfFul服务交互,那就是Mule RESTPack。
Mule RESTPack提供了一整套连接器与完整的指南以帮助用户创建新的RESTful应用。在本文撰写之际,该软件包提供了三种传送器,分别基于三种流行的REST框架:Abdera、Jersey及Restlet。这样我们就可以轻松公开新的资源,但如何集成现有的REST资源呢?
好消息是Mule标准的脚本模块所提供的Groovy支持有助于Mule HTTP传送器的使用,这样我们就可以成功与RESTful服务交互了。
首先来看看第一个交互。HTTP向特定的资源发送一个XML实体来创建订单,如以下程序片段所示:
POST /orders HTTP 1.1 ... <order xmlns='urn:acme:order:3:1'> <customerId>123456</customerId> <productId>P987C</productId> <quantity>2</quantity> </order>
如果成功服务器的响应如下:
201 Created Location: http://acme.com/order/O13579 ... <order id='O13579' />
在Mule中,我们可以通过一个简单的HTTP输出端点(outbound endpoint)实现该交互。注意到交互本身是通过向订单创建服务发送一个包含请求值(客户与产品ID、数量)的映射而触发的。该服务如下所示:
<service name="OrderCreationService">
<inbound>
<inbound-endpoint ref="OrderCreationQueue" />
</inbound>
<outbound>
<chaining-router>
<http:outbound-endpoint synchronous="true"
responseTimeout="15" method="POST"
host="${acme.order.hostname}"
port="${acme.order.port}" path="orders"
user="${acme.order.username}"
password="${acme.order.password}"
contentType="application/vnd.acme+xml" encoding="UTF-8">
<transformers>
<transformer ref="OrderMapToMicroformat" />
</transformers>
<response-transformers>
<message-properties-transformer>
<add-message-property key="OrderPlaced"
value="#[groovy:message.getStringProperty('http.status','ERR')=='201']" />
<add-message-property
key="OrderResourceLocation"
value="#[groovy:message.getStringProperty('Location','')]" />
</message-properties-transformer>
<object-to-string-transformer />
</response-transformers>
</http:outbound-endpoint>
<outbound-endpoint ref="OrderCreationResultQueue" />
</chaining-router>
</outbound>
</service>
这全是XML,我们来仔细分析一下:
OrderMapToMicroformat转换器完成了服务中的重头戏,而它是由Groovy的MarkupBuilder实现的。MarkupBuilder API提供了一种自然的方式生成兼容于特定微格式的XML实体:
<scripting:transformer name="OrderMapToMicroformat">
<scripting:script engine="groovy"> <![CDATA[
def writer = new StringWriter()
def xml = new groovy.xml.MarkupBuilder(writer)
xml.order(xmlns: 'urn:acme:order:3:1') {
customerId(payload.clientId)
productId(payload.productCode)
quantity(payload.quantity)
}
result = writer.toString() ]]>
</scripting:script>
</scripting:transformer>
注意map payload中的值是如何用于组装XML元素的:这里解决了一些不匹配的命名约定(比如将clientId转换为customerId)。
如你所期望的那样,该转换器产生了如下输入:
<order xmlns='urn:acme:order:3:1'> <customerId>123456</customerId> <productId>P987C</productId> <quantity>2</quantity> </order>
除了正确的内容类型外都是订单的RESTful服务用于创建新资源所需的内容。
现在我们来看一下负责异步分析订单创建结果并决定是否需要进一步进行编排的服务:
<service name="OrderCreationResultProcessor">
<inbound>
<inbound-endpoint ref="OrderCreationResultQueue" />
<selective-consumer-router>
<message-property-filter pattern="OrderPlaced=true" />
</selective-consumer-router>
<logging-catch-all-strategy />
</inbound>
<outbound>
<pass-through-router>
<outbound-endpoint ref="SuccessfulOrderQueue" />
</pass-through-router>
</outbound>
</service>
我们使用的选择性消费者(selective consumer)所接收的消息中一定要包含订单成功处理的头信息。如果该头信息为true,那就通过一个名为SuccessfulOrderQueue 的内存队列将该消息路由给第三个(也是最终的)服务,该服务会处理订单成功创建的消息。注意在这个例子中我们只是简单地将错误消息以日志的方式记录下来, 但在实际应用中需要将错误消息发送给专门的队列以进行后续的分析或是及时的反馈。
组成该编排的最后一个服务负责HTTP GET处理,它会获得新创建的订单,订单中包含了额外的值以形成一个合法的消息供email网关使用。如下是个示例交互:
GET /order/O13579 HTTP 1.1 200 OK Content-Type: application/vnd.acme+xml ... <order xmlns='urn:acme:order:3:1'> <customerId>123456</customerId> <productId>P987C</productId> <quantity>2</quantity> <customerEmail>foo@bar.baz</customerEmail> <estimatedShipping>2009-31-12T00:00:00Z</estimatedShipping> </order>
好消息是Mule的HTTP传送包含了一个名为rest-servicecomponent的组件,该组件简化了服务与REST资源的交互。幸好有了这样一个组件,我们就无需将GET操作的结果发给随后的服务了,相反可以在单独的服务中完成一切。除此以外,它还支持在配置中使用表达式,这样就能实现与动态构建的URL之间的连通了。
<service name="SuccessfulOrderProcessor">
<inbound>
<inbound-endpoint ref="SuccessfulOrderQueue" />
</inbound>
<http:rest-service-component httpMethod="GET"
serviceUrl="#[header:OrderResourceLocation]" />
<outbound>
<pass-through-router>
<outbound-endpoint ref="EmailGatewayQueue">
<transformers>
<object-to-string-transformer />
<transformer ref="OrderMicroformatToEmailMap" />
</transformers>
</outbound-endpoint>
</pass-through-router>
</outbound>
</service>
在接收到成功的订单消息后,该服务使用REST服务组件生成一个HTTP GET请求,并将该请求发送给此前存储在OrderResourceLocation属性(aka heade)中的URL。注意到我们是如何通过Mule表达式框架(使用#[...]语法)在组件中注入动态URL的。
在将GET请求的响应发送给负责与email网关进行通信的服务前,我们对XML订单实体进行了两次转换:
Groovy的XmlSlurper是解析XML微格式的理想工具,这要归功于其类似DSL的API。
如下代码展示了OrderMicroformatToEmailMap转换器的实现:
<scripting:transformer name="OrderMicroformatToEmailMap">
<scripting:script engine="groovy"><![CDATA[
def order = new XmlSlurper().parseText(payload)
.declareNamespace(acme: 'urn:acme:order:3:1')
result = [emailId:'OrderConfirmation',
emailAddress:order.'acme:customerEmail'.text(),
orderId:order.@id.text()]
]]>
</scripting:script>
</scripting:transformer>
没错,就两行Groovy代码,我们使用了一个命名空间感知的XML解析器和一个map构建器。其好处真是让人难以置信,不过这就是创建map(email网关服务所期望的)所需的全部内容。
在本文中,我们遵循着一个事先定义好的编排,新订单资源的URL是唯一的动态元素。开发者可以利用示例中介绍的转换器和表达式来支持更多的动态交互,如果你打算遵从HATEOAS路线,你就能获得一切。如果事实如此,那其他的Mule路由就唾手可得了,比如可以创建幂等接收者的 路由。你也看到了Groovy的强大功能和灵巧性加上Mule的通信能力极大地简化了与RESTful服务的交互。Mule的表达式和少量的Groovy 脚本能够有效地动态定义Mule配置。除此之外,通过使用异步的VM队列将编排的各个步骤链接起来可以在最大负荷下优雅地降级,这要归功于Mule内在的SEDA架构。
借助于这些强大的工具,集成REST资源变得非常简单了。
祝你好运!
大家可以从http://dossot.net/datastore/mule-groovy-rest.tar.gz下载完整的配置和相关的测试资源,这是一个独立的Maven项目。
查看英文原文:Orchestrating RESTful Services With Mule ESB And Groovy。
给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。
本文将对特性注入以及相关方法做一个扫盲性的介绍。我们会解释这个框架的关键要素,并附上实例来证实它们。为了让文章保持相对较短,我们不会深入到某个工具或方法中,而是会给出一些参考资料,以便大家做进一步的研究。
2 条回复
关注此讨论 回复