Slide 1

Slide 1 text

Commander Decoupled, Immutable REST APIs with Kafka Streams

Slide 2

Slide 2 text

Hi, I’m Bobby I’m on the Technology Fellow’s team at I dislike accidental complexity [email protected] @bobbycalderwood https://github.com/bobby

Slide 3

Slide 3 text

Problem Space • Provide valuable informational and transactional services via Mobile and Web software • To lots of customers, with excellent user experience • Securely and in compliance with regulations • With ability to easily enhance, experiment, monitor, maintain, and operate • By many participants within a large organization

Slide 4

Slide 4 text

Big Ideas • Immutability is central to information systems • Data language of system >> Programming language of components • Action and perception are not the same, and immutability facilitates their separation • Businesses services are not databases, they’re event stream reactors • Cross-cutting concerns must be satisfied in the presence of Conway’s Law

Slide 5

Slide 5 text

Problematic Architecture /[resource](/:id) Database Logic Analytics Web Services Business Logic Databases and Services Operations Metrics/Monitoring Security/Compliance Audit Afterthoughts Other side-effects

Slide 6

Slide 6 text

Immutability is central to information systems

Slide 7

Slide 7 text

An Analogy Image by Alan Light CC BY-SA 3.0

Slide 8

Slide 8 text

Data Loss by Design /[resource](/:id) Database Logic Analytics Web Services Business Logic Databases and Services Operations Metrics/Monitoring Security/Compliance Audit Afterthoughts Other side-effects

Slide 9

Slide 9 text

The (data) language of the System >> The (runtime) language of each component

Slide 10

Slide 10 text

What is system language? /[resource](/:id) Database Logic Analytics Web Services Business Logic Databases and Services Operations Metrics/Monitoring Security/Compliance Audit Afterthoughts Other side-effects

Slide 11

Slide 11 text

Action != Perception

Slide 12

Slide 12 text

Writes != Reads

Slide 13

Slide 13 text

Writes Tied to Reads /[resource](/:id) Database Logic Analytics Web Services Business Logic Databases and Services Operations Metrics/Monitoring Security/Compliance Audit Afterthoughts Other side-effects

Slide 14

Slide 14 text

Business Services are not Databases

Slide 15

Slide 15 text

–John M. Culkin “We shape our tools and thereafter our tools shape us.”

Slide 16

Slide 16 text

Database Leaking /[resource](/:id) Database Logic Analytics Web Services Business Logic Databases and Services Operations Metrics/Monitoring Security/Compliance Audit Afterthoughts Other side-effects

Slide 17

Slide 17 text

Conway’s Law Yup, totally a thing

Slide 18

Slide 18 text

–Melvin Conway “organizations which design systems ... are constrained to produce designs which are copies of the communication structures of these organizations”

Slide 19

Slide 19 text

Cross-cutting Concerns? /[resource](/:id) Database Logic Analytics Web Services Business Logic Databases and Services Operations Metrics/Monitoring Security/Compliance Audit Afterthoughts Other side-effects

Slide 20

Slide 20 text

We can do better!

Slide 21

Slide 21 text

Commander • A better architecture for APIs and services using REST + Immutable Event Log + Reactive Event Stream Processing • The write-handling component of that architecture, my implementation is in Clojure

Slide 22

Slide 22 text

Commander Architecture • Several categories of microservices with structured interactions among them • REST + CQRS + Event Sourcing + Reactive Event Stream Processing

Slide 23

Slide 23 text

Commander Architecture /commands(/:id) /[query-apis] commands /updates Read- optimized View Command Processing Analytics [events topics] Arbitrary command action Arbitrary command action Microconsume rs Web Services Load balancing Auth(n|z) Input validation command-results Business Logic Event Log Datastores and Materialized Views sync “Ledger” of events Operations Metrics/Monitoring Security/Compliance Audit User-facing APIs Third-party Partners WS/SSE audit

Slide 24

Slide 24 text

Commander Component /commands(/:id) /[query-apis] commands /updates Read- optimized View Command Processing Analytics [events topics] Arbitrary command action Arbitrary command action Microconsume rs Web Services Load balancing Auth(n|z) Input validation command-results Business Logic Event Log Datastores and Materialized Views sync “Ledger” of events Operations Metrics/Monitoring Security/Compliance Audit User-facing APIs Third-party Partners WS/SSE audit

Slide 25

Slide 25 text

Embrace Immutability

Slide 26

Slide 26 text

Immutable Data Log /commands(/:id) /[query-apis] commands /updates Read- optimized View Command Processing Analytics [events topics] Arbitrary command action Arbitrary command action Microconsume rs Web Services Load balancing Auth(n|z) Input validation command-results Business Logic Event Log Datastores and Materialized Views sync “Ledger” of events Operations Metrics/Monitoring Security/Compliance Audit User-facing APIs Third-party Partners WS/SSE audit

Slide 27

Slide 27 text

Express actions in domain language (not in database language)

Slide 28

Slide 28 text

A Command {"id": "33bb75db-6e13-48ee-8a54-b3976d3d065b", "action": "transfer-money", "data": {"from_account": "12345", "to_account": "54321", "amount": 10000} "timestamp": "2016-05-20T14:33:28.902-00:00"}

Slide 29

Slide 29 text

An Event {"id": "d435ed18-4ff7-4cae-a21b-3adb7b06fe58", "parent": "33bb75db-6e13-48ee-8a54-b3976d3d065b", "action": "money-transferred", "data": {"id": "a6b903f6-0b9c-4c5b-95fa-afd4cc3bf938", "from_account": "12345", "to_account": "54321", "amount": 10000}, "timestamp": "2016-05-20T14:33:28.904-00:00"}

Slide 30

Slide 30 text

Separate Action from Perception

Slide 31

Slide 31 text

Commander Architecture /commands(/:id) /[query-apis] commands /updates Read- optimized View Command Processing Analytics [events topics] Arbitrary command action Arbitrary command action Microconsume rs Web Services Load balancing Auth(n|z) Input validation command-results Business Logic Event Log Datastores and Materialized Views sync “Ledger” of events Operations Metrics/Monitoring Security/Compliance Audit User-facing APIs Third-party Partners WS/SSE audit

Slide 32

Slide 32 text

Exploit Conway’s Law

Slide 33

Slide 33 text

Primary Team Provides /commands(/:id) /[query-apis] commands /updates Read- optimized View Command Processing Analytics [events topics] Arbitrary command action Arbitrary command action Microconsume rs Web Services Load balancing Auth(n|z) Input validation command-results Business Logic Event Log Datastores and Materialized Views sync “Ledger” of events Operations Metrics/Monitoring Security/Compliance Audit User-facing APIs Third-party Partners WS/SSE audit

Slide 34

Slide 34 text

Enterprise Provides /commands(/:id) /[query-apis] commands /updates Read- optimized View Command Processing Analytics [events topics] Arbitrary command action Arbitrary command action Microconsume rs Web Services Load balancing Auth(n|z) Input validation command-results Business Logic Event Log Datastores and Materialized Views sync “Ledger” of events Operations Metrics/Monitoring Security/Compliance Audit User-facing APIs Third-party Partners WS/SSE audit

Slide 35

Slide 35 text

Kafka Streams!

Slide 36

Slide 36 text

What is Kafka? • Apache Kafka is publish-subscribe messaging rethought as a distributed commit log • But it’s not really about messaging, that’s just the interface • Logs > Messages for my domain • It provides distributed, immutable logs!

Slide 37

Slide 37 text

What is Kafka Streams? • A Java library for building streaming applications on top of Kafka, lives in your application • Low-level API for building topologies of processors, streams, and tables • High-level DSL for common patterns like filter, map, aggregations, joins, stateful and stateless processing • Nice operational characteristics (low latency, elastic, fault-tolerant)

Slide 38

Slide 38 text

How to use Kafka Streams within Commander • Implement Command Processor • Implement Event consumers and producers • Provide local state management as backend for APIs

Slide 39

Slide 39 text

Commander Architecture /commands(/:id) /[query-apis] commands /updates Read- optimized View Command Processing Analytics [events topics] Arbitrary command action Arbitrary command action Microconsume rs Web Services Load balancing Auth(n|z) Input validation command-results Business Logic Event Log Datastores and Materialized Views sync “Ledger” of events Operations Metrics/Monitoring Security/Compliance Audit User-facing APIs Third-party Partners WS/SSE audit

Slide 40

Slide 40 text

KStreamBuilder builder = new KStreamBuilder(); KStream commands = builder.stream(commandsTopic); KStream customerEvents = commands .filter((id, command) -> command.get("action") .equals("create-customer")) .map((id, command) -> { Map userEvent = new HashMap(command); userEvent.put("action", "customer-created"); userEvent.put("parent", id); Map userValue = (Map) userEvent.get("data"); userValue.put("id", UUID.randomUUID()); return new KeyValue<>(UUID.randomUUID(), userEvent); }).through(eventsTopic); KStream customers = customerEvents .map((id, event) -> { Map customer = (Map) event.get("data"); UUID customerId = (UUID) customer.get("id"); return new KeyValue(customerId, customer); }); customers.through(customersTopic); StateStoreSupplier store = Stores.create("Customers") .persistent() .build(); builder.addStateStore(store); customers.process(customerStore, "Customers"); this.kafkaStreams = new KafkaStreams(builder, kafkaStreamsConfig); this.kafkaStreams.start();

Slide 41

Slide 41 text

public class CustomerStore implements Processor { private KeyValueStore store; public List getCustomers() { List customers = new ArrayList<>(); KeyValueIterator iterator = store.all(); while (iterator.hasNext()) { KeyValue entry = iterator.next(); customers.add(new Customer(entry.value)); } iterator.close(); return customers; } public Customer getCustomer(UUID id) { return new Customer(store.get(id)); } @Override public void init(ProcessorContext processorContext) { this.store = (KeyValueStore) context.getStateStore("Customers"); } @Override public void process(UUID uuid, Map map) { store.put(uuid, map); } @Override public void punctuate(long l) {} @Override public void close() {} }

Slide 42

Slide 42 text

Demo

Slide 43

Slide 43 text

High-level Benefits • Captures customer intent and business events as immutable data • Allow simple evolution of business logic and the addition of new features and integrations • De-coupled cooperation between organizations via a common data lingua franca used by all • Provides many “non-functional” requirements for free!

Slide 44

Slide 44 text

Developer Benefits • Not language-specific! Supports existing talent base and/or a polyglot approach • Reduce cognitive load by working with simple, single-purpose pieces and a common data abstraction • Properly divides responsibility between central teams and product teams; provides just enough structure.

Slide 45

Slide 45 text

Operational Benefits • Operational monitoring and metrics extensibility built-in! • Better write performance: just write to Kafka • Better read performance: read-optimized databases store exactly what APIs serve • Helps us toward DevOps, microservices, continuous delivery, server-less architectures • Doesn’t require run-time dependency among many services

Slide 46

Slide 46 text

Business Benefits • Audit and compliance log built-in! Clear data provenance • Analytics and reporting extensibility built-in! Fast-data first! • Increased agility, velocity from working with small pieces • Ability to A/B test and experiment with new features or offerings with no impact to existing systems • Lower cost of Dev and Ops

Slide 47

Slide 47 text

Customer Benefits • Better performing APIs on both read and write ops • More real-time perception and interaction • New products and features quickly • We remember the whole story of our customer interactions with us

Slide 48

Slide 48 text

Path • Pursue this idea in parallel with existing systems! 1. Instrument write APIs, either individually or at API gateway, to write commands to Kafka before doing regular processing 2. Build processing infrastructure for each type of command 3. Build read APIs for each event stream 4. Compare results from existing systems to those of new system 5. Cut over to new system when appropriate

Slide 49

Slide 49 text

Giant Shoulders • Immutability: Rich Hickey, Stu Halloway • CQRS: Udi Dahan, Martin Fowler, Chris Richardson • Kafka Event Stream Reactors: Neha Narkhede, Jay Kreps, Martin Kleppmann • Organization and Management: Mel Conway, Eliyahu Goldratt, Gene Kim, Michael Nygard

Slide 50

Slide 50 text

References • http://www.datomic.com/ • http://blog.cognitect.com/?tag=NewNormal+Series • https://martin.kleppmann.com/2015/03/04/turning-the- database-inside-out.html • https://engineering.linkedin.com/distributed-systems/ log-what-every-software-engineer-should-know-about- real-time-datas-unifying • https://www.infoq.com/presentations/Value-Values