Skip to content

Instantly share code, notes, and snippets.

@seratch
Created May 18, 2012 00:51
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save seratch/2722513 to your computer and use it in GitHub Desktop.
Save seratch/2722513 to your computer and use it in GitHub Desktop.
Finagle Developer Guide (December 15, 2011 Draft) の適当な和訳

細かい点で間違いなどあるかと思います。fork して直していただけると助かります。

Finagle is built using sbt. We've included a bootstrap script to ensure the correct version of sbt is used. To build:

Finagle は sbt を使ってビルドしています。私たちは確実に適切なバージョンの sbt を使うようにブートストラップ用のスクリプトを含めています。このように実行します。

    $ ./sbt test

Finagle Developer Guide (December 15, 2011 Draft)

Quick Start

Finagle is an asynchronous network stack for the JVM that you can use to build asynchronous Remote Procedure Call (RPC) clients and servers in Java, Scala, or any JVM-hosted language. Finagle provides a rich set of tools that are protocol independent.

Finagle は 非同期な RPC クライアントとそのサーバを Java や Scala、その他の JVM 上の言語で書くためにつくられた JVM 向け非同期ネットワークスタックです。Finagle は特定のプロトコルに依存しない豊富なツール群を提供します。

The following Quick Start sections show how to implement simple RPC servers and clients in Scala and Java. The first example shows the creation a simple HTTP server and corresponding client. The second example shows the creation of a Thrift server and client. You can use these examples to get started quickly and have something that works in just a few lines of code. For a more detailed description of Finagle and its features, start with Finagle Overview and come back to Quick Start later.

以下のクイックスタートの節ではシンプルな RPC サーバとクライアントを Scala と Java で実装する方法を説明します。最初の例は、シンプルな HTTP サーバとそれに対応するクライアントです。二つ目の例は Thrift サーバとそのクライアントです。これらの例は少ない行数のコードでささっと何か動くものをつくるのに流用できるでしょう。Finagle に関するより詳細な説明やその機能が知りたい場合は Finagle Overview から読み始めて、またこのクイックスタートに後で戻ってきてください。

Note: The examples in this section include both Scala and Java implementations. Other sections show only Scala examples. For more information about Java, see Java Design Patterns for Finagle.

この節での例は Scala と Java の両方の実装を含んでいます。他の節では Scala だけの例を示しています。Java に関する情報がもっと欲しければ Java Design Patterns for Finagle をご覧ください。

Top

Simple HTTP Server

Consider a very simple implementation of an HTTP server and client in which clients make HTTP GET requests and the server responds to each one with an HTTP 200 OK response.

クライアントが HTTP GET リクエストを投げて、サーバが 200 OK で応答するだけの、とても単純なHTTP サーバ・クライアントの実装を考えてみましょう。

The following server, which is shown in both Scala and Java, responds to a client's HTTP request with an HTTP 200 OK response:

以下にある Scala と Java 両方で書かれたサーバの例はクライアントからの HTTP リクエストに対して 200 OK で応答します。

Scala HTTP Server Implementation
val service: Service[HttpRequest, HttpResponse] = new Service[HttpRequest, HttpResponse] { // 1
  def apply(request: HttpRequest) = Future(new DefaultHttpResponse(HTTP_1_1, OK))          // 2
}

val address: SocketAddress = new InetSocketAddress(10000)                                  // 3

val server: Server[HttpRequest, HttpResponse] = ServerBuilder()                            // 4
  .codec(Http)
  .bindTo(address)
  .name("HttpServer")
  .build(service)
Java HTTP Server Implementation
Service<HttpRequest, HttpResponse> service = new Service<HttpRequest, HttpResponse>() {    // 1
  public Future<HttpResponse> apply(HttpRequest request) {
    return Future.value(                                                                   // 2
            new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK));
  }
};

ServerBuilder.safeBuild(service, ServerBuilder.get()                                       // 4
  .codec(Http.get())
  .name("HttpServer")
  .bindTo(new InetSocketAddress("localhost", 10000)));                                     // 3
HTTP Server Code Annotations
  1. Create a new Service that handles HTTP requests and responses.
  2. For each request, respond asynchronously with an HTTP 200 OK response. A Future instance represents an asynchronous operation that may be performed later.
  3. Specify the socket addresses on which your server responds; in this case, on port 10000 of localhost.
  4. Build a server that responds to HTTP requests on the socket and associate it with your service. In this case, the Server builder specifies
  • an HTTP codec, which ensures that only valid HTTP requests are received by the server
  • the host socket that listens for requests
  • the association between the server and the service, which is specified by .build in Scala and the first argument to safeBuild in Java
  • the name of the service
  • HTTP リクエストとレスポンスをハンドルする新しいサービスをつくります
  • 各リクエストに対して非同期に 200 OK で応答します。Future のインスタンスは非同期な処理(少し遅れて実行されるかもしれない)であることを表わしています。
  • サーバが応答するソケットアドレスを指定します。今回のケースでは localhost の 1000 番ポートです。
  • そのソケット(アドレス・ポート)において HTTP リクエストに応答するサーバを生成し、それをサービスに関連づけます。今回のケースでは、Server builder が以下を規定します。
  • HTTP コーデック(有効な HTTP リクエストのみがサーバによって受け付けられることを保証する)
  • 指定されたソケットでリクエストを待ち受ける
  • サーバとサービスの関連づけ(Scala では #buildの Java では #safeBuild の第一引数としてサービスを渡す)
  • サービスの名前

Note: For more information about the Java implementation, see Java Design Patterns for Finagle.

Java での実装に関するより詳細な情報は Java Design Patterns for Finagle をご覧ください。

Top

Simple HTTP Client

The client, which is shown in both Scala and Java, connects to the server, and issues a simple HTTP GET request:

Scala と Java 両方で書かれたクライアントです。サーバに接続し、単純な HTTP GET リクエストを発行します。

Scala HTTP Client Implementation
val client: Service[HttpRequest, HttpResponse] = ClientBuilder()                           // 1
  .codec(Http)
  .hosts(address)
  .hostConnectionLimit(1)
  .build()

// Issue a request, get a response:
val request: HttpRequest = new DefaultHttpRequest(HTTP_1_1, GET, "/")                      // 2
val responseFuture: Future[HttpResponse] = client(request)                                 // 3
  onSuccess { response => println("Received response: " + response)                        // 4
      }
Java HTTP Client Implementation
Service<HttpRequest, HttpResponse> client = ClientBuilder.safeBuild(ClientBuilder.get()    // 1
  .codec(Http.get())
  .hosts("localhost:10000")
  .hostConnectionLimit(1));

// Issue a request, get a response:
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET, "/");   // 2
client.apply(request).addEventListener(new FutureEventListener<HttpResponse>() {           // 3
  public void onSuccess(HttpResponse response) {                                           // 4
    System.out.println("received response: " + response);
  }
  public void onFailure(Throwable cause) {
    System.out.println("failed with cause: " + cause);
  }
});
HTTP Client Code Annotations
  1. Build a client that sends an HTTP request to the host identified by its socket address. In this case, the Client builder specifies
  • an HTTP request filter, which ensures that only valid HTTP requests are sent to the server
  • a list of the server's hosts that can process requests
  • maximum number of connections from the client to the host
  • to build this client service
  1. Create an HTTP GET request.
  2. Make the request to the host identified in your client.
  3. Specify a callback, onSuccess, that Finagle executes when the response arrives.
  • クライアントを生成し ソケットアドレスで指定されたホストに HTTP リクエストを送信します。今回のケースでは、ClientBuilder は以下を規定します。
  • HTTP リクエストフィルター(有効な HTTP リクエストだけをサーバに送信することを保証する)
  • リクエストを送ることができるサーバホストの一覧
  • このクライアントからサーバホストへの最大(同時)接続数
  • クライアントサービスを生成
  • HTTP GET リクエストを生成します。
  • クライアントによって指定されたホストにリクエストを送信します。
  • 応答が届いたときに Finagle によって実行される onSuccess コールバック処理を指定します。

Note: Although the example shows building the client and execution of the built client on the same thread, you should build your clients only once and execute them separately. There is no requirement to maintain a 1:1 relationship between building a client and executing a client.

この例ではクライアントの生成とクライアントによる処理の実行を同じスレッドでやっていますが、クライアントは一度だけ生成し、各リクエストの実行は別で行われるべきです。クライアントの生成とクライアントの実行は 1対1 の関係を守らなければならないという条件は特にありません。

Top

Simple Client and Server for Thrift

Apache Thrift is a binary communication protocol that defines available methods using an interface definition language (IDL). Consider the following Thrift IDL definition for a Hello service that defines only one method, hi:

Apache Thrift は IDL(Interface Definition Language)を用いて利用可能なメソッドを定義するバイナリ転送プロトコルです。hi という一つだけのメソッドを持つ Hello サービスについて、以下のような IDL 定義を考えてみましょう。

service Hello {
  string hi();
}

Simple Thrift Server

In this Finagle example, the ThriftServer object implements the Hello service defined using the Thrift IDL.

この Finagle のサンプルでは、 ThriftServer オブジェクトは Thrift IDL を使って定義された Hello サービスを実行します。

Scala Thrift Server Implementation
object ThriftServer {
  def main(args: Array[String]) {
    // Implement the Thrift Interface
    val processor = new Hello.ServiceIface {                                 // 1
    def hi() = Future.value("hi")                                            // 2
  }

  val service = new Hello.Service(processor, new TBinaryProtocol.Factory())  // 3

  val server: Server = ServerBuilder()                                       // 4
    .name("HelloService")
    .bindTo(new InetSocketAddress(8080))
    .codec(ThriftServerFramedCodec())
    .build(service)
  }
}
Java Thrift Server Implementation
Hello.ServiceIface processor = new Hello.ServiceIface() {                    // 1
public Future<String> hi() {                                                 // 2
  return Future.value("hi");
  }
}

ServerBuilder.safeBuild(                                                     // 4
  new Hello.Service(processor, new TBinaryProtocol.Factory()),               // 3
  ServerBuilder.get()
    .name("HelloService")
    .codec(ThriftServerFramedCodec.get())
 // .codec(ThriftServerFramedCodecFactory$.MODULE$) previously
    .bindTo(new InetSocketAddress(8080)));
Thrift Server Code Annotations
  1. Create a Thrift processor that implements the Thrift service interface, which is Hello in this example.
  2. Implement the service interface. In this case, the only method in the interface is hi, which only returns the string "hi". The returned value must be a Future to conform the signature of a Finagle Service. (In a more robust example, the Thrift service might perform asynchronous communication.)
  3. Create an adapter from the Thrift processor to a Finagle service. In this case, the Hello Thrift service uses TBinaryProtocol as the Thrift protocol.
  4. Build a server that responds to Thrift requests on the socket and associate it with your service. In this case, the Server builder specifies
  • the name of the service
  • the host addresses that can receive requests
  • the Finagle-provided ThriftServerFramedCodec codec, which ensures that only valid Thrift requests are received by the server
  • the association between the server and the service
  • Thrift サービスインタフェースを実装した Thrift プロセッサをつくります。今回の例では Hello のことです。
  • サービスインタフェースを実行します。今回のケースでは、インタフェースに定義されたメソッドは "hi" という文字列を返すだけの hi というメソッドのみです。戻り値は Finagle の Service のシグニチャに従うために Future 型の値でなければなりません。(もっとちゃんとしたものでは Thrift サービスは非同期通信を実行するかもしれません)
  • Thrift プロセッサから Finagle サービスへのアダプタをつくります。今回の場合は Hello Thrift サービスは TBinaryProtocol を Thrift プロトコルとして使用します。
  • 指定されたソケットで Thrift リクエストに応答するサーバを生成し、サービスに関連づけます。今回の場合は ServerBuilder は以下を規定します。
  • サービスの名前
  • リクエストを受け付けるソケットアドレス
  • Finagle が提供する ThriftServerFramedCodec(サーバが有効な Thrift リクエストだけを受け付けることを保証する)
  • サーバとサービスの関連付け

Simple Thrift Client

In this Finagle example, the ThriftClient object creates a Finagle client that executes the methods defined in the Hello Thrift service.

この Finagle サンプルでは、ThriftClient オブジェクトは Finagle クライアントを生成し、 Hello Thrift サービスに定義されたメソッドを実行します。

Scala Thrift Client Implementation
object ThriftClient {
  def main(args: Array[String]) {
    // Create a raw Thrift client service. This implements the
    // ThriftClientRequest => Future[Array[Byte]] interface.
    val service: Service[ThriftClientRequest, Array[Byte]] = ClientBuilder()               // 1
      .hosts(new InetSocketAddress(8080))
      .codec(ThriftClientFramedCodec())
      .hostConnectionLimit(1)
      .build()

    // Wrap the raw Thrift service in a Client decorator. The client provides
    // a convenient procedural interface for accessing the Thrift server.
    val client = new Hello.ServiceToClient(service, new TBinaryProtocol.Factory())         // 2

    client.hi() onSuccess { response =>                                                    // 3
      println("Received response: " + response)
    } ensure {
      service.release()                                                                    // 4
    }
  }
}
Java Thrift Client Implementation
Service<ThriftClientRequest, byte[]> client = ClientBuilder.safeBuild(ClientBuilder.get()  // 1
  .hosts(new InetSocketAddress(8080))
  .codec(new ThriftClientFramedCodecFactory())
  .hostConnectionLimit(1));

Hello.ServiceIface client =
  new Hello.ServiceToClient(client, new TBinaryProtocol.Factory());                        // 2

client.hi().addEventListener(new FutureEventListener<String>() {
  public void onSuccess(String s) {                                                        // 3
    System.out.println(s);
  }

  public void onFailure(Throwable t) {
    System.out.println("Exception! ", t.toString());
  }
});
Thrift Client Code Annotation
  1. Build a client that sends a Thrift protocol-based request to the host identified by its socket address. In this case, the Client builder specifies - the host addresses that can receive requests - the Finagle-provided ThriftServerFramedCodec codec, which ensures that only valid Thrift requests are received by the server - to build this client service
  2. Make a remote procedure call to the Hello Thrift service's Hi method. This returns a Future that represents the eventual arrival of a response.
  3. When the response arrives, the onSuccess callback executes to print the result.
  4. Release resources acquired by the client.
  • ソケットアドレスによって指定されたThrift プロトコルベースのリクエストを送信するクライアントを生成します。今回のケースでは ClientBuilder は以下を規定します。
  • リクエストを受け付けるホストアドレス
  • Finagle が提供する ThriftServerFramedCodec(有効な Thrift リクエストだけがサーバによって受け付けられることを保証する)
  • クライアントサービスの生成
  • Hello Thrift サービスの hi メソッドを呼び出す RPC を生成します。この呼び出しは最終的にはレスポンスが届くということを意味する Future を返します。
  • レスポンスが届いたら onSuccess コールバックが実行され、結果が出力されます。
  • クライアントによって確保されたリソースが解放されます。

Top

Finagle Overview

Use the Finagle library to implement asynchronous Remote Procedure Call (RPC) clients and servers. Finagle is flexible enough to support a variety of RPC styles, including request-response, streaming, and pipelining; for example, HTTP pipelining and Redis pipelining. It also makes it easy to work with stateful RPC styles; for example, RPCs that require authentication and those that support transactions.

Finagle ライブラリは、非同期な RPC(Remote Procedure Call)のクライアントとサーバを実装するために利用できます。Finagle はリクエスト・レスポンス方式、ストリーミング方式、パイプライン方式といった様々な RPC 方式に柔軟に対応することができます。例えば HTTP でのパイプライン方式や Redis を使ったパイプライン方式などです。またステートフルな RPC 方式にも簡単に対応することができます。例えば、認証やトランザクションのサポートなどです。

Top

Client Features

  • Connection Pooling
  • Load Balancing
  • Failure Detection
  • Failover/Retry
  • Distributed Tracing (a la Dapper)
  • Service Discovery (e.g., via Zookeeper)
  • Rich Statistics
  • Native OpenSSL Bindings
  • コネクションプール
  • ロードバランシング
  • 障害検知
  • フェイルオーバー/リトライ機構
  • Dapper による分散トレース
  • ZooKeeper によるサービスディスカバリ
  • 豊富な統計
  • OpenSSL 連携

Top

Server Features

  • Backpressure (to defend against abusive clients)
  • Service Registration (e.g., via Zookeeper)
  • Distributed Tracing
  • Native OpenSSL bindings
  • 不正なクライアントを防御する背圧制御
  • ZooKeeper によるサービスレジストレーション
  • 分散トレース
  • OpenSSL 連携

Top

Supported Protocols

  • HTTP
  • HTTP streaming (Comet)
  • Thrift
  • Memcached/Kestrel
  • More to come!

Top

Architecture

Finagle extends the stream-oriented Netty model to provide asynchronous requests and responses for remote procedure calls (RPC). Internally, Finagle manages a service stack to track outstanding requests, responses, and the events related to them. Finagle uses a Netty pipeline to manage connections between the streams underlying request and response messages. The following diagram shows the relationship between your RPC client or server, Finagle, Netty, and Java libraries:

Finagle は、RPC での非同期リクエスト・レスポンスを提供するために、ストリーム指向な Netty のモデルを拡張しています。Finagle は内部的に Finagle は未処理のリクエスト、レスポンスと関連したイベントを監視するためのサービススタックを管理しています。Finagle はリクエストやレスポンスのメッセージが内在するストリームのつながりを管理するために Netty のパイプラインを使用します。以下の図はあなたがつくった RPC クライアントやサーバと Finagle、Netty と Java ライブラリの関係性を示しています。

Relationship between your RPC client or server, Finagle, Netty, and Java Libraries (doc/FinagleRelationship.png)

Finagle manages a Netty pipeline for servers built on Finagle RPC services. Netty itself is built on the Java NIO library, which supports asynchronous IO. While an understanding of Netty or NIO might be useful, you can use Finagle without this background information.

Finagle は Finagle RPC サーバのために Netty パイプラインを管理します。Netty 自体は Java の NIO ライブラリ(非同期 IO をサポートする)を利用しています。Netty や NIO を理解することは有用かもしれませんが、Finagle はこれらの予備知識がなくても使うことができます。

Finagle objects are the building blocks of RPC clients and servers:

  • Future objects enable asynchronous operations required by a service
  • Service objects perform the work associated with a remote procedure call
  • Filter objects enable you to transform data or act on messages before or after the data or messages are processed by a service
  • Codec objects decode messages in a specific protocol before they are handled by a service and encode messages before they are transported to a client or server.
  • Future オブジェクトは Service によって必要とされる非同期な処理を可能にします
  • Service オブジェクトは RPC に関連する仕事をします
  • Filter オブジェクトはデータを変換したり、Service によってメッセージが処理される前後にメッセージに対して何か作用をもたらすことを可能にします
  • Codec オブジェクトは Service によって処理される前にメッセージを指定されたプロトコルで複合して、サーバからクライアントに送信される前に符号化します

You combine these objects to create:

Finagle provides a ServerBuilder and a ClientBuilder object, which enable you to configure servers and clients, respectively.

Finagle は サーバやクライアントを構成するためにそれぞれ ServerBuilder や ClientBuilder オブジェクトを提供しています。

Top

Future Objects

In Finagle, Future objects are the unifying abstraction for all asynchronous computation. A Future represents a computation that has not yet completed, which can either succeed or fail. The two most basic ways to use a Future are to

Finagle では Future オブジェクトは統一的にすべての非同期な計算処理を抽象化したものです。Future は(それが最終的に成功するにしろ失敗するにしろ)まだ終わっていない計算処理であることを意味します。Future を使うには二つの最も基本的な方法があります。

  • block and wait for the computation to return
  • register a callback to be invoked when the computation eventually succeeds or fails
  • ブロックして計算が終わって結果が返されるのを待つ
  • 最終的に成功または失敗したら実行されるコールバック処理を登録しておく

For more information about Future objects, see Using Future Objects.

Future に関するより詳細な情報は Using Future Objects をご覧ください。

Top

Service Objects

A Service is simply a function that receives a request and returns a Future object as a response. You extend the abstract Service class to implement your service; specifically, you must define an apply method that transforms the request into the future response.

Service はリクエストを受け取って Future をレスポンスとして返すだけのシンプルな関数です。abstract な Service クラスを継承して Service を実装します。具体的にはリクエストを Future なレスポンスに変換する apply メソッドを定義する必要があります。

Top

Filter Objects

It is useful to isolate distinct phases of your application into a pipeline. For example, you may need to handle exceptions, authorization, and other phases before your service responds to a request. A Filter provides an easy way to decouple the protocol handling code from the implementation of the business rules. A Filter wraps a Service and, potentially, converts the input and output types of the service to other types. For an example of a filter, see Creating Filters to Transform Requests and Responses.

Filter はアプリケーションの明確なフェーズをパイプラインに分離するのに役立ちます。たとえば、例外をハンドリングしたい、認証をかけたい、サービスがリクエストに対して応答する前のあらゆるフェーズが必要となるかもしれません。Filter はプロトコルをハンドリングするコードを業務的なルールから分断する簡単な方法を提供します。Filter は Service をラップして潜在的にサービスの入力や出力の型を変換しうるものです。Filter の例は Creating Filters to Transform Requests and Responses をご覧ください。

A SimpleFilter is a kind of Filter that does not convert the request and response types. For an example of a simple filter, see Creating Filters.

SimpleFilter はリクエストやレスポンスの型を変換しない Filter の一種です。SimpleFilter の例は Creating Filters をご覧ください。

Top

Codec Objects

A Codec object encodes and decodes wire protocols, such as HTTP. You can use Finagle-provided Codec objects for encoding and decoding the Thrift, HTTP, memcache, Kestrel, HTTP chunked streaming (ala Twitter Streaming) protocols. You can also extend the CodecFactory class to implement encoding and decoding of other protocols.

Codec オブジェクトはたとえば HTTP のようなプロトコルを符号化、複合化するものです。Finagle が提供している Thirft、HTTP、Memcache、Kestrel、HTTP chunked streaming(Twitter ストリーミングのような) といったプロトコルを符号化/複合化するための Codec オブジェクトを使うことができます。CodecFactory クラスを拡張してその他のプロトコルを符号化/複合化することもできます。

Top

Servers

In Finagle, RPC servers are built out of a Service and zero or more Filter objects. You apply filters to the service request after which you execute the service itself:

Finagle では RPC サーバは一つの Service と 0 個以上の Filter オブジェクトから構成されます。リクエストに対して Service それ自体を実行する Filter 群を適用します。

Relationship between a service and filters (doc/Filters.png)

Typically, you use a ServerBuilder to create your server. A ServerBuilder enables you to specify the following general attributes:

通常は ServerBuilder を使ってサーバを生成します。ServerBuilder は以下のような一般的な属性を指定することができます:

Attribute Description Default Value
codec Object to handle encoding and decoding of the service's request/response protocol None
statsReceiver Statistics receiver object, which enables logging of important events and statistics None
name Name of the service None
bindTo The IP host:port pairs on which to listen for requests; localhost is assumed if the host is not specified None
logger Logger object None

You can specify the following attributes to handle fault tolerance and manage clients:

Attribute Description Default Value
maxConcurrentRequests Maximum number of requests that can be handled concurrently by the server None
hostConnectionMaxIdleTime Maximum time that this server can be idle before the connection is closed None
hostConnectionMaxLifeTime Maximum time that this server can be connected before the connection is closed None
requestTimeout Maximum time to complete a request None
readTimeout Maximum time to wait for the first byte to be read None
writeCompletionTimeout Maximum time to wait for notification of write completion from a client None

You can specify the following attributes to manage TCP connections:

Attribute Description Default Value
sendBufferSize Requested TCP buffer size for responses None
recvBufferSize Actual TCP buffer size for requests None

You can also specify these attributes:

Attribute Description Default Value
tls The kind of transport layer security None
channelFactory Channel service factory object None
traceReceiver Trace receiver object new NullTraceReceiver object

Once you have defined your Service, it can be bound to an IP socket address, thus becoming an RPC server.

Top

Clients

Finagle makes it easy to build RPC clients with connection pooling, load balancing, logging, and statistics reporting. The balancing strategy is to pick the endpoint with the least number of outstanding requests, which is similar to least connections in other load balancers. The load-balancer deliberately introduces jitter to avoid synchronicity (and thundering herds) in a distributed system.

Finagle では、コネクションプーリング、ロードバランシング、ログ出力や統計結果のレポートといった機能を持つ RPC クライアントの作成が簡単にできます。バランシングストラテジーは、ロードバランサが最もコネクションが少ないところを選ぶのと似た感じで、未処理のリクエストの数が最も少ないエンドポイントを選ぶようになっています。分散システムにおいて、ロードバランサは同時発生をさけるために意図的にジッターを取り入れます。

Your code should separate building the client from invocation of the client. A client, once built, can be used with lazy binding, saving the resources required to build a client. Note: The examples, which show the creation of the client and its first execution together, represent the first-execution scenario. Typically, subsequent execution of the client does not require rebuilding.

あなたの書くコードはクライアントの生成と起動を分離するべきです。クライアントは一度生成したものを再利用してクライアントを生成するためのリソースを節約することができます。(注)クライアントの生成とその初回起動を一緒に説明する例は初回実行のシナリオを表しています。通常、後続の処理ではクライアントを再生成する必要はありません。

Finagle will retry the request in the event of an error, up to the number of times specified; however, Finagle does not assume your RPC service is Idempotent. Retries occur only when the request is known to be idempotent, such as in the event of TCP-related WriteException errors, for which the RPC has not been transmitted to the remote server.

Finagle は指定された回数までエラーイベント時にリクエストをリトライします。Finagle はあなたの RPC サービスが冪等(ある操作を1回行っても複数回行っても結果が同じであること)であるとは仮定しません。リトライはリクエストが冪等であるとわかっている場合のみ発生します。たとえば TCP に関係した「WriteException」のような RPC がリモートサーバに届いていないようなエラーイベントです。

A robust way to use RPC clients is to have an upper-bound on how long to wait for a response to arrive. With Future objects, you can

RPC クライアントがレスポンス到達をどれくらい待つかの上限を設定するとより強力です。Future オブジェクトを使ってこのように:

  • block, waiting for a response to arrive and throw an exception if it does not arrive in time.
  • register a callback to handle the result if it arrives in time, and register another callback to invoke if the result does not arrive in time
  • ブロックしてレスポンスが届くのを待ち、もし時間内に届かなかったら例外を throw する
  • 時間内にレスポンスが届いたらその結果を処理するコールバックを登録し、かつ時間内に届かなかった場合に実行される別のコールバックも登録する

A client is a Service and can be wrapped by Filter objects. Typically, you call ClientBuilder to create your client service. ClientBuilder enables you to specify the following general attributes:

クライアントは Service なので Filter オブエジェクト群によってラップすることができます。通常は ClientBuilder を使ってクライアントの Service を生成します。ClientBuilder は以下のような一般的な属性を指定することができます:

Attribute Description Default Value
name Name of the service None
codec Object to handle encoding and decoding of the service's request/response protocol None
statsReceiver Statistics receiver object, which enables logging of important events and statistics None
loadStatistics How often to load statistics from the server (60, 10.seconds)
logger A Logger object with which to log Finagle messages None
retries Number of retries per request (only applies to recoverable errors) None

You can specify the following attributes to manage the host connection:

Attribute Description Default Value
connectionTimeout Time allowed to establish a connection 10.milliseconds
requestTimeout Request timeout None, meaning it waits forever
hostConnectionLimit Number of connections allowed from this client to the host None
hostConnectionCoresize Host connection's cache allocation None
hostConnectionIdleTime None
hostConnectionMaxWaiters The maximum number of queued requests awaiting a connection None
hostConnectionMaxIdleTime Maximum time that the client can be idle until the connection is closed None
hostConnectionMaxLifeTime Maximum time that client can be connected before the connection is closed None

You can specify the following attributes to manage TCP connections:

Attribute Description Default Value
sendBufferSize Requested TCP buffer size for responses None
recvBufferSize Actual TCP buffer size for requests None

You can also specify these attributes:

Attribute Description Default Value
cluster The cluster connections associated with the client None
channelFactory Channel factory associated with this client None
tls The kind of transport layer security None

If you are using stateful protocols, such as those used for transaction processing or authentication, you should call buildFactory, which creates a ServiceFactory to support stateful connections.

もしトランザクション処理や認証のようなステートフルなプロトコルを用いる場合、 ステートフルなコネクションをサポートした ServiceFactory を生成する BuildFactory を呼び出します。

Top

Threading Model

The Finagle threading model requires that you avoid blocking operations in the Finagle event loop. Finagle-provided methods do not block; however, you could inadvertently implement a client, service or a Future callback that blocks.

Finagle のスレッドモデルでは Finagle のイベントループの中でブロックする処理をしないようにする必要があります。Finagle が提供するメソッドはブロックしませんが、あなたがうっかりブロックするようなクライアント、Service や Future のコールバックを実装することは考えられます。

Blocking events include but are not limited to

  • network calls
  • system calls
  • database calls

Note: You do not need to be concerned with long-running or CPU intensive operations if they do not block. Examples of these operations include image processing operations, public key cryptography, or anything that might take a non-trivial amount of clock time to perform. Only operations that block in Finagle are of concern. Because Finagle and its event loop use a relatively low number of threads, blocked threads can cause performance issues.

(注)ブロックしていなければ、長時間実行される処理やCPU ヘビーな処理について気にかける必要はありません。こういった処理には、画像処理や公開鍵の暗号化、あるいは少なくない CPU クロック時間を要するあらゆる処理を含みます。Finagle ではブロックするような処理だけを気にする必要があります。Finagle とそのイベントループは比較的少ないスレッドを用いているため、ブロックされたスレッドはパフォーマンスの問題を引き起こす場合があります。

Consider the following diagram, which shows how a client uses the Finagle event loop:

クライアントがどのように Finagle を使っているかを説明する以下の図をみてみましょう。

Relationship between your threads and Finagle (doc/ThreadEx.png)

Your threads, which are shown on the left, are allowed to block. When you call a Finagle method or Finagle calls a method for you, it dispatches execution of these methods to its internal threads. Thus, the Finagle event loop and its threads cannot block without degrading the performance of other clients and servers that use the same Finagle instance.

図の左側にあるスレッドではブロックすることが許されます。Finagle のメソッドを呼び出すときや Finagle があなたのためにあるメソッドを呼び出すときに、それらのメソッドの実行を内部スレッドに送ります。そのため、Finagle イベントループとそのスレッド群をブロックしてしまうと、同じ Finagle インスタンスを使うクライアントとサーバにひどいパフォーマンス劣化がおこります。

In complex RPC operations, it may be necessary to perform blocking operations. In these cases, you must set up your own thread pool and use Future or FuturePool objects to execute the blocking operation on your own thread. Consider the following diagram:

複雑な RPC 処理では、ブロックする処理を行うことが必要になるかもしれません。こういったケースでは、自前でスレッドプールをセットアップして Future や FuturePool オブジェクトを使って、自前のスレッドでブロッキング処理を実行しなければなりません。以下の図をみてみましょう:

Handling operations that block (doc/ThreadExNonBlockingServer.png)

In this example, you can use a FuturePool object to provide threads for blocking operations outside of Finagle. Finagle can then dispatch the blocking operation to your thread. For more information about FuturePool objects, see Using Future Pools.

この例では Finagle の外側でブロッキング処理を実行するスレッド群を提供する FuturePool オブジェクトを使うことができます。Finagle はブロッキング処理をあなたが管理するスレッドにふりわけることができます。FuturePool に関するより詳細な情報については Using Future Pools をご覧ください。

Top

Starting and Stopping Servers

A server automatically starts when you call build on the server after assigning the IP address on which it runs. To stop a server, call its close method. The server will immediately stop accepting requests; however, the server will continue to process outstanding requests until all have been handled or until a specific duration has elapsed. You specify the duration when you call close. In this way, the server is allowed to drain out outstanding requests but will not run indefinitely. You are responsible for releasing all resources when the server is no longer needed.

IP アドレスを割り当てた後 build メソッドを呼び出すと、サーバは自動的にスタートします。サーバを停止するためには close メソッドを呼び出します。サーバはすぐにリクエストを受け付けるのをやめますが、未処理のリクエストがあれば、それがすべて終わるか、指定された時間が経過するまで処理は継続します。close を呼び出すときにその時間を指定することができます。このやり方(=一定時間が経過したら停止すること)だとサーバは未処理のリクエストを失うことがありえますが、それらのリクエストが実行されることはありません。利用者はサーバがもはや必要でないという場合はすべてのリソースを解放する必要があります。

Top

Finagle Projects and Packages

The Core project contains the execution framework, Finagle classes, and supporting classes, whose objects are only of use within Finagle. The Core project includes the following packages:

Core プロジェクトは実行フレームワーク、Finagle クラス群、サポート用のクラス群(Finagle の中だけで利用されるもの)を含んでいます。Core プロジェクトは以下のパッケージを含みます:

  • builder - contains ClientBuilder, ServerBuilder
  • channel
  • http
  • loadbalancer
  • pool
  • service
  • stats
  • tracing
  • util

It also contains packages to support remote procedure calls over Kestrel, Thrift, streams, clusters, and provides statistics collection (Ostrich).

Kestrel、Thrift、ストリーミング、クラスター構成や統計データの集計(OStrich)を用いた RPC をサポートするパッケージもあります。

The Util project contains classes, such as Future, which are both generally useful and specifically useful to Finagle.

Uitl プロジェクトは Future のような汎用的にも有用であり、Fingale にとっても有用なクラスを含みます。

Top

Using Future Objects

In the simplest case, you can use Future to block for a request to complete. Consider an example that blocks for an HTTP GET request:

もっとも単純なケースだと Future をリクエストをリクエストが終わるまでブロックするために使うことができます。HTTP GET リクエストを(終了まで)ブロックする例です。

    // Issue a request, get a response:
    val request: HttpRequest = new DefaultHttpRequest(HTTP_1_1, GET, "/")
    val responseFuture: Future[HttpResponse] = client(request)

In this example, a client issuing the request will wait forever for a response unless you specified a value for the requestTimeout attribute when you built the client.

この例ではクライアントはリクエストを発行してクライアント生成時に requestTimeout 属性で指定された時間が経過しない限り、レスポンスが届くまで永遠に待ち続けます。

Consider another example:

別の例を考えてみると

    val responseFuture: Future[String] = executor.schedule(job)

In this example, the value of responseFuture is not available until after the scheduled job has finished executing and the caller will block until responseFuture has a value.

この例では responseFuture はスケジューリングされたジョブの実行が終了するまで利用できないので、呼び出し側は responseFuture が値を返すまでブロックすることになるでしょう。

Note: For examples of using Finagle Future objects in Java, see Using Future Objects With Java.

Finagle オブジェクトを Java で使った例については Using Future Objects With Java をご覧ください。

Top

Future Callbacks

In cases where you want to continue execution immediately, you can specify a callback. The callback is identified by the onSuccess keyword:

すぐに実行を続けたいという場合、コールバックを指定できます。 コールバックは onSucess キーワードで識別されます。

val request: HttpRequest = new DefaultHttpRequest(HTTP_1_1, GET, "/")
val responseFuture: Future[HttpResponse] = client(request)
responseFuture onSuccess { responseFuture =>
  println(responseFuture)
}

Top

Future Timeouts

In cases where you want to continue execution after some amount of elapsed time, you can specify the length of time to wait in the Future object. The following example waits 1 second before displaying the value of the response:

一定の時間が経過したら処理を継続したいという場合、Future オブジェクトに wait 時間の長さを指定することができます。以下の例ではレスポンスの値を表示するまで 1 秒待ちます。

val request: HttpRequest = new DefaultHttpRequest(HTTP_1_1, GET, "/")
val responseFuture: Future[HttpResponse] = client(request)
println(responseFuture(1.second))

In the above example, you do not know whether the response timed out before the request was satisfied. To determine what kind of response you actually received, you can provide two callbacks, one to handle onSuccess conditions and one for onFailure conditions. You use the within method of Future to specify how long to wait for the response. Finagle also creates a Timer thread on which to wait until one of the conditions are satisfied. Consider the following example:

上の例だとリクエストが処理される前にレスポンスがタイムアウトするかどうか知ることができません。実際にどのような種類のレスポンスを受け取ったかを特定するために、二つのコールバックを指定できます。一つは onSuccess でもう一つは onFailure の条件文です。Future の within メソッドでどれくらいの時間レスポンスを待つか指定することができます。Finagle は条件のうち一つが満たされるまで待つ Timer スレッドをつくることもできます。以下の例をみてみましょう。

import com.twitter.finagle.util.Timer._
...
val request: HttpRequest = new DefaultHttpRequest(HTTP_1_1, GET, "/")
val responseFuture: Future[HttpResponse] = client(request)
responseFuture.within(1.second) onSuccess { response =>
  println("responseFuture)
} onFailure {
  case e: TimeoutException => ...
}

If a timeout occurs, Finagle takes the onFailure path. You can use a TimeoutException object to display a message or take other actions.

タイムアウトが発生したら、Finagle は onFailure の経路を通ります。エラーメッセージを表示したり、何か別のことをするために TimeoutException オブジェクトを触ることができます。

Top

Future Exceptions

To set up an exception, specify the action in a try block and handle failures in a catch block. Consider an example that handles Future timeouts as an exception:

例外をセットアップするためには try ブロックの中に処理を置いて失敗を catch 節で処理します。以下のような Future のタイムアウトを例外として処理する例をみてみましょう。

val request: HttpRequest = new DefaultHttpRequest(HTTP_1_1, GET, "/")
val responseFuture: Future[HttpResponse] = client(request)
try {
  println(responseFuture(1.second))
} catch {
  case e: TimeoutException => ...
}

In this example, after 1 second, either the HTTP response is displayed or the TimeoutException is thrown.

この例では 1 秒後に HTTP レスポンスが表示されるか TimeoutException が throw されます。

Top

Promises

Promise is a subclass of Future. Although a Future can only be read, a Promise can be both read and written. Usually a producer makes a Promise and casts it to a Future before giving it to the consumer. The following example shows how this might be useful in the case where you intend to make a Future service but need to anticipate errors:

Promise は Future のサブクラスです。Future は読み込みだけができますが Promise は読み込みも書き込みも両方できます。通常、プロデューサーは Promise を作ってコンシューマに渡す前にそれを Future にキャストします。以下の例は Future サービスをつくるつもりで、しかしエラーを見込む必要がある場合にこれがどのように便利かを有用であるかを示しています。

def make() = {
...
val promise = new Promise[Service[Req, Rep]]
... {
  case Ok(myObject) =>
    ...
    promise() = myConfiguredObject
  case Error(cause) =>
    promise() = Throw(new ...Exception(cause))
  case Cancelled =>
    promise() = Throw(new WriteException(new ...Exception))
  }
  promise
}

You are discouraged from creating your own Promises. Instead, where possible, use Future combinators to compose actions (discussed next).

自前で Promise を生成することはお勧めできません。可能であれば、代わりにふるまいを合成する Future コンビネータを使ってください。

Top

Using Future map and flatMap Operations

In addition to waiting for results to return, Future can be transformed in interesting ways. For instance, it is possible to convert a Future[String] to a Future[Int] by using map:

返される結果を待つのに加えて Future は興味深いやり方で変換されることがあります。たとえば map を使って Future[String] を Future[Int] に変換することができます。

val stringFuture: Future[String] = Future("1")
val intFuture: Future[Int] = stringFuture map (_.toInt)

Similar to map, you can use flatMap to easily pipeline a sequence of Futures:

map と似たもので複数の Future のシーケンスを容易につなぎ合わせる flatMap を使うこともできます。

val authenticateUser: Future[User] = User.authenticate(email, password)
val lookupTweets: Future[Seq[Tweet]] = authenticateUser flatMap { user =>
  Tweet.findAllByUser(user)
}

In this example, Tweet.findAllByUser(user) is a function of type User => Future[Seq[Tweet]].

この例では Tweet.findAllByUser(user) は User => Future[Seq[Tweet]] という関数です。

Top

Using Future in Scatter/Gather Patterns

For scatter/gather patterns, the challenge is to issue a series of requests in parallel and wait for all of them to arrive. To wait for a sequence of Future objects to return, you can define a sequence to hold the objects and use the Future.collect method to wait for them, as follows:

scatter(まき散らす)/gather(収集する)パターンでの課題は、並行して一連のリクエストを発行し、そのすべてが届くまで待つことです。Future オブジェクトのシーケンスを待つために、オブジェクトを保持するシーケンスを定義して 以下のように Future.collect メソッドでそれらを待ちます。

val myFutures: Seq[Future[Int]] = ...
val waitTillAllComplete: Future[Seq[Int]] = Future.collect(myFutures)

A more complex variation of scatter/gather pattern is to perform a sequence of asynchronous operations and harvest only those that return within a certain time, ignoring those that don't return within the specified time. For example, you might want to issue a set of parallel requests to N partitions of a search index; those that don't return in time are assumed to be empty. The following example allows 1 second for the query to return:

scatter/gather パターンのより複雑なバリエーションとしては、非同期処理のシーケンスを実行して一定時間内に返された結果だけを収集する、というものがあります。指定された時間内に結果が返らなかった非同期処理は無視されます。例えば、n 個に分割された検索インデックスに対して平行リクエストのセットを発行したいという場合、時間内に結果を返さないものは(クエリにマッチする)検索結果がないとみなします。以下の例では 1 秒間クエリが返るのを待ちます。

import com.twitter.finagle.util.Timer._

val results: Seq[Future[Result]] = partitions.map { partition =>
  partition.get(query).within(1.second) handle {
    case _: TimeoutException => EmptyResult
  }
}
val allResults: Future[Seq[Result]] = Future.collect(timedResults)

allResults onSuccess { results =>
  println(results)
}

Top

Using Future Pools

A FuturePool object enables you to place a blocking operation on its own thread. In the following example, a service's apply method, which executes in the Finagle event loop, creates the FuturePool object and places the blocking operation on a thread associated with the FuturePool object. The apply method returns immediately without blocking.

FuturePool オブジェクトは自前のスレッドにブロッキング処理をやらせることができます。以下の例では Finagle のイベントループの中で実行される Service の apply メソッドが FuturePool オブジェクトを生成し、ブロッキング処理を FuturePool に関連づけられたスレッドで実行させます。apply メソッドはブロックすることなくすぐに結果を返します。

class ThriftFileReader extends Service[String, Array[Byte]] {
  val diskIoFuturePool = FuturePool(Executors.newFixedThreadPool(4))

  def apply(path: String) = {
    val blockingOperation = {
      scala.Source.fromFile(path) // potential to block
    }
    // give this blockingOperation to the future pool to execute
    diskIoFuturePool(blockingOperation)
    // returns immediately while the future pool executes the operation on a different thread
  }
}

Note: For an example implementation of a thread pool in Java, see Implementing a Pool for Blocking Operations in Java.

Java でのスレッドプールのサンプル実装については Implementing a Pool for Blocking Operations in Java をご覧ください。

Top

Creating a Service

The following example extends the Service class to respond to an HTTP request:

以下の例は Service クラスを継承し HTTP リクエストに応答します。

class Respond extends Service[HttpRequest, HttpResponse] {
  def apply(request: HttpRequest) = {
    val response = new DefaultHttpResponse(HTTP_1_1, OK)
    response.setContent(copiedBuffer(myContent, UTF_8))
    Future.value(response)
  }
}

Top

Creating Simple Filters

The following example extends the SimpleFilter class to throw an exception if the HTTP authorization header contains a different value than the specified string:

以下の例は SimpleFilter を継承し、もし HTTP Authorization ヘッダーが指定された文字列と違った値を含んでいたら例外を throw します。

class Authorize extends SimpleFilter[HttpRequest, HttpResponse] {
  def apply(request: HttpRequest, continue: Service[HttpRequest, HttpResponse]) = {
    if ("shared secret" == request.getHeader("Authorization")) {
      continue(request)
    } else {
      Future.exception(new IllegalArgumentException("You don't know the secret"))
    }
  }
}

The following example extends the SimpleFilterclass to set the HTTP response code if an error occurs and return the error and stack trace in the response:

以下の例は SimpleFilter クラスを継承し、もしエラーが発生したらHTTP レスポンスコードを設定し、エラー内容とスタックトレースをレスポンスメッセージに含めて返します。

class HandleExceptions extends SimpleFilter[HttpRequest, HttpResponse] {
  def apply(request: HttpRequest, service: Service[HttpRequest, HttpResponse]) = {
    service(request) handle { case error =>
      val statusCode = error match {
        case _: IllegalArgumentException =>
          FORBIDDEN
        case _ =>
          INTERNAL_SERVER_ERROR
        }

      val errorResponse = new DefaultHttpResponse(HTTP_1_1, statusCode)
      errorResponse.setContent(copiedBuffer(error.getStackTraceString, UTF_8))

      errorResponse
    }
  }
}

For an example implementation using a Filter object, see Creating Filters to Transform Requests and Responses.

Filter オブジェクトを使った実装例については Creating Filters to Transform Requests and Responses をご覧ください。

Top

Building a Robust Server

The following example encapsulates the filters and service in the previous examples and defines the execution order of the filters, followed by the service. The ServerBuilder object specifies the service that indicates the execution order along with the codec and IP address on which to bind the service:

以下の例はこれまでの例で出てきた Filter や Service を取り込んだもので、Filter の実行順序を定義しています。Filter の後に Service が続きます。ServerBuilder オブジェクトはサービスに結びつける Codec や IP アドレスとともに Service の実行順序についても指示します。

object HttpServer {
  class HandleExceptions extends SimpleFilter[HttpRequest, HttpResponse] {...}
  class Authorize extends SimpleFilter[HttpRequest, HttpResponse] {...}
  class Respond extends Service[HttpRequest, HttpResponse] {... }


  def main(args: Array[String]) {
    val handleExceptions = new HandleExceptions
    val authorize = new Authorize
    val respond = new Respond

  val myService: Service[HttpRequest, HttpResponse]
    = handleExceptions andThen authorize andThen respond

  val server: Server = ServerBuilder()
    .codec(Http)
    .bindTo(new InetSocketAddress(8080))
    .build(myService)
  }
}

In this example, the HandleExceptions filter is executed before the authorize filter. All filters are executed before the service. The server is robust not because of its complexity; rather, it is robust because it uses filters to remove issues before the service executes.

この例では HandleExceptions という Filter が authorize という Filter の前に実行されます。すべての Filter は Service の前に実行されます。サーバはその複雑さによってではなく Filter によって Service 実行の前の問題を取り除いているため強力になっています。

Top

Building a Robust Client

A robust client has little to do with the lines of code (SLOC) that goes into it; rather, the robustness depends on how you configure the client and the testing you put into it. Consider the following HTTP client:

クライアントは SLOC(コード行数)によってやれることが多くなるのではなく、その強力さはどのようにクライアントに設定をできるか、テストをどれだけできるかによって決まります。以下のような HTTP クライアントをみてみてください。

val client = ClientBuilder()
  .codec(Http)
  .hosts("localhost:10000,localhost:10001,localhost:10003")
  .hostConnectionLimit(1)             // max number of connections at a time to a host
  .connectionTimeout(1.second)        // max time to spend establishing a TCP connection
  .retries(2)                         // (1) per-request retries
  .reportTo(new OstrichStatsReceiver) // export host-level load data to ostrich
  .logger(Logger.getLogger("http"))
  .build()

The ClientBuilder object creates and configures a load balanced HTTP client that balances requests among 3 (local) endpoints. The Finagle balancing strategy is to pick the endpoint with the least number of outstanding requests, which is similar to a least connections strategy in other load balancers. The Finagle load balancer deliberately introduces jitter to avoid synchronicity (and thundering herds) in a distributed system. It also supports failover.

ClientBuilder オブジェクトはロードバランスされた HTTP クライアントを設定し、リクエストを 3 つの(ローカルな)エンドポイントに対して振り分けます。Finagle のバランシングストラテジーは最も未処理のリクエストが少ないエンドポイントを選ぶというものです。Finagle のロードバランサは分散されたシステムで同時発生を防ぐために意図的にジッターを取り入れます。また、フェイルオーバーもサポートされています。

The following examples show how to invoke this client from Scala and Java, respectively:

以下の例はこのクライアントを Scala と Java から起動するやり方をそれぞれ示すものです。

Scala Client Invocation
val request: HttpRequest = new DefaultHttpRequest(HTTP_1_1, Get, "/")
val futureResponse: Future[HttpResponse] = client(request)
Java Client Invocation
HttpRequest request = new DefaultHttpRequest(HTTP_1_1, Get, "/")
Future<HttpResponse> futureResponse = client.apply(request)

For information about using Future objects with Java, see Using Future Objects With Java.

Java における Future オブジェクトについてのより詳細な情報は Using Future Objects With Java をご覧ください。

Top

Creating Filters to Transform Requests and Responses

The following example extends the Filter class to authenticate requests. The request is transformed into an HTTP response before being handled by the AuthResult service. In this case, the RequireAuthentication filter does not transform the resulting HTTP response:

以下の例は Filter クラスを継承してリクエストに認証を行うものです。リクエストは AuthResult サービスに処理される前に HTTP レスポンスに変換されます。このケースでは RequireAuthentication という Filter は結果として返される HTTP レスポンスの変換を行いません。

class RequireAuthentication(val p: ...)
  extends Filter[Request, HttpResponse, AuthenticatedRequest, HttpResponse]
  {
    def apply(request: Request, service: Service[AuthenticatedRequest, HttpResponse]) = {
      p.authenticate(request) flatMap {
        case AuthResult(AuthResultCode.OK, Some(passport: OAuthPassport), _, _) =>
          service(AuthenticatedRequest(request, passport))
        case AuthResult(AuthResultCode.OK, Some(passport: SessionPassport), _, _) =>
          service(AuthenticatedRequest(request, passport))
        case ar: AuthResult =>
          Trace.record("Authentication failed with " + ar)
          Future.exception(new RequestUnauthenticated(ar.resultCode))
    }
  }
}

In this example, the flatMap object enables pipelining of the requests.

この例では flatMap がリクエストをパイプライン化することを可能にしています(?)。

Top

Using ServerSet Objects

finagle-serversets is an implementation of the Finagle Cluster interface using com.twitter.com.zookeeper ServerSets.

finagle-serversets は com.twitter.common.zookeeper.ServerSet を用いた Finagle Cluster インタフェースの実装です。

You can instantiate a ServerSet object as follows:

ServerSet を以下のようにしてインスタンス化できます。

val serverSet = new ServerSetImpl(zookeeperClient, "/twitter/services/...")
val cluster = new ZookeeperServerSetCluster(serverSet)

Servers join a cluster, as in the following example:

以下の例のようにして、サーバはクラスタに参加します。

val serviceAddress = new InetSocketAddress(...)
val server = ServerBuilder()
  .bindTo(serviceAddress)
  .build()

cluster.join(serviceAddress)

A client can access a cluster, as follows:

以下のようにしてクライアントはクラスターにアクセスします。

val client = ClientBuilder()
  .cluster(cluster)
  .hostConnectionLimit(1)
  .codec(new StringCodec)
  .build()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment