1.基本理解
-kafka是基于JMS实现的,构建企业中统一的、高通量的、低延时的消息平台,此消息平台是基于生产者和消费者模式的。
2.架构
组件:Cluster、broker、Producer、consumer、Topic
3.Shell操作
创建订单的topic
bin/kafka-topics.sh --create --zookeeper zk01:2181 --replication-factor 1 --partitions 1 --topic order
生产数据
bin/kafka-console-producer.sh --broker-list kafka01:9092 --topic order
消费数据
bin/kafka-console-consumer.sh --zookeeper zk01:2181 --from-beginning --topic order
4.JavaApi操作
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>0.11.0.1</version>
</dependency>
/**
* 订单的生产者代码
*/
public class OrderProducer {
public static void main(String[] args) throws InterruptedException {
/* 1、连接集群,通过配置文件的方式
* 2、发送数据-topic:order,value
*/
Properties props = new Properties();
props.put("bootstrap.servers", "node01:9092");
props.put("acks", "all");
props.put("retries", 0);
props.put("batch.size", 16384);
props.put("linger.ms", 1);
props.put("buffer.memory", 33554432);
props.put("key.serializer",
"org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer",
"org.apache.kafka.common.serialization.StringSerializer");
KafkaProducer<String, String> kafkaProducer = new KafkaProducer<String, String>(props);
for (int i = 0; i < 1000; i++) {
// 发送数据 ,需要一个producerRecord对象,最少参数 String topic, V value
kafkaProducer.send(new ProducerRecord<String, String>("order", "订单信息!"+i));
Thread.sleep(100);
}
}
}
/**
* 消费订单数据--- javaben.tojson
*/
public class OrderConsumer {
public static void main(String[] args) {
// 1\连接集群
Properties props = new Properties();
props.put("bootstrap.servers", "node01:9092");
props.put("group.id", "test");
props.put("enable.auto.commit", "true");
props.put("auto.commit.interval.ms", "1000");
props.put("key.deserializer",
"org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer",
"org.apache.kafka.common.serialization.StringDeserializer");
KafkaConsumer<String, String> kafkaConsumer = new KafkaConsumer<String, String>(props);
// 2、发送数据 发送数据需要,订阅下要消费的topic。 order
kafkaConsumer.subscribe(Arrays.asList("order"));
while (true) {
// jdk queue offer插入、poll获取元素。 blockingqueue put插入原生,take获取元素
ConsumerRecords<String, String> consumerRecords = kafkaConsumer.poll(100);
for (ConsumerRecord<String, String> record : consumerRecords) {
System.out.println("消费的数据为:" + record.value());
}
}
}
}
5.分片与副本机制
分片
当数据量非常大的时候,一个服务器存放不了,就将数据分成两个或者多个部分,存放在多台服务器上。每个服务器上的数据,叫做一个分片。
副本机制
当数据只保存一份的时候,有丢失的风险。为了更好的容错和容灾,将数据拷贝几份,保存到不同的机器上。
6.消息不丢失机制
生产者端
同步消息有三种状态(0:生产者只负责发送数据,1:某个partition的leader收到数据给出响应,-1:某个partition的所有副本都收到数据后给出响应)。生产者等待10S,如果broker没有给出ack响应,就认为失败。生产者重试3次,如果还没有响应,就报错。
异步消息:先将数据保存在生产者端的buffer中。Buffer大小是2万条。满足数据阈值或者数量阈值其中的一个条件就可以发送数据。发送一批数据的大小是500条。
如果broker迟迟不给ack,而buffer又满了。开发者可以设置是否直接清空buffer中的数据。
broker端
broker端的消息不丢失,其实就是用partition副本机制来保证。同步消息设置成-1
消费者端
只要记录offset值,消费者端不会存在消息不丢失的可能。只会重复消费。对于重复消费,可以去重:将消息的唯一标识保存到外部介质中,每次消费处理时判断是否处理过。如果使用了storm,要开启storm的ackfail机制;如果没有使用storm,确认数据被完成处理之后,再更新offset值。低级API中需要手动控制offset值。
7.消息存储与查询机制
消息存储
消息存储使用segment段中,segment段中有两个核心的文件一个是log,一个是index。 当log文件等于1G时,新的会写入到下一个segment中。一个segment段差不多会存储70万条数据。
查询
读取offset=12345的message,需要先找到segment file,然后根据index找到12345对应的log中的具体文件,使用的是二分查找。
8.生产者数据分发策略
kafka在数据生产的时候,有一个数据分发策略。如果指定了partition,生产就不会调用DefaultPartitioner.partition()方法;如果指定key,使用hash算法,Utils.toPositive(Utils.murmur2(keyBytes)) % numPartitions;如果既没有指定partition,也没有key的情况下如何发送数据,使用轮询的方式发送数据。
9.消费者的负载均衡
如果消费组中有多于partition数量的消费者,那么一定会有消费者无法消费数据。因为负载均衡策略规定,多出来的消费者处于空闲状态,所以真实的解决方案是修改topic的partition数量或者减少消费者处理时间,提高处理速度。
提高消费速度
- 增加分区
- 关闭autocommit(偏移量手工提交可以按需减少分区偏移量的更新,有利于提升消费速度)
- 增加单次拉取消息的大小(大量消息的场景下可减少拉取消息的次数)
- 如果不考虑数据一致性,可以将key值平均一下,这样每个分区的消息大小都差不多,有利于负载均衡
- 如果没有开启压缩,最好开启压缩(需要重启集群),可大大提高通信效率,有得消费速度提升
10.应用场景
消息
- kafka更好的替换传统的消息系统,消息系统被用于各种场景(解耦数据生产者,缓存未处理的消息,等),与大多数消息系统比较,kafka有更好的吞吐量,内置分区,副本和故障转移,这有利于处理大规模的消息。
- 根据我们的经验,消息往往用于较低的吞吐量,但需要低的端到端延迟,并需要提供强大的耐用性的保证。
- 在这一领域的kafka比得上传统的消息系统,如的ActiveMQ或RabbitMQ的。
网站活动追踪
- kafka原本的使用场景:用户的活动追踪,网站的活动(网页游览,搜索或其他用户的操作信息)发布到不同的话题中心,这些消息可实时处理,实时监测,也可加载到Hadoop或离线处理数据仓库。
- 每个用户页面视图都会产生非常高的量。
指标
- kafka也常常用于监测数据。分布式应用程序生成的统计数据集中聚合。
日志聚合
- 许多人使用Kafka作为日志聚合解决方案的替代品。日志聚合通常从服务器中收集物理日志文件,并将它们放在中央位置(可能是文件服务器或HDFS)进行处理。Kafka抽象出文件的细节,并将日志或事件数据更清晰地抽象为消息流。这允许更低延迟的处理并更容易支持多个数据源和分布式数据消费。
流处理
- kafka中消息处理一般包含多个阶段。其中原始输入数据是从kafka主题消费的,然后汇总,丰富,或者以其他的方式处理转化为新主题,例如,一个推荐新闻文章,文章内容可能从“articles”主题获取;然后进一步处理内容,得到一个处理后的新内容,最后推荐给用户。这种处理是基于单个主题的实时数据流。从0.10.0.0开始,轻量,但功能强大的流处理,就可以这样进行数据处理了。
- 除了Kafka Streams,还有Apache Storm和Apache Samza可选择。
事件采集
- 事件采集是一种应用程序的设计风格,其中状态的变化根据时间的顺序记录下来,kafka支持这种非常大的存储日志数据的场景。
提交日志
- kafka可以作为一种分布式的外部日志,可帮助节点之间复制数据,并作为失败的节点来恢复数据重新同步,kafka的日志压缩功能很好的支持这种用法,这种用法类似于Apacha BookKeeper项目。
11.同类型框架的异同
kafka
- kafka是个日志处理缓冲组件,在大数据信息处理中使用。和传统的消息队列相比较简化了队列结构和功能,以流形式处理存储(持久化)消息(主要是日志)。日志数据量巨大,处理组件一般会处理不过来,所以作为缓冲曾的kafka,支持巨大吞吐量。为了防止信息都是,其消息被消防后不直接丢弃,要多存储一段时间,等过期时间过了才丢弃。这是mq和redis不能具备的。
主要特点入下:
- 巨型存储量: 支持TB甚至PB级别数据。
- 高吞吐,高IO:一般配置的服务器能实现单机每秒100K条以上消息的传输。
- 消息分区,分布式消费:能保消息顺序传输。 支持离线数据处理和实时数据处理。
- Scale out:支持在线水平扩展,以支持更大数据处理量。
redis
- redis只是提供一个高性能的、原子操作内存键值队,具有高速访问能力,可用做消息队列的存储,但是不具备消息队列的任何功能和逻辑,要作做为消息队列来实现的话,功能和逻辑要通过上层应用自己实现。
MQ
- 我们以是RabbitMQ为例介绍。它是用Erlang语言开发的开源的消息队列,支持多种协议,包括AMQP,XMPP, SMTP, STOMP。适合于企业级的开发。
- MQ支持Broker构架,消息发送给客户端时需要在中心队列排队。对路由,负载均衡或者数据持久化都有很好的支持。
- 其他更多消息队列还有ActiveMq,ZeroMq等。功能基本上大同小异。专门测结果,并发吞吐TPS比较,ZeroMq 最好,RabbitMq 次之, ActiveMq 最差。