Finagle是一个协议不可知的,异步的,用于 JVM 的 RPC 系统,它使得在 Java、Scala 或任何基于JVM 的语言重构建鲁棒的客户端和服务器非常容易。
在 Twitter.com上面即使是渲染最简单的网页也需要十多个说着不同协议的网络服务的合作。比如,为了渲染首页,应用程序需要向社交网络图(SocialGraph)服务、Memcached、数据库、以及许多其它网络服务发出请求。他们每个都使用不同的协议:Thrift、Memcached、MySQL等等。此外,这些服务之间还相互交谈——他们既是服务器又是客户端。比如,社交网络图服务就提供了一个 Thrift接口,但是它也从一个 MySQL 集群里面获取信息。
在这样一个系统里面,服务中断最常见的原因就是这些部件之间在发生故障的时候糟糕的交互;常见的故障包括崩溃的主机和极高的时延差异。这些故障可以通过让工作队列任务堆积、TCP连接搅动(churn)、耗光内存和文件描述符等方式在系统里面叠加起来。在最糟的情况下,用户就会看到失败鲸。
构造一个稳定的分布式系统的挑战
复杂的网络服务器和客户端有很多活动部件:故障检测器、负载平衡器、失效备援策略(failoverstrategy)等等。这些部件之间需要达到一种精致的平衡,以便对大型产品系统里面的故障有足够的弹性。
故障检测器、负载平衡器等部件的不同协议的很多不同实现使得这个任务变得尤其困难。比如,Thrift 的背压(backpressure)策略就和 HTTP 的不同。在事故的时候确保在这种异构系统上的覆盖率非常具有挑战性。
我们的方法
我们设计了一个能够用于我们所有协议的基本网络服务器和客户端组件的单一实现。Finagle 是一个协议不可知的、异步的、用于Java 虚拟机的远程过程调用(RPC)系统,它可能让在 Java、Scala或任何基于 JVM的语言上构建鲁棒的客户端和服务器变得很容易。Finagle 支持广泛的基于请求/答复的 RPC 协议和很多类型的流协议。
Finagle 提供了以下功能的鲁棒实现:
val request: HttpRequest = newDefaultHttpRequest(HTTP_1_1, GET,"/") val responseFuture: Future[HttpResponse] = client(request) responseFutureonSuccess {responseFuture => println(responseFuture) } onFailure { exception => println(exception) }
val stringFuture: Future[String] =Future("1") val intFuture: Future[Int] =stringFuture map{ string => string.toInt }
类似地,你还可以用 flatMap 把一系列 Future 串成一个流水线: val authenticatedUser: Future[User] = User.authenticate(email, password) val lookupTweets: Future[Seq[Tweet]] = authenticatedUser flatMap{ user => Tweet.findAllByUser(user) }
for { user<- User.authenticate(email, password) tweets<- Tweet.findAllByUser(user) } yield tweets
val severalFutures = Seq[Future[Int]] = Seq(Tweet.find(1), Tweet.find(2), ...) val combinedFuture: Future[Seq[Int]] = Future.collect(severalFutures)
val service = new Service[HttpRequest, HttpResponse] { defapply(request: HttpRequest) = Future(newDefaultHttpResponse(HTTP_1_1, OK)) } val address = new InetSocketAddress(10000) val server: Server[HttpRequest, HttpResponse] = ServerBuilder() .name("MyWebServer") .codec(Http()) .bindTo(address) .build(service)
val client: Service[HttpRequest, HttpResponse] = ClientBuilder() .codec(Http()) .hosts(address) .build() // Issue a request, geta response: val request: HttpRequest = newDefaultHttpRequest(HTTP_1_1, GET,"/") client(request) onSuccess { response => println("Receivedresponse: " + response) }
classRequireAuthentication(a:Authenticator)extends Filter[...] { defapply( request:Request, continue:Service[AuthenticatedRequest, HttpResponse] )= { a.authenticate(request)flatMap { caseAuthResult(OK,passport)=> continue(AuthenticatedRequest(request,passport)) caseAuthResult(Error(code))=> Future.exception(newRequestUnauthenticated(code)) } } }
来源:http://blog.csdn.net/jmppok/article/details/17268251