kafka接入学习

本文介绍如何搭建Kafka集群,并实现Flume与Kafka的集成,包括配置指南及性能评估。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

什么是kafka?

Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的行动)是在现代网络上的许多社会功能的一个关键因素。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。 对于像Hadoop的一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。Kafka的目的是通过Hadoop的并行加载机制来统一线上和离线的消息处理,也是为了通过集群机来提供实时的消费。

kafka有哪些优点?

1.它是一种高容错的消息发布订阅系统(因为它的数据是持久化到硬盘,可以重复读取)

2.它是高效率,有很大的吞吐量

3.它的扩展性极高,是用zookeeper集群来管理Consumer和Broker节点的动态加入与退出

4.支持实时流的方式传输数据


怎么样使用kafka?

1.首先要配置一下zookeeper的集群,这里是配置一下Zookeeper.properties

  1. #记录节点的信息已经Kafka节点和Consumer的一些值  
  2. dataDir=/data/zookeeper  
  3. # the port at which the clients will connect  
  4. #占用到的端口  
  5. clientPort=2181  
  6. # disable the per-ip limit on the number of connections since this is a non-production config  
  7. maxClientCnxns=0  
  8. #心跳最长时间确定节点的存活  
  9. tickTime=2000  
  10. syncLimit=2  
  11. #初始尝试最多链接5次  
  12. initLimit=5  
  13. #集群配置  
  14. server.1=192.168.196.138:2888:3888  
  15. server.2=192.168.196.140:2888:3888  
  16. server.3=192.168.196.139:2888:3888  

2.然后在配置kafka的broker的节点,这边是配置Conf里面的Server.properties文件

  1. broker.id=0  #broker的唯一标识,集群中也不能一样  
  2. port=9092 #broker用到的端口  
  3. num.network.threads=2  
  4. num.io.threads=8 #开启多少线程同时在执行IO数据持久化  
  5. socket.send.buffer.bytes=1048576   #数据接受的缓冲大小  
  6. socket.receive.buffer.bytes=1048576  #消费时发出去的缓冲大小  
  7. socket.request.max.bytes=104857600  #一个请求会接受的最大数据量  
  8. log.dirs=/tmp/kafka-logs   #日志的打印目录  
  9. num.partitions=2  #Topic默认的分区数  
  10. log.retention.hours=168   
  11. log.segment.bytes=536870912  
  12. log.retention.check.interval.ms=60000  
  13. log.cleaner.enable=false  
  14. zookeeper.connect=localhost:2181,192.168.196.140:2181,192.168.196.139:2181  #zookeeper集群配置  
  15. zookeeper.connection.timeout.ms=1000000    
  16. host.name=192.168.196.138  #hostname  
  17. delete.topic.enable=true  #配置这个参数删除Topic的时候同时也会删除数据   

3.启动zookeeper集群

  1. ./bin/zookeeper-server-start.sh ./conf/zookeeper.properties  

4.启动kafk的Broker节点

  1. ./bin/kafka-server-start.sh ./conf/server.properties  

5.创建Topic

  1. ./bin/kafka-topics.sh --create --zookeeper Master:2181 --replication-factor 2 --partitions 2 --topic test-topic  

6.可以查看以下kafka集群中存在的Topic

  1. ./bin/kafka-topics.sh --list --zookeeper 192.168.196.138:2181  
  1. ./bin/kafka-topics.sh --describe --zookeeper Master:2181--topic test-topic  #查看某一个分区的具体情况  

7.Flume数据源传输数据到Kafka

KafkaSink的代码:这边还需要把要用到的包引入到Flume底下的lib文件夹,具体的包可以在我的百度云盘下载:点击打开链接这里面解压后又一个lib里面的所有包都拷贝进去。

  1. package org.apache.flume.plugins;  
  2.   
  3. /** 
  4.  * KAFKA Flume Sink (Kafka 0.8 Beta, Flume 1.5). 
  5.  * User: YiYongWu 
  6.  * Date: 2016/03/28 
  7.  * Time: PM 4:32 
  8.  */  
  9.   
  10. import java.util.Properties;  
  11.   
  12. import kafka.javaapi.producer.Producer;  
  13. import kafka.producer.KeyedMessage;  
  14. import kafka.producer.ProducerConfig;  
  15.   
  16. import org.apache.commons.lang.StringUtils;  
  17. import org.apache.flume.*;  
  18. import org.apache.flume.conf.Configurable;  
  19. import org.apache.flume.event.EventHelper;  
  20. import org.apache.flume.sink.AbstractSink;  
  21. import org.slf4j.Logger;  
  22. import org.slf4j.LoggerFactory;  
  23.   
  24. import com.google.common.base.Preconditions;  
  25. import com.google.common.collect.ImmutableMap;  
  26.   
  27. /** 
  28.  * kafka sink. 
  29.  */  
  30. public class KafkaSink extends AbstractSink implements Configurable {  
  31.   
  32.     /** 
  33.      * 日志记录 
  34.      */  
  35.     private static final Logger LOGGER = LoggerFactory.getLogger(KafkaSink.class);  
  36.   
  37.     /** 
  38.      * 参数 
  39.      */  
  40.     private Properties parameters;  
  41.     /** 
  42.      * 生产者 
  43.      */  
  44.     private Producer<String, String> producer;  
  45.     /** 
  46.      * The Context.上下文 
  47.      */  
  48.     private Context context;  
  49.   
  50.     /** 
  51.      * Configure void. 参数设置 
  52.      *  
  53.      * @param context 
  54.      *            the context 
  55.      */  
  56.     @Override  
  57.     public void configure(Context context) {  
  58.         this.context = context;  
  59.         ImmutableMap<String, String> props = context.getParameters();  
  60.   
  61.         parameters = new Properties();  
  62.         for (String key : props.keySet()) {  
  63.             String value = props.get(key);  
  64.             this.parameters.put(key, value);  
  65.         }  
  66.     }  
  67.     /** 
  68.      * Start void. 
  69.      */  
  70.     @Override  
  71.     public synchronized void start() {  
  72.         super.start();  
  73.         ProducerConfig config = new ProducerConfig(this.parameters);  
  74.         this.producer = new Producer<String, String>(config);  
  75.     }  
  76.   
  77.     /** 
  78.      * Process status. 
  79.      *  
  80.      * @return the status 
  81.      * @throws EventDeliveryException 
  82.      *             the event delivery exception 
  83.      */  
  84.     @Override  
  85.     public Status process() throws EventDeliveryException {  
  86.         Status status = null;  
  87.   
  88.         // Start transaction  
  89.         Channel ch = getChannel();  
  90.         Transaction txn = ch.getTransaction();  
  91.         txn.begin();  
  92.         try {  
  93.             // This try clause includes whatever Channel operations you want to do  
  94.             Event event = ch.take();  
  95.   
  96.             String partitionKey = (String) parameters.get(KafkaFlumeConstans.PARTITION_KEY_NAME);  
  97.             String encoding = StringUtils.defaultIfEmpty(  
  98.                     (String) this.parameters.get(KafkaFlumeConstans.ENCODING_KEY_NAME),  
  99.                     KafkaFlumeConstans.DEFAULT_ENCODING);  
  100.             String topic = Preconditions.checkNotNull(  
  101.                     (String) this.parameters.get(KafkaFlumeConstans.CUSTOME_TOPIC_KEY_NAME),  
  102.                     "custom.topic.name is required");  
  103.   
  104.             String eventData = new String(event.getBody(), encoding);  
  105.   
  106.             KeyedMessage<String, String> data;  
  107.   
  108.             // if partition key does'nt exist  
  109.             if (StringUtils.isEmpty(partitionKey)) {  
  110.                 data = new KeyedMessage<String, String>(topic, eventData);  
  111.             } else {  
  112.                 data = new KeyedMessage<String, String>(topic, partitionKey, eventData);  
  113.             }  
  114.   
  115.             if (LOGGER.isInfoEnabled()) {  
  116.                 LOGGER.info("Send Message to Kafka : [" + eventData + "] -- [" + EventHelper.dumpEvent(event) + "]");  
  117.             }  
  118.   
  119.             producer.send(data);  
  120.             txn.commit();  
  121.             status = Status.READY;  
  122.         } catch (Throwable t) {  
  123.             txn.rollback();  
  124.             status = Status.BACKOFF;  
  125.   
  126.             // re-throw all Errors  
  127.             if (t instanceof Error) {  
  128.                 throw (Error) t;  
  129.             }  
  130.         } finally {  
  131.             txn.close();  
  132.         }  
  133.         return status;  
  134.     }  
  135.   
  136.     /** 
  137.      * Stop void. 
  138.      */  
  139.     @Override  
  140.     public void stop() {  
  141.         producer.close();  
  142.     }  
  143. }  


还要写一个分区策略,简单的分区策略SinglePartition
  1. @Override  
  2.    public int partition(Object key, int numPartitions) {  
  3.        try {  
  4.            int partitionNum = Integer.parseInt((String) key);  
  5.            return Math.abs(Integer.parseInt((String) key) % numPartitions);  
  6.        } catch (Exception e) {  
  7.            return Math.abs(key.hashCode() % numPartitions);  
  8.        }  
  9.    }  


8.写kafka消费着去消费集群中所在Topic的数据.

1.Consumer所需要用到的静态配置数据

  1. package com.yiyong.kafka;  
  2.   
  3. /** 
  4.  * Created by root on 16-3-13. 
  5.  */  
  6. public class KafkaProperties {  
  7.     public final static String zkConnect="192.168.196.138:2181,192.168.196.139:2181,192.168.196.140:2181";  
  8.     public final static String groupId="group1";  
  9.     public final static String groupId2="group2";  
  10.     public final static String topic="kafkaToptic";  
  11.     public final static int kafkaProduceBufferSize=64*1024;  
  12.     public final static int connectionTimeOut=20000;  
  13.     public final static int reconnectInterval=10000;  
  14.     public final static String topic2="topic2";  
  15.     public final static String topic3="topic3";  
  16.   
  17.   
  18. }  
2.消费者的具体实现
  1. package com.yiyong.kafka;  
  2.   
  3. import kafka.consumer.ConsumerConfig;  
  4. import kafka.consumer.ConsumerIterator;  
  5. import kafka.consumer.KafkaStream;  
  6. import kafka.javaapi.consumer.ConsumerConnector;  
  7.   
  8. import java.util.HashMap;  
  9. import java.util.List;  
  10. import java.util.Map;  
  11. import java.util.Properties;  
  12.   
  13. /** 
  14.  * Created by root on 16-3-14. 
  15.  */  
  16. public class KafkaConsumer2 extends Thread {  
  17.   
  18.     private final String topic;  
  19.     private final ConsumerConnector consumer;  
  20.     public KafkaConsumer2(String topic){  
  21.         consumer = kafka.consumer.Consumer.createJavaConsumerConnector(createConsumerConfig());  
  22.   
  23.         this.topic = topic;  
  24.     }  
  25.   
  26.     private static ConsumerConfig createConsumerConfig(){  
  27.         Properties props = new Properties();  
  28.         props.put("zookeeper.connect",KafkaProperties.zkConnect);  
  29.         props.put("group.id",KafkaProperties.groupId2);  
  30.         props.put("zookeeper.session.timeout.ms","40000");  
  31.         props.put("zookeeper.sync.time.ms","200");  
  32.         props.put("auto.commit.interval.ms","1000");  
  33.   
  34.         return new ConsumerConfig(props);  
  35.     }  
  36.   
  37.     @Override  
  38.     public void run() {  
  39.         Map<String,Integer> topicCountMap = new HashMap<String,Integer>();  
  40.         topicCountMap.put(topic, new Integer(1));  
  41.         Map<String,List<KafkaStream<byte[],byte[]>>> consumerMap = consumer.createMessageStreams(topicCountMap);  
  42.         KafkaStream<byte[],byte[]> stream = consumerMap.get(topic).get(0);  
  43.         ConsumerIterator<byte[],byte[]> it = stream.iterator();  
  44.         while(it.hasNext()){  
  45.             System.out.println("receiced:"+new String(it.next().message()));  
  46.             try {  
  47.                 sleep(3000);  
  48.             }catch(InterruptedException e){  
  49.                 e.printStackTrace();  
  50.             }  
  51.         }  
  52.   
  53.     }  
  54. }  

这里还需要把用到的Kafka相关的包给引进来,直接用maven引进就可以,下次直接补充。

我的海量日志采集架构

我这边实现一个海量日志采集平台,主要是利用Flume采集服务平台的实时日志,然后对日志进行过滤复制处理,其中正则配置只选择JSON格式的日志,复制两份日志数据,一份存入HDFS,一份传入Kafka转为实时流。其中在HDFS和Kafka两条线都做了负载均衡处理。一张整体框架图还有一张详细的数据路径图






架构实现

该架构的其中一条线已经在Flume的那篇博客讲述过,这边就不在重复,这边只进行Kafka这条线进行实现分析。这里上文已经知道消费者怎么进行消费,所以只需要在Flume端配置联通这个数据传输通道就能将数据稳定传输,Flume客户端启动在Flume那篇博客已经写得很清楚了。这里也不做过多介绍。
接下去写Flume接入Kafka的那个MasterClient2.conf的配置如下:
  1. Flume配置  
  2.   
  3. client2.sources = source1  
  4. client2.sinks  = sink1 sink2  
  5. client2.channels = channel1  
  6.   
  7. #Define a sink group which for Load balancing  
  8. client1.sinkgroups = g1  
  9. client1.sinkgroups.g1.sinks = sink1 sink2  
  10. client1.sinkgroups.g1.processor.type = load_balance  
  11. client1.sinkgroups.g1.processor.backoff = true  
  12. client1.sinkgroups.g1.processor.selector = round_robin  
  13.   
  14. #Describe source  
  15. client2.sources.source1.type = avro  
  16. client2.sources.source1.channels = channel1  
  17. client2.sources.source1.port = 6666  
  18. client2.sources.source1.bind = 0.0.0.0  
  19.   
  20. #Describe sink1  
  21. #client2.sinks.sink1.type = logger  
  22. client2.sinks.sink1.type = org.apache.flume.plugins.KafkaSink  
  23. client2.sinks.sink1.metadata.broker.list=192.168.196.138:9092,192.168.196.139:9092,192.168.196.140:9092  
  24. client2.sinks.sink1.zk.connect=192.168.196.138:2181,192.168.196.139:2181,192.168.196.140:2181  
  25. client2.sinks.sink1.partition.key=0  
  26. client2.sinks.sink1.partitioner.class=org.apache.flume.plugins.SinglePartition  
  27. client2.sinks.sink1.serializer.class=kafka.serializer.StringEncoder  
  28. client2.sinks.sink1.request.required.acks=1  
  29. client2.sinks.sink1.max.message.size=1000000  
  30. client2.sinks.sink1.producer.type=async  
  31. client2.sinks.sink1.custom.encoding=UTF-8  
  32. client2.sinks.sink1.custom.topic.name=kafkaToptic  
  33.   
  34. #Describe sink2  
  35. #client2.sinks.sink2.type = logger  
  36. client2.sinks.sink2.type = org.apache.flume.plugins.KafkaSink  
  37. client2.sinks.sink2.metadata.broker.list=192.168.196.138:9092,192.168.196.139:9092,192.168.196.140:9092  
  38. client2.sinks.sink2.zk.connect=192.168.196.138:2181,192.168.196.139:2181,192.168.196.140:2181  
  39. client2.sinks.sink2.partition.key=0  
  40. client2.sinks.sink2.partitioner.class=org.apache.flume.plugins.SinglePartition  
  41. client2.sinks.sink2.serializer.class=kafka.serializer.StringEncoder  
  42. client2.sinks.sink2.request.required.acks=1  
  43. client2.sinks.sink2.max.message.size=1000000  
  44. client2.sinks.sink2.producer.type=async  
  45. client2.sinks.sink2.custom.encoding=UTF-8  
  46. client2.sinks.sink2.custom.topic.name=kafkaToptic  
  47.   
  48. #Describe channel  
  49. client2.channels.channel1.type = memory  
  50. client2.channels.channel1.capacity = 10000  
  51. client2.channels.channel1.transactionCapacity = 1000  
  52.   
  53. #bind the source/sink with channel  
  54. client2.sinks.sink1.channel = channel1  
  55. client2.sources.source1.channels = channel1  

然后启动三个Flume客户端后在开启日志模拟器,开启消费者程序就可以开始看到日志的传输,在2G内存,20G硬盘,1核处理器的集群单个节点上数据的传输延迟大概是0.8秒。

转载自: http://blog.youkuaiyun.com/u014001866/article/details/50971098
<think>好的,我现在需要帮助用户解决在NestJS中集成Kafka的问题。首先,我得回顾一下自己对NestJS和Kafka的了解。NestJS是一个基于Node.js的框架,支持TypeScript,常用于构建高效、可扩展的服务器端应用。而Kafka是一个分布式流处理平台,常用于处理实时数据流,支持高吞吐量和容错性。所以用户的需求应该是如何在NestJS应用中配置和使用Kafka进行消息的生产和消费。 接下来,我应该考虑NestJS中集成Kafka的常见方法。记得NestJS有一个模块化的系统,可以通过导入不同的模块来扩展功能。可能需要使用到@nestjs/microservices模块,这个模块支持多种传输层,包括Kafka。所以,首先需要安装相关的依赖包,比如kafkajs,因为NestJS的Microservices模块通常与kafkajs库配合使用。 然后,配置部分。用户需要知道如何在NestJS中配置Kafka的客户端和生产者、消费者的设置。可能需要创建一个Kafka客户端实例,指定brokers的地址和其他配置参数。比如,在app.module.ts中通过registerMicroservice来配置Kafka的连接参数,如brokers列表、客户端ID等。 接下来是消息的生产和消费。生产者部分,用户可能需要一个服务类,使用ClientKafka来发送消息到指定的topic。消费者部分,则需要使用@MessagePattern或@EventPattern装饰器来订阅特定的topic,并处理接收到的消息。需要注意的是,消费者需要作为微服务启动,以便监听Kafka的消息。 另外,关于代码示例,需要确保语法正确,特别是装饰器的使用和模块的导入。比如,在模块中导入ClientsModule,并使用registerAsync来异步配置Kafka客户端,可能涉及到环境变量的使用,比如从配置服务中获取brokers地址。 还有可能涉及到消息序列化和反序列化的处理。Kafka消息通常以缓冲区的形式传输,所以可能需要配置编码器(serializer)和解码器(deserializer),比如使用JSON格式进行序列化。 用户可能还会关心如何运行和测试这个集成。需要指导他们启动Kafka服务器,创建所需的topic,并运行NestJS应用。同时,可能需要使用命令行工具如kafka-console-producer和kafka-console-consumer来测试消息的发送和接收。 此外,需要注意NestJS的版本是否与所使用的@nestjs/microservices版本兼容,以及kafkajs的版本是否适配。如果用户遇到连接问题,可能需要检查Kafka broker的地址是否正确,防火墙设置是否允许访问,以及Kafka的配置是否正确,比如advertised.listeners的设置。 最后,应该考虑用户可能的后续问题,比如如何处理错误、实现重试机制,或者如何扩展消费者组。这时候可以提到NestJS的拦截器、过滤器,或者Kafka本身的消费者组机制。例如,断路器模式可以使用@nestjs/circuit-breaker或者之前提到的@UseFilters装饰器,如引用中的CircuitBreakerFilter[^2]。 总结步骤大致如下: 1. 安装必要的依赖包。 2. 配置Kafka客户端和微服务模块。 3. 创建生产者服务发送消息。 4. 创建消费者控制器处理消息。 5. 启动微服务监听。 6. 测试生产和消费流程。 现在需要把这些步骤转化为结构化的回答,确保代码示例正确,配置参数清晰,并且引用相关的文档或资源。同时,生成相关问题,帮助用户进一步学习,比如配置多个brokers、处理消息序列化问题或者性能优化方法。</think>### NestJS 集成 Kafka 的配置与示例 #### 1. 安装依赖 首先安装 Kafka 客户端库和 NestJS 微服务模块: ```bash npm install kafkajs @nestjs/microservices ``` #### 2. 配置 Kafka 连接 在 `app.module.ts` 中注册 Kafka 微服务: ```typescript import { Module } from '@nestjs/common'; import { ClientsModule, Transport } from '@nestjs/microservices'; @Module({ imports: [ ClientsModule.register([ { name: 'KAFKA_SERVICE', transport: Transport.KAFKA, options: { client: { brokers: ['localhost:9092'], // Kafka Broker 地址 clientId: 'nestjs-kafka-client', }, consumer: { groupId: 'nestjs-group' // 消费者组 ID } } } ]) ] }) export class AppModule {} ``` #### 3. 生产者服务示例 创建生产者服务 `kafka.producer.service.ts`: ```typescript import { Injectable } from '@nestjs/common'; import { ClientKafka } from '@nestjs/microservices'; @Injectable() export class KafkaProducerService { constructor(@Inject('KAFKA_SERVICE') private client: ClientKafka) {} async sendMessage(topic: string, message: string) { await this.client.emit(topic, { value: message }).toPromise(); } } ``` #### 4. 消费者控制器示例 创建消费者控制器 `kafka.consumer.controller.ts`: ```typescript import { Controller } from '@nestjs/common'; import { MessagePattern, Payload } from '@nestjs/microservices'; @Controller() export class KafkaConsumerController { @MessagePattern('test-topic') // 订阅的 Topic async handleMessage(@Payload() message: any) { console.log('Received message:', message.value); } } ``` #### 5. 启动微服务监听 在 `main.ts` 中启动微服务: ```typescript import { NestFactory } from '@nestjs/core'; import { MicroserviceOptions } from '@nestjs/microservices'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); app.connectMicroservice<MicroserviceOptions>({ transport: Transport.KAFKA, options: { client: { brokers: ['localhost:9092'] }, consumer: { groupId: 'nestjs-group' } } }); await app.startAllMicroservices(); await app.listen(3000); } bootstrap(); ``` #### 6. 测试流程 1. 启动 Kafka 服务并创建 Topic `test-topic` 2. 运行 NestJS 应用:`npm run start` 3. 使用生产者发送消息: ```typescript // 在控制器中调用 await this.kafkaProducerService.sendMessage('test-topic', 'Hello Kafka!'); ``` --- ### 配置说明 - **Broker 地址**:根据实际环境修改 `brokers` 参数,集群环境需配置多个地址,例如 `['kafka1:9092', 'kafka2:9092']` - **序列化**:可通过 `serializer` 和 `deserializer` 配置消息编解码(默认使用 JSON) - **重试机制**:在 `client` 配置中添加 `retry` 参数实现连接重试[^1]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值