当前位置: 首页 > 科技观察

如何让你的数据库在高并发下更快?

时间:2023-03-15 09:48:17 科技观察

消息队列(MessageQueue)是一种利用高效可靠的数据传输机制进行平台无关数据通信的技术。消息队列具有消息投递、消息生产、消息消费、消息优先级等功能,为我们的分布式系统提供了丰富的数据通信、功能解耦、弹性伸缩、数据冗余、限流调峰、异步消息等能力.,是分布式系统的重要组成部分。当前的开源消息队列有各种各样的组件。如果你在Github上搜索MessageQueue,有4K+的资源。在这么多的消息队列开源项目中,我们比较熟悉的有RabbitMQ、Kafka、RocketMQ、ActiveMQ、Pulsar等,很多公司也根据业务需求定制了自己的消息队列中间件。这些消息队列组件各有各的特点和侧重点,适合自己的才是最好的。那么如何选择最合适的消息队列组件呢?本文选择目前应用最广泛的两种消息RabbitMQ和Kafka,探讨如何综合考虑消费模式、性能、语言支持、社区生态等多方面因素,选择一款合适的消息队列组件。概述1.RabbitMQRabbitMQ是一个历史悠久的消息队列中间件。最早可以追溯到2007年,它是一个用Erlang语言开发的AMQP(AdvancedMessageQueueProtocol高级消息队列协议)实现。AMQP是为面向消息的中间件设计的应用层协议的开放标准。基于这个协议,客户端和消息中间件可以不受产品、开发语言等条件的限制,传递消息。RabbitMQ最初起源于金融系统,在可靠性、可用性、可扩展性、消息持久化、高并发性等方面有着出色的表现。2.KafkaKafka最早由LinkedIn开发。它是一个用Scala语言开发的支持多分区、多副本、基于Zookeeper协调的分布式消息系统。它是一种高吞吐量、低延迟、容错的分布式发布-订阅消息系统,以其可水平扩展的高吞吐量而被广泛使用。在大数据和流数据处理方面,Kafka的周边生态也是一大优势。Cloudera、ApacheStorm、Spark、Flink等越来越多的开源分布式处理系统支持与Kafka集成。比较1.消费模式消费模式是指消息队列消费消息时的策略。分为两种,一种是Push模式,一种是Pull模式。推送模式是指当消息队列的服务器端收到新消息时,主动向消费者端推送(Push)消息。与Pull模式相比,这种消费模式实时性更好,但是当服务端消息较多时,可能会出现消费者来不及消费消息从而压垮消费者的情况。需要某些策略来避免这种情况的发生。拉取模式是指消息队列的服务端不主动向消费者推送消息,而是由消费者主动从服务端拉取(Pull)消息,通常是定时或者定量的方式。Pull模式的实时性低于Push模式。它的好处是消费者可以根据自己消费消息的能力来拉取消息,不会出现消息不能消费的情况。RabbitMQ同时支持Push模式和Pull模式,而Kafka只支持Pull模式。2.消息持久化消息持久化是指将消息队列中的消息保存到磁盘中,防止出现异常或服务器宕机等紧急情况时数据丢失。消息持久化是保证消息队列消息可靠性的关键技术之一。默认情况下,RabbitMQ不启用持久化操作。exchange、queue、message等数据都保存在内存中,这意味着如果RabbitMQ重启、关闭或崩溃,所有信息都会丢失。我们可以在使用RabbitMQ时显式声明exchange、queue、message等数据对象是持久化的,这样即使服务器宕机或者出现故障,我们也可以从硬盘中恢复这些数据。但是需要注意的是,如果RabbitMQ持久化所有这些对象,会严重影响RabbitMQ的性能,因为同步写入磁盘的速度会比写入内存慢很多,所以需要在可靠性和性能之间做出选择一个权衡。与RabbitMQ需要明确指定数据类型的持久化相比,Kafka从设计之初就依赖磁盘上的文件系统来存储消息。从传统的概念来看,磁盘的读写速度总是比内存慢很多,但实际上磁盘读写速度的快慢取决于我们如何使用它:“磁盘的线性写入速度一块SATARAID-5阵列盘可以达到数百M_s,而随机写入的速度只能达到100多KB_s,线性写入的速度比随机写入快数千倍。”Kafka的数据存储设计是基于磁盘文件的追加写入,数据读取也是顺序访问,这种数据存储设计带来了很大的优势:1.读操作不会阻塞写操作等操作,数据大小不会影响性能;2.磁盘的容量和内存相比,据说会大很多,消息队列的容量大,可以随时存,所以有不用担心失败导致数据丢失;综上所述,RabbitMQ和Kafka都支持消息持久化,但是RabbitMQ需要显式开启持久化,开启持久化会影响消息队列的性能,Kafka从设计之初就支持消息持久化,并且通过其优秀的设计,保证高效的消息读写,保证高吞吐量3.性能性能是我们技术选型的重要参考维度。消息队列,我们??最关注的性能指标之一就是它的吞吐量。在吞吐量这个性能指标上,Kafka基于其优秀的存储和读写设计,比RabbitMQ有更高的性能。一般来说,RabbitMQ的单机QPS在1万左右,而Kafka的单机QPS可以达到10万甚至上百万。这里我没有进行单机吞吐性能测试,引用网上其他团队进行的消息队列单机吞吐性能测试,让大家感受一下RabbitMQ和Kafka在吞吐性能上的区别。本次测试比较服务器发送小消息(124Byte)的性能。测试策略是不断增加发送端的压力,直到系统吞吐量不再上升,系统响应时间增加。这个时候服务端可以判断一条消息发生了性能瓶颈,此时的吞吐量是系统的最高吞吐量。测试结果如下:1.Kafka单机吞吐量17.3w/s。当达到这个吞吐量时,它的Broker磁盘IO就达到了瓶颈。Kafka能够实现单机如此高的吞吐量,主要得益于其优秀的设计。2、RabbitMQ的单机吞吐量为5.95w/s,CPU资源消耗比较高。主要是它支持AMQP协议,非常重量级,在消息可靠性和吞吐量之间做了一个权衡。可以看出,Kafka在吞吐量这个性能指标上相比RabbitMQ有明显的优势。说完吞吐量,再讨论另一个性能指标:延迟。事实上,在使用消息队列的背景下讨论延迟是有些矛盾的,因为使用消息队列意味着可以允许更高的延迟,因为使用消息队列可能会导致消息堆积,而且堆积的消息越多,从更高从消息生产到消息消费的延迟,对延迟要求高的场景不宜使用消息队列。我们应该使用具有较低延迟的解决方案,例如RPC远程过程调用。4.可靠性消息队列消息的可靠性也是我们技术选型的重点考虑因素之一,尤其是涉及到金融、支付、安全等领域,消息的可靠性尤为重要。保证消息可靠性的关键技术之一就是消息持久化,上面已经讨论过,RabbitMQ和Kafka都支持,这里不再赘述。这里我们讨论消息队列可靠性的另一个方面,消息投递(消费)的三种不同保证:1.atmostoncedelivery:消息最多投递一次,但可能会丢失2.atleastoncedelivery:消息是至少会被传递一次,但可能会被重复消费。3、准一发:保证只发一次,只有一次发。RabbitMQ和Kafka都支持最多一次投递和至少一次投递的保证,而Kafka在0.11.0.0版本之后,通过事务机制支持这种exactly-once投递的保证。5.可用性可靠性是保证消息不会丢失或重复消费,这里的可用性是指系统正常运行时间占总运行时间的百分比。高可用性也对应于低故障率。那么RabbitMQ和Kafka有什么区别呢?保证系统高可用的机制?RabbitMQ采用镜像集群策略来保证系统的高可用。在镜像集群模式下,消息队列和消息都会存储在集群中的多个实例上。也就是说,对于集群中的每一个队列,集群中的每一个节点都有一个完整的队列镜像,这样即使一个节点宕机,也不会影响整个集群的功能。并且即使某个主节点宕机,RabbitMQ集群也可以通过选主算法选举出新的主节点来恢复正常的服务。Kafka的高可用主要来源于其健壮的复制(Replication)策略。它使用类似PacificA的一致性协议,使用ISR(In-Sync-Replica)来保证多副本之间的同步,支持强一致性语义(通过acks实现)。6.社区生态和语言支持从长远来看,社区生态是我们选择解决方案时考虑的关键因素之一。一个开源的组件,用的人越多,社区越活跃,也就意味着别人踩过的坑越多,我们在开发中遇到问题的时候就越容易找到解决方案。同时,如果一个开源组件更新速度非常快,那么它可以快速修复之前版本的问题,同时快速迭代开发新功能。在社区生态方面,总体来说,Kafka的生态和周边环境比RabbitMQ更加成熟和丰富。Kafka有更多的开源客户端和负载均衡组件,知名的开源项目如Kubernetes和Spark也对Kafka有更好的支持。这也可能是因为Kafka的流数据概念在大数据处理方面更兼容大数据处理。与Kafka相比,RabbitMQ的社区规模可能要小一些,但毕竟也是一个经过验证的开源消息队列组件。一般来说,我们在使用过程中一般不会遇到社区无法解决的疑难问题。在语言支持方面,RabbitMQ和Kafka都支持非常多的语言。Kafka支持约17种语言,RabbitMQ支持约22种语言,Java、PHP、C++等主流语言均有支持。我相信在使用的编程语言方面应该没有太大问题。本文对RabbitMQ和Kafka这两个主流的消息队列组件进行了对比和探讨,希望能为大家在消息队列技术的选型上提供一些思路。大家在选择的时候要注意自己的业务需求和团队的技术栈体系,选择最合适的消息队列组件!