CWYAlpha

Just another WordPress.com site

Thought this was cool: Twitter搜索架构设计核心之二:Blender

leave a comment »


Twitter的实时搜索在2010年重写了架构。新架构的核心就是Blender 和
Earlybird。本文主要介绍一下Blender架构。Blender是Twitter实时搜索的前端检索架构,上线替换了从前的Ruby-on-Rails前端架构。Blender比之前的架构提升了3倍的性能(搜索时延从800ms降低到250ms,前端机的CPU负载降低到一半),也使得能够更快的迭代搜索新功能。

1

为了理解Blender的性能提升,先来看看旧架构Ruby-on-Rails前端服务的低效的地方。每个前端运营固定数量的单线程rails工作线程,每个处理如下事务:

  • Query分析(parsed queries)
  • 同步查询索引服务器
  • 汇总和呈现结果

同步请求模型对CPU的利用率非常低效。随着时间的推移,Ruby代码积累了更多的技术债务,很难增加新的功能和改善搜索引擎的可靠性。Blender的解决方案如下:

  • 创建一个完全异步的聚合服务。没有线程在等待网络I/O的完成。
  • 从后端服务汇总结果。例如,实时结果、Top tweet和地理位置索引。
  • 优雅的处理了服务之间的依赖关系。工作流程自动处理后端服务之间的传递依赖。

下图是Twitter搜索引擎的架构。从网站上、API或者内部客户端发来的Queries,通过硬件负载均衡器,被提交给Blender。Blender做Query分析,并提交给后端服务,使用工作流程处理服务之间的依赖。最后,检索服务返回的结果合并,并以合适语言呈现在终端。
image

Blender概览

Blender是建立在Netty(一个Java编写的高度可扩展的NIO客户端服务器库,支持多种协议)基础上Thrift和HTTP服务。Twitter之所以选择Netty框架,而不是Mina或Jetty等,因为Netty是一个更干净的API,也有更好的文档说明,且在Twitter很多项目中已经得到应用。为了让Netty能用在Thrift中,Twitter写了一个简单Thrift解码器,负责Thrift和Netty之间的协议数据转换。

Netty定义了一个关键抽象Channel,封装了网络socket读写,对外提供了一套I/O操作接口,如read、write、connect和bind。所有通道的I/O操作都具有异步特性。这意味着任何I/O调用都能够立即返回一个ChannelFuture实例,并通知所请求的I/O操作成功、失败或取消与否。

当Netty服务接受到一个新的连接,将会创建一个新的通道来处理它。一个通道实际上没有什么,只是一序列实现了业务处理逻辑的channel
handlers。接下来,我们来看看Blender是如何映射这些通道到Query的处理流程中。

工作流框架

Blender中工作流(workflow)是一套后端服务相互依赖的服务。Blender自动解析了服务之间的依赖关系,例如,如果服务A依赖服务B,A被先请求是,它的结果会被传递给B。很方便的使用有向无环图(directed
acyclic graphs)表示工作流(如下图)。


image

在上例的工作流中,有6个服务{s1,s2,s3,s4,s5,s6},彼此有一定依赖关系。从s3到s1的有向边表示调用s1之前一定要调用s3,因为s1需要从s3返回的结果。鉴于这样的工作流程,Blender框架执行一个拓扑排序(topological
sort),也决定服务的总体序。上面的例子,执行顺序是{(s3,s4),(s1,s5,s6),(s2)},即s3和s4可以首批并行调用,一旦它们的结果返回,s1,s5和s6在第二批并行调用,最后调用s2。

一旦Blender决定了工作流的执行顺序,它将会被映射到Netty管道。这个管道是一系列请求相关的业务处理句柄。

请求复用

因为工作流被映射到Netty管道,所以必须将输入的请求能够找到合适的管道。Twitter构建了一个代理层(proxy
layer)复用和路由客户端请求到合适管道。称之为:请求复用(Multiplexing Incoming
Requests)。如下:

  • 当远程的Thrift客户端打开一个持久连接到Blender,代理层创建一个本地客户的映射——本地工作流服务之一。注意,所有的本地工作流服务都运行在Blender的JVM进程中,并在Blender启动时就被实例化。
  • 当请求到达socket时,代理层读到它,判断出所需要的工作流,并路由到合适的工作流服务。
  • 类似地,本地工作流服务的响应,代理层读取它,并写回远端的应答中。

Twitter使用了Netty的事件驱动模型(event-driven)来异步的完成上述所有的任务,所以没有线程在等待I/O。

调度后端请求

调度后端请求(Dispatching back-end
requests)。一旦请求到达了工作流管道,将运行一系列服务句柄。每个服务句柄构造合适的后端服务请求,并提交到远端服务器。例如,实时服务句柄构造一个实时搜索请求,并异步地发给一个或者多个实时索引服务。Twitter使用Twitter
commons库(即将开源)做连接池的管理,负载均衡和僵死连接检测。

当后端服务已经被分配时,相应处理请求的I/O线程就可以被释放了。一个时钟线程(timer
thread)每隔几毫秒就检测一下是否后端结果已经返回,并做标识请求成功、超时或失败。在一个检索Query的生命周期里,我们需要维护一个对象来管理这类型的数据。

成功返回的结果汇总后,会发给工作流管道中的下一批服务句柄。当首批调用服务都返回了结果,第二批异步请求才会开始。这个过程会不断重复,直到我们完成了工作流或者工作流超时。

通过工作流的执行方式,没有线程在等待I/O。这样Blender机器上CPU都被有效利用,并能够处理更大数量的并发请求。同时,后端服务的并行请求也节省的响应时间。

 

参考文章:http://engineering.twitter.com/2011/04/twitter-search-is-now-3x-faster_1656.html

转载请注明出处:互联网旁观者~黄言之 http://blog.sina.com.cn/netreview/

from 互联网旁观者: http://blog.sina.com.cn/s/blog_72995dcc01013pyu.html

Written by cwyalpha

五月 11, 2012 在 2:39 下午

发表在 Uncategorized

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s

%d 博主赞过: