11

Netty, which is used within Finagle, uses a pipeline of "handlers" to sequentially process in and out bound data. Netty examples, and included libraries, show various handlers used for things such as authentication, protocol codecs, and the actual business logic of the service.

Finagle appears to take the handler concept, and instead directly offer API users codecs, filters, and services. While these have varying signatures, new users of Finagle are left with the tasks of deciding which to use in order to implement each portion of their overall server. Instead of merely deciding where to break the chain up into various Netty handlers, they now need to decide which portion should be part of a codec, versus any filters, versus the singular service at the end of the chain. In sum, although Finagle is a higher-level library than Netty, and should make the task of building the service easier, the API user may have more choices to make.

What are the key decision points, and pros/cons, for placing a particular portion of the processing stream into a codec vs. a filter vs. the singular service? If there is a possibility that the pipeline could be extended further, should the service logic be placed into a filter instead, with a "noop" service at the end of the pipeline? Given the flexibility in ordering filters (as handlers in the pipeline), versus the singular codec on one end and service on the other end, why shouldn't "everything" be a filter?

scaling_out
  • 1,103
  • 1
  • 10
  • 15

2 Answers2

18

Finagle and Netty are structured quite differently.

Services, Filters, and codecs are actually quite orthogonal concepts. Let me try & explain. As a user -- ie. not an implementor of a codec -- you should only need to know about services and filters.

First, a codec is responsible for turning a stream of bytes into a discrete requests or responses. For example, the HTTP codec reads the bytestream, and produces HttpRequest or HttpResponse objects.

A Service is an object that, given a request, produces a Future of a reply -- it’s a simple function (and indeed it extends Function). The interesting thing about services is that they are symmetric. A client uses a service, a server provides one. The important thing about services is that (1) they operate over discrete requests and responses, and (2) they match requests to responses - all of which is implied by its type. This is why we call finagle an “RPC” system - request/response pairs are the defining characteristic of RPCs.

So, we have Services, but it's useful and important to have modify Service behavior independently of the service itself. For example, we might want to provide timeout functionality, or retries. This is what Filters do. They provide a service independent method of modifying Service behavior. This enhanced modularity and reuse. For example, timeouts in finagle are implemented as a filter, and can be applied to any service.

You can find more details about services & filters in the Scala School.

*

So, let’s contrast this to Netty’s handlers. These are generic event handlers, that are also stackable. You can do many similar things with them, but the underlying model is a stream of events that are attached to a connection. This makes it more difficult to write generic modules (eg. to implement retries, timeouts, failure accrual, tracing, exception reporting, etc..) because you cannot make many assumptions about the pipeline you’re operating with.

Netty pipelines also conflate the protocol implementation with application handlers. Finagle cleanly separates the two, and modularity is enhanced because of it.

Netty is a wonderful set of abstractions, but for RPC servers, finagle offers greater modularity and composability.

*

Summarizing crudely you could say that Netty is “stream oriented” while finagle is “service oriented”. This is an important distinction, and it's what allows us to implement robust RPC services in a modular manner. For example, connection pooling and load balancing - crucially important to RPC clients - fall out naturally from the service model, but doesn’t fit in the stream model.

  • Oh, and I guess to more succinctly answer the question in your final paragraph: A Service exposes application behavior, and Filters are used to modify their behavior in a generic and modular way. So, for example you might have a Service that serves an HTTP endpoint, but a filter that converts exceptions into nice HTTP 500 messages. – marius a. eriksen Jul 21 '12 at 17:26
  • Thank you, Marius, for clearly elucidating what may be gained using Finagle instead of a stack of Netty handlers. – scaling_out Jul 22 '12 at 18:43
0

I don't think it should be a decision between codec or filter. Codecs would rather get wrapped in filters.

As for decision logic, where to place it, would depend on the decisions that has to be made. Business decisions should go with your business logic, while some decisions like routing, load balancing, certain types of access control, etc. could fit in well as a filter.

Services are typically sit at the end of the line, and Finagle with it's filters will get you there.

Don't know if this makes sense?

Just step away from the technical detail for a moment, and look at the logic. What should be responsible for what, and then get the technology to fit your design. Don't bend your design too much to fit the technology.

By the way, I've implemented a gateway server on top of Finagle, and I must say: It's a nice library to work with.

I don't know what you are trying to build, but have a look at possible alternatives also: Spray, Blueeyes, Unfiltered, Play-Mini, etc. It may help you get a better understanding of what goes where.

Jack
  • 16,506
  • 19
  • 100
  • 167
  • If you look at the source for Finagle's ServerBuilder class, you will see that the discrete steps are indeed implemented by adding more handlers to the pipeline. The order is fixed around various options (such as the stats receiver option). The gist of my question is that it may be both simpler for Finagle users to understand, as well as providing more flexibility, by just sticking with a single concept of filter (ie: Netty handler), and provide more examples of how to order them to get the results you want. The codec, stats option, ssl, and others are all handlers. – scaling_out Jul 19 '12 at 18:48
  • Standard setups/orders of handlers could easily be offered in the library, and users could build up their own with the "andThen" chains. This approach may shrink the cognitive load involved in learning Finagle, by reducing the amount of special concepts. Additionally, who can say that someone won't want to encode something, and then send the results to a different codec for further wrapping? The same goes for the Finagle service at the other end of the line. What happens when you want another service to come directly after? – scaling_out Jul 19 '12 at 18:51
  • Cool, apologies if I misunderstood. I was about to suggest you should post this on the Finaglers forum, but someone just did. https://groups.google.com/forum/?fromgroups#!topic/finaglers/upDrkR4GX7o – Jack Jul 19 '12 at 19:16