В 14 году я показал как можно собирать трафик не через коллекторы (ip/netflow и т.д), а через аккаунтинг радиуса:
http://forum.nodeny.com.ua/index.php?topic=2495.0Эта фича интересна тем, что аккаунтинг как раз и предназначен для сбора трафика, а то, что мы используем его как продление авторизации - это побочный бонус. Таким образом, раз данные о трафике к нам приходят - значит не надо тратить ресурсы на их подсчет модулем collectors. Конечно, у нас не будет данных по детализации (на какие ip были запросы), но многим она и не нужна.
В чем сложность считать трафик через аккаунтинг? Дело в том, что радиус присылает нам общий трафик на сессию, а не то, сколько скачал абонент за последний срез. Допустим в 10:41 радиус прислал 100 мб, а в 10:42 - 101 мб. Таким образом, биллинг должен увеличить счетчики трафика на 1 мб (101 - 100). Следовательно, нужно где-то хранить данные трафика за предыдущий срез. Для этого и была придумана таблица ses_traf.
Но как оказалось, при большом количестве запросов mysql начинает жестко тупить. Поэтому то, что написано по ссылке выше, уже не будем использовать. А слегка поменяем схему. Теперь в аккаунтинге процедуры mysql просто будут писать текущие значения трафика, а начислять трафик будет модуль ядра ses_traf.
Необходимо немного поменять структуру таблицы ses_traf:
DROP TABLE ses_traf;
CREATE TABLE `ses_traf` (
`id` bigint(21) NOT NULL AUTO_INCREMENT,
`uid` int(10) unsigned NOT NULL,
`ses_id` varchar(32) NOT NULL DEFAULT '',
`time` int(10) unsigned NOT NULL DEFAULT '0',
`traf_in` bigint(12) unsigned NOT NULL DEFAULT '0',
`traf_out` bigint(12) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `time` (`time`)
) ENGINE=MyISAM AUTO_INCREMENT=1;
По сути в нее внесли 2 изменения: добавили поле uid (id абона) и убрали уникальность ses_id - теперь эта таблица хранит не последние данные по трафику, а по сути лог трафика, но лог с накоплением трафика, который требует обработки модулем ses_traf.
Чтобы данные попадали в таблицу ses_traf, нужно изменить процедуру радиуса radupdate, примерно так:
CREATE DEFINER=`root`@`localhost` PROCEDURE `radupdate`(IN login VARCHAR(64), IN ip VARCHAR(16),
IN properties VARCHAR(255), IN ses VARCHAR(32), IN trafin BIGINT(20), IN trafout BIGINT(20))
BEGIN
DECLARE usr_id INT;
DECLARE usr_ip VARCHAR(15) DEFAULT NULL;
SELECT id INTO usr_id FROM users WHERE name=login LIMIT 1;
SELECT get_ip(usr_id) INTO usr_ip;
CALL set_auth(usr_ip, CONCAT('mod=pppoe;',REPLACE(properties,':','')));
INSERT INTO ses_traf SET ses_id=ses, traf_in=trafin, traf_out=trafout, time=UNIX_TIMESTAMP(), uid=usr_id;
END
По сути в параметры процедуры добавлено 3 параметра: сессия, входящий и исходящий трафик + строка:
INSERT INTO ses_traf SET ses_id=ses, traf_in=trafin, traf_out=trafout, time=UNIX_TIMESTAMP(), uid=usr_id;
Кстати, привязка работает именно к сессии. У клиента может быть несколько сессий с разным трафиком.
Создание X-таблицы для лога трафика NoDeny не нужно - это также делается в модуле ses_traf.
Конфиг радиуса:
authorize_check_query = "call radcheck('%{User-Name}')"
authorize_reply_query = "call radreply('%{User-Name}')"
accounting {
query = "call radupdate('%{User-Name}','%{Framed-IP-Address}',\
'user=%{Calling-Station-Id};nas=%{NAS-IP-Address};ses=%{Acct-Session-Id}','%{Acct-Session-Id}',\
(%{%{Acct-Input-Gigawords}:-0} * POWER(2, 32)) + %{%{Acct-Input-Octets}:-0},\
(%{%{Acct-Output-Gigawords}:-0} * POWER(2, 32)) + %{%{Acct-Output-Octets}:-0})"
type {
start {
query = "call radupdate('%{User-Name}','%{Framed-IP-Address}',\
'user=%{Calling-Station-Id};nas=%{NAS-IP-Address};ses=%{Acct-Session-Id}','%{Acct-Session-Id}',\
(%{%{Acct-Input-Gigawords}:-0} * POWER(2, 32)) + %{%{Acct-Input-Octets}:-0},\
(%{%{Acct-Output-Gigawords}:-0} * POWER(2, 32)) + %{%{Acct-Output-Octets}:-0})"
}
}
}
accounting_update_query = "call radupdate('%{User-Name}','%{Framed-IP-Address}',\
'user=%{Calling-Station-Id};nas=%{NAS-IP-Address};ses=%{Acct-Session-Id}','%{Acct-Session-Id}',\
(%{%{Acct-Input-Gigawords}:-0} * POWER(2, 32)) + %{%{Acct-Input-Octets}:-0},\
(%{%{Acct-Output-Gigawords}:-0} * POWER(2, 32)) + %{%{Acct-Output-Octets}:-0})"
Запускаем модуль ядра ses_traf и наслаждаемся.