RabbitMQ: 入門指南

如何使用 Stackhero 連接 RabbitMQ

以下將說明如何利用 Aio Pika library,讓您的 Python 應用程式連接至 RabbitMQ。在大多數情況下,您只需提供 AMQPS URL,即可建立安全連線:

connection = await aio_pika.connect_robust(
  "amqps://admin:<PASSWORD>@<XXXXXX>.stackhero-network.com:<AMQP_PORT_TLS>",
)

以下是一個完整範例,展示如何建立安全連線至 RabbitMQ、建立 channel 及宣告一個基本 queue。這是驗證您的設定是否正確的好方法:

import asyncio
import logging
import aio_pika

async def main() -> None:
    # 如果您想查看 debug log,可以取消註解下一行
    # logging.basicConfig(level=logging.DEBUG)

    connection = await aio_pika.connect_robust(
        "amqps://admin:<PASSWORD>@<XXXXXX>.stackhero-network.com:<AMQP_PORT_TLS>"
    )

    async with connection:
        print("The connection worked!")
        channel = await connection.channel()
        await channel.set_qos(prefetch_count=10)
        queue = await channel.declare_queue("test_queue", auto_delete=True)

if __name__ == "__main__":
    asyncio.run(main())

如果您在 Python 連線時遇到如下錯誤:

aiormq.exceptions.AMQPConnectionError: [Errno 5] [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1006)

這通常代表您的系統缺少 Let's Encrypt 的 CA 憑證。您可以透過安裝作業系統常見的 CA 憑證套件來解決:

  1. Ubuntu/Debian,請執行:

    sudo apt install ca-certificates
    
  2. Alpine Linux,請執行:

    apk add ca-certificates
    

如果您無法使用上述指令,也可以手動安裝 CA 憑證:

  1. https://letsencrypt.org/certs/isrgrootx1.pem 下載 Let's Encrypt CA 憑證。

  2. 然後在 Python 程式中指定 CA 憑證檔案來連接 RabbitMQ:

    import ssl
    
    ssl_context = ssl.create_default_context()
    ssl_context.load_verify_locations(cafile='isrgrootx1.pem')
    
    connection = await aio_pika.connect_robust(
      "amqps://admin:<PASSWORD>@<XXXXXX>.stackhero-network.com:<AMQP_PORT_TLS>",
      ssl_context=ssl_context
    )
    

以下是使用 Let's Encrypt CA 憑證進行安全連線的完整範例:

import asyncio
import logging
import ssl
import aio_pika

async def main() -> None:
    # 如需啟用 debug log,可取消註解下行
    # logging.basicConfig(level=logging.DEBUG)

    ssl_context = ssl.create_default_context()
    # 載入您下載的 Let's Encrypt CA 憑證
    # 例如:wget https://letsencrypt.org/certs/isrgrootx1.pem
    ssl_context.load_verify_locations(cafile='isrgrootx1.pem')

    connection = await aio_pika.connect_robust(
        "amqps://admin:<PASSWORD>@<XXXXXX>.stackhero-network.com:<AMQP_PORT_TLS>",
        ssl_context=ssl_context
    )

    async with connection:
        print("The connection worked!")
        channel = await connection.channel()
        await channel.set_qos(prefetch_count=10)
        queue = await channel.declare_queue("test_queue", auto_delete=True)

if __name__ == "__main__":
    asyncio.run(main())

如果您想從 Go 應用程式連接 RabbitMQ,官方的 Go RabbitMQ Client Library 讓流程變得非常簡單。以下是開始步驟:

  1. 建立新目錄並初始化 Go module:
go mod init rabbitmq-example
  1. 接著將 RabbitMQ library 加入您的專案:
go get github.com/rabbitmq/amqp091-go
  1. 現在,建立一個名為 main.go 的檔案並加入以下程式碼:

    package main
    
    import (
      "fmt"
      amqp "github.com/rabbitmq/amqp091-go"
    )
    
    func main() {
      connection, err := amqp.Dial("amqps://<PASSWORD>@<XXXXXX>.stackhero-network.com:<AMQP_PORT_TLS>")
      if err != nil {
        panic(err)
      }
      defer connection.Close()
    
      fmt.Println("Successfully connected to RabbitMQ instance")
    }
    
  2. 執行您的程式碼:

go run main.go

如果連線成功,您會看到 "Successfully connected to RabbitMQ instance" 訊息。這代表您已透過認證及 TLS 加密安全連線。

如需更進階範例,建議參考 RabbitMQ 官方 repository 的 Go 範例:https://github.com/rabbitmq/rabbitmq-tutorials/tree/main/go

若您使用 PHP,可以透過 php-amqplib library 連接 RabbitMQ。由於 Stackhero 採用 TLS 加密(SSL),建議使用 AMQPSSLConnection

use PhpAmqpLib\Connection\AMQPSSLConnection;

$connection = new AMQPSSLConnection(
  '<XXXXXX>.stackhero-network.com',
  <AMQP_PORT_TLS>,
  'admin',
  '<PASSWORD>',
  '/',
  array()
);

/**
 * @param \PhpAmqpLib\Connection\AbstractConnection $connection
 */
function shutdown($connection)
{
  $connection->close();
}

register_shutdown_function('shutdown', $connection);

有時候,您的 TLS 連線可能需要 Certificate Authority (CA) 憑證。雖然大多數系統已內建,但如有需要,您可手動下載。方法如下:

  1. https://letsencrypt.org/certs/isrgrootx1.pem 下載憑證並儲存於伺服器。
  2. 然後在 PHP 連線時指定下載的憑證:
$sslOptions = array(
  'cafile' => realpath(__DIR__ . '/isrgrootx1.pem'),
);

$connection = new AMQPSSLConnection(
  '<XXXXXX>.stackhero-network.com',
  <AMQP_PORT_TLS>,
  'admin',
  '<PASSWORD>',
  '/',
  $sslOptions
);

如果您使用 Symfony,可以透過設定 MESSENGER_TRANSPORT_DSN 環境變數,將 RabbitMQ 作為 message broker。只需更新 .env 檔案:

MESSENGER_TRANSPORT_DSN=amqps://<USER>:<PASSWORD>@<HOST>:<PORT>/%2f/messages?cacert=%2Fetc%2Fssl%2Fcerts%2Fca-certificates.crt

請將 <USER><PASSWORD><HOST><PORT> 替換為您自己的 RabbitMQ 資訊。

接著,請確認您的 config/packages/messenger.yaml 檔案有使用 MESSENGER_TRANSPORT_DSN 變數。內容應如下:

framework:
    messenger:
        transports:
            async: '%env(MESSENGER_TRANSPORT_DSN)%'

對於 Spring Boot 應用程式,您可以透過更新 application properties,設定安全連線至 Stackhero RabbitMQ:

spring.rabbitmq.host=<XXXXXX>.stackhero-network.com
spring.rabbitmq.port=<AMQP_PORT_TLS>
spring.rabbitmq.username=admin
spring.rabbitmq.password=<PASSWORD>
spring.rabbitmq.ssl.enabled=true
spring.rabbitmq.ssl.algorithm=TLSv1.2

如果您使用 .NET 及 MassTransit,以下是如何設定專案,透過 TLS 加密安全連線至 Stackhero RabbitMQ:

using MassTransit;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;

public class Program
{
  public static void Main(string[] args)
  {
    var host = Host.CreateDefaultBuilder(args)
      .ConfigureServices((context, services) =>
      {
        services.AddMassTransit(x =>
        {
          x.UsingRabbitMq((context, cfg) =>
          {
            cfg.Host(new Uri("amqps://admin:<PASSWORD>@<XXXXXX>.stackhero-network.com:<AMQP_PORT_TLS>"), h =>
            {
              h.UseSsl(s =>
              {
                s.Protocol = System.Security.Authentication.SslProtocols.Tls12;
              });
            });
          });
        });

        services.AddMassTransitHostedService(true);
      })
      .Build();

    host.Run();
  }
}

如果您從 Elixir 連線時看到以下錯誤訊息:

CLIENT ALERT: Fatal - Handshake Failure

這通常是 AMQP library 在支援 TLS 1.3 時出現的 bug。建議的解決方法是強制使用 TLS 1.2,於開啟連線時加入以下選項:

AMQP.Connection.open("amqps://admin:<PASSWORD>@<XXXXXX>.stackhero-network.com:<AMQP_PORT_TLS>", :undefined, ssl_options: [ versions: [ :"tlsv1.2" ] ])

如果您在 Node.js 使用時看到 Error: Socket closed abruptly during opening handshake,很可能是因為您使用的 amqplib library 版本低於 0.10.7,且 RabbitMQ 版本為 4.1.0 或以上。這與 RabbitMQ 4.1.0 引入的 frame_max 設定有關。

請將您的 amqplib library 更新至 0.10.7 或更新版本,即可解決此問題。