CDR (Clock Data Recovery)
Clock Data Recovery (CDR) — это процесс восстановления тактового сигнала и восстановления данных в цифровых коммуникационных системах. В оптических сетях и высокоскоростных цифровых интерфейсах, таких как Ethernet, InfiniBand, Fibre Channel и других, передача данных осуществляется с использованием серийного битового потока. Однако тактовые сигналы, которые синхронизируют передачу и прием данных, могут быть искажены или потеряны в процессе передачи по оптоволоконному каналу или из-за других факторов, таких как джиттер или шум.
Применение CDR
CDR предназначен для восстановления источника тактового сигнала из полученных данных и корректировки любых искажений, связанных с тактовой частотой и фазой. Он выполняет синхронизацию приемника с передатчиком путем извлечения тактового сигнала из входных данных и генерации точного тактового сигнала, который синхронизирует прием и передачу данных. В результате, CDR позволяет эффективно восстанавливать источник тактовой информации и обеспечивает стабильную и надежную передачу данных через оптические каналы и другие цифровые интерфейсы.
CDR имеет широкое применение в высокоскоростных оптических системах связи, где точная синхронизация тактового сигнала критически важна для обеспечения надежной передачи данных. Он также используется в цифровых системах передачи данных на короткие расстояния, таких как внутренние компьютерные сети, где требуется точная синхронизация тактового сигнала для согласования скорости передачи данных между отправителем и приемником.
Принцип работы CDR
CDR (Clock Data Recovery) работает путем восстановления тактового сигнала из входных данных и синхронизации приемника с передатчиком. Вот общая схема работы CDR:
- Детекция начала бита. CDR анализирует входные данные для определения момента начала каждого бита. Это может выполняться с использованием методов, таких как детекция уровня сигнала или анализ краев.
- Восстановление тактового сигнала. Используя информацию о начале бита, CDR восстанавливает тактовый сигнал, который синхронизирует прием и передачу данных. Это может быть сделано с помощью фазового блокирования петли (PLL), который создает стабильный тактовый сигнал на основе входных данных.
- Фильтрация и декодирование данных. CDR выполняет фильтрацию и усиление входных данных, чтобы минимизировать шум и искажения. Затем данные декодируются в соответствии с используемым кодированием, чтобы получить исходные биты.
- Оценка джиттера. CDR также может анализировать уровень джиттера (несовершенства тактового сигнала) во входных данных и применять коррекции для компенсации джиттера и повышения качества сигнала.
- Автоматическая регулировка параметров. CDR обычно обладает возможностью автоматической настройки своих параметров для оптимальной работы в различных условиях передачи данных. Это позволяет адаптировать работу CDR к изменяющимся условиям сети или качеству сигнала.
В результате работы CDR обеспечивается точная синхронизация тактового сигнала между приемником и передатчиком, что позволяет надежно восстанавливать данные и минимизировать ошибки в передаче информации. CDR играет важную роль в обеспечении стабильной и эффективной передачи данных в высокоскоростных оптических системах связи и других цифровых коммуникационных сетях.
Заключение
CDR обеспечивает стабильность и надежность передачи данных, минимизируя искажения, связанные с тактовым сигналом. Он позволяет эффективно использовать доступную пропускную способность оптических каналов и обеспечивает высокую скорость передачи данных с минимальной потерей информации. Таким образом, CDR является важной технологией, применяемой в современных оптических сетях и высокоскоростных цифровых интерфейсах для обеспечения стабильной и эффективной передачи данных.
База знаний
Asterisk может сохранять CDR записи в базе данных MySQL как альтернативу текстовых CSV файлов и других форматов баз данных.
Как загрузить cdr_mysql
Обязанный лицензированию библиотек MySQL клиента, приложение MySQL биллинга – больше не интегрированная часть стандартного распределения Астериска. Сейчас оно находится в asterisk-addons CVS директории.
# cd /usr/src
# svn checkout http://svn.digium.com/svn/asterisk/branches/1.2 asterisk-1.2
- В Linux, базированном на RPM, вы должны проверить наличие MySQL, например так:
- Для debian или других dpkg-пободных систем, проверьте так:
- В FreeBSD, вы найдете MySQL в портах библиотеки, /usr/ports/databases/mysql4-server
Компиляция
Запустите «make clean», затем «make», затем «make install» в добавленной директории, которую вы создали. Если произойдут неисправности из-за жалобы на отсутствующий файл “asterisk.h”, вы можете как скопировать этот файл из директории Астериска, так и создать непостоянную ссылку («ln -s . «) для /usr/src/Asterisk, которая укажет на директорию источника астериска.
Примерный конфигурационный файл, который можно найти на страничке cdr_mysql.conf.
Скопируйте Примерный конфигурационный файл в /etc/asterisk/cdr_mysql.conf и отредактируйте его в соответсвии вашим требованиям. Затем отредактируйте modules.conf для загрузки cdr_addon_mysql.so и в конце перезапустите Астериск; перед перезапуском вы должны, как водится, проверить, что ваши cdr таблицы были созданы корректно и доступны для username и пароля, которые вы определили.
Таблицы, определенные для cdr_mysql Астериска
Это описание БД, которую вы используете для установки в Mysql для поддержки биллинга.
Создание базы данных
mysql —user=root —password=password -h dbhost
CREATE DATABASE asterisk;
GRANT INSERT
ON asterisk.*
TO asterisk@localhost
IDENTIFIED BY ‘yourpassword’;
CREATE TABLE `cdr` (
`calldate` datetime NOT NULL default ‘0000-00-00 00:00:00’,
`clid` varchar(80) NOT NULL default »,
`src` varchar(80) NOT NULL default »,
`dst` varchar(80) NOT NULL default »,
`dcontext` varchar(80) NOT NULL default »,
`channel` varchar(80) NOT NULL default »,
`dstchannel` varchar(80) NOT NULL default »,
`lastapp` varchar(80) NOT NULL default »,
`lastdata` varchar(80) NOT NULL default »,
`duration` int(11) NOT NULL default ‘0’,
`billsec` int(11) NOT NULL default ‘0’,
`disposition` varchar(45) NOT NULL default »,
`amaflags` int(11) NOT NULL default ‘0’,
`accountcode` varchar(20) NOT NULL default »,
`userfield` varchar(255) NOT NULL default »
);
ALTER TABLE `cdr` ADD INDEX ( `calldate` );
ALTER TABLE `cdr` ADD INDEX ( `dst` );
ALTER TABLE `cdr` ADD INDEX ( `accountcode` );
Пожалуйста заметьте, что права, предоставленные в GRANT выше – это самые малые, которые будут нужны пользователю Астериска. Чтобы позволить пользователю больше, чем просто добавить новые данные в таблицу, смотри MySQL manual on the topic
Для trunk версии начиная с 29 дек 2007 нужны права на чтение:
GRANT INSERT, SELECT .
потому что cdr_addon_mysql теперь делает DESC ‘cdr’; чтобы проверить поля таблицы.
Подсказка: Скопируйте и вставьте эту SQL команду в текстовый файл, сохраните под соответствующим именем, затем выполните следующую команду:
mysql —user=username —password=password databasename
CDR. Сохранить и приумножить

Очень часто, созданию базы данных CDR отводится мало места в описаниях настройки. Как правило, все сводится к цитате SQL команд и обещанию, что если кинуть ее в консоль то «все будет ОК».
К примеру, первая же ссылка в гугле рекомендует создать табличку таким образом:
CREATE TABLE `cdr` ( `calldate` datetime NOT NULL default '0000-00-00 00:00:00', `clid` varchar(80) NOT NULL default '', `src` varchar(80) NOT NULL default '', `dst` varchar(80) NOT NULL default '', `dcontext` varchar(80) NOT NULL default '', `channel` varchar(80) NOT NULL default '', `dstchannel` varchar(80) NOT NULL default '', `lastapp` varchar(80) NOT NULL default '', `lastdata` varchar(80) NOT NULL default '', `duration` int(11) NOT NULL default '0', `billsec` int(11) NOT NULL default '0', `disposition` varchar(45) NOT NULL default '', `amaflags` int(11) NOT NULL default '0', `accountcode` varchar(20) NOT NULL default '', `userfield` varchar(255) NOT NULL default '' ); ALTER TABLE `cdr` ADD INDEX ( `calldate` ); ALTER TABLE `cdr` ADD INDEX ( `dst` ); ALTER TABLE `cdr` ADD INDEX ( `accountcode` );
Сразу можно обратить внимание, что как минимум два индекса в базе бесполезны. Это calldate и accountcode. Первый в силу того, что при ежесекундном добавлении записей, размер индекса будет равен количеству записей в самой базе. Да, этот индекс отсортирован, и можно применить некоторые способы к ускорению поиска, но будет ли он эффективен? Второй индекс (accountcode) практически никогда и никем не используется. В качестве подопытной базы — база с 80 млн записей.
SELECT * FROM CDR WHERE src=***** AND calldate>'2016-06-21' AND calldate
Почти 10 минут ожидания.
Другими словами, создание отчетов становится проблемой. Конечно, табличку можно ратировать, но зачем такие жертвы, если достаточно провести оптимизацию.
Внимание! Никогда не делай это в продакшене! Только на копии базы! База лочится на время от 1 часа до нескольких и возможны потери данных при аварийном завершении!
Итак, два шага к успеху эффективного хранения CDR:
- Разбить на партиции, чтобы ускорить выборку по периодам
- Эффективное индексирвоание
Собственно есть два распространенных варианта — MyISAM и INNODB. Холиварить на эту тему можно бесконечно долго, но сравнение движков на реальной базе дало перевес в пользу MyISAM.
Причин тут несколько:
- При чистой настройке сервера неопытным админом, именно MyISAM более корректно работает при индексации больших объемов. В то время, как INNODB требует тюнинга. В противном случае можно увидеть интересные ошибки о том, что индекс не может быть перестроен
- MyISAM при включении опции FIXED ROW приобретает дополнительные свойства, а именно:
- Устойчивость к сбоям даже при падении сервера
- Возможность читать файл напрямую из внешнего приложения, минуя сервер MySQL, что бывает полезно
- Скорость обращения к рандомным строкам выше, за счет того, что все строки имеют одинаковую длину
Остановимся на нем.
Шаг 1. Партиции.
В виду того, что мы либо дополняем базу, либо читаем из нее, эффективно раз и навсегда поделить базу на файлы, чтобы уменьшить возможное количество обращений, при чтении определенных временных промежутков. Естественно, разбивать базу нужно по какому-то ключу. Но по какому? Определенно, это должно быть время, но эффективно ли бить базу по calldate? Думаю нет, поэтому вводим дополнительное поле, которое нам также пригодиться и в следующем шаге. А именно — дату. Просто дату, без времени.
Вводим дополнительное поле date, и делаем очень простой триггер на табличку, before update cdr:
BEGIN SET new.date=DATE(new.calldate); END
Таким образом, в это поле у нас попадет только дата. И сразу разбиваем табличку на партиции по годам:
ALTER TABLE cdr PARTITION BY RANGE (YEAR(date)) (PARTITION old VALUES LESS THAN (2015) ENGINE = MyISAM, PARTITION p2015 VALUES LESS THAN (2016) ENGINE = MyISAM, PARTITION p2016 VALUES LESS THAN (2017) ENGINE = MyISAM, PARTITION p2018 VALUES LESS THAN (2018) ENGINE = MyISAM, PARTITION p2019 VALUES LESS THAN (2019) ENGINE = MyISAM, PARTITION p2020 VALUES LESS THAN (2020) ENGINE = MyISAM, PARTITION p2021 VALUES LESS THAN (2021) ENGINE = MyISAM, PARTITION p2022 VALUES LESS THAN (2022) ENGINE = MyISAM, PARTITION p2023 VALUES LESS THAN (2023) ENGINE = MyISAM, PARTITION pMAXVALUE VALUES LESS THAN MAXVALUE ENGINE = MyISAM)
Готово, теперь если мы будем выборку делать с указанием диапазона даты, то MySQL не придется лопатить всю базу за все года. Небольшой плюсик уже есть.
Шаг 2. Индексируем базу.
Собственно, это самый важный шаг. Эксперименты показывают, что в 90% случаев возникает необходимость в индексах на 3 столбцах (по мере необходимости):
date
MySQL может использовать только один индекс за раз, поэтому некоторые администраторы пытаются создавать составные индексы. Эффектность их не очень высока, потому что как правило приходиться выбирать диапазоны, а в этом случае составные индексы игнорируются MySQL, т.е. происходит FullScan. Исправить поведение скуля мы не можем, но можем сделать так, чтобы количество строк для сканирования было минимальным и дать движку выбор, какой индекс использовать. С одной стороны, нам необходима максимальная подробность индекса, с другой стороны нам нужно затратить как можно меньше операций, чтобы получить диапазон, который мы будем перебирать. Именно поэтому и рекомендую использовать индекс по полю date, а не calldate. Количество элементов в индексе будет равно количеству дней, с момента начала ведения базы, что позволит базе быстро перейти к нужным строчкам.
Есть еще один споcоб помочь базе — сделать так, чтобы она могла вычислить положение строки в файле еще ДО открытия файла. Именно для этого можно использовать FIXED ROW. Положение строки в файле будет вычисляться умножение номера строки на длину строки, а не перебором. Естественно, у того подхода есть жертвы — база будет занимать на диске значительно больше места. Вот к примеру:

Размер базы вырос с 18 Гб до 53,8 Гб. Делать или нет — выбор каждого админа, но если место на сервере позволяет, то это будет еще одним плюсиком.
src,dst
Тут несколько меньше простора для оптимизаций. Точнее, один момент:
Если у вас не используется текстовых номеров, например в софтфонах, то данные поля можно преобразовать в BigInt, что тоже очень хорошо скажется на индексировании и выборке. Но если, Вы как и мы, используете текстовые номера, то данная оптимизация не для вас и придется смириться с более низкой производительностью.
В качестве вишенки на торте — подчищаем те поля, которые нас не интересуют и выставляем размер полей в ожидаемый для нашего случая. У меня получилось вот так:

Ну и финальный запрос:
SELECT * FROM CDR WHERE src=***** AND date='2016-06-21'; /* Affected rows: 0 Найденные строки: 4 Предупреждения: 0 Длительность 1 query: 0,577 sec. */
Прирост на два порядка.
Для примера еще, по диапазону:
SELECT * FROM CDR WHERE src=***** AND date>'2016-09-01' AND date
База asteriskcdrdb и как с ней работать?
Как и любая современная АТС, Asterisk имеет свою встроенную систему хранения истории звонков – CDR (Call Detail Record). Она используется для снятия статистики, ведения отчетности, прослушивания вызовов или подсчета биллинговых показателей.
В Asterisk для этого создана база данных asteriskcdrdb, в которой существует таблица cdr. Давайте рассмотрим как пользоваться данной таблицей и ее структуру.
[root@asterisk]# mysql
После успешного подключения, необходимо выбрать для работы базу данных asteriskcdrdb:
mysql> use asteriskcdrdb; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed
Давайте убедимся, что у нас есть таблица cdr. Выполним это, как указано ниже:
mysql> show tables; +-------------------------+ | Tables_in_asteriskcdrdb | +-------------------------+ | cdr | | cel | +-------------------------+ 2 rows in set (0.00 sec)
На данном этапе мы убедились, что у нас есть база данных asteriskcdrdb, в которой находится таблица cdr. Давайте попробуем посмотреть входящие звонки из города за сегодня (дата написания статьи 18 марта 2016 года), в период с 12:00 до 12:10, т.е за 10 минут:
SELECT `dst` , `src` , `duration` , `calldate` , `recordingfile` FROM `cdr` WHERE `calldate` >= '2016-03-18 12:00:00' AND `calldate` 3; +-----+-------------+----------+---------------------+----------------------------------------------------------------+ | dst | src | duration | calldate | recordingfile | +-----+-------------+----------+---------------------+----------------------------------------------------------------+ | 113 | 84991111111 | 140 | 2016-03-18 12:00:36 | external-113-84991111111-20160318-115933-1458291573.157155.wav | | 104 | 89162222222 | 81 | 2016-03-18 12:01:33 | external-104-89162222222-20160318-120133-1458291693.157169.wav | +-----+-------------+----------+---------------------+----------------------------------------------------------------+ 2 rows in set (0.00 sec)
В вышеуказанном примере, в SQL запросе указано LENGTH( `src` ) >3. Столбец ‘src’ – показывает номер звонящего (source – источник). Это сделано для того, чтобы исключить внутренние звонки, так как у нас используется трехзначная нумерация. Тем самым, мы получаем в результате данные, с которыми затем можем работать. Например, отправить на почту в виде отчета. Ниже рассмотрена структура таблицы cdr в базе данных asteriskcdrdb:
| Столбец | Пример значения | Описание |
|---|---|---|
| calldate | 2016-03-18 12:00:36 | Дата и время звонка |
| clid | “Oleg Ivanov” | В данное поле попадает полное CallerID (CLID, CID), которое состоит из имени и номера звонящего. Это доступно только для считывания. |
| src | 84991111111 | Номер звонящего в конструкции CallerID (CNUM). Это доступно только для считывания. |
| dst | 113 | Номер назначения для звонка. Это доступно только для считывания. |
| dcontext | CustomContext1 | Контекст для обработки. Это доступно только для считывания. |
| channel | SIP/0002B2356854-a34bh3ef | Канал, через который поступил звонок |
| dstchannel | SIP/0004F6675969-97836bb0 | Канал, через который ушел исходящий звонок |
| lastapp | Dial, Busy, Congestion | Приложение, которое последним отработало этот вызов перед попаданием в таблицу cdr |
| lastdata | SIP/0004F6675969,30,tT | Аргумент, который был передан приложению, которое отработало вызов последним (lastapp) |
| duration | 75 | Количество секунд от начала (отметка start) до окончания вызова (отметка end) |
| billsec | 67 | Количество секунд от ответа (отметка answer) до окончания вызова (отметка end). Данное значение всегда меньше значения duration, и отражает длительность самого разговора, что важно для подсчета стоимости. |
| disposition | ANSWERED, BUSY, NO ANSWER, FAILED | Результат звонка |
| amaflags | OMIT, BILLING, DOCUMENTATION, Unknown | Метка Automatic Message Accounting (AMA) – автоматический учет стоимости вызова. |
| accountcode | 23232 | Идентификатор аккаунта. Данное значение пустое по умолчанию, и определяется параметрами конкретного пользователя. |
| uniqueid | 1458291693.157169 | Уникальный идентификатор звонка |
| userfield | Пользовательское поле. Здесь можно передавать что угодно, добавляя данные в этот столбец при работе с вызовом внутри контекста обработки. | |
| did | 4996491913 | DID (Direct Inward Dialing). На основании DID вызова на Asterisk осуществляется его маршрутизация (это значение приходит от провайдера). |
| recordingfile | external-113-84991111111-20160318-115933-1458291573.157155.wav | Имя файла, содержащего запись разговора. В данном имени можно проследить путь к файлу в файловой структуре сервера. |
| cnum | 84991111111 | Номер звонящего в структуре CallerID. |
| cnam | Oleg Ivanov | Имя звонящего в структуре CallerID. |
Теперь, когда вы понимаете принцип формирования запросов к базе данных и ее структуру, вы можете без труда формировать собственные отчеты. Например, ежедневный отчет о количестве входящих звонков за текущий день на почту. Это реализуется средствами php скрипта и добавления расписания через cron. Поговорим об этом в следующей статье
Любое использование материалов сайта возможно только с разрешения автора и с обязательным указанием источника.