FROM HTTP TO KAFKA-BASED FROM HTTP TO KAFKA-BASED MICROSERVICES MICROSERVICES (EXTENDED) (EXTENDED) Wojciech Rząsa, FLYR Poland @wrzasa From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
Informatics specialist by passion and by profession 15 years of academic work PhD but primarily an engineer FLYR Inc. Distributed systems Rzeszow Ruby User Group ABOUT ME ABOUT ME http://flyrlabs.com http://rrug.pl From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
FLYR FLYR Revenue management system for airlines Offices in San Francisco, USA (PST) Kraków, Poland (CEST) Machine Learning Microservices Python GCloud Kubernetes Big Query From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
IN FLYR MICROSERVICES IN FLYR MICROSERVICES IPC based on HTTP New requirements for eCommerce use case From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
IN FLYR MICROSERVICES IN FLYR MICROSERVICES IPC based on HTTP New requirements for eCommerce use case partial responses From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
IN FLYR MICROSERVICES IN FLYR MICROSERVICES IPC based on HTTP New requirements for eCommerce use case partial responses performance From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
IN FLYR MICROSERVICES IN FLYR MICROSERVICES IPC based on HTTP New requirements for eCommerce use case partial responses performance We will need MQs anyway in the future From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
BUT... BUT... We have HTTP-based infrastructure We have HTTP developers experience and habits From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
BUT... BUT... We have HTTP-based infrastructure We have HTTP developers experience and habits We lack experience with MQ-based IPC From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
BUT... BUT... We have HTTP-based infrastructure We have HTTP developers experience and habits We lack experience with MQ-based IPC We need to do it well ;-) From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
NEW OPPORTUNITIES... NEW OPPORTUNITIES... TO MAKE TO MAKE NEW MISTAKES NEW MISTAKES From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
NEW OPPORTUNITIES... NEW OPPORTUNITIES... TO MAKE TO MAKE NEW MISTAKES NEW MISTAKES Concurrency issues From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
NEW OPPORTUNITIES... NEW OPPORTUNITIES... TO MAKE TO MAKE NEW MISTAKES NEW MISTAKES Concurrency issues Race conditions From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
NEW OPPORTUNITIES... NEW OPPORTUNITIES... TO MAKE TO MAKE NEW MISTAKES NEW MISTAKES Concurrency issues Race conditions Incorrect broker choice From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
NEW OPPORTUNITIES... NEW OPPORTUNITIES... TO MAKE TO MAKE NEW MISTAKES NEW MISTAKES Concurrency issues Race conditions Incorrect broker choice Incorrect driver for the correct broker From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
NEW OPPORTUNITIES... NEW OPPORTUNITIES... TO MAKE TO MAKE NEW MISTAKES NEW MISTAKES Concurrency issues Race conditions Incorrect broker choice Incorrect driver for the correct broker Incorrect usage patterns for the correct driver From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
NEW OPPORTUNITIES... NEW OPPORTUNITIES... TO MAKE TO MAKE NEW MISTAKES NEW MISTAKES Concurrency issues Race conditions Incorrect broker choice Incorrect driver for the correct broker Incorrect usage patterns for the correct driver Incorrect usage patterns for the correct broker From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
NEW OPPORTUNITIES... NEW OPPORTUNITIES... TO MAKE TO MAKE NEW MISTAKES NEW MISTAKES Concurrency issues Race conditions Incorrect broker choice Incorrect driver for the correct broker Incorrect usage patterns for the correct driver Incorrect usage patterns for the correct broker . . . From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
LET'S CONTAIN THE RISKS IN LET'S CONTAIN THE RISKS IN ONE PLACE ONE PLACE (A LIBRARY) (A LIBRARY) From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
AND CALL THIS PLACE AND CALL THIS PLACE async_calls async_calls (FOR THE LACK OF BETTER CONCEPT) (FOR THE LACK OF BETTER CONCEPT) From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
A LIBRARY THAT A LIBRARY THAT meets functional requirements for developers, resembles HTTP where possible uses a MQ broker for communication From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
FOR MAINTAINERS FOR MAINTAINERS THE SAURON ADVANTAGE :) THE SAURON ADVANTAGE :) One place to fix them all (bugs) One place to change them all (decisions about broker, drivers, ...) One place to apply them all (correct usage patters) From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
ASSUMPTIONS ASSUMPTIONS Make it simple – provide just IPC Library, not framework approach Make it testable manually (curl-like tool) automatically (reasonable mocks) Make it resemble Flask? From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
CREATE AN APPLICATION OBJECT CREATE AN APPLICATION OBJECT from async_calls import AsyncCalls async_calls = AsyncCalls('a-money-broker') From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
CREATE AN APPLICATION OBJECT CREATE AN APPLICATION OBJECT CREATE A BASIC ENDPOINT CREATE A BASIC ENDPOINT from async_calls import AsyncCalls async_calls = AsyncCalls('a-money-broker') @async_calls.server.callback_for('/show-me-the-money') def show_me_the_money(request): for i in range(1,5): payload = f"Response {i} for call: {request.id}" response = request.create_response(payload) async_calls.server.send(response) time.sleep(1) From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
CREATE AN APPLICATION OBJECT CREATE AN APPLICATION OBJECT CREATE A BASIC ENDPOINT CREATE A BASIC ENDPOINT from async_calls import AsyncCalls async_calls = AsyncCalls('a-money-broker') # a service ID @async_calls.server.callback_for('/show-me-the-money') def show_me_the_money(request): for i in range(1,5): payload = f"Response {i} for call: {request.id}" response = request.create_response(payload) async_calls.server.send(response) time.sleep(1) From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
CREATE AN APPLICATION OBJECT CREATE AN APPLICATION OBJECT CREATE A BASIC ENDPOINT CREATE A BASIC ENDPOINT from async_calls import AsyncCalls async_calls = AsyncCalls('a-money-broker') # a service ID @async_calls.server.callback_for('/show-me-the-money') def show_me_the_money(request): # ^^^^^^^^ an endpoint name for i in range(1,5): payload = f"Response {i} for call: {request.id}" response = request.create_response(payload) async_calls.server.send(response) time.sleep(1) From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
TO START LISTENING TO START LISTENING (CLIENT AND SERVER) (CLIENT AND SERVER) async_calls.listen() From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
WHAT WE HAVE THEN? WHAT WE HAVE THEN? Server — event-driven (like HTTP) Client — non-blocking, event-driven (unlike HTTP) From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
WHAT WE HAVE THEN? WHAT WE HAVE THEN? Server — event-driven (like HTTP) Client — non-blocking, event-driven (unlike HTTP) One request — any number of responses From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
WHAT WE HAVE THEN? WHAT WE HAVE THEN? Server — event-driven (like HTTP) Client — non-blocking, event-driven (unlike HTTP) One request — any number of responses A single process can be a server and a client From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
TESTING A SERVER TESTING A SERVER DOES IT RESPOND CORRECTLY? DOES IT RESPOND CORRECTLY? From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
TESTING A CLIENT TESTING A CLIENT DOES IT SEND EXPECTED REQUESTS? DOES IT SEND EXPECTED REQUESTS? From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
TESTING SUMMARY TESTING SUMMARY Tools out-of-the-box Calls made on stack, deterministic tests No MQ broker required for unittests No need to think about IPC details when implementing tests From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
MANY MORE FEATURES MANY MORE FEATURES before send and before receive hooks (e.g. for validations) endpoint context managers (e.g. for performance measurements) endpoint error handlers Kubernetes healthcheck CLI curl-like client From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
ANY DRAWBACKS? ANY DRAWBACKS? Hiding complexity we hide opportunities... ...not only to make new errors e.g. no Kafka Streams via async_calls From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
HOW DID IT SAVE US? HOW DID IT SAVE US? Concurrency issues Race conditions Incorrect broker choice Incorrect driver for the correct broker Incorrect usage patterns for the correct driver Incorrect usage patterns for the correct broker . . . From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
SUMMARY SUMMARY Switching from HTTP to async_calls Server is straightforward Client is not complicated From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
SUMMARY SUMMARY Switching from HTTP to async_calls Server is straightforward Client is not complicated Support for one-way communication From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
SUMMARY SUMMARY Switching from HTTP to async_calls Server is straightforward Client is not complicated Support for one-way communication More complex use cases require more attention From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
SUMMARY SUMMARY Switching from HTTP to async_calls Server is straightforward Client is not complicated Support for one-way communication More complex use cases require more attention Services are easily testable From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
SUMMARY SUMMARY Switching from HTTP to async_calls Server is straightforward Client is not complicated Support for one-way communication More complex use cases require more attention Services are easily testable Standard project-wide layer for asynchronous IPC From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
SUMMARY SUMMARY Switching from HTTP to async_calls Server is straightforward Client is not complicated Support for one-way communication More complex use cases require more attention Services are easily testable Standard project-wide layer for asynchronous IPC A number of small but useful bonuses From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
COMMUNICATION ASSUMPTIONS COMMUNICATION ASSUMPTIONS Deduplication (using version on each record) Version checking on >= version not on == version + 1 Error in code causes exception Exception prevents committing of Kafka message From HTTP to Kafka-based Microservices – [email protected] – @wrzasa
SUMMARY SUMMARY A library hiding MQ from devs works well Cannot hide all async problems behind a facade Consequences in DB design Decisions dependent on business logic HTTP to MQ is not just a change of transport Procedures of restoring data consistency Do I really need all this mess? From HTTP to Kafka-based Microservices – [email protected] – @wrzasa