分布式-Kafka

 

Kafka是最初由Linkedin公司开发,是一个分布式、分区的、多副本的、多订阅者,基于zookeeper协调的分布式日志系统(也可以当做MQ系统),常见可以用于web/nginx日志、访问日志,消息服务等等,Linkedin于2010年贡献给了Apache基金会并成为顶级开源项目。

主要应用场景是:日志收集系统和消息系统。

Kafka主要设计目标如下:

  • 以时间复杂度为O(1)的方式提供消息持久化能力,即使对TB级以上数据也能保证常数时间的访问性能。
  • 高吞吐率。即使在非常廉价的商用机器上也能做到单机支持每秒100K条消息的传输。
  • 支持Kafka Server间的消息分区,及分布式消费,同时保证每个partition内的消息顺序传输。
  • 同时支持离线数据处理和实时数据处理。
  • Scale out:支持在线水平扩展

一、kafka的特点
  高吞吐量:Kafka 每秒可以生产约 25 万消息(50 MB),每秒处理 55 万消息(110 MB)
  持久化数据存储:可进行持久化操作。将消息持久化到磁盘,因此可用于批量消费,例如 ETL,以及实时应用程序。通过将数据持久化到硬盘以及replication 防止数据丢失。
  分布式系统易于扩展:所有的 producer、broker 和 consumer 都会有多个,均为分布式的。无需停机即可扩展机器。
  客户端状态维护:消息被处理的状态是在 consumer 端维护,而不是由 server 端维护。当失败时能自动平衡。
二、Topics、Producers、Consumers
  1.Topics
   一个topic是对一组消息的归纳。对每个topic,Kafka 对它的日志进行了分区。
   每个分区都由一系列有序的、不可变的消息组成,这些消息被连续的追加到分区中。
   分区中的每个消息都有一个连续的序列号叫做offset,用来在分区中唯一的标识这个消息。
   在一个可配置的时间段内,Kafka集群保留所有发布的消息,不管这些消息有没有被消费。比如,如果消息的保存策略被设置为2天,那么在一个消息被发布的两天时间内,它都是可以被消费的。之后它将被丢弃以释放空间。
   Kafka的性能是和数据量无关的常量级的,所以保留太多的数据并不是问题。
   每个分区在Kafka集群的若干服务中都有副本,这样这些持有副本的服务可以共同处理数据和请求,副本数量是可以配置的。副本使Kafka具备了容错能力。
   每个分区都由一个服务器作为“leader”,零或若干服务器作为“followers”,leader负责处理消息的读和写,followers则去复制leader.如果leader down了,followers中的一台则会自动成为leader。集群中的每个服务都会同时扮演两个角色:作为它所持有的一部分分区的leader,同时作为其他分区的followers,这样集群就会据有较好的负载均衡。
   将日志分区可以达到以下目的:首先这使得每个日志的数量不会太大,可以在单个服务上保存。另外每个分区可以单独发布和消费,为并发操作topic提供了一种可能。
   分区是负载均衡失败恢复分布式数据存储的基本单元。
  2.Producers
   Producer将消息发布到它指定的topic中,并负责决定发布到哪个分区。通常简单的由负载均衡机制随机选择分区,但也可以通过特定的分区函数选择分区。使用的更多的是第二种。
  3.Consumers
   实际上每个consumer唯一需要维护的数据是消息在日志中的位置,也就是offset.这个offset由consumer来维护:一般情况下随着consumer不断的读取消息,这offset的值不断增加,但其实consumer可以以任意的顺序读取消息,比如它可以将offset设置成为一个旧的值来重读之前的消息。
   以上特点的结合,使Kafka consumers非常的轻量级:它们可以在不对集群和其他consumer造成影响的情况下读取消息。你可以使用命令行来"tail"消息而不会对其他正在消费消息的consumer造成影响。
   消费消息通常有两种模式:队列模式(queuing)和发布-订阅模式(publish-subscribe)。
   (1)队列模式
    队列模式中,多个consumers可以同时从服务端读取消息,每个消息只被其中一个consumer读到;
   (2)发布订阅模式
    发布-订阅模式中消息被广播到所有的consumer中。
   (3)Consumers可以加入一个consumer group,组内的Consumer是一个竞争的关系,共同竞争一个topic内的消息,topic中的消息将被分发到组中的一个成员中,同一条消息只发往其中的一个消费者。同一组中的consumer可以在不同的程序中,也可以在不同的机器上。而如果有多个Consumer group来消费相同的Topic中的消息,则组和组之间是一个共享数据的状态,每一个组都可以获取到这个主题中的所有消息。
    如果所有的consumer都在一个组中,这就成为了传统的队列模式,在各consumer中实现负载均衡。
    如果所有的consumer都不在不同的组中,这就成为了发布-订阅模式,所有的消息都被分发到所有的consumer中。
    更常见的是,每个topic都有若干数量的consumer组来消费,每个组都是一个逻辑上的“订阅者”,为了容错和更好的稳定性,每个组都由若干consumer组成,在组内竞争实现负载均衡。实现了组内竞争负载均衡,组间共享互不影响,这其实就是一个发布-订阅模式,只不过订阅者是个组而不是单个consumer
三、相比传统的消息系统
  传统的队列在服务器上保存有序的消息,如果多个consumers同时从这个服务器消费消息,服务器就会以消息存储的顺序向consumer分发消息。虽然服务器按顺序发布消息,但是消息是被异步的分发到各consumer上,所以当消息到达时可能已经失去了原来的顺序,这意味着并发消费将导致顺序错乱。为了避免故障,这样的消息系统通常使用“专用consumer”的概念,其实就是只允许一个消费者消费消息,当然这就意味着失去了并发性。
  在这方面Kafka做的更好,通过分区的概念,Kafka可以在多个consumer组并发的情况下提供较好的有序性和负载均衡。将每个分区分只分发给一个consumer组,这样一个分区就只被这个组的一个consumer消费,就可以顺序的消费这个分区的消息。因为有多个分区,依然可以在多个consumer组之间进行负载均衡。注意consumer组的数量不能多于分区的数量,也就是有多少分区就允许多少并发消费。
  Kafka只能保证一个分区之内消息的有序性,在不同的分区之间是不可以的,这已经可以满足大部分应用的需求。如果需要topic中所有消息的有序性,那就只能让这个topic只有一个分区,当然也就只有一个consumer组消费它。
四、为什么大数据环境下的消息队列常选择kafka?
  分布式存储数据,提供了更好的性能 可靠性 可扩展能力
  利用磁盘存储数据,且按照主题、分区来分布式存放数据,持久化存储,提供海量数据存储能力
  采用磁盘存储数据,连续进行读写保证性能,性能和磁盘的性能相关和数据量的大小无关
五、为什么Kafka 的写入操作是很快的?
  主要得益于它对磁盘的使用方法的不同 虽然Kafka 会持久化所有数据到磁盘,但本质上每次写入操作其实都只是把数据写入到操作系统的页缓存(page cache )中,然后由操作系统自行决定什么时候把页缓存中的数据写回磁盘上。这样的设计有 个主要优势:
   1、操作系统页缓存是在内存中分配的,所以消息写入的速度非常快。
   2、Kafka 不必直接与底层的文件系统打交道。所有烦琐的 1/0 操作都交由操作系统来处理。
   3、Kafka 写入操作采用追加写入( append )的方式,避免了磁盘随机写操作。
  Kafka 就是依靠下列4点达到了高吞吐量、低延时的设计目标的。
   1、大量使用操作系统页缓存,内存操作速度快且命中率高。
   2、Kafka 不直接参与物理 1/0 操作,而是交由最擅长此事的操作系统来完成。
   3、采用追加写入方式,摒弃了缓慢的磁盘随机读/写操作。
   4、使用以 sendfile 为代表的零拷贝技术加强网络间的数据传输效率。
六、消息持久化
  Kafk且是要持久化消息的,而且要把消息持久化到磁盘上。这样做的好处如下。
   解耦消息发送与消息消费:本质上来说, Kafka 最核心的功能就是提供了生产者-消费者模式的完整解决方案。通过将消息持久化使得生产者方不再需要直接和消费者方藕合,它只是简单地把消息生产出来井交由 Kafka 服务器保存即可,因此提升了整体的吞吐量。
   实现灵活的消息处理:很 Kafka 的下游子系统(接收 Kafka 消息的系统)都有这样的需求一一对于已经处理过的消息可能在未来的某个时间点重新处理 次,即所谓的消息重演( message replay )。消息持久化便可以很方便地实现这样的需求。
   另外, Kafka 实现持久化的设计也有新颖之处。普通的系统在实现持久化时可能会先尽量使用内存,当内存资源耗尽时,再 次性地把数据“刷盘”;而 Kafka 则反其道而行之,所有数据都会立即被写入文件系统的持久化日志中,之后 Kafka 服务器才会返回结果给客户端通知它们消息已被成功写入。这样做既实时保存了数据,又减少了 Kafka 程序对于内存的消耗,从而将节省出的内存留给页缓存使用,更进一步地提升了整体性能。
七、负载均衡和故障转移
  作为一个功能完备的分布式系统, Kafka 如果只提供了最基本的消息引擎功能肯定不足以帮助它脱颖而出。一套完整的消息引擎解决方案中必然要提供负载均衡 Cload balancing )和故障转移( fai l-over )功能。
  默认情况下 Kafka 的每台服务器都有均等的机会为 Kafka 的客户提供服务,可以把负载分散到所有集群中的机器上,避免出现“耗尽某台服务器”的情况发生。Kafka 默认提供了很智能的 leader 选举算法,可以在集群的所有机器上以均等机会分散各个partition的leader ,从而整体上实现了负载均衡。
  除了负载均衡,完备的分布式系统还需要支持故障转移 所谓故障转移,是指当服务器意外中止时,整个集群可以快速地检测到该失效( fai lur ),井立即将该服务器上的应用或服务自动转移到其他服务器上 故障转移通常是以“心跳”或“会话”的机制来实现的,即只要主服务器与备份服务器之间的心跳无法维持或主服务器注册到服务中心的会话超时过期了,那么就认为主服务器己无法正常运行,集群会自动启动某个备份服务器来替代主服务器的工作。
  Kafka 服务器支持故障转移的方式就是使用会话机制 。每台Kafka 服务器启动后会以会话的形式把自己注册到ZooKeeper 服务器上 。一旦该 服务器运转出现问题,与ZooKeeper 的会话便不能维持从而超时失效,此时 Kafka 集群
会选举出另一台服务器来完全代替这台服务器继续提供服务。

常用Message Queue对比

RabbitMQ

RabbitMQ是使用Erlang编写的一个开源的消息队列,本身支持很多的协议:AMQP,XMPP, SMTP, STOMP,也正因如此,它非常重量级,更适合于企业级的开发。同时实现了Broker构架,这意味着消息在发送给客户端时先在中心队列排队。对路由,负载均衡或者数据持久化都有很好的支持。

Redis

Redis是一个基于Key-Value对的NoSQL数据库,开发维护很活跃。虽然它是一个Key-Value数据库存储系统,但它本身支持MQ功能,所以完全可以当做一个轻量级的队列服务来使用。对于RabbitMQ和Redis的入队和出队操作,各执行100万次,每10万次记录一次执行时间。测试数据分为128Bytes、512Bytes、1K和10K四个不同大小的数据。实验表明:入队时,当数据比较小时Redis的性能要高于RabbitMQ,而如果数据大小超过了10K,Redis则慢的无法忍受;出队时,无论数据大小,Redis都表现出非常好的性能,而RabbitMQ的出队性能则远低于Redis。

ZeroMQ

ZeroMQ号称最快的消息队列系统,尤其针对大吞吐量的需求场景。ZeroMQ能够实现RabbitMQ不擅长的高级/复杂的队列,但是开发人员需要自己组合多种技术框架,技术上的复杂度是对这MQ能够应用成功的挑战。ZeroMQ具有一个独特的非中间件的模式,你不需要安装和运行一个消息服务器或中间件,因为你的应用程序将扮演这个服务器角色。你只需要简单的引用ZeroMQ程序库,可以使用NuGet安装,然后你就可以愉快的在应用程序之间发送消息了。但是ZeroMQ仅提供非持久性的队列,也就是说如果宕机,数据将会丢失。其中,Twitter的Storm 0.9.0以前的版本中默认使用ZeroMQ作为数据流的传输(Storm从0.9版本开始同时支持ZeroMQ和Netty作为传输模块)。

ActiveMQ

ActiveMQ是Apache下的一个子项目。 类似于ZeroMQ,它能够以代理人和点对点的技术实现队列。同时类似于RabbitMQ,它少量代码就可以高效地实现高级应用场景。

Kafka/Jafka

Kafka是Apache下的一个子项目,是一个高性能跨语言分布式发布/订阅消息队列系统,而Jafka是在Kafka之上孵化而来的,即Kafka的一个升级版。具有以下特性:快速持久化,可以在O(1)的系统开销下进行消息持久化;高吞吐,在一台普通的服务器上既可以达到10W/s的吞吐速率;完全的分布式系统,Broker、Producer、Consumer都原生自动支持分布式,自动实现负载均衡;支持Hadoop数据并行加载,对于像Hadoop的一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。Kafka通过Hadoop的并行加载机制统一了在线和离线的消息处理。Apache Kafka相对于ActiveMQ是一个非常轻量级的消息系统,除了性能非常好之外,还是一个工作良好的分布式系统。

猜你喜欢

转载自www.cnblogs.com/snow1314/p/12693043.html