резюме
В этой статье в основном представлен основной принцип добавочного обновления (частичное обновление, также известное как частичное обновление), представлены примеры использования скрипта Elasticsearch версии 6.3.1 и преимущества добавочного обновления.
Процесс и принцип инкрементного обновления
Краткий обзор
Мы кратко представили синтаксис приращений в предыдущей статье, давайте кратко рассмотрим пример запроса:
POST /music/children/1/_update
{
"doc": {
"length": "76"
}
}
Как правило, от клиента до Elasticsearch полный процесс запроса приложения в основном выглядит следующим образом:
- Сначала клиент инициирует запрос GET, получает информацию о документе и отображает ее на странице внешнего интерфейса для редактирования пользователями.
- После того, как пользователь завершит редактирование данных, нажмите «Отправить».
- Фоновая система обрабатывает измененные данные и формирует полное сообщение документа.
- Отправьте запрос PUT в ES для полной замены.
- ES помечает старый документ как удаленный, а затем воссоздает новый документ.
Документ Elasticsearch разработан на основе неизменяемого режима.Все обновления документа фактически создают новый документ, а затем помечают старый документ как удаленный.Инкрементное обновление не является исключением.Он просто ПОЛУЧАЕТ полные данные документа и интегрирует новый документ. трехэтапная операция замены старого документа и замены старого документа выполняется за один сегмент, который выполняется за миллисекунды.
Взаимодействие между осколками добавочного обновления
Шаги для постепенного обновления документа:
- Клиент Java отправляет запрос на обновление в кластер ES.
- Узел координат получает запрос, но документа нет на текущем узле, он перенаправляет запрос на сегмент P0 узла Node2.
- Узел 2 извлекает документ, изменяетJSON в источнике и переиндексировать документ, если другие потоки изменили документ, если есть конфликт версий, он повторит попытку обновить документ, максимальное количество повторных попытокon_conflict раз и сдаться после превышения количества повторных попыток.
- Если операция на шаге 3 выполнена успешно, Node2 асинхронно перешлет все содержимое документа в сегменты реплик Node1 и Node3 и перестроит индекс. После того, как все реплики вернули успех, Node2 возвращает сообщение об успехе в Coodinate Node.
- Узел Coodinate отвечает клиенту на сообщение об успешном обновлении.В это время как основной сегмент, так и сегмент реплики в кластере ES были обновлены.
Несколько замечаний:
- Когда основной сегмент синхронизирует данные документа с сегментом реплики, он отправляет полную информацию о документе, поскольку упорядочение асинхронных запросов не гарантируется.
- Пока Coodinate Node успешно отвечает Java-клиенту, это означает, что все первичные сегменты завершили операцию обновления для сегмента реплики.В это время данные в кластере ES непротиворечивы, а обновление безопасно.
- Стратегия повторных попыток, ES снова получает данные документа и номер последней версии, обновляет их в случае успеха и повторяет попытку в случае сбоя.Можно установить максимальное количество раз, например 5 раз: повторитьonconflict=5
- Стратегия повторных попыток более применима в сценариях, где добавочные операции не имеют последовательности, например операции подсчета.Неважно, кто выполняется первым, а кто — позже, лишь бы окончательный результат был правильным. В других сценариях, таких как изменение запасов и изменение баланса счета, если вы напрямую обновляете указанное значение, стратегия повтора не должна использоваться, но ее можно преобразовать в сложение и вычитание.При размещении заказа логика прямого обновление количества запасов изменяется на «текущее. Доступное количество запасов = количество запасов - количество товара в заказе», баланс счета обновляется плюс или минус сумма изменения, так что в определенной степени заказ может быть преобразован в заказ- независимыми, и стратегия повторных попыток может быть более удобной для решения проблемы конфликта.
Преимущества добавочных обновлений
- Все операции запросов, модификации и обратной записи выполняются внутри ES, что снижает накладные расходы на передачу данных по сети (в 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 с высокой степенью параллелизма и распределенной архитектуре, большем обмене техническими галантереями и опытом, пожалуйста, обратите внимание на общедоступный номер: Сообщество архитектуры Java