Привет! Меня зовут Павел Голов, я инженер отдела связи.
Наше подразделение занимается разработкой функционала взаимодействия с пользователем на Авито.
В феврале 2022 года для нашей команды произошло большое событие - мы закрыли всю рекламу частных пользователей с номерами безопасности.
О пути, который мы прошли, мне хотелось бы рассказать в этой статье.
Что такое защита номера
Для начала давайте быстренько разберемся, что такое защита номера, как она работает и зачем она нужна пользователям.Защита номера — бесплатная услуга для частных пользователей.
Если вы продаете на Авито, то при создании или редактировании объявления вы могли увидеть следующее предупреждение:
Когда продавец размещает объявление, мы прикрепляем к нему дополнительный виртуальный номер, который показываем покупателям, решившим связаться с продавцом.
Когда покупатель звонит на этот виртуальный номер, мы перенаправляем звонки на реальный номер продавца.
Каковы цели защиты номера и зачем она нужна продавцам?
- Реальный номер продавца в базе преступников не имеется.
Продажа на сайте становится безопаснее, и вам не придется беспокоиться, что после закрытия объявления позвонят спамеры.
- Пользователь не может написать в сторонний мессенджер или отправить СМС с фейковыми ссылками, что усложняет жизнь злоумышленникам.
Сообщения на Авито приходят как и раньше.
- Фильтруем звонки на антиспам номера.
Система блокирует значительное количество нецелевых звонков, и продавцы на них не отвлекаются.
Историческая справка
В 2018 году на Авито появился первый прототип защиты номера для частных пользователей.
С точки зрения пользовательской истории защита номеров состояла из двух сценариев:
- Отображение номера при просмотре объявления.
- Звонки на номера безопасности.
Отображение номера при просмотре объявления.
При создании объявления служба защиты номера асинхронно получила событие от Databus — нашего брокер сообщений на основе Кафки.
Если продавец включил защиту номера телефона, мы выбирали один из доступных нам бесплатных виртуальных номеров и привязывали его к созданному объявлению.
Виртуальный номер был привязан к объявлению на протяжении всей его жизни; мы отвязали виртуальный номер после закрытия или удаления объявления.
Когда покупатель зашел на страницу с объявлением, он увидел кнопку «Показать телефон».
При нажатии этой кнопки на бэкенд отправлялся запрос в службу защиты номера.
Далее мы проверяли, связан ли с этим объявлением виртуальный номер: если да, то показывали покупателю контрольный номер, если нет, то показывали реальный номер продавца.
Звонки на номера безопасности.
Покупатель увидел на странице объявления защитный номер, набрал его на телефоне и позвонил.
Первым делом звонок дошел до сотового оператора, которому принадлежит виртуальный номер.
Оператор понял, что этот номер закреплен за Авито и отправил запрос в наше API. Запрос поступил в микросервис обработки звонков.
На этом этапе мы использовали алгоритмы машинного обучения, чтобы определить, был ли звонок спамом.
Если звонок определялся как спам, оператору отправлялась команда на сброс звонка.
Если звонок не является спамом, мы выясняем, связан ли виртуальный номер, на который пытаются позвонить, с реальным номером продавца.
Если было активное соединение, мы отвечали на запрос оператора номером телефона, на который должен быть переадресован текущий звонок, и звонок доходил до продавца.
На практике схема звонка выглядела немного сложнее, но я оставил самую важную часть, чтобы не перегружать вас лишней информацией.
Масштабирование и проблемы
Первый прототип был запущен для частных пользователей в категориях «Недвижимость» и «Авто», которые охватили примерно 20% частных пользователей Авито.Прототип работал хорошо, и мы решили внедрить защиту номеров для всех частных пользователей.
Прототип рабочий, казалось бы, просто масштабируем его на все категории Авито, и готово! Но все немного сложнее: как я описывал выше, мы привязывали к каждому объявлению пользователя виртуальный номер, чтобы поддерживать атрибуцию звонков.
И эта ссылка была активной до тех пор, пока было активно само объявление.
Сейчас на Авито более 90 миллионов активных объявлений, и эта цифра постоянно растет. Часть рекламы принадлежит профессиональным пользователям, и тем не менее, чтобы закрыть всю рекламу частных пользователей, нам потребуются десятки, а в будущем и сотни миллионов виртуальных номеров.
Это привело бы к огромным затратам, которых мы хотели избежать.
Решение: динамический номер безопасности
Так как виртуальных номеров у нас в десятки раз меньше, чем активных объявлений, пришлось задуматься, как закрыть все объявления с имеющимся количеством номеров.Мы провели ряд аналитических исследований, которые показали, что ~98,2% первичных звонков покупатели совершают в течение первых двух часов с момента получения номера при просмотре объявления.
Что касается звонков, то когда покупатель перезванивает продавцу на тот же номер, ~99,7% звонков совершаются в первые 14 дней после первого звонка.
На основе этих данных мы построили алгоритм динамической защиты номеров, который стал усовершенствованием созданного ранее прототипа.
Алгоритм основан на следующих тезисах:
- Виртуальные номера присваиваются объявлениям не на весь жизненный цикл объявления, а только на определенное время.
- В каждом регионе РФ мы выделяем ограниченный пул виртуальных номеров.
- Виртуальные номера постоянно меняются между рекламными объявлениями.
Давайте рассмотрим каждую историю подробнее.
Отображение динамического кода безопасности
Теперь виртуальные номера закрепляются за объявлениями только на определенный период времени и постоянно чередуются между ними.Как это работает и как определить, какой виртуальный номер показывать по запросу покупателя? Когда покупатель нажимает кнопку «Показать телефон» на странице объявления, запрос все равно поступает в микросервис защиты номера.
Если к объявлению уже привязан виртуальный номер, то мы его просто показываем.
Если в объявлении нет активной ссылки, то мы:
- Смотрим пул виртуальных номеров конкретного региона РФ, где зарегистрирован реальный номер продавца;
- Ищем в пуле номер, который давно не показывался на сайте и показывался более двух часов назад.
Все происходит за десятки миллисекунд.
Примеры ротации номеров безопасности
Давайте рассмотрим простые примеры того, как работает вращение чисел.Пусть у нас есть пул номеров, в котором есть только 1 виртуальный номер.
Как я уже говорил, виртуальные номера сгруппированы по регионам РФ.
Прямоугольниками в примерах обозначены периоды времени, в течение которых клиенты могут звонить на полученные номера телефонов:
В первом примере у нас есть только 1 продавец, у которого есть 1 объявление.
В момент времени t1 покупатель получает номер телефона на рекламной карточке.
С этого момента к реальному номеру продавца привязывается виртуальный номер из пула и начинается обратный отсчет, в течение которого покупатель может позвонить продавцу, используя полученный виртуальный номер.
Сейчас это 2 часа.
В момент времени t2, при условии, что ни один другой покупатель не запросил номер телефона из этого объявления, виртуальный номер перестает перенаправлять вызов на номер продавца.
Если до момента времени t3 этот виртуальный номер еще не был передан какому-либо другому продавцу, а какой-то покупатель снова запрашивает номер телефона в объявлении в момент t3, тот же виртуальный номер снова становится «активным» и перенаправляет вызовы на реальный номер.
нашего первого продавца.
Отмечу, что каждый просмотр телефона в объявлении продлевает время, в течение которого мы переадресовываем звонки с текущего виртуального номера на реальный номер продавца.
Второй пример посложнее: теперь у нас есть 2 продавца, у каждого свое объявление.
В момент t1 покупатель запрашивает номер телефона по объявлению 1, в результате чего к реальному номеру продавца 1 привязывается виртуальный номер из пула.
В момент t2 время переадресации заканчивается и присвоенный номер становится неактивным.
Пусть в момент времени t3 покупатель запрашивает номер телефона по объявлению 2, который принадлежит другому продавцу из того же региона РФ, что и продавец с объявлением 1. Поскольку регионы совпадают, виртуальные номера для них берутся из того же пула.
.
Единственный виртуальный номер из текущего пула в этот момент закреплен за рекламой 1, но так как время переадресации для этого номера уже истекло, он переходит в рекламу 2. С этого момента виртуальный номер переадресовывает звонки на реальный номер продавец 2. В момент времени t4 время переадресации снова заканчивается, номер становится неактивным и остается закрепленным за вторым продавцом.
Стоит отметить, что если бы во втором примере время переадресации виртуального номера на рекламу 1 еще не истекло, когда по рекламе 2 произошел запрос номера, то произошла бы ошибка, так как свободных номеров в пуле нет. Мы постоянно следим за тем, чтобы в пулах всегда было достаточное количество виртуальных номеров для обеспечения работы алгоритма.
Для этого в моменты перехода числа от одного продавца к другому мы записываем временную метрику, которая рассчитывается как:
Здесь:
- Т я — рассчитываемая метрика для i-го региона (период обращения номера).
- now() — время в момент перехода числа от одного продавца к другому.
- LastShowTime — время последнего отображения на сайте виртуального номера, который переходит от одного продавца к другому.
Из графика можно сделать вывод, что чем больше трафика (в течение дня), тем короче расчетное время.
Если показатель времени достигает порога в 2 часа, это признак того, что в пуле недостаточно виртуальных номеров и необходимо добавить еще.
Реализация ротации чисел
При переходе номера от одного продавца к другому мы ищем в пуле виртуальный номер, который дольше всего не показывался на сайте.Расскажу, как мы это реализовали технически.
Когда алгоритм динамической защиты номеров находился на стадии AB-тестирования, мы не хотели тратить много усилий на разработку сложного решения и организовали своеобразную очередь приоритетов на базе PostgreSQL. У нас была таблица с основной информацией о привязке виртуальных номеров к рекламе и столбец Last_show_time, в котором хранилось время последнего показа виртуального номера на Авито.
В тот момент, когда нам нужно было передать номер от одного продавца другому, мы открыли транзакцию, в которой выполнили два запроса.
Первый запрос искал в таблице виртуальный номер, который давно не отображался на сайте:
Второй запрос обновил информацию о продавце, которому принадлежит полученный виртуальный номер телефона.SELECT * FROM dynamic_protections ORDER BY last_show_time LIMIT 1 FOR UPDATE SKIP LOCKED;
Очевидно, что у такого подхода есть свои недостатки.
Во-первых, чем больше становилась таблица Dynamic_protections, тем дольше выполнялся запрос из-за необходимости сортировки.
Во-вторых, с небольшой вероятностью запрос вернул виртуальный номер, который был показан на сайте совсем недавно, что было некорректно.
Это произошло из-за особенности блокировки строк и одновременной сортировки данных в запросе.
Вы можете прочитать больше в документации PostgreSQL в разделе «Запирающее предложение».
Позже, когда алгоритм доказал свою пригодность в ходе AB-теста, мы переработали схему получения виртуального номера, который давно не показывался на сайте.
За основу мы взяли Redis и его структуру данных Sorted Set, которая по сути представляет собой очередь с приоритетами.
Для каждого пула виртуальных номеров мы создаём свою приоритетную очередь.
За заполнение очередей отвечает отдельный работник.
Он запускается каждые несколько секунд и запрашивает PostgreSQL, чтобы получить виртуальные номера, которые стали доступны другому пользователю для перехода с момента последнего запроса.
После получения чисел мы раскладываем их по очередям в Redis, а в качестве показателя используется поле Last_show_time, преобразованное в формат unix-time, — параметр, по которому сортируется очередь.
В тот момент, когда приходит запрос на номер от пользователя и возникает необходимость передать номер от одного продавца другому, мы идем в Redis в очереди нужного пула.
Из очереди достаем номер, который дольше всего не показывался на сайте и обновляем данные для него в PostgreSQL. Если виртуальный номер из объявления уже стоит в очереди и какой-то покупатель решает посмотреть его до того, как номер перейдет к другому пользователю, мы удаляем этот номер из очереди.
Звонки на динамические номера безопасности
Сценарий звонков на динамические номера безопасности мало чем отличается от сценария из прототипа, но есть некоторые особенности.Когда покупатель получает динамический защитный номер на рекламной карточке, у него есть 2 часа с момента последнего показа номера на сайте, чтобы совершить первоначальный звонок продавцу.
После того, как покупатель совершил первоначальный звонок на определенный номер телефона и связался с продавцом, у него есть 14 дней с даты последнего звонка, чтобы связаться с тем же продавцом, используя тот же виртуальный номер.
Масштабирование и результат
Мы провели AB-тест алгоритма динамической защиты номеров, который показал, что алгоритм снижает показатель подтвержденного телефонного мошенничества на 52%.Это отличный результат, и поэтому было решено масштабировать алгоритм на всех пользователей Авито.
Масштабирование происходило поэтапно: каждые несколько дней мы включали алгоритм в нескольких новых регионах РФ и отслеживали основные технические и продуктовые метрики.
При этом мы провели нагрузочное тестирование с ожидаемой нагрузкой, чтобы доказать, что наши сервисы ее выдержат. В результате в начале февраля 2022 года алгоритм был распространен на всех частных пользователей Авито!
Скриншот из чата злоумышленников, которые брали с сайта номера телефонов и писали людям через мессенджеры, пытаясь их обмануть Мы гордимся своим решением, поскольку мы первые в России, кому удалось охватить такое большое количество рекламы и пользователей номерами безопасности.
Теперь мы закрываем общение покупателей и частных продавцов внутри Авито и делаем его еще безопаснее.
Теги: #информационная безопасность #Юзабилити #безопасность данных #безопасность данных #телефония
-
Вирусы — Мой Друг Их Ненавидит.
19 Oct, 24 -
Вся Правда Об Apple
19 Oct, 24 -
Корбина Снизила Тарифы На Интернет
19 Oct, 24 -
Лагерная Игра «Торренты»
19 Oct, 24