Как одно изменение ускорило загрузку правил фильтрации в Safari в 5 раз

Сегодня я хочу поделиться историей о паре регулярных выражений — небольшая неточность в них в конечном итоге стоила миру более 50 миллионов часов процессорного времени на устройствах iOS.

Предупреждение: в этом посте много технических деталей, и его сложно читать, если вы не умеете программировать.

Как работают блокировщики контента в Safari

Сначала объясню, как работают блокировщики рекламы в Safari — без этого сложно двигаться дальше. AdGuard на iOS использует встроенный механизм Safari — Content blockers (блокировщики контента).

Также поддерживается альтернативный подход — declarativeNetRequest (DNR), частично совместимый с Chrome и Firefox. Интересно, что в случае Safari правила DNR незаметно переводятся в правила блокировщиков контента Safari.

Самая первая версия AdGuard для iOS была выпущена в октябре 2015 года, и мы сразу же столкнулись с неприятной проблемой. Исторически сложилось так, что блокировщики рекламы всегда использовали свой собственный синтаксис правил фильтрации. Он мощный и специально разработан для веб-фильтрации. Однако Apple представила свой собственный подход, который значительно отличался от того, к чему привыкло сообщество разработчиков фильтров.

Забегая немного вперёд: когда Chrome представил declarativeNetRequest, они также пошли своим путём. По крайней мере, когда дело дошло до сопоставления URL, их синтаксис был гораздо ближе к тому, к которому мы привыкли.

Вот пример того, как стандартное правило AdGuard преобразуется в синтаксис, поддерживаемый Safari:

Преобразование правила AdGuard в правило, принимаемое Safari

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

Регулярные выражения

Блокировщики контента Safari, с другой стороны, полагаются на регулярные выражения — хотя и в очень упрощённой форме, чтобы их всё ещё можно было скомпилировать в структуру, ускоряющую сопоставление.

Если вам интересно узнать о внутреннем устройстве: Safari создаёт байт-код DFA из шаблонов регулярных выражений, который затем выполняется пользовательским интерпретатором: DFABytecodeInterpreter.cpp.

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

Преобразование шаблонов 1.0

Итак, в 2015 году нам нужно было выяснить, как преобразовать шаблоны URL-адресов AdGuard в регулярные выражения, которые бы принимал Safari.

В то время перед нами стояли две основные задачи.

Во-первых, нам нужно было сократить общее количество правил в окончательном наборе. Тогда у Safari был жёсткий лимит в 50 000 правил. Мы описывали, как справились с этой задачей, в посте о блокировке рекламы в Safari.

Впоследствии лимит был увеличен до 150 000 правил. Однако из-за ограничений памяти процесса на практике можно использовать только около 60–80 тысяч. Мы несколько раз сообщали об этом Apple (отчёты Apple Feedback Assistant: FB19728743, FB13282146), но безрезультатно.

Вторая задача заключалась в том, чтобы убедиться, что сгенерированные нами регулярные выражения были достаточно эффективными для быстрой работы и достаточно лёгкими, чтобы iOS мог их скомпилировать. В те дни мы иногда видели, как система убивала процесс com.apple.Safari.ContentBlockerLoader, потому что он потреблял слишком много ресурсов.

После множества ручных тестов мы остановились на том, что казалось оптимальными правилами преобразования:

  • Символ || (начало URL) стал ^[htpsw]+://([a-z0-9-]\.)?
  • Символ ^ (разделитель) — [/:&?]

Мы были уверены, что сделали всё необходимое, поэтому перестали об этом беспокоиться и оставили всё как есть — почти на десять лет.

Мы ошибались

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

Простым решением было использовать регулярное выражение, первоначально предложенное разработчиками WebKit ещё в 2015 году — то самое, которое мы тогда отвергли как «неоптимальное». Но мы были настолько уверены в своём выборе, что до недавнего времени даже не удосужились его перепроверить.

Изменения, которые мы должны были внести, были предельно просты:

  • Заменить || на ^[^:]+://+([^:/]+\.)?
  • Заменить ^ в большинстве случаев на [/:]

Была ли разница настолько велика? Оказалось — да, была.

Ох, как же мы ошибались

После замены на новые регулярные выражения мы провели несколько быстрых тестов, и результаты поразили нас. Скорость загрузки правил в Safari не просто немного улучшилась — она взлетела до небес.

Если говорить цифрами: компиляция Фильтра счётчиков и систем аналитики в Safari стала в 5,5 раз быстрее, а компиляция Базового фильтра — в 2,8 раз быстрее.

Чтобы было понятнее, посмотрите видео ниже:

Если посчитать количество пользователей AdGuard за последнее десятилетие и количество раз, когда приложению приходилось перекомпилировать фильтры, то количество потраченного впустую времени процессора составляет как минимум 50 миллионов дополнительных часов на устройствах iOS.

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

Так в чём же заключалась наша ошибка? Думаю, всё дело в несовершенной методологии тестирования. Мы пытались судить «на глаз», вместо того чтобы:

  1. Определить чёткий набор критериев: использование памяти, скорость и фактическая производительность блокировщика контента в браузере.
  2. И, что наиболее важно, научиться точно измерять эти показатели. Не визуально оценивая монитор активности или top, а используя нормальный профилировщик.

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

Понравился пост?
27 596 27596 отзывов
Отлично!

AdGuard для Windows

AdGuard для Windows — это не просто «ещё один блокировщик». Это многоцелевой инструмент, который блокирует рекламу и доступ к опасным сайтам, ускоряет загрузку страниц и защищает детей от взрослого контента.
Скачивая программу, вы принимаете условия Лицензионного соглашения
Узнать больше
AdGuard для Windows, версия 7.21, пробный период 14 дней
27 596 27596 отзывов
Отлично!

AdGuard для Mac

В отличие от других блокировщиков, AdGuard разработан с учётом специфики операционной системы macOS. Он не только блокирует рекламу в Safari и других браузерах, но и защищает вас от слежки, фишинга и мошенничества в сети.
Скачивая программу, вы принимаете условия Лицензионного соглашения
Узнать больше
AdGuard для Mac, версия 2.17, пробный период 14 дней
27 596 27596 отзывов
Отлично!

AdGuard для Android

AdGuard для Android — это идеальное решение для Android-устройств. В отличие от других блокировщиков, AdGuard не требует root-доступа и позволяет управлять трафиком любых приложений на вашем устройстве.
Скачивая программу, вы принимаете условия Лицензионного соглашения
Узнать больше
Отсканируйте код, чтобы загрузить
Используйте любой сканер QR-кода на вашем устройстве.
AdGuard для Android, версия 4.11, пробный период 14 дней
27 596 27596 отзывов
Отлично!

AdGuard для iOS

Лучший блокировщик рекламы для iPhone и iPad. AdGuard устраняет рекламу в Safari, защищает ваши данные и ускоряет загрузку страниц. AdGuard для iOS использует новейшую технологию блокировки, которая обеспечивает непревзойденное качество фильтрации и позволяет применять множество различных фильтров одновременно
Скачивая программу, вы принимаете условия Лицензионного соглашения
Узнать больше
Отсканируйте код, чтобы загрузить
Используйте любой сканер QR-кода на вашем устройстве.
AdGuard для iOS, версия 4.5
27 596 27596 отзывов
Отлично!

AdGuard Content Blocker

AdGuard Content Blocker устраняет все виды рекламы в мобильных браузерах, которые поддерживают технологию блокировки контента, — а именно Samsung Internet и Яндекс. Браузер. Его функции ограничены по сравнению с AdGuard для Android, но он бесплатен, прост в установке и эффективен
Скачивая программу, вы принимаете условия Лицензионного соглашения
Узнать больше
AdGuard Content Blocker, версия 2.8
27 596 27596 отзывов
Отлично!

Браузерное расширение AdGuard

AdGuard — самое быстрое и легкое браузерное расширение для блокировки всех типов рекламы! Выбирайте AdGuard для быстрого и безопасного серфинга без рекламы.
Браузерное расширение AdGuard, версия 5.1
27 596 27596 отзывов
Отлично!

Помощник AdGuard

Дополнительное браузерное расширение для десктопных приложений AdGuard. Даёт доступ к таким функциям в браузере, как блокировка отдельных элементов, занесение сайта в белый список или отправление отчёта.
Помощник AdGuard, версия 1.4
27 596 27596 отзывов
Отлично!

AdGuard Home

AdGuard Home — это решение для блокировки рекламы и трекеров во всей сети. Установите его один раз на роутер, и все устройства в доме будут защищены. Дополнительные программы не потребуются. Это особенно важно для умных устройств, которые могут угрожать вашей конфиденциальности
AdGuard Home, версия 0.107
27 596 27596 отзывов
Отлично!

AdGuard Pro для iOS

AdGuard Pro для iOS включает все расширенные функции защиты от рекламы. Он предлагает те же инструменты, что и платная версия AdGuard для iOS. Отлично справляется с блокировкой рекламы в Safari и позволяет настраивать параметры DNS. Блокирует рекламу в браузерах и приложениях, защищает детей от нежелательного контента и сохраняет личные данные в безопасности
Скачивая программу, вы принимаете условия Лицензионного соглашения
Узнать больше
AdGuard Pro для iOS, версия 4.5
27 596 27596 отзывов
Отлично!

AdGuard для Safari

Расширения, блокирующие рекламу в Safari, переживают не лучшие времена с тех пор, как компания Apple вынудила всех использовать новый SDK. Познакомьтесь с нашим легко настраиваемым и молниеносным приложением!
AdGuard для Safari, версия 1.11
27 596 27596 отзывов
Отлично!

AdGuard для Android TV

AdGuard для Android TV — единственное приложение, которое блокирует рекламу, защищает ваши данные и действует как фаервол для Smart TV. Получайте предупреждения о веб-угрозах, используйте безопасный DNS, а ваш трафик будет зашифрован. Смотрите любимые сериалы безопасно и без рекламы!
AdGuard для Android TV, версия 4.11, пробный период 14 дней
27 596 27596 отзывов
Отлично!

AdGuard для Linux

AdGuard для Linux — это первый в мире блокировщик рекламы, работающий на уровне системы. Блокируйте рекламу и трекеры, выбирайте предустановленные фильтры или добавляйте свои — всё через интерфейс командной строки
AdGuard для Linux, версия 1.0
27 596 27596 отзывов
Отлично!

AdGuard Temp Mail

Ваш временный почтовый ящик, чтобы на основную почту не приходил спам
27 596 27596 отзывов
Отлично!

AdGuard VPN

66 локаций по всему миру

Доступ к любому контенту

Надёжное шифрование

Без логирования

Быстрое соединение

Поддержка 24/7

Попробовать
Скачивая программу, вы принимаете условия Лицензионного соглашения
Узнать больше
27 596 27596 отзывов
Отлично!

AdGuard DNS

AdGuard DNS – это альтернативный способ заблокировать рекламу, защитить личные данные и оградить детей от взрослых материалов. Он прост в настройке и использовании и обеспечивает необходимый минимум защиты от рекламы, трекинга и фишинга, независимо от платформы.
27 596 27596 отзывов
Отлично!

AdGuard Mail

Сохраняйте анонимность, избавьтесь от спама и защитите почту с нашими алиасами и временными адресами. Наш сервис пересылки бесплатный и подходит для всех операционных систем
27 596 27596 отзывов
Отлично!

AdGuard Wallet

Безопасный и приватный криптокошелёк: полностью контролируйте активы, управляйте несколькими кошельками и найдите тысячи криптовалют для хранения, отправки и обмена
Загрузка AdGuard началась Стрелка указывает на файл: нажмите на него, и установка начнётся Выберите «Открыть», нажмите «OK» и дождитесь загрузки файла. В открывшемся окне перетащите значок AdGuard в папку «Приложения». Спасибо за выбор AdGuard! Выберите «Открыть», нажмите «OK» и дождитесь загрузки файла. В открывшемся окне нажмите «Установить». Спасибо за выбор AdGuard!
AdGuard есть и в мобильном варианте