Серия Elasticsearch --- принцип и преимущества добавочного обновления

распределенный

резюме

В этой статье в основном представлен основной принцип добавочного обновления (частичное обновление, также известное как частичное обновление), представлены примеры использования скрипта Elasticsearch версии 6.3.1 и преимущества добавочного обновления.

Процесс и принцип инкрементного обновления

Краткий обзор

Мы кратко представили синтаксис приращений в предыдущей статье, давайте кратко рассмотрим пример запроса:

POST /music/children/1/_update
{
  "doc": {
    "length": "76"
  }
}

Как правило, от клиента до Elasticsearch полный процесс запроса приложения в основном выглядит следующим образом:

  • Сначала клиент инициирует запрос GET, получает информацию о документе и отображает ее на странице внешнего интерфейса для редактирования пользователями.
  • После того, как пользователь завершит редактирование данных, нажмите «Отправить».
  • Фоновая система обрабатывает измененные данные и формирует полное сообщение документа.
  • Отправьте запрос PUT в ES для полной замены.
  • ES помечает старый документ как удаленный, а затем воссоздает новый документ.

Документ Elasticsearch разработан на основе неизменяемого режима.Все обновления документа фактически создают новый документ, а затем помечают старый документ как удаленный.Инкрементное обновление не является исключением.Он просто ПОЛУЧАЕТ полные данные документа и интегрирует новый документ. трехэтапная операция замены старого документа и замены старого документа выполняется за один сегмент, который выполняется за миллисекунды.

Взаимодействие между осколками добавочного обновления

12

Шаги для постепенного обновления документа:

  1. Клиент Java отправляет запрос на обновление в кластер ES.
  2. Узел координат получает запрос, но документа нет на текущем узле, он перенаправляет запрос на сегмент P0 узла Node2.
  3. Узел 2 извлекает документ, изменяетJSON в источнике и переиндексировать документ, если другие потоки изменили документ, если есть конфликт версий, он повторит попытку обновить документ, максимальное количество повторных попытокon_conflict раз и сдаться после превышения количества повторных попыток.
  4. Если операция на шаге 3 выполнена успешно, Node2 асинхронно перешлет все содержимое документа в сегменты реплик Node1 и Node3 и перестроит индекс. После того, как все реплики вернули успех, Node2 возвращает сообщение об успехе в Coodinate Node.
  5. Узел Coodinate отвечает клиенту на сообщение об успешном обновлении.В это время как основной сегмент, так и сегмент реплики в кластере ES были обновлены.
Несколько замечаний:
  • Когда основной сегмент синхронизирует данные документа с сегментом реплики, он отправляет полную информацию о документе, поскольку упорядочение асинхронных запросов не гарантируется.
  • Пока Coodinate Node успешно отвечает Java-клиенту, это означает, что все первичные сегменты завершили операцию обновления для сегмента реплики.В это время данные в кластере ES непротиворечивы, а обновление безопасно.
  • Стратегия повторных попыток, ES снова получает данные документа и номер последней версии, обновляет их в случае успеха и повторяет попытку в случае сбоя.Можно установить максимальное количество раз, например 5 раз: повторитьonconflict=5
  • Стратегия повторных попыток более применима в сценариях, где добавочные операции не имеют последовательности, например операции подсчета.Неважно, кто выполняется первым, а кто — позже, лишь бы окончательный результат был правильным. В других сценариях, таких как изменение запасов и изменение баланса счета, если вы напрямую обновляете указанное значение, стратегия повтора не должна использоваться, но ее можно преобразовать в сложение и вычитание.При размещении заказа логика прямого обновление количества запасов изменяется на «текущее. Доступное количество запасов = количество запасов - количество товара в заказе», баланс счета обновляется плюс или минус сумма изменения, так что в определенной степени заказ может быть преобразован в заказ- независимыми, и стратегия повторных попыток может быть более удобной для решения проблемы конфликта.

Преимущества добавочных обновлений

  1. Все операции запросов, модификации и обратной записи выполняются внутри ES, что снижает накладные расходы на передачу данных по сети (в 2 раза) и повышает производительность.
  2. По сравнению с интервалом времени полной замены (более секунд) интервал времени между запросом и модификацией (уровень миллисекунд) сокращается, что может эффективно уменьшить ситуацию параллельных конфликтов.

Инкрементальные обновления с использованием скриптов

Elasticsearch поддерживает использование скриптов для реализации более гибкой логики.После версии 6.0 поддерживаемый по умолчанию скрипт безболезненный, а Groovy больше не поддерживается.Потому что при компиляции Groovy есть определенная вероятность того, что память не будет освобождена, что в конечном итоге приведет к Проблема полного GC.

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

{
  "_index": "music",
  "_type": "children",
  "_id": "2",
  "_version": 6,
  "found": true,
  "_source": {
    "name": "wake me, shark me",
    "content": "don't let me sleep too late, gonna get up brightly early in the morning",
    "language": "english",
    "length": "55",
    "likes": 0
  }
}

встроенный скрипт

Теперь есть такое требование: каждый раз, когда кто-то нажимает, чтобы воспроизвести песню, поле лайков документа автоматически увеличивается на 1. Для этого мы можем использовать простой скрипт:

POST /music/children/2/_update
{
   "script" : "ctx._source.likes++"
}

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

внешний скрипт

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

Создать скрипт
POST _scripts/music-likes
{
  "script": {
    "lang": "painless",
    "source": "ctx._source.likes += params.new_likes" 
  }
}

Идентификатор скрипта — music-likes, а параметр — new_likes, который можно передать при вызове.

использовать сценарий

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

POST /music/children/2/_update
{
  "script": {
    "id": "music-likes", 
    "params": {
      "new_likes": 2
    }
  }
}

id - это музыка-лайки при создании скрипта, а params - это фиксированный способ записи. Параметр внутри - new_likes. После его выполнения проверьте информацию о документе. Вы можете видеть, что значение поля нравится накапливается в соответствии с входящее значение, и результат соответствует ожидаемому.

Посмотреть сценарий

Заказ:

GET _scripts/music-likes

Параметр после косой черты - это идентификатор скрипта

удалить скрипт

Заказ:

DELETE _scripts/music-likes

Параметр после косой черты - это идентификатор скрипта

Рекомендации по сценариям

  • Когда ES обнаруживает новый скрипт, он выполняет компиляцию скрипта и сохраняет его в кеше, что требует много времени для компиляции.
  • Написание скрипта может быть параметризовано, поэтому не делайте его жестко закодированным, чтобы улучшить возможность повторного использования скрипта.
  • За короткое время компилируется слишком много скриптов, если это превышает допуск ES, ES сообщит об этом напрямую в схему.breakingОшибка исключения, этот диапазон по умолчанию равен 15 записям в минуту.
  • Кэш скрипта по умолчанию 100 элементов, по умолчанию без срока действия.Максимальный символ каждого скрипта 65535 байт.Если вы хотите настроить его самостоятельно, вы можете изменить script.cache.expire, script.cache.maxразмер и script.maxsizeinпараметр байт.

Одним словом, улучшить возможность повторного использования скриптов.

синтаксис upsert

Как и в случае только что, он реализует функцию счетчика воспроизведения.В настоящее время счетчик хранится вместе с контентом.Если счетчик хранить отдельно, может появиться новая песня, но документ счетчика может еще не существовать. Он сообщит о документе, когда выполнит операцию обновления.missingОшибка исключения, в этом сценарии нам нужно использовать синтаксис upsert:

POST /music/children/3/_update
{
   "script" : "ctx._source.likes++",
   "upsert": {
     "likes": 0
   }
}

Если запись с идентификатором 3 не существует, содержимое JSON в upsert выполняется для первого запроса, а новый документ инициализируется с идентификатором 3 и значением лайков 0; при выполнении второго запроса документ уже существует, а скрипт в это время выполняется.Операция обновления скрипта, вроде автоинкремента.

резюме

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

Сосредоточьтесь на Java с высокой степенью параллелизма и распределенной архитектуре, большем обмене техническими галантереями и опытом, пожалуйста, обратите внимание на общедоступный номер: Сообщество архитектуры JavaJava架构社区