← Назад к вопросам

Как минимизировать время когда приложение не работает при деплое?

3.0 Senior🔥 141 комментариев
#DevOps и инфраструктура

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Минимизация времени простоя при деплое

Это критически важный вопрос для production-систем. Существует несколько стратегий, которые позволяют достичь нулевого простоя (zero-downtime deployment).

1. Blue-Green Deployment

Это наиболее надёжный метод для Node.js приложений:

  • Запускаешь две идентичные production-среды: Blue (текущая) и Green (новая версия)
  • Деплоишь новую версию только в Green
  • Прогоняешь полный набор smoke-тестов
  • Переключаешь load balancer / reverse proxy с Blue на Green
  • Blue становится резервной копией на случай, если нужен rollback
// Пример с Nginx
upstream app {
  server blue-app:3000 weight=100;
  server green-app:3000 weight=0;  // Слушает, но не получает трафик
}

// При деплое меняешь веса через конфиг или systemctl restart

2. Rolling Deployment

Поступательное обновление инстансов приложения:

  • Имеешь несколько инстансов (например, 4 server'а за load balancer'ом)
  • Выводишь один инстанс из работы (drain connections)
  • Деплоишь на него новую версию
  • Возвращаешь в rotation
  • Повторяешь для остальных
// graceful shutdown handler
let isShuttingDown = false;

server.on('SIGTERM', async () => {
  if (isShuttingDown) return;
  isShuttingDown = true;
  
  // Перестаём принимать новые запросы
  server.close(() => {
    // Завершаем существующие подключения
    console.log('Server closed gracefully');
    process.exit(0);
  });
  
  // Timeout для насильственного завершения
  setTimeout(() => process.exit(1), 30000);
});

3. Graceful Shutdown & Connection Draining

Это обязательная часть любой стратегии:

const gracefulShutdown = (server, db, redis) => {
  const shutdown = async (signal) => {
    console.log(`Received ${signal}, starting graceful shutdown`);
    
    // Шаг 1: Выводим из load balancer
    await removeFromLoadBalancer();
    
    // Шаг 2: Даём время активным запросам завершиться
    await new Promise(resolve => {
      const timeout = setTimeout(resolve, 30000);
      server.close(() => clearTimeout(timeout));
    });
    
    // Шаг 3: Закрываем БД и Redis соединения
    await db.close();
    await redis.disconnect();
    
    process.exit(0);
  };
  
  process.on('SIGTERM', () => shutdown('SIGTERM'));
  process.on('SIGINT', () => shutdown('SIGINT'));
};

4. Database Migrations Strategy

Миграции — главный источник простоя:

  • Expand-Contract Pattern: сначала добавляешь новую колонку, затем переводишь приложение на её использование, потом удаляешь старую
  • Online Migrations: используешь инструменты типа Percona's pt-online-schema-change или Ghost для MySQL
  • Separate Migration Step: запускаешь миграции ДО деплоя нового кода
-- ✅ Безопасно: добавление колонки
ALTER TABLE users ADD COLUMN email_verified_at TIMESTAMPTZ;

-- ❌ Опасно: удаление колонки (может заблокировать таблицу)
ALTER TABLE users DROP COLUMN old_field;

5. Health Checks & Load Balancer Configuration

// Health check endpoint
app.get('/health', (req, res) => {
  res.json({ 
    status: 'ok',
    uptime: process.uptime(),
    timestamp: Date.now()
  });
});

// Readiness check (готовность принимать трафик)
app.get('/ready', async (req, res) => {
  try {
    await db.query('SELECT 1');
    res.json({ ready: true });
  } catch (err) {
    res.status(503).json({ ready: false });
  }
});

6. DNS & Sticky Sessions

  • Минимизируй TTL перед деплоем (чтобы DNS быстро обновился)
  • Если используешь sticky sessions, убедись что load balancer корректно перенаправляет сессии при переводе инстанса

Рекомендуемая практика для production

Blue-Green + Graceful Shutdown — это gold standard:

  1. Запускаешь Green окружение
  2. Прогоняешь все тесты (unit, integration, smoke)
  3. Выполняешь миграции БД (если нужны)
  4. Отправляешь трафик на Green (мгновенное переключение)
  5. Мониторишь логи и метрики на предмет ошибок
  6. Сохраняешь Blue как fallback на 30-60 минут

При таком подходе downtime составляет менее 1 секунды (время переключения load balancer'а).