rabbitmq安装和使用

官网:https://www.rabbitmq.com/


1 rabbitmq基础知识

RabbitMQ是一套开源(MPL)的消息队列服务软件,是由 LShift 提供的一个 Advanced Message Queuing Protocol (AMQP) 的开源实现,由以高性能、健壮以及可伸缩性出名的 Erlang 写成。

RabbitMQ内建的集群功能可以实现其高可用,允许消费者和生产者在RabbitMQ节点崩溃的情况下继续工作,同时可以通过添加更多的节点来提高消息处理的吞吐量。

单个节点的RabbitMQ会将这些meta data保存到内存中,同时对于那些属性为持久化的信息,例如durable的Exchange、Queue等持久化到硬盘上,持久化到硬盘上的Exchange和Queue可以在RabbitMQ节点重启后被重新创建。

当以集群形式部署RabbitMQ的多个节点时,RabbitMQ集群需要新的meta data来保存集群的信息。RabbitMQ集群有以下两种模式:

  • 普通模式:在这种模式下,对于集群中rabbit1和rabbit2两个节点,一个消息只会存在于其中某个节点上的Queue上。rabbit1和rabbit2这两个节点仅仅是拥有相同的meta data,即队列的结构和属性。当consumer连接rabbi2消费rabbit1上的消息时,RabbitMQ会在这两个节点上进行消息传输,将rabbit1上的消息传输到rabbit2上。在该模式下consumer和producer应该尽量连接每个节点,在多个节点建立物理队列,这样也起到了线性扩展的作用。但是在这种模式下要考虑一种情况,某个节点挂掉时其上面还有没有被消费的消息,如果队列和消息都做了持久化,只有该节点恢复时,消息才可以继续被消费;如果队列和消息没有持久化的话,就会丢失消息。
  • 镜像模式:就是把队列做成镜像队列,存在于多个节点上,在该模式下,消息会在节点的镜像队列间做同步,这样可以实现RabbitMQ高可用,但会降低系统性能,特别是镜像队列数量较多,大量消息进入和同步时会占用集群内部大量带宽,因此镜像模式使用于对可靠性要求比较高的场景。

接下来看一下镜像队列的声明,可以通过rabbitmqctl命令或在RabbitMQ Management WebUI中通过创建Policies的方式来声明镜像队列。例如:

rabbitmqctl set_policy ha-all “^ha.” ‘{“ha-mode”:“all”}’

上面这个命令配置了策略,所有名称以ha.开始的队列,都会在集群的所有节点上成为镜像队列。这里使用的ha模式是all,另外还有exactly, nodes两种模式,分别可以指定具体的镜像节点数量,镜像节点名称,可以参考Highly Available (Mirrored) Queues,这里不再展开。

通过上面对RabbitMQ基础知识的一个简单的回顾,在使用RabbitMQ需要考虑一下几点:

  • Queue和Message是否要做持久化。
  • 在使用RabbitMQ的集群时是否要使用镜像队列。


2 安装rabbitMQ

2.1 在docker安装单机版

docker-compose.yaml配置文件内容如下:

version: '3'
 
services:
  rabbitmq:
    image: rabbitmq:3.7.5-management
    hostname: rabbitmq-server
    restart: always
    ports:
      - 5672:5672
      - 15672:15672
    volumes:
      - ./data/rabbitmq:/var/lib/rabbitmq/mnesia/rabbit@rabbitmq-server
    environment:
      RABBITMQ_DEFAULT_USER: guest
      RABBITMQ_DEFAULT_PASS: guest
      RABBITMQ_ERLANG_COOKIE: rec123456
      RABBITMQ_DEFAULT_VHOST: /

启动rabbitmq:

docker-compose up -d


2.2 在docker安装高可用的rabbit集群

安装根据实际需要使用普通模式和镜像模式,一共有三个rabbitmq节点和一个高可用代理服务haproxy,haproxy务作为代理连接入口,文件列表如下:

.
├── cluster-entrypoint.sh
├── docker-compose.yml
├── .env
└── haproxy.cfg


(1) 加入rabbitMQ集群的脚本文件cluster-entrypoint.sh内容如下:

#!/bin/bash

set -e

# Start RMQ from entry point.
# This will ensure that environment variables passed
# will be honored
/usr/local/bin/docker-entrypoint.sh rabbitmq-server -detached

# Do the cluster dance
rabbitmqctl stop_app
rabbitmqctl join_cluster rabbit@rabbitmq1

# Stop the entire RMQ server. This is done so that we
# can attach to it again, but without the -detached flag
# making it run in the forground
rabbitmqctl stop

# Wait a while for the app to really stop
sleep 2s

# Start it
rabbitmq-server


(2) docker-compose配置文件的环境变量.env内容如下,.env文件包含可用于更改默认用户名,密码等。

RABBITMQ_DEFAULT_USER=guest
RABBITMQ_DEFAULT_PASS=guest
RABBITMQ_DEFAULT_VHOST=/
RABBITMQ_ERLANG_COOKIE=rec123456


(3) 高可用服务的配置文件haproxy.cfg内容如下:

global
        log 127.0.0.1   local1
        maxconn 4096
 
defaults
        log     global
        mode    tcp
        option  tcplog
        retries 3
        option redispatch
        maxconn 2000
        timeout connect 5000
        timeout client 50000
        timeout server 50000
 
listen  stats
        bind *:1936
        mode http
        stats enable
        stats hide-version
        stats realm Haproxy\ Statistics
        stats uri /
 
listen rabbitmq
        bind *:5672
        mode            tcp
        balance         roundrobin
        timeout client  3h
        timeout server  3h
        option          clitcpka
        server          rabbitmq1 rabbitmq1:5672  check inter 5s rise 2 fall 3
        server          rabbitmq2 rabbitmq2:5672  check inter 5s rise 2 fall 3
        server          rabbitmq3 rabbitmq3:5672  check inter 5s rise 2 fall 3

listen mgmt
        bind *:15672
        mode            tcp
        balance         roundrobin
        timeout client  3h
        timeout server  3h
        option          clitcpka
        server          rabbitmq1 rabbitmq1:15672  check inter 5s rise 2 fall 3
        server          rabbitmq2 rabbitmq2:15672  check inter 5s rise 2 fall 3
        server          rabbitmq3 rabbitmq3:15672  check inter 5s rise 2 fall 3


(4) docker-compose.yml配置文件内容如下:

version: '3'

services:

  rabbitmq1:
    hostname: rabbitmq1
    image: rabbitmq:3.7.5-management
    restart: always
    environment:
      - RABBITMQ_ERLANG_COOKIE=${RABBITMQ_ERLANG_COOKIE}
      - RABBITMQ_DEFAULT_USER=${RABBITMQ_DEFAULT_USER}
      - RABBITMQ_DEFAULT_PASS=${RABBITMQ_DEFAULT_PASS}
      - RABBITMQ_DEFAULT_VHOST=${RABBITMQ_DEFAULT_VHOST}
    volumes:
      - ./data/rabbitmq1:/var/lib/rabbitmq/mnesia

  rabbitmq2:
    hostname: rabbitmq2
    image: rabbitmq:3.7.5-management
    restart: always
    depends_on:
      - rabbitmq1
    environment:
      - RABBITMQ_ERLANG_COOKIE=${RABBITMQ_ERLANG_COOKIE}
    volumes:
      - ./cluster-entrypoint.sh:/usr/local/bin/cluster-entrypoint.sh
      - ./data/rabbitmq2:/var/lib/rabbitmq/mnesia
    entrypoint: sh /usr/local/bin/cluster-entrypoint.sh

  rabbitmq3:
    hostname: rabbitmq3
    image: rabbitmq:3.7.5-management
    restart: always
    depends_on:
      - rabbitmq1
    environment:
      - RABBITMQ_ERLANG_COOKIE=${RABBITMQ_ERLANG_COOKIE}
    volumes:
      - ./cluster-entrypoint.sh:/usr/local/bin/cluster-entrypoint.sh
      - ./data/rabbitmq3:/var/lib/rabbitmq/mnesia
    entrypoint: sh /usr/local/bin/cluster-entrypoint.sh
    
  haproxy:
    image: haproxy:1.9
    restart: always
    volumes:
      - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
    depends_on:
      - rabbitmq1
      - rabbitmq2
      - rabbitmq3
    ports:
      - 15672:15672
      - 5672:5672


启动rabbitMQ集群:

docker-compose up -d

# 默认用户名guest,默认密码guest
# 代理连接地址:localhost:5672
# 管理界面地址:localhost:15672

参考: https://github.com/pardahlman/docker-rabbitmq-cluster


2.3 在k8s安装rabbitmq集群

根据实际需要,安装rabbitmq集群可以选择普通模式和镜像模式,如果需要设置为镜像模式,在普通集群的中任意节点启用策略,策略会自动同步到集群节点:

rabbitmqctl set_policy ha-all “^ha.” ‘{“ha-mode”:“all”}’

注意:”^ha” 这个规则要根据自己修改,这个是指同步”ha”开头的队列名称,配置时使用的应用于所有队列,所以表达式为”^“。


创建rabbitmq集群的Erlang cookie,配置文件rabbitmq-secret.yml内容如下:

apiVersion: v1
kind: Secret
metadata:
  name: rabbitmq-config
  namespace: default
data:
  erlang-cookie: |-
    MTIzNDU2Nzg5MAo=


使用statefulset启动rabbitmq,配置文件rabbitmq-sts.yml内容如下:

apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: rabbitmq
spec:
  serviceName: rabbitmq
  replicas: 3
  template:
    metadata:
      labels:
        app: rabbitmq
    spec:
      containers:
      - name: rabbitmq
        image: rabbitmq:3.6.6-management-alpine
        lifecycle:
          postStart:
            exec:
              command:
              - /bin/sh
              - -c
              - >
                if [ -z "$(grep rabbitmq /etc/resolv.conf)" ]; then
                  sed "s/^search \([^ ]\+\)/search rabbitmq.\1 \1/" /etc/resolv.conf > /etc/resolv.conf.new;
                  cat /etc/resolv.conf.new > /etc/resolv.conf;
                  rm /etc/resolv.conf.new;
                fi;
                until rabbitmqctl node_health_check; do sleep 1; done;
                if [[ "$HOSTNAME" != "rabbitmq-0" && -z "$(rabbitmqctl cluster_status | grep rabbitmq-0)" ]]; then
                  rabbitmqctl stop_app;
                  rabbitmqctl join_cluster rabbit@rabbitmq-0;
                  rabbitmqctl start_app;
                fi;
                rabbitmqctl set_policy ha-all "." '{"ha-mode":"exactly","ha-params":3,"ha-sync-mode":"automatic"}'
        env:
        - name: RABBITMQ_ERLANG_COOKIE
          valueFrom:
            secretKeyRef:
              name: rabbitmq-config
              key: erlang-cookie
        ports:
        - containerPort: 5672
          name: amqp
        volumeMounts:
        - name: rabbitmq
          mountPath: /var/lib/rabbitmq
  volumeClaimTemplates:
  - metadata:
      name: rabbitmq
      annotations:
        volume.alpha.kubernetes.io/storage-class: anything
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 2Gi

注:必须准备好存储卷后,pod才能启动。


rabbitmq服务配置文件rabbitmq-svc.yml内容如下,对外开放http端口,其它端口在集群内部使用。

apiVersion: v1
kind: Service
metadata:
  # Expose the management HTTP port on each node
  name: rabbitmq-management
  labels:
    app: rabbitmq
spec:
  selector:
    app: rabbitmq
  type: NodePort
  ports:
  - port: 15672
    name: http
    nodePort: 30072

---

apiVersion: v1
kind: Service
metadata:
  # The required headless service for StatefulSets
  name: rabbitmq
  labels:
    app: rabbitmq
spec:
  selector:
    app: rabbitmq
  clusterIP: None
  ports:
  - port: 5672
    name: amqp
  - port: 4369
    name: epmd
  - port: 25672
    name: rabbitmq-dist


启动rabbitmq集群

kubectl apply -f rabbitmq-secret.yml
kubectl apply -f rabbitmq-sts.yml
kubectl apply -f rabbitmq-svc.yml

# 默认用户名guest,默认密码guest
# 代理连接地址:rabbitmq.default:5672
# 管理界面地址:node-ip:30072

参考:https://wesmorgan.svbtle.com/rabbitmq-cluster-on-kubernetes-with-statefulsets




专题「消息中间件」的其它文章 »