RabbitMQ组成部分:生产者,消费者,队列,交换机;
---
apiVersion: v1
kind: Secret
metadata:
name: rabbitmq-secret
namespace: rabbitmq
data:
username: YWRtaW4K
password: MTIzNDU2Cg==
type: Opaque
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: rabbitmq
namespace: rabbitmq
labels:
app: rabbitmq
spec:
replicas: 1
selector:
matchLabels:
app: rabbitmq
serviceName: rabbitmq-headless
template:
metadata:
labels:
app: rabbitmq
spec:
containers:
- name: rabbitmq
image: registry.cn-hangzhou.aliyuncs.com/yuanli123/rabbitmq:3.9.22-management
ports:
- name: tcp-5672
containerPort: 5672
protocol: TCP
- name: tcp-15672
containerPort: 15672
protocol: TCP
# 不知道为什么自己使用的username会多出一个回车字符导致rabbitmq无法识别到
# env:
# - name: RABBITMQ_DEFAULT_USER
# valueFrom:
# secretKeyRef:
# name: rabbitmq-secret
# key: username
# - name: RABBITMQ_DEFAULT_PASS
# valueFrom:
# secretKeyRef:
# name: rabbitmq-secret
# key: password
resources:
limits:
cpu: '1'
memory: '2Gi'
requests:
cpu: '200m'
memory: '500Mi'
imagePullSecrets:
- name: regcred
---
apiVersion: v1
kind: Service
metadata:
name: rabbitmq-headless
namespace: rabbitmq
labels:
app: rabbitmq
spec:
ports:
- name: tcp-rabbitmq-5672
port: 5672
targetPort: 5672
nodePort: 32672
selector:
app: rabbitmq
type: NodePort
---
apiVersion: v1
kind: Service
metadata:
name: rabbitmq-external
namespace: rabbitmq
labels:
app: rabbitmq-external
spec:
ports:
- name: http-rabbitmq-external
protocol: TCP
port: 15672
targetPort: 15672
selector:
app: rabbitmq
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rabbitmq-ingress
namespace: rabbitmq
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: rabbitmq.liyuan.com
http:
paths:
- backend:
service:
name: rabbitmq-external
port:
number: 15672
pathType: Prefix
path: /
根据上述yaml,再结合修改 /etc/hosts 文件
通过 http://rabbitmq.liyuan.com:30001/#/exchanges 访问
并暴露了 192,168.31.175:32672 用于发消息
rabbitmq-test 源码参考
# pom.yaml
<?xml version="1.0" encoding="UTF-8"?>
://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
>4.0.0 >
>org.example >
>rqbbitmq-test >
>1.0-SNAPSHOT >
>
>8 >
>8 >
>UTF-8 >
>
>
>
>com.rabbitmq >
>amqp-client >
>5.16.0 >
>
>
>
// Producer.java
package com.liyuan.rabbitmq;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Producer {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.31.175");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
connectionFactory.setPort(32672);
try (Connection connection = connectionFactory.newConnection()) {
Channel channel = connection.createChannel();
String exchangeName = "xc_exchange_name";
AMQP.Exchange.DeclareOk exchangeDeclare = channel.exchangeDeclare(exchangeName, BuiltinExchangeType.DIRECT, true, false, null);
String queueName = "xc_queue_name";
AMQP.Queue.DeclareOk queueDeclare = channel.queueDeclare(queueName, false, false, false, null);
channel.queueBind(queueName, exchangeName, queueName);
String message = "Hello, my name is liyuan.";
channel.basicPublish(exchangeName, queueName, null, message.getBytes());
channel.close();
}
}
}
package com.liyuan.rabbitmq;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.31.175");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
connectionFactory.setPort(32672);
try (Connection connection = connectionFactory.newConnection()) {
Channel channel = connection.createChannel();
String exchangeName = "xc_exchange_name";
String queueName = "xc_queue_name";
DeliverCallback deliverCallback = new DeliverCallback() {
@Override
public void handle(String consumerTag, Delivery message) throws IOException {
System.out.println("Delivered consuming: " + consumerTag + " " + new String(message.getBody()));
}
};
CancelCallback cancelCallback = new CancelCallback() {
@Override
public void handle(String consumerTag) throws IOException {
System.out.println("Canceled: " + consumerTag);
}
};
channel.basicConsume(queueName, true, deliverCallback, cancelCallback);
channel.close();
}
}
}
路由键与队列完全匹配交换机,通过routingKey路由键将交换机和队列进行绑定,消息被发送到exchange时,根据消息的routingKey来进行匹配,只将消息发送到完全匹配此routingKey的队列;
且同一个key可以绑定多个queue,因此会同时将消息发给多个queue;
queueName | routingKey |
---|---|
queue01 | “direct_key01” |
queue02 | “direct_key02” |
根据上述表格的规则来发送消息,当发送消息时的routingKey为以下值时,以下队列会收到消息;
routingKey | queueName |
---|---|
“direct_key01” | queue01 will receive |
“direct_key02” | queue02 will receive |
将消息分发给所有绑定了此交换机的队列;
queueName | routingKey |
---|---|
queue01 | “fanout_key01” |
queue02 | “fanout_key01” |
queue03 | “fanout_key01” |
根据上述表格的规则来发送消息,当发送消息时的routingKey为以下值时,以下队列会收到消息;
routingKey | queueName |
---|---|
“fanout_key01” | queue01, queue02, queue03 will receive |
类似于direct方式,但是topic可以模糊匹配routingKey;通过此种方式,我们可以使得一个队列模糊绑定多个routingKey;
queueName | routingKey |
---|---|
queue01 | key1.key2.key3.* |
queue02 | key1.# |
queue03 | *.key2.*.key4 |
queue04 | #.key3.key4 |
根据上述表格的规则来发送消息,当发送消息时的routingKey为以下值时,以下队列会收到消息;
routingKey | queueName |
---|---|
“key1” | queue02 will receive |
“key3” | no queue will receive |
“key1.key2.key3” | queue02 will receive |
“key1.key2.key3.key4” | queue01, queue02, queue03, queue04 will receive |
headers 匹配AMQP消息的header而不是路由键,此外headers交换器和direct交换器完全一致,但性能差了很多;
消费方要求指定的headers中必须包含一个"x-match"的键;
生产者按照 x-match 配置的规则发送消息到指定的queue上;
queueName | x-match |
---|---|
queue01 | {name:“liyuan01”, sex:“male”, x-match: all} |
queue02 | {name:“liyuan02”, sex:“male”, x-match: any} |
通过上述规则,按照指定的消息头发送消息时;
x-match | queueName |
---|---|
{name: “liyuan01”} | no queue will receive |
{name: “liyuan02”} | queue02 will receive |
{name: “liyuan01”, sex:“male”} | queue02, queue01 will receive |
wget https://github.com/rabbitmq/cluster-operator/releases/latest/download/cluster-operator.yml -O cluster-operator.yaml
# 找到自己的cluster-operator image
# HINT: 若cpu架构为arm,需要执行如下command
sed -i 's#rabbitmqoperator/cluster-operator:2.2.0#cyrilix/rabbitmq-cluster-operator:2.2.0#g' cluster-operator.yaml
kubectl apply -f cluster-operator.yaml && kubectl get po -n rabbitmq-system
# rabbitmq-cluster.yaml
apiVersion: rabbitmq.com/v1beta1
kind: RabbitmqCluster
metadata:
name: rabbitmq-cluster
namespace: default
spec:
replicas: 2
# image: registry.cn-hangzhou.aliyuncs.com/yuanli123/rabbitmq:3.9.22-management
persistence:
storage: 3Gi
storageClassName: nfs-client
resources:
limits:
cpu: 2000m
memory: 1Gi
requests:
cpu: 1000m
memory: 500Mi
secretBackend:
externalSecret:
name: rabbitmq-cluster-username-password
# rabbitmq:
# additionalConfig: |
# cluster_formation.k8s.host = 10.1.0.1
# cluster_formation.k8s.host = kubernetes.default.svc.cluster.local
# imagePullSecrets:
# - name: regcred
---
apiVersion: v1
stringData:
default_user.conf: |
default_user = liyuan
default_pass = liyuan
password: "liyuan"
username: "liyuan"
host: "rabbitmq-cluster.default.svc"
port: "5672"
provider: "rabbitmq"
kind: Secret
metadata:
annotations:
rabbitmq.com/queueRebalanceNeededAt: "2023-06-05T13:16:17Z"
labels:
app.kubernetes.io/component: rabbitmq
app.kubernetes.io/name: rabbitmq-cluster
app.kubernetes.io/part-of: rabbitmq
name: rabbitmq-cluster-username-password
namespace: default
type: Opaque
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: default
name: rabbitmq-cluster-ingress
spec:
rules:
- host: rabbitmq.liyuan.com
http:
paths:
- backend:
service:
name: rabbitmq-cluster
port:
number: 15672
pathType: Prefix
path: /
# HINT: 注意我们使用默认的rabbitmq镜像即可 'rabbitmq:3.11.10-management'
kubectl apply -f rabbitmq-cluster.yaml
username: liyuan
password: liyuan
默认情况下消息只会被路由到某一个节点的符合条件的队列上,并不会痛不到其他节点的相同队列上;若此时该节点宕机,那么该消息就会丢失;因此我们可以开启镜像队列,将集群中的队列彼此之间进行镜像,此时消息就会被拷贝到处于同一个镜像分组中的所有队列上;
当使用如上配置时,当我们发送消息给符合该名称^liyuan_*的队列时,该消息会被自动镜像