RabbitMQ 简介
以熟悉的电商场景为例,如果商品服务和订单服务是两个不同的微服务,在下单的过程中订单服务需要调用商品服务进行扣库存操作。按照传统的方式,下单过程要等到调用完毕之后才能返回下单成功,如果网络产生波动等原因使得商品服务扣库存延迟或者失败,会带来较差的用户体验,如果在高并发的场景下,这样的处理显然是不合适的,那怎么进行优化呢?这就需要消息队列登场了。
消息队列提供一个异步通信机制,消息的发送者不必一直等待到消息被成功处理才返回,而是立即返回。消息中间件负责处理网络通信,如果网络连接不可用,消息被暂存于队列当中,当网络畅通的时候在将消息转发给相应的应用程序或者服务,当然前提是这些服务订阅了该队列。如果在商品服务和订单服务之间使用消息中间件,既可以提高并发量,又降低服务之间的耦合度。
RabbitMQ就是这样一款我们苦苦追寻的消息队列。RabbitMQ是一个开源的消息代理的队列服务器,用来通过普通协议在完全不同的应用之间共享数据。
RabbitMQ 的特点
开源、性能优秀,速度快,稳定性保障提供可靠性消息投递模式、返回模式与Spring AMQP完美整合,API丰富集群模式丰富,表达式配置,HA模式,镜像队列模型保证数据不丢失的前提做到高可靠性、可用性
RabbitMQ 典型应用场景
- 异步处理:把消息放入消息中间件中,等到需要的时候再去处理。
- 流量削峰:例如秒杀活动,在短时间内访问量急剧增加,使用消息队列,当消息队列满了就拒绝响应,跳转到错误页面,这样就可以使得系统不会因为超负载而崩溃。
- 日志处理;(不过一般日志处理都使用Kafka这种消息队列)
- 应用解耦:假设某个服务A需要给许多个服务(B、C、D)发送消息,当某个服务(例如B)不需要发送消息了,服务A需要改代码再次部署;当新加入一个服务(服务E)需要服务A的消息的时候,也需要改代码重新部署;另外服务A也要考虑其他服务挂掉,没有收到消息怎么办?要不要重新发送呢?是不是很麻烦,使用MQ发布订阅模式,服务A只生产消息发送到MQ,B、C、D从MQ中读取消息,需要A的消息就订阅,不需要了就取消订阅,服务A不再操心其他的事情,使用这种方式可以降低服务或者系统之间的耦合。
RabbitMQ集群节点之间是如何相互认证的:
- 通过Erlang Cookie,相当于共享秘钥的概念,长度任意,只要所有节点都一致即可。
- rabbitmq server在启动的时候,erlang VM会自动创建一个随机的cookie文件。cookie文件的位置是/var/lib/rabbitmq/.erlang.cookie 或者 /root/.erlang.cookie,为保证cookie的完全一致,采用从一个节点copy的方式。
Erlang Cookie是保证不同节点可以相互通信的密钥,要保证集群中的不同节点相互通信必须共享相同的Erlang Cookie。具体的目录存放在/var/lib/rabbitmq/.erlang.cookie。
说明:这就要从rabbitmqctl命令的工作原理说起,RabbitMQ底层是通过Erlang架构来实现的,所以rabbitmqctl会启动Erlang节点,并基于Erlang节点来使用Erlang系统连接RabbitMQ节点,在连接过程中需要正确的Erlang Cookie和节点名称,Erlang节点通过交换Erlang Cookie以获得认证。
RabbitMQ集群模式
- 单机模式
- 普通集群模式(无高可用性)
- 镜像集群模式(高可用性),最常用的集群模式。
RabbitMQ集群故障处理机制:
- rabbitmq broker集群允许个体节点down机,
- 对应集群的的网络分区问题( network partitions)
RabbitMQ集群推荐用于LAN环境,不适用WAN环境;
要通过WAN连接broker,Shovel or Federation插件是最佳的解决方案;Shovel or Federation不同于集群。
RabbitMQ节点类型
- RAM node:只保存状态到内存。内存节点将所有的队列、交换机、绑定、用户、权限和vhost的元数据定义存储在内存中,好处是可以使得像交换机和队列声明等操作更加的快速。
- Disk node:将元数据存储在磁盘中。单节点系统只允许磁盘类型的节点,防止重启RabbitMQ的时候,丢失系统的配置信息。
内存节点虽然不写入磁盘,但是它执行比磁盘节点要好。RabbitMQ集群中,只需要一个磁盘节点来保存状态就足够了;如果集群中只有内存节点,那么不能停止它们,否则所有的状态,消息等都会丢失。
问题说明:
- RabbitMQ要求在集群中至少有一个磁盘节点,所有其他节点可以是内存节点,当节点加入或者离开集群时,必须要将该变更通知到至少一个磁盘节点。
- 如果集群中唯一的一个磁盘节点崩溃的话,集群仍然可以保持运行,但是无法进行其他操作(增删改查),直到节点恢复。
解决方案:设置两个磁盘节点,至少有一个是可用的,可以保存元数据的更改。
RabbitMQ集群的节点运行模式:
- 为保证数据持久性,当前所有node节点跑在disk模式。
- 如果今后压力大,需要提高性能,考虑采用ram模式。
RabbitMQ集群记录
本案例采用 "镜像模式",即队列为镜像队列,队列消息存在集群的每个节点上。
1、版本说明
因为考虑到较早版本rabbitmq在k8s上的集群部署是使用autocluster插件去调用kubernetes apiserver来获取rabbitmq服务的endpoints,进而获取node节点信息,并自动加入集群,但是现在autocluster已不再更新了,并且只支持3.6.x版本,故而放弃这种方式。
对于3.7.x或更新的版本,现在市场主流是使用 peer discovery subsystem来构建rabbitmq-cluster,参考这里。
2、部署方式
在Kubernetes上搭建RabbitMQ有4种部署方法(IP模式、Pod与Server的DNS模式、Statefulset 与Headless Service模式、hostname模式),这里选择StatefulSet与Headless Service模式部署有状态的RabbitMQ集群。
3、使用NFS配置StatefulSet的动态持久化存储
1)在NFS服务器端(172.16.60.238)通过nfs创建RabbitMQ集群的共享目录
1
|
[root@k8s-harbor01 ~] # mkdir -p /data/storage/k8s/rabbitmq |
2)创建nfs的rbac
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
[root@k8s-master01 ~] # mkdir -p /opt/k8s/k8s_project/rabbitmq [root@k8s-master01 ~] # cd /opt/k8s/k8s_project/rabbitmq [root@k8s-master01 rabbitmq] # vim nfs-rbac.yaml --- apiVersion: v1 kind: ServiceAccount metadata: name: nfs-provisioner namespace: wiseco --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io /v1 metadata: name: nfs-provisioner-runner namespace: wiseco rules: - apiGroups: [ "" ] resources: [ "persistentvolumes" ] verbs: [ "get" , "list" , "watch" , "create" , "delete" ] - apiGroups: [ "" ] resources: [ "persistentvolumeclaims" ] verbs: [ "get" , "list" , "watch" , "update" ] - apiGroups: [ "storage.k8s.io" ] resources: [ "storageclasses" ] verbs: [ "get" , "list" , "watch" ] - apiGroups: [ "" ] resources: [ "events" ] verbs: [ "watch" , "create" , "update" , "patch" ] - apiGroups: [ "" ] resources: [ "services" , "endpoints" ] verbs: [ "get" , "create" , "list" , "watch" , "update" ] - apiGroups: [ "extensions" ] resources: [ "podsecuritypolicies" ] resourceNames: [ "nfs-provisioner" ] verbs: [ "use" ] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io /v1 metadata: name: run-nfs-provisioner subjects: - kind: ServiceAccount name: nfs-provisioner namespace: wiseco roleRef: kind: ClusterRole name: nfs-provisioner-runner apiGroup: rbac.authorization.k8s.io |
查看并创建
1
2
3
4
5
6
7
8
9
10
11
12
13
|
[root@k8s-master01 rabbitmq] # kubectl apply -f nfs-rbac.yaml serviceaccount /nfs-provisioner created clusterrole.rbac.authorization.k8s.io /nfs-provisioner-runner created clusterrolebinding.rbac.authorization.k8s.io /run-nfs-provisioner created [root@k8s-master01 rabbitmq] # kubectl get sa -n wiseco|grep nfs nfs-provisioner 1 6h2m [root@k8s-master01 rabbitmq] # kubectl get clusterrole -n wiseco|grep nfs nfs-provisioner-runner 2021-02-07T03:30:56Z [root@k8s-master01 rabbitmq] # kubectl get clusterrolebinding -n wiseco|grep nfs run-nfs-provisioner ClusterRole /nfs-provisioner-runner 6h2m |
3)创建RabbitMQ集群的storageclass
1
2
3
4
5
6
7
8
9
10
11
12
|
[root@k8s-master01 rabbitmq] # ll total 4 -rw-r--r-- 1 root root 1216 Feb 7 17:33 nfs-rbac.yaml [root@k8s-master01 rabbitmq] # vim rabbitmq-nfs-class.yaml apiVersion: storage.k8s.io /v1beta1 kind: StorageClass metadata: name: rabbitmq-nfs-storage namespace: wiseco provisioner: rabbitmq /nfs reclaimPolicy: Retain |
查看并创建
1
2
3
4
5
6
|
[root@k8s-master01 rabbitmq] # kubectl apply -f rabbitmq-nfs-class.yaml storageclass.storage.k8s.io /rabbitmq-nfs-storage created [root@k8s-master01 rabbitmq] # kubectl get sc NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE rabbitmq-nfs-storage rabbitmq /nfs Retain Immediate false 3s |
4)创建MongoDB集群的nfs-client-provisioner
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
[root@k8s-master01 rabbitmq] # ll total 8 -rw-r--r-- 1 root root 1216 Feb 7 17:33 nfs-rbac.yaml -rw-r--r-- 1 root root 161 Feb 7 17:37 rabbitmq-nfs-class.yaml [root@k8s-master01 rabbitmq] # vim rabbitmq-nfs.yml apiVersion: apps /v1 kind: Deployment metadata: name: rabbitmq-nfs-client-provisioner namespace: wiseco spec: replicas: 1 selector: matchLabels: app: rabbitmq-nfs-client-provisioner strategy: type : Recreate template: metadata: labels: app: rabbitmq-nfs-client-provisioner spec: serviceAccount: nfs-provisioner containers: - name: rabbitmq-nfs-client-provisioner image: registry.cn-hangzhou.aliyuncs.com /open-ali/nfs-client-provisioner imagePullPolicy: IfNotPresent volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes env : - name: PROVISIONER_NAME value: rabbitmq /nfs - name: NFS_SERVER value: 172.16.60.238 - name: NFS_PATH value: /data/storage/k8s/rabbitmq volumes: - name: nfs-client-root nfs: server: 172.16.60.238 path: /data/storage/k8s/rabbitmq |
查看并创建
1
2
3
4
5
|
[root@k8s-master01 rabbitmq] # kubectl apply -f rabbitmq-nfs.yml deployment.apps /rabbitmq-nfs-client-provisioner created [root@k8s-master01 rabbitmq] # kubectl get pods -n wiseco|grep rabbitmq rabbitmq-nfs-client-provisioner-c4f95d479-xvm8r 1 /1 Running 0 17s |
4、部署RabbitMQ基于镜像模式的集群
1
2
3
4
5
6
7
8
|
[root@k8s-master01 rabbitmq] # ll total 12 -rw-r--r-- 1 root root 1216 Feb 7 17:33 nfs-rbac.yaml -rw-r--r-- 1 root root 161 Feb 7 17:37 rabbitmq-nfs-class.yaml -rw-r--r-- 1 root root 1027 Feb 7 17:46 rabbitmq-nfs.yml [root@k8s-master01 rabbitmq] # mkdir deployment [root@k8s-master01 rabbitmq] # cd deployment [root@k8s-master01 deployment] # |
采用StatefulSet与Headless Service模式部署有状态的RabbitMQ集群。
rabbitmq.yml文件内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
[root@k8s-master01 deployment] # vim rabbitmq.yml --- apiVersion: v1 kind: Service metadata: name: rabbitmq-management namespace: wiseco labels: app: rabbitmq spec: ports: - port: 15672 name: http selector: app: rabbitmq type : NodePort --- apiVersion: v1 kind: Service metadata: name: rabbitmq namespace: wiseco labels: app: rabbitmq spec: ports: - port: 5672 name: amqp - port: 4369 name: epmd - port: 25672 name: rabbitmq-dist clusterIP: None selector: app: rabbitmq --- apiVersion: apps /v1 kind: StatefulSet metadata: namespace: wiseco name: rabbitmq spec: serviceName: "rabbitmq" replicas: 3 selector: matchLabels: app: rabbitmq template: metadata: labels: app: rabbitmq spec: affinity: podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: "app" operator: In values: - rabbitmq topologyKey: "kubernetes.io/hostname" containers: - name: rabbitmq image: rabbitmq:3.7-rc-management 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 [ -z "$(rabbitmqctl cluster_status | grep rabbitmq-0)" ]; then touch /gotit rabbitmqctl stop_app; rabbitmqctl reset; rabbitmqctl join_cluster rabbit@rabbitmq-0; rabbitmqctl start_app; else touch /notget fi ; env : - name: MY_POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: RABBITMQ_ERLANG_COOKIE value: "YZSDHWMFSMKEMBDHSGGZ" - name: RABBITMQ_NODENAME value: "rabbit@$(MY_POD_NAME)" ports: - name: http protocol: TCP containerPort: 15672 - name: amqp protocol: TCP containerPort: 5672 livenessProbe: tcpSocket: port: amqp initialDelaySeconds: 5 timeoutSeconds: 5 periodSeconds: 10 readinessProbe: tcpSocket: port: amqp initialDelaySeconds: 15 timeoutSeconds: 5 periodSeconds: 20 volumeMounts: - name: rabbitmq-data mountPath: /var/lib/rabbitmq volumeClaimTemplates: - metadata: name: rabbitmq-data annotations: volume.beta.kubernetes.io /storage-class : "rabbitmq-nfs-storage" spec: accessModes: - ReadWriteMany resources: requests: storage: 10Gi |
查看并创建
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
[root@k8s-master01 deployment] # kubectl apply -f rabbitmq.yml service /rabbitmq-management created service /rabbitmq created statefulset.apps /rabbitmq created [root@k8s-master01 deployment] # kubectl get pods -n wiseco -o wide|grep rabbitmq rabbitmq-0 1 /1 Running 0 11m 172.30.85.206 k8s-node01 <none> <none> rabbitmq-1 1 /1 Running 0 9m9s 172.30.217.69 k8s-node04 <none> <none> rabbitmq-2 1 /1 Running 0 7m59s 172.30.135.145 k8s-node03 <none> <none> rabbitmq-nfs-client-provisioner-c4f95d479-xvm8r 1 /1 Running 0 20h 172.30.217.122 k8s-node04 <none> <none> [root@k8s-master01 deployment] # kubectl get svc -n wiseco|grep rabbitmq rabbitmq ClusterIP None <none> 5672 /TCP ,4369 /TCP ,25672 /TCP 8m27s rabbitmq-management NodePort 10.254.128.136 <none> 15672:32513 /TCP 8m27s |
查看PV、PVC
1
2
3
4
5
6
7
8
9
10
11
|
[root@k8s-master01 deployment] # kubectl get pvc -n wiseco NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE rabbitmq-data-rabbitmq-0 Bound pvc-19579da4-fe40-4cc5-abb5-670486cc3f12 10Gi RWX rabbitmq-nfs-storage 9m38s rabbitmq-data-rabbitmq-1 Bound pvc-13218c20-2a79-40f2-92fa-a18300729c12 10Gi RWX rabbitmq-nfs-storage 7m5s rabbitmq-data-rabbitmq-2 Bound pvc-7a13561a-1d9c-430c-90df-45ccad455fce 10Gi RWX rabbitmq-nfs-storage 5m55s [root@k8s-master01 deployment] # kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-13218c20-2a79-40f2-92fa-a18300729c12 10Gi RWX Delete Bound wiseco /rabbitmq-data-rabbitmq-1 rabbitmq-nfs-storage 7m3s pvc-19579da4-fe40-4cc5-abb5-670486cc3f12 10Gi RWX Delete Bound wiseco /rabbitmq-data-rabbitmq-0 rabbitmq-nfs-storage 9m38s pvc-7a13561a-1d9c-430c-90df-45ccad455fce 10Gi RWX Delete Bound wiseco /rabbitmq-data-rabbitmq-2 rabbitmq-nfs-storage 5m55s |
查看NFS共享存储
NFS服务器(172.16.60.238),查看共享目录/data/storage/k8s/rabbitmq
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
[root@k8s-harbor01 ~] # cd /data/storage/k8s/rabbitmq/ [root@k8s-harbor01 rabbitmq] # ll total 0 drwxrwxrwx 5 polkitd root 70 Feb 8 14:17 wiseco-rabbitmq-data-rabbitmq-0-pvc-19579da4-fe40-4cc5-abb5-670486cc3f12 drwxrwxrwx 5 polkitd root 70 Feb 8 14:19 wiseco-rabbitmq-data-rabbitmq-1-pvc-13218c20-2a79-40f2-92fa-a18300729c12 drwxrwxrwx 5 polkitd root 70 Feb 8 14:21 wiseco-rabbitmq-data-rabbitmq-2-pvc-7a13561a-1d9c-430c-90df-45ccad455fce [root@k8s-harbor01 rabbitmq] # ls ./* . /wiseco-rabbitmq-data-rabbitmq-0-pvc-19579da4-fe40-4cc5-abb5-670486cc3f12 : config mnesia schema . /wiseco-rabbitmq-data-rabbitmq-1-pvc-13218c20-2a79-40f2-92fa-a18300729c12 : config mnesia schema . /wiseco-rabbitmq-data-rabbitmq-2-pvc-7a13561a-1d9c-430c-90df-45ccad455fce : config mnesia schema 查看RabbitMQ的三个容器节点的.erlang.cookie,内容是一致的! [root@k8s-harbor01 rabbitmq] # ll ./*/.erlang.cookie -rw------- 1 polkitd input 21 Feb 8 14:16 . /wiseco-rabbitmq-data-rabbitmq-0-pvc-19579da4-fe40-4cc5-abb5-670486cc3f12/ .erlang.cookie -rw------- 1 polkitd input 21 Feb 8 14:19 . /wiseco-rabbitmq-data-rabbitmq-1-pvc-13218c20-2a79-40f2-92fa-a18300729c12/ .erlang.cookie -rw------- 1 polkitd input 21 Feb 8 14:20 . /wiseco-rabbitmq-data-rabbitmq-2-pvc-7a13561a-1d9c-430c-90df-45ccad455fce/ .erlang.cookie [root@k8s-harbor01 rabbitmq] # cat ./*/.erlang.cookie YZSDHWMFSMKEMBDHSGGZ YZSDHWMFSMKEMBDHSGGZ YZSDHWMFSMKEMBDHSGGZ |
5、验证RabbitMQ集群
进入RabbitMQ集群节点Pod容器,查看RabbitMQ集群状态(三个Pod查看的集群状态是一样的)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
登录rabbitmq-0容器查看集群状态 [root@k8s-master01 deployment] # kubectl exec -ti rabbitmq-0 -n wiseco -- rabbitmqctl cluster_status Cluster status of node rabbit@rabbitmq-0 ... [{nodes,[{disc,[ 'rabbit@rabbitmq-0' , 'rabbit@rabbitmq-1' , 'rabbit@rabbitmq-2' ]}]}, {running_nodes,[ 'rabbit@rabbitmq-2' , 'rabbit@rabbitmq-1' , 'rabbit@rabbitmq-0' ]}, {cluster_name,<< "rabbit@rabbitmq-0.rabbitmq.wiseco.svc.cluster.local" >>}, {partitions,[]}, {alarms,[{ 'rabbit@rabbitmq-2' ,[]}, { 'rabbit@rabbitmq-1' ,[]}, { 'rabbit@rabbitmq-0' ,[]}]}] 登录rabbitmq-1容器查看集群状态 [root@k8s-master01 deployment] # kubectl exec -ti rabbitmq-1 -n wiseco -- rabbitmqctl cluster_status Cluster status of node rabbit@rabbitmq-1 ... [{nodes,[{disc,[ 'rabbit@rabbitmq-0' , 'rabbit@rabbitmq-1' , 'rabbit@rabbitmq-2' ]}]}, {running_nodes,[ 'rabbit@rabbitmq-2' , 'rabbit@rabbitmq-0' , 'rabbit@rabbitmq-1' ]}, {cluster_name,<< "rabbit@rabbitmq-0.rabbitmq.wiseco.svc.cluster.local" >>}, {partitions,[]}, {alarms,[{ 'rabbit@rabbitmq-2' ,[]}, { 'rabbit@rabbitmq-0' ,[]}, { 'rabbit@rabbitmq-1' ,[]}]}] 登录rabbitmq-2容器查看集群状态 [root@k8s-master01 deployment] # kubectl exec -ti rabbitmq-2 -n wiseco -- rabbitmqctl cluster_status Cluster status of node rabbit@rabbitmq-2 ... [{nodes,[{disc,[ 'rabbit@rabbitmq-0' , 'rabbit@rabbitmq-1' , 'rabbit@rabbitmq-2' ]}]}, {running_nodes,[ 'rabbit@rabbitmq-0' , 'rabbit@rabbitmq-1' , 'rabbit@rabbitmq-2' ]}, {cluster_name,<< "rabbit@rabbitmq-0.rabbitmq.wiseco.svc.cluster.local" >>}, {partitions,[]}, {alarms,[{ 'rabbit@rabbitmq-0' ,[]}, { 'rabbit@rabbitmq-1' ,[]}, { 'rabbit@rabbitmq-2' ,[]}]}] |
6、访问RabbitMQ的Web界面,查看集群状态
1
2
3
|
[root@k8s-master01 deployment] # kubectl get svc -n wiseco|grep rabbitmq rabbitmq ClusterIP None <none> 5672 /TCP ,4369 /TCP ,25672 /TCP 23m rabbitmq-management NodePort 10.254.128.136 <none> 15672:32513 /TCP 23m |
通过K8S的node节点的32513访问web页面,用户名和密码都是guest
7、RabbitMQ的日常操作命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
1)用户管理 ===================================================================================================== 新增一个用户 # rabbitmqctl add_user Username Password 删除一个用户 # rabbitmqctl delete_user Username 修改用户的密码 # rabbitmqctl change_password Username Newpassword 查看当前用户列表 # rabbitmqctl list_users 比如:修改guest用户密码、新增或删除一个用户 查看当前用户列表 [root@k8s-master01 deployment] # kubectl exec -ti rabbitmq-0 -n wiseco -- rabbitmqctl list_users Listing users ... user tags guest [administrator] 修改guest用户密码为 guest@123 [root@k8s-master01 deployment] # kubectl exec -ti rabbitmq-0 -n wiseco -- rabbitmqctl change_password guest guest@123 Changing password for user "guest" .. 新增一个用户,用户名为kevin,密码为 kevin@123 [root@k8s-master01 deployment] # kubectl exec -ti rabbitmq-0 -n wiseco -- rabbitmqctl add_user kevin kevin@123 Adding user "kevin" ... 查看当前用户列表 [root@k8s-master01 deployment] # kubectl exec -ti rabbitmq-0 -n wiseco -- rabbitmqctl list_users Listing users ... user tags guest [administrator] kevin [] 设置kevin用户角色为administrator [root@k8s-master01 deployment] # kubectl exec -ti rabbitmq-0 -n wiseco -- rabbitmqctl set_user_tags kevin administrator Setting tags for user "kevin" to [administrator] ... 查看当前用户列表 [root@k8s-master01 deployment] # kubectl exec -ti rabbitmq-0 -n wiseco -- rabbitmqctl list_users Listing users ... user tags guest [administrator] kevin [administrator] 修改kevin用户角色为monitoring、policymaker [root@k8s-master01 deployment] # kubectl exec -ti rabbitmq-0 -n wiseco -- rabbitmqctl set_user_tags kevin monitoring policymaker Setting tags for user "kevin" to [monitoring, policymaker] ... 查看当前用户列表 [root@k8s-master01 deployment] # kubectl exec -ti rabbitmq-0 -n wiseco -- rabbitmqctl list_users Listing users ... user tags guest [administrator] kevin [monitoring, policymaker] 删除kevin用户 [root@k8s-master01 deployment] # kubectl exec -ti rabbitmq-0 -n wiseco -- rabbitmqctl delete_user kevin Deleting user "kevin" ... 查看当前用户列表 [root@k8s-master01 deployment] # kubectl exec -ti rabbitmq-0 -n wiseco -- rabbitmqctl list_users Listing users ... user tags guest [administrator] 2)用户角色 ===================================================================================================== 用户角色分类 用户角色可分为五类:超级管理员、监控者、策略制定者、普通管理者以及其他。 超级管理员 (administrator) 可登陆管理控制台(启用management plugin的情况下),可查看所有的信息,并且可以对用户,策略(policy)进行操作。 监控者 (monitoring) 可登陆管理控制台(启用management plugin的情况下),同时可以查看rabbitmq节点的相关信息(进程数,内存使用情况,磁盘使用情况等) 策略制定者 (policymaker) 可登陆管理控制台(启用management plugin的情况下), 同时可以对policy进行管理。但无法查看节点的相关信息 普通管理者 (management) 仅可登陆管理控制台(启用management plugin的情况下),无法看到节点信息,也无法对策略进行管理。 其他 无法登陆管理控制台,通常就是普通的生产者和消费者。 相关操作命令: 设置用户角色的命令为: # rabbitmqctl set_user_tags User Tag 其中: User为用户名 Tag为角色名 (对应于上面的administrator,monitoring,policymaker,management,或其他自定义名称)。 也可以给同一用户设置多个角色,例如: # rabbitmqctl set_user_tags kevin monitoring policymaker 3)用户权限 ===================================================================================================== 用户权限指的是用户对exchange,queue的操作权限,包括配置权限,读写权限。 配置权限会影响到exchange,queue的声明和删除。 读写权限影响到从queue里取消息,向exchange发送消息以及queue和exchange的绑定(bind)操作。 例如: 将queue绑定到某exchange上,需要具有queue的可写权限,以及exchange的可读权限; 向exchange发送消息需要具有exchange的可写权限; 从queue里取数据需要具有queue的可读权限。 相关操作命令: 设置用户权限 # rabbitmqctl set_permissions -p VHostPath User ConfP WriteP ReadP 查看(指定hostpath)所有用户的权限信息 # rabbitmqctl list_permissions [-p VHostPath] 查看指定用户的权限信息 # rabbitmqctl list_user_permissions User 清除用户的权限信息 # rabbitmqctl clear_permissions [-p VHostPath] User 设置节点类型 RabbitMQ节点类型分为内存节点和硬盘节点。 如果你想更换节点类型可以通过命令修改: # rabbitmqctl stop_app # rabbitmqctl change_cluster_node_type dist # rabbitmqctl change_cluster_node_type ram # rabbitmqctl start_app |
8、模拟RabbitMQ节点故障
模拟故障,重启其中的一个node节点,比如rabbitmq-0,然后观察集群状态:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
[root@k8s-master01 deployment] # kubectl get pods -n wiseco -o wide|grep rabbitmq rabbitmq-0 1 /1 Running 0 71m 172.30.85.206 k8s-node01 <none> <none> rabbitmq-1 1 /1 Running 0 68m 172.30.217.69 k8s-node04 <none> <none> rabbitmq-2 1 /1 Running 0 67m 172.30.135.145 k8s-node03 <none> <none> rabbitmq-nfs-client-provisioner-c4f95d479-xvm8r 1 /1 Running 0 21h 172.30.217.122 k8s-node04 <none> <none> 删除rabbitmq-0节点 [root@k8s-master01 deployment] # kubectl delete pods rabbitmq-0 -n wiseco pod "rabbitmq-0" deleted 查看pod,发现rabbitmq-0节点删除后,重启需要耗费一段时间 [root@k8s-master01 deployment] # kubectl get pods -n wiseco -o wide|grep rabbitmq rabbitmq-0 0 /1 ContainerCreating 0 44s <none> k8s-node01 <none> <none> rabbitmq-1 1 /1 Running 0 70m 172.30.217.69 k8s-node04 <none> <none> rabbitmq-2 1 /1 Running 0 69m 172.30.135.145 k8s-node03 <none> <none> rabbitmq-nfs-client-provisioner-c4f95d479-xvm8r 1 /1 Running 0 21h 172.30.217.122 k8s-node04 <none> <none> 此时,查看RabbitMQ集群状态 发现此时,rabbit@rabbitmq-0节点还没有恢复,running的node节点只有rabbit@rabbitmq-2、rabbit@rabbitmq-1 [root@k8s-master01 ~] # kubectl exec -ti rabbitmq-1 -n wiseco -- rabbitmqctl cluster_status Cluster status of node rabbit@rabbitmq-1 ... [{nodes,[{disc,[ 'rabbit@rabbitmq-0' , 'rabbit@rabbitmq-1' , 'rabbit@rabbitmq-2' ]}]}, {running_nodes,[ 'rabbit@rabbitmq-2' , 'rabbit@rabbitmq-1' ]}, {cluster_name,<< "rabbit@rabbitmq-0.rabbitmq.wiseco.svc.cluster.local" >>}, {partitions,[]}, {alarms,[{ 'rabbit@rabbitmq-2' ,[]},{ 'rabbit@rabbitmq-1' ,[]}]}] |
此时,查看web界面的集群状态,先后经历了下面三个状态:
- 红色表示 节点故障。
- 黄色表示 节点恢复中,暂不可用。
- 绿色表示 点运行正常。
9、客户端访问RabbitMQ集群地址
客户端连接RabbitMQ集群地址:rabbitmq-0.rabbitmq.wiseco.svc.cluster.local:5672、rabbitmq-0.rabbitmq.wiseco.svc.cluster.local:5672、rabbitmq-0.rabbitmq.wiseco.svc.cluster.local:5672
连接方式:
- 客户端可以连接RabbitMQ集群中的任意一个节点。如果一个节点故障,客户端自行重新连接到其他的可用节点;
- 也就是说,RabbitMQ集群有"重连"机制,但是这种集群连接方式对客户端不透明,不太建议这种连接方式。
推荐方式:给客户端提供一个统一的透明的集群连接地址
做法:在前面部署LVS或Haproxy,通过四层负载均衡代理后RabbitMQ的三个node节点的5672端口。