代码之家  ›  专栏  ›  技术社区  ›  jeril

Rabbit mq-等待Mnesia表时出错

  •  29
  • jeril  · 技术社区  · 5 年前

    我已经在kubernetes集群上使用helm-chart安装了rabbitmq。Rabbitmqpod不断重启。在检查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 [email protected] ...
    Status of node [email protected] ...
    Error:
    {:aborted, {:no_exists, [:rabbit_vhost, [{{:vhost, :"$1", :_, :_}, [], [:"$1"]}]]}}
    Error:
    {:aborted, {:no_exists, [:rabbit_vhost, [{{:vhost, :"$1", :_, :_}, [], [:"$1"]}]]}}
    

    我已经在kubernetes集群上的Google Cloud上配置了上述内容。我不确定它是在什么具体情况下开始失败的。我不得不重新启动吊舱,从那以后它一直在失败。

    这里的问题是什么?

    7 回复  |  直到 5 年前
        1
  •  49
  •   Ulli    4 年前

    太长,读不下去了

    helm upgrade rabbitmq --set clustering.forceBoot=true

    问题

    出现问题的原因如下:

    • 由于某种原因(可能是因为您将StatefulSet副本显式设置为0或其他原因),所有RMQ Pod都会同时终止
    • 其中一个是最后一个停下来的(可能只是在其他人之后一点点)。它将此条件(“我现在是独立的”)存储在其文件系统中,在k8s中,该文件系统是PersistentVolume(Claim)。假设这个吊舱是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 StatefulSet说:“一次启动一切是不可能的,我们将从0开始”。

    解决方案

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

    但看看这个问题,你也可以看到为什么删除PVC会奏效( other answer ). Pod都会“忘记”上次它们是RMQ集群的一部分,并愉快地开始。不过,我更喜欢上述解决方案,因为没有数据丢失。

        2
  •  17
  •   Michael Klishin    1 年前

    RabbitMQ核心团队成员在这里。默认情况下,从未打算使用强制启动节点。 命令存在 只有 当许多集群成员永久丢失,因此永远不会回来时,使节点启动。

    使用 force_boot 是一种巧妙的变通方法,掩盖了根本问题或一组问题,可能很危险(见下文)。

    在Kubernetes上,有一种常见的情况,即不幸选择的就绪状态探测会导致集群重启死锁。以下是相关的文档部分:

    以下是一个简化的简短版本:

    • 在3.x版本中,RabbitMQ节点期望其对等节点在继续启动前5分钟内上线
    • 在当前节点通过就绪探测之前,有状态集控制器不会继续启动任何其他节点
    • 许多探测器实际上需要一个形成的集群,一个节点是不够的(除非只有一个节点)
    • 因此,部署过程陷入僵局

    使用基本就绪探测(请参阅上面的文档链接),所有节点必须在(默认情况下)5分钟内全部启动,必要时可以延长这一时间。但默认情况下强制节点启动是错误的,在99%的情况下应该是不必要的。

    结合其他部署时间事件,强制启动可能会导致一些相同的结果 described in this recommended against deployment strategy .

    结合 podManagementPolicy: parallel 文档中提到的简单的“单节点”就绪性探测将是一个更安全的解决方案,它不会滥用在集群的一部分永久丢失的特殊情况下作为最后手段而创建的功能。 播客管理策略:并行 什么 RabbitMQ cluster Operator 使用,因此RabbitMQ核心团队实践我们所宣扬的。

        3
  •  15
  •   jeril    5 年前

    刚刚删除了现有的持久卷声明并重新安装了rabbitmq,它就开始工作了。

    因此,每次在kubernetes集群上安装rabbitmq后,如果我将Pod缩小到0,并且稍后扩大Pod时,我都会遇到同样的错误。我还尝试在不卸载rabbitmq-helm图表的情况下删除持久卷声明,但仍然出现了同样的错误。

    因此,似乎每次我将集群缩小到0时,我都需要卸载rabbitmq-helm图表,删除相应的持久卷声明,并每次安装rabbitmq-shelm图表以使其正常工作。

        4
  •  2
  •   vidbaz    3 年前

    如果你和我一样,不知道是谁部署了舵图,也不知道它是如何部署的。。。你可以直接编辑statefulset,以避免弄乱更多的东西。。

    我能够在不删除helm_chart的情况下使其工作

    kubectl -n rabbitmq edit statefulsets.apps rabbitmq

    在规范部分,我添加了如下env变量RABBITMQ_FORCE_BOOT=yes:

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

    这也应该解决这个问题。。。请先按照Ulli的解释,以正确的方式进行。

        5
  •  1
  •   Ali Ahmad    3 年前

    在我看来,解决方案很简单

    步骤1:缩小状态集,它不会删除PVC。

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

    步骤2:访问RabbitMQ Pod。

    kubectl exec -it rabbitmq-1-rabbitmq-0 -n Rabbit
    

    步骤3:重置集群

    rabbitmqctl stop_app
    rabbitmqctl force_boot
    

    步骤4:重新缩放状态集

      kubectl scale statefulsets rabbitmq-1-rabbitmq --namespace teps-rabbitmq --replicas=4
    
        6
  •  0
  •   Muhammad Dyas Yaskur    5 年前

    我也遇到了类似的错误,如下所示。

    2020-06-05 03:45:37.153[信息]<0.234.0>等待Mnesia桌子 30000毫秒,还剩9次重试2020-06-05 03:46:07.154[警告]<0.234.0> 等待Mnesia表时出错: {timeout_waiting_for_tables,[rabbit_user,rabbit_user_permission,rabbit_topic_permissions,rabbit_vhost,rabbitdurable_route,rabbit durable_exchange,rabbitruntime_parameters,rabbitDurable_queue] 2020-06-05 03:46:07.154[信息]<0.234.0>等待Mnesia桌子 30000毫秒,还剩8次重试

    在我的例子中,RabbitMQ集群的从属节点(服务器)已经关闭。一旦我启动了从节点,主节点就启动了,没有出现任何错误。

        7
  •  -7
  •   Amir Soleimani Borujerdi    5 年前

    测试此部署:

    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