← Назад к вопросам

Что такое ZooKeeper?

3.0 Senior🔥 121 комментариев
#Docker, Kubernetes и DevOps

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

ZooKeeper

Apache ZooKeeper - это централизованный сервис управления конфигурацией, координацией и синхронизацией в распределённых системах. Это инструмент, который помогает решить проблемы согласованности, отказоустойчивости и координации в масштабируемых приложениях.

Основное назначение

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

Ключевые концепции

Znodes - это элементы иерархии ZooKeeper, похожие на файлы и папки. Каждый znode может содержать данные и иметь дочерние элементы.

Watch - это механизм оповещений. Если вы подписаны на znode, вы получите уведомление, когда его данные изменятся.

Последовательность и атомарность - операции в ZooKeeper либо полностью выполняются, либо нет. Это гарантирует консистентность.

Session - соединение между клиентом и ZooKeeper сервером. Если соединение разрывается, все временные znodes удаляются.

Практические примеры использования ZooKeeper в Java

1. Избрание лидера (Leader Election)

Общая проблема в распределённых системах: нужно, чтобы один сервер был "главным". ZooKeeper решает это:

import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs;

public class LeaderElection {
    private ZooKeeper zk;
    private static final String ELECTION_PATH = "/election";
    private String myNodePath;

    public LeaderElection(String connectString) throws Exception {
        zk = new ZooKeeper(connectString, 3000, event -> {});
    }

    public boolean becomeLeader() throws Exception {
        // Создаём временный последовательный node
        myNodePath = zk.create(
            ELECTION_PATH + "/candidate_",
            "hostname".getBytes(),
            ZooDefs.Ids.OPEN_ACL_UNSAFE,
            CreateMode.EPHEMERAL_SEQUENTIAL
        );

        // Получаем всех кандидатов
        List<String> candidates = zk.getChildren(ELECTION_PATH, false);
        Collections.sort(candidates);

        // Если мой node - первый, я лидер
        String myNode = myNodePath.substring(ELECTION_PATH.length() + 1);
        return candidates.get(0).equals(myNode);
    }
}

2. Синхронизированное переключение конфигурации

Используется для управления конфигурацией во всем кластере:

import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher;

public class ConfigurationManager {
    private ZooKeeper zk;
    private volatile String currentConfig;
    private static final String CONFIG_PATH = "/config/app-settings";

    public ConfigurationManager(String connectString) throws Exception {
        zk = new ZooKeeper(connectString, 3000, event -> {
            if (event.getType() == Watcher.Event.EventType.NodeDataChanged) {
                updateConfiguration();
            }
        });
        
        // Загружаем конфигурацию и подписываемся на изменения
        updateConfiguration();
    }

    private void updateConfiguration() {
        try {
            byte[] data = zk.getData(CONFIG_PATH, event -> updateConfiguration(), null);
            currentConfig = new String(data);
            System.out.println("Configuration updated: " + currentConfig);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public String getConfig() {
        return currentConfig;
    }
}

3. Distributed Lock (Распределённая блокировка)

Захват ресурса несколькими сервисами одновременно:

import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.ZooDefs;

public class DistributedLock {
    private ZooKeeper zk;
    private String lockPath;
    private static final String LOCKS_PATH = "/locks";

    public DistributedLock(String connectString, String resourceName) throws Exception {
        zk = new ZooKeeper(connectString, 3000, event -> {});
        this.lockPath = LOCKS_PATH + "/" + resourceName;
    }

    public void acquireLock() throws Exception {
        // Создаём временный node как индикатор захвата
        String myNode = zk.create(
            lockPath + "/lock_",
            Thread.currentThread().getName().getBytes(),
            ZooDefs.Ids.OPEN_ACL_UNSAFE,
            CreateMode.EPHEMERAL_SEQUENTIAL
        );

        while (true) {
            List<String> locks = zk.getChildren(lockPath, false);
            Collections.sort(locks);

            String myLock = myNode.substring((lockPath + "/").length());
            
            if (locks.get(0).equals(myLock)) {
                // Я получил блокировку
                System.out.println("Lock acquired by " + Thread.currentThread().getName());
                return;
            } else {
                // Жду, пока удалится предыдущий node
                String previousLock = locks.get(locks.indexOf(myLock) - 1);
                zk.exists(lockPath + "/" + previousLock, event -> {});
                // Ждём оповещения об удалении
                Thread.sleep(100);
            }
        }
    }

    public void releaseLock(String myNode) throws Exception {
        zk.delete(myNode, -1);
    }
}

Архитектура ZooKeeper

ZooKeeper работает как кластер серверов (рекомендуется нечётное количество, например 3, 5, 7). Один сервер - это лидер, остальные - последователи.

Гарантии консистентности:

  • Линеаризуемость записей - все клиенты видят одну последовательность операций
  • FIFO порядок клиента - операции одного клиента выполняются в порядке отправки
  • Долговечность - данные сохраняются на диск перед подтверждением

Где используется ZooKeeper

  1. Kafka - управление координацией partitions и consumer groups
  2. HBase - управление master election и cluster state
  3. Hadoop YARN - координация ресурсов
  4. Elasticsearch - управление состоянием кластера (в старых версиях)
  5. Микросервисная архитектура - service discovery, конфигурационные сервисы

Когда использовать ZooKeeper

Используй ZooKeeper, если нужно:

  • Избрать лидера в кластере
  • Управлять динамической конфигурацией
  • Синхронизировать состояние между сервисами
  • Реализовать распределённые блокировки
  • Хранить малые объёмы критичных для системы данных

Не используй ZooKeeper, если:

  • Нужно хранить большие объёмы данных (это база данных, не хранилище)
  • Приложение очень простое и не требует распределённой координации
  • Есть альтернативы проще (например, Consul или etcd)

Альтернативы

  • etcd - более новый, использует Raft consensus
  • Consul - от HashiCorp, с встроенным service discovery
  • Redis - для простых случаев с lock и pub/sub

ZooKeeper - это мощный инструмент, но требует понимания распределённых систем и может быть сложен в эксплуатации. В современных проектах часто выбирают более простые альтернативы.

Что такое ZooKeeper? | PrepBro