Настройка CDC-репликации

В этом руководстве показано, как развернуть два автономных кластера Milvus с помощью Milvus Operator и настроить CDC-репликацию с исходного кластера на целевой.

В примерах используется:

  • source-cluster в качестве основного кластера.
  • target-cluster в качестве резервного кластера.
  • milvus в качестве пространства имен для кластеров Milvus.
  • milvus-operator в качестве пространства имен для Milvus Operator.

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

Необходимые условия

  • Milvus v2.6.16 или более поздняя версия.
  • Milvus Operator v1.3.4 или более поздняя версия.
  • Доступен кластер Kubernetes.
  • Исходный и целевой кластеры могут подключаться друг к другу по сети.
  • У вас есть учетные данные администратора для обоих кластеров Milvus.
  • Вы знаете количество физических каналов для каждого кластера.

Шаг 1: Обновление Milvus Operator

Добавьте репозиторий Milvus Operator Helm:

helm repo add zilliztech-milvus-operator https://zilliztech.github.io/milvus-operator/

Обновите репозиторий:

helm repo update zilliztech-milvus-operator

Установите или обновите Milvus Operator:

helm -n milvus-operator upgrade --install milvus-operator \
  zilliztech-milvus-operator/milvus-operator \
  --create-namespace

Убедитесь, что операторская капсула запущена:

kubectl get pods -n milvus-operator

Пример вывода:

NAME                               READY   STATUS    RESTARTS   AGE
milvus-operator-6f7d8c9c7d-xm4tj   1/1     Running   0          54s

Шаг 2: Развертывание исходного кластера

Создайте файл с именем milvus_source_cluster.yaml:

apiVersion: milvus.io/v1beta1
kind: Milvus
metadata:
  name: source-cluster
  namespace: milvus
  labels:
    app: milvus
spec:
  mode: standalone
  components:
    image: milvusdb/milvus:v2.6.16
    cdc:
      replicas: 1
  dependencies:
    msgStreamType: woodpecker

Примените конфигурацию:

kubectl create namespace milvus
kubectl apply -f milvus_source_cluster.yaml

Проверьте, что стручки исходного кластера запущены:

kubectl get pods -n milvus

Пример вывода:

NAME                                                   READY   STATUS    RESTARTS   AGE
source-cluster-etcd-0                                  1/1     Running   0          3m
source-cluster-minio-6d8f7d9b9f-9t7j2                  1/1     Running   0          3m
source-cluster-milvus-standalone-7f8d9c8f6d-r2m5x      1/1     Running   0          2m
source-cluster-milvus-cdc-66d64747bd-sckxj             1/1     Running   0          2m

Убедитесь, что стручок CDC, например source-cluster-milvus-cdc-..., находится в состоянии Running.

Шаг 3: Развертывание целевого кластера

Создайте файл с именем milvus_target_cluster.yaml:

apiVersion: milvus.io/v1beta1
kind: Milvus
metadata:
  name: target-cluster
  namespace: milvus
  labels:
    app: milvus
spec:
  mode: standalone
  components:
    image: milvusdb/milvus:v2.6.16
    cdc:
      replicas: 1
  dependencies:
    msgStreamType: woodpecker

Компонент CDC включен и на целевом кластере. Он бездействует, пока целевой кластер является резервным, но он необходим, если целевой кластер впоследствии станет основным после переключения.

Примените конфигурацию:

kubectl apply -f milvus_target_cluster.yaml

Убедитесь, что капсулы целевого кластера запущены:

kubectl get pods -n milvus | grep -E 'NAME|target-cluster'

Пример вывода:

NAME                                                   READY   STATUS    RESTARTS   AGE
target-cluster-etcd-0                                  1/1     Running   0          3m
target-cluster-minio-5f7c8d9b6f-k8s2q                  1/1     Running   0          3m
target-cluster-milvus-standalone-66dc8d9f7f-5n6bp      1/1     Running   0          2m
target-cluster-milvus-cdc-7f8c9d6b8c-q4t9m             1/1     Running   0          2m

Шаг 4: Подготовка информации о кластере

Получите адреса служб Milvus для обоих кластеров:

kubectl get svc -n milvus | grep -E 'NAME|source-cluster|target-cluster'

Пример вывода:

NAME                                  TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)              AGE
source-cluster-milvus                 ClusterIP   10.98.124.90     <none>        19530/TCP,9091/TCP   8m
target-cluster-milvus                 ClusterIP   10.109.234.172   <none>        19530/TCP,9091/TCP   3m

Подготовьте два типа адресов:

  • Адреса кластеров записываются в конфигурацию репликации и используются компонентами CDC. Эти адреса должны быть достижимы из стручков CDC.
  • Адреса клиентов используются только вашим Python-клиентом при вызове Milvus API. Если вы запускаете Python-клиент вне кластера Kubernetes, откройте сервисы Milvus через обычный метод доступа, например, через балансировщик нагрузки, ингресс или порт-форвард.

Подготовьте информацию о подключении и списки pchannel для обоих кластеров:

source_cluster_addr = "http://source-cluster-milvus.milvus.svc.cluster.local:19530"
target_cluster_addr = "http://target-cluster-milvus.milvus.svc.cluster.local:19530"

source_client_addr = source_cluster_addr
target_client_addr = target_cluster_addr

# If your Python client runs outside the Kubernetes cluster, replace only
# source_client_addr and target_client_addr with externally reachable addresses.
# Keep source_cluster_addr and target_cluster_addr reachable from CDC pods.
# For example:
# source_client_addr = "http://127.0.0.1:19530"
# target_client_addr = "http://127.0.0.1:19531"

source_cluster_token = "root:Milvus"
target_cluster_token = "root:Milvus"

source_cluster_id = "source-cluster"
target_cluster_id = "target-cluster"

pchannel_num = 16
source_cluster_pchannels = [
    f"{source_cluster_id}-rootcoord-dml_{i}"
    for i in range(pchannel_num)
]
target_cluster_pchannels = [
    f"{target_cluster_id}-rootcoord-dml_{i}"
    for i in range(pchannel_num)
]

Замените адреса на реальные адреса служб Milvus в вашей среде. Не устанавливайте source_cluster_addr или target_cluster_addr на локальный адрес переадресации, если только стручки CDC не могут также обращаться к этому адресу. Список pchannel должен соответствовать вашему развертыванию Milvus. Не копируйте значения из примера, не проверив конфигурацию своего кластера.

Шаг 5: Создание конфигурации репликации

Создайте конфигурацию репликации с source-cluster на target-cluster:

replicate_config = {
    "clusters": [
        {
            "cluster_id": source_cluster_id,
            "connection_param": {
                "uri": source_cluster_addr,
                "token": source_cluster_token,
            },
            "pchannels": source_cluster_pchannels,
        },
        {
            "cluster_id": target_cluster_id,
            "connection_param": {
                "uri": target_cluster_addr,
                "token": target_cluster_token,
            },
            "pchannels": target_cluster_pchannels,
        },
    ],
    "cross_cluster_topology": [
        {
            "source_cluster_id": source_cluster_id,
            "target_cluster_id": target_cluster_id,
        }
    ],
}

Шаг 6: Примените конфигурацию репликации

Примените одну и ту же конфигурацию к обоим кластерам:

from pymilvus import MilvusClient

source_client = MilvusClient(
    uri=source_client_addr,
    token=source_cluster_token,
)
target_client = MilvusClient(
    uri=target_client_addr,
    token=target_cluster_token,
)

try:
    source_client.update_replicate_configuration(**replicate_config)
    target_client.update_replicate_configuration(**replicate_config)
finally:
    source_client.close()
    target_client.close()

Для автоматизации производства используйте отдельные короткоживущие клиенты для этой операции в плоскости управления. Это позволит избежать совместного использования одного и того же канала gRPC с трафиком DML приложений во время смены роли кластера.

После применения конфигурации изменения, записанные на source-cluster, реплицируются на target-cluster.

Шаг 7: Проверка репликации данных

Чтобы проверить, что репликация работает:

  1. Подключитесь к source-cluster.
  2. Создайте коллекцию.
  3. Вставьте данные в коллекцию.
  4. Загрузите коллекцию и выполните запрос или поиск на source-cluster.
  5. Подключитесь к target-cluster.
  6. Запустите тот же запрос или поиск на target-cluster без ручной загрузки коллекции на резервном кластере.
  7. Убедитесь, что ожидаемые данные видны на обоих кластерах.

В этой топологии целевой кластер является резервным. Не выполняйте ручные операции DDL или DCL, такие как load_collection, на резервном кластере. Эти операции должны выполняться на исходном кластере и реплицироваться на целевой кластер.

Точный код проверки зависит от схемы коллекции. Базовый рабочий процесс создания коллекции Milvus см. в документации по быстрому запуску Milvus.

Задержка CDC

Задержка CDC - это окно данных между основным и резервным кластерами. Его необходимо постоянно контролировать после настройки репликации.

Задержка CDC может увеличиться, если:

  • Высокая скорость записи в основной кластер.
  • Между кластерами увеличивается сетевая задержка или потеря пакетов.
  • Резервный кластер перегружен.
  • Узлы CDC недостаточно обеспечены ресурсами.
  • Выполняются большие операции DDL или импорта.

Используйте задержку CDC для принятия оперативных решений:

  • Если задержка низкая, переключение должно происходить быстрее.
  • Если задержка велика, при обходе отказа может быть потеряно больше данных.

Оценить задержку CDC можно с помощью следующего запроса PromQL:

clamp_min(
  max by (channel_name) (
    milvus_wal_last_confirmed_time_tick
  )
  -
  min by (channel_name) (
    milvus_cdc_last_replicated_time_tick
  ),
  0
)

Результат выражается в секундах. Для каждого канала источника запрос сравнивает последний подтвержденный временной интервал WAL с последним временным интервалом, реплицированным CDC. Если основной канал реплицируется на несколько резервных кластеров, выражение min by (channel_name) сообщает о самом медленном прогрессе репликации для этого канала.

Если Prometheus обследует несколько кластеров Milvus, добавьте фильтры меток, соответствующие вашему развертыванию, например namespace или app_kubernetes_io_instance, чтобы избежать смешивания метрик из разных кластеров.

ЧАСТО ЗАДАВАЕМЫЕ ВОПРОСЫ

Нужно ли вызывать update_replicate_configuration на обоих кластерах?

Да. Примените одинаковую топологию ко всем участвующим кластерам. Если один из кластеров не является основным на момент вызова, он подождет, пока топология не будет применена через CDC.

Как выбрать cluster_id?

Используйте стабильный, уникальный идентификатор для каждого кластера. Идентификатор также используется в именах pchannel и ссылках на топологию репликации.

Можно ли изменить pchannels после настройки репликации?

Вы можете обновлять топологию, но список pchannel должен соответствовать схеме кластера. Относитесь к изменению pchannel как к продвинутой операции и тщательно проверяйте репликацию после этого.