目录
1 Kafka入门
1.1 主流mq框架对比
1.2 kafka主要特性
1.3 AMQP协议
1.4 Kafka整体架构
1.5 核心概念
broker
topic
partition
record
replication
1.6 kafaka 核心API
概述
producer
consumer
3 consumer的commit offset
4 consumer的数据获取方式
2 kafka使用场景
2.1 消息系统
2.2 存储系统
2.3 日志聚合
2.4 跟踪网站活动(其实就是埋点)
2.5 流处理
ActiveMQ | RabbitMQ | Kafka | |
---|---|---|---|
吞吐量 | 1w | 1w | 10w |
支持的协议 | OpenMessage, AMQP, MQTT, STOMP | AMQP | 仿AMQP |
事务 | 支持 | 支持 | 支持 |
集群 | 支持(不良好) | 支持(不良好) | 支持 |
负载均衡 | 支持 | 支持 | 支持 |
动态扩展 | 不支持 | 不支持 | 支持 |
编写语言 | Java | Erlang | Scala |
这三个MQ组件中, ActiveMQ的功能最丰富, 支持的协议最多。 吞吐量上, 一般情况下Kafka > RabbitMQ > ActiveMQ; 可靠性上, 一般情况下RabbitMQ > ActiveMQ > Kafka。
动态扩展, 是指可以向运行中的集群添加新的节点, 而不影响已有节点的使用。 之所以说ActiveMQ对集群的支持不良好, 其中一个原因是 ActiveMQ的节点只能是主从模式, 只有再master节点上才可以发布和消费消息, 这样的话对并发量的提升相对较弱。
消息系统: 可以发布和订阅消息, 类似于消息队列或企业级消息系统。
存储: 提供容错的方式来存储流数据。 存储在kafka中的数据, 都会落到磁盘上, 只要不手动删除, 将一直存在, 不像其他消息中间件, 当消息消费后, 会对消息进行删除。
流处理: 可以在一个流的数据产生时, 就对它进行处理, 即流处理。这个特性是kafka的streams api来支持的,需要在客户端上编码, 实质上是读取现有的流数据, 将处理的结果推到结果的流上。 但主流的还是采用fink, storm sreams, spark等批处理框架来进行流处理。 kafka更多的是充当一个流数据的存储角色。
总的来说, Kafka不仅仅是一个消息系统, 还是一个数据存储。
AMQP是由金融业的摩根大通公司主导制定的消息协议, 是一个应用层的协议。
在Kafka中, 生产者push,消费者poll,都是客户端主动发起数据请求。kafka都是以多个broker集群的方式对外提供服务。
一个Kafka示例, 一般情况下, Kafka都是以集群的方式部署的。
消息的一种分类, 一个主题的消息可以视为一个数据流。主题中的消息不一定按照发布的顺序消费。
一个主题可以分为多个partition,每一个partition都是顺序存储在磁盘的。 每个partition的消息有自己的id, 对于消费者, partion有自己对应的commit offset。partition的意义: 其一, 如果通过将一个主题分隔成多个partition, 部署到多个broker上来提升io的速度, 甚至通过这种方式, 获得和内存相近的吞吐量; 其二, partition可以分布在多个broker上, 可以避免一次性丢失所有数据的情况。
partition中的消息是会按照发布的顺序消费的。
每条记录都有key, value和timestamp三个数据。 其中具有相同key的消息, 可以保证落到同一个partition中。
每一个partition可以有多个副本, 副本分布在不同的broker上, 通过这种冗余, 可以保证数据的安全性, 只要不是所有的副本都丢失, 那么partition中的数据就是安全的。 副本的数量(replication-factor)不能超过broker的数量, 因为将同样的副本存在同一台机器上, 对于数据安全性,没有作用。
replicationreplication有一下的特性:
注意: 这里的leader和follower是replication级别的, Kafka的broker节点之间没有主次之分, 它们是完全同等的。
这四种API, 用来构建四种类型的Kafka客户端, 如下:
使用代码示例:
// 设置producer的配置
Properties settings = new Properties();
settings.put("batch.size", 16 * 1024); // 缓冲区大小, 默认16k
settings.put("linger.ms", 1000); // 发送前, 等待的时间, 默认为0
settings.put("acks", "all"); // 多少个broker 确认才认为成功。 0,
settings.put("retries", 1 ); // 重试的次数
....
Producer producer = new KafkaProducer(settings);
// 发送消息
ProducerRecord record = new ProducerRecord<>("my-topic", "key", "value");
producer.send(record);
producer.close();
producer发送消息时, 并不是直接发送到broker中的, 而是先放在本地内存中的一个缓冲区,当缓冲区大小达到最大大小或缓冲区中的消息达到停留时间时, 才进行发送。 如下:
producer有三个重要的配置:
一旦达到batch.size或linger.ms其中一个条件, 缓冲区的消息就会被立刻发送。
1 simple consumer API
每次消费消息时, 都需要提供topic, partition, offset, feichSize等四个参数, 不提供负载均衡和容错的特性。
非常基础, 但是基于可以定义实现所有的功能。
2 high level consumer API
消费时只需要指定topic, 客户端透明地切换consumer的partition, 实现consumer group级别的负载均衡。 如下图:
consumer group有如下的特性:
可以通过consumer group来实现队列和广播:
consumer 什么时候会退出group?
consumer可以通过commit, 来告诉服务器, 当前已经消费了的消息, 当consumer因为某种原因重启时, 会从最新提交的offset的下一个消息开始消费。 默认的情况下, Consumer是自动提交的, 每当poll数据时, 就会提交上一条数据。
除了这个存在kafka的commit offset, 还有一个consumer自己持有的offset, 来指向下一个消息。
kafka中,消费者是只能通过主动poll的方式来获取数据的。
push和poll两种方式的难点:
poll时间间隔的解决方案--- long polling:
consumer poll数据时, 如果当前数据不够, 那么这个poll请求会阻塞, 等待有足够多的数据或者到达等待时间时才返回。
原因: 高可用; 根据经验, 通常对消息传递对吞吐量的要求比较低, 但是要求较低的端到端延迟, 并且要有可靠的durable机制(kafka是一个持久化的消息队列);高吞吐量;
对于消息顺序的保证, 从某种角度来说, kafka会比较好。因为即使是RabbitMQ和ActiveMQ, 当有多个消费者进行消费时, 其实我们没有办法保证哪个消费者先消费完, 其实顺序也会丢失。
kafka实现顺序消费的方法:
高性能, 低延迟, 高可用的日志提交存储。
日志处理的流程: 收集, 清洗(一般是使用正则来清洗), 聚合,存储, 展示
可能不能作为一个完全的日志解决方案, ELK的日志解决方案更加有优势。 (ELK的缺点: 聚合节点Logstash可能会成为系统瓶颈)
为什么要进行日志的聚合?
如果是分布式系统, 那么一个程序的多个实例的日志需要进行聚合。 一个请求在上下游的日志也需要聚合。
kafka在LinkedIn中就因此而生。
Kafka StreamAPIs 可以进行流处理, 但是如果要使用复杂的流处理功能, 还是使用flink, spark streaming等框架。
为什么需要流处理?
和流处理相对的是批处理, 批处理有很大的延迟, 比如说前一天去跑一些统计数据。 而流处理, 是一有新的数据就马上计算更新结果的处理方式。