Rabbit mq - 等待 Mnesia 表时出错

26
我已经在Kubernetes集群上使用Helm Chart安装了RabbitMQ。RabbitMQ的pod一直在重新启动。检查pod日志后,我得到了以下错误信息。
2020-02-26 04:42:31.582 [warning] <0.314.0> Error while waiting for Mnesia tables: {timeout_waiting_for_tables,[rabbit_durable_queue]}
2020-02-26 04:42:31.582 [info] <0.314.0> Waiting for Mnesia tables for 30000 ms, 6 retries left

当我尝试运行kubectl describe pod时,会出现以下错误

Conditions:
  Type              Status
  Initialized       True
  Ready             False
  ContainersReady   False
  PodScheduled      True
Volumes:
  data:
    Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
    ClaimName:  data-rabbitmq-0
    ReadOnly:   false
  config-volume:
    Type:      ConfigMap (a volume populated by a ConfigMap)
    Name:      rabbitmq-config
    Optional:  false
  healthchecks:
    Type:      ConfigMap (a volume populated by a ConfigMap)
    Name:      rabbitmq-healthchecks
    Optional:  false
  rabbitmq-token-w74kb:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  rabbitmq-token-w74kb
    Optional:    false
QoS Class:       Burstable
Node-Selectors:  beta.kubernetes.io/arch=amd64
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type     Reason     Age                      From                                               Message
  ----     ------     ----                     ----                                               -------
  Warning  Unhealthy  3m27s (x878 over 7h21m)  kubelet, gke-analytics-default-pool-918f5943-w0t0  Readiness probe failed: Timeout: 70 seconds ...
Checking health of node rabbit@rabbitmq-0.rabbitmq-headless.default.svc.cluster.local ...
Status of node rabbit@rabbitmq-0.rabbitmq-headless.default.svc.cluster.local ...
Error:
{:aborted, {:no_exists, [:rabbit_vhost, [{{:vhost, :"$1", :_, :_}, [], [:"$1"]}]]}}
Error:
{:aborted, {:no_exists, [:rabbit_vhost, [{{:vhost, :"$1", :_, :_}, [], [:"$1"]}]]}}

我已经在谷歌云上的一个Kubernetes集群中进行了上述配置。我不确定它在什么具体情况下开始出现故障。我不得不重启Pod,自那以后它一直在出现问题。

这里的问题是什么?


这是我得到的错误。我更新了问题并加入了错误详情。{:aborted, {:no_exists, [:rabbit_vhost, [{{:vhost, :"$1", :_, :_}, [], [:"$1"]}]]}} 错误: {:aborted, {:no_exists, [:rabbit_vhost, [{{:vhost, :"$1", :_, :_}, [], [:"$1"]}]]}}``` - jeril
你用了哪个 Helm Chart? - Dawid Kruk
这是我使用的 helm chart。https://github.com/helm/charts/tree/master/stable/rabbitmq 。这些是我使用的值-https://github.com/helm/charts/blob/master/stable/rabbitmq/values-production.yaml仅在 values-production.yaml 中注释了此部分。

extraPlugins: "rabbitmq_auth_backend_ldap

- jeril
你能解决你的问题吗? - Amir Soleimani Borujerdi
@AmirSoleimani - 你的解决方案有效。 - jeril
显示剩余3条评论
6个回答

52

TLDR

helm upgrade rabbitmq --set clustering.forceBoot=true

问题

出现问题的原因如下:

  • 由于某些原因(可能是您将StatefulSet副本显式设置为0,或其他原因),所有RMQ pod同时终止。
  • 其中一个是最后停止的(可能仅比其他人晚一点)。它在其文件系统中存储此条件(“我现在是独立的”),在k8s中为PersistentVolume(Claim)。假设此pod为rabbitmq-1。
  • 当您重新启动StatefulSet时,pod rabbitmq-0始终首先启动(请参见here)。
  • 在启动期间,pod rabbitmq-0首先检查是否应该独立运行。但就其自己的文件系统而言,它是集群的一部分。因此,它会检查其同行并找不到任何同行。这results in a startup failure by default
  • rabbitmq-0因此永远不会准备就绪。
  • rabbitmq-1从未启动,因为这就是StatefulSets的部署方式-一个接一个地启动。如果它要启动,它将成功启动,因为它看到它也可以独立运行。

因此,最终结果是RabbitMQ和StatefulSets的工作方式有点不匹配。RMQ表示:“如果一切都崩溃了,请同时启动一切,其中一个将能够启动,并且只要此项已经启动,其他人就可以重新加入集群。” k8s StatefulSets表示:“无法同时启动所有内容,我们将从0开始启动。”

解决方案

为了解决这个问题,rabbitmqctl有一个force_boot命令,基本上告诉实例在找不到任何对等体时独立启动。如何在Kubernetes中使用取决于您正在使用的Helm图表和容器。在使用Bitnami Docker imageBitnami Chart中,有一个值clustering.forceBoot = true,它转换为容器中的env变量RABBITMQ_FORCE_BOOT = yes,然后将为您发出上述命令。

但是,从问题的角度来看,您也可以看到为什么删除 PVC 将起作用(其他答案)。Pod 只会“忘记”他们上次是 RMQ 集群的一部分,然后愉快地开始。虽然没有数据丢失,但我更喜欢上述解决方案。


5
此外,Bitnami的Github中有一个关于恢复的部分,提到了forceBoot和另一种选项(使用Parallel podManagementPolicy)。 https://github.com/bitnami/charts/tree/master/bitnami/rabbitmq#recover-the-cluster-from-complete-shutdown - victorm1710
(1.) 提醒一下,当你有三台运行RabbitMQ并配置为集群时,“等待Mnesia表时出错”的问题也会发生。所以这不仅仅是一个Kubernetes、Helm的问题。(2.) 不幸的是,对于RabbitMQ来说,没有针对clustering.forceBoot的配置文件设置。所以我必须清除/var/lib/rabbitmq/mnesia,才能让服务器启动。现在它们都卡在了“inconsistent_database”的启动循环中。(3.) 在我的情况下,如果你停止了server1、2、3的Rabbit集群,那么你必须按照LIFO的顺序启动,即3、2、1。这样可以避免出现问题。 - Trevor Boyd Smith
相关的 RabbitMQ 文档:https://www.rabbitmq.com/clustering.html#restarting - Trevor Boyd Smith
这应该被标记为答案。谢谢Ulli,你节省了我数小时的烦恼! - Andrey
4
我不得不添加 podManagementPolicy=Parallel。即使使用了 forceBoot 选项,rabbitmq-0 仍未启动。 - dev-rowbot
显示剩余2条评论

15

只需删除现有的持久化卷声明并重新安装rabbitmq即可使其正常工作。

因此,每次在Kubernetes集群上安装rabbitmq并将Pod数量缩减至0后,当我在稍后再次将Pod数量增加时,我会得到相同的错误。 我还尝试了删除持久性卷索赔而不卸载rabbitmq helm图表,但仍然出现相同的错误。

因此,似乎每次我将集群规模缩减至0时,都需要卸载rabbitmq helm图表,删除相应的持久性卷索赔,并重新安装rabbitmq helm图表才能使其正常工作。


3
请注意,删除持久卷索赔可能会破坏您的数据。在生产环境中不要这样做。 - Ulli
我同意通常情况下删除持久卷可能会导致数据丢失。但是对于RabbitMQ开发人员(以及我认识的许多其他RabbitMQ用户),我们不需要、不想要或不使用任何RabbitMQ持久性功能。我的同事告诉我,他将Helm的“持久性”设置为false,并且没有任何RabbitMQ的“PVC”。这也是我要尝试的方法。 - Trevor Boyd Smith
您提供的删除Pod和PVC的解决方案对我很有帮助。我认为RabbitMQ没有正常关闭,导致Mnesia文件损坏,因此通过删除PVC和Pod,我获得了一个新的Pod和空的PVC,使得RabbitMQ的Helm图表最终能够成功上线。 - Trevor Boyd Smith
1
运行 rabbitmq helm chart,并将持久化设置为“false”肯定更好:
  1. 更简单的配置
  2. 请求少一些kubernetes资源
  3. 在启动和关闭方面更加强大
  4. 更可靠(无需编写自定义脚本来检查错误状态,然后删除pod / pvc)
- Trevor Boyd Smith
如果还有其他人和 Docker 一起遇到了同样的问题,我也遇到了,并看到了这个答案。删除 RabbitMQ Docker 容器并重新拉取镜像可以为我们的应用程序解决此问题。 - dabyland

3

如果你和我一样处于相同的情境,不知道是谁部署了helm图表以及如何部署...你可以直接编辑statefulset来避免更多问题的混乱。

我能够在不删除helm_chart的情况下让它工作。

kubectl -n rabbitmq edit statefulsets.apps rabbitmq

在spec部分下面,我添加了一个名为RABBITMQ_FORCE_BOOT = yes的环境变量:

    spec:
      containers:
      - env:
        - name: RABBITMQ_FORCE_BOOT # New Line 1 Added
          value: "yes"              # New Line 2 Added

这应该也可以解决问题...请先按照Ulli上面所述的正确方式尝试。


1
在我的情况下,解决方案很简单。
步骤1:降低有状态集的规模,这不会删除永久卷(PVC)。
kubectl scale statefulsets rabbitmq-1-rabbitmq --namespace teps-rabbitmq --replicas=1

步骤二:访问RabbitMQ Pod。
kubectl exec -it rabbitmq-1-rabbitmq-0 -n Rabbit

步骤三:重置集群

rabbitmqctl stop_app
rabbitmqctl force_boot

步骤4:重新调整有状态集

  kubectl scale statefulsets rabbitmq-1-rabbitmq --namespace teps-rabbitmq --replicas=4

0

我也遇到了一个类似以下的错误:

2020-06-05 03:45:37.153 [info] <0.234.0> 等待 Mnesia 表格 30000 毫秒,还剩下 9 次重试 2020-06-05 03:46:07.154 [warning] <0.234.0> 在等待 Mnesia 表格时出现错误:{timeout_waiting_for_tables,[rabbit_user,rabbit_user_permission,rabbit_topic_permission,rabbit_vhost,rabbit_durable_route,rabbit_durable_exchange,rabbit_runtime_parameters,rabbit_durable_queue]} 2020-06-05 03:46:07.154 [info] <0.234.0> 等待 Mnesia 表格 30000 毫秒,还剩下 8 次重试

在我的情况中,RabbitMQ 集群中的从节点(服务器)已停机。一旦启动了从节点,主节点就能够正常启动而不会出现错误。


我尝试了很多方法来解决这个问题,最终我使用了RabbitMQ运算符。 https://www.rabbitmq.com/kubernetes/operator/operator-overview.html - Amir Soleimani Borujerdi

-7

测试此部署:

kind: Service
apiVersion: v1
metadata:
  namespace: rabbitmq-namespace
  name: rabbitmq
  labels:
    app: rabbitmq
    type: LoadBalancer  
spec:
  type: NodePort
  ports:
   - name: http
     protocol: TCP
     port: 15672
     targetPort: 15672
     nodePort: 31672
   - name: amqp
     protocol: TCP
     port: 5672
     targetPort: 5672
     nodePort: 30672
   - name: stomp
     protocol: TCP
     port: 61613
     targetPort: 61613
  selector:
    app: rabbitmq
---
kind: Service 
apiVersion: v1
metadata:
  namespace: rabbitmq-namespace
  name: rabbitmq-lb
  labels:
    app: rabbitmq
spec:
  # Headless service to give the StatefulSet a DNS which is known in the cluster (hostname-#.app.namespace.svc.cluster.local, )
  # in our case - rabbitmq-#.rabbitmq.rabbitmq-namespace.svc.cluster.local  
  clusterIP: None
  ports:
   - name: http
     protocol: TCP
     port: 15672
     targetPort: 15672
   - name: amqp
     protocol: TCP
     port: 5672
     targetPort: 5672
   - name: stomp
     port: 61613
  selector:
    app: rabbitmq
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: rabbitmq-config
  namespace: rabbitmq-namespace
data:
  enabled_plugins: |
      [rabbitmq_management,rabbitmq_peer_discovery_k8s,rabbitmq_stomp].

  rabbitmq.conf: |
      ## Cluster formation. See http://www.rabbitmq.com/cluster-formation.html to learn more.
      cluster_formation.peer_discovery_backend  = rabbit_peer_discovery_k8s
      cluster_formation.k8s.host = kubernetes.default.svc.cluster.local
      ## Should RabbitMQ node name be computed from the pod's hostname or IP address?
      ## IP addresses are not stable, so using [stable] hostnames is recommended when possible.
      ## Set to "hostname" to use pod hostnames.
      ## When this value is changed, so should the variable used to set the RABBITMQ_NODENAME
      ## environment variable.
      cluster_formation.k8s.address_type = hostname   
      ## Important - this is the suffix of the hostname, as each node gets "rabbitmq-#", we need to tell what's the suffix
      ## it will give each new node that enters the way to contact the other peer node and join the cluster (if using hostname)
      cluster_formation.k8s.hostname_suffix = .rabbitmq.rabbitmq-namespace.svc.cluster.local
      ## How often should node cleanup checks run?
      cluster_formation.node_cleanup.interval = 30
      ## Set to false if automatic removal of unknown/absent nodes
      ## is desired. This can be dangerous, see
      ##  * http://www.rabbitmq.com/cluster-formation.html#node-health-checks-and-cleanup
      ##  * https://groups.google.com/forum/#!msg/rabbitmq-users/wuOfzEywHXo/k8z_HWIkBgAJ
      cluster_formation.node_cleanup.only_log_warning = true
      cluster_partition_handling = autoheal
      ## See http://www.rabbitmq.com/ha.html#master-migration-data-locality
      queue_master_locator=min-masters
      ## See http://www.rabbitmq.com/access-control.html#loopback-users
      loopback_users.guest = false
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: rabbitmq
  namespace: rabbitmq-namespace
spec:
  serviceName: rabbitmq
  replicas: 3
  selector:
    matchLabels:
      name: rabbitmq
  template:
    metadata:
      labels:
        app: rabbitmq
        name: rabbitmq
        state: rabbitmq
      annotations:
        pod.alpha.kubernetes.io/initialized: "true"
    spec:
      serviceAccountName: rabbitmq
      terminationGracePeriodSeconds: 10
      containers:        
      - name: rabbitmq-k8s
        image: rabbitmq:3.8.3
        volumeMounts:
          - name: config-volume
            mountPath: /etc/rabbitmq
          - name: data
            mountPath: /var/lib/rabbitmq/mnesia
        ports:
          - name: http
            protocol: TCP
            containerPort: 15672
          - name: amqp
            protocol: TCP
            containerPort: 5672
        livenessProbe:
          exec:
            command: ["rabbitmqctl", "status"]
          initialDelaySeconds: 60
          periodSeconds: 60
          timeoutSeconds: 10
        resources:
            requests:
              memory: "0"
              cpu: "0"
            limits:
              memory: "2048Mi"
              cpu: "1000m"
        readinessProbe:
          exec:
            command: ["rabbitmqctl", "status"]
          initialDelaySeconds: 20
          periodSeconds: 60
          timeoutSeconds: 10
        imagePullPolicy: Always
        env:
          - name: MY_POD_IP
            valueFrom:
              fieldRef:
                fieldPath: status.podIP
          - name: NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
          - name: HOSTNAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
          - name: RABBITMQ_USE_LONGNAME
            value: "true"
          # See a note on cluster_formation.k8s.address_type in the config file section
          - name: RABBITMQ_NODENAME
            value: "rabbit@$(HOSTNAME).rabbitmq.$(NAMESPACE).svc.cluster.local"
          - name: K8S_SERVICE_NAME
            value: "rabbitmq"
          - name: RABBITMQ_ERLANG_COOKIE
            value: "mycookie"      
      volumes:
        - name: config-volume
          configMap:
            name: rabbitmq-config
            items:
            - key: rabbitmq.conf
              path: rabbitmq.conf
            - key: enabled_plugins
              path: enabled_plugins
  volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes:
        - "ReadWriteOnce"
      storageClassName: "default"
      resources:
        requests:
          storage: 3Gi

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: rabbitmq 
  namespace: rabbitmq-namespace 
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: endpoint-reader
  namespace: rabbitmq-namespace 
rules:
- apiGroups: [""]
  resources: ["endpoints"]
  verbs: ["get"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: endpoint-reader
  namespace: rabbitmq-namespace
subjects:
- kind: ServiceAccount
  name: rabbitmq
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: endpoint-reader

说实话,这并不是真正有帮助的。为什么有人想要尝试它,还要配置一堆与他/她无关的东西呢? - Haris Osmanagić
@HarisOsmanagić,您可以根据您的使用情况编辑配置映射。 - Amir Soleimani Borujerdi
不行,因为其中包含太多内容。每个人都会欣赏看到能够解决问题的确切参数,而不必尝试使用另一个配置映射。 - Haris Osmanagić

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接