Kafka的设计初衷是为了更高效地做日志收集,本文将先行解释日志收集和处理的复杂性,来了解使用Kafka的必要性。
kafka日志消息系统
我们最开始的需求是有多台服务器的日志被收集并在面板中展示。新建一个日志收集服务,将应用服务器的日志直接发送到这里进行统计,展示。
log-before-kafka.png
现在我又想要持久化这些日志,比如将某些我认为重要的日志存储在数据库或者Hbase中,我会再新建一个服务,应用服务器同样发送日志到这里,然后进行存储和数据处理。后续我会用更多的需求,每次都会新建一个服务,最后系统将变得十分复杂。
log-before-k.png现在我新建一个专门收集日志的服务,将不同的日志分发给不同的日志处理程序,这样降低了点对点连接的复杂性。
log-mq.png如果读者有对于消息队列的储备知识,这种建构就是一个发布-订阅消息系统。了解更多请看RabbitMQ Tutorials
横向扩展
我们需要做用户行为分析,类似于前述的日志分发系统,新建一个发布-订阅消息服务,这样做是要将发布者和订阅者解耦合。最终的架构存在两个独立的发布-订阅消息系统。
log-mq-multi.png两个系统存在重复工作,而且后续更多的消息系统将被建立,增加维护成本和出错概率。我们想要的是一个中心化的消息分发系统,可以处理多种数据类型,满足各种消息格式的需求。为了解决这个问题,我们有了Kafka。
初识Kafka
特性概括:
- 持久化
- 有序
- 容错
- 实时
持久化通过消息保留(retention)策略进行配置,不管是设置超时时间(例如7天),或者达到存储空间限制(比如1G),然而还有最终的限制,磁盘空间。
有序通过分区(partition)进行保证,同一个partition内的消息保证有序。
容错通过备份(replication)进行配置,以partition为单位的多个备份分布存储在不同的broker上。可以把broker简单的理解为物理机(并非物理机,而是Kafka抽象出来的数据存储节点)。
实时,是延迟和吞吐量之间的取舍。Kafka支持批处理以提高网络性能(吞吐量),即压缩多条消息在一个网络请求中发送,一次批处理数据量越大,对于单条消息的处理延迟越大。
Topic和Partition
Kafka消息被归并为Topic(主题),类比数据库,Topic可以看作是一张表,消息可以看作是行数据。每一个Topic底层的数据存储由Partition(分区)负责。类似于数据库中的分库分表(sharding),kafka里的sharding叫做partition,以此实现负载均衡,提高吞吐量。写入时,消息依顺序添加到分区的末尾,读取时,按顺序读取。因为一个Topic往往有多个Partition,在整个Topic下的消息是不保证有序的,消息的有序性只在同一个Partition中保证。
partitonsPartition是Kafka分布式的最小单位,每个Partition可以存储在不同的服务器上,这种方式可以实现两个功能:
- 对一个Topic进行水平扩展,提高读写性能
- 容错。之前提到的replication也是基于Partition分布在不同的机器上实现的。
生产者和消费者
生产者和消费者作为Kafka的客户端,通过client API与Kafka集群通信,写入消息或者读取消息。
生产者推送消息给Kafka,Kafka持久化到磁盘中,用户不用担心消息丢失。默认配置下,生产者也不用关心消息存储在哪个Partition中,Kafka会通过key的哈希自动将消息负载均衡到多个Partition。这样也保证了拥有同一个key的消息被存储在同一个partition,保证了消息的顺序。当然也支持定制分区规则来满足特定的存储需求,比如要求某几个key同时存储到一个partition。
消费者读取消息,可以订阅一个或者多个Topic。消费者通过offset(偏移量)得知消费到了哪里,以此追溯此刻的消费位置。offset在一个partition内才有意义,同一个partition下的消息都有一个唯一的offset。存储上一条被消费消息的offset(一般存储在zookeeper中),消费者可以保证消息不丢失的情况下停机和重启。
消费者中一个很重要的概念是consumer group
(组),同属于一个group的多个消费者消费一个Topic。组可以保证一个partition只由一个消费者消费,以下图为例,三个消费者在一个group中消费topicName
,consumer 0和consumer 2分别消费一个partition,consumer 1消费两个partition。
当其中一个消费者停机,它之前消费的partition将自动切换到另外的消费者,只要这个group下有一个活跃的消费者程序,就不会影响正常消费,只是性能变差而已。
还用一种罕见情况,同一个group,当活跃消费者数量多于partition数量时,总有空闲的消费者不消费任何消息。
idle consumer分布式及容错
单个的Kafka存储服务器叫做Broker。在一个Kafka集群中有多个Broker提供性能保证和容错。性能由多个partition提供,容错通过多个replication提供。下图为例,Topic A有2个partition(性能)和2个replication(一个broker失败容错)。
cluster写消息和读消息操作只交由作为leader的broker进行处理,其他的备份仅仅需要和leader保持同步。当leader意外停止时会在剩余的备份中选取数据最新的broker作为新的leader。
参考:
- Kafka: The Definitive Guide, Preview
- RabbitMQ
网友评论