Finagle

Twitter的RPC框架Finagle简介
http://www.infoq.com/cn/news/2014/05/twitter-finagle-intro

Twitter研发人员John Oskasson分析Twitter后台软件栈
http://www.infoq.com/cn/news/2013/02/twitter-stack

Finagle抽象出了RPC系统的底层核心功能,大大降低了服务开发人员需要处理的复杂性。让开发人员可以专心编写业务逻辑,而不是处理分布式系统的底层细节。网站本身使用这些服务完成运维操作,或是获取产生HTML的数据。在Twitter里面,内部服务都使用Thrift协议,但是Fingale支持其他协议,包括Protocol buffers和HTTP。

使用Finagle设置一个服务需要四个步骤:

编写一个Thrift文件,定义API。其中应该包含结构体、异常和方法,用来描述服务的功能。可以查看Thrift的接口描述语言文档(Interface Description Language,简称IDL),特别是结尾处的例子。
使用Thrift文件作为代码生成器的输入,生成你需要的语言代码。对于基于Scala和Finagle的项目,John推荐Scrooge。
实现Thrift IDL中的Scala特性。这就是服务真正要实行的功能。
为Finagle服务构建器提供上述实现的实例,还有用来绑定的端口,还有其他启动服务需要的任何设定。
似乎这与平常使用Thrift没有区别,但是Finagle中有很多改进,比如出色的监控支持、跟踪,Finagle还能让开发人员以异步方式编写服务。同时,Finagle也可用来作为客户端,处理超时、重试和负载均衡。

Finagle构建在Netty之上,并不是直接在原生NIO之上构建的,这是因为Netty已经解决了许多Twitter所遇到的问题并提供了干净整洁的API。

Twitter的RPC框架Finagle简介_系统架构
http://www.kuqin.com/shuoit/20140604/340351.html

Finagle依赖于Netty的IO多路复用技术(multiplexing),并在Netty面向连接的模型之上提供了面向事务(transaction-oriented)的框架。

Finagle的工作原理

    Finagle强调模块化的理念,它会将独立的组件组合在一起。每个组件可以根据配置进行替换。比如,所有的跟踪器(tracer)都实现了相同的接口,这样的话,就可以创建跟踪器将追踪数据存储到本地文件、保持在内存中并暴露为读取端点或者将其写入到网络之中。
    在Finagle栈的底部是Transport,它代表了对象的流,这种流可以异步地读取和写入。Transport实现为Netty的ChannelHandler,并插入到ChannelPipeline的最后。当Finagle识别到服务已经准备好读取数据时,Netty会从线路中读取数据并使其穿过ChannelPipeline,这些数据会被codec解析,然后发送到Finagle的Transport。从这里开始,Finagle将数据发送到自己的栈之中。
    对于客户端的连接,Finagle维持了一个Transport的池,通过它来平衡负载。根据所提供的连接池语义,Finagle可以向Netty请求一个新的连接,也可以重用空闲的连接。当请求新的连接时,会基于客户端的codec创建一个Netty ChannelPipeline。一些额外的ChannelHandler会添加到ChannelPipeline之中,以完成统计(stats)、日志以及SSL的功能。如果所有的连接都处于忙碌的状态,那么请求将会按照所配置的排队策略进行排队等候。

    在服务端,Netty通过所提供的ChannelPipelineFactory来管理codec、统计、超时以及日志等功能。在服务端ChannelPipeline中,最后一个ChannelHandler是Finagle桥(bridge)。这个桥会等待新进入的连接并为每个连接创建新的Transport。Transport在传递给服务器实现之前会包装一个新的channel。然后,会从ChannelPipeline之中读取信息,并发送到所实现的服务器实例中。
   
    Finagle客户端位于Finagle Transport之上,这个Transport为用户抽象了Netty;
Netty ChannelPipeline包含了所有的ChannelHandler实现,这些实现完成实际的工作;
对于每一个连接都会创建Finagle服务器,并且会为其提供一个Transport来进行读取和写入;
ChannelHandler实现了协议的编码/解码逻辑、连接级别的统计以及SSL处理。

    桥接Netty与Finagle
   
    Finagle客户端使用ChannelConnector来桥接Finagle与Netty。ChannelConnector是一个函数,接受SocketAddress并返回Future Transport。当请求新的Netty连接时,Finagle使用ChannelConnector来请求一个新的Channel,并使用该Channel创建Transport。连接会异步建立,如果连接成功的话,会使用新建立的Transport来填充Future,如果无法建立连接的话,就会产生失败。Finagle客户端会基于这个Transport分发请求。
    Finagle服务器会通过Listener绑定一个接口和端口。当新的连接创建时,Listener创建一个Transport并将其传入一个给定的函数。这样,Transport会传给Dispatcher,它会根据指定的策略将来自Transport的请求分发给Service。

     Finagle的抽象
   Finagle的核心概念是一个简单的函数(在这里函数式编程很关键),这个函数会从Request生成包含Response的Future:
   type Service[Req, Rep] = Req => Future[Rep]
  
   Future是一个容器,用来保存异步操作的结果,这样的操作包括网络RPC、超时或磁盘的I/O操作。Future要么是空——此时尚未有可用的结果,要么成功——生成者已经完成操作并将结果填充到了Future之中,要么失败——生产者发生了失败,Future中包含了结果异常。

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

在这里,客户端代码的行为方式是一样的,但是并不需要网络连接,这就使得客户端和服务器的测试变得很简单直接。

客户端和服务器提供的都是应用特定的功能,但通常也会需要一些与应用本身无关的功能,举例来说认证、超时、统计等等。Filter为实现应用无关的特性提供了抽象。
    Filter接受一个请求以及要进行组合的Service:
    type Filter[Req, Rep] = (Req, Service[Req, Rep]) => Future[Rep]

    在应用到Service之前,Filter可以形成链:

recordHandletime andThentraceRequest andThencollectJvmStatsandThen myService
    Finagle在内部大量使用了Filter,Filter有助于促进模块化和可重用性。

    Filter还可以修改请求和响应的数据及类型。下图展现了一个请求穿过过滤器链到达Service以及响应反向穿出的过程:
   
    对请求失败的管理
    为了获取更好的失败管理功能,Finagle在吞吐量和延迟上做了一定的牺牲。
    Finagle可以使用主机集群实现负载的平衡,客户端在本地会跟踪它所知道的每个主机。它是通过计数发送到某个主机上的未完成请求做到这一点的。这样的话,Finagle就能将新的请求发送给最低负载的主机,同时也就能获得最低的延迟。
    如果发生了失败的请求,Finagle会关闭到失败主机的连接,并将其从负载均衡器中移除。在后台,Finagle会不断地尝试重新连接,如果Finagle能够重新建立连接的话,就会再次将其添加到负载均衡器之中。

   服务的组合
Finagle将服务作为函数的理念能够编写出简单且具有表述性的代码。例如,某个用户对其时间线(timeline)的请求会涉及到多个服务,核心包括认证服务、时间线服务以及Tweet服务。它们之间的关系可以很简洁地进行表述:
val timelineSvc = Thrift.newIface[TimelineService](...) // #1  
val tweetSvc = Thrift.newIface[TweetService](...) 
val authSvc = Thrift.newIface[AuthService](...)   
val authFilter = Filter.mk[Req, AuthReq, Res, Res] { (req, svc) => // #2
           authSvc.authenticate(req) flatMap svc(_) 
}   
val apiService = Service.mk[AuthReq, Res] { req =>   
   timelineSvc(req.userId) flatMap {tl =>     
	val tweets = tl map tweetSvc.getById(_)     
	Future.collect(tweets) map tweetsToJson(_) }     
	}    
} //#3  
Http.serve(":80", authFilter andThen apiService) // #4   
// #1 创建每个服务的客户端 
// #2 创建过滤器来认证传入的请求
// #3 创建服务,将已认证的时间线请求转换为json响应  
// #4 使用认证过滤器和服务,在80端口启动新的HTTP服务器


在上面的例子中,创建了时间线服务、Tweet服务以及认证服务的客户端,创建了一个Filter来认证原始的请求,最后,实现了服务,将其与认证过滤器组合起来,并暴露在80端口上。
 
[转]Finagle:一个支持多协议的RPC系统
http://blog.csdn.net/heiyeshuwu/article/details/41480635

Finagle 非常灵活且易于使用,因为它是构造在几个简单的、可组合的基本元素上:Future,Services,以及Filters。
    我们设计了一个能够用于我们所有协议的基本网络服务器和客户端组件的单一实现。Finagle 是一个协议不可知的、异步的、用于Java 虚拟机的远程过程调用(RPC)系统,它可能让在 Java、Scala或任何基于 JVM的语言上构建鲁棒的客户端和服务器变得很容易。Finagle 支持广泛的基于请求/答复的 RPC 协议和很多类型的流协议。

Finagle 提供了以下功能的鲁棒实现:
连接池(connection pool):带有限流(throttling)支持以防止 TCP连接搅动(churn);
故障检测器(failure detector),用于识别太慢或者崩溃了的主机;
失效备援策略(failover strategies),用于把流量从不健康的主机上引开;
平衡负载器(load-balancer),包括“最少连接”和其它策略;以及
背压(back-pressure)技术,用于保护服务器免受客户端滥用或者叠罗汉(或DoS攻击)。
此外,Finagle 还让构造和部署下列服务变得容易:
发布标准统计信息、日志和异常报告;
支持跨协议的分布式追踪(以 Dapper 形式);
选择性地使用 ZooKeeper 用于集群管理;以及
支持常见切分(sharding)策略。

Future 对象
在 Finagle 中,Future 对象是对于所有异步计算的统一抽象。一个 Future表示了一个尚未完成的计算,其可能成功也可能失败。使用 Future 两个最基本的方法是:
阻塞并等待计算结束返回
注册一个回调函数,在计算最终成功或失败时 Future 回调

Service对象

Service 是一个函数,其接受一个请求,返回一个 Future 对象作为答复。注意客户端和服务器都是用 Service对象表示的。

要创建一个 Service 对象,你需要继承抽象的 Service 类并监听一个端口。

Filter对象

Filter 是一种把你的应用程序中不同的阶段的孤立出来组成一个流水线的有用的方式。比如,你可能需要在你的 Service开始接受请求前处理异常、授权等问题。

一个 Filter 包裹了一个 Service,且潜在地,把 Service 的输入和输出类型转换成其它类型。换一句话说,Filter是一个转换器。

java搭建finagle(1)
http://www.cnblogs.com/rufus-hua/p/4159278.html
java搭建finagle(2)---学习下
http://www.cnblogs.com/rufus-hua/p/4969863.html


猜你喜欢

转载自wangqiaowqo.iteye.com/blog/2258128