五月花号 發表於 2025-9-20 23:59:00

【RabbitMQ】核心模型简介,以及消息的生产与消费

<h3>本章学习目标</h3>
<ul>
<li>
<p class="ds-markdown-paragraph">理解AMQP模型中的核心概念:Connection, Channel, Producer, Consumer, Queue。</p>
</li>
</ul>
<ul>
<li>
<p class="ds-markdown-paragraph">创建一个.NET项目并添加RabbitMQ客户端库。</p>
</li>
<li>
<p class="ds-markdown-paragraph">使用C#编写代码发送一条消息("Hello World")。</p>
</li>
<li>
<p class="ds-markdown-paragraph">使用C#编写代码接收并处理这条消息。</p>
</li>
</ul>
<hr>
<h2>一、理论部分</h2>
<h3>1. AMQP 0-9-1 核心模型简介</h3>
<p class="ds-markdown-paragraph">在编写代码前,我们需要理解几个核心概念,它们构成了RabbitMQ一切功能的基础:</p>
<ul>
<li>
<p class="ds-markdown-paragraph">生产者 (Producer):发送消息的应用程序。</p>
</li>
<li>
<p class="ds-markdown-paragraph">消费者 (Consumer):接收消息的应用程序。</p>
</li>
<li>
<p class="ds-markdown-paragraph">队列 (Queue):一个类似于邮箱的存储结构,位于RabbitMQ内部,用于存储消息。多个生产者可以向同一个队列发送消息,多个消费者也可以从同一个队列接收消息。消息只能存储在队列中。</p>
</li>
<li>
<p class="ds-markdown-paragraph">连接 (Connection):一个TCP连接,应用程序通过它与RabbitMQ服务器建立网络连接。创建连接的开销较大。</p>
</li>
<li>
<p class="ds-markdown-paragraph">通道 (Channel):建立在连接之上的虚拟连接。几乎所有的操作都在通道中进行。使用通道的原因是为了避免频繁创建和销毁TCP连接带来的巨大开销。一个连接可以包含多个通道。</p>
</li>
</ul>
<p class="ds-markdown-paragraph">简单工作流:<code>Producer</code>&nbsp;-&gt; (<code>Connection</code>&nbsp;-&gt;&nbsp;<code>Channel</code>) -&gt;&nbsp;<code>Queue</code>&nbsp;-&gt; (<code>Channel</code>&nbsp;-&gt;&nbsp;<code>Connection</code>) -&gt;&nbsp;<code>Consumer</code></p>
<h3>2.&nbsp;<code>RabbitMQ.Client</code>&nbsp;库</h3>
<p class="ds-markdown-paragraph">这是RabbitMQ官方提供的.NET客户端库,它实现了AMQP协议,是我们与RabbitMQ服务器交互的桥梁。我们将通过NuGet包管理器来安装它。</p>
<hr>
<h2>二、实操部分:创建"Hello World"</h2>
<p class="ds-markdown-paragraph">我们将创建两个控制台应用程序:一个生产者(Send)和一个消费者(Receive)。</p>
<h3>第1步:创建项目并添加NuGet包</h3>
<ol start="1">
<li>
<p class="ds-markdown-paragraph">打开IDE(如Visual Studio或VS Code),创建一个新的解决方案(Solution)。</p>
</li>
<li>
<p class="ds-markdown-paragraph">在该解决方案中,创建两个新的控制台应用程序项目,分别命名为&nbsp;<code>Send</code>&nbsp;和&nbsp;<code>Receive</code>。</p>
</li>
<li>
<p class="ds-markdown-paragraph">为两个项目添加&nbsp;<code>RabbitMQ.Client</code>&nbsp;NuGet包。</p>
<ul>
<li>
<p class="ds-markdown-paragraph">Visual Studio:右键点击项目 -&gt; "Manage NuGet Packages..." -&gt; 浏览 -&gt; 搜索&nbsp;<code>RabbitMQ.Client</code>&nbsp;-&gt; 安装。</p>
</li>
<li>
<p class="ds-markdown-paragraph">.NET CLI:</p>
<div class="md-code-block md-code-block-light">
<div class="md-code-block-banner-wrap">
<div class="md-code-block-banner md-code-block-banner-lite">
<div class="_121d384">
<div class="d2a24f03">
<div class="cnblogs_code">
<pre>cd /path/to/<span style="color: rgba(0, 0, 0, 1)">Send
dotnet add package RabbitMQ.Client

cd </span>/path/to/<span style="color: rgba(0, 0, 0, 1)">Receive
dotnet add package RabbitMQ.Client</span></pre>
</div>
</div>
</div>
</div>
</div>
</div>
</li>
</ul>
</li>
</ol>
<h3>第2步:编写生产者(Send.cs)</h3>
<p class="ds-markdown-paragraph">将&nbsp;<code>Send</code>&nbsp;项目中的&nbsp;<code>Program.cs</code>&nbsp;替换为以下代码。请务必将&nbsp;<code>hostName</code>、<code>userName</code>&nbsp;和&nbsp;<code>password</code>&nbsp;替换为在上1章中设置的值(如果按教程做,应该是&nbsp;<code>localhost</code>,&nbsp;<code>myuser</code>,&nbsp;<code>mypassword</code>)。</p>
<div class="md-code-block md-code-block-light">
<div class="md-code-block-banner-wrap">
<div class="md-code-block-banner md-code-block-banner-lite">
<div class="_121d384">
<div class="d2a24f03">
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.Text;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> RabbitMQ.Client;

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 1. 创建连接工厂(ConnectionFactory)并设置连接参数</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> factory = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ConnectionFactory()
{
    HostName </span>= <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">localhost</span><span style="color: rgba(128, 0, 0, 1)">"</span>,   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> RabbitMQ服务器地址</span>
    UserName = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">myuser</span><span style="color: rgba(128, 0, 0, 1)">"</span>,      <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 用户名</span>
    Password = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">mypassword</span><span style="color: rgba(128, 0, 0, 1)">"</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 密码</span>
<span style="color: rgba(0, 0, 0, 1)">};

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 2. 使用工厂创建一个连接(Connection)和一个通道(Channel)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 'using' 语句确保在代码块结束时,连接和通道会被正确关闭和释放,这是很重要的。</span>
<span style="color: rgba(0, 0, 255, 1)">using</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> connection =<span style="color: rgba(0, 0, 0, 1)"> factory.CreateConnection())
</span><span style="color: rgba(0, 0, 255, 1)">using</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> channel =<span style="color: rgba(0, 0, 0, 1)"> connection.CreateModel())
{
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 3. 声明一个队列。如果队列不存在,则创建它。
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 参数说明:
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> queue: "hello" - 队列的名称
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> durable: false - 队列是否持久化(服务器重启后是否存在)
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> exclusive: false - 是否为当前连接的专用队列(其他连接不能访问)
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> autoDelete: false - 当最后一个消费者断开后,队列是否自动删除</span>
    channel.QueueDeclare(queue: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">hello</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
                         durable: </span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">,
                         exclusive: </span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">,
                         autoDelete: </span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">,
                         arguments: </span><span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">);

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 4. 准备要发送的消息</span>
    <span style="color: rgba(0, 0, 255, 1)">string</span> message = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">Hello World!</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">var</span> body = Encoding.UTF8.GetBytes(message); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 将消息转换为字节数组

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 5. 发布消息到队列
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 参数说明:
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> exchange: "" - 使用默认的(无名)交换机
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> routingKey: "hello" - 路由键,对于默认交换机,它指定了消息要发送到的队列名称
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> basicProperties: null - 消息属性(如持久化)
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> body: body - 消息体</span>
    channel.BasicPublish(exchange: <span style="color: rgba(128, 0, 0, 1)">""</span><span style="color: rgba(0, 0, 0, 1)">,
                         routingKey: </span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">hello</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
                         basicProperties: </span><span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">,
                         body: body);

    Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)"> Sent {message}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
}

Console.WriteLine(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)"> Press to exit.</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
Console.ReadLine();</span></pre>
</div>
</div>
</div>
</div>
</div>
</div>
<p class="ds-markdown-paragraph">代码解析:</p>
<ul>
<li>
<p class="ds-markdown-paragraph">我们首先创建了一个连接工厂,并配置了连接到我们本地RabbitMQ服务器所需的参数。</p>
</li>
<li>
<p class="ds-markdown-paragraph">然后,我们建立了连接和通道。这是与RabbitMQ交互的标准方式。</p>
</li>
<li>
<p class="ds-markdown-paragraph"><code>QueueDeclare</code>&nbsp;是幂等的——它只会在队列不存在时创建它。</p>
</li>
<li>
<p class="ds-markdown-paragraph">默认交换机(<code>""</code>)是一个直连交换机(Direct Exchange),它会把消息路由到&nbsp;<code>routingKey</code>&nbsp;完全匹配的队列中。所以这里&nbsp;<code>routingKey: "hello"</code>&nbsp;意味着消息会被投递到名为&nbsp;<code>hello</code>&nbsp;的队列。</p>
</li>
</ul>
<h3>第3步:运行生产者并查看管理后台</h3>
<ol start="1">
<li>
<p class="ds-markdown-paragraph">运行&nbsp;<code>Send</code>&nbsp;项目(在Visual Studio中按F5,或使用CLI命令&nbsp;<code>dotnet run</code>)。</p>
</li>
<li>
<p class="ds-markdown-paragraph">会在控制台看到&nbsp;<code> Sent Hello World!</code>。</p>
</li>
<li>
<p class="ds-markdown-paragraph">现在,打开RabbitMQ管理后台 (http://localhost:15672),登录后点击&nbsp;Queues&nbsp;标签页。应该能看到一个名为&nbsp;<code>hello</code>&nbsp;的队列,并且它下面有&nbsp;1&nbsp;条消息正准备被消费("Ready"状态)!<br></p>







</li>







</ol>
<h3>第4步:编写消费者(Receive.cs)</h3>
<p class="ds-markdown-paragraph">现在我们来编写消费者程序,从&nbsp;<code>hello</code>&nbsp;队列中取出消息。</p>
<p class="ds-markdown-paragraph">将&nbsp;<code>Receive</code>&nbsp;项目中的&nbsp;<code>Program.cs</code>&nbsp;替换为以下代码:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> System.Text;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> RabbitMQ.Client;
</span><span style="color: rgba(0, 0, 255, 1)">using</span><span style="color: rgba(0, 0, 0, 1)"> RabbitMQ.Client.Events;

</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 同生产者一样,创建连接和通道</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> factory = <span style="color: rgba(0, 0, 255, 1)">new</span> ConnectionFactory() { HostName = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">localhost</span><span style="color: rgba(128, 0, 0, 1)">"</span>, UserName = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">myuser</span><span style="color: rgba(128, 0, 0, 1)">"</span>, Password = <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">mypassword</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)"> };
</span><span style="color: rgba(0, 0, 255, 1)">using</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> connection =<span style="color: rgba(0, 0, 0, 1)"> factory.CreateConnection())
</span><span style="color: rgba(0, 0, 255, 1)">using</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> channel =<span style="color: rgba(0, 0, 0, 1)"> connection.CreateModel())
{
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 声明队列。这一步也是必需的,以防我们先启动消费者,而队列还不存在。</span>
    channel.QueueDeclare(queue: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">hello</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
                         durable: </span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">,
                         exclusive: </span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">,
                         autoDelete: </span><span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">,
                         arguments: </span><span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">);

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 创建一个事件消费者(EventingBasicConsumer)对象,并关联到我们的通道</span>
    <span style="color: rgba(0, 0, 255, 1)">var</span> consumer = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> EventingBasicConsumer(channel);

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 当消费者收到消息时,触发这个事件</span>
    consumer.Received += (model, ea) =&gt;<span style="color: rgba(0, 0, 0, 1)">
    {
      </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 消息体是字节数组,我们需要将其转换回字符串</span>
      <span style="color: rgba(0, 0, 255, 1)">var</span> body =<span style="color: rgba(0, 0, 0, 1)"> ea.Body.ToArray();
      </span><span style="color: rgba(0, 0, 255, 1)">var</span> message =<span style="color: rgba(0, 0, 0, 1)"> Encoding.UTF8.GetString(body);
      Console.WriteLine($</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)"> Received {message}</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
    };

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 开始消费队列中的消息
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 参数说明:
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> queue: "hello" - 要消费的队列名称
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> autoAck: true - 自动确认模式。如果为true,消息一旦被送达,RabbitMQ会立即将其从队列中标记为删除。
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> consumer: consumer - 我们上面定义的消费者对象</span>
    channel.BasicConsume(queue: <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">hello</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,
                         autoAck: </span><span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">,
                         consumer: consumer);

    Console.WriteLine(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)"> Press to exit.</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">);
    Console.ReadLine(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 保持程序运行,持续监听消息</span>
}</pre>
</div>
<p class="ds-markdown-paragraph">代码解析:</p>
<ul>
<li>
<p class="ds-markdown-paragraph">前面的连接、通道、队列声明步骤与生产者完全一致,这确保了所需的队列存在。</p>
</li>
<li>
<p class="ds-markdown-paragraph">我们创建了一个&nbsp;<code>EventingBasicConsumer</code>&nbsp;对象,并为它的&nbsp;<code>Received</code>&nbsp;事件订阅了一个处理方法。每当有消息到达时,这个匿名方法就会被调用。</p>
</li>
<li>
<p class="ds-markdown-paragraph"><code>BasicConsume</code>&nbsp;方法启动消费过程。它将我们的消费者注册到指定的队列。</p>
</li>
<li>
<p class="ds-markdown-paragraph"><code>autoAck: true</code>&nbsp;表示自动确认模式。这意味着消费者一收到消息,RabbitMQ就认为它已成功处理并立即从队列中删除该消息。这是一种简单的模式,但如果消费者在处理消息过程中崩溃,消息就会丢失。我们将在下一章学习更可靠的手动确认模式。</p>
</li>
</ul>
<h3>第5步:运行消费者</h3>
<ol start="1">
<li>
<p class="ds-markdown-paragraph">运行&nbsp;<code>Receive</code>&nbsp;项目。</p>
</li>
<li>
<p class="ds-markdown-paragraph">会立刻在控制台看到&nbsp;<code> Received Hello World!</code>。消费者程序取走了我们之前发送的消息并打印了出来。</p>
</li>
<li>
<p class="ds-markdown-paragraph">再次查看管理后台的&nbsp;Queues&nbsp;页面,会发现&nbsp;<code>hello</code>&nbsp;队列中的消息数又变回了&nbsp;0。</p>
</li>
</ol>
<p class="ds-markdown-paragraph">尝试一下:</p>
<ol start="1">
<li>
<p class="ds-markdown-paragraph">先运行&nbsp;<code>Receive</code>&nbsp;程序,让它保持运行并监听消息。</p>
</li>
<li>
<p class="ds-markdown-paragraph">然后再运行&nbsp;<code>Send</code>&nbsp;程序多次。</p>
</li>
<li>
<p class="ds-markdown-paragraph">观察&nbsp;<code>Receive</code>&nbsp;的控制台,它会实时地打印出每一条新收到的消息。</p>
</li>
</ol><hr>
<h2>总结</h2>
<p class="ds-markdown-paragraph">我们已经成功实现了一个RabbitMQ应用程序。在本文中,我们:</p>
<ol start="1">
<li>
<p class="ds-markdown-paragraph">创建了.NET项目并引入了&nbsp;<code>RabbitMQ.Client</code>&nbsp;库。</p>
</li>
<li>
<p class="ds-markdown-paragraph">理解了AMQP模型中的&nbsp;<code>Connection</code>、<code>Channel</code>、<code>Queue</code>、<code>Producer</code>&nbsp;和&nbsp;<code>Consumer</code>&nbsp;等核心概念。</p>
</li>
<li>
<p class="ds-markdown-paragraph">编写了生产者代码,成功向名为&nbsp;<code>hello</code>&nbsp;的队列发送了一条消息。</p>
</li>
<li>
<p class="ds-markdown-paragraph">编写了消费者代码,成功从队列中取出了消息并进行处理。</p>
</li>
<li>
<p class="ds-markdown-paragraph">使用了管理后台来验证消息的流动。</p>
</li>
</ol>
<p class="ds-markdown-paragraph">这是一个最简单的模型,生产者和消费者直接与队列打交道。在下一章,我们将学习如何实现工作队列(Work Queue)与消息确认(Ack),让多个消费者共同处理任务,这将使我们的应用变得更加实用和强大。</p><br><br>
来源:https://www.cnblogs.com/jixingsuiyuan/p/19103083
頁: [1]
查看完整版本: 【RabbitMQ】核心模型简介,以及消息的生产与消费