Записи в устройства ceph rbd, отображенные на нескольких узлах, не распространяются до размонтирования.

Вопрос или проблема

Я управляю средой OpenShift, поддерживаемой службой Ceph, предоставляющей блочные устройства RBD. Когда одно и то же тома подключается к нескольким узлам (например, при использовании режима блочного тома), я наблюдаю неожидаемое поведение: изменения, внесенные в одну из томов, не отражаются на других узлах, которые также подключают то же самое RBD-тома.

Примечание: Чтобы избежать путаницы, так как много людей задают другие вопросы, я не пытаюсь монтировать файловую систему с этих устройств. Я взаимодействую напрямую с блочным устройством.

Например, рассмотрим PersistentVolumeClaim, как этот:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: blockvol
spec:
  accessModes:
  - ReadWriteMany
  volumeMode: Block
  resources:
    requests:
      storage: 1Gi

Это томо подключено как блочное устройство к нескольким подам с помощью следующего развертывания:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: bvexample
spec:
  replicas: 2
  template:
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - blockvol
            topologyKey: kubernetes.io/hostname
      containers:
      - name: blockvol
        image: docker.io/python:3.12
        env:
        - name: NODE
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        resources:
          requests:
            cpu: 100m
            memory: 512Mi
          limits:
            cpu: 100m
            memory: 1Gi
        volumeDevices:
        - devicePath: /dev/blockvol
          name: blockvol
        command:
        - sleep
        - inf
      volumes:
        - name: blockvol
          persistentVolumeClaim:
            claimName: blockvol

Когда все запущено и работает, мы видим, что поды работают на двух разных узлах в кластере:

$ kubectl get pod -l app=blockvol -o wide
NAME                         READY   STATUS    RESTARTS   AGE     IP              NODE     NOMINATED NODE   READINESS GATES
bvexample-6f64cffc5f-5f5jc   1/1     Running   0          6m27s   10.128.17.189   wrk-29   <none>           <none>
bvexample-6f64cffc5f-k8bjr   1/1     Running   0          6m27s   10.131.17.137   wrk-35   <none>           <none>

Устройство доступно как /dev/blockvol внутри подов:

$ kubectl get pod -l app=blockvol -o name |
  xargs -IPOD sh -c 'echo === POD ===; kubectl exec POD -- ls -l /dev/blockvol'
=== pod/bvexample-6f64cffc5f-5f5jc ===
brw-rw-rw-. 1 root disk 252, 16 Sep 25 01:09 /dev/blockvol
=== pod/bvexample-6f64cffc5f-k8bjr ===
brw-rw-rw-. 1 root disk 252, 16 Sep 25 01:09 /dev/blockvol

Изначально устройство содержит только нули:

1000820000@bvexample-6f64cffc5f-k8bjr:/$ od -N16 -xa /dev/blockvol
0000000    0000    0000    0000    0000    0000    0000    0000    0000
        nul nul nul nul nul nul nul nul nul nul nul nul nul nul nul nul
0000020

Если я запишу данные на это устройство, я ожидаю, что эти изменения будут видны немедленно на других узлах. Однако, если в одном поде я выполню:

1000820000@bvexample-6f64cffc5f-k8bjr:/$ echo this is a test. > /dev/blockvol
1000820000@bvexample-6f64cffc5f-k8bjr:/$ od -N16 -xa /dev/blockvol
0000000    6874    7369    6920    2073    2061    6574    7473    0a2e
          t   h   i   s  sp   i   s  sp   a  sp   t   e   s   t   .  nl
0000020

Другой под — на другом узле — продолжает видеть исходные данные:

1000820000@bvexample-6f64cffc5f-5f5jc:/$ od -N16 -xa /dev/blockvol
0000000    0000    0000    0000    0000    0000    0000    0000    0000
        nul nul nul nul nul nul nul nul nul nul nul nul nul nul nul nul
0000020

Если я убью поды, заставив их переназначиться на новые узлы:

$ kubectl delete pod -l app=blockvol

Тогда изменения будут видны на блочном устройстве в обоих местах:

=== pod/bvexample-6f64cffc5f-bkb5q ===
0000000    6874    7369    6920    2073    2061    6574    7473    0a2e
          t   h   i   s  sp   i   s  sp   a  sp   t   e   s   t   .  nl
0000020
=== pod/bvexample-6f64cffc5f-vv595 ===
0000000    6874    7369    6920    2073    2061    6574    7473    0a2e
          t   h   i   s  sp   i   s  sp   a  sp   t   e   s   t   .  nl
0000020

Похоже, что драйвер RBD кэширует изменения локально, пока устройство RBD не будет отсоединено от узла, в этот момент изменения действительно записываются на диск. Это… регулярное поведение для устройств RBD? Какой-то параметр конфигурации? Это было неожиданно и означает, что режим ReadWriteMany фактически является ложью (да, вы можете записать в него, но вы не сможете фактически прочитать эти данные нигде).

Ответ или решение

Ваш вопрос касается поведения RBD-устройств в Ceph, когда они смонтированы на нескольких узлах, что может вызывать недоразумения в плане видимости данных между ними. Давайте рассмотрим вашу ситуацию подробнее и постараемся воссоздать полное понимание проблемы.

Проблема

Вы используете RBD (RADOS Block Device) в рамках OpenShift кластера, и при работе с блочными устройствами (volumeMode: Block) изменения, которые вы вносите в блок устройства в одном из подов, не отображаются в другом поде, запущенном на другом узле, пока блок-устройство не будет размонтировано. Выходит, что данные "кэша" на одном узле не синхронизируются с другим узлом до тех пор, пока одно из устройств не будет отключено.

Описание поведения RBD

К сожалению, такое поведение действительно может иметь место, когда вы напрямую взаимодействуете с блочными устройствами, и это связано с особенностями работы RBD и кэширования в драйверах. RBD не предназначен для одновременной записи из нескольких источников, поскольку он не реализует механизмы блокировки или синхронизации данных на уровне блочного устройства. Поэтому, когда вы записываете данные на одно устройство, другие узлы не видят изменения, пока устройство не будет размонтировано.

Рекомендации по решению проблемы

  1. Подумайте о механизмах синхронизации: Если вам нужна функциональность, в которой данные должны быть видимыми для всех узлов немедленно, вам, возможно, стоит рассмотреть использование системы управления данными, такой как файловая система, обеспечивающая консистентность, например, CephFS (Ceph File System) вместо RBD-устройств. CephFS поддерживает распределенные файловые системы и может справляться с многими конкурентными запросами.

  2. Рассматривайте архитектуру приложения: Возможно, есть смысл изменить способ работы приложений, чтобы избежать одновременного доступа к блочным устройствам из различных подов. Предусмотрите механизм очередей или другие методы, которые позволят отложить операции записи и избежать конфликтов.

  3. Проверьте настройки Ceph и RBD: Вы можете изучить настройки RBD, такие как rbd_cache, которые отвечают за кэширование. Хотя кэширование на уровне блока может повысить производительность, оно может также привести к проблемам с согласованностью, как вы уже заметили. Может быть, изменение параметров кэширования поможет.

  4. Изучите уровни производительности и доступности Ceph: Если вам необходимо высокое согласование данных при многопользовательском доступе, возможно, вам стоит переосмыслить, действительно ли RBD является вашим наилучшим вариантом или стоит обратить внимание на другие решения.

Заключение

Таким образом, поведение, которое вы наблюдаете, связано с механизмом кэширования в RBD и тем, как блочные устройства работают с записью данных и отзывом их обратно в хранилище. Рекомендуется рассмотреть использование альтернативных подходов для управления данными или же адаптировать логику вашего приложения, чтобы минимизировать проблемы с согласованностью данных.

Оцените материал
Добавить комментарий

Капча загружается...