Впервые опубликовано в публичном аккаунтеТехническая команда MXPlayer, добро пожаловать, чтобы следовать.
О Файсс
Faiss — это библиотека с открытым исходным кодом для кластеризации и поиска по сходству, созданная командой Facebook AI. Она предоставляет эффективные службы поиска по сходству для плотных векторов и поддерживает поиск векторов на уровне миллиардов. Faiss предоставляет различные типы индексов, такие как расстояние L2, векторное внутреннее произведение и т. д. Подробную информацию см.Faiss Indexes, мы можем выбрать подходящие типы индексов для наборов векторов разного размера и алгоритмов кластеризации.
В службе рекомендаций mx Faiss в настоящее время в основном используется для отзыва сходства и оценки. Мы загружаем данные внедрения элемента и пользователя из разных алгоритмов и загружаем их в индекс Файсса для реализации алгоритмов, таких как на основе элементов/пользователей. В то же время вы также можете использовать Faiss для оценки и сортировки соответствующих результатов в соответствии с потребностями бизнес-сценариев.
Выбор услуги
Первоначально сервер MX Faiss был основан на веб-сервере с открытым исходным кодом, разработанном с использованием фреймворка flask (faiss-web-service) была улучшена.Для скорейшего запуска экспериментов детальный дизайн и оптимизация не проводились.Поэтому производительность в онлайне не очень.Среднее время отклика около 6мс.Кроме того,плохая масштабируемость,и добавление или удаление индексов во многих отношениях ограничено фреймворком. После достаточных исследований и технического отбора было окончательно решено использовать для реконструкции каркас RPC.
В настоящее время существует множество сред RPC с открытым исходным кодом, таких как Thrift, Dubbo, gRPC, rpcx и т. д. Поскольку служба рекомендаций mx разработана на языке Java, Faiss в настоящее время поддерживает только C++ и Python.Учитывая необходимость многоязычной поддержки , только gRPC и Thrift соответствуют требованиям. найдено в исследовании (ссылка«Популярный бенчмарк RPC Framework»), при работе с сервисами уровня 10 мс gRPC имеет определенные преимущества перед Thrift с точки зрения пропускной способности и задержки, поэтому в итоге был выбран фреймворк gRPC.
анализ спроса
1. Многотипная векторная загрузка
Векторы, созданные различными алгоритмами, хранятся на s3 с именем имени алгоритма + тип элемента + выходная временная метка (номер версии).Например, файл с ключом deepwalk/movie/index.20190821_043002_64 на S3 создается алгоритмом deepwalk , Вектор элементов типа кино. Сервер Faiss должен иметь возможность загружать различные типы векторов для построения индекса и выполнять поиск по сходству из соответствующего индекса в соответствии с типом алгоритма и типом элемента в запросе.
2. Многотипный индексный тест
Faiss предоставляет множество типов индексов. Мы можем загружать один и тот же тип вектора в разные типы индексов, чтобы проводить небольшие эксперименты с трафиком, чтобы найти наилучший набор сопоставлений между типами векторов и типами индексов. Эффекты здесь включают индикаторы рекомендуемых результатов, Faiss использование памяти сервера, использование ЦП, время отклика и т. д.
3. Индекс легко настроить
Поскольку онлайн-производительность каждого индекса не одинакова, по ходу эксперимента некоторые индексы необходимо отбросить, а вектор, сгенерированный новым алгоритмом, необходимо вовремя протестировать, поэтому сервер Faiss должен иметь возможность настроить гибко индексировать.
4. Контроль версии индекса
Когда мы генерируем вектор элементов, мы также генерируем пользовательский вектор.Система рекомендаций может использовать пользовательский вектор для вызова элементов в том же векторном пространстве, но пользовательский вектор хранится в pika, и выходные данные будут отставать от вектора элементов. Также возможно По какой-то причине возникает проблема с записью пользовательского вектора, из-за чего рекомендательная система получает старый вектор, а сервер Faiss обновился до нового индекса, поэтому серверу Faiss необходимо иметь возможность загружать несколько версий одного и того же типа вектора, чтобы система рекомендаций могла. Указав версию, вы можете получить элементы, которые являются соседями пользовательского вектора в том же векторном пространстве.
5. Горячее обновление индекса
Векторы, созданные различными алгоритмами, будут обновляться нерегулярно каждый день.Помимо загрузки последнего вектора для построения индекса при запуске службы, серверу Faiss также необходимо своевременно обновлять индекс последним вектором, и в то же время , он должен иметь возможность нормально отвечать на запросы.
Дизайн и реализация
1. Faiss Server
1.1 Организационная структура
На приведенном выше рисунке показана организационная структура сервера Faiss.Чтобы выполнить требования 1, 2 и 4, мы инкапсулируем индекс Файсса в FaissHandler. FaissHandler содержит 5 полей: algorithm_type, category и index_type указывают только индекс, который может легко поддерживать несколько типов векторов и несколько типов индексов, а index_dict сохраняет реальный индекс Faiss с версией вектора (индекса) в качестве ключа, Faiss Индекс значение, которое может легко поддерживать сервис поиска ближайших соседей указанной версии.Кроме того, есть поле last_version, которое используется для сохранения номера последней версии в index_dict.При поиске без указания версии вектора последняя версия будет использоваться индекс search.
Мы можем настроить FaissHandler, который должен использоваться в настоящее время в HandlerCollection, а модуль обновления индекса может обновлять индекс один за другим, обходя коллекцию. Кроме того, также выполняется Требование 3. Для добавления, изменения или удаления требуется модифицировать только одну строку кода, что очень удобно. Службе gRPC нужно только собрать параметры в запросе, а затем направить их соответствующему обработчику, а остальные операции выполняет обработчик.
1.2 Дизайн интерфейса
Сервер Faiss должен обеспечить поиск интерфейса RPC для поиска ближайшего соседнего элемента.В запросе интерфейса поиска необходимо указать, какой индекс использовать, а также идентификатор или вектор целевого элемента.Основные поля тела запроса: следующее:
message SearcRequest {
string algorithmType = 1;
string category = 2;
int32 num = 3;
string indexType = 4;
repeated string itemId = 5;
repeated FloatArray vector = 6;
}
Первые четыре поля в SearchRequest являются обязательными, поскольку эти четыре поля используются для поиска обработчика, и должно существовать хотя бы одно из itemId и vector. И itemId, и вектор украшены повторами, чтобы поддерживать многоэлементный и многовекторный поиск.
message SearchResponse {
message Str2FloatMap {
map<string, float> innerMap = 1;
}
map<string, Str2FloatMap> similarItems = 1;
}
Ответ очень прост, есть только одна карта, ключ — это целевой элемент или вектор (в SearchRequest), а значение — результат ближайшего соседа и оценка для него.
1.3 процесс поиска
2. Обновление индекса
На рисунке выше представлена схема архитектуры обновления индекса. Celery beat создает задачу на обновление индекса каждые 2 минуты и требует обновить индексы, соответствующие всем обработчикам в HandlerCollection. После получения задачи рабочий загружает соответствующий векторный файл из AWS S3 и загружает вектор Создайте индекс, а затем сериализуйте индекс в файл.Сервер Faiss предоставляет интерфейс gRPC для получения уведомлений (вызовов) от сельдерея и прямой загрузки файла индекса для обновления индекса после получения уведомления. Загрузка вектора и построение индекса — очень трудоемкие операции, доверив их Celery, можно сэкономить ресурсы сервера и обеспечить стабильную и эффективную работу сервера. Подробный процесс обновления индекса выглядит следующим образом:
На приведенной выше диаграмме подробно описан процесс обновления, но некоторые детали спрятаны для большей наглядности и удобочитаемости. Операция обновления не является единым потоком на всем пути, потому что у нас много индексов, чтобы как можно быстрее обновить индекс для предоставления услуг, при обходе коллекции обработчиков будет создана задача celery, которая проверяет версию, для каждого обработчик, и тогда параллельно пойдет celery worker.Выполнить эти задачи, для каждой задачи, если она действительно нуждается в обновлении, также создать задачу загрузки вектора для параллельного выполнения, но здесь есть проблема, то есть celery beat создает стоит задача обновлять индекс каждые 2 минуты, но загрузка вектора очень трудоемкая операция, т.к. векторный файл может быть большим, если последняя операция обновления была еще в процессе загрузки вектора, а в этот раз он достиг шаг загрузки вектора, что приведет к тому, что несколько рабочих процессов загрузят один и тот же вектор одновременно. , что приведет не только к трате рабочих ресурсов, но и к трате сетевого ввода-вывода. Поэтому, прежде чем вектор будет фактически загружен, он попытается получить блокировку для определенного вектора. Если блокировка не может быть получена, это означает, что рабочий процесс выполняет задачу загрузки вектора. , текущий рабочий процесс возвращается напрямую, завершает задачу и ожидает получения других задач. После загрузки вектора одновременно загружается индекс, и сервер уведомляется об обновлении.
развертывать
Сервер Faiss разработан на языке python.Поскольку python имеет глобальную блокировку интерпретатора и не может эффективно использовать многоядерные процессоры, мы развертываем его в режиме мультисервисного экземпляра на одной машине.
онлайн-выступление
Перед выходом в онлайн был проведен достаточный стресс-тест, и результаты показали, что одномашинный QPS стал более чем в 2 раза выше, чем раньше, а время отклика сократилось примерно на 67%. Сравнение времени отклика на newrelic до и после запуска нового сервиса выглядит следующим образом:
Суммировать
Сервер Faiss на базе gRPC — это узкоспециализированный сервис для нужд бизнеса, который эффективно решает различные проблемы, существующие в исходном сервисе, и обладает характеристиками высокой эффективности и высокой масштабируемости.