+ All Categories
Home > Technology > I Can’t Believe It’s Not A Queue: Using Kafka with Spring

I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Date post: 13-Feb-2017
Category:
Upload: spring-io
View: 698 times
Download: 2 times
Share this document with a friend
63
Transcript
Page 1: I Can’t Believe It’s Not A Queue: Using Kafka with Spring
Page 2: I Can’t Believe It’s Not A Queue: Using Kafka with Spring
Page 3: I Can’t Believe It’s Not A Queue: Using Kafka with Spring
Page 4: I Can’t Believe It’s Not A Queue: Using Kafka with Spring
Page 5: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

BombMQ

“cut the red wire”“cut the blue wire”

Page 6: I Can’t Believe It’s Not A Queue: Using Kafka with Spring
Page 7: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Bombfka

“cut the red wire”“cut the blue wire”

replaybutton

Page 8: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Bombfka

“cut the blue wire”

“cut the red wire”

Page 9: I Can’t Believe It’s Not A Queue: Using Kafka with Spring
Page 10: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

@codefingerJoe Kutner

Page 11: I Can’t Believe It’s Not A Queue: Using Kafka with Spring
Page 12: I Can’t Believe It’s Not A Queue: Using Kafka with Spring
Page 13: I Can’t Believe It’s Not A Queue: Using Kafka with Spring
Page 14: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Agenda• What is Kafka?

• Kafka + Spring

• Metrics Example

• How Heroku uses Kafka

Page 15: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

What is Kafka?

Page 16: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Kafka is a distributed, partitioned, replicated commit log service. It provides the functionality of a messaging system, but with a unique design.

Page 17: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Distributed Publish Subscribe Messaging

Page 18: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Fast Scalable Durable

Page 19: I Can’t Believe It’s Not A Queue: Using Kafka with Spring
Page 20: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

“hundreds of thousands to millions of messages a second on a small cluster”

Tom Crayford Heroku Kafka

Page 21: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Know Your Cuts of Kafka

Producers Consumers

Partitions

GroupsBrokers

Messages

Topics

Keys

Page 22: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Producers & Consumers

Page 23: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Messages

• Header • Key • Value

(Byte Array)

Page 24: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Messages feed into Topics

Page 25: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Each Topic Partition is an ordered log of immutable messages, append-only

Page 26: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Offsets

Page 27: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Consumer Groups

Page 28: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

• Messages are produced in order

• Messages are consumed in order

• Topics are distributed and replicated

Kafka Guarantees

Page 29: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Kafka + Java

Page 30: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

props.put("bootstrap.servers", “broker1:9092,broker2:9092”);props.put(“key.serializer”, StringSerializer.class.getName());props.put(“value.serializer”, StringSerializer.class.getName());

Producer<String, String> producer = new KafkaProducer<>(props);

Producer API

producer.send(new ProducerRecord<>("my-topic", message2));

producer.send(new ProducerRecord<>("my-topic", message3));

producer.send(new ProducerRecord<>("my-topic", message1));

producer.send(...).get();

Page 31: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Consumer APIAutomatic Offset Committing

props.put("bootstrap.servers", “broker1:9092,broker2:9092”);props.put(“key.deserializer”, StringDeserializer.class.getName());props.put(“value.deserializer”, StringDeserializer.class.getName());

KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);

consumer.subscribe(singletonList(“my-topic”));

while (running.get()) { ConsumerRecords<String, String> records = consumer.poll(100);

for (ConsumerRecord<String, String> record : records) { // ... }}

Page 32: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Consumer APIManual Offset Committing

props.put("enable.auto.commit", "false");// ...

KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);

consumer.subscribe(singletonList(“my-topic”));

final int minBatchSize = 200;

while (running.get()) { ConsumerRecords<String, String> records = consumer.poll(100); for (ConsumerRecord<String, String> record : records) { buffer.add(record); } if (buffer.size() >= minBatchSize) { insertIntoDb(buffer); consumer.commitSync(); buffer.clear(); }}

Page 33: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Consumer API

Kafka Consumer is NOT threadsafe

Page 34: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Consumer APIAdvanced!

• Per-message offset commit

• Manual Partition Assignment

• Storing Offsets Outside Kafka

• Kafka Streams (since 0.10)

Page 35: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Using Kafka with SpringProducer

@SpringBootApplication@EnableKafkapublic class SpringApplicationProducer {

@Bean public KafkaTemplate<Integer, String> kafkaTemplate() {

return new KafkaTemplate<Integer, String>(producerFactory()); }

@Bean public ProducerFactory<Integer, String> producerFactory() {

return new DefaultKafkaProducerFactory<>(producerConfigs()); }

private Map<String, Object> producerConfigs() { Map<String, Object> props = new HashMap<>();

props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092"); props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, IntegerSerializer.class); // ...

return props; }

}

Page 36: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Using Kafka with SpringProducer

@Autowiredprivate KafkaTemplate<Integer, String> template;

public void send() throws Exception { template.send(“my-topic", message);}

Page 37: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Using Kafka with SpringConsumer

@Servicepublic class MyKafkaListener {

@KafkaListener(topicPattern = “my-topic") public void listen(String message) { System.out.println("received: " + message); }}

Page 38: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Using Kafka with SpringConsumer

@Servicepublic class MyKafkaListener {

@KafkaListener(id = “my-listener", topicPartitions = { @TopicPartition(topic = "topic1", partitions = { "0", "1" }), @TopicPartition(topic = "topic2", partitions = { "0", "1" }) }) public void listen(String message) { System.out.println("received: " + message); }}

Page 39: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Metrics App Example

Page 40: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Architecture

Web Request

Primary App

Metrics AppRouter Logs

Page 41: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

POST

Spring App

Log Drain App (Producer)

Kafka Cluster

Log Drain (HTTPS)

Architecture

Web Request

Metrics Aggregator (Consumer)

Page 42: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

POST

Spring App

Log Drain App (Producer)

Kafka Cluster

Log Drain (HTTPS)

Architecture

Web Request

Metrics Aggregator (Consumer)

Page 43: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Heroku Log Drains

$ heroku drains:add https://<metrics-app>/logs

242 <158>1 2016-06-20T21:56:57.107495+00:00 host heroku router -

at=info method=GET path="/" host=demodayex.herokuapp.com

request_id=1850b395-c7aa-485c-aa04-7d0894b5f276 fwd="68.32.161.89"

dyno=web.1 connect=0ms service=6ms status=200 bytes=1548

Page 44: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

POST

Spring App

Log Drain App (Producer)

Kafka Cluster

Log Drain (HTTPS)

Architecture

Web Request

Metrics Aggregator (Consumer)

Page 45: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

@RequestMapping(value = "/logs", method = RequestMethod.POST) @ResponseBodypublic String logs(@RequestBody String body) throws IOException { // "application/logplex-1" does not conform to RFC5424. // It leaves out STRUCTURED-DATA but does not replace it with // a NILVALUE. To workaround this, we inject empty STRUCTURED-DATA. String[] parts = body.split("router - "); String log = parts[0] + "router - [] " + (parts.length > 1 ? parts[1] : ""); RFC6587SyslogDeserializer parser = new RFC6587SyslogDeserializer(); InputStream is = new ByteArrayInputStream(log.getBytes()); Map<String, ?> messages = parser.deserialize(is); ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(messages);

template.send("logs", json); return "ok"; }

Page 46: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

POST

Spring App

Log Drain App (Producer)

Kafka Cluster

Log Drain (HTTPS)

Architecture

Web Request

Metrics Aggregator (Consumer)

Page 47: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Heroku Kafka

$ heroku addons:create heroku-kafka

$ heroku kafka:create logs Create the Topic

$ heroku plugins:install heroku-kafka

Create the Cluster

Page 48: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Heroku Kafka

$ heroku kafka:info=== KAFKA_URL

Name: kafka-asymmetrical-77749Created: 2016-06-20 18:21 UTCPlan: Beta DevStatus: availableVersion: 0.9.0.1Topics: 2 topics (see heroku kafka:list)Connections: 0 consumers (0 applications)Messages: 32.0 messages/sTraffic: 2.25 KB/s in / 2.25 KB/s out

Page 49: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Heroku Kafka

$ heroku kafka:topic logs=== KAFKA_URL :: logs

Producers: 0.0 messages/second (0 Bytes/second)Consumers: 0 Bytes/second totalPartitions: 32 partitionsReplication Factor: 2 (recommend > 1)Compaction: Compaction is disabled for logsRetention: 24 hours

Page 50: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

POST

Spring App

Log Drain App (Producer)

Kafka Cluster

Log Drain (HTTPS)

Architecture

Web Request

Metrics Aggregator (Consumer)

Page 51: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

public class Metrics { // ...

public static void main(String[] args) { /* … */ }

public Metrics() throws Exception { // ... URI redisUri = new URI(System.getenv("REDIS_URL")); pool = new JedisPool(redisUri); }

private void start() { // ... running.set(true); executor = Executors.newSingleThreadExecutor(); executor.submit(this::loop); stopLatch = new CountDownLatch(1); } }

Main Consumer Class

Page 52: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

private void loop() { // ...

consumer = new KafkaConsumer<>(properties); consumer.subscribe(singletonList(KafkaConfig.getTopic()));

while (running.get()) { ConsumerRecords<String, String> records = consumer.poll(100); for (ConsumerRecord<String, String> record : records) { try { Map<String,String> recordMap = mapper.readValue(record.value(), typeRef); Route route = new Route(recordMap); receive(route); } catch (IOException e) { e.printStackTrace(); } } } consumer.close(); stopLatch.countDown(); }

Main Consumer Method

Page 53: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

private void receive(Route route) { // … jedis.hincrBy(key, "sum", value); jedis.hincrBy(key, "count", 1); Integer sum = Integer.valueOf(jedis.hget(key, "sum")); Float count = Float.valueOf(jedis.hget(key, "count")); Float avg = sum / count;

jedis.hset(key, "average", String.valueOf(avg)); }

Update Redis

Page 54: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

?

POST

Spring App

Log Drain App (Producer)

Kafka Cluster

Log Drain (HTTPS)

Architecture

Web Request

Metrics Aggregator (Consumer)

Page 55: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

POST

Spring App

Log Drain App (Producer)

Kafka Cluster

Log Drain (HTTPS)

Architecture

Web Request

Metrics Aggregator (Consumer)

Replay (Consumer) Staging App

Page 56: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Demo App

https://github.com/jkutner/heroku-metrics-spring

$ docker-compose up web

Page 57: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Other Use Cases• User Activity

• Stream Processing

Page 58: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Metrics

Logs

IoT Data

Kafka Cluster

Stream Processing

Page 59: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Kafka @ Heroku• Metrics

• API Event Bus

Page 60: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Heroku Metrics Dashboard

Page 61: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Heroku API Event Bus

Page 62: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

Heroku Kafka http://heroku.com/kafka

$ heroku addons:create heroku-kafka

Page 63: I Can’t Believe It’s Not A Queue: Using Kafka with Spring

@codefingerJoe Kutner

Thank You!


Recommended