RabbitMQ でメッセージの送受信を行うまでの環境設定についてのメモ

# 概要

## RabbitMQとは

* RabbitMQ は Pivotal によって開発されているオープンソースのメッセージブローカー。
* AMQP (v0-8, v0-9, v0-9-1, v1.0), STOMP, MQTT, HTTP プロトコルに対応している。

## AMQPとは
* メッセージ転送 (MQ) に使われる通信プロトコルの一種。
* 様々なメッセージ転送用プロトコルがある中では最もメジャーな存在と思われる。
* 仕様のバージョンには 0-8, 0-9, 0-9-1, 1.0 がある。
  * 1.0 は 0-9-1 の後発だが 0-9-1 から大きく仕様が変更されており、相互運用性がない。
  * RabbitMQ が標準でサポートするプロトコルは AMQP 0-9-1。AMQP 1.0 はプラグインを適用することで使用可能。
  * ActiveMQ が標準でサポートするプロトコルは AMQP 1.0。

### AMQP における用語・概念の説明
* これらのサイト、ページに詳しい解説あり。
  * [AMQPによるメッセージング | GREE Engineers' Blog](http://labs.gree.jp/blog/2010/06/262/)
  * [RabbitMQ - AMQP 0-9-1 Model Explained](https://www.rabbitmq.com/tutorials/amqp-concepts.html)

# 起動

## Docker による起動

* 公式の Docker イメージが配布されているのでこれを使用するのが早い。
  * [library/rabbitmq - Docker Hub](https://hub.docker.com/_/rabbitmq/)

例）

```yaml:docker-compose.yml
version: '3'
 
services:
  my-queue:
    container_name: rabbitmq
    image: rabbitmq:3.7.4-management
    ports:
      - '5672:5672'
      - '15672:15672'
    volumes:
      - rabbitmq-data:/var/lib/rabbitmq
 
volumes:
  rabbitmq-data:
```

```bash
docker-compose up -d
```

通常の rabbitmq:x.x.x の他に rabbitmq:x.x.x-management というイメージが用意されており、これを使うと Management Plugin 導入済みのものが起動され、管理コンソールが使用できる。

# メッセージング環境の構築と設定

## RabbitMQ の設定

設定方法として大きく３つある。

### 管理画面による設定

Management Plugin を導入して起動した場合に http://localhost:15672 で管理画面にアクセス可能。
デフォルトのユーザー名/パスワードは guest/guest。

![localhost_15672_(Laptop with HiDPI screen).png](https://qiita-image-store.s3.amazonaws.com/0/43205/cb7b5189-11ea-251c-4d71-d31fdcd729dd.png)

管理画面でできない設定・操作はほとんど無いというくらいには機能が充実している印象。

### コマンドラインツールによる設定

２種類のコマンドラインツールが提供されている。

#### rabbitmqctl

標準の管理ツールとして `rabbitmqctl` が用意されている。
Virtual Host の管理やユーザーの管理など、RabbitMQ のインフラとなる部分の管理を行うことができる。

例）Docker コンテナ上のツールを実行する例

```bash
# ヘルプ参照
docker exec my-queue rabbitmqctl --help

### 参照系
# ユーザー
docker exec my-queue rabbitmqctl list_users
# Exchange の情報を全て表示
docker exec my-queue rabbitmqctl list_exchanges name type durable auto_delete internal arguments policy
 
### 追加・設定系
# ユーザーの追加
docker exec my-queue rabbitmqctl add_user admin admin
# ユーザーにタグを付与
docker exec my-queue rabbitmqctl set_user_tags admin administrator
 
# Virtual Host の追加
docker exec my-queue rabbitmqctl add_vhost my-vhost
# ユーザーに Virtual Host に対するパーミッションを設定
docker exec my-queue rabbitmqctl set_permissions -p my-vhost admin ".*" ".*" ".*"
```

#### rabbitmqadmin

Management Plugin に付属するツールとして `rabbitmqadmin` が用意されている。
Exchange や Queue の作成、メッセージの送受信などを行うことができる。

例）Docker コンテナ上のツールを実行する例

```bash
# ヘルプ参照
docker exec my-queue rabbitmqadmin --help
 
# 現在の設定を JSON ファイルで出力
docker exec my-queue rabbitmqadmin export /tmp/export.json

### 参照系コマンド
# Exchange の情報を全て表示
docker exec my-queue rabbitmqadmin list exchanges name type durable auto_delete internal arguments policy
# Queue の情報を全て表示
docker exec my-queue rabbitmqadmin list queues node vhost name auto_delete durable arguments messages
 
### 定義系コマンド
# 新規 Exchange の定義
docker exec my-queue rabbitmqadmin -u admin -p admin -V my-vhost declare exchange --vhost=my-vhost name=my-exchange type=direct
# 新規 Queue の定義
docker exec my-queue rabbitmqadmin -u admin -p admin -V my-vhost declare queue name=my-q auto_delete=false durable=true
# 新規 Binding の定義
docker exec my-queue rabbitmqadmin -u admin -p admin -V my-vhost declare binding source=my-exchange destination=my-q routing_key=my-key
```

### 設定ファイルによる設定

2種類の設定ファイルの書き方がある。

* rabbitmq.config
  * 旧式の書き方。Erlang の標準設定ファイル書式で記述する。
* rabbitmq.conf
  * 新式の書き方。sysctl 方式で記述する。

rabbitmq.conf を配置するとそのファイルが優先されて使用される模様。

#### Management Plugin による JSON を用いた一括設定

起動時に JSON ファイルを読み込んで Exchange や Queue などの作成・設定を一括で行う機能が Management Plugin に備わっている。
設定ファイルに以下の設定を追加することによって有効となる。

```rabbitmq.conf
management.load_definitions = /etc/rabbitmq/custom_definitions.json
```

```json:custom_definitions.json
{
    "rabbit_version": "3.7.5",
    "users": [
        {
            "name": "admin",
            "password_hash": "QyUFLumOV/zF7ungeOvVbcZ+bUKRGsxp654s9lF5CY//v6rk",
            "hashing_algorithm": "rabbit_password_hashing_sha256",
            "tags": "administrator"
        }
    ],
    "vhosts": [
        {
            "name": "my-vhost"
        }
    ],
    "permissions": [
        {
            "user": "admin",
            "vhost": "my-vhost",
            "configure": ".*",
            "write": ".*",
            "read": ".*"
        }
    ],
    "queues": [
        {
            "name": "my-q",
            "vhost": "my-vhost",
            "durable": true,
            "auto_delete": false,
            "arguments": {}
        }
    ],
    "exchanges": [
        {
            "name": "my-exchange",
            "vhost": "my-vhost",
            "type": "direct",
            "durable": true,
            "auto_delete": false,
            "internal": false,
            "arguments": {}
        }
    ]
}
```

JSON ファイルは手書きで書くことももちろん可能だが、現在設定されている状態を JSON ファイルとしてエクスポートすることも可能。管理画面からダウンロードすることもできるし、以下のコマンドで出力することも可能。

```bash
docker exec my-queue rabbitmqadmin export /tmp/export.json
```

## RabbitMQ における各要素の設定について

### Exchange

|項目|意味|
|---|---|
|name|Exchange の名前。|
|type|キューに対するメッセージの配布方式。|
|durable|true に設定するとサーバーを再起動してもこの Exchange は残り続ける。|
|auto_delete|true に設定するとこの Exchange を使用するキューがなくなった時点で自動的にこの Exchange は削除される。|
|internal|true に設定すると Publisher から直接使用されることはなくなり、他の Exchange から使用されるだけとなる。|

### Queue

|項目|意味|
|---|---|
|name|Queue の名前。|
|durable|true に設定するとサーバーを再起動してもこの Queue は残り続ける。|
|auto_delete|true に設定するとこの Queue を使用する Consumer がなくなった時点で自動的にこの Queue は削除される。|

### その他
* RabbitMQ にはポリシーという概念があり、これによって Exchange や Queue に対してデフォルトの設定を定義することができる。
  * 後述のデッドレター Exchange を設定するときになどに有効。

# メッセージの送受信

## メッセージの送信

メッセージの送信は管理画面でも行えるし、`rabbitmqadmin`を使っても行える。

```bash
# メッセージの送信
docker exec my-queue rabbitmqadmin -u admin -p admin -V my-vhost publish routing_key=my-key exchange=my-exchange payload=test
```

## メッセージの受信

### 受信確認

キューからメッセージを受信するだけでは即座にキューからメッセージは削除されない。コンシューマーからの受信確認が必要である。コンシューマーからの受信確認信号には以下の3つがある。

* ack：メッセージが正常に処理できたことを示す。メッセージはキューから削除される。
* nack：メッセージが正常に処理できなかったことを示す。デフォルトではメッセージは再度キューイングされる。複数のメッセージを一括で処理可能。
* reject：メッセージが正常に処理できなかったことを示す。デフォルトではメッセージは再度キューイングされない。複数のメッセージを一括で処理することができない。

### メッセージの受信

メッセージの受信は管理画面でも行えるし、`rabbitmqadmin`を使っても行える。

```bash
# メッセージの受信
docker exec my-queue rabbitmqadmin -u admin -p admin -V my-vhost get queue=my-q ackmode=ack_requeue_true
```

指定できる`ackmode`は以下の種類あり。

* ack_requeue_true：nack を返してリキューする。
* ack_requeue_false：ack を返してリキューしない。
* reject_requeue_true：reject を返してリキューする。
* reject_requeue_false：reject を返してリキューしない。


# デッドレターチャンネルパターン
送信されたメッセージが正常に処理されなかった場合に、処理できなかったメッセージを専用の Exchange に送信するパターン。RabbitMQ にはこれを実現するための仕組みが組み込まれている。
[RabbitMQ - Dead Letter Exchanges](https://www.rabbitmq.com/dlx.html)

# 参考サイト
## AMQP
[AMQPによるメッセージング | GREE Engineers' Blog](http://labs.gree.jp/blog/2010/06/262/)
[RabbitMQ - AMQP 0-9-1 Model Explained](https://www.rabbitmq.com/tutorials/amqp-concepts.html)

## RabbitMQ
[Understanding When to use RabbitMQ or Apache Kafka](https://content.pivotal.io/blog/understanding-when-to-use-rabbitmq-or-apache-kafka)
[RabbitMQとAMQPについての調査・使い方メモ - mookjp.github.io](https://mookjp.github.io/memo/rabbitmq%E3%81%A8amqp%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6%E3%81%AE%E8%AA%BF%E6%9F%BB%E4%BD%BF%E3%81%84%E6%96%B9%E3%83%A1%E3%83%A2/)
[Dead Letter Channel Pattern with RabbitMQ | Siguniang's Blog](https://siguniang.wordpress.com/2012/10/06/dead-letter-pattern-with-rabbitmq/)