wiki:SoftswitchFailOver

Version 11 (modified by alx, 8 years ago) ( diff )

Добавлено конфигурирование автоматического переключения на резерв

Вариант настройки отказоустойчивого сервера FreeSwitch

Исходные данные

Имеется ubuntu-16.04 c настроенным и работающим сервером FreeSwitch, установленным из нашего репозитория, и используемым для организации диспетчерской связи. Требуется сделать резервирование из двух идентичных серверов FreeSwitch.

Переносим базы данных FreeSwitch в MySQL

Устанавливаем драйвер MyODBC и настраиваем доступ к базе данных

Устанавливаем необходимые пакеты
$ sudo apt-get install libodbc1 odbcinst unixodbc
Установим драйвер myodbc
  • Скачиваем архив mysql-connector-odbc-5.3.7-linux-ubuntu16.04-x86-64bit.tar.gz отсюда;
  • Распаковываем архив:
    $ tar zxvf mysql-connector-odbc-5.3.7-linux-ubuntu16.04-x86-64bit.tar.gz
    
  • Переходим в распакованный каталог:
    $ cd mysql-connector-odbc-5.3.7-linux-ubuntu16.04-x86-64bit
    
  • Скопируем драйвер в каталог odbc:
    $ sudo cp lib/* /usr/lib/x86_64-linux-gnu/odbc/
    
  • Конфигурируем установленный драйвер с помощью инсталлятора:
    $ sudo bin/myodbc-installer -d -a -n MySQL -t "DRIVER=/usr/lib/x86_64-linux-gnu/odbc/libmyodbc5w.so;"
    
  • Конфигурирвем источник:
    $ sudo bin/myodbc-installer -s -a -n freeswitch -t "DRIVER=MySQL;SERVER=127.0.0.1;DATABASE=dispatcher;OPTION=67108864"
    
    где "dispatcher" - имя нашей базы данных на сервере MySQL.

В результате в каталоге /etc должны быть созданы файлы odbc.ini и odbcinst.ini с приблизительно таким содержанием:

odbc.ini:

[freeswitch]
Driver=MySQL
SERVER=127.0.0.1
DATABASE=dispatcher
PORT=3306
MULTI_STATEMENTS=1

odbcinst.ini:

[MySQL]
Driver=/usr/lib/x86_64-linux-gnu/odbc/libmyodbc5w.so
UsageCount=1
FileUsage=1
Проверим работу с базой данных MySQL серез ODBC
$ isql freeswitch <username> <password>
+---------------------------------------+
| Connected!                            |
|                                       |
| sql-statement                         |
| help [tablename]                      |
| quit                                  |
|                                       |
+---------------------------------------+
SQL> show tables;
+-----------------------------------------------------------------+
| Tables_in_dispatcher                                            |
+-----------------------------------------------------------------+
| cdr                                                             |
| options                                                         |
| recordings                                                      |
+-----------------------------------------------------------------+
SQLRowCount returns 10
10 rows fetched
SQL> quit

где <username> и <password> - имя и пароль, установленные для доступа FreeSwitch к базе данных при конфигурации FreeSwitch.

Теперь необходимо установить базе данных charset по умолчанию utf8, чтобы новые таблицы, которые создаст FreeSwitch, использовали именно его:

mysql> alter database <db-name> character set utf8;
Query OK, 1 row affected (0,00 sec)

где <db-name> - имя базы данных.

Конфигурируем FreeSwitch для хранения его данных в MySQL

Конфигурируем SIP профили FreeSwitch для хранения данных в MySQL

В файлах конфигурации SIP профилей в разделе <settings/> добавляем такой параметр:

<param name="odbc-dsn" value="odbc://freeswitch:<username>:<password>"/>

где <username> и <password> - имя и пароль, установленные для доступа FreeSwitch к базе данных при конфигурации FreeSwitch. Например:

<param name="odbc-dsn" value="odbc://freeswitch:freeswitch:lagjh46dh3"/>

Здесь же включаем track-calls:

<!-- Enable Track Calls -->
<param name="track-calls" value="true"/>

Теперь в консоли FreeSwitch перезапускаем профили командой:

> sofia profile <profile-name> restart

где <profile-name> - имя SIP профиля, например:

> sofia profile internal restart

Контролируем, что профили перезупустились с помощью команды в консоли FreeSwitch:

> sofia status

В нашей базе данных должны создаться новые таблицы. Проверим это:

$ mysql -u <username> -p <dbname> -e 'show tables'
Enter password: 
+-------------------------------------+
| Tables_in_dispatcher                |
+-------------------------------------+
| cdr                                 |
| options                             |
| recordings                          |
| sip_authentication                  |
| sip_dialogs                         |
| sip_presence                        |
| sip_registrations                   |
| sip_shared_appearance_dialogs       |
| sip_shared_appearance_subscriptions |
| sip_subscriptions                   |
+-------------------------------------+
Конфигурируем хранение core-db в MySQL

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

CREATE TABLE channels (
   uuid  VARCHAR(256),
   direction  VARCHAR(32),
   created  VARCHAR(128),
   created_epoch  INTEGER,
   name  VARCHAR(1024),
   state  VARCHAR(64),
   cid_name  VARCHAR(1024),
   cid_num  VARCHAR(256),
   ip_addr  VARCHAR(256),
   dest  VARCHAR(1024),
   application  VARCHAR(128),
   application_data  TEXT(4096),
   dialplan VARCHAR(128),
   context VARCHAR(128),
   read_codec  VARCHAR(128),
   read_rate  VARCHAR(32),
   read_bit_rate  VARCHAR(32),
   write_codec  VARCHAR(128),
   write_rate  VARCHAR(32),
   write_bit_rate  VARCHAR(32),
   secure VARCHAR(64),
   hostname VARCHAR(256),
   presence_id TEXT(4096),
   presence_data TEXT(4096),
   accountcode VARCHAR(256),
   callstate  VARCHAR(64),
   callee_name  VARCHAR(1024),
   callee_num  VARCHAR(256),
   callee_direction  VARCHAR(5),
   call_uuid  VARCHAR(256),
   sent_callee_name  VARCHAR(1024),
   sent_callee_num  VARCHAR(256),
   initial_cid_name  VARCHAR(1024),
   initial_cid_num  VARCHAR(256),
   initial_ip_addr  VARCHAR(256),
   initial_dest  VARCHAR(1024),
   initial_dialplan  VARCHAR(128),
   initial_context  VARCHAR(128)
);

В конфиг-файле switch.conf.xml добавляем параметр:

<param name="core-db-dsn" value="odbc://freeswitch:<username>:<password>"/>

где <username> и <password> - имя и пароль, установленные для доступа FreeSwitch к базе данных при конфигурации FreeSwitch.

Здесь же устанавливаем имя коммутатора:

<param name="switchname" value="freeswitch"/>

Теперь выполняем рестарт FreeSwitch:

$ sudo service freeswitch restart

Убедимся, что в базе данных появились новые таблицы:

$ mysql -u root -p dispatcher -e 'show tables'
Enter password: 
+-------------------------------------+
| Tables_in_dispatcher                |
+-------------------------------------+
| aliases                             |
| basic_calls                         |
| calls                               |
| cdr                                 |
| channels                            |
| complete                            |
| detailed_calls                      |
| interfaces                          |
| nat                                 |
| options                             |
| recordings                          |
| recovery                            |
| registrations                       |
| sip_authentication                  |
| sip_dialogs                         |
| sip_presence                        |
| sip_registrations                   |
| sip_shared_appearance_dialogs       |
| sip_shared_appearance_subscriptions |
| sip_subscriptions                   |
| tasks                               |
+-------------------------------------+

Конфигурируем второй сервер

Устанавливаем и конфигурируем второй сервер полностью аналогично первому. Проверим, что установлены все необходимые модули. Конфигурацию нового сервера (/etc/freeswitch) можно целиком скопировать с первого.

Настраиваем репликацию между двумя серверами mysql

Останавливаем FreeSwitch на обоих серверах:

$ sudo service freeswitch stop

В конфиг-файлы mysqld добавляем следующее:

server-id               = 1
log_bin                 = /var/log/mysql/mysql-bin.log
expire_logs_days        = 10
max_binlog_size         = 100M
binlog_do_db            = dispatcher

где server-id - идентификатор сервера, он должен быть разный у разных серверов.

Перезапускаем mysqld на обоих серверах:

$ sudo service mysql restart

Подключаемся к mysql серверу и создаем пользователя для репликации:

mysql> CREATE USER 'replicator'@'%' IDENTIFIED BY 'password';

заменив "password" каким-нибудь паролем.

Даем пользователю право на репликацию:

mysql> GRANT REPLICATION SLAVE ON *.* TO 'replicator'@'%';

На сервере 1 блокируем базу данных на запись:

mysql> FLUSH TABLES WITH READ LOCK;

Выводим состояние мастера:

mysql> SHOW MASTER STATUS;

Будет выведена примерно такая таблица:

+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000002 | 62249651 | dispatcher   |                  |                   |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)

Не выходя из консоли mysql (при выходе снимется блокировка), из другого терминала дампим базу данных:

$ mysqldump -u root -p dispatcher >dispatcher.dump

Когда дамп будет готов, снова выведем SHOW MASTER STATUS; и убедимся, что значение Position не изменилось. Теперь можно снять блокировку:

mysql> UNLOCK TABLES;

или просто выйти из консоли mysql.

Копируем сделанный дамп базы на второй сервер. Записываем дамп в базу данных:

$ mysql -u root -p dispatcher <dispatcher.dump

Теперь входим в консоль mysql сервера 2 и запускаем репликацию:

mysql> STOP SLAVE;
mysql> CHANGE MASTER TO MASTER_HOST = '<server 1 address>' , MASTER_USER = 'replicator', MASTER_PASSWORD = 'password', MASTER_LOG_FILE = 'mysql-bin.000002', MASTER_LOG_POS = 62249651;
mysql> START SLAVE;

заменив "password" на тот пароль, который установили пользователю replicator ранее.

Проверим, что репликация активирована:

mysql> SHOW SLAVE STATUS\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.0.64
                  Master_User: replicator
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.000003
          Read_Master_Log_Pos: 118750
               Relay_Log_File: r3-relay-bin.000002
                Relay_Log_Pos: 82017
        Relay_Master_Log_File: mysql-bin.000003
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB: 
          Replicate_Ignore_DB: 
           Replicate_Do_Table: 
       Replicate_Ignore_Table: 
      Replicate_Wild_Do_Table: 
  Replicate_Wild_Ignore_Table: 
                   Last_Errno: 0
                   Last_Error: 
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 118750
              Relay_Log_Space: 82221
              Until_Condition: None
               Until_Log_File: 
                Until_Log_Pos: 0
           Master_SSL_Allowed: No
           Master_SSL_CA_File: 
           Master_SSL_CA_Path: 
              Master_SSL_Cert: 
            Master_SSL_Cipher: 
               Master_SSL_Key: 
        Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error: 
               Last_SQL_Errno: 0
               Last_SQL_Error: 
  Replicate_Ignore_Server_Ids: 
             Master_Server_Id: 1
                  Master_UUID: 7603167a-1081-11e6-9637-902b3433882b
             Master_Info_File: /var/lib/mysql/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
           Master_Retry_Count: 86400
                  Master_Bind: 
      Last_IO_Error_Timestamp: 
     Last_SQL_Error_Timestamp: 
               Master_SSL_Crl: 
           Master_SSL_Crlpath: 
           Retrieved_Gtid_Set: 
            Executed_Gtid_Set: 
                Auto_Position: 0
         Replicate_Rewrite_DB: 
                 Channel_Name: 
           Master_TLS_Version: 
1 row in set (0.00 sec)

Аналогично, только без выполнения/восстановления дампа настраиваем репликацию сервера 2 на сервер 1.

Настраиваем общий адрес

Общий адрес - это IP адрес, используя который один из двух серверов (активный) будет предоставлять сервис. Пусть для определенности это будет адрес 192.168.0.63.

Для начала установим пакет arping:

$ sudo apt-get install arping

В файле /etc/network/interfaces обоих серверов добавляем настройку для общего адреса:

iface eth0:0 inet static
address 192.168.0.63
netmask 255.255.255.0

где вместо "eth0" следует вписать имя используемого сетевого интерфейса.

Отредактируем файл /etc/default/arping, вписав в него IPUP=1 и DOWN=1.

На первом сервере выполняем команду

$ sudo ifup eth0:0

Выполнение этой команды на втором сервере должно дать ошибку, так как адрес уже присутствует в сети:

$ sudo ifup eth0:0
 * Using arping to check duplicity of 192.168.0.63...
   ...fail!
run-parts: /etc/network/if-up.d/arping exited with return code 1
Failed to bring up eth0:0.

Теперь необходимо изменить настройки odbc таким образом, чтобы оба сервера FreeSwitch подключались к базе данных используя общий адрес и, таким образом, подключались к одному и тому же серверу mysql. Для этого в ранее созданном файле /etc/odbc.ini указываем адрес сервера 192.168.0.63.

Устанавливаем параметр sysctl net.ipv4.ip_nonlocal_bind в значение 1 чтобы дать возможность неактивному серверу FreeSwitch слушать адрес, отсутствующий на его интерфейсах:

$ sudo sysctl net.ipv4.ip_nonlocal_bind=1

Для автоматической установки этого значения в файл /etc/sysctl.conf добавляем строку

net.ipv4.ip_nonlocal_bind=1

В конфигурации профилей FreeSwitch устанавливаем параметры sip-ip, rtp-ip, presence-hosts, ext-sip-ip и ext-rtp-ip в значение 192.168.0.63.

Теперь можно запустить сервера FreeSwitch:

$ sudo service freeswitch start

Синхронизация файлов конфигурации и записей переговоров

Синхронизацию файлов конфигурации и записей переговоров сделаем с помощью rsync. Чтобы схема была симметричной, каждый из серверов будет копировать свои обновившиеся файлы на другой сервер. Копирование будет производиться по SSH.

Для начала проверим, что в /etc/passwd пользователю freeswitch установлен реальный shell (а не /bin/false или что-то аналогичное). При необходимости установим шелл командой:

$ sudo usermod -s /bin/sh freeswitch

Генерируем пользователю freeswitch rsa ключ для ssh:

$ sudo su -l freeswitch
$ ssh-keygen -t rsa -b 4096

В результате в домашнем каталоге пользователя freeswitch будет создан файл .ssh/id_rsa.pub. Добавляем содержимое этого файла в файл .ssh/authorized_keys в домашнем каталоге пользователя freeswitch на другом сервере. Проверим, что пользователь freeswitch с одного сервера может войти по ssh на другой сервер без ввода пароля:

$ sudo su -l freeswitch
$ ssh <address>
Welcome to Ubuntu 16.04.2 LTS (GNU/Linux 4.4.0-62-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
Last login: Wed Feb 22 11:27:59 2017 from 192.168.0.61
$

Теперь, когда каждый из серверов может соединиться по SSH со своим собратом, настроим синхронизацию файлов конфигурации и записей переговоров. Для этого добавим в /etc/crontab каждого сервера такие записи:

*/5 * * * * freeswitch rsync -au -e ssh /etc/freeswitch/ <address>:/etc/freeswitch/
*/5 * * * * freeswitch rsync -au -e ssh /var/lib/freeswitch/recordings/ <address>:/var/lib/freeswitch/recordings/

В вышеприведенном примере файлы синхронизируются каждые 5 минут.

Для более равномерного распределения нагрузки на сеть можно настроить серверам разное время синхронизации, например:

0-59/5 * * * * freeswitch rsync -au -e ssh /etc/freeswitch/ .......
1-59/5 * * * * freeswitch rsync -au -e ssh /var/lib/freeswitch/recordings/ ........

на первом сервере и

2-59/5 * * * * freeswitch rsync -au -e ssh /etc/freeswitch/ .......
3-59/5 * * * * freeswitch rsync -au -e ssh /var/lib/freeswitch/recordings/ ........

на втором сервере.

Проверим работу синхронизации: на первом сервере создадим новый файл в /var/lib/freeswitch/recordings/ и изменим какой-нибудь файл в /etc/freeswitch/. Подождем 5 минут и убедимся, что на втором сервере появился новый файл в /var/lib/freeswitch/recordings/ и отразилось изменение файла в /etc/freeswitch/. Аналогично проверим копирование в обратном направлении.

Переключение на резерв

Далее будет описано два варианта настройки переключения на резервный сервер:

  • автоматическое переключение;
  • ручное переключение.

Автоматическое переключение

Для автоматического переключения будем использовать протокол VRRP и демон keepalived. Устанавливаем пакет keepalived:

$ sudo apt-get install keepalived

Конфигурируем keepalived. Сначала создадим скрипт /etc/keepalived/ka-master.pl, который будет передавать FreeSwitch команду sofia recover при переходе сервера в состояние MASTER:

#!/usr/bin/perl

my $password = "secret";
 
open(STDOUT, "|/usr/bin/logger -t ka-master");
print "Instance went to master, issuing sofia recover.\n";
system("/usr/bin/fs_cli", "-p$password", "-x", "sofia recover");

где "secret" меняем на наш пароль доступа к event-socket FreeSwitch. Так как файл содержит пароль, не забываем установить ему права доступа, разрешающие чтение только для пользователя root:

$ sudo chown root:root /etc/keepalived/ka-master.pl
$ sudo chmod 700 /etc/keepalived/ka-master.pl

Создаем базовый файл конфигурации /etc/keepalived/keepalived.conf:

global_defs {
    router_id FREESW
}

vrrp_instance VI_FREESW {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass labuda25
    }
    notify_master "/etc/keepalived/ka-master.pl"
    virtual_ipaddress {
        192.168.0.63/24 dev eth0 label eth0:0
    }
}

где "eth0" - имя сетевого интерфейса, "eth0:0" - алиас виртуального адреса - меняем их в соответствии с именем интерфейса каждого сервера.

Запускаем keepalived на одном из серверов:

$ sudo service keepalived start

Контролируем в /var/log/syslog, что демон успешно запустился и, так как на втором сервере keepalived еще не запуцщен, сразу после запуска keepalived должен перейти в состояние MASTER. Контролируем, что у сервера появился адрес 192.168.0.63.

Теперь запускаем keepalived на втором сервере. Контролируем, что демон запустился, на находится в состоянии BACKUP, так как в сети уже есть MASTER.

Контролируем переход сервера из состояния BACKUP в состояние MASTER. Для этого на несколько секунд отключаем активный в данный момент MASTER от сети (или просто останавливаем на нем демон keepalived). Контролируцем, что сервер, находившийся в состоянии BACKUP, перешел в состояние MASTER.

На данном этапе у нас настроен переход сервера из резерва в активное состояние по единственному критерию - недоступности мастера, определяемой по протоколу VRRP. Теперь добавим сюда контроль работоспособности FreeSwitch. Для этого создаем следующий скрипт:

#!/usr/bin/perl
 
my $password = "secret";
my @required = ("internal");
 
my %saw = ();
open(my $in, "-|") || exec("/usr/bin/fs_cli", "-p$password", "-x", "sofia xmlstatus");
while ( defined(my $line = <$in>) )
{
    if ( $line =~ m|<name>(.*)</name>|o )
    {
        $saw{$1} = 1;
    }
}
close($in);
 
foreach my $profile ( @required )
{
    if ( ! $saw{$profile} )
    {
        exit(1);
    }
}
 
exit(0);

где "secert" заменяем на пароль доступа к event-socket FreeSwitch-сервера, а массиву "@required" присваиваем имена SIP-профилей, наличие которых необходимо контролировать. Теперь, если все перечисленные в @required профили запущены, скрипт вернет 0, иначе - 1. Проверпим его функционирование, запустив вручную. Если все хорошо, укажем keepalived проверять работоспособность FreeSwitch каждые 10 секунд. Для этого в /etc/keepalived/keepalived.conf добавляем секцию с описанием скрипта:

vrrp_script chk_fs {
    script "/etc/keepalived/ka-status.pl"
    interval 10
}

и в секцию vrrp_instance VI_FREESW добавляем указание использовать этот скрипт:

    track_script {
        chk_fs
    }

Перезапустим keepalived:

$ sudo service keepalived restart

Контролируем, что сервер в состоянии BACKUP. Теперь подключаемся к консоли FreeSwitch и останавливаем профиль internal:

> sofia profile internal stop

Ждем 10 секунд и контролируем, что keepalived перешел в состояние FAULT.

Ручное переключение

Attachments (1)

Download all attachments as: .zip

Note: See TracWiki for help on using the wiki.