You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

38 KiB

Введение

Крупномасштабным распределённым приложениям требуются различные формы синхронизации для достижения консенсуса о базовой информации окружения. Выделение примитивов синхронизации в API позволяет выделить ядро координации из логики приложения в отдельный сервис. Являясь частью критической инфраструктуры, к такому сервису предъявляются в первую очередь требования надёжности и доступности. Подобный дизайн делает разработку и поддержку распределённого приложения проще.

ZooKeeper является проектом с открытым исходным кодом, который предоставляет отказоустойчивый распределённый сервис хранения критичных для работы кластера данных. Хранимыми данными могут быть: конфигурационная информация, иерархическое пространство имён, url ссылки, идентификаторы задач и прочее. ZooKeeper, созданный для внутренних нужд компании Yahoo!”, в настоящее время стал использоваться такими открытыми технологиями, как: Apache HBase, HDFS, Apache Storm, Apache Kafka и др.

Сайт проекта http://zookeeper.apache.org/.
Статья: Hunt P. et al. ZooKeeper: Wait-free Coordination for Internet-scale Systems //USENIX annual technical conference. 2010. Т. 8. №. 9.

Цель работы

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

Данная лабораторная может выполняться на виртуальной машине создаваемой по Vagrant конфигурации в приложении А или с ZooKeeper, установленным в Windows.

Изучение ZooKeeper

Установка

Данный шаг может быть пропущен, если вы будете работать с Vagrant.

Перейдите на страницу Download на официальном сайте https://zookeeper.apache.org/ и скачайте последнюю стабильную версию (на момент написания 3.4.14).

Архив содержит скрипты как для Windows, так и для Unix операционных систем. Необходимым условием для работы Zookeeper является наличие в системе Java Runtime Environment.

Распакуйте архив в директорию С:\Temp в Windows. Если вы используете Unix систему, распакуйте и переместите содержимое архива в /opt. Набор команд, устанавливающих ZooKeeper в CentOS 7, вы можете найти в Vagrantfile из приложения А.

Перед первым запуском переименуйте файл zoo_sample.cfg в директории conf в zoo.cfg. Файл zoo.cfg, который на данный момент содержит базовые настройки, используется для конфигурации сервера.

Примечание. В Windows системе в Панель управления\Система и безопасность\Система -> Дополнительные параметры системы -> Переменные среды можно установить JAVA_HOME, если она не была сконфигурирована вами или администратором после установки Java в систему.

Запуск

Windows

В Windows запустите сервер двойным кликом по скрипту zkServer.cmd в папке ./bin/ или из терминала, набрав:

zkServer.cmd 

Linux

zkServer.sh 

Проверьте, что zookeeper работает

systemctl status zookeeper

Изучение директории установки ZooKeeper

Перейдите в директорию установки ZooKeeper.

Изучите содержимое директории.

В директории находятся следующие папки:

  • bin с исполняемыми файлами для запуска, остановки и взаимодействия с ZooKeeper,
  • conf с конфигурационными файлами,
  • contrib с инструментами для интеграции ZooKeeper в другие системы: rest, fuse, perl и python библиотеки,
  • dist-maven артефакты Maven,
  • docs в которой хранится документация,
  • recipes различные рецепты, помогающие решать задачи с использованием ZooKeeper (выбор лидера, блокировки, очереди),
  • src с исходным кодом и тестовыми скриптами.

Взаимодействие с ZooKeeper через командный интерфейс CLI

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

Прежде всего нам понадобится перейти в папку bin директории установки ZooKeeper.

Для запуска интерактивной сессии ZooKeeper CLI используйте скрипт zkCli с расширением в зависимости от той среды, в который вы его запускаете (sh - unix, cmd - windows).

Следующая команда устанавливает подключение к ZooKeeper CLI сессии:

./zkCli.sh -server 127.0.0.1:2181

Примечание. При запуске zkCli.sh без параметров по умолчанию подключение производится к localhost:2181, поэтому явно указанные выше параметры вы можете опустить.

Подключение установлено. Для вывода всех возможных команд наберите help.

[zk: localhost:2181(CONNECTED) 0] help
ZooKeeper -server host:port -client-configuration properties-file cmd args
        addWatch [-m mode] path # optional mode is one of [PERSISTENT, PERSISTENT_RECURSIVE] - default is PERSISTENT_RECURSIVE
        addauth scheme auth
        close
        config [-c] [-w] [-s]
        connect host:port
        create [-s] [-e] [-c] [-t ttl] path [data] [acl]
        delete [-v version] path
        deleteall path [-b batch size]
        delquota [-n|-b|-N|-B] path
        get [-s] [-w] path
        getAcl [-s] path
        getAllChildrenNumber path
        getEphemerals path
        history
        listquota path
        ls [-s] [-w] [-R] path
        printwatches on|off
        quit
        reconfig [-s] [-v version] [[-file path] | [-members serverID=host:port1:port2;port3[,...]*]] | [-add serverId=host:port1:port2;port3[,...]]* [-remove serverId[,...]*]
        redo cmdno
        removewatches path [-c|-d|-a] [-l]
        set [-s] [-v version] path data
        setAcl [-s] [-v version] [-R] path acl
        setquota -n|-b|-N|-B val path
        stat [-w] path
        sync path
        version
        whoami

Выйти из консоли вы можете с помощью команды quit или отправив EOF символ сочетанием Ctrl+D.

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

Находясь в консоли CLI введите команду ls /.

[zk: localhost:2181(CONNECTED) 2] ls /
[zookeeper]

В результе вы должны получить список узлов в корне иерархической структуры данных ZooKeeper. В данном случае выводится один узел. Аналогично вы можете изучать некорневые узлы. Выведите список дочерних узлов /zookeeper.

Примечание. Используйте автоматическое дополнение при наборе, срабатываемое по нажатию клавиши TAB.

Теперь в корне создайте свой узел /mynode с данными "first_version" следующей командой:

create /mynode 'first_version'

Проверьте, что в корне появился новый узел.

[zk: localhost:2181(CONNECTED) 4] ls /
[mynode, zookeeper]

Следующие команды возвращают данные и метаданные узла:

get /mynode
stat /mynode
[zk: localhost:2181(CONNECTED) 10] get /mynode
first_version

[zk: localhost:2181(CONNECTED) 13] stat /mynode
cZxid = 0x2
ctime = Wed Sep 01 10:51:29 SAMT 2021
mZxid = 0x2
mtime = Wed Sep 01 10:51:29 SAMT 2021
pZxid = 0x2
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 13
numChildren = 0

Изучим структуру, хранимую в узле

Поле Описание
'first_version' Хранимые данные
cZxid Номер транзакции создания узла в системе
ctime Время создания узла
mZxid Номер транзакции модификации узла
mtime Время модификации узла
pZxid Номер транзакции модификации дочерних узлов
cversion Количество изменений дочерних узлов
dataVersion Количество изменений данных узла
aclVersion Количество изменений прав доступа к данному узлу
ephemeralOwner Идентификатор сессии владельца узла, если узел эфимерный. Иначе значение равно нулю.
dataLength Размер данных
numChildren Количество дочерних узлов

Измените данные узла на "second_version":

set /mynode 'second_version'
[zk: localhost:2181(CONNECTED) 15] get /mynode
second_version

[zk: localhost:2181(CONNECTED) 16] stat /mynode
cZxid = 0x2
ctime = Wed Sep 01 10:51:29 SAMT 2021
mZxid = 0x3
mtime = Wed Sep 01 10:56:11 SAMT 2021
pZxid = 0x2
cversion = 0
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 14
numChildren = 0

В качестве результата мы получим обновлённые метаданные узла. Обратите внимание на те значения, которые изменились.

Изменилась дата модификации mtime и значение поля dataVersion стало больше на единицу, так как мы провели одно изменение. Также изменился размер данных.

Теперь создайте два нумерованных (sequential) узла в качестве дочерних mynode:

create -s /mynode/child 'im_sequential'
create -s /mynode/child 'me_too'
[zk: localhost:2181(CONNECTED) 17] create -s /mynode/child 'im_sequential'
Created /mynode/child0000000000
[zk: localhost:2181(CONNECTED) 18] create -s /mynode/child 'me_too'
Created /mynode/child0000000001

Передав дополнительно флаг -s, мы указали, что создаваемый узел нумерованный. Этот способ позволяет создавать узлы с уникальными именами, по которым можно узнать порядок поступления запросов на сервер.

Пример. Принадлежность клиентов к группе

Несмотря на то, что ZooKeeper используется, как правило, из программного кода, мы можем эмулировать простой сценарий мониторинга принадлежности клиентов к группе в CLI.

В данном примере в корне zookeeper файловой системы будет создан узел под именем mygroup. Затем несколько сессий CLI будут эмулировать клиентов, добавляющих себя в эту группу. Клиент будет добавлять эфимерный узел в mygroup иерархию. При закрытии сессии узел автоматически будет удаляться.

Примечание. При использовании Vagrant управляемой виртуальной машины из VisualCode создайте несколько терминалов и установите ssh соединение в каждом командой vagrant ssh.

Этот сценарий может применяться для реализации сервиса разрешения имён (DNS) узлов кластера. Каждый узел регистрирует себя под своим именем и сохраняет свой url или ip адрес. Узлы, которые временно недоступны или аварийно завершили работу, в списке отсутствуют. Таким образом директория хранит актуальный список работающих узлов с их адресами.

Внутри CLI сессии, создайте узел mygroup.

create /mygroup 'top_node'

Откройте две новых CLI консоли и в каждой создайте по дочернему узлу в mygroup:

Примечание. Удобный способ открыть CLI консоль в windows Shift + Правая кнопка мыши -> Открыть окно PowerShell здесь в директории zookeeper, затем выполнить bin/zkCli.cmd.

Консоль 1 - grue.

create -e /mygroup/grue 'iam_grue'

Консоль 2 - bleen.

create -e /mygroup/bleen 'iam_bleen'

Эфимерный тип узла задаётся ключом -e.

Проверьте в исходной консоли, что grue и bleen являются членами группы mygroup.

Представим теперь, что одному из клиентов нужна информация о другом клиенте (к качестве клиентов могут выступать узлы кластера). Этот сценарий эмулируется получением информации командой get, которую мы уже запускали ранее. Выберите консоль grue и обратитесь к информации узла bleen.

get /mygroup/bleen

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

Теперь эмулируйте аварийное отключение любого клиента. Нажмите сочетание клавиш Ctrl+D в одной из консолей, создавшей эфимерный узел.

Проверьте, что соответствующий узел пропал из mygroup. Изменение списка дочерних узлов может произойти не сразу — от 2 до 20 tickTime, значение которого вы можете посмотреть в zoo.cfg.

[zk: localhost:2181(CONNECTED) 53] ls /mygroup
[bleen, grue]
[zk: localhost:2181(CONNECTED) 54] ls /mygroup
[bleen, grue]
[zk: localhost:2181(CONNECTED) 55] ls /mygroup
[bleen, grue]
[zk: localhost:2181(CONNECTED) 56] ls /mygroup
[bleen, grue]
[zk: localhost:2181(CONNECTED) 57] ls /mygroup
[bleen, grue]
[zk: localhost:2181(CONNECTED) 58] ls /mygroup
[bleen, grue]
[zk: localhost:2181(CONNECTED) 59] ls /mygroup
[bleen, grue]
[zk: localhost:2181(CONNECTED) 60] ls /mygroup
[bleen]
[zk: localhost:2181(CONNECTED) 61]

Таким образом клиенты могут получать информацию о появлении и отключении других клиентов.

В заключении удалите узел /mygroup.

delete /mygroup

Пример управления конфигурацией распределённого приложения

Хранение конфигурационной информации в ZooKeeper одно из наиболее популярных приложений. Мы будем эмулировать данную концепцию также с помощью CLI.

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

Создадим в корне узел "myconfig" в задачу которого будет входить хранение конфигурации. В нашем случае узел будет хранить строку 'sheep_count=1'.

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

Откройте новую консоль и подключитесь к ZooKeeper. Данная консоль будет играть роль физического сервера, который ожидает получить оповещение в случае изменения конфигурационной информации, записанной в /myconfig znode.

Следующая команда устанавливает watch-триггер на узел:

get /myconfig -w true

Вернитесь к первому терминалу и измените значение myconfig:

set /myconfig 'sheep_count=2'

Во втором терминале должно появиться оповещение об изменении данных!

[zk: localhost:2181(CONNECTED) 87]
WATCHER::

WatchedEvent state:SyncConnected type:NodeDataChanged path:/myconfig

Триггер сбрасывается после одного срабатывания, а значит его придётся 'взводить' каждый раз заново. Как правило, в приложении, в логике обработчика события присутствует такая процедура.

Удалите узел /myconfig. Проверьте, что эта команда выполнилась.

Примеры приложений:

  • Эфимерные узлы в сочетании возможностью быть нумерованными позволяют реализовать механизм аварийного переключения https://ru.wikipedia.org/wiki/Аварийное_переключение, производить выбор лидера, обеспечивать координацию доступа к ресурсам.
  • Асинхронная передача и рассылка сообщений.

Другие примеры использования ZooKeeper https://zookeeper.apache.org/doc/r3.4.5/recipes.html.

Мониторинг ZooKeeper

ZooKeeper позволяет проводить мониторинг его состояния с использованием 4 буквенных команд: conf, cons, stat и других. Полный список команд доступен по адресу https://zookeeper.apache.org/doc/r3.7.0/zookeeperAdmin.html#sc_4lw .

Примечание. С коммита 5fe68506f2 Zookeeper 4-буквенные команды отключены по умолчанию. Вы можете их включить при запуске сервера с параметром JVM -Dzookeeper.4lw.commands.whitelist=*.

Команды можно отправлять на сервер из linux терминала с помощью утилит echo и netcat. Для некоторых linux систем netcat может быть вызван по сокращённому имени nc. Синтаксис команды:

echo <команда> | nc <имя или адрес хоста zookeeper> <порт>

В Windows вы можете установить подключение к zookeeper командой telnet

telnet <имя или адрес хоста zookeeper> <порт>

Для следующей команды сервер должен прислать ответ "imok", если он функционирует и доступен:

echo ruok | nc localhost 2181 

Узнать версию zookeeper позволяет следующая команда:

echo stat | nc localhost 2181

Следующая команда возвращает конфигурационные параметры ZooKeeper сервера:

echo conf | nc localhost 2181

После выполнения распечатываются следующие параметры:

  • порт клиента (clientPort),
  • путь к директории, где хранятся данные (dataDir),
  • путь к директории, где хранятся логи сервера (dataLogDir),
  • интервал часов, указанный миллисекундах (tickTime),
  • максимальное количество подключений к серверу (maxClientCnxns),
  • минимальный и максимальный таймаут сессии (minSessionTimeout, maxSessionTimeout),
  • идентификатор сервера.

Вышеперечисленные параметры могут быть указана в конфигурационном файле в директории conf (полный путь /opt/ibm/biginsights/zookeeper/conf/).

Отправьте команду cons для получения списка подключений всех клиентов с детальной информацией о сессиях.

echo cons | nc localhost 2181

Команды cons и conf дают детальную информацию. Для получения более общей информации используйте stat.

echo stat | nc localhost 2181

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

echo dump | nc localhost 2181

Для того, чтобы посмотреть информацию о watch-триггерах используйте команду wchs:

echo wchs | nc localhost 2181

Существуют и другие команды, найти которые вы можете в документации по администрированию ZooKeeper (Administrator's Guide).

На этом первая часть работы завершена.

Разработка распределённого приложения

ZooKeeper поставляется с двумя клиентами для языков C и Java. В текущей лабораторной мы будем использовать Java API для реализации приложения с барьерной синхронизацией. Аналогия с животными и зоопарком позволит лучше понять концепты ZooKeeper.

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

Настройка среды и проекта

Разработка распределённого приложения будет вестись на языке Scala в IDE IntelliJ Idea.

Создайте новый проект SBT аналогично тому, как это делалось в лабораторной работе 4. Дождитесь когда SBT инициализирует проект. Это может занять несколько минут.

Добавьте в качестве зависимости библиотеку ZooKeeper в build.sbt как provided. Определите версию ZooKeeper. Координаты библиотеки соответствующей версии вы можете найти в https://mvnrepository.com/.

Примечание. При указании zookeeper зависимости может потребоваться исключения из зависимостей: com.sun.jdmk, com.sun.jmx, javax.jms.

Реализация логики приложения

Инициализируйте пакет zoo в папке src/main/scala/.

В пакете zoo создайте scala объект Main и поместите туда следующий код.

package zoo

object Main {
  val sleepTime = 100

  def main(args: Array[String]): Unit = {
    println("Starting animal runner")

    val Seq(animalName, hostPort, partySize) = args.toSeq

    val animal = Animal(animalName, hostPort, "/zoo", partySize.toInt)

    try {
      
    } catch {
      case e: Exception => println("Animal was not permitted to the zoo. " + e)
    }
  }
}

Этот код объявляет главный класс с методом main. Программа ожидает в качестве аргументов список: имя животного, адрес и порт zookeeper, размер группы животных. Далее следует создание объекта Animal на основе параметров: имя животного, адрес и порт zookeeper, путь к корневому узлу для узлов животных, величина группы животных. В конце метода main располагается try/catch блок, в котором будет выполняться код взаимодействующий с ZooKeeper.

Примечание. Приём, с помощью которого присваиваются списку имён переменных соответствующие значения списка аргументов, называется "сопоставление по шаблону" (pattern matching).

Нашей следующей задачей будет реализация класса Animal и заполнение тела try блока.

В методе enter объект Animal должен связываться с ZooKeeper, создавать эфимерный узел с именем animalName и подписываться на обновления группы /zoo.

animal.enter()
println(s"${animal.name} entered.")

Напишите цикл, в котором с интервалом sleepTime в миллисекундах печатается сообщение о работе процесса. Количество итераций может быть случайным.

for (i <- 1 to Random.nextInt(100)) {
   Thread.sleep(sleepTime)
   println(s"${animal.name} is running...")
}

animal.leave()

Перейдём к реализации класса Animal. Для удобства обращения к полям класса будем использовать case class. Инициализация Animal заключается в установлении соединения с ZooKeeper, определении переменных mutex и animalPath.

package zoo

import org.apache.zookeeper._

case class Animal(name:String, hostPort:String, root:String, partySize:Integer) extends Watcher {
  val zk = new ZooKeeper(hostPort, 3000, this)
  val mutex = new Object()
  val animalPath = root+"/"+name

  if (zk == null) throw new Exception("ZK is NULL.")
}

Для реакции на события от ZooKeeper класс должен реализовывать метод process интерфейса Watcher.

override def process(event: WatchedEvent): Unit = {
  // код реакции на событие
}

Так как обработка событий и проверка условия барьера выполняются в разных потоках нам понадобится выполнять код методов в синхронизованном блоке. Синхронизация в Scala похожа на Java и выполняется на объекте-мьютексе. Ниже приведён пример блока синхронизации.

mutex.synchronized {
  // код       
}

Реализуем простую реакцию - вывод на экран события.

override def process(event: WatchedEvent): Unit = {
  mutex.synchronized {
    println(s"Event from keeper: ${event.getType}")
  }
}

Далее перейдём к реализации метода enter.

def enter():Boolean = {
  // код создания узла и ожидания у барьера
}

В начале метода создайте эфимерный узел.

zk.create(animalPath, Array.emptyByteArray, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL)

Затем в синхронизованном блоке в цикле напишите код, ожидающий появления в корневом узле /zoo всех животных.

mutex.synchronized {
  while (true) {
    val party = zk.getChildren(root, this)
    if (party.size() < partySize) {
       println("Waiting for the others.")
       mutex.wait()
       println("Noticed someone.")
     } else {
       return true
     }
   }
  }
  return false
}

Реализуйте оставшийся метод, который вызывается в конце приложения и удаляет созданный в начале эфимерный узел с помощью метода delete.

Проверка работоспособности приложения

Запустите несколько клиентов распределённого приложения и проверьте его работу.

Примечание. Перед запуском создайте корневой узел животных /zoo, если он ещё не создан.

Примечание. Убедитесь, что библиотеки, которые используются проектом (zookeeper, log4j и другие) находятся в области видимости CLASSPATH. Окружения этапов компиляции, тестирования и исполнения как правило различны.

Упражнения

С использованием Zookeeper сервиса:

  1. Решите проблему обедающих философов (каждый философ - отдельный процесс в системе)
  2. Реализуйте двуфазный коммит протокол для high-available регистра (каждый регистр - отдельный процесс в системе)

Приложение А. Инициализация виртуальной машины с помощью Vagrant

Для работы Vagrant необходим гипервизор Oracle VM VirtualBox. Для инициализации виртуальной машины поместите следующие файлы в пустую папку, находясь в ней откройте терминал и запустите команду vagrant up.

Vagrantfile

# -*- mode: ruby -*-
# vi: set ft=ruby :


# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure("2") do |config|
# The most common configuration options are documented and commented below.
# For a complete reference, please see the online documentation at
# https://docs.vagrantup.com.


# Every Vagrant development environment requires a box. You can search for
# boxes at https://vagrantcloud.com/search.
config.vm.box = "centos/7"
# config.vm.provider "virtualbox" do |vb|
# # Display the VirtualBox GUI when booting the machine
# vb.gui = true
#
# # Customize the amount of memory on the VM:
# vb.memory = "1024"
# end
#
# View the documentation for the provider you are using for more
# information on available options.


# Enable provisioning with a shell script. Additional provisioners such as
# Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
# documentation for more information about their specific syntax and use.
config.vm.provision "file", source: "zookeeper.service", destination: "zookeeper.service"
config.vm.provision "shell", inline: <<-SHELL
yum install nc -y
yum install java-11-openjdk -y
yum install wget -y
wget http://apache-mirror.rbc.ru/pub/apache/zookeeper/zookeeper-3.4.14/zookeeper-3.4.14.tar.gz
tar zxf zookeeper-3.4.14.tar.gz
mv zookeeper-3.4.14 /opt/
cp /opt/zookeeper-3.4.14/conf/zoo_sample.cfg /opt/zookeeper-3.4.14/conf/zoo.cfg
mv zookeeper.service /etc/systemd/system/zookeeper.service
chmod 664 /etc/systemd/system/zookeeper.service
systemctl start zookeeper
SHELL
end

zookeeper.service

[Unit]
Description=Zookeeper
After=syslog.target
 
[Service]
SyslogIdentifier=zookeeper
TimeoutStartSec=10min
Type=forking
ExecStart=/opt/zookeeper-3.4.14/bin/zkServer.sh start
ExecStop=/opt/zookeeper-3.4.14/bin/zkServer.sh stop
 
[Install]
WantedBy=multi-user.target

Дополнительные ссылки

  1. https://www.youtube.com/c/DistributedSystemsCourse
  2. https://www.youtube.com/c/lindseykuperwithasharpie
  3. https://lamport.azurewebsites.net/video/videos.html (recent talk: https://www.youtube.com/watch?v=Ocxczi-CvRQ)
  4. https://hydraconf.com/ (free talks: https://www.youtube.com/channel/UCcwI0q9tsGZYZDvz5mLsXZA)
  5. Lynch, Nancy A. Distributed Algorithms. 1996. https://dl.acm.org/doi/book/10.5555/2821576
  6. Martin Kleppmann. Designing Data-Intensive Applications: The Big Ideas Behind Reliable, Scalable, and Maintainable Systems
  7. Alex Petrov. Database Internals: A Deep Dive Into How Distributed Data Systems Work.