⇨ Yotam Oron (@YotamOron2)
⇨ Asy Ronen (A.K.A Async)
⇨ Eran Harel (@eran_ha)
What is OB1K?
Asynchronous IO based on Netty
Synchronous Modules based on Jetty 9
Drop-in replacement for Tomcat apps
Kick A$$ Performance :)
Self Contained
Isolated Services
● Own JVM
● Own JVM settings
● Own configuration
● Own port
● Own logs
● Own log configuration
Full control over your module
● JVM options
● Configuration properties
● Logging
● Ports
● Compression
● Threads
● Etc
Seamless RPC
● Strongly Typed RPC Client
Seamless RPC
● No need to configure anything
○ Except for more advanced cases…
Seamless RPC
● RPC complexity is transparent to the client
Seamless RPC
● Server implementation only worries about
the business logic
Seamless RPC
● Configurable client behavior (e.g. retries)
Seamless RPC
● Built-In serialization support
○ MsgPack
○ JSON
○ Compression
Free Standard API entry points
● /selftest
● /version
● /help (/)
● /properties
● /ping
● /presence
● /jmx
Free Service Monitoring
Free ZooKeeper Registration
Easier upgrades, easier deployment
Same execution path for
Dev / Prod / JUnit
Maven Archetype Scaffolding
$ mvn archetype:generate -DarchetypeGroupId=com.outbrain -
DarchetypeArtifactId=outbrain-ob1k-archetype -DarchetypeVersion=1.0.13 -
DinteractiveMode=false -Dversion=trunk -DgroupId=com.outbrain -
Dpackage=com.outbrain.YOUR_PACKAGE_NAME -DartifactId=YOUR_SERVICE_NAME
A set of asynchronous modules
● Async memcached client
● Async RPC client
● Async HTTP client
● Async DB query execution
● Async Event Stream support
● Composable Futures infrastructure
The main class
Jetty Server
public class GruffaloServer {
private static final Logger logger = LoggerFactory.getLogger(GruffaloServer.class);
public static void main(String[] args) {
new GruffaloServer().build().start();
logger.info("******** Gruffalo started ********");
}
public Server build() {
return new JettyServerBuilder().useConfigurationPorts().setContextPath("/Gruffalo");
}
}
Netty Server
public static Server buildServer() {
final String contextPath = "/Ob1kTemplate";
Context ctx = new SpringContextBuilder(contextPath).
addInitParam("self-tests", "properties,zookeeper,url,valid-context").
setMainContext("main", "classpath:applicationContext-Ob1kTemplate-all.xml").
addSubContext("ops", "classpath:WEB-INF/spring/ops-services.xml").
addSubContext("service", "classpath:WEB-INF/spring/Ob1kTemplate-service.xml").
build();
ServerBuilder serverBuilder = new ServerBuilder().
setContextPath(contextPath).
setContext(ctx).
addStaticPath("/html").
addStaticPath("/css").
addBaseServices("ops").
addServiceFromContext("service", Ob1kService.class, "/api").
createServiceFromContext("service", Ob1kNamedService.class, "/names").
addEndpoint("handleFirstRequest", "/first/{id}").
addEndpoint("handleSecondRequest", "/second/{name}").
addEndpoint("handleThirdRequest", "/third/{state}/{city}").
addService().useConfigurationPorts();
return serverBuilder.build();
}
OB1K Service
public class Ob1kService implements Service {
private static final Logger log = LoggerFactory.getLogger(Ob1kService.class);
private final String greetingMessage;
public Ob1kService(final String greetingMessage) {
this.greetingMessage = greetingMessage;
}
public ComposableFuture<String> echo(final String name) {
return ComposableFutures.fromValue("hello " + name + ". " + greetingMessage);
}
}
OB1K client
new ClientBuilder<>(IOb1kService.class).
setProtocol(ContentType.JSON).
setRequestTimeout(requestTimeout).
setRetries(retries).
addEndpoint("http://somehost:8080/Ob1kApp/Ob1kService").
build();
ComposableFuture
public interface ComposableFuture<T> extends Future<T> {
<R> ComposableFuture<R> continueWith(FutureResultHandler<T, R> handler);
<R> ComposableFuture<R> continueWith(ResultHandler<T, R> handler);
<R> ComposableFuture<R> continueOnSuccess(FutureSuccessHandler<T, R> handler);
ComposableFuture<T> continueOnError(FutureErrorHandler<T> handler);
ComposableFuture<T> withTimeout(long duration, final TimeUnit unit);
void onResult(Handler<T> handler);
<R> ComposableFuture<R> transform(final Function<? super T, ? extends R> function);
State getState();
Throwable getError();
}
ComposableFuture Example
ComposableFuture<Response> f1 = client.httpGet("http://www.google.co.il/search?q=term1");
ComposableFuture<Response> f2 = client.httpGet("http://www.google.co.il/search?q=term2");
ComposableFuture<Response> f3 = client.httpGet("http://www.google.co.il/search?q=term3");
ComposableFuture<List<Response>> combined = all(f1, f2, f3);
ComposableFuture<String> res = combined.continueWith((result) -> {
// prepare combined result.
});
schedule(() -> {
return trySomething().continueOnError((error) -> {
return getFallback();
});
}, 30, TimeUnit.SECONDS);
how does it all works ?
● All IO is non blocking and done via Netty
● Basically one thread per core, all working
unless there is nothing to do
● Context switch is minimized
● Transport is always HTTP, payload may vary
● Adjusted Executor for blocking actions(if you
must)
What is the catch?
● Blocking code is (almost)forbidden in the
async mode
● Writing asynchronous code has a learning
curve
● Libraries have to be adapted
Alternatives
Finagle
Drop Wizard
Vert.x
Play Framework
RESTEasy
Etc
Future Features
● Client Side Load Balancing
● Client Side Discovery (ZK based)
● Aggregation
● Scatter-Gather
● Throttling
● Session Tracing (a-la Zipkin)
*W
e’rerecruiting;)

OB1K - New, Better, Faster, Devops Friendly Java container by Outbrain

  • 1.
    ⇨ Yotam Oron(@YotamOron2) ⇨ Asy Ronen (A.K.A Async) ⇨ Eran Harel (@eran_ha)
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 8.
  • 9.
    Isolated Services ● OwnJVM ● Own JVM settings ● Own configuration ● Own port ● Own logs ● Own log configuration
  • 10.
    Full control overyour module ● JVM options ● Configuration properties ● Logging ● Ports ● Compression ● Threads ● Etc
  • 11.
    Seamless RPC ● StronglyTyped RPC Client
  • 12.
    Seamless RPC ● Noneed to configure anything ○ Except for more advanced cases…
  • 13.
    Seamless RPC ● RPCcomplexity is transparent to the client
  • 14.
    Seamless RPC ● Serverimplementation only worries about the business logic
  • 15.
    Seamless RPC ● Configurableclient behavior (e.g. retries)
  • 16.
    Seamless RPC ● Built-Inserialization support ○ MsgPack ○ JSON ○ Compression
  • 17.
    Free Standard APIentry points ● /selftest ● /version ● /help (/) ● /properties ● /ping ● /presence ● /jmx
  • 18.
  • 19.
  • 20.
  • 21.
    Same execution pathfor Dev / Prod / JUnit
  • 22.
    Maven Archetype Scaffolding $mvn archetype:generate -DarchetypeGroupId=com.outbrain - DarchetypeArtifactId=outbrain-ob1k-archetype -DarchetypeVersion=1.0.13 - DinteractiveMode=false -Dversion=trunk -DgroupId=com.outbrain - Dpackage=com.outbrain.YOUR_PACKAGE_NAME -DartifactId=YOUR_SERVICE_NAME
  • 23.
    A set ofasynchronous modules ● Async memcached client ● Async RPC client ● Async HTTP client ● Async DB query execution ● Async Event Stream support ● Composable Futures infrastructure
  • 25.
  • 26.
    Jetty Server public classGruffaloServer { private static final Logger logger = LoggerFactory.getLogger(GruffaloServer.class); public static void main(String[] args) { new GruffaloServer().build().start(); logger.info("******** Gruffalo started ********"); } public Server build() { return new JettyServerBuilder().useConfigurationPorts().setContextPath("/Gruffalo"); } }
  • 27.
    Netty Server public staticServer buildServer() { final String contextPath = "/Ob1kTemplate"; Context ctx = new SpringContextBuilder(contextPath). addInitParam("self-tests", "properties,zookeeper,url,valid-context"). setMainContext("main", "classpath:applicationContext-Ob1kTemplate-all.xml"). addSubContext("ops", "classpath:WEB-INF/spring/ops-services.xml"). addSubContext("service", "classpath:WEB-INF/spring/Ob1kTemplate-service.xml"). build(); ServerBuilder serverBuilder = new ServerBuilder(). setContextPath(contextPath). setContext(ctx). addStaticPath("/html"). addStaticPath("/css"). addBaseServices("ops"). addServiceFromContext("service", Ob1kService.class, "/api"). createServiceFromContext("service", Ob1kNamedService.class, "/names"). addEndpoint("handleFirstRequest", "/first/{id}"). addEndpoint("handleSecondRequest", "/second/{name}"). addEndpoint("handleThirdRequest", "/third/{state}/{city}"). addService().useConfigurationPorts(); return serverBuilder.build(); }
  • 28.
    OB1K Service public classOb1kService implements Service { private static final Logger log = LoggerFactory.getLogger(Ob1kService.class); private final String greetingMessage; public Ob1kService(final String greetingMessage) { this.greetingMessage = greetingMessage; } public ComposableFuture<String> echo(final String name) { return ComposableFutures.fromValue("hello " + name + ". " + greetingMessage); } }
  • 29.
  • 30.
    ComposableFuture public interface ComposableFuture<T>extends Future<T> { <R> ComposableFuture<R> continueWith(FutureResultHandler<T, R> handler); <R> ComposableFuture<R> continueWith(ResultHandler<T, R> handler); <R> ComposableFuture<R> continueOnSuccess(FutureSuccessHandler<T, R> handler); ComposableFuture<T> continueOnError(FutureErrorHandler<T> handler); ComposableFuture<T> withTimeout(long duration, final TimeUnit unit); void onResult(Handler<T> handler); <R> ComposableFuture<R> transform(final Function<? super T, ? extends R> function); State getState(); Throwable getError(); }
  • 31.
    ComposableFuture Example ComposableFuture<Response> f1= client.httpGet("http://www.google.co.il/search?q=term1"); ComposableFuture<Response> f2 = client.httpGet("http://www.google.co.il/search?q=term2"); ComposableFuture<Response> f3 = client.httpGet("http://www.google.co.il/search?q=term3"); ComposableFuture<List<Response>> combined = all(f1, f2, f3); ComposableFuture<String> res = combined.continueWith((result) -> { // prepare combined result. }); schedule(() -> { return trySomething().continueOnError((error) -> { return getFallback(); }); }, 30, TimeUnit.SECONDS);
  • 32.
    how does itall works ? ● All IO is non blocking and done via Netty ● Basically one thread per core, all working unless there is nothing to do ● Context switch is minimized ● Transport is always HTTP, payload may vary ● Adjusted Executor for blocking actions(if you must)
  • 33.
    What is thecatch? ● Blocking code is (almost)forbidden in the async mode ● Writing asynchronous code has a learning curve ● Libraries have to be adapted
  • 34.
  • 35.
    Future Features ● ClientSide Load Balancing ● Client Side Discovery (ZK based) ● Aggregation ● Scatter-Gather ● Throttling ● Session Tracing (a-la Zipkin)
  • 36.