Проектирование и внедрение службы кэширования аварийного восстановления для системы рекомендаций Ma Honeycomb

JavaScript

Внезапно отключается база данных, сторонний интерфейс медленно возвращает результаты, сеть дергается в часы пик... Когда программа неожиданно выходит из строя, наше приложение может сообщить звонящему или пользователю: «Извините, что-то не так с server.”; или найти лучший способ улучшить взаимодействие с пользователем.

1. Предпосылки

Когда пользователь «пролистывает» приложение Mafengwo, рекомендательная система должна постоянно рекомендовать контент, который может заинтересовать пользователя.Он в основном делится на отзыв контента, рассчитанного в соответствии с различными алгоритмами машинного обучения в соответствии с характеристиками пользователя и бизнес-сценариями, а затем анализировать этот контент. Контент сортируется и возвращается во внешний интерфейс для этих шагов.

Рекомендуемый процесс включает ряд операций, таких как запросы MySQL и Redis, вызовы службы REST и обработка данных. Для рекомендательных систем требования к задержке относительно высоки. Средняя задержка обработки сотовой рекомендательной системы Ma для запросов находится на уровне 10 мс, а 99 строк задержки удерживаются в пределах 1 с.

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

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

2. Дизайн и реализация

Дизайнерские идеи и выбор технологий

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

В сочетании с бизнес-сценариями и требованиями, о которых мы упоминали выше, мы приняли решение, основанное на кэше вне кучи OHC и SpringBoot, чтобы добавить локальную систему кэширования аварийного восстановления к существующей системе рекомендаций. В основном с учетом следующих факторов:

1. Избегайте влияния на онлайн-сервисы и изолируйте бизнес-логику от логики кэша.

Чтобы не влиять на онлайн-сервис, мы инкапсулируем систему кэширования как CacheService, настраиваем ее в конце существующего процесса и предоставляем API чтения и записи для внешних вызовов, чтобы изолировать бизнес-логику от логики кэша.

2. Кэш асинхронной записи для повышения производительности

Кэш чтения и записи требует времени, особенно кеш записи. Чтобы повысить производительность, мы рассматриваем возможность сделать кэш записи асинхронным. Эта часть реализована с использованием пула потоков ThreadPoolExecutor, предоставляемого JDK.Основной поток должен только отправлять задачи в пул потоков, а рабочий поток в пуле потоков реализует кеш записи.

3. Локальный кеш для повышения скорости доступа

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

4. Резервное копирование экземпляров кеша для обеспечения доступности

Чтобы обеспечить доступность кеша, мы не только кэшируем в памяти, но и регулярно делаем резервную копию в файловой системе, чтобы гарантировать, что приложение может быть загружено из файловой системы в память при запуске приложения. В частности, это можно реализовать с помощью запланированных задач и ApplicationRunner, предоставляемых SpringBoot.

Общая структура

Мы поддерживаем существующую логику рекомендательной системы и в конце существующего процесса настраиваем CacheModule и CacheService, которые отвечают за всю логику, связанную с кешем.

Среди них CacheService — это конкретная реализация кеша, обеспечивающая интерфейсы чтения и записи; CacheModule обрабатывает запрошенные на этот раз данные и решает, вызывать ли CacheService для работы с кешем.

Интерпретация модуля

1. CacheModule

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

Рабочий процесс CacheModule показан на рисунке, на котором оранжевая часть представляет вызов CacheService:

  • Отправить задачу кэширования. Если запрос не генерирует исключение, а результат ответа не пуст, задача кэширования будет отправлена ​​в CacheService. Ключевое значение задачи — соответствующий бизнес-сценарий, а значение — содержимое, рассчитанное по этому ответу. Представленное действие не блокирует и мало влияет на время работы интерфейса.

  • читать данные кэша. Когда само приложение или зависимое приложение выдает исключение, система считывает кэш из CacheService в соответствии со значением ключа бизнес-сценария и возвращает его вызывающей стороне. Когда пользователь сам сбросил все доступные данные, нет необходимости читать кеш, но запрошенные данные вовремя возвращаются пользователю.

2. CacheService

В конкретной реализации кэширования CacheService использует OHC, который не зависит от проекта Apache Cassandra. Кроме того, поскольку все наше приложение основано на SpringBoot, мы также используем различные функции, предоставляемые SpringBoot.

Как упоминалось выше, для кеша не существует жестких требований к согласованности, поэтому мы используем локальный кеш вместо распределенного кеша и абстрагируем класс CacheService для поддержки локального кеша.

(1) Формат данных

Когда система рекомендаций возвращает данные, она возвращает данные в единицах «экранов» в соответствии с бизнес-сценариями и характеристиками пользователя.Каждый экран может содержать несколько элементов контента, поэтому используется формат данных набора ключей: ключевое значение — это бизнес-сценарий. , такие как домашняя страница. Канал «видео»; кешированный контент представляет собой набор «экранов».

(2) Место хранения

Для приложений Java кэш может храниться в памяти или в файле на жестком диске. Пространство памяти делится на кучу (heap memory) и вне кучи (off-heap memory). Мы сравнили эти методы:

Чтобы обеспечить более высокую скорость чтения и записи и избежать влияния сборщика мусора на онлайн-сервисы, в качестве пространства кэша выбирается вне кучи. OHC сначала был включен в проект Apache Cassandra, а затем стал самостоятельным и стал инструментом кэширования с открытым исходным кодом, основанным на вне кучи. Он может одновременно поддерживать большой объем памяти вне кучи, а также использоваться для небольших объектов кэша с низкими накладными расходами. Поэтому мы используем OHC в качестве реализации кэша вне кучи.

(3) Резервное копирование файлов

Когда приложение перезапускается, кэш вне кучи пуст. Чтобы загрузить кеш как можно быстрее, мы используем функцию планирования задач SpringBoot для регулярного резервного копирования кеша из кучи в файловую систему; отслеживаем процесс запуска приложения, наследуя ApplicationRunner SpringBoot, и загружаем файл резервной копии на жесткий диск. диск во внекучу после завершения запуска кучи, чтобы обеспечить доступность кэшированных данных.

CacheService поддерживает очередь задач, в которой хранятся задачи кэширования, отправленные CacheModule, неблокирующим образом, и CacheService решает, следует ли выполнять эти задачи кэширования.

(4) API, предоставляемый CacheModule

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

  • При записи в кеш инкапсулируйте ключ и значение как задачу, отправьте ее в очередь задач, а очередь задач отвечает за асинхронную запись в кеш.

(5) Очередь задач и асинхронная запись

Здесь мы используем пул потоков в JDK для реализации. При построении пула потоков использование LinkedBlockingQueue в качестве очереди задач позволяет быстро добавлять и удалять элементы; поскольку QPS приложения находится в пределах 100, количество рабочих потоков фиксируется на уровне 1; при заполнении очереди выполняется DiscardPolicy и вставка в очередь отменяется.

(6) Контроль количества кеша

Если кеш занимает слишком много места в памяти, это повлияет на онлайн-приложение.Мы можем контролировать количество кешей, настроив максимальное количество кешей для разных бизнес-сценариев. Когда значение конфигурации не достигнуто, успешно обработанные данные записываются в кеш; когда значение конфигурации достигнуто, исходные элементы кеша могут быть выбраны случайным образом и перезаписаны, чтобы обеспечить производительность кеша в реальном времени.

С учетом вышеперечисленных аспектов конструкция CacheService выглядит следующим образом:

онлайн-выступление

Чтобы проверить эффект кеша аварийного восстановления, мы закапывали кеш при попадании в кеш и проверяли количество попаданий в кеш в час через Kibana. Как показано на рисунке, в системе существует определенный тайм-аут с 18:00 до 19:00, и в этот период доступность системы повышается за счет эффекта службы кэширования.

Мы также отслеживали скорость чтения и записи OHC. Задержка записи в кеш находится на уровне миллисекунд, а запись асинхронная, задержка чтения кеша — на уровне микросекунд. В принципе, система не требует дополнительных затрат времени.

вытоптанная яма

Перед записью кеша в OHC необходимо выполнить сериализацию, и мы используем крио с открытым исходным кодом в качестве инструмента сериализации. При использовании kyro ранее было обнаружено, что десериализация может завершиться ошибкой для классов, которые не реализуют Serializable, таких как внутренний класс java.util.ArrayList$SubList, возвращаемый методом List#subList. Сериализаторы можно зарегистрировать вручную, чтобы решить эту проблему.Репозиторий крио-сериализаторов с открытым исходным кодом на Github предоставляет различные типы сериализаторов.

Еще один момент, вам нужно обратить внимание на настройку емкости и maxEntrySize в OHC в соответствии с конкретным сценарием использования. Если настроенное значение слишком мало, это приведет к сбою кэша записи. Вы можете измерить пространство, занимаемое кешем, перед подключением к Интернету и разумно установить размер всего пространства кеша и размер каждой записи в кеше.

3. Направление оптимизации

На основе SpringBoot и OHC мы добавили к существующей системе рекомендаций локальную систему кэширования аварийного восстановления, которая может возвращать кэшированные данные при внезапном сбое зависимой службы или самого приложения.

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

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

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

  • В настоящее время некоторые конфигурации рекомендуемой системы по-прежнему зависят от MySQL, и в будущем будет рассмотрено локальное кэширование файлов.

[Ссылка]

1. Java Caching Benchmarks 2016 - Part 1

2. On Heap vs Off Heap Memory Usage

3. OHC - An off-heap-cache

4. kryo-serializers

5. scheduling-tasks

Автор этой статьи: Sun Xingbin, Mafengwo рекомендации и инженер по исследованиям и разработкам.

(Исходное содержание Ma Honeycomb Technology, пожалуйста, укажите источник и сохраните изображение QR-кода в конце статьи при перепечатке, спасибо за сотрудничество.)

Обратите внимание на официальный аккаунт Ma Honeycomb Technology, чтобы найти больше нужного вам контента.