Биллинговая система Nodeny
19 Апреля 2024, 21:57:28 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
Новости: Прекращена поддержка версии Nodeny 49
 
   Начало   Помощь Поиск Войти Регистрация  
Страниц: [1] 2 3 4
  Печать  
Автор Тема: Deadlock-и, дубликаты ip и прочая хрень  (Прочитано 15294 раз)
Efendy
Администратор
Спец
*****

Карма: 138
Offline Offline

Сообщений: 4782



Просмотр профиля
« : 23 Декабря 2017, 18:20:49 »

Время от времени я вижу жалобы на то, что бывают разного рода глюки с выдачей динамических ip. Я тут хорошо покрутил все и кажется понял в чем проблема. На самом деле основные проблемы 2:

1) deadlock-и в mysql - это когда некоторые запросы блокируют друг-друга и из-за этого не дают выполняться другим
2) бывает, что ip на nas-е не соответствует ip, которое светится в биллинге

Насчет deadlock-ов. Причин тут несколько:
1) сука тупой mysql. Вот реально гадина, я тебя всегда защищал, но ты впадаешь в лок на запросах, которые ну никак логически не должны приводить к такому
2) большая нагрузка

Начнем с нагрузки. Старайтесь выносить такие модули ядра как сбор трафика и заглушка на другой сервер. Особенно заглушка ибо на нее бывает льется столько трафика, что отжирает 100% проца. Если нет возможности вынести - хотя бы ограничьте количество сессий с одного ip на заглушку.

Что касается mysql. Мне пришлось кординально переделать процедуру get_ip. Я сделал такие 2 серьезных изменения:
1) сделал код примитивным и очень избыточным, что бы все sql были максимально нежными. Процедура стала выглядеть тупо, не показывайте ее профи))
2) основной затык был в выборе незанятого динамического ip. Дело в том, что mysql при большом количестве запросов выдавало одну и туже свободную запись, в этом проблемы нет, это разруливалось, но из-за такой коллизии сильно росла нагрузка. Я бы мог сделать выборку и из нее выбрать случайную строку, но mysql в этом случае создает временную таблицу, а это тоже плохо. Поэтому я поступил хитро: в таблице ip (ip_pool) я физически перегруппировую записи по типу, тегам и т.д. Для этого я создал процедуру normalize_ippool:

Код:
DROP FUNCTION IF EXISTS `normalize_ippool`;
DELIMITER $$
CREATE FUNCTION `normalize_ippool` ( )
    RETURNS TINYINT NO SQL
BEGIN
    DECLARE mid INTEGER UNSIGNED;

    CREATE TEMPORARY TABLE temp_ip_pool(
        id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
        ip_id BIGINT UNSIGNED NOT NULL,
        PRIMARY KEY (id)
    );

    SELECT MAX(id) into mid FROM ip_pool;
    UPDATE ip_pool SET id = id + mid;
    INSERT temp_ip_pool (SELECT NULL, id FROM ip_pool ORDER BY realip, type, tags);
    UPDATE ip_pool i JOIN temp_ip_pool t ON i.id = t.ip_id SET i.id = t.id;
    DROP TEMPORARY TABLE IF EXISTS temp_ip_pool;

    RETURN 1;
END$$
DELIMITER ;

Вызов этой функции я добавлю в админку при изменении любого ip/пула.

Благодаря этому в get_ip я сразу беру рандомную строку без предварительной выборки, зная только начальный и конечный id нужной группы.

Конечно, вам эта инфа особо не интересна, это я так для себя чтоб сохранилось в истории, ну и может теоретически кому-то понадобится.

Насчет дубликатов ip. Имеется ввиду такая ситуация: есть nas и есть сервер с биллингом. Сервер перезагружается, загружается больше 6 минут, запускает модуль ядра auth, который сразу освобождает все ip по таймауту. Он-то думает, что раз 6 минут не было аккаунтинга по данным ip - значит все сессии на насе кильнулись. Он же не знает, что просто небыло коннекта с nas. А на nas сесси-то висят, а биллинг считает ip свободными и выдает другим абонам. Когда я давно придумал схему с освобождением ip, я подумал, что сервер стартанет за пару минут. Кроме того, я не предусмотрел, что может быть разрыв канала больше чем 6 минут. Поэтому сейчас я установил таймаут в час (3600 секунд) в get_ip и set_auth:

Код:
DROP PROCEDURE IF EXISTS `set_auth`;
DELIMITER $$
CREATE PROCEDURE `set_auth` (IN usr_ip VARCHAR(15), IN auth_properties VARCHAR(255))
BEGIN
  DECLARE usr_id INT;
  SELECT uid INTO usr_id FROM ip_pool WHERE INET_ATON(usr_ip) = ip LIMIT 1;

  IF( usr_id > 0 ) THEN

    INSERT INTO auth_now SET
        ip = usr_ip,
        properties = auth_properties,
        start = UNIX_TIMESTAMP(),
        last = UNIX_TIMESTAMP()
    ON DUPLICATE KEY UPDATE
        properties = IF(auth_properties!='',auth_properties,properties),
        last = UNIX_TIMESTAMP();

    UPDATE ip_pool SET `release` = UNIX_TIMESTAMP() + 3600
        WHERE ip = INET_ATON(usr_ip) AND type = 'dynamic' LIMIT 1;
  END IF;
END$$
DELIMITER ;
Код:
DROP FUNCTION IF EXISTS `get_ip`;
DELIMITER $$
CREATE FUNCTION `get_ip` ( user_id INTEGER UNSIGNED )
    RETURNS VARCHAR(15) NO SQL
BEGIN
    DECLARE user_ip VARCHAR(15);
    DECLARE real_ip VARCHAR(15) DEFAULT 0;
    DECLARE row_cnt INTEGER;
    DECLARE ip_id INTEGER;
    DECLARE tries INTEGER DEFAULT 30;
    DECLARE id_min INTEGER;
    DECLARE id_max INTEGER;

    SELECT INET_NTOA(ip) INTO user_ip FROM ip_pool
        WHERE uid = user_id AND type='static' LIMIT 1;
    IF( user_ip IS NOT NULL ) THEN RETURN user_ip; END IF;

    SELECT 1 INTO real_ip FROM users_services WHERE uid = user_id AND tags LIKE '%,realip,%';

    SELECT id, INET_NTOA(ip) INTO ip_id, user_ip FROM ip_pool
        WHERE uid = user_id AND type = 'dynamic' AND realip = IF(real_ip>0,1,0)
        LIMIT 1;

    IF( ip_id IS NOT NULL) THEN
        UPDATE ip_pool SET `release` = UNIX_TIMESTAMP() + 3600
            WHERE id = ip_id AND uid = user_id;
        SELECT ROW_COUNT() INTO row_cnt;
        IF( row_cnt > 0 ) THEN RETURN user_ip; END IF;
    END IF;

    SELECT MAX(id), MIN(id) INTO id_max, id_min
        FROM ip_pool
        WHERE type = 'dynamic' AND realip = IF(real_ip>0,1,0);

    sel_ip: WHILE tries > 0 DO
        SELECT id, INET_NTOA(ip) INTO ip_id, user_ip
            FROM ip_pool
            WHERE uid = 0
                AND id >= (CEIL(RAND() * (id_max - id_min)) + id_min)
                AND id <= id_max
                LIMIT 1;
        IF( user_ip IS NOT NULL) THEN
            UPDATE ip_pool SET uid = user_id, `release` = UNIX_TIMESTAMP() + 3600
                WHERE id = ip_id AND uid = 0;
            SELECT ROW_COUNT() INTO row_cnt;
            IF( row_cnt > 0 ) THEN RETURN user_ip; END IF;
            SET tries = tries - 5;
        END IF;
        SET tries = tries - 1;
    END WHILE;

END$$
DELIMITER ;
« Последнее редактирование: 02 Февраля 2018, 13:12:55 от Efendy » Записан
Efendy
Администратор
Спец
*****

Карма: 138
Offline Offline

Сообщений: 4782



Просмотр профиля
« Ответ #1 : 23 Декабря 2017, 18:25:17 »

Если вы захотите все это проверить уже сейчас, то после создания всех трех процедур и функций, надо выполнить:

Код:
select normalize_ippool();

пока надо будет выполнять каждый раз если вы что-то будете менять в пуле ip
Записан
Efendy
Администратор
Спец
*****

Карма: 138
Offline Offline

Сообщений: 4782



Просмотр профиля
« Ответ #2 : 24 Декабря 2017, 10:10:50 »

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

Код:
DELETE FROM auth_now WHERE INET_ATON(ip) NOT IN (SELECT ip FROM ip_pool WHERE uid>0)

его лучше заменить на 2:

Код:
DELETE a FROM auth_now a LEFT JOIN ip_pool i ON INET_ATON(a.ip) = i.ip WHERE i.uid=0;
DELETE a FROM auth_now a LEFT JOIN ip_pool i ON INET_ATON(a.ip) = i.ip WHERE i.ip IS NULL;

(не тупо заменить, а сделать 2 Db->do(..))
я, конечно, это все включу в стандартную поставку
Записан
fix
Пользователь
**

Карма: 0
Offline Offline

Сообщений: 14


Просмотр профиля
« Ответ #3 : 04 Января 2018, 08:53:59 »

2) большая нагрузка:
Начнем с нагрузки. Старайтесь выносить такие модули ядра как сбор трафика и заглушка на другой сервер. Особенно заглушка ибо на нее бывает льется столько трафика, что отжирает 100% проца. Если нет возможности вынести - хотя бы ограничьте количество сессий с одного ip на заглушку.
Возможно у меня мало опыта, не видел чтоб заглушка отжирала 100% проца. Вы не ошиблись, может быть 100% ядра ? 100% ядра видел, а 100% всех 8-10-12-16 ядер не видел.

2) бывает, что ip на nas-е не соответсвует ip, которое светится в биллинге:
Насчет дубликатов ip. Имеется ввиду такая ситуация: есть nas и есть сервер с биллингом. Сервер перезагружается, загружается больше 6 минут, запускает модуль ядра auth, который сразу освобождает все ip по таймауту. Он-то думает, что раз 6 минут не было аккаунтинга по данным ip - значит все сессии на насе кильнулись. Он же не знает, что просто небыло коннекта с nas. А на nas сесси-то висят, а биллинг считает ip свободными и выдает другим абонам. Когда я давно придумал схему с освобождением ip, я подумал, что сервер стартанет за пару минут. Кроме того, я не предусмотрел, что может быть разрыв канала больше чем 6 минут. Поэтому сейчас я установил таймаут в час (3600 секунд) в get_ip и set_auth:
Подскажите пожалуйста, если например ночью упал канал, между биллингом и насом больше чем на час, например на 2-3-4 часа и в итоге ситуация с дубликатами и не соответствием айпи в биллинге и на насе станет возможной ? 
Перезагружать насы после восстановления связности ?
Записан
cojiict
Старожил
****

Карма: 0
Offline Offline

Сообщений: 341


Просмотр профиля Email
« Ответ #4 : 04 Января 2018, 09:11:47 »

Подскажите пожалуйста, если например ночью упал канал, между биллингом и насом больше чем на час, например на 2-3-4 часа и в итоге ситуация с дубликатами и не соответствием айпи в биллинге и на насе станет возможной ? 
Перезагружать насы после восстановления связности ?
noserver з певною періодичністю буде звертатись до бази даних і головне перевірити чи є між ними доступ.
Все ще залежить від типу авторизації. Буває radius треба синхронізувати
Записан
fix
Пользователь
**

Карма: 0
Offline Offline

Сообщений: 14


Просмотр профиля
« Ответ #5 : 09 Января 2018, 14:16:10 »

Подскажите пожалуйста, если например ночью упал канал, между биллингом и насом больше чем на час, например на 2-3-4 часа и в итоге ситуация с дубликатами и не соответствием айпи в биллинге и на насе станет возможной ? 
Перезагружать насы после восстановления связности ?
noserver з певною періодичністю буде звертатись до бази даних і головне перевірити чи є між ними доступ.
Все ще залежить від типу авторизації. Буває radius треба синхронізувати
После восстановления связности, с высокой вероятностью, связь между насом и биллингом восстановится "автоматически".
Не могли бы Вы более развернуто выразить вашу мысль, про типы авторизации и синхронизацию радиуса ?
Если мне не изменяет мой склероз, то дубликаты айпи, возможны при PPPoE авторизации, при отсутствии связности, некоторый промежуток времени(6 минут раньше, 60 минут сейчас), между насом и биллингом.
Так вот меня очень интересует, после вышеописанных изменений, возможно ли повторение ситуации с дублями айпи, если связности между насом и биллингом, не будет больше часа ?
Записан
Efendy
Администратор
Спец
*****

Карма: 138
Offline Offline

Сообщений: 4782



Просмотр профиля
« Ответ #6 : 09 Января 2018, 16:30:31 »

Если больше часа, то дубли будут. Есть возможность выявить такую ситуацию автоматически, просто надо подумать что делать в этом случае - в идеале послать команду дисконнекта, но mpd игнорит ее в аккаунтинге, поэтому надо привлекать модуль coa. Но отсутствие связи с базой в течение часа - это разве нормально?
Записан
fix
Пользователь
**

Карма: 0
Offline Offline

Сообщений: 14


Просмотр профиля
« Ответ #7 : 09 Января 2018, 17:24:15 »

Если больше часа, то дубли будут. Есть возможность выявить такую ситуацию автоматически, просто надо подумать что делать в этом случае - в идеале послать команду дисконнекта, но mpd игнорит ее в аккаунтинге, поэтому надо привлекать модуль coa. Но отсутствие связи с базой в течение часа - это разве нормально?
Не совсем нормально, отсутствие связи. Связность в случаях с удаленными насами, имеет свойство иногда падать, по различным причинам. Не рядовое, но вполне обычное событие.
Модуль радиус соа или вебсоа ?
В идеале, "синхронизация" между насом и биллингом и посыл дисконнекта, с "неправильными" айпи адресами.
Возможно, кто то предложит более изящное решение.
Записан
sever
Пользователь
**

Карма: 1
Offline Offline

Сообщений: 82


Просмотр профиля
« Ответ #8 : 24 Января 2018, 17:31:09 »

Кто-то в боевой режим уже внедрил?
Как успехи?
Записан
Efendy
Администратор
Спец
*****

Карма: 138
Offline Offline

Сообщений: 4782



Просмотр профиля
« Ответ #9 : 24 Января 2018, 17:38:39 »

Я этот топик написал по факту внедрения. Вроде там несколько тысяч онлайна было
Записан
kosmich
Пользователь
**

Карма: 1
Offline Offline

Сообщений: 90


Просмотр профиля
« Ответ #10 : 26 Января 2018, 14:00:13 »

Кто-то в боевой режим уже внедрил?
Как успехи?
Успехи внедрения из первого поста, работает отлично, 3-4К со старта авторизует и дальше, пока без проблем работает.
Записан
Cell
NoDeny
Спец
*

Карма: 52
Offline Offline

Сообщений: 1407



Просмотр профиля
« Ответ #11 : 26 Января 2018, 16:46:33 »

Может немного не в тему, но у меня вопрос - а в чем прикол динамических ip пулов? В чем  их преимущество перед статическими?
Экономия ip адресов была актуальна лет 10 назад, если не больше. В настоящее время нет никакой экономии от слова совсем. Ну может 10% от общего числа и то этот процент скорее плавающая в сторону уменьшения величина по причине поголовного использования абонентами домашних роутеров.
Да, могу придумать плюсы для всяких дота-дрочеров, которым ипы банят на игровых серверах... им лафа - а для провайдера какой смысл? Все это уже проходили с прозрачными прокси-серверами экономя 15% трафика, где они сейчас?
Вот и хочу понять в чем извращение с этими динамическими пулами. Кто-то может ответить аргументированно, без "А мне так хочется"?

Записан
Warlock
NoDeny
Старожил
*

Карма: 8
Offline Offline

Сообщений: 369


Просмотр профиля
« Ответ #12 : 26 Января 2018, 19:36:01 »

Мы всем клиентам даём внешние айпи. И как тут без динамики?
Записан
fet4
Старожил
****

Карма: 2
Offline Offline

Сообщений: 324


Просмотр профиля Email
« Ответ #13 : 05 Февраля 2018, 11:33:22 »

Периодические записи в логе freeradius такого рода
Код:
Sun Feb  4 08:53:43 2018 : Error: [sql] Couldn't update SQL accounting ALIVE record - Deadlock found when trying to get lock; try restarting transaction
Sun Feb  4 08:53:43 2018 : Error: rlm_sql_mysql: Cannot store result
Sun Feb  4 08:53:43 2018 : Error: rlm_sql_mysql: MySQL error 'Deadlock found when trying to get lock; try restarting transaction'
Mon Feb  5 01:32:00 2018 : Error: rlm_sql (sql) in sql_postauth: Database query error - Deadlock found when trying to get lock; try restarting transaction

Говорят о данной проблеме ?

В логе самого мускула пусто.
Записан
kosmich
Пользователь
**

Карма: 1
Offline Offline

Сообщений: 90


Просмотр профиля
« Ответ #14 : 05 Февраля 2018, 15:13:02 »

Периодические записи в логе freeradius такого рода
Код:
Sun Feb  4 08:53:43 2018 : Error: [sql] Couldn't update SQL accounting ALIVE record - Deadlock found when trying to get lock; try restarting transaction
Sun Feb  4 08:53:43 2018 : Error: rlm_sql_mysql: Cannot store result
Sun Feb  4 08:53:43 2018 : Error: rlm_sql_mysql: MySQL error 'Deadlock found when trying to get lock; try restarting transaction'
Mon Feb  5 01:32:00 2018 : Error: rlm_sql (sql) in sql_postauth: Database query error - Deadlock found when trying to get lock; try restarting transaction

Говорят о данной проблеме ?
С какой периодичностью такое в логе ?
Периодически, несколько строк, такое в логах раньше проскакивало и каких то ощутимых проблем небыло.
Если такое валит в логе "пачками" и постоянно, то да, началось.
Записан
Страниц: [1] 2 3 4
  Печать  
 
Перейти в:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.20 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!