linux怎么开启rabbitmq服务器

linux怎么开启rabbitmq服务器,第1张

尽管有多种的负载均衡算法可以较好的把数据流量分配给服务器去负载,但如果负载均衡策略没有对网络系统状况的检测方式和能力,一旦在某台服务器或某段负载均衡设备与服务器网络间出现故障的情况下,负载均衡设备依然把一部分数据流量引向那台服

如果有一个消息生产者或者消息消费者通过amqp-client的客户端连接至节点1进行消息的发布或者订阅,那么此时的集群中的消息收发只与节点1相关。

如果消息生产者所连接的是节点2或者节点3,此时队列1的完整数据不在该两个节点上,那么在发送消息过程中这两个节点主要起了一个路由转发作用,根据这两个节点上的元数据转发至节点1上,最终发送的消息还是会存储至节点1的队列1上。

RabbitMQ 集群是一个或多个节点的逻辑分组,每个节点共享用户、虚拟主机、队列、交换器、绑定、运行时参数和其他分布式状态。

一些分布式系统 有leader和follower节点。 对于 RabbitMQ 来说, RabbitMQ集群中的所有节点都是平等的。

RabbitMQ 集群可以通过多种方式组成:

RabbitMQ 节点绑定到端口以接受客户端和 CLI 工具连接。其他进程和工具(例如 SELinux)可能会阻止 RabbitMQ 绑定到端口。发生这种情况时,节点将无法启动。

CLI工具、客户端库和 RabbitMQ 节点也会打开连接(客户端 TCP 套接字)。防火墙会阻止节点和 CLI 工具相互通信。确保可以访问以下端口:

RabbitMQ节点和 CLI 工具(例如 rabbitmqctl)使用 cookie 来确定它们是否被允许相互通信。为了让两个节点能够通信,它们必须具有相同的共享密钥,称为 Erlang cookie。cookie 只是一串最多 255 个字符的字母数字字符。 它通常存储在本地文件中。该文件必须只能由所有者访问(例如具有 600 或类似的 UNIX 权限)。每个集群节点必须具有相同的 cookie。

在 UNIX 系统上,cookie通常是位于/var/lib/rabbitmq/erlangcookie(由服务器使用)和$HOME/erlangcookie(由 CLI 工具使用)。

RabbitMQ 节点使用主机名相互寻址

<!== 所有主机执行 ==>

<!== 所有主机执行 ==>

<!== 所有主机执行 ==>

默认配置文件/usr/lib/rabbitmq/lib/rabbitmq_server-3717/ebin/rabbitapp

<!== node01主机执行 ==>

<!== node02主机执行 ==>

<!== node03主机执行 ==>

<!== 所有主机执行 ==>

因RabbitMQ 集群元数据同步基于 cookie 共享方案实现

文件路径/var/lib/rabbitmq/erlangcookie

<!== node02、node03主机执行 ==>

<!== 任意主机执行 ==>

节点分为:磁盘节点及内存节点

RAM节点是一种特殊情况,可用于提高具有高队列、交换或绑定搅动的集群的性能。RAM节点不提供更高的消息速率。 官方建议在绝大多数情况下,仅使用磁盘节点。

如果一个集群中都是RAM节点,那么集群停止,将无法再次启动,并将丢失所有数据

官方提示:经典队列镜像将在未来版本中删除,考虑改用仲裁队列或非复制经典队列

每个镜像队列由一个领导副本和一个或多个镜像副本,leader被托管的节点成为leader节点。首先应用给定队列的所有 *** 作 在队列的leader节点上,然后传播到镜像。

如果承载队列的leader节点出现故障,则只要已同步,最旧的镜像将升级为新的leader。根据队列镜像参数,也可以升级未同步的镜像。

队列通过策略启用了镜像,策略模式的说明如下:

每当队列的策略发生变化时,它都保持其现有的镜像尽可能适用新策略。

设置的镜像队列可以通过开启的网页的管理端Admin->Policies,也可以通过命令。

管理端界面:

命令行:

为避免集群中的某个节点托管大多数leader队列,因此导致高负载,leader队列应合理均匀的分布在集群节点上。控制leader队列分布节点策略有三种,可以在rabbitmqconf文件中定义queue_master_locator参数设置

修改节点策略可能会导致现有的leader队列没有在新的策略中,为了防止消息丢失,RabbitMQ会保留现有的leader直到至少另一个镜像已同步,一旦发生同步,消费者将与leader断开连接,需要重新连接。

如果leader故障,其他镜像升级为leader过程如下:

如果消费者使用 自动确认模式 ,那么消息可能会丢失。这与非镜像队列没有什么不同:代理认为消息一旦以自动确认模式发送给消费者,就会被确认。

如果客户端突然断开连接,则可能永远不会收到消息。在镜像队列的情况下,如果leader死亡,那些正在以 自动确认模式 发送给消费者的消息可能永远不会被这些客户端接收,并且不会被新leader重新排队。由于消费客户端连接到存活节点的可能性,消费者取消通知有助于识别此类事件何时发生。 当然,在实践中,如果数据安全性不如吞吐量重要,那么自动确认模式是可行的方法。

节点可以随时加入集群。 根据队列的配置,当节点加入集群时,队列可能会在新节点上添加镜像。 此时,新镜像将是空的:它不会包含队列中任何现有的内容。 这样的镜像将接收发布到队列的新消息,因此随着时间的推移将准确地表示镜像队列的尾部。 随着消息从镜像队列中排出,新镜像丢失消息的队列头部的大小将缩小,直到最终镜像的内容与leader的内容完全匹配。 在这一点上,镜像可以被认为是完全同步的。

新添加的镜像不提供添加镜像之前存在的队列内容的额外形式的冗余或可用性,除非队列已明确同步。 由于在发生明确同步时队列变得无响应,因此最好允许正在从中排出消息的活动队列自然同步,并且仅明确同步非活动队列。

启用自动队列镜像时,请考虑所涉及队列的预期磁盘数据集 。 具有庞大数据集(例如,数十 GB 或更多)的队列必须将其复制到新添加的镜像中,这会给集群资源(例如网络带宽和磁盘 I/O)带来很大的负载。

要查看镜像状态(是否同步):

手动同步队列:

取消正在进行的同步:

如果你停止一个包含镜像队列leader的 RabbitMQ 节点,其他节点上的一些镜像将被提升为leader。 如果继续停止节点,那么将到达一个镜像队列不再有镜像的点:它仅存在于一个节点上,且该节点上它是leader。 如果它的最后一个剩余节点关闭,但是镜像队列被声明为持久的,那么队列中的持久消息将在该节点重新启动后继续存在。

然而,镜像目前无法知道它的队列内容是否已经偏离了它重新加入的leader。 因此,当一个镜像重新加入一个镜像队列时, 它会丢弃已经拥有的任何持久本地内容并开始为空

默认情况下,RabbitMQ 将拒绝leader节点在受控关闭(即明确停止 RabbitMQ 服务或关闭 *** 作系统)时提升非同步镜像,以避免消息丢失; 相反,整个队列将关闭,就好像未同步的镜像不存在一样。

leader节点不受控制的关闭(即服务器或节点崩溃,或网络中断)仍将触发未同步镜像的提升。

如果您希望在所有情况下都让leader队列移动到未同步的镜像(即,您会选择队列的可用性而不是避免由于未同步的镜像升级而导致的消息丢失),那么将 ha-promote-on-shutdown 策略键设置为 always 而不是比它的默认值 when-synced 。

如果 ha-promote-on-failure 策略键设置为 when-synced ,则即使 ha-promote-on-shutdown 键设置为 always ,也不会提升未同步的镜像。 这意味着如果leader节点发生故障,队列将变得不可用,直到leader恢复。 如果leader队列永久丢失,队列将不可用,除非它被删除(这也将删除其所有内容)并重新声明。

当队列的所有镜像都关闭时,可能会丢失队列的leader。 在正常 *** 作中,队列关闭的最后一个节点将成为leader,该节点在再次启动时仍然是leader(因为它可能收到了其他镜像没有看到的消息)。

但是,当您调用 rabbitmqctl forget_cluster_node 时,RabbitMQ 将尝试为每个在我们忘记的节点上有其领导者的队列找到当前停止的镜像,并在它再次启动时“提升”该镜像成为新的领导者。 如果有多个候选者,将选择最近停止的镜像。

重要的是要理解 RabbitMQ 只能在 forget_cluster_node 期间提升停止的镜像,因为任何再次启动的镜像都会清除它们的内容,如上面“停止节点和同步”中所述。 因此在停止的集群中移除丢失的leader时,您必须在再次启动镜像之前调用 rabbitmqctl forget_cluster_node 。

    消费者客户端可以通过推模式和拉模式来进行消息消费。
    当rabbitmq队列有多个消费者时,队列收到的消息将以轮询(round-robin)的分发方式发送给消费者。每条消息只会发送给订阅列表里的一个消费者。如果现在负载加重,那么只需要创建更多的消费者来消费处理消息即可。
    很多时候轮询的分发机制也不是那么优雅。默认情况下,如果有n个消费者,那么RabbitMQ会将第m条消息分发给第m%n(取余的方式)个消费者,RabbitMQ不管消费者是否消费并已经确认(BasicAck)了消息。 试想一下,如果某些消费者任务繁重,来不及消费那么多的消息,而某些其他消费者由于某些原因(比如业务逻辑简单、机器性能卓越等)很快地处理完了所分配到的消息,进而进程空闲,这样就会造成整体应用吞吐量的下降。

    比如在订阅消费队列之前,消费端程序调用了channelbasicQos(5),之后订阅了某个队列进行消费。RabbitMQ 会保存一个消费者的列表,每发送一条消息都会为对应的消费者计数,如果达到了所设定的上限,那么 RabbitMQ 就不会向这个消费者再发送任何消息。直到消费者确认了某条消息之后 RabbitMQ 将相应的计数减1 ,之后消费者可以继续接收消息,直到再次到达计数上限。

    对于channelbasicQos还有要特别注意的一点是它的重载方法

    global为true的时候,是该信道上所有的消费者未确认的消息数上限总和
    为false的时候是针对单个消费者
比如:一个信道设置了

    那么这里每个消费者最多只能收到3个未确认的消息,两个消费者能收到的未确认的消息个数之和的上限为5。
如无特殊需要,最好只使用global=false 设置,这也是默认的设置。

    消息的顺序性是指消费者消费到的消息和发送者发布的消息的顺序是一致的。
    如果生产者发布的消息分别为 msg1 msg2 msg3 ,那么消费者必然也是按照 msg1 msg2 msg3 的顺序进行消费的。

     在以下情况下消息的顺序性会被打破:

    1如果生产者使用了事务机制,在发送消息之后遇到异常进行了事务回滚,那么需要重新补偿发送这条消息,如果补偿发送是在另一个线程实现的,那么消息在生产者这个源头就出现了错序。
    2同样,如果启用 publisher confirm时,在发生超时、中断,又或者是收到RabbitMQ的 BasicNack命令时,那么同样需要补偿发送,结果与事务机制一样会错序。或者这种说法有些牵强,我们可以固执地认为消息的顺序性保障是从存入队列之后开始的,而不是在发送的时候。
    3考虑另一种情形,如果生产者发送的消息设置了不同的超时时间,并且也设置了死信队列,整体上来说相当于一个延迟队列,那么消费者在消费这个延迟队列的时候,消息的顺序必然不会和生产者发送消息的顺序一致。
    4如果消息设置了优先级,那么消费者消费到的消息也必然不是顺序性的
    5使用BasicNack/Reject将消息拒绝,比如:
    如果一个队列按照前后顺序分有msg1、msg2、msg3、msg4这4个消息,同时有ConsumerA和 ConsumerB 这两个消费者同时订阅了这个队列。队列中的消息轮询分发到各个消费者之中, ConsumerA 中的消息为 msg1和msg3,ConsumerB中的消息为msg2、msg4。ConsumerA收到消息 msg1 之后并不想处理而调用了BasicNack/Reject 将消息拒绝,与此同时将 requeue 设置为 true,这样这条消息就可以重新存入队列中。消息 msg1之后被发送到了 ConsumerB中,此时 ConsumerB已经消费了msg2、msg4,之后再消费 msg1,这样消息顺序性也就错乱了。或者消息 msg1 又重新发往 ConsumerA中,此时 ConsumerA已经消费了msg3,那么再消费 msg1,消息顺序性也无法得到保障。

QueueingConsumer 还包含(但不仅限于)以下一些缺陷∶

    一般消息中间件的消息传输保障分为三个层级。

rabbitmq支持最少一次和最多一次。
最少一次:
(1)消息生产者需要开启事务机制或者 publisher confim 机制,以确保消息可以可靠地传输到RabbitMQ中。
(2)消息生产者需要配合使用 mandatory参数或者备份交换器来确保消息能够从交换器路由到队列中,进而能够保存下来而不会被丢弃。
(3)消息和队列都需要进行持久化处理,以确保 RabbitMQ 服务器在遇到异常情况时不会造成消息丢失
(4)消费者在消费消息的同时需要将 autoAck 设置为 false,然后通过手动确认的方式去确认已经正确消费的消息,以避免在消费端引起不必要的消息丢失。

最多一次:
就无须考虑以上那些方面,生产者随意发送,消费者随意消费,不过这样很难确保消息不会丢失

恰好一次:
恰好一次是RabbitMQ目前无法保障的。

一、消费端限流

1什么是消费端的限流

假设一个场景,首先,Rabbitmq服务器有上万条未处理的消息,我们随便打开一个消费者客户端,就会出现:巨大的消息瞬间全部推送过来,但是我们单个客户端无法同时处理这么多数据!

2RabbitMQ提供了一种Qos(服务质量控制)功能,即在非自动确认消息的前提下,如果一定数目的消息(通过基于consume或者channel设置Qos的值)未被确认前,不进行消费新的消息。

void BasicQos(uint prefetchSize,ushort prefetchCount,bool global);

prefetchCount:会告诉RabbitMQ不要同时给一个消费者推送多于N个消息,即一旦有N个消息还没有ACK,则该comsumer将block掉,直到有消息ack

global:true/false 是否将上面的设置应用于channel,就是限制是channel级别还是consumer级别

二、消费端的手动ACK和NACK

消费端进行消费的时候,如果由于业务异常我们可以进行日志的记录,然后进行补偿!

如果由于服务器宕机等严重问题,那我们就需要手动进行ACK保障消费端消费成功!

三、消费端的重回队列

1消费端重回队列是为了对没有处理成功的消息,把消息重新会递给Broker

2一般我们在实际应用中,都会关闭重回队列,也就是设置为false

四、TTL队列/消息

1TTL

TTL:time  to live 的缩写,也就是生存时间

RabbitMQ支持消息的过期时间,在消息发送时可以进行指定

RabbitMQ支持队列的过去时间,从消息入队列开始计算,只要超过了队列的超时时间配置,那么消息会自动删除

2DLX

DLX:Dead-Letter-Exchange,死信队列

利用DLX,当消息在一个队列中变成死信(dead message)之后,它能被重新publish到另一个Exchange,这个Exchange就是DLX

DLX也是一个正常的Exchange,和一般的Exchange没有区别,它能在任何的队列上被指定,实际上就是设置某个队列的属性

当一个队列中有死信时,RabbitMQ就会自动的将这个消息重新发布到设置的Exchange上去,进而被路由到另一个队列

可以监听DLX这个队列中的消息做相应的处理,这个特性可以弥补RabbitMQ30以前支持的immediate参数的功能

3消息变成死信的情况

消息被拒绝(basicreject/basicnack),并且requeue=false

消息TTL过期

队列达到最大长度

4DLX死信队列设置

首先需要设置死信队列的exchange(dlxexchange)、queue(dlxqueue)和路由规则(RoutingKey:#),然后进行绑定

然后进行正常交换机、队列、绑定,只不过我们需要在队列上加上一个参数即可:argumentsput("x-dead-letter-exchange","dlxexchange");


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zz/13483442.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-08-16
下一篇 2023-08-16

发表评论

登录后才能评论

评论列表(0条)

保存