阶段三:消息中间件RabbitMQ

二、云岚到家微服务项目为什么需要MQ

在单体系统中,业务方法可以直接调用本地代码。

到了微服务架构后,订单、支付、用户、服务、搜索、历史订单等能力被拆成多个服务。服务之间如果全部同步调用,会带来几个问题:

MQ 的核心价值:

三、RabbitMQ 的核心角色

RabbitMQ 遵循 AMQP 思想,核心角色包括:

四、常见交换机类型

1、Direct Exchange

2、Topic Exchange

3、Fanout Exchange

云岚到家项目里大量使用 topic 类型,便于按业务模块分发 Canal 数据和交易状态

五、RabbitMQ部署模式

1、单机部署

YAML 保存位置: ~/k8s-manifests/jzo2o/rabbitmq-config.yaml

先在 Kubernetes 管理节点执行:

mkdir -p ~/k8s-manifests/jzo2o
cd ~/k8s-manifests/jzo2o
vi rabbitmq-config.yaml

把下方 YAML 全部复制进去;红色字段按当前环境修改;按 Esc 后输入 :wq 保存退出。

apiVersion: v1
kind: ConfigMap
metadata:
  name: rabbitmq-config
  namespace: jzo2o
data:
  rabbitmq.conf: |
    management.load_definitions = /etc/rabbitmq/definitions.json
    loopback_users.guest = false

  definitions.json: |
    {
      "users": [
        {
          "name": "xzb",
          "password": "xzb",
          "tags": ""
        },
        {
          "name": "czri",
          "password": "czri1234",
          "tags": "administrator"
        }
      ],
      "vhosts": [
        {
          "name": "/"
        },
        {
          "name": "/xzb"
        }
      ],
      "permissions": [
        {
          "user": "xzb",
          "vhost": "/xzb",
          "configure": ".*",
          "write": ".*",
          "read": ".*"
        },
        {
          "user": "czri",
          "vhost": "/",
          "configure": ".*",
          "write": ".*",
          "read": ".*"
        },
        {
          "user": "czri",
          "vhost": "/xzb",
          "configure": ".*",
          "write": ".*",
          "read": ".*"
        }
      ],
      "parameters": [],
      "policies": [],
      "queues": [],
      "exchanges": [
         {
          "name": "exchange.canal-jzo2o",
          "vhost": "/xzb",
          "type": "topic",
          "durable": true,
          "auto_delete": false,
          "internal": false,
          "arguments": {}
        }
      ],
      "bindings": []
    }

配置详解:

需要改的项为什么改
namespace: jzo2o与实际命名空间一致;使用默认命名空间时可不写。

配置详解:

需要改的项为什么改
namespace: jzo2o与实际命名空间一致;使用默认命名空间时可不写。

注意事项:

YAML 保存位置: ~/k8s-manifests/jzo2o/rabbitmq.yaml

先在 Kubernetes 管理节点执行:

mkdir -p ~/k8s-manifests/jzo2o
cd ~/k8s-manifests/jzo2o
vi rabbitmq.yaml

把下方 YAML 全部复制进去;红色字段按当前环境修改;按 Esc 后输入 :wq 保存退出。

apiVersion: v1
kind: Service
metadata:
  name: rabbitmq
  namespace: jzo2o
spec:
  type: NodePort
  selector: {app: rabbitmq}
  ports:
    - name: amqp
      port: 5672
      targetPort: 5672
      nodePort: 30672
    - name: management
      port: 15672
      targetPort: 15672
      nodePort: 31672
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: rabbitmq
  namespace: jzo2o
spec:
  serviceName: rabbitmq
  replicas: 1
  selector:
    matchLabels: {app: rabbitmq}
  template:
    metadata:
      labels: {app: rabbitmq}
    spec:
      containers:
        - name: rabbitmq
          image: harbor.lanqicheng.top/jzo2o/rabbitmq:3.9.17-management-delayed
          ports:
            - containerPort: 5672
              name: amqp
            - containerPort: 15672
              name: management
          env:
            - name: RABBITMQ_DEFAULT_USER
              value: czri
            - name: RABBITMQ_DEFAULT_PASS
              value: czri1234
          volumeMounts:
            - name: rabbitmq-data
              mountPath: /var/lib/rabbitmq
            - name: rabbitmq-config
              mountPath: /etc/rabbitmq/rabbitmq.conf
              subPath: rabbitmq.conf
            - name: rabbitmq-config
              mountPath: /etc/rabbitmq/definitions.json
              subPath: definitions.json
      volumes:
        - name: rabbitmq-config
          configMap:
            name: rabbitmq-config
  volumeClaimTemplates:
    - metadata:
        name: rabbitmq-data
      spec:
        accessModes: ["ReadWriteMany"]
        storageClassName: nfs-storage
        resources:
          requests:
            storage: 10Gi

配置详解:

需要改的项为什么改
namespace: jzo2o与实际命名空间一致;使用默认命名空间时可不写。
port: 5672对外暴露的 Service 端口;调用方按此端口访问。
targetPort: 5672必须与容器实际监听端口一致。
nodePort: 30672集群外通过 NodeIP:NodePort 访问时才需要改。
port: 15672对外暴露的 Service 端口;调用方按此端口访问。
targetPort: 15672必须与容器实际监听端口一致。

注意事项:

2、集群模式

YAML 保存位置: ~/k8s-manifests/jzo2o/rabbitmq-erlang-cookie.yaml

先在 Kubernetes 管理节点执行:

mkdir -p ~/k8s-manifests/jzo2o
cd ~/k8s-manifests/jzo2o
vi rabbitmq-erlang-cookie.yaml

把下方 YAML 全部复制进去;红色字段按当前环境修改;按 Esc 后输入 :wq 保存退出。

apiVersion: v1
kind: Secret
metadata:
  name: rabbitmq-erlang-cookie
  namespace: jzo2o
type: Opaque
stringData:
  cookie: "jzo2o-rabbitmq-cookie"
apiVersion: v1
kind: ConfigMap
metadata:
  name: rabbitmq-config
  namespace: jzo2o
data:
  enabled_plugins: |
    [rabbitmq_management,rabbitmq_peer_discovery_k8s].
  rabbitmq.conf: |
    management.load_definitions = /etc/rabbitmq/definitions.json
    loopback_users.guest = false

    cluster_formation.peer_discovery_backend = rabbit_peer_discovery_k8s
    cluster_formation.k8s.host = kubernetes.default.svc.cluster.local
    cluster_formation.k8s.address_type = hostname
    cluster_formation.k8s.service_name = rabbitmq-headless
    cluster_formation.k8s.hostname_suffix = .rabbitmq-headless.jzo2o.svc.cluster.local

    cluster_partition_handling = pause_minority
    queue_master_locator = min-masters
  definitions.json: |
    {
      "users": [
        {
          "name": "xzb",
          "password": "xzb",
          "tags": ""
        },
        {
          "name": "czri",
          "password": "czri1234",
          "tags": "administrator"
        }
      ],
      "vhosts": [
        {
          "name": "/"
        },
        {
          "name": "/xzb"
        }
      ],
      "permissions": [
        {
          "user": "xzb",
          "vhost": "/xzb",
          "configure": ".*",
          "write": ".*",
          "read": ".*"
        },
        {
          "user": "czri",
          "vhost": "/",
          "configure": ".*",
          "write": ".*",
          "read": ".*"
        },
        {
          "user": "czri",
          "vhost": "/xzb",
          "configure": ".*",
          "write": ".*",
          "read": ".*"
        }
      ],
      "parameters": [],
      "policies": [],
      "queues": [],
      "exchanges": [],
      "bindings": []
    }

配置详解:

需要改的项为什么改
namespace: jzo2o与实际命名空间一致;使用默认命名空间时可不写。

注意事项:

YAML 保存位置: ~/k8s-manifests/jzo2o/rabbitmq-rbac.yaml

先在 Kubernetes 管理节点执行:

mkdir -p ~/k8s-manifests/jzo2o
cd ~/k8s-manifests/jzo2o
vi rabbitmq-rbac.yaml

把下方 YAML 全部复制进去;红色字段按当前环境修改;按 Esc 后输入 :wq 保存退出。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: rabbitmq
  namespace: jzo2o
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: rabbitmq-peer-discovery
  namespace: jzo2o
rules:
  - apiGroups: [""]
    resources: ["endpoints", "pods", "services"]
    verbs: ["get", "list", "watch"]
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: rabbitmq-peer-discovery
  namespace: jzo2o
subjects:
  - kind: ServiceAccount
    name: rabbitmq
    namespace: jzo2o
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: rabbitmq-peer-discovery

配置详解:

需要改的项为什么改
namespace: jzo2o与实际命名空间一致;使用默认命名空间时可不写。

注意事项:

YAML 保存位置: ~/k8s-manifests/jzo2o/rabbitmq-headless.yaml

先在 Kubernetes 管理节点执行:

mkdir -p ~/k8s-manifests/jzo2o
cd ~/k8s-manifests/jzo2o
vi rabbitmq-headless.yaml

把下方 YAML 全部复制进去;红色字段按当前环境修改;按 Esc 后输入 :wq 保存退出。

apiVersion: v1
kind: Service
metadata:
  name: rabbitmq-headless
  namespace: jzo2o
spec:
  clusterIP: None
  selector:
    app: rabbitmq
  ports:
    - name: amqp
      port: 5672
      targetPort: 5672
    - name: management
      port: 15672
      targetPort: 15672
    - name: epmd
      port: 4369
      targetPort: 4369
    - name: clustering
      port: 25672
      targetPort: 25672
apiVersion: v1
kind: Service
metadata:
  name: rabbitmq
  namespace: jzo2o
spec:
  type: NodePort
  selector:
    app: rabbitmq
  ports:
    - name: amqp
      port: 5672
      targetPort: 5672
      nodePort: 30672
    - name: management
      port: 15672
      targetPort: 15672
      nodePort: 31672
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: rabbitmq
  namespace: jzo2o
spec:
  serviceName: rabbitmq-headless
  replicas: 3
  selector:
    matchLabels:
      app: rabbitmq
  template:
    metadata:
      labels:
        app: rabbitmq
    spec:
      serviceAccountName: rabbitmq
      containers:
        - name: rabbitmq
          image: harbor.lanqicheng.top/jzo2o/rabbitmq:3.9.17-management-delayed
          imagePullPolicy: IfNotPresent
          ports:
            - name: amqp
              containerPort: 5672
            - name: management
              containerPort: 15672
            - name: epmd
              containerPort: 4369
            - name: clustering
              containerPort: 25672
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: RABBITMQ_USE_LONGNAME
              value: "true"
            - name: RABBITMQ_NODENAME
              value: rabbit@$(POD_NAME).rabbitmq-headless.jzo2o.svc.cluster.local
            - name: RABBITMQ_ERLANG_COOKIE
              valueFrom:
                secretKeyRef:
                  name: rabbitmq-erlang-cookie
                  key: cookie
          volumeMounts:
            - name: rabbitmq-data
              mountPath: /var/lib/rabbitmq
            - name: rabbitmq-config
              mountPath: /etc/rabbitmq/rabbitmq.conf
              subPath: rabbitmq.conf
            - name: rabbitmq-config
              mountPath: /etc/rabbitmq/definitions.json
              subPath: definitions.json
            - name: rabbitmq-config
              mountPath: /etc/rabbitmq/enabled_plugins
              subPath: enabled_plugins
      volumes:
        - name: rabbitmq-config
          configMap:
            name: rabbitmq-config
  volumeClaimTemplates:
    - metadata:
        name: rabbitmq-data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: nfs-storage
        resources:
          requests:
            storage: 10Gi

配置详解:

需要改的项为什么改
namespace: jzo2o与实际命名空间一致;使用默认命名空间时可不写。
port: 5672对外暴露的 Service 端口;调用方按此端口访问。
targetPort: 5672必须与容器实际监听端口一致。
port: 15672对外暴露的 Service 端口;调用方按此端口访问。
targetPort: 15672必须与容器实际监听端口一致。
port: 4369对外暴露的 Service 端口;调用方按此端口访问。

注意事项: