Prácticas recomendadas de Kafka

prefacio

Las mejores prácticas de Kafka, que involucran

  1. Escenarios de uso típicos
  2. 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.

Flujo de datos de Kafka

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.

fluentd-kafka-es

fluentd-kafka-logstash

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:

borde-centro-de-datos-nube

puerta de enlace kafka

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.commitparámetro debe establecerse Falsepara 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 = 0y 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.commitpará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_committedy otra vez enable.auto.commit = falsepara 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.

grupos_kafka

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.sizeignorará 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.sizey linger.msse ignorarán las restricciones de y. buffer.memoryEl 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.classel 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.texto alternativo

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.texto alternativo

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 No
Dstream directo
Compatibilidad con SSL/TLS No
Api de confirmación compensada No
Suscripción de tema dinámico No

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 testdenominado .

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:

  1. instalar sbt
  2. Instalar protobuf
  3. Instalar Hadoop
  4. 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.

  1. build.sbtAñadir dependencias en :
name := "Producer Example"
version := "1.0"
scalaVersion := "2.11.8"
libraryDependencies += "org.apache.kafka" % "kafka-clients" % "0.10.2.1"
  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
  1. build.sbtAñ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"
  1. 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
  1. Configuración build.sbt(la configuración es la misma que la anterior, haga clic para ver ).
  2. 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 kafkaParamsuso , 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 NodeMaster Node上运行Nimbus进程,用于资源分配与状态监控。Worker Node上运行Supervisor进程,监听工作任务,启动executor执行。整个 Storm 集群依赖zookeeper负责公共数据存放、集群状态监听、任务分配等功能。

用户提交给 Storm 的数据处理程序称为topology,它处理的最小消息单位是tuple,一个任意对象的数组。topologyspoutbolt构成,spout是产生tuple的源头,bolt可以订阅任意spoutbolt发出的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

前提条件

操作步骤

步骤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。

  1. inputs:产生数据来源,例如文件、syslog、redis 和 beats 此类来源。
  2. filters:修改过滤数据, 在 Logstash 数据管道中属于中间环节,可以根据条件去对事件进行更改。一些常见的过滤器包括:grok、mutate、drop 和 clone 等。
  3. outputs:将数据传输到其他地方,一个事件可以传输到多个 outputs,当传输完成后这个事件就结束。Elasticsearch 就是最常见的 outputs。

同时 Logstash 支持编码解码,可以在 inputs 和 outputs 端指定格式。

Logstash 接入 Kafka 的优势

  • 可以异步处理数据:防止突发流量。
  • 解耦:当 Elasticsearch 异常的时候不会影响上游工作。

:exclamation: 注意:​ Logstash 过滤消耗资源,如果部署在生产 server 上会影响其性能。

操作步骤

准备工作

步骤1:创建 Topic

创建一个名为 logstash_test的 Topic。

步骤2:接入 Kafka

作为 inputs 接入
  1. 执行 bin/logstash-plugin list,查看已经支持的插件是否含有 logstash-input-kafka

  2. .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}
    }
  3. 执行以下命令启动 Logstash,进行消息消费。

    ./logstash -f input.conf

会看到刚才 Topic 中的数据被消费出来。

作为 outputs 接入
  1. 执行 bin/logstash-plugin list,查看已经支持的插件是否含有 logstash-output-kafka

  2. 在.bin/目录下编写配置文件 output.conf。 此处将标准输入作为数据来源,将 Kafka 作为数据目的地。

    input {
        input {
          stdin{}
      }
    }
    
    output {
       kafka {
            bootstrap_servers => "xx.xx.xx.xx:xxxx"  // ckafka 实例接入地址
            topic_id => "logstash_test" // ckafka topic 名称
           }
    }
  3. 执行如下命令启动 Logstash,向创建的 Topic 发送消息。

    ./logstash -f output.conf
  4. 启动 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 的操作指方法,及接入后常见问题的解决方法。

前提条件

操作步骤

步骤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 发送消息

  1. 执行如下命令启动客户端。

    sudo ./filebeat -e -c filebeat.yml 
  2. 为监控文件增加数据(示例为写入监听的 testlog 文件)。

    echo ckafka1 >> testlog
    echo ckafka2 >> testlog
    echo ckafka3 >> testlog
  3. 开启 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 .

Supongo que te gusta

Origin blog.csdn.net/east4ming/article/details/129485758
Recomendado
Clasificación