MQ在分布式场景下的应用已经非常广泛了。但是在所有的MQ使用场景中,大多都要求不能丢消息,意味着必须有持久化的能力,传统行业常用的activemq、rabbitmq虽然有持久化能力,无奈的是性能太低,扩展性太差,对于互联网公司来说,要么就去基于他们去扩展,要么就是自己研发一个新的MQ,自从kafka横空出世,唤醒了人们对高性能 MQ的追求。实际上kafka0.8版本已经脱胎换骨,再也不只是适合日志收集的场景了,kafka在可靠性方面做了很多改进。实际上kafka已经可以用在企业级应用里面了。
如何达到高性能?
1、 顺序写
磁盘的IO是所有应用性能的万恶之源,磁盘的顺序写能达到几百M每秒,而随机写只有几十K,如果是一个千兆网卡,真实性能也就百M左右,可见,磁盘顺序写的威力巨大。
2、 零拷贝
某些情况下,数据的传输是不需要经过应用程序的,可以减少数据在用户空间和系统空间的缓冲区进行copy,降低对cpu和网卡的消耗,这样可以获得很好的性能,Linux下提供此功能的系统调用主要有sendfile、mmap、splice。
3、 扩展性
如果要想突破单机的性能,必须拥有良好的扩展性,kafka可以在topic下建立partition,partition才是kafka的最小单位,这样就意味着同一个topic可以持久化到N台物理机上,只要有足够的分区。Kafka天生的分布式特性,几乎可以无限的扩展。
实际上,kafka的吞吐量可以达到几万TPS,性能非常高。并且扩展性如此高,在大并发、大数据量的场景下非常适合。
怎么保证不丢消息?
丢消息主要有以下几个地方:
1、生产者发送消息。Kafka是采用ack机制保障的,如果消息没法送成功,也不会返回ack,所以,只要在生产者端做好重试机制就好。如何做好重试机制,又是一个非常大的话题,此处不扩展开来。Kafka服务端收到消息后可以直接复制到其他分片,成功后再通知生产者确定收到消息。就算不做同步的持久化,如果有三个节点,除非三个物理机同时宕机才会丢失数据。注意,这里如果仅仅是kafka进程挂掉是不会丢数据的,操作系统会把数据持久化到磁盘。
2、Kafka存储的消息会不会丢失?kafka有定时删除策略,不以是否消费为前提,也就意味着没有经过消费的消息删除后就丢了,因为磁盘足够大,几天不删应该不是问题,如果几天的数据没有被消费你都没发现,那只能怪你的监控系统太弱,或者你的应用量太小,出问题都没人发现,那也没有必要使用kafka。
3、消费消息。如果使用high level的api,所有消费者的信息都是存储在zookeeper中的,zookeeper的可靠性此处不必赘述。如果采用simple api,offset的可靠性要依赖于存储,务必小心。最好做充足的备份方案。无论哪种方式,如果不能正常消费,你可以不去移动offset,这个地方完全可以自己控制。
有重复的消息怎么办?
虽然这样造成了重复消息的问题,但是这是很难避免的,试想,像activeMQ那样,就算在服务端做了去重,消费时一样有可能会重复消费,不只是在MQ中,就算你调用一个普通的服务接口,也有可能重复调用,最好的办法是通过业务尽量实现幂等性。例如增加唯一键。
从这些角度考虑,在互联网和大并发的企业级应用中,kafka会越来越重要,会被更多的人重视,就算是不用kafka,也会有跟kafka类似的架构模式、原理差不多的MQ,类似于rocketMQ。现在差的,就是被更多的企业使用,更复杂的场景证明。