Reducing Microservice Complexity with Kafka and Reactive Streams

60
Reducing Microservice Complexity with Kafka and Reactive Streams Jim Riecken

Transcript of Reducing Microservice Complexity with Kafka and Reactive Streams

Page 1: Reducing Microservice Complexity with Kafka and Reactive Streams

Reducing Microservice Complexity with Kafka and Reactive Streams

Jim Riecken

Page 2: Reducing Microservice Complexity with Kafka and Reactive Streams
Page 3: Reducing Microservice Complexity with Kafka and Reactive Streams

Reducing Microservice Complexity with Kafka and Reactive Streams

Senior Software DeveloperJim Riecken

@jimriecken - [email protected]

Page 4: Reducing Microservice Complexity with Kafka and Reactive Streams

@jimriecken

Page 5: Reducing Microservice Complexity with Kafka and Reactive Streams
Page 6: Reducing Microservice Complexity with Kafka and Reactive Streams
Page 7: Reducing Microservice Complexity with Kafka and Reactive Streams
Page 8: Reducing Microservice Complexity with Kafka and Reactive Streams

• Monolith to Microservices + Complexity

• Asynchronous Messaging• Kafka• Reactive Streams + Akka Streams

Agenda

Page 9: Reducing Microservice Complexity with Kafka and Reactive Streams

• Details on how to set up a Kafka cluster

• In-depth tutorial on Akka Streams

Anti-Agenda

Page 10: Reducing Microservice Complexity with Kafka and Reactive Streams

Monolith to Microservices

Page 11: Reducing Microservice Complexity with Kafka and Reactive Streams

M

Page 12: Reducing Microservice Complexity with Kafka and Reactive Streams

Efficie

ncy

Time

Page 13: Reducing Microservice Complexity with Kafka and Reactive Streams

MS1

S2

Page 14: Reducing Microservice Complexity with Kafka and Reactive Streams

F

S1

S2

S3

S4

S5

Page 15: Reducing Microservice Complexity with Kafka and Reactive Streams

Efficie

ncy

Time

•Small•Scalable•Independent•Easy to Create•Clear ownership

Page 16: Reducing Microservice Complexity with Kafka and Reactive Streams

Network Calls

•Latency•Failure

Page 17: Reducing Microservice Complexity with Kafka and Reactive Streams

~99.5%

Reliability

99.9% 99.9% 99.9% 99.9%

Page 18: Reducing Microservice Complexity with Kafka and Reactive Streams

Coordination

•Between services

•Between teams

Page 19: Reducing Microservice Complexity with Kafka and Reactive Streams
Page 20: Reducing Microservice Complexity with Kafka and Reactive Streams

AsynchronousMessaging

Page 21: Reducing Microservice Complexity with Kafka and Reactive Streams

Message Bus

Synchronous

Asynchronous

Page 22: Reducing Microservice Complexity with Kafka and Reactive Streams

• Decoupling•Pub/Sub

• Less coordination•Additional consumers are easy

•Help scale organization

Why?

Page 23: Reducing Microservice Complexity with Kafka and Reactive Streams

•Well-defined delivery semantics

• High-Throughput• Highly-Available• Durable• Scalable• Backpressure

Messaging Requirements

Page 24: Reducing Microservice Complexity with Kafka and Reactive Streams

Kafka

Page 25: Reducing Microservice Complexity with Kafka and Reactive Streams

• Distributed, partitioned, replicated commit log service

• Pub/Sub messaging functionality• Created by LinkedIn, now an

Apache open-source project

What is Kafka?

Page 26: Reducing Microservice Complexity with Kafka and Reactive Streams

Producers

Kafka Brokers

Consumers

Page 27: Reducing Microservice Complexity with Kafka and Reactive Streams

0 | 1 | 2 | 3 | 4 | 5

0 | 1 | 2 | 3 | 4 | 5 | 6

0 | 1 | 2 | 3

P0

P1

P2

New Messages Appended

Topic

Topics + Partitions

Page 28: Reducing Microservice Complexity with Kafka and Reactive Streams

• Send messages to topics• Responsible for choosing which

partition to send to•Round-robin•Consistent hashing based on a message key

Producers

Page 29: Reducing Microservice Complexity with Kafka and Reactive Streams

• Pull messages from topics• Track their own offset in each

partition

Consumers

Page 30: Reducing Microservice Complexity with Kafka and Reactive Streams

P0 P1 P2

1 2 3 4 5 6

Topic

Group 1 Group 2

Page 31: Reducing Microservice Complexity with Kafka and Reactive Streams

How does Kafka meet the

requirements?

Page 32: Reducing Microservice Complexity with Kafka and Reactive Streams

• Hundreds of MB/s of reads/writes from thousands of concurrent clients

• LinkedIn (2015)•800 billion messages per day (18

million/s peak)•175 TB of data produced per day•> 1000 servers in 60 clusters

Kafka is Fast

Page 33: Reducing Microservice Complexity with Kafka and Reactive Streams

• Brokers•All data is persisted to disk•Partitions replicated to other nodes

• Consumers•Start where they left off

• Producers•Can retry - at-least-once messaging

Kafka is Resilient

Page 34: Reducing Microservice Complexity with Kafka and Reactive Streams

• Capacity can be added at runtime with zero downtime

•More servers => more disk space• Topics can be larger than any

single node could hold• Additional partitions can be added

to add more parallelism

Kafka is Scalable

Page 35: Reducing Microservice Complexity with Kafka and Reactive Streams

• Large storage capacity•Topic retention is a Consumer SLA

• Almost impossible for a fast producer to overload a slow consumer

•Allows real-time as well as batch consumption

Kafka Helps with Back-Pressure

Page 36: Reducing Microservice Complexity with Kafka and Reactive Streams

Message Data Format

Page 37: Reducing Microservice Complexity with Kafka and Reactive Streams

• Array[Byte]• Serialization?• JSON?• Protocol Buffers

•Binary - Fast•IDL - Code Generation•Message evolution

Messages

Page 38: Reducing Microservice Complexity with Kafka and Reactive Streams

Processing Data with Reactive

Streams

Page 39: Reducing Microservice Complexity with Kafka and Reactive Streams

• Standard for async stream processing with non-blocking back-pressure

•Subscriber signals demand to publisher

•Publisher sends no more than demand

• Low-level• Mainly meant for library authors

Reactive Streams

Page 40: Reducing Microservice Complexity with Kafka and Reactive Streams

Publisher[T] Subscriber[T]

onSubscribe(s: Subscription)onNext(t: T)onComplete()onError(t: Throwable)

Subscription

subscribe(s: Subscriber[-T])

request(n: Long)cancel()

Page 41: Reducing Microservice Complexity with Kafka and Reactive Streams

Processing Data with Akka Streams

Page 42: Reducing Microservice Complexity with Kafka and Reactive Streams

• Library on top of Akka Actors and Reactive Streams

• Process sequences of elements using bounded buffer space

• Strongly Typed

Akka Streams

Page 43: Reducing Microservice Complexity with Kafka and Reactive Streams

Flow

Source

SinkFanOut

FanIn

Concepts

Page 44: Reducing Microservice Complexity with Kafka and Reactive Streams

Runnable Graph

Concepts

Page 45: Reducing Microservice Complexity with Kafka and Reactive Streams

Composition

Page 46: Reducing Microservice Complexity with Kafka and Reactive Streams

• Turning on the tap•Create actors•Open files/sockets/other

resources•Materialized values

•Source: Actor, Promise, Subscriber

•Sink: Actor, Future, Producer

Materialization

Page 47: Reducing Microservice Complexity with Kafka and Reactive Streams

Reactive Kafka

Page 48: Reducing Microservice Complexity with Kafka and Reactive Streams

• https://github.com/akka/reactive-kafka

• Akka Streams wrapper around Kafka API

•Consumer Source•Producer Sink

Reactive Kafka

Page 49: Reducing Microservice Complexity with Kafka and Reactive Streams

• Sink - sends message to Kafka topic•Flow - sends message to Kafka topic + emits result downstream

• When the stream completes/fails the connection to Kafka will be automatically closed

Producer

Page 50: Reducing Microservice Complexity with Kafka and Reactive Streams

• Source - pulls messages from Kafka topics

• Offset Management• Back-pressure• Materialization

•Object that can stop the consumer (and complete the stream)

Consumer

Page 51: Reducing Microservice Complexity with Kafka and Reactive Streams

Simple Producer Example implicit val system = ActorSystem("producer-test")

implicit val materializer = ActorMaterializer()

val producerSettings = ProducerSettings(

system, new ByteArraySerializer, new StringSerializer

).withBootstrapServers("localhost:9092")

Source(1 to 100)

.map(i => s"Message $i")

.map(m => new ProducerRecord[Array[Byte], String]

("lower", m))

.to(Producer.plainSink(producerSettings)).run()

Page 52: Reducing Microservice Complexity with Kafka and Reactive Streams

Simple Consumer Example implicit val system = ActorSystem("producer-test")

implicit val materializer = ActorMaterializer()

val consumerSettings = ConsumerSettings(

system, new ByteArrayDeserializer, new StringDeserializer, Set("lower")

).withBootstrapServers("localhost:9092").withGroupId("test-group")

val control =

Consumer.atMostOnceSource(consumerSettings.withClientId("client1"))

.map(record => record.value)

.to(Sink.foreach(v => println(v))).run()

control.stop()

Page 53: Reducing Microservice Complexity with Kafka and Reactive Streams

val control =

Consumer.committableSource(consumerSettings.withClientId("client1"))

.map { msg =>

val upper = msg.value.toUpperCase

Producer.Message(

new ProducerRecord[Array[Byte], String]("upper", upper),

msg.committableOffset)

}.to(Producer.commitableSink(producerSettings)).run()

control.stop()

Combined Example

Page 54: Reducing Microservice Complexity with Kafka and Reactive Streams

Demo

Page 55: Reducing Microservice Complexity with Kafka and Reactive Streams

Wrap-Up

Page 56: Reducing Microservice Complexity with Kafka and Reactive Streams

• Microservices have many advantages, but can introduce failure and complexity.

• Asynchronous messaging can help reduce this complexity and Kafka is a great option.

• Akka Streams makes reliably processing data from Kafka with back-pressure easy

Wrap-Up

Page 57: Reducing Microservice Complexity with Kafka and Reactive Streams
Page 58: Reducing Microservice Complexity with Kafka and Reactive Streams

Thank you!Questions?

@jimriecken - [email protected] Riecken

Page 59: Reducing Microservice Complexity with Kafka and Reactive Streams
Page 60: Reducing Microservice Complexity with Kafka and Reactive Streams