DoS своими силами: К чему приводит бесконтрольный рост таблиц в базе данных

в 9:27, , рубрики: dos, radius, авторизация, Блог компании Латера Софтвер, инфраструктура, ит-инфраструктура, проблемы

DoS своими силами: К чему приводит бесконтрольный рост таблиц в базе данных - 1

Биллинг — сложная система, одним из важнейших компонентов которой является база данных. В ней содержится множество разнообразных таблиц, которые со временем разрастаются до больших размеров.

Для того, чтобы это рост не замедлял работу базы, в Oracle, PostgreSQL и других СУБД существует эффективный механизм секционирования (partitioning) — однако его не всегда можно применять. К примеру, он отсутствует в относительно бюджетной редакции системы Oracle Standard Edition.

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

Предыстория

Биллинг «Гидра» используют операторы связи, а значит, одной из самых важных и крупных таблиц в базе является та, которая отвечает за хранение данных о PPP-сессиях и CDR абонентов провайдеров интернета или телефонии. В этой таблице хранятся данные о начале, завершении и времени ее последнего обновления, а также информация об абоненте, инициировавшем ее, например, IP-адресе, с которого он установил соединение.

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

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

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

Все плохо

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

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

У этого конкретного оператора абоненты попадали в сеть по VPN, а значит, им нужно было получить доступ к VPN-серверу, который уже по протоколу RADIUS обращался к базе данных.

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

При таймауте обработки запроса VPN-сервер посылает еще пару запросов на авторизацию — и для их обработки опять необходимо прочитать данные из той самой огромной таблицы. И только после этого абонент увидит сообщение об отказе в доступе. Естественно, что получив такое сообщение, пользователь пытается установить соединение повторно, и все повторяется вновь. Таким образом возникла ситуация с настоящим DoS сервера RADIUS.

Что делать

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

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

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

В итоге, когда таблица с сессиями сократилась в размере до 30 млн строк, авторизация абонентов вновь заработала, и мы смогли отключить автономный режим работы RADIUS-сервера.

Уроки

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

Теперь при обнаружении потенциально опасной ситуации, подобной описанное выше, создается заявка в службу поддержки «Латеры», с которой мы детально разбираемся.

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

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

Если описывать схему кратко, то каждый сервер доступа состоит из нескольких компонентов:

  • База данных с профилями абонентов и данными о потребленных услугах.
  • Наше приложение под кодовым названием HARD. Оно отвечает на HTTP-запросы, которые идут от следующего компонента.
  • FreeRADIUS — непосредственно сервер, реализующий стандартный AAA-протокол — RADIUS. Он непосредственно общается с абонентской сетью и переводит запросы из бинарного формата в обычный HTTP+JSON для HARD.

Базы данных всех AAA-серверов (это MongoDB) объединены в группу с одним основным узлом (master) и двумя подчиненными (slave). Все запросы из абонентской сети идут на один AAA-сервер, при этом необязательно и даже нежелательно, чтобы им был сервер с основной БД.

Если что-то пойдет не так, и один из компонентов откажет, то, абоненты не потеряют доступ к услугам. Скорее всего, они вообще ничего не заметят.

Кроме того, мы продолжаем следить за размером таблиц, в том числе отслеживаем объём таблицы сессий — никто не застрахован от роста данных в неархивный период.

На сегодня все, спасибо за внимание! Не забывайте подписываться на наш блог.

Автор: Латера Софтвер

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js