1.kafka定义
Kafka是一个分布式消息队列:生产者、消费者的功能。
Kafka可以解决:并发、解耦、异步
2.kafka主要组件
Producer:
生产者负责获取数据并将数据上传到Kafka的,比如flume、logstash
生产者往往是监控一个或多个目录(文件)将数据对接到Kafka
生产者集群是由多个进程组成,一个生产者可以作为一个独立的进程,一个生产者就具有生产并发送的功能
多个生产者发送的数据可以发送到同一个topic中的
一个生产者可以将数据发送到多个topic中
Kafka集群:里面的节点叫broker
Kafka集群负责存储数据的,一种数据往往是存在一个topic当中,一个Kafka可以创建多个topic
每个topic可以创建多个副本和多个分区,副本决定了数据的安全性和提高吞吐量。多个分区会存在多个broker当中,分区的数量也会影响吞吐量。
每个分区的数据是由多个Segment组成的,一个segment由多个index和对应的log数据文件组成,index存的是索引,log存的是数据,索引和数据一一对应。
一个topic的分区数可以有多个副本(副本数可以在配置文件里设置),原始数据和副本数据是不可以在同一个节点的
Consumer Group:
消费者负责拉取数据,比如:Streaming、Storm、Flink
一个消费者组里可以有多个消费者
一个消费者对应的一个线程
新增或减少ConsumerGroup的Consumer数量是会触发Kafka集群的负载均衡,负载均衡的目的是尽量的将消费者均衡到每一个节点当中
Consumer可以消费多个分区的数据,一个分区的数据只能在同一时刻被一个Consumer来消费
在一个消费者组中,同一个分区的数据不可以重复消费,如果想重复消费可以更改组名或部署一个Kafka镜像集群
'
3.Kafka的一些基础概念
Kafka怎么解决负载均衡?
1)获取Consumer消费的起始分区号
2)计算出Consumer消费的分区数
3)用起始分区号的hash值模余分区数
segment的概念:
一个分区被分成了多个相同大小的segment(默认是1G),每个segment是由多个index和log文件组成
数据的存储机制:
1.Broker先接收到数据后,将数据放到操作系统(linux)的缓存里(pagecache),pagecache会尽可能多的使用空闲内存,
会是有sendfile技术尽可能多的减少操作系统和应用程序之间的重复缓存。
2、写入数据的时候使用顺序写入,速度可达600m/s
3、如果此时正好有消费者消费数据,会直接绕过磁盘从pagecache里进行消费
数据的分发策略:
Kafka默认会调用自己的分区器(DefaultPartitioner),也可以自定义分区器,需要实现Partitioner特质
Kafka怎么保证数据不丢失?
在创建topic的时候,需要指定副本数和分区数,多副本机制保证了数据的安全性
Kafka存的数据的生存周期默认是168小时(7天),可以根据需求调整
offset:每个分区对应一个offset,记录的是消费到哪个位置了
二、常用命令
1.启动kafka
首先要启动zk
$ZK_HOME/bin/zkServer.sh start
然后启动kafka
nohup $KAFKA_HOME/bin/kafka-server-start.sh $KAFKA_HOME/config/server.properties &
ps:每个节点要分别运行启动命令;
输入命令后,显示nohup: ignoring input and appending output to `nohup.out' ,直接按回车即可
2.停用kafka
停用zk:
$ZK_HOME/bin/zookeeper-server-stop.sh
停用kafka
$KAFKA_HOME/bin/kafka-server-stop.sh
3.查看当前服务器中所有topic
$KAFKA_HOME/bin/kafka-topics.sh --list --zookeeper mini1:2181
4.创建topic
$KAFKA_HOME/bin/kafka-topics.sh --create --zookeeper mini1:2181 --replication-factor 1 --partitions 1 --topic mytest1
5.删除topic
$KAFKA_HOME/bin/kafka-topics.sh --delete --zookeeper mini1:2181 --topic mytest1
需要server.properties中设置delete.topic.enable=true否则只是标记删除或者直接重启。
6.通过shell命令生产消息
$KAFKA_HOME/bin/kafka-console-producer.sh --broker-list mini1:9092 --topic mytest1
7.通过shell命令消费消息
$KAFKA_HOME/bin/kafka-console-consumer.sh --zookeeper mini:2181 --from-beginning --topic mytest1
//报错No brokers found in ZK. 尚未解决
8.查看消费位置
$KAFKA_HOME/bin/kafka-run-class.sh kafka.tools.ConsumerOffsetChecker --zookeeper mini1:2181 --group testGroup
9.查看某个Topic的详情
$KAFKA_HOME/bin/kafka-topics.sh --topic mytest1 --describe --zookeeper mini1:2181
10.对分区数进行修改
$KAFKA_HOME/bin/kafka-topics.sh --zookeeper mini1 --alter --partitions 5 --topic mytest1
三、idea上创建生产者消费者
生产者:
package com.zgm.sc.day16
import java.util.Properties
import org.apache.kafka.clients.producer.{KafkaProducer, ProducerRecord}
object KafkaProducer {
def main(args: Array[String]): Unit = {
val topic="test2"
val props=new Properties()
//指定kafka集群
props.put("bootstrap.servers","mini1:9092,mini2:9092")
//请求失败时的重试次数
props.put("retries","3")
//指定消息key的序列化方式
props.put("key.serializer","org.apache.kafka.common.serialization.StringSerializer")
//指定消息value的序列化方式
props.put("value.serializer","org.apache.kafka.common.serialization.StringSerializer")
//创建生产者对象
val producer: KafkaProducer[String, String] = new KafkaProducer[String,String](props)
//开始讲模拟的数据发送给对应的kafka的topic中
for(i <- 1 to 1000){
val msg=s"$i:producer send msg"
producer.send(new ProducerRecord[String,String](topic,msg))
Thread.sleep(500)
}
producer.close()
}
}
消费者:
package com.zgm.sc.day16
import java.util
import java.util.{Collections, Properties}
import org.apache.kafka.clients.consumer.{ConsumerRecord, ConsumerRecords, KafkaConsumer}
object KafkaConsumer {
def main(args: Array[String]): Unit = {
val props=new Properties()
//指定消费的kafka集群
props.put("bootstrap.servers","mini1:9092,mini2:9092,mini3:9092")
//指定消费组
props.put("group.id","group1")
//如果value合法,自动提交offset
props.put("enable.auto.commit","true")
//设置多长时间更新offset
props.put("auto.commit.interval.ms","1000")
//设置读取数据的位置,1.1.0版本之后的值位earlest、latest
props.put("auto.offset.reset","earliest")
//设置key和value反序列化的方式
props.put("key.deserializer","org.apache.kafka.common.serialization.StringDeserializer")
props.put("value.deserializer","org.apache.kafka.common.serialization.StringDeserializer")
//创建消费者对象
val consumer: KafkaConsumer[String, String] = new KafkaConsumer[String,String](props)
//开始订阅topic,可以传一个或者多个topic
consumer.subscribe(Collections.singletonList("test2"))
while(true){
//poll:一次可以拉取多少消息,可以设置超时时间(1000)
val msgs: ConsumerRecords[String, String] = consumer.poll(1000)
val it: util.Iterator[ConsumerRecord[String, String]] = msgs.iterator()
while (it.hasNext){
val msg: ConsumerRecord[String, String] = it.next()
println("offset:"+msg.offset()+"key:"+msg.key()+"value:"+msg.value())
}
}
}
}