
На протяжении последних 3-х недель мне несколько раз приходилось сталкиваться с перебоями в работе моего хостинга, по скольку я веду проект с большой посещаемостью даже кратковременный простой сказывается на количестве звонков с сайта.
При этом всё могло быть гораздо лучше, если вместо стандартной страницы «Сервер не найден» повесить заставку в стиле сайта с текстом «Сайт временно не доступен, позвоните по телефону или оставьте заявку».
Было принято решение воспользоваться DNS сервисом от Amazon для быстрой смены A-записи.
Описание Amazon Route 53
Это надёжный DNS сервис, с достаточно удобным API для редактирования, добавления и удаления записей.
Стоимость услуги составляет 1$ в месяц + 0.50$ за первый миллион запросов и 0.25$ за каждый следующий миллион запросов.
Серьёзным неудобством в некоторых случаях является способ оплаты — оплатить услугу можно только по пластиковой карте, однако есть выход из положения, например можно воспользоваться виртуальной картой Visa от qiwi.
После регистрации и оплаты услуги мы получаем пару ID и ключ, которые в последствии используются для авторизации в API.
Готовим домен
Для подключения домена и настройки всех необходимых записей использовать API не очень удобно.
Я предлагаю воспользоваться сервисом Interstate53.
Сервис представляет собой интерфейс для управления аккаунтом на Route 53 и обеспечивает полный спектр его функций.

Все записи заполняем как раньше — A-записи идут на IP-адрес основного хостинга.
Выбираем хостинг
В моём случае резервный сервер должен быть как можно более дешевым и обладать следующим набором функций:
- PHP — для работы с Route 53 API
- cron — для периодической проверки основного хостинга на доступность
- статический HTML — для показа заставки
Выбор пал на Джино, это единственных хостинг который я нашел, где можно отказаться от поддержки баз данных не отказываясь от PHP. Цена вышла 75 рублей в месяц.
Основной хостинг clodo, хотя это не имеет значения.
Настраиваем основной хостинг
Нас интересует работоспособность сайта в любых условиях, а значит, если зависнет база или apache необходимо также менять A-запись. Для тестирования создадим небольшой PHP скрипт, доступный по IP адресу сервера.
-
- $link = mysql_connect('localhost', 'root', 'password') or die('0');
- $result = mysql_query('SELECT VERSION();');
- if(!$result)
- die('0');
- mysql_close($link);
- echo 'OK!';
-
В случае неполадок с базой скрипт выдаст 0, если не работает сервер или завис apache, скрипт не выдаст ничего, в случае успеха будет передана надпись «OK!».
На этом настройка основного сервера завершена.
Настраиваем дублирующий хостинг
Для работы с API Route 53 я использовал готовый PHP класс Route53.
-
- define('MASTER_HOST', 'xxx.xxx.xxx.xxx');//IP адрес основного сервера
- define('SLAVE_HOST', 'xxx.xxx.xxx.xxx');//IP адрес дополнительного сервера
- define('ACCESS_KEY', 'my_key');//Ключ для доступа к API
- define('SECRET_KEY', 'my_pass');//Пароль для доступа к API
- define('ZONE_ID', '/hostedzone/my_zone_id');//ID зоны (можно увидеть после добавлени домена в interstate53.com)
-
- include 'r53.php';
- $route = new Route53(ACCESS_KEY, SECRET_KEY);
- $ns = $route->listResourceRecordSets(ZONE_ID);//Сразу получаем значения ns записей для домена
-
- function test(){
- try{
- $answer = file_get_contents('http://'.MASTER_HOST.'/');
- if($answer == 'OK!')//Проверяем ответ от основного сервера
- return true;
- else
- return false;
- }catch (Exception $e){
- return false;
- }
- }
-
- function update($arr){
- GLOBAL $route;
- if(count($arr) > 0)
- {
- $route->changeResourceRecordSets(ZONE_ID, $arr);//Обновление ns-записей
- }
- }
-
- function changeIP($name, $ttl, $from_ip, $to_ip){//Функция генерирует массив в котором одна запись удаляет старую, а вторая добавляет новую
- return Array(
- "
- <Change>
- <Action>DELETE</Action>
- <ResourceRecordSet>
- <Name>$name</Name>
- <Type>A</Type>
- <TTL>$ttl</TTL>
- <ResourceRecords>
- <ResourceRecord>
- <Value>$from_ip</Value>
- </ResourceRecord>
- </ResourceRecords>
- </ResourceRecordSet>
- </Change>
- ",
- "
- <Change>
- <Action>CREATE</Action>
- <ResourceRecordSet>
- <Name>$name</Name>
- <Type>A</Type>
- <TTL>$ttl</TTL>
- <ResourceRecords>
- <ResourceRecord>
- <Value>$to_ip</Value>
- </ResourceRecord>
- </ResourceRecords>
- </ResourceRecordSet>
- </Change>
- "
- );
- }
-
- $changes = Array();
-
- if(!test()){
- if(!test()){// делаем проверку 2 раза для надёжности
- foreach($ns['ResourceRecordSets'] as $record){
- if($record['Type'] == 'A' && $record['ResourceRecords']['0'] == MASTER_HOST){
- $changes = array_merge($changes, changeIP($record['Name'], $record['TTL'], MASTER_HOST, SLAVE_HOST));
- }
- }
- update($changes);
- exit(0);
- }
- }
-
- foreach($ns['ResourceRecordSets'] as $record){
- if($record['Type'] == 'A' && $record['ResourceRecords']['0'] == SLAVE_HOST){
- $changes = array_merge($changes, changeIP($record['Name'], $record['TTL'], SLAVE_HOST, MASTER_HOST));
- }
- }
- update($changes);
- exit(0);
-
Немного резюмирую код по порядку: проверяем сервер на ответ «OK!» 2 раза для надёжности, если ответ не верный, меняем записи, если ответ верный, возвращаем записи на место.
Остаётся настроить cron
В Джино это делается достаточно просто, кидаем полученный скрипт в папку тестового домена mydomain.jino.ru, в «Задания по расписанию» нажимаем «Новое задание», далее заполняем поля:
Задание: curl -s mydomain.jino.ru/route53/core.php > /dev/null
Комментарий:
Минуты, Часы, Дни, Месяцы, Дни недели: *
Наш скрипт будет выполняться каждую минуту. Это означает, что максимальное время простоя сайта составит 2 минуты 29 секунд в худшем раскладе и 30 секунд (зависит от TTL A-записи) в лучшем.
Итог
В идеале конечно следует держать копию сайта на дополнительном хостинге — заставка с контактами и надписью «сервер не работает» может отпугнуть некоторых людей. Но этот способ тоже имеет право на существование.