Jump to content
View in the app

A better way to browse. Learn more.

T.M.I IThub

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Мониторинг: от "прод упал, узнали от пользователей" до "прод думает что упасть и уже получил алерт"

(0 reviews)

Есть два типа DevOps. Первые узнают об авариях от пользователей. Вторые — за 5 минут до того как проблема станет аварией. Я прошёл путь от первого ко второму. Это было долго, больно и неочевидно. Расскажу как.


Уровень 0: Никакого мониторинга

Это страшное место. Узнаёшь что что-то не так, когда:

  • Пишет пользователь в поддержку

  • Звонит CEO в воскресенье

  • Видишь в Twitter "ваш сайт сломан"

Это лечится быстро — после первого воскресного звонка от CEO инстинкт самосохранения быстро мотивирует к действию.


Уровень 1: Uptime monitoring

Самое простое: проверяем что сайт отвечает:

class HealthCheck extends BaseCommand
{
    protected $name = 'health:check';

    public function run(array $params): void
    {
        $endpoints = config('HealthCheck')->endpoints;
        
        foreach ($endpoints as $endpoint) {
            $start = microtime(true);
            
            try {
                $response = \Config\Services::curlrequest()->get($endpoint['url'], [
                    'timeout' => 10,
                    'http_errors' => false,
                ]);
                
                $duration = (microtime(true) - $start) * 1000;
                $status = $response->getStatusCode();
                
                if ($status !== 200 || $duration > $endpoint['threshold_ms']) {
                    $this->alertTeam($endpoint, $status, $duration);
                }
                
            } catch (\Exception $e) {
                $this->alertTeam($endpoint, 0, 0, $e->getMessage());
            }
        }
    }
}

Лучше чем ничего. Но это как термометр в одной комнате большого дома.


Уровень 2: Application метрики

Prometheus + Grafana. В CI4 интегрируем через After-фильтр:

<?php

namespace App\Filters;

class MetricsFilter implements FilterInterface
{
    public function before(RequestInterface $request, $arguments = null): void
    {
        $GLOBALS['_request_start_time'] = microtime(true);
    }

    public function after(
        RequestInterface $request,
        ResponseInterface $response,
        $arguments = null
    ): ResponseInterface {
        $duration = microtime(true) - ($GLOBALS['_request_start_time'] ?? microtime(true));
        $status   = $response->getStatusCode();
        $route    = service('router')->controllerName();
        $method   = $request->getMethod();

        $metrics = service('metricsCollector');

        $metrics->histogram(
            'http_request_duration_seconds',
            $duration,
            ['method' => $method, 'route' => $route, 'status' => $status]
        );

        $metrics->counter(
            'http_requests_total',
            1,
            ['method' => $method, 'route' => $route, 'status' => (string)intdiv($status, 100) . 'xx']
        );

        if ($status >= 500) {
            $metrics->counter('http_errors_total', 1, ['route' => $route]);
        }

        return $response;
    }
}

Уровень 3: Предиктивные алерты

Настоящий прорыг — когда алерты стали срабатывать ДО того как всё упало.

Пример: за 8-12 минут до OOM Redis всегда происходило:

  1. Memory usage рос быстрее обычного (+15% за 5 минут)

  2. Cache hit rate начинал падать

  3. Eviction rate был 0

Prometheus alerting rule:

groups:
  - name: redis_predictive
    rules:
      - alert: RedisMemoryGrowthAnomaly
        expr: |
          (
            redis_memory_used_bytes / redis_memory_max_bytes > 0.75
          ) and (
            rate(redis_memory_used_bytes[5m]) > 0
          ) and (
            redis_stat_keyspace_hits /
            (redis_stat_keyspace_hits + redis_stat_keyspace_misses) < 0.85
          )
        for: 3m
        labels:
          severity: warning
        annotations:
          summary: "Redis memory growing fast, potential OOM in ~10min"

      - alert: MySQLConnectionPoolDanger
        expr: |
          mysql_global_status_threads_connected /
          mysql_global_variables_max_connections > 0.8
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "MySQL connection pool at {{ $value | humanizePercentage }}"

Уровень 4: Synthetic monitoring

Проверяем что реальный пользовательский сценарий работает end-to-end. CLI-команда CI4 каждые 2 минуты симулирует key user journey:

namespace App\Commands\Synthetic;

class CheckoutFlow extends BaseCommand
{
    protected $name = 'synthetic:checkout';

    public function run(array $params): void
    {
        $client  = service('curlrequest');
        $baseUrl = env('SYNTHETIC_BASE_URL');
        $metrics = service('metricsCollector');
        $start   = microtime(true);
        $step    = 'init';

        try {
            $step = 'login';
            $loginResp = $client->post($baseUrl . '/api/auth/login', [
                'json' => ['email' => env('SYNTHETIC_USER_EMAIL'), 'password' => env('SYNTHETIC_USER_PASSWORD')],
                'timeout' => 5,
            ]);
            assert($loginResp->getStatusCode() === 200);
            $token = json_decode($loginResp->getBody(), true)['token'];

            $step = 'product_list';
            $productsResp = $client->get($baseUrl . '/api/products', [
                'headers' => ['Authorization' => "Bearer $token"],
                'timeout' => 3,
            ]);
            assert($productsResp->getStatusCode() === 200);

            // ... другие шаги

            $metrics->counter('synthetic_checkout_flow_success_total', 1);
            $this->write("

Checkout flow OK

"); } catch (\Throwable $e) {

$metrics->counter('synthetic_checkout_flow_failure_total', 1, ['step' => $step]);

service('alertManager')->fire(level: 'critical', title: "Synthetic checkout failed at: {$step}", body: $e->getMessage()); } } }


Текущий стек мониторинга

  • Prometheus — сбор метрик

  • Grafana — визуализация и алертинг

  • Loki — агрегация логов

  • Alertmanager — маршрутизация (Telegram, PagerDuty, Slack)

  • Synthetic monitoring — CI4 CLI команды в cron

  • OpenTelemetry + Jaeger — distributed tracing

MTTR за год:

Период

MTTR

До нормального мониторинга

47 минут

После

8 минут

Это не просто красивая цифра. Это живые деньги. Мониторинг — это бизнес-инвестиция с прямым ROI. 📈


0 Comments

Recommended Comments

There are no comments to display.

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.