Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Reasonable RPC with Remotely

Remotely is an elegant, purely functional machine-to-machine communication library developed in Scala at Verizon. Remotely is fast, lightweight, and models network operations as a monad. It features compositional, reusable protocols and codecs, where the compatibility between client and server is enforced using Scala's type system. It has support for TCP endpoints, with combinators for encryption, circuit-breaking, and load-balancing. In this talk we describe the API of Remotely, and delve into its design and implementation.

  • Be the first to comment

  • Be the first to like this

Reasonable RPC with Remotely

  1. 1. Reasonable RPC with Remotely ScalaDays, 18th March 2015 Rúnar Bjarnason Tim Perrett
  2. 2. Existing solutions No panaceas. Just tradeoffs.
  3. 3. Monolith • All functionality in a single binary • Doesn’t scale • Difficult to evolve and maintain
  4. 4. Broker pattern • Message bus or broker mediates between services • Single point of failure/integration • If broker goes down, the whole system is down
  5. 5. Message-passing • Lightweight and inexpensive • Reliable and scales well • Discovery is a pain
  6. 6. Message passing solutions • Finagle • Thrift • Akka • HTTP*(JSON+XML)/REST
  7. 7. Finagle • Imperative API • No reuse • Too powerful • No higher-order constructs
  8. 8. Thrift • All of the problems with Finagle • Tough tooling • Documentation is lacking • No formal spec for wire format
  9. 9. Akka • Too powerful • Untyped • Actor system API bleeds to the outside • Behavior of complex systems 
 is unreasonable
  10. 10. HTTP*(JSON+XML)/REST • Unproductive, developer time wasted • Marshalling/unmarshalling • Defining HTTP endpoints and using HTTP clients • Resources wasted on HTTP layer and parsing • Does what we want, but at tremendous cost
  11. 11. Our Vision Productivity, Safety, Reuse
  12. 12. Productivity Don’t want to think about: • HTTP protocol specifics • Every possible failure mode • Serialization format • Compatibility
  13. 13. Safety • Ad-hoc evolution doesn’t scale • Incompatibilities should be compile-time failures • Fail as early as possible
  14. 14. Reuse • Use an actual programming language • Build protocols from modular primitives • Compose large protocols from small ones
  15. 15. Remotely RPC for reasonable people
  16. 16. Remotely RPC for reasonable people BETA
  17. 17. Remotely • Pilot for Verizon open-source • Taking the time to build exactly what we want to use • You can use it too!
  18. 18. Remote call val x = factorial(9)
  19. 19. Remote reference factorial: Remote[Int => Int]
  20. 20. Applying a remote function val x: Remote[Int] = factorial(9)
  21. 21. Getting a response val x: Response[Int] = factorial(9).run(endpoint)
  22. 22. Response monad type Demo[A] = Kleisli[Response, Endpoint, A] implicit def remoteToK[A](r: Remote[A]): Demo[A] = Kleisli.ask[Response, Endpoint].flatMapK(r.run) def call: Demo[(Movie,List[Actor])] = for { a <- MovieClient.getMovie("m2") b <- MovieClient.getActors(a) } yield (a,b)
  23. 23. Running Responses val address = new InetSocketAddress("10.1.0.1",8080) val exe: Task[(Movie,List[Actor])] = for { transport <- NettyTransport.single(address) endpoint = Endpoint.single(transport) output <- call(endpoint)(Context.empty) _ <- transport.shutdown } yield output val (movie, actors) = exe.run
  24. 24. Demo
  25. 25. Feature Pageant
  26. 26. Binary Codecs • Fast, lightweight binary serialization • Built on scodec • Ships with codecs for standard Scala types • Easy to make codecs for your own types • Future goal: Fully automate codec-creation
  27. 27. Pluggable transports • Uses Netty 4 out of the box • Akka I/O • Netty 3 • ØMQ
  28. 28. Pluggable transports type Handler = Process[Task,BitVector] => Process[Task,BitVector]
  29. 29. Endpoints case class Endpoint( connections: Process[Task,Handler])
  30. 30. Endpoint combinators def circuitBroken: (Duration,Int,Endpoint) => Endpoint def failoverChain: (Duration,Process[Task,Endpoint]) => Endpoint
  31. 31. Context-passing • Context provides arbitrary container for experiment propagation. • Every request tagged with a UUID. • Contains stack of request UUIDs. • highlights the “path” through the system request graph when debugging.
  32. 32. Pluggable monitoring • Report round-trip latency timing. • Trace every request uniquely. • Trace the request stack entirely. • Bring your own by implementing the Monitoring trait. • Uses println out of the box.
  33. 33. Capability checking • Protocol versioning over time inevitable • Determine client/server compatibility before establishing connection
  34. 34. How fast is it? • Went from 56 ms to 32 ms
 (production payload) • In benchmarks on modest hardware • Min: ~400 μs • Mean: ~1.5 ms • Throughput is an issue currently
  35. 35. Spray I/O Netty 4
  36. 36. Future work • Prettier API • Drastically improve throughput • Extensible protocol language • More built-ins for e.g. server-side map and flatMap • Remote polymorphic functions
  37. 37. Summary • Remotely is productive • It’s safe • It promotes code reuse • You can contribute!
  38. 38. EOF @runarorama @timperrett github.com/oncue/remotely github.com/oncue/remotely-demo

×