Академический Документы
Профессиональный Документы
Культура Документы
0. Índice de contenidos.
1. Introducción.
2. Entorno.
3. Instalación.
4. Producer.
5. Consumer.
6. KafkaLog4jAppender.
7. Referencias.
8. Conclusiones.
1. Introducción.
Apache Kafka es un sistema de almacenamiento publicador/subscriptor distribuido, particionado y replicado. Estas
características, añadidas a que es muy rápido en lecturas y escrituras lo convierten en una herramienta excelente para
comunicar streams de información que se generan a gran velocidad y que deben ser gestionados por uno o varias aplicaciones.
Se destacan las siguientes características:
2. Entorno.
El tutorial se ha realizado con el siguiente entorno:
MacBook Pro 15′ (2.4 GHz Intel Core i5, 8GB DDR3 SDRAM).
Sistema Operativo: Mac OS Mavericks 10.9.5
Oracle Java SDK 1.7.0_60
Apache Kafka 0.8.1.1
3. Instalación
Lo primero será descargarnos la última versión desde la página web o cial, actualmente es la 0.8.1.1.
Una vez descomprimido kafka, lo movemos al directorio que más nos guste, por ejemplo a /opt/kafka:
Shell
Tendremos que dar permisos de ejecución a los scripts dentro del directorio bin
Shell
1 $ cd bin
2 $ sudo chmod +x *
Kafka necesitar Zookeeper para trabajar. Por defecto con la distribución viene uno para pruebas que arrancar una única
instancia. Lo arrancamos a través del script de arranque zookeeper-server-start.sh
Shell
Shell
Tanto la con guración de zookeeper como de kafka está en el directorio con g donde se con guran los puertos de escucha,
directorio de almacenamiento por defecto, número de particiones por defecto, etc.
Zookeeper escucha en el puerto 2181 y almacena por defecto los datos en /tmp/zookeeper. Kafka escuha en el puerto 9092.
4. Producer.
Kafka dispone de un API Java para construir productores y consumidores de mensajes. El productor es muy sencillo,
únicamente se indica el servidor donde está corriendo Kafka y el topic por el que escribimos los mensajes:
Shell
1 package com.autentia.tutoriales;
2
3 import java.util.Properties;
4
5 import kafka.javaapi.producer.Producer;
6 import kafka.producer.KeyedMessage;
7 import kafka.producer.ProducerConfig;
8
9 public class KafkaProducer {
10
11 private static final String KAFKA_SERVER = "localhost:9092";
12 private final Producer<String, String> producer;
13
14 public KafkaProducer() {
15 final Properties props = new Properties();
16 props.put("metadata.broker.list", KAFKA_SERVER);
17 props.put("serializer.class", "kafka.serializer.StringEncoder");
18 producer = new Producer<String, String>(new ProducerConfig(props));
19 }
20
21 public void send(String topic, String message) {
22 producer.send(new KeyedMessage<String, String>(topic, message));
23 }
24
25 public void close() {
26 producer.close();
27 }
28
29 public static void main(String[] args) {
30 new KafkaProducer().send("test", "esto es un test");
31 }
32 }
5. Consumer.
Para ver de forma rápida si el producer está escribiendo en el topic indicado y le llega este mensaje a Kafka podemos arrancar un
consumer por línea de comandos:
Shell
Ahora vamos a construirnos un Consumer mediante el API que nos proporciona Kafka.
Shell
1 package com.autentia.tutoriales;
2
3 import java.nio.ByteBuffer;
4 import java.util.HashMap;
5 import java.util.Map;
6
7 import kafka.api.FetchRequest;
8 import kafka.api.FetchRequestBuilder;
9 import kafka.api.PartitionOffsetRequestInfo;
10 import kafka.common.TopicAndPartition;
11 import kafka.javaapi.FetchResponse;
12 import kafka.javaapi.OffsetRequest;
13 import kafka.javaapi.consumer.SimpleConsumer;
14 import kafka.message.MessageAndOffset;
15
16 import org.apache.log4j.Logger;
17
18 public class KafkaConsumer {
19
20 private static final Logger log = Logger.getLogger(KafkaConsumer.class);
21 private static final int FETCH_SIZE = 100000;
22 private static final int MAX_NUM_OFFSETS = 1;
23 private static final int BUFFER_SIZE = 64 * 1024;
24 private static final int TIMEOUT = 100000;
25 private static final int PARTITION = 1;
26 private static final int PORT = 9092;
27 private static final String TOPIC = "test";
28 private static final String BROKER = "localhost";
29 private static final String CLIENT = "testClient";
30 private final SimpleConsumer consumer;
31
32 public KafkaConsumer() {
33 this.consumer = new SimpleConsumer(BROKER, PORT, TIMEOUT, BUFFER_SIZE, CLIENT);
34 }
35
36 public void run() throws Exception {
37 long readOffset = getLastOffset(consumer, kafka.api.OffsetRequest.EarliestTime());
38
39 //consumer never stops
40 while (true) {
41 final FetchRequest req = new FetchRequestBuilder().clientId(CLIENT).addFetch(TOPIC, PARTITION, readOffset, FETCH_SIZE
42 final FetchResponse fetchResponse = consumer.fetch(req);
43
44 for (MessageAndOffset messageAndOffset : fetchResponse.messageSet(TOPIC, PARTITION)) {
45 long currentOffset = messageAndOffset.offset();
46 if (currentOffset < readOffset) {
47 continue;
48 }
49
50 readOffset = messageAndOffset.nextOffset();
51 final ByteBuffer payload = messageAndOffset.message().payload();
52
53 final byte[] bytes = new byte[payload.limit()];
54 payload.get(bytes);
55
56 log.info("[" + messageAndOffset.offset() + "]: " + new String(bytes, "UTF-8"));
57 }
58 }
59 }
60
61 public static long getLastOffset(SimpleConsumer consumer, long whichTime) {
62 final TopicAndPartition topicAndPartition = new TopicAndPartition(TOPIC, PARTITION);
63 final Map<TopicAndPartition, PartitionOffsetRequestInfo> requestInfo = new HashMap<TopicAndPartition, PartitionOffsetRequ
64 requestInfo.put(topicAndPartition, new PartitionOffsetRequestInfo(whichTime, MAX_NUM_OFFSETS));
65
66 final OffsetRequest offsetRequest = new OffsetRequest(requestInfo, kafka.api.OffsetRequest.CurrentVersion(), CLIENT);
67
68 return consumer.getOffsetsBefore(offsetRequest).offsets(TOPIC, PARTITION)[0];
69 }
70
71 public static void main(String args[]) {
72 try {
73 new KafkaConsumer().run();
74 } catch (Exception e) {
75 log.error("Error:" + e);
76 }
77 }
78 }
Levantamos el Producer con el mensaje enviado para el topic ‘test’ y lo que va saliendo por el log del consumer es el mensaje que
nos llega por estar suscritos al topic.
Creamos el consumer indicando el host y puerto donde está arrancado el broker. También se con guran parámetros para indiar
un timeout, el tamaño del buffer y un identi cador para el consumer.
La gran velocidad en lecturas que tiene Kafka se debe a que los topics se leen a partir de un puntero que marca el offset donde
empiezan los mensajes. Es responsabilidad del consumer el mantenimiento de este offset.
La salida del consumer por consola devuelve lo mismo que por línea de comandos:
Shell
6. KafkaLog4jAppender.
Dada la velocidad con la que se escribe en Kafka, un posible caso de uso sería enviar a Kafka las trazas operacionales de nuestra
aplicación. De esta forma podriamos con gurar consumers de logs que fueran procesándolos para detectar problemas.
Kafka ya dispone de un Log4jAppender que nos hace todo el trabajo del productor de logs, únicamente tendríamos que
con gurarlo en nuestro log4j.properties:
Shell
Si lanzamos la clase KafkaConsumer vemos cómo en el topic ‘logs’ aparecen los logs de info que envía.
Shell
7. Referencias.
http://kafka.apache.org/07/quickstart.html
http://www.slideshare.net/miguno/apache-kafka-08-basic-training-verisign
8. Conclusiones.
Son muchos las compañias (LinkedIn, Twitter, Net ix, Square, Spotify, Pinterest, Uber, Tumblr y muchos más) las que utilizan
Apache Kafka para analizar trá co de sus aplicaciones, como parte de su infraestructura de procesamiento de datos,
monitorización en tiempo real, como bus de eventos, etc.
Un saludo.
Juan
Esta obra está licenciada bajo licencia Creative Commons de Reconocimiento-No comercial-Sin obras derivadas 2.5