prefacio
Las mejores prácticas de Kafka, que involucran
- Escenarios de uso típicos
- Prácticas recomendadas para el uso de Kafka
Escenarios de uso típicos de Kafka
Transmisión de datos
Kafka se puede conectar a múltiples tecnologías de procesamiento de datos de transmisión convencionales, como Spark, Flink y Flume. Aprovechando el alto rendimiento de Kafka, los clientes pueden establecer un canal de transmisión a través de Kafka para transmitir datos masivos desde el lado de la aplicación al motor de procesamiento de datos de flujo. Una vez que los datos se procesan y analizan, puede admitir el análisis de big data de back-end, Entrenamiento de modelos de IA, etc. negocios.
plataforma de registro
El escenario de Kafka más utilizado y con el que estoy más familiarizado es el sistema de análisis de registros. Una implementación típica es implementar un recopilador de registros (como Fluentd, Filebeat o Logstash, etc.) en el lado del cliente para la recopilación de registros, enviar los datos a Kafka y luego realizar cálculos de datos a través del ES de back-end, etc. ., y luego construya una capa de visualización como Kibana.Presentación de datos de análisis estadístico.
Internet de las Cosas
El Internet de las cosas (IoT) está ganando terreno a medida que surgen valiosos casos de uso. Sin embargo, un desafío clave es integrar dispositivos y máquinas para procesar datos en tiempo real y a escala. Apache Kafka® y su ecosistema circundante, incluidos Kafka Connect, Kafka Streams, se han convertido en la tecnología elegida para integrar y procesar dichos conjuntos de datos.
Kafka ya se usa en muchas implementaciones de IoT, incluido IoT de consumo e Internet industrial de las cosas (IIoT). La mayoría de los escenarios requieren una integración de extremo a extremo confiable, escalable y segura que admita la comunicación bidireccional en tiempo real y el procesamiento de datos. Algunos casos de uso específicos son:
- Infraestructura de vehículos conectados
- Ciudades inteligentes y hogares inteligentes
- Smart Retail y Cliente 360
- fabricación inteligente
La arquitectura de implementación específica se muestra en la siguiente figura:
mejores prácticas para usar
Mejores prácticas de confiabilidad
Satisfacer diferentes confiabilidades basadas en la configuración del productor y del consumidor
Productor Al Menos Una Vez
El productor debe configurar request.required.acks = ALL
, el nodo maestro en el lado del servidor escribe correctamente y el nodo de respaldo se sincroniza correctamente para devolver la Respuesta.
Consumidor al menos una vez
Después de recibir el mensaje, el consumidor primero debe realizar la operación comercial correspondiente y luego comprometerse a indicar que el mensaje ha sido procesado.Este método de procesamiento puede garantizar que un mensaje pueda consumirse nuevamente cuando falla el procesamiento comercial. Tenga en cuenta que el enable.auto.commit
parámetro debe establecerse False
para garantizar que la acción de confirmación se controle manualmente.
ProductorComo máximo una vez
Para garantizar que un mensaje se pueda entregar como máximo una vez, debe configurarse request.required.acks = 0
y configurarse al mismo tiempo retries = 0
. El principio aquí es que el productor no vuelve a intentar cuando encuentra alguna excepción y no considera si el corredor responde a la escritura exitosa.
Consumidor Como máximo una vez
Para garantizar que un mensaje se pueda consumir como máximo una vez, los consumidores deben comprometerse a indicar que el mensaje se procesó después de recibirlo y luego realizar las operaciones comerciales correspondientes . El principio aquí es que el consumidor no necesita preocuparse por el resultado del procesamiento del negocio real, e inmediatamente después de recibir el mensaje se compromete a decirle al corredor que el mensaje se procesó con éxito. Tenga en cuenta que el enable.auto.commit
parámetroFalse
debe establecerse para garantizar que la acción de confirmación se controle manualmente.
Productor Exactamente una vez
Desde la versión 0.11 de Kafka, se ha agregado la semántica de los mensajes idempotentes Al configurar los parámetros, se puede realizar la idempotencia del mensaje de una sola partición .enable.idempotence=true
Si el tema implica varias particiones o es necesario encapsular varios mensajes en una transacción para garantizar la idempotencia, debe aumentar el control de transacciones de la siguiente manera:
// 开启幂等控制参数
producerProps.put("enbale.idempotence", "true");
// 初始化事务
producer.initTransactions();
// 设置事务 ID
producerProps.put("transactional.id", "id-001");
try{
// 开始事务,并在事务中发送 2 条消息
producer.beginTranscation();
producer.send(record0);
producer.send(record1);
// 提交事务
producer.commitTranscation();
} catch( Exception e ) {
producer.abortTransaction();
producer.close();
}
Consumidor Exactamente una vez
Debe configurarse una isolation.level=read_committed
y otra vez enable.auto.commit = false
para garantizar que el consumidor solo consuma los mensajes que el productor ha comprometido. La empresa del consumidor debe garantizar la transaccionalidad para evitar el procesamiento repetido de los mensajes, como conservar el mensaje en la base de datos y luego enviar el compromiso. al servidor
Elija la semántica adecuada según el escenario empresarial
Use la semántica Al menos una vez para apoyar a las empresas que pueden aceptar una pequeña cantidad de mensajes repetidos
At Least Once es la semántica más utilizada, que puede garantizar que los mensajes se envíen y consuman tanto como sea posible, con un buen equilibrio entre rendimiento y confiabilidad, y se puede usar como el modo predeterminado . El lado comercial también puede garantizar la idempotencia agregando una clave principal comercial única al cuerpo del mensaje y garantizar que los mensajes con la misma clave principal comercial solo se procesen una vez en el lado del consumidor.
El uso del soporte semántico Exactamente una vez requiere un fuerte negocio idempotente
La semántica Exactamente una vez se usa generalmente para negocios clave que absolutamente no permiten la repetición. Los casos típicos son escenarios relacionados con pedidos y pagos .
Use la semántica At Most Once para respaldar negocios no críticos
A lo sumo, la semántica se usa generalmente en negocios no críticos , los negocios no son sensibles a la pérdida de mensajes , solo deben tratar de garantizar la producción y el consumo exitosos de mensajes. Un escenario típico donde se usa la semántica At Most Once es la notificación de mensajes , donde una pequeña cantidad de mensajes faltantes tiene poco impacto. Por el contrario, el envío de notificaciones repetidamente causará una experiencia de usuario deficiente.
Mejores prácticas de ajuste de rendimiento
Establezca razonablemente el número de particiones para Tema
A continuación, se resumen las dimensiones que se recomiendan para ajustar el rendimiento a través de particiones. Se recomienda ajustar el rendimiento general del sistema según el análisis teórico y las pruebas de esfuerzo.
Considere las dimensiones | ilustrar |
---|---|
rendimiento | Aumentar el número de particiones puede aumentar la simultaneidad del consumo de mensajes.Cuando el cuello de botella del sistema se encuentra en el extremo de consumo, y el extremo de consumo se puede expandir horizontalmente, aumentar la partición puede aumentar el rendimiento del sistema. Cada partición bajo cada tema en Kafka es un canal de procesamiento de mensajes independiente. Los mensajes en una partición solo pueden ser consumidos por un grupo de consumidores al mismo tiempo. Cuando la cantidad de grupos de consumidores excede la cantidad de particiones, el grupo de consumidores redundante Idle aparecer. |
secuencia de mensajes | Kafka puede garantizar el orden de los mensajes dentro de una partición, pero no se puede garantizar el orden de los mensajes entre particiones. Al agregar particiones, debe considerar el impacto del orden de los mensajes en el negocio. |
Límite superior de partición de instancia | El aumento de la partición consumirá más recursos subyacentes, como memoria, E/S y identificadores de archivos. Al planificar la cantidad de particiones para un tema, debe tener en cuenta el límite superior de particiones que puede admitir el clúster de Kafka. |
Descripción de la relación entre productores, consumidores y particiones.
Establecer razonablemente el tamaño del lote
Si el tema tiene varias particiones, el productor debe confirmar a qué partición enviar el mensaje primero. Al enviar varios mensajes a la misma partición, el cliente productor empaquetará los mensajes relacionados en un lote y los enviará al servidor por lotes. Por lo general, un lote pequeño hará que el cliente Producer genere una gran cantidad de solicitudes, lo que hará que la cola de solicitudes se ponga en cola en el cliente y el servidor, lo que aumentará los retrasos en el envío y el consumo de mensajes en general.
Un tamaño de lote adecuado puede reducir la cantidad de solicitudes iniciadas por el cliente al servidor al enviar mensajes y mejorar el rendimiento y la demora del envío de mensajes en general.
Los parámetros de lote se describen a continuación:
parámetro | ilustrar |
---|---|
batch.size |
La cantidad de mensajes en caché enviados a cada partición (la suma de los bytes del contenido del mensaje, no la cantidad de mensajes). Cuando se alcance el valor establecido, se activará una solicitud de red y luego el cliente Producer enviará mensajes al servidor en lotes. |
linger.ms |
El tiempo máximo que cada mensaje estará en el caché. Si se excede este tiempo, el cliente Producer batch.size ignorará el límite y enviará el mensaje al servidor de inmediato. |
buffer.memory |
Cuando el tamaño total de todos los mensajes en caché supere este valor, el mensaje se enviará al servidor batch.size y linger.ms se ignorarán las restricciones de y. buffer.memory El valor predeterminado es de 32 MB, lo que puede garantizar un rendimiento suficiente para un solo productor. |
No existe un método general para seleccionar valores de parámetros relacionados con el lote. Se recomienda realizar pruebas de presión y ajustes para escenarios comerciales sensibles al rendimiento.
Use particiones pegajosas para manejar envíos masivos
Los productores y servidores de Kafka tienen un mecanismo de envío por lotes al enviar mensajes, y solo los mensajes enviados a la misma partición se colocarán en el mismo lote. En un escenario de envío de lotes grandes, si los mensajes se dispersan en varias particiones, se pueden formar varios lotes pequeños, lo que hace que el mecanismo de envío por lotes falle y reduzca el rendimiento.
La estrategia predeterminada de Kafka para seleccionar particiones es la siguiente
Escenas | Estrategia |
---|---|
Mensaje especificado Clave | Haga un hash de la clave del mensaje y luego seleccione una partición según el resultado del hash para asegurarse de que los mensajes con la misma clave se envíen a la misma partición. |
El mensaje no especifica una Clave | La estrategia predeterminada es recorrer todas las particiones del tema y enviar mensajes a cada partición en forma rotativa. |
Se puede ver en el mecanismo predeterminado que la selección de particiones es muy aleatoria. Por lo tanto, en el escenario de transferencia masiva, se recomienda establecer partitioner.class
el parámetro y especificar un algoritmo de selección de partición personalizado para implementar particiones pegajosas .
Uno de los métodos de implementación es usar la misma partición durante un período de tiempo fijo y cambiar a la siguiente partición después de un período de tiempo para evitar que los datos se dispersen en varias particiones diferentes.
Mejores prácticas generales
Garantía de orden de mensajes de Kafka
Kafka garantizará el orden de los mensajes en la misma partición. Si hay varias particiones en el tema, no se puede garantizar el orden global. Si necesita garantizar el orden global, debe controlar el número de particiones a 1.
Establecer una clave única para el mensaje
El mensaje de la cola de mensajes Kafka tiene dos campos: Clave (identificador del mensaje) y Valor (contenido del mensaje). Para facilitar el seguimiento, se recomienda establecer una clave única para el mensaje. Después de eso, puede rastrear un mensaje a través de Key, imprimir el registro de envío y el registro de consumo, y comprender la producción y el consumo del mensaje.
Establecer razonablemente la estrategia de reintento de la cola
En un entorno distribuido, debido a razones como la red, los mensajes pueden fallar ocasionalmente en el envío.La razón puede ser que el mensaje se envió correctamente pero el mecanismo ACK falló o el mensaje no se envió correctamente. Los parámetros predeterminados pueden cumplir con la mayoría de los escenarios, pero los siguientes parámetros de reintento se pueden configurar según sea necesario según las necesidades del negocio:
parámetro | ilustrar |
---|---|
retries |
El número de reintentos, el valor predeterminado es 3, pero para aplicaciones con tolerancia cero para la pérdida de datos, considere establecerlo en Integer.MAX_VALUE (efectivo y máximo). |
retry.backoff.ms |
Se recomienda establecer el intervalo de reintento en 1000. |
:exclamación: Nota:
Si desea implementar la semántica como máximo una vez, los reintentos deben desactivarse.
Acceda a las mejores prácticas
Conexión de Spark Streaming a Kafka
Spark Streaming es una extensión de Spark Core para el procesamiento tolerante a fallas y de alto rendimiento de datos persistentes. Actualmente, las entradas externas admitidas incluyen Kafka, Flume, HDFS/S3, Kinesis, Twitter y socket TCP.
Spark Streaming abstrae datos continuos en DStream (Flujo discretizado), y DStream consta de una serie de RDD continuos (conjuntos de datos distribuidos elásticos), y cada RDD son datos generados dentro de un cierto intervalo de tiempo. Usar funciones para procesar DStream es en realidad procesar estos RDD.
Cuando se utiliza Spark Streaming como entrada de datos de Kafka, se pueden admitir la versión estable y la versión experimental de Kafka:
Versión Kafka | chispa-streaming-kafka-0.8 | chispa-streaming-kafka-0.10 |
---|---|---|
Versión del corredor | 0.8.2.1 o superior | 0.10.0 o superior |
Madurez API | Obsoleto | Estable |
Ayuda de idioma | Scala, Java, Python | Scala, Java |
Receptor DStream | Sí | No |
Dstream directo | Sí | Sí |
Compatibilidad con SSL/TLS | No | Sí |
Api de confirmación compensada | No | Sí |
Suscripción de tema dinámico | No | Sí |
Esta práctica utiliza la dependencia de Kafka de la versión 0.10.2.1.
Pasos
Paso 1: crear un clúster y un tema de Kafka
Se omiten los pasos para crear un clúster de Kafka y, a continuación, se crea un tema test
denominado .
Paso 2: preparar el entorno del servidor
Sistema Centos6.8
paquete | versión |
---|---|
algo | 0.13.16 |
hadoop | 2.7.3 |
Chispa - chispear | 2.1.0 |
Protobuf | 2.5.0 |
ssh | Instalación predeterminada de CentOS |
Java | 1.8 |
Se omiten los pasos de instalación específicos, incluidos los siguientes pasos:
- instalar sbt
- Instalar protobuf
- Instalar Hadoop
- Instalar chispa
Paso 3: Conéctese a Kafka
Producir mensajes a Kafka
Aquí se utiliza la dependencia de Kafka de la versión 0.10.2.1.
build.sbt
Añadir dependencias en :
name := "Producer Example"
version := "1.0"
scalaVersion := "2.11.8"
libraryDependencies += "org.apache.kafka" % "kafka-clients" % "0.10.2.1"
Configuración
producer_example.scala
:import java.util.Properties import org.apache.kafka.clients.producer._ object ProducerExample extends App { val props = new Properties() props.put("bootstrap.servers", "172.0.0.1:9092") //实例信息中的内网 IP 与端口 props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer") props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer") val producer = new KafkaProducer[String, String](props) val TOPIC="test" //指定要生产的 Topic for(i<- 1 to 50){ val record = new ProducerRecord(TOPIC, "key", s"hello $i") //生产 key 是"key",value 是 hello i 的消息 producer.send(record) } val record = new ProducerRecord(TOPIC, "key", "the end "+new java.util.Date) producer.send(record) producer.close() //最后要断开 }
Para obtener más información sobre el uso de ProducerRecord, consulte la documentación de ProducerRecord .
Consumir mensajes de Kafka
DirectStream
build.sbt
Añadir dependencias en :
name := "Consumer Example"
version := "1.0"
scalaVersion := "2.11.8"
libraryDependencies += "org.apache.spark" %% "spark-core" % "2.1.0"
libraryDependencies += "org.apache.spark" %% "spark-streaming" % "2.1.0"
libraryDependencies += "org.apache.spark" %% "spark-streaming-kafka-0-10" % "2.1.0"
- Configuración
DirectStream_example.scala
:
import org.apache.kafka.clients.consumer.ConsumerRecord
import org.apache.kafka.common.serialization.StringDeserializer
import org.apache.kafka.common.TopicPartition
import org.apache.spark.streaming.kafka010._
import org.apache.spark.streaming.kafka010.LocationStrategies.PreferConsistent
import org.apache.spark.streaming.kafka010.ConsumerStrategies.Subscribe
import org.apache.spark.streaming.kafka010.KafkaUtils
import org.apache.spark.streaming.kafka010.OffsetRange
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import collection.JavaConversions._
import Array._
object Kafka {
def main(args: Array[String]) {
val kafkaParams = Map[String, Object](
"bootstrap.servers" -> "172.0.0.1:9092",
"key.deserializer" -> classOf[StringDeserializer],
"value.deserializer" -> classOf[StringDeserializer],
"group.id" -> "spark_stream_test1",
"auto.offset.reset" -> "earliest",
"enable.auto.commit" -> "false"
)
val sparkConf = new SparkConf()
sparkConf.setMaster("local")
sparkConf.setAppName("Kafka")
val ssc = new StreamingContext(sparkConf, Seconds(5))
val topics = Array("spark_test")
val offsets : Map[TopicPartition, Long] = Map()
for (i <- 0 until 3){
val tp = new TopicPartition("spark_test", i)
offsets.updated(tp , 0L)
}
val stream = KafkaUtils.createDirectStream[String, String](
ssc,
PreferConsistent,
Subscribe[String, String](topics, kafkaParams)
)
println("directStream")
stream.foreachRDD{ rdd=>
//输出获得的消息
rdd.foreach{iter =>
val i = iter.value
println(s"${i}")
}
//获得offset
val offsetRanges = rdd.asInstanceOf[HasOffsetRanges].offsetRanges
rdd.foreachPartition { iter =>
val o: OffsetRange = offsetRanges(TaskContext.get.partitionId)
println(s"${o.topic} ${o.partition} ${o.fromOffset} ${o.untilOffset}")
}
}
// Start the computation
ssc.start()
ssc.awaitTermination()
}
}
RDD
- Configuración
build.sbt
(la configuración es la misma que la anterior, haga clic para ver ). - Configuración
RDD_example
:
import org.apache.kafka.clients.consumer.ConsumerRecord
import org.apache.kafka.common.serialization.StringDeserializer
import org.apache.spark.streaming.kafka010._
import org.apache.spark.streaming.kafka010.LocationStrategies.PreferConsistent
import org.apache.spark.streaming.kafka010.ConsumerStrategies.Subscribe
import org.apache.spark.streaming.kafka010.KafkaUtils
import org.apache.spark.streaming.kafka010.OffsetRange
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import collection.JavaConversions._
import Array._
object Kafka {
def main(args: Array[String]) {
val kafkaParams = Map[String, Object](
"bootstrap.servers" -> "172.0.0.1:9092",
"key.deserializer" -> classOf[StringDeserializer],
"value.deserializer" -> classOf[StringDeserializer],
"group.id" -> "spark_stream",
"auto.offset.reset" -> "earliest",
"enable.auto.commit" -> (false: java.lang.Boolean)
)
val sc = new SparkContext("local", "Kafka", new SparkConf())
val java_kafkaParams : java.util.Map[String, Object] = kafkaParams
//按顺序向 parition 拉取相应 offset 范围的消息,如果拉取不到则阻塞直到超过等待时间或者新生产消息达到拉取的数量
val offsetRanges = Array[OffsetRange](
OffsetRange("spark_test", 0, 0, 5),
OffsetRange("spark_test", 1, 0, 5),
OffsetRange("spark_test", 2, 0, 5)
)
val range = KafkaUtils.createRDD[String, String](
sc,
java_kafkaParams,
offsetRanges,
PreferConsistent
)
range.foreach(rdd=>println(rdd.value))
sc.stop()
}
}
Para más kafkaParams
uso , consulte la documentación de kafkaParams .
Conexión de Flume a Kafka
Apache Flume 是一个分布式、可靠、高可用的日志收集系统,支持各种各样的数据来源(如 HTTP、Log 文件、JMS、监听端口数据等),能将这些数据源的海量日志数据进行高效收集、聚合、移动,最后存储到指定存储系统中(如 Kafka、分布式文件系统、Solr 搜索服务器等)。
Flume 基本结构如下:
Flume 以 agent 为最小的独立运行单位。一个 agent 就是一个 JVM,单个 agent 由 Source、Sink 和 Channel 三大组件构成。
Flume 与 Kafka
把数据存储到 HDFS 或者 HBase 等下游存储模块或者计算模块时需要考虑各种复杂的场景,例如并发写入的量以及系统承载压力、网络延迟等问题。Flume 作为灵活的分布式系统具有多种接口,同时提供可定制化的管道。 在生产处理环节中,当生产与处理速度不一致时,Kafka 可以充当缓存角色。Kafka 拥有 partition 结构以及采用 append 追加数据,使 Kafka 具有优秀的吞吐能力;同时其拥有 replication 结构,使 Kafka 具有很高的容错性。 所以将 Flume 和 Kafka 结合起来,可以满足生产环境中绝大多数要求。
准备工作
- 下载 Apache Flume (1.6.0以上版本兼容 Kafka)
- 下载 Kafka工具包 (0.9.x以上版本,0.8已经不支持)
- 确认 Kafka 的 Source、 Sink 组件已经在 Flume 中。
接入方式
Kafka 可作为 Source 或者 Sink 端对消息进行导入或者导出。
Kafka Source
配置 kafka 作为消息来源,即将自己作为消费者,从 Kafka 中拉取数据传入到指定 Sink 中。主要配置选项如下:
配置项 | 说明 |
---|---|
channels |
自己配置的 Channel |
type |
必须为:org.apache.flume.source.kafka.KafkaSource |
kafka.bootstrap.servers |
Kafka Broker 的服务器地址 |
kafka.consumer.group.id |
作为 Kafka 消费端的 Group ID |
kafka.topics |
Kafka 中数据来源 Topic |
batchSize |
每次写入 Channel 的大小 |
batchDurationMillis |
每次写入最大间隔时间 |
示例:
tier1.sources.source1.type = org.apache.flume.source.kafka.KafkaSource
tier1.sources.source1.channels = channel1
tier1.sources.source1.batchSize = 5000
tier1.sources.source1.batchDurationMillis = 2000
tier1.sources.source1.kafka.bootstrap.servers = localhost:9092
tier1.sources.source1.kafka.topics = test1, test2
tier1.sources.source1.kafka.consumer.group.id = custom.g.id
更多内容请参考 Apache Flume 官网。
Kafka Sink
配置 Kafka 作为内容接收方,即将自己作为生产者,推到 Kafka Server 中等待后续操作。主要配置选项如下:
配置项 | 说明 |
---|---|
channel |
自己配置的 Channel |
type |
必须为:org.apache.flume.sink.kafka.KafkaSink |
kafka.bootstrap.servers |
Kafka Broker 的服务器 |
kafka.topics |
Kafka 中数据来源 Topic |
kafka.flumeBatchSize |
每次写入的 Bacth 大小 |
kafka.producer.acks |
Kafka 生产者的生产策略 |
示例:
a1.sinks.k1.channel = c1
a1.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink
a1.sinks.k1.kafka.topic = mytopic
a1.sinks.k1.kafka.bootstrap.servers = localhost:9092
a1.sinks.k1.kafka.flumeBatchSize = 20
a1.sinks.k1.kafka.producer.acks = 1
更多内容请参考 Apache Flume 官网。
Storm 接入 Kafka
Storm 是一个分布式实时计算框架,能够对数据进行流式处理和提供通用性分布式 RPC 调用,可以实现处理事件亚秒级的延迟,适用于对延迟要求比较高的实时数据处理场景。
Storm 工作原理
在 Storm 的集群中有两种节点,控制节点Master Node
和工作节点Worker Node
。Master Node
上运行Nimbus
进程,用于资源分配与状态监控。Worker Node
上运行Supervisor
进程,监听工作任务,启动executor
执行。整个 Storm 集群依赖zookeeper
负责公共数据存放、集群状态监听、任务分配等功能。
用户提交给 Storm 的数据处理程序称为topology
,它处理的最小消息单位是tuple
,一个任意对象的数组。topology
由spout
和bolt
构成,spout
是产生tuple
的源头,bolt
可以订阅任意spout
或bolt
发出的tuple
进行处理。
Storm with Kafka
Storm 可以把 Kafka 作为spout
,消费数据进行处理;也可以作为bolt
,存放经过处理后的数据提供给其它组件消费。
Centos6.8系统
package | version |
---|---|
maven | 3.5.0 |
storm | 2.1.0 |
ssh | 5.3 |
Java | 1.8 |
前提条件
- 下载并安装 JDK 8。具体操作,请参见 Download JDK 8。
- 下载并安装 Storm,参考 Apache Storm downloads。
- 已创建 Kafka 集群。
操作步骤
步骤1:创建 Topic
步骤2:添加 Maven 依赖
pom.xml 配置如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>storm</groupId>
<artifactId>storm</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>storm</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.storm</groupId>
<artifactId>storm-core</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.storm</groupId>
<artifactId>storm-kafka-client</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka_2.11</artifactId>
<version>0.10.2.1</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>ExclamationTopology</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
步骤3:生产消息
使用 spout/bolt
topology 代码:
//TopologyKafkaProducerSpout.java
import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.StormSubmitter;
import org.apache.storm.kafka.bolt.KafkaBolt;
import org.apache.storm.kafka.bolt.mapper.FieldNameBasedTupleToKafkaMapper;
import org.apache.storm.kafka.bolt.selector.DefaultTopicSelector;
import org.apache.storm.topology.TopologyBuilder;
import org.apache.storm.utils.Utils;
import java.util.Properties;
public class TopologyKafkaProducerSpout {
//申请的kafka实例ip:port
private final static String BOOTSTRAP_SERVERS = "xx.xx.xx.xx:xxxx";
//指定要将消息写入的topic
private final static String TOPIC = "storm_test";
public static void main(String[] args) throws Exception {
//设置producer属性
//函数参考:https://kafka.apache.org/0100/javadoc/index.html?org/apache/kafka/clients/consumer/KafkaConsumer.html
//属性参考:http://kafka.apache.org/0102/documentation.html
Properties properties = new Properties();
properties.put("bootstrap.servers", BOOTSTRAP_SERVERS);
properties.put("acks", "1");
properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
//创建写入kafka的bolt,默认使用fields("key" "message")作为生产消息的key和message,也可以在FieldNameBasedTupleToKafkaMapper()中指定
KafkaBolt kafkaBolt = new KafkaBolt()
.withProducerProperties(properties)
.withTopicSelector(new DefaultTopicSelector(TOPIC))
.withTupleToKafkaMapper(new FieldNameBasedTupleToKafkaMapper());
TopologyBuilder builder = new TopologyBuilder();
//一个顺序生成消息的spout类,输出field是sentence
SerialSentenceSpout spout = new SerialSentenceSpout();
AddMessageKeyBolt bolt = new AddMessageKeyBolt();
builder.setSpout("kafka-spout", spout, 1);
//为tuple加上生产到kafka所需要的fields
builder.setBolt("add-key", bolt, 1).shuffleGrouping("kafka-spout");
//写入kafka
builder.setBolt("sendToKafka", kafkaBolt, 8).shuffleGrouping("add-key");
Config config = new Config();
if (args != null && args.length > 0) {
//集群模式,用于打包jar,并放到storm运行
config.setNumWorkers(1);
StormSubmitter.submitTopologyWithProgressBar(args[0], config, builder.createTopology());
} else {
//本地模式
LocalCluster cluster = new LocalCluster();
cluster.submitTopology("test", config, builder.createTopology());
Utils.sleep(10000);
cluster.killTopology("test");
cluster.shutdown();
}
}
}
创建一个顺序生成消息的 spout 类:
import org.apache.storm.spout.SpoutOutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.base.BaseRichSpout;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Values;
import org.apache.storm.utils.Utils;
import java.util.Map;
import java.util.UUID;
public class SerialSentenceSpout extends BaseRichSpout {
private SpoutOutputCollector spoutOutputCollector;
@Override
public void open(Map map, TopologyContext topologyContext, SpoutOutputCollector spoutOutputCollector) {
this.spoutOutputCollector = spoutOutputCollector;
}
@Override
public void nextTuple() {
Utils.sleep(1000);
//生产一个UUID字符串发送给下一个组件
spoutOutputCollector.emit(new Values(UUID.randomUUID().toString()));
}
@Override
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
outputFieldsDeclarer.declare(new Fields("sentence"));
}
}
为 tuple
加上 key、message 两个字段,当 key 为 null 时,生产的消息均匀分配到各个 partition,指定了 key 后将按照 key 值 hash 到特定 partition 上:
//AddMessageKeyBolt.java
import org.apache.storm.topology.BasicOutputCollector;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.base.BaseBasicBolt;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Tuple;
import org.apache.storm.tuple.Values;
public class AddMessageKeyBolt extends BaseBasicBolt {
@Override
public void execute(Tuple tuple, BasicOutputCollector basicOutputCollector) {
//取出第一个filed值
String messae = tuple.getString(0);
//System.out.println(messae);
//发送给下一个组件
basicOutputCollector.emit(new Values(null, messae));
}
@Override
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
//创建发送给下一个组件的schema
outputFieldsDeclarer.declare(new Fields("key", "message"));
}
}
使用 trident
使用 trident 类生成 topology:
//TopologyKafkaProducerTrident.java
import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.StormSubmitter;
import org.apache.storm.kafka.trident.TridentKafkaStateFactory;
import org.apache.storm.kafka.trident.TridentKafkaStateUpdater;
import org.apache.storm.kafka.trident.mapper.FieldNameBasedTupleToKafkaMapper;
import org.apache.storm.kafka.trident.selector.DefaultTopicSelector;
import org.apache.storm.trident.TridentTopology;
import org.apache.storm.trident.operation.BaseFunction;
import org.apache.storm.trident.operation.TridentCollector;
import org.apache.storm.trident.tuple.TridentTuple;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Values;
import org.apache.storm.utils.Utils;
import java.util.Properties;
public class TopologyKafkaProducerTrident {
//申请的kafka实例ip:port
private final static String BOOTSTRAP_SERVERS = "xx.xx.xx.xx:xxxx";
//指定要将消息写入的topic
private final static String TOPIC = "storm_test";
public static void main(String[] args) throws Exception {
//设置producer属性
//函数参考:https://kafka.apache.org/0100/javadoc/index.html?org/apache/kafka/clients/consumer/KafkaConsumer.html
//属性参考:http://kafka.apache.org/0102/documentation.html
Properties properties = new Properties();
properties.put("bootstrap.servers", BOOTSTRAP_SERVERS);
properties.put("acks", "1");
properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
//设置Trident
TridentKafkaStateFactory stateFactory = new TridentKafkaStateFactory()
.withProducerProperties(properties)
.withKafkaTopicSelector(new DefaultTopicSelector(TOPIC))
//设置使用fields("key", "value")作为消息写入 不像FieldNameBasedTupleToKafkaMapper有默认值
.withTridentTupleToKafkaMapper(new FieldNameBasedTupleToKafkaMapper("key", "value"));
TridentTopology builder = new TridentTopology();
//一个批量产生句子的spout,输出field为sentence
builder.newStream("kafka-spout", new TridentSerialSentenceSpout(5))
.each(new Fields("sentence"), new AddMessageKey(), new Fields("key", "value"))
.partitionPersist(stateFactory, new Fields("key", "value"), new TridentKafkaStateUpdater(), new Fields());
Config config = new Config();
if (args != null && args.length > 0) {
//集群模式,用于打包jar,并放到storm运行
config.setNumWorkers(1);
StormSubmitter.submitTopologyWithProgressBar(args[0], config, builder.build());
} else {
//本地模式
LocalCluster cluster = new LocalCluster();
cluster.submitTopology("test", config, builder.build());
Utils.sleep(10000);
cluster.killTopology("test");
cluster.shutdown();
}
}
private static class AddMessageKey extends BaseFunction {
@Override
public void execute(TridentTuple tridentTuple, TridentCollector tridentCollector) {
//取出第一个filed值
String messae = tridentTuple.getString(0);
//System.out.println(messae);
//发送给下一个组件
//tridentCollector.emit(new Values(Integer.toString(messae.hashCode()), messae));
tridentCollector.emit(new Values(null, messae));
}
}
}
创建一个批量生成消息的 spout 类:
//TridentSerialSentenceSpout.java
import org.apache.storm.Config;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.trident.operation.TridentCollector;
import org.apache.storm.trident.spout.IBatchSpout;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Values;
import org.apache.storm.utils.Utils;
import java.util.Map;
import java.util.UUID;
public class TridentSerialSentenceSpout implements IBatchSpout {
private final int batchCount;
public TridentSerialSentenceSpout(int batchCount) {
this.batchCount = batchCount;
}
@Override
public void open(Map map, TopologyContext topologyContext) {
}
@Override
public void emitBatch(long l, TridentCollector tridentCollector) {
Utils.sleep(1000);
for(int i = 0; i < batchCount; i++){
tridentCollector.emit(new Values(UUID.randomUUID().toString()));
}
}
@Override
public void ack(long l) {
}
@Override
public void close() {
}
@Override
public Map<String, Object> getComponentConfiguration() {
Config conf = new Config();
conf.setMaxTaskParallelism(1);
return conf;
}
@Override
public Fields getOutputFields() {
return new Fields("sentence");
}
}
步骤4:消费消息
使用 spout/bolt
//TopologyKafkaConsumerSpout.java
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.StormSubmitter;
import org.apache.storm.kafka.spout.*;
import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.TopologyBuilder;
import org.apache.storm.topology.base.BaseRichBolt;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Tuple;
import org.apache.storm.tuple.Values;
import org.apache.storm.utils.Utils;
import java.util.HashMap;
import java.util.Map;
import static org.apache.storm.kafka.spout.FirstPollOffsetStrategy.LATEST;
public class TopologyKafkaConsumerSpout {
//申请的kafka实例ip:port
private final static String BOOTSTRAP_SERVERS = "xx.xx.xx.xx:xxxx";
//指定要将消息写入的topic
private final static String TOPIC = "storm_test";
public static void main(String[] args) throws Exception {
//设置重试策略
KafkaSpoutRetryService kafkaSpoutRetryService = new KafkaSpoutRetryExponentialBackoff(
KafkaSpoutRetryExponentialBackoff.TimeInterval.microSeconds(500),
KafkaSpoutRetryExponentialBackoff.TimeInterval.milliSeconds(2),
Integer.MAX_VALUE,
KafkaSpoutRetryExponentialBackoff.TimeInterval.seconds(10)
);
ByTopicRecordTranslator<String, String> trans = new ByTopicRecordTranslator<>(
(r) -> new Values(r.topic(), r.partition(), r.offset(), r.key(), r.value()),
new Fields("topic", "partition", "offset", "key", "value"));
//设置consumer参数
//函数参考http://storm.apache.org/releases/1.1.0/javadocs/org/apache/storm/kafka/spout/KafkaSpoutConfig.Builder.html
//参数参考http://kafka.apache.org/0102/documentation.html
KafkaSpoutConfig spoutConfig = KafkaSpoutConfig.builder(BOOTSTRAP_SERVERS, TOPIC)
.setProp(new HashMap<String, Object>(){
{
put(ConsumerConfig.GROUP_ID_CONFIG, "test-group1"); //设置group
put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, "50000"); //设置session超时
put(ConsumerConfig.REQUEST_TIMEOUT_MS_CONFIG, "60000"); //设置请求超时
}})
.setOffsetCommitPeriodMs(10_000) //设置自动确认时间
.setFirstPollOffsetStrategy(LATEST) //设置拉取最新消息
.setRetry(kafkaSpoutRetryService)
.setRecordTranslator(trans)
.build();
TopologyBuilder builder = new TopologyBuilder();
builder.setSpout("kafka-spout", new KafkaSpout(spoutConfig), 1);
builder.setBolt("bolt", new BaseRichBolt(){
private OutputCollector outputCollector;
@Override
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
}
@Override
public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) {
this.outputCollector = outputCollector;
}
@Override
public void execute(Tuple tuple) {
System.out.println(tuple.getStringByField("value"));
outputCollector.ack(tuple);
}
}, 1).shuffleGrouping("kafka-spout");
Config config = new Config();
config.setMaxSpoutPending(20);
if (args != null && args.length > 0) {
config.setNumWorkers(3);
StormSubmitter.submitTopologyWithProgressBar(args[0], config, builder.createTopology());
}
else {
LocalCluster cluster = new LocalCluster();
cluster.submitTopology("test", config, builder.createTopology());
Utils.sleep(20000);
cluster.killTopology("test");
cluster.shutdown();
}
}
}
使用 trident
//TopologyKafkaConsumerTrident.java
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.StormSubmitter;
import org.apache.storm.generated.StormTopology;
import org.apache.storm.kafka.spout.ByTopicRecordTranslator;
import org.apache.storm.kafka.spout.trident.KafkaTridentSpoutConfig;
import org.apache.storm.kafka.spout.trident.KafkaTridentSpoutOpaque;
import org.apache.storm.trident.Stream;
import org.apache.storm.trident.TridentTopology;
import org.apache.storm.trident.operation.BaseFunction;
import org.apache.storm.trident.operation.TridentCollector;
import org.apache.storm.trident.tuple.TridentTuple;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Values;
import org.apache.storm.utils.Utils;
import java.util.HashMap;
import static org.apache.storm.kafka.spout.FirstPollOffsetStrategy.LATEST;
public class TopologyKafkaConsumerTrident {
//申请的kafka实例ip:port
private final static String BOOTSTRAP_SERVERS = "xx.xx.xx.xx:xxxx";
//指定要将消息写入的topic
private final static String TOPIC = "storm_test";
public static void main(String[] args) throws Exception {
ByTopicRecordTranslator<String, String> trans = new ByTopicRecordTranslator<>(
(r) -> new Values(r.topic(), r.partition(), r.offset(), r.key(), r.value()),
new Fields("topic", "partition", "offset", "key", "value"));
//设置consumer参数
//函数参考http://storm.apache.org/releases/1.1.0/javadocs/org/apache/storm/kafka/spout/KafkaSpoutConfig.Builder.html
//参数参考http://kafka.apache.org/0102/documentation.html
KafkaTridentSpoutConfig spoutConfig = KafkaTridentSpoutConfig.builder(BOOTSTRAP_SERVERS, TOPIC)
.setProp(new HashMap<String, Object>(){
{
put(ConsumerConfig.GROUP_ID_CONFIG, "test-group1"); //设置group
put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "true"); //设置自动确认
put(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG, "50000"); //设置session超时
put(ConsumerConfig.REQUEST_TIMEOUT_MS_CONFIG, "60000"); //设置请求超时
}})
.setFirstPollOffsetStrategy(LATEST) //设置拉取最新消息
.setRecordTranslator(trans)
.build();
TridentTopology builder = new TridentTopology();
// Stream spoutStream = builder.newStream("spout", new KafkaTridentSpoutTransactional(spoutConfig)); //事务型
Stream spoutStream = builder.newStream("spout", new KafkaTridentSpoutOpaque(spoutConfig));
spoutStream.each(spoutStream.getOutputFields(), new BaseFunction(){
@Override
public void execute(TridentTuple tridentTuple, TridentCollector tridentCollector) {
System.out.println(tridentTuple.getStringByField("value"));
tridentCollector.emit(new Values(tridentTuple.getStringByField("value")));
}
}, new Fields("message"));
Config conf = new Config();
conf.setMaxSpoutPending(20);conf.setNumWorkers(1);
if (args != null && args.length > 0) {
conf.setNumWorkers(3);
StormSubmitter.submitTopologyWithProgressBar(args[0], conf, builder.build());
}
else {
StormTopology stormTopology = builder.build();
LocalCluster cluster = new LocalCluster();
cluster.submitTopology("test", conf, stormTopology);
Utils.sleep(10000);
cluster.killTopology("test");
cluster.shutdown();stormTopology.clear();
}
}
}
步骤5:提交 Storm
使用 mvn package
编译后,可以提交到本地集群进行 debug 测试,也可以提交到正式集群进行运行。
storm jar your_jar_name.jar topology_name
storm jar your_jar_name.jar topology_name tast_name
Logstash 接入 Kafka
Logstash 是一个开源的日志处理工具,可以从多个源头收集数据、过滤收集的数据并对数据进行存储作为其他用途。
Logstash 灵活性强,拥有强大的语法分析功能,插件丰富,支持多种输入和输出源。Logstash 作为水平可伸缩的数据管道,与 Elasticsearch 和 Kibana 配合,在日志收集检索方面功能强大。
Logstash 工作原理
Logstash 数据处理可以分为三个阶段:inputs → filters → outputs。
- inputs:产生数据来源,例如文件、syslog、redis 和 beats 此类来源。
- filters:修改过滤数据, 在 Logstash 数据管道中属于中间环节,可以根据条件去对事件进行更改。一些常见的过滤器包括:grok、mutate、drop 和 clone 等。
- outputs:将数据传输到其他地方,一个事件可以传输到多个 outputs,当传输完成后这个事件就结束。Elasticsearch 就是最常见的 outputs。
同时 Logstash 支持编码解码,可以在 inputs 和 outputs 端指定格式。
Logstash 接入 Kafka 的优势
- 可以异步处理数据:防止突发流量。
- 解耦:当 Elasticsearch 异常的时候不会影响上游工作。
:exclamation: 注意: Logstash 过滤消耗资源,如果部署在生产 server 上会影响其性能。
操作步骤
准备工作
- 下载并安装 Logstash,参考 Download Logstash。
- 下载并安装 JDK 8,参考 Download JDK 8。
- 已创建 Kafka 集群。
步骤1:创建 Topic
创建一个名为 logstash_test
的 Topic。
步骤2:接入 Kafka
作为 inputs 接入
执行
bin/logstash-plugin list
,查看已经支持的插件是否含有logstash-input-kafka
。在
.bin/
目录下编写配置文件input.conf
。 此处将标准输出作为数据终点,将 Kafka 作为数据来源。input { kafka { bootstrap_servers => "xx.xx.xx.xx:xxxx" // kafka 实例接入地址 group_id => "logstash_group" // kafka groupid 名称 topics => ["logstash_test"] // kafka topic 名称 consumer_threads => 3 // 消费线程数,一般与 kafka 分区数一致 auto_offset_reset => "earliest" } } output { stdout{codec=>rubydebug} }
执行以下命令启动 Logstash,进行消息消费。
./logstash -f input.conf
会看到刚才 Topic 中的数据被消费出来。
作为 outputs 接入
执行
bin/logstash-plugin list
,查看已经支持的插件是否含有logstash-output-kafka
。在.
bin/
目录下编写配置文件output.conf
。 此处将标准输入作为数据来源,将 Kafka 作为数据目的地。input { input { stdin{} } } output { kafka { bootstrap_servers => "xx.xx.xx.xx:xxxx" // ckafka 实例接入地址 topic_id => "logstash_test" // ckafka topic 名称 } }
执行如下命令启动 Logstash,向创建的 Topic 发送消息。
./logstash -f output.conf
启动 Kafka 消费者,检验上一步的生产数据。
./kafka-console-consumer.sh --bootstrap-server 172.0.0.1:9092 --topic logstash_test --from-begging --new-consumer
Filebeats 接入 Kafka
Beats 平台 集合了多种单一用途数据采集器。这些采集器安装后可用作轻量型代理,从成百上千或成千上万台机器向目标发送采集数据。 Beats 有多种采集器,您可以根据自身的需求下载对应的采集器。本文以 Filebeat(轻量型日志采集器)为例,向您介绍 Filebeat 接入 Kafka 的操作指方法,及接入后常见问题的解决方法。
前提条件
- 下载并安装 Filebeat(参见 Download Filebeat)
- 下载并安装JDK 8(参见 Download JDK 8)
- 已 创建 Kafka 集群
操作步骤
步骤1:创建 Topic
创建一个名为 test
的 Topic。
步骤2:准备配置文件
进入 Filebeat 的安装目录,创建配置监控文件 filebeat.yml。
#======= Filebeat prospectors ==========
filebeat.prospectors:
- input_type: log
# 此处为监听文件路径
paths:
- /var/log/messages
#======= Outputs =========
#------------------ kafka -------------------------------------
output.kafka:
version:0.10.2 // 根据不同 Kafka 集群版本配置
# 设置为Kafka实例的接入地址
hosts: ["xx.xx.xx.xx:xxxx"]
# 设置目标topic的名称
topic: 'test'
partition.round_robin:
reachable_only: false
required_acks: 1
compression: none
max_message_bytes: 1000000
# SASL 需要配置下列信息,如果不需要则下面两个选项可不配置
username: "yourinstance#yourusername" //username 需要拼接实例ID和用户名
password: "yourpassword"
步骤4:Filebeat 发送消息
执行如下命令启动客户端。
sudo ./filebeat -e -c filebeat.yml
为监控文件增加数据(示例为写入监听的 testlog 文件)。
echo ckafka1 >> testlog echo ckafka2 >> testlog echo ckafka3 >> testlog
开启 Consumer 消费对应的 Topic,获得以下数据。
{"@timestamp":"2017-09-29T10:01:27.936Z","beat":{"hostname":"10.193.9.26","name":"10.193.9.26","version":"5.6.2"},"input_type":"log","message":"ckafka1","offset":500,"source":"/data/ryanyyang/hcmq/beats/filebeat-5.6.2-linux-x86_64/testlog","type":"log"} {"@timestamp":"2017-09-29T10:01:30.936Z","beat":{"hostname":"10.193.9.26","name":"10.193.9.26","version":"5.6.2"},"input_type":"log","message":"ckafka2","offset":508,"source":"/data/ryanyyang/hcmq/beats/filebeat-5.6.2-linux-x86_64/testlog","type":"log"} {"@timestamp":"2017-09-29T10:01:33.937Z","beat":{"hostname":"10.193.9.26","name":"10.193.9.26","version":"5.6.2"},"input_type":"log","message":"ckafka3","offset":516,"source":"/data/ryanyyang/hcmq/beats/filebeat-5.6.2-linux-x86_64/testlog","type":"log"}
SASL/PLAINTEXT 模式
如果您需要进行 SALS/PLAINTEXT 配置,则需要配置用户名与密码。 在 Kafka 配置区域新增加 username 和 password 配置即可。
参考链接
消息队列 CKafka - 文档中心 - 腾讯云 (tencent.com)
Tres personas caminan juntas, debe ser mi maestro, el intercambio de conocimientos, el mundo es para el público. Este artículo está escrito por el blog técnico de Dongfeng Weiming EWhisper.cn .