Kafka从入门到基础使用

一、消息队列介绍和kafka

1、消息队列(MQ:Message Quene)

概念:
        存储消息(数据)的容器。容器具有队列的特点(按照顺序先进先出)FIFO。

2、消息队列中数据的处理模型:

2.2、传统数据的处理模型

2.3、消息队列中数据的处理模型(发邮件)

3、消息队列的核心组件及其运行模式:

3.1、核心组件:
        producer  :生产者,发送消息的程序(往队列中添加数据)
        consumer:消费者,消费消息的程序(从队列中获取数据)

3.2、运行模式:
         点对点(point to point):P2P模式包含三个角色:消息队列(Queue),发送者(Sender),接收者(Receiver)。每个消息都被发送到一个特定的队列,接收者从队列中获取消息。队列保留着消息,直到他们被消费或超时。

特点:
       生产者发送一条消息到queue,一个queue可以有很多消费者,但是一个消息只能被一个消费者接受,消息一旦被消费,消息就不再在消息队列中。queue实现了负载均衡

3.3、发布与订阅(Subscribe/Publish):
       包含三个角色主题(Topic),发布者(Publisher),订阅者(Subscriber) 。多个发布者将消息发送到Topic,系统将这些消息传递给多个订阅者。

特点:【常见于公众号订阅
       每个消息可以有多个消费者
       发布者和订阅者之间有时间上的依赖性。针对某个主题(Topic)的订阅者,它必须创建一个订阅者之后,才能消费发布者的消息。为了消费消息,订阅者必须保持运行的状态。

4、使用消息队列的好处:

4.1、降低系统间的耦合度
4.2、暂缓对数据的处理,在高并发情况下减小服务器的压力。

5、消息队列的使用场景:

         请求的异步处理(注册发送邮件),应用解耦(电商下订单创建物流信息,使用RPC通信),流量削锋(秒杀系统),日志处理(大数据flume+kafka)和消息通讯(聊天室)等场景

6、常见的消息队列框架

 

Kafka

ActiveMQ

RabbitMQ

ZeroMQ【号称最快MQ】

Redis

公司/社区

Apache/LinkedIn

Apache

MozillaPublic
License

 

 

开发语言

Scala

Java

Erlang

C、C++、Java、.NET、Python

C++

支持的协议

仿AMQP

OpenWire/STOMP
/REST/XMPP/AMQP

AMQP

 

 

事务

不支持

支持

不支持

 

 

集群

支持

支持

支持

 

 

负载均衡

支持

支持

支持

 

 

动态扩容

支持(Zookeeper)

不支持

不支持

 

 

Kafka:

1、概念:
         Kafka最初是由linked-in使用Scala编写的开源项目,后来交由apache管理的是一个分布式的基于publisher-subscribe的消息系统。Kafka中的Producer和consumer采用的是push-and-pull模式,即Producer只管向Broker push消息,consumer只管从Broker pull消息,两者对消息的生产和消费是异步的。

2、特点:

①、高吞吐量、低延迟:kafka每秒可以处理几十万条消息,它的延迟最低只有几毫秒。
②、顺序读写:kafka的消息是不断追加到文件中的,这个特性使kafka可以充分利用磁盘的顺序读写性能。顺序读写不需要硬盘磁头的寻道时间,只需很少的扇区旋转时间,所以速度远快于随机读写顺序读写的性能在某些情况下高于内存读写
③、零拷贝:在Linux kernel2.2 之后出现了一种叫做"零拷贝(zero-copy)"系统调用机制,就是跳过“用户缓冲区”的拷贝,建立一个磁盘空间和内存的直接映射,数据不再复制到“用户态缓冲区”。

 

④、文件分段:kafka的队列topic被分为了多个区partition,每个partition又分为多个段segment,所以一个队列中的消息实际上是保存在N多个片段文件中。通过分段的方式,每次文件操作都是对一个小文件的操作,非常轻便,同时也增加了并行处理能力。

每一个分区里面都会包含***.index和***.log文件,***.index是针对***.log的文件索引,加快查询速度,会成对出现

 

⑤、批量发送:kafka允许进行批量发送消息,先将消息缓存在内存中,然后一次请求批量发送出去。大大减少服务端的I/O次数
⑥、数据压缩:Kafka还支持对消息集合进行压缩,Producer可以通过GZIP或Snappy格式对消息集合进行压缩。压缩的好处就是减少传输的数据量,减轻对网络传输的压力
⑦、可扩展性:kafka集群支持热扩展
⑧、持久性、可靠性:消息被持久化到本地磁盘,并且支持数据备份防止数据丢失 activeMQ不支持持久化
⑨、容错性:允许集群中节点失败(若副本数量为n,则允许n-1个节点失败)
⑩、高并发:支持数千个客户端同时读写

3、kafka的使用场景:

日志收集:一个公司可以用Kafka可以收集各种服务的Log,通过kafka以统一接口服务的方式开放给各种consumer,例如hadoop、Hbase、Solr等。
用户活动跟踪:Kafka经常被用来记录web用户或者app用户的各种活动,如浏览网页、搜索、点击等活动,这些活动信息被各个服务器发布到kafka的topic中,然后订阅者通过订阅这些topic来做实时的监控分析,或者装载到hadoop、数据仓库中做离线分析和挖掘。
运营指标:Kafka也经常用来记录运营监控数据。包括收集各种分布式应用的数据,生产各种操作的集中反馈,比如报警和报告。
流式处理:比如Spark Streaming和Storm 集成组件已经写好了!

4、kafka中的设计到的概念

1、Broker:每一个Broker就是kafka实例(服务器),多个Broker组成kafka集群。生产者会把消息发送到Broker,消费者会从Broker消费消息。Kafka集群会通过选举来选出一个Broker作为管理者(KafkaController),负责处理分区的Leader选举,以及分区的迁移。
2、Topic(主题):kafka对消息进行分类,每一个分类就是一个topic,一个topic可以分布在多台服务器上,在生产中通常一个业务对应一个topic。
3、Producer:生产者,发送消息的进程,将消息发送到topic中
4、Consumer:消费者,消费消息的进程,从topic中读取消息
5、ConsumerGroup:由多个消费者组成的组,每一个组中的所有消费者共同消费一个完整的Topic,彼此消费的消息不重复(消费方的集群)
6、Partition:由于消息是海量的,为了消息的读写性能,每一个topic都被分成很多部分(至少有一个分区),每一个部分就叫做一个分区(Partiton),在创建topic的时候可以指定分多少个区,每一个区就是一个文件目录,这个目录只负责存储该topic的一部分消息,所有的Partition中的消息加起来就组成一个完整的topic。每个topic的每个分区会被均匀的分布到kafka集群的各个broker机器上。一个分区可以看做是一个FIFO的队列。
7、Replication:副本,每一个分区都有多个副本
8、Leader和follower:每个topic的每一个分区的多个副本中,其中一个副本会被选为leader,其他的副本都是follower。Leader负责消息的读写,而所有的follower都会从leader复制消息
9、ISR:是Replicas的一个子集,表示目前活跃的并且同步速度能够跟得上leader的那些分区副本的集合。由于读写都是首先落到Leader上,所以一般来说通过同步机制从Leader上拉取数据的Replica都会和Leader有一些延迟,不管是在时间上跟不上进度,还是在数量上跟不上进度,都会被踢出ISR。每个Partition都有它自己独立的ISR。
10、Offset:每一条消息都有一个offset值作为唯一标识,就是一条消息在一个分区中的编号,编号的顺序不是全局的,所以不能跨分区。
11、Zookeeper:生产者、消费者、和Kafka集群都依赖于Zookeeper存储一些元数据信息

Kafka架构图

Kafka 的数据顺序读写

集群内部架构:1个Leader,两个Follower

一、启动Kafka的依赖组件,Zookeeper和Kafka服务Broker

1、启动zk:

./bin/zookeeper-server-start.sh config/zookeeper.properties

2、启动kafak的broker:

./bin/kafka-server-start.sh -daemon config/server.properties

3、在broker中创建一个topic:

./bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic topicName   这是一个Topic 的名字  这是创建一个Topic(一个业务对应一个Topic)

4、显示所有的topic:

./bin/kafka-topics.sh --list --zookeeper localhost:2181

5、显示某个特定topic的信息:

./bin/kafka-topics.sh --describe --zookeeper localhost:2181 --topic topicName

6、producer产生数据(往topic中push数据):

./bin/kafka-console-producer.sh --broker-list localhost:9092 --topic topicName

7、consumer消费topic中的数据(从topic中pull数据):

./bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topic topicName --from-beginning

8、修改topic,添加分区数:4

./bin/kafka-topics.sh --zookeeper localhost:2181 --alter --topic topicName --partitions 4

9、删除topic:

./bin/kafka-topics.sh --zookeeper localhost:2181 --delete --topic topicName

此命令需要在server.properties文件中添加如下配置,才能使删除生效:delete.topic.enable=true

测试生产者推送数据,消费者消费数据

./bin/kafka-topics.sh --help 查看kafka 语法使用帮助说明

①、创建话题Topic

./bin/kafka-topics.sh --create --zookeeper 192.168.1.212:2181,192.168.1.214:2181,192.168.1.215:2181 --replication-factor 3 --partitions 3 --topic my-topic01
Created topic "my-topic01".

--zookeeper 表示Kafka 连接的Zk集群,如果是单节点写一个即可。

--replication-factor 表示指定副本数,如果3台机器,可以设副本为 3

--partitions 3 表示当前Topic 的话题为 3

--topic my-topic01 表示当前的话题名称

②、显示某个特定topic的集群信息

./bin/kafka-topics.sh --describe --zookeeper 192.168.1.212:2181,192.168.1.214:2181,192.168.1.215:2181 --topic my-topic01

③、往topic中push数据

6667的端口来自 listeners
./bin/kafka-console-producer.sh --broker-list 192.168.1.212:6667,192.168.1.214:6667,192.168.1.215:6667 --topic my-topic01

④、从topic中pull数据

./bin/kafka-console-consumer.sh --zookeeper 192.168.1.212:6667,192.168.1.214:6667,192.168.1.215:6667 --topic my-topic01

切记 生产这生产数据,端口是配置文件listeners的端口 不是固定的6667

⑤、从头开始消费数据:

./bin/kafka-console-consumer.sh --zookeeper 192.168.1.212:2181,192.168.1.214:2181,192.168.1.215:2181 --from-beginning --topic my-topic01

消费者 连接端口为 2181 即zookeeper 的端口

--from-beginning 表是从当前话题最开始消费,如果不加即从当前消费者开始消费,从启动消费者后消费.......

Java代码操作Kafka

pom

  <dependencies>
        <dependency>
            <groupId>org.apache.kafka</groupId>
            <artifactId>kafka_2.10</artifactId>
            <version>0.8.0</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.15</version>
            <exclusions>
                <exclusion>
                    <artifactId>jmxtools</artifactId>
                    <groupId>com.sun.jdmk</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>jmxri</artifactId>
                    <groupId>com.sun.jmx</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>jms</artifactId>
                    <groupId>javax.jms</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>mail</artifactId>
                    <groupId>javax.mail</groupId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

创建配置文件:

package kafka.demo01;

public class Config {
	public static final String TOPIC_NAME="mytopic-01";
	public static final String BROKER_LIST = "192.168.1.212:6667,192.168.1.214:6667,192.168.1.215:6667";
	public static final String ZK_LIST = "192.168.1.212:2181,192.168.1.215:2181,192.168.1.215:2181";
}

创建生产者代码:

package kafka.demo01;

import java.util.Properties;
import java.util.UUID;
import kafka.javaapi.producer.Producer;
import kafka.producer.KeyedMessage;
import kafka.producer.ProducerConfig;
import kafka.serializer.StringEncoder;

public class Producer1 {
	public static void main(String[] args) {
		try{
			// 设置producer的配置信息
			Properties properties = new Properties();
			// 指定broke的地址列表,列表格式:host1:port1,host2:port2,host3:port3
			properties.put("metadata.broker.list", Config.BROKER_LIST);
			// 指定key 和value的序列化方式。默认是StringEncoder
			properties.put("serializer.class", StringEncoder.class.getName());
			ProducerConfig config =new ProducerConfig(properties);
			Producer<String, String> producer = new Producer<String, String>(config);
			int i = 0 ; 
			while(true){
				String msgKey = "key"+i;
				String msgContent = UUID.randomUUID().toString().replaceAll("_", "");
				KeyedMessage<String, String> msg = new KeyedMessage<String, String>(Config.TOPIC_NAME	, msgKey, msgContent);
				producer.send(msg);
				i++;
			}
		}catch (Exception e) {
			e.printStackTrace();
		}
	}
}

创建消费者代码:

package kafka.demo01;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import kafka.consumer.Consumer;
import kafka.consumer.ConsumerConfig;
import kafka.consumer.ConsumerIterator;
import kafka.consumer.KafkaStream;
import kafka.javaapi.consumer.ConsumerConnector;
import kafka.serializer.StringEncoder;

public class Consumer01 {

	public static void main(String[] args) {
		Properties prop = new Properties();
		prop.put("zookeeper.connect", Config.ZK_LIST);
		prop.put("serializer.class", StringEncoder.class.getName());
		// prop.put("metadata.broker.list", MsgConfig.brokelist);
		prop.put("group.id", "group1");
		ConsumerConnector consumer = Consumer
				.createJavaConsumerConnector(new ConsumerConfig(prop));
		Map<String, Integer> topicCountMap = new HashMap<String, Integer>();
		// 创建3个线程去消费topic中的内容,每一个线程一个stream流
		topicCountMap.put(Config.TOPIC_NAME, 3);
		Map<String, List<KafkaStream<byte[], byte[]>>> messageStreams = consumer
				.createMessageStreams(topicCountMap);
		System.out.println(messageStreams);
		KafkaStream<byte[], byte[]> kafkaStream = messageStreams.get(
				Config.TOPIC_NAME).get(0);
		ConsumerIterator<byte[], byte[]> iterator = kafkaStream.iterator();
		while (iterator.hasNext()) {
			String msg = new String(iterator.next().message());
			System.out.println("收到消息:" + msg);
		}
	}
}

启动生产者:

启动消费者:

至此Java代码操作成功!

解决报错

kafka.common.FailedToSendMessageException: Failed to send messages after 3 tries.

zookeeper.connect=localhost:2181改成zookeeper.connect=192.168.1.116 (自己的服务器IP地址):2181

修改Windows的hosts 配置文件

即可解决问题

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值