微信号:infoqchina

介绍:有内容的技术社区媒体

Twitter的RPC框架Finagle简介

2014-06-02 20:06 InfoQ

FinagleTwitter基于Netty开发的支持容错的、协议无关的RPC框架,该框架支撑了Twitter的核心服务。来自Twitter的软件工程师Jeff Smick撰文详细描述了该框架的工作原理和使用方式。

Jeff Smick的博客文章中,介绍了Twitter的架构演进历程。Twitter面向服务的架构是由一个庞大的Ruby on Rails应用转化而来的。为了适应这种架构的变化,需要有一个高性能的、支持容错的、协议无关且异步的RPC框架。在面向服务的架构之中,服务会将大多数的时间花费在等待上游服务的响应上,因此使用异步的库能够让服务并发地处理请求,从而充分发挥硬件的潜能。Finagle构建在Netty之上,并不是直接在原生NIO之上构建的,这是因为Netty已经解决了许多Twitter所遇到的问题并提供了干净整洁的API

Twitter构建在多个开源协议之上,包括HTTPThriftMemcachedMySQL以及Redis。因此,网络栈需要足够灵活,以保证能与这些协议进行交流并且还要具有足够的可扩展性以支持添加新的协议。Netty本身没有与任何特定的协议绑定,对其添加协议支持非常简单,只需创建对应的事件处理器(event handler)即可。这种可扩展性产生了众多社区驱动的协议实现,包括SPDYPostrgreSQLWebSocketsIRC以及AWS

Netty的连接管理以及协议无关性为Finagle奠定了很好的基础,不过Twitter的有些需求是Netty没有原生支持的,因为这些需求都是“较高层次的”。比如,客户端需要连接到服务器集群并且要进行负载均衡。所有的服务均需要导出指标信息(如请求率、延迟等),这些指标为调试服务的行为提供了有价值的内部信息。在面向服务架构中,一个请求可能会经过数十个服务,所以如果没有跟踪框架的话,调试性能问题几乎是不可能的。为了解决这些问题,Twitter构建了Finagle。简而言之,Finagle依赖于NettyIO多路复用技术(multiplexing),并在Netty面向连接的模型之上提供了面向事务(transaction-oriented)的框架。

Finagle的工作原理

Finagle强调模块化的理念,它会将独立的组件组合在一起。每个组件可以根据配置进行替换。

Finagle栈的底部是Transport,它代表了对象的流,这种流可以异步地读取和写入。Transport实现为NettyChannelHandler,并插入到ChannelPipeline的最后。当Finagle识别到服务已经准备好读取数据时,Netty会从线路中读取数据并使其穿过ChannelPipeline,这些数据会被codec解析,然后发送到FinagleTransport。从这里开始,Finagle将数据发送到自己的栈之中。

对于客户端的连接,Finagle维持了一个Transport的池,通过它来平衡负载。根据所提供的连接池语义,Finagle可以向Netty请求一个新的连接,也可以重用空闲的连接。当请求新的连接时,会基于客户端的codec创建一个Netty ChannelPipeline。一些额外的ChannelHandler会添加到ChannelPipeline之中,以完成统计(stats)、日志以及SSL的功能。如果所有的连接都处于忙碌的状态,那么请求将会按照所配置的排队策略进行排队等候。

在服务端,Netty通过所提供的ChannelPipelineFactory来管理codec、统计、超时以及日志等功能。在服务端ChannelPipeline中,最后一个ChannelHandlerFinagle桥(bridge)。这个桥会等待新进入的连接并为每个连接创建新的TransportTransport在传递给服务器实现之前会包装一个新的channel。然后,会从ChannelPipeline之中读取信息,并发送到所实现的服务器实例中。

  1. Finagle客户端位于FinagleTransport之上,这个Transport为用户抽象了Netty

  2. Netty ChannelPipeline包含了所有的ChannelHandler实现,这些实现完成实际的工作;

  3. 对于每一个连接都会创建Finagle服务器,并且会为其提供一个Transport来进行读取和写入;

  4. ChannelHandler实现了协议的编码/解码逻辑、连接级别的统计以及SSL处理。

桥接NettyFinagle

Finagle客户端使用ChannelConnector来桥接FinagleNettyChannelConnector是一个函数,接受SocketAddress并返回FutureTransport。当请求新的Netty连接时,Finagle使用ChannelConnector来请求一个新的Channel,并使用该Channel创建Transport。连接会异步建立,如果连接成功的话,会使用新建立的Transport来填充Future,如果无法建立连接的话,就会产生失败。Finagle客户端会基于这个Transport分发请求。

Finagle服务器会通过Listener绑定一个接口和端口。当新的连接创建时,Listener创建一个Transport并将其传入一个给定的函数。这样,Transport会传给Dispatcher,它会根据指定的策略将来自Transport的请求分发给Service

Finagle的抽象

Finagle的核心概念是一个简单的函数(在这里函数式编程很关键),这个函数会从Request生成包含ResponseFuture

Future是一个容器,用来保存异步操作的结果,这样的操作包括网络RPC、超时或磁盘的I/O操作。Future要么是空——此时尚未有可用的结果,要么成功——生成者已经完成操作并将结果填充到了Future之中,要么失败——生产者发生了失败,Future中包含了结果异常。

这种简单性能够促成很强大的结构。在客户端和服务器端,Service代表着相同的API。服务器端实现Service接口,这个服务器可以用来进行具体的测试,Finagle也可以将其在某个网络接口上导出。客户端可以得到Service的实现,这个实现可以是虚拟的,也可以是远程服务器的具体实现。

对请求失败的管理

为了获取更好的失败管理功能,Finagle在吞吐量和延迟上做了一定的牺牲。

Finagle可以使用主机集群实现负载的平衡,客户端在本地会跟踪它所知道的每个主机。它是通过计数发送到某个主机上的未完成请求做到这一点的。这样的话,Finagle就能将新的请求发送给最低负载的主机,同时也就能获得最低的延迟。

如果发生了失败的请求,Finagle会关闭到失败主机的连接,并将其从负载均衡器中移除。在后台,Finagle会不断地尝试重新连接,如果Finagle能够重新建立连接的话,就会再次将其添加到负载均衡器之中。

服务的组合

Finagle将服务作为函数的理念能够编写出简单且具有表述性的代码。例如,某个用户对其时间线(timeline)的请求会涉及到多个服务,核心包括认证服务、时间线服务以及Tweet服务。

更多精彩内容,请点击阅读原文。

***********************************

本文来自InfoQ微信公众账号:infoqchina

1、回复“今日新闻”,查看今天更新的新闻;

2、回复“今日英文”,查看今天英文站的更新;

3、回复“文章 +关键词”,搜索关键词相关内容;

4、回复“QCon”,了解QCon大会相关信息;

5、回复“活动”,了解最近InfoQ组织的线下沙龙;

6、回复“架构师”,获取《架构师》下载地址;

7、回复“投稿”,了解投稿和加入编辑团队的流程。

***********************************


 
InfoQ 更多文章 Facebook如何实现PB级别数据库自动化备份 学术派Google软件工程师Matt Welsh谈移动开发趋势 Spotify为什么要使用一些“无聊”的技术? 妹纸们放假了,汉纸们做啥? 大多数重构可以避免
猜您喜欢 为了腾讯云,马化腾不仅亲自上阵,还约了郁亮、俞敏洪、方洪波等百名大咖 Folly源码分析系列(一) — ThreadLocalPtr Android混淆的故事 1209万人课堂实录 | 物流配送系统的高可用服务揭秘 @京东青龙 iOS内存泄漏自动检测工具LeakSniffer