Принимаем 10 000 ивентов в Яндекс.Облаке. Часть 2

    И снова здравствуйте! Продолжаем нашу серию статей про то, как мы щупали Яндекс.Облако.

    Давайте вспомним план, по которому мы с вами двигаемся:

    1 часть. Мы определились с ТЗ и архитектурой решения, написали приложение на golang.
    2 часть (вы сейчас здесь). Выливаем наше приложение на прод, делаем масштабируемым и тестируем нагрузку.
    3 часть. Попробуем разобраться, зачем нам нужно хранить сообщения в буфере, а не в файлах, а также сравним между собой kafka, rabbitmq и yandex queue service.
    4 часть. Будем разворачивать Clickhouse кластер, писать стриминг для перекладывания туда данных из буфера, настроим визуализацию в datalens.
    5 часть. Приведем всю инфраструктуру в должный вид — настроим ci/cd, используя gitlab ci, подключим мониторинг и service discovery с помощью consul и prometheus.



    Ну что, переходим к нашим задачкам.

    Выливаемся в production


    В 1 части мы собрали приложение, оттестировали его, а также загрузили образ в приватный container registry, готовый для развертывания.

    Вообще следующие шаги должны быть практически очевидными — создаем виртуалки, настраиваем load balancer и прописываем DNS имя с проксированием на cloudflare. Но боюсь, такой вариант не сильно соответствует нашему техническому заданию. Мы хотим уметь масштабировать наш сервис в случае увеличения нагрузки и выкидывать из него битые ноды, которые не могут обслуживать запросы.

    Для масштабирования мы будем использовать группы машин (instance groups), доступные в compute cloud. Они позволяют создавать виртуалки по шаблону, следить за их доступностью с помощью health check’ов, а также автоматически увеличивать количество узлов в случае возрастания нагрузки. Подробнее здесь.

    Встает только один вопрос — какой шаблон использовать для виртуальной машины? Конечно, можно установить linux, настроить его, сделать образ и залить в хранилище образов в Яндекс.Облаке. Но для нас это долгий и непростой путь. В процессе рассмотрения различных образов, доступных при создании виртуалки, мы наткнулись на интересный экземпляр — container optimized image (https://cloud.yandex.ru/docs/cos/concepts/). Он позволяет запустить один docker контейнер в сетевом режиме host. То есть при создании виртуалки указывается примерно такая спецификация для образа container optimized image:

    spec:
      containers:
        - name: api
          image: vozerov/events-api:v1
          command:
            - /app/app
          args:
            - -kafka=kafka.ru-central1.internal:9092
          securityContext:
            privileged: false
          tty: false
          stdin: false
          restartPolicy: Always

    И после старта виртуальной машины этот контейнер будет скачан и запущен локально.

    Схема вырисовывается вполне интересная:

    1. Мы создаем instance group с автоматическим масштабированием при превышении 60% cpu usage.
    2. В качестве шаблона указываем виртуальную машину с образом container optimized image и параметрами для запуска нашего Docker-контейнера.
    3. Создаем load balancer, который будет смотреть на нашу instance group и автоматически обновляться при добавлении или удалении виртуальных машин.
    4. Приложение будет мониториться и как instance group, и самим балансировщиком, который выкинет недоступные виртуалки из балансировки.

    Звучит как план!

    Попробуем создать instance group с помощью terraform. Все описание лежит в instance-group.tf, прокомментирую основные моменты:

    1. service account id будет использоваться для создания и удаления виртуалок. Кстати, нам его придется создать.

      service_account_id = yandex_iam_service_account.instances.id
    2. Данные для указания спецификации контейнера вынесены в отдельный файл spec.yml, где помимо прочего указывается образ, который необходимо запустить. Поскольку внутренний registry у нас появился во время написания данной статьи, а гит-репозиторий я выложил в паблик на гитхаб — на данный момент там прописан образ с публичного docker hub. Чтобы использовать образ из нашего репозитория, достаточно прописать путь до него —

      	    
              metadata = {
      	  docker-container-declaration = file("spec.yml")
      	  ssh-keys = "ubuntu:${file("~/.ssh/id_rsa.pub")}"
      	}
    3. Укажем еще один service account id, он будет использоваться образом container optimized image, чтобы пройти аутентификацию в container registry и скачать образ нашего приложения. Сервисный аккаунт с доступом к registry мы уже создавали, поэтому будем использовать его:

      service_account_id = yandex_iam_service_account.docker.id
    4. Scale policy. Самая интересная часть:

      autoscale {
        initialsize = 3
        measurementduration = 60
        cpuutilizationtarget = 60
        minzonesize = 1
        maxsize = 6
        warmupduration = 60
        stabilizationduration = 180
      }

      Здесь мы определяем политику масштабирования наших виртуалок. Есть два варианта — либо fixed_scale с фиксированным числом виртуальных машин, либо auth_scale.

      Основные параметры такие:

      initial size — первоначальный размер группы;
      measurement_duration — период изменения целевого показателя;
      cpu_utilization_target — целевое значение показателя, при большем значении которого надо расширить группу;
      min_zone_size — минимальное количество нод в одной зоне доступности — планировщик не будет удалять ноды, чтобы их количество стало ниже этого значения;
      max_size — максимальное количество нод в группе;
      warmup_duration — период прогрева, в течение которого планировщик не будет брать значения метрик с данной ноды, а будет использовать среднее значение в группе;
      stabilization_duration — период стабилизации — после увеличения количества нод в группе в течение указанного промежутка времени балансировщик не будет удалять созданные машины, даже если целевой показатель опустился ниже порогового значения.

      Теперь простыми словами о наших параметрах. На начальном этапе создаем 3 машинки (initial_size), минимум по одной в каждой зоне доступности (min_zone_size). Измеряем показатель cpu раз в минуту на всех машинках (measurement_duration). Если среднее значение превышает 60% (cpu_utilization_target), то создаем новые виртуалки, но не больше шести (max_size). После создания в течение 60 секунд не собираем метрики с новой машинки (warmup_duration), поскольку во время старта она может использовать достаточно много cpu. А 120 секунд после создания новой машинки не удаляем ничего (stabilization_duration), даже если среднее значение метрик в группе стало ниже 60% (cpu_utilization_target).

      Подробнее о масштабировании — https://cloud.yandex.ru/docs/compute/concepts/instance-groups/policies#auto-scale-policy
    5. Allocation policy. Указывает, в каких зонах доступности создавать наши виртуальные машины, — используем все три доступных зоны.

       allocationpolicy {
        zones = ["ru-central1-a", "ru-central1-b", "ru-central1-c"]
      }
      
    6. Политика деплоя машинок:

      
      deploy_policy {
        maxunavailable = 1
        maxcreating = 1
        maxexpansion = 1
        maxdeleting = 1
      }

      max_creating — максимальное число одновременно создаваемых машин;
      max_deleting — максимальное число одновременно удаляемых машин;
      max_expansion — на какое число виртуалок можно превысить размер группы при обновлении;
      max_unavailable — максимальное число виртуалок в статусе RUNNING, которые могут быть удалены;

      Подробнее о параметрах — https://cloud.yandex.ru/docs/compute/concepts/instance-groups/policies#deploy-policy
    7. Настройки балансировщика:

       load_balancer {
        target_group_name = "events-api-tg"
      }

      При создании instance group можно создать и целевую группу для балансировщика нагрузки. Она будет направлена на относящиеся к ней виртуальные машины. В случае удаления ноды будут выводиться из балансировки, а при создании — добавляться в балансировку после прохождения проверок состояния.

    Вроде все основное прописали — давайте создавать сервисный аккаунт для instance group и, собственно, саму группу.

    vozerov@mba:~/events/terraform (master *) $ terraform apply -target yandex_iam_service_account.instances -target yandex_resourcemanager_folder_iam_binding.editor
    
    ... skipped ...
    
    Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
    
    vozerov@mba:~/events/terraform (master *) $ terraform apply -target yandex_compute_instance_group.events_api_ig
    
    ... skipped ...
    
    Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

    Группа создалась — можно посмотреть и проверить:

    vozerov@mba:~/events/terraform (master *) $ yc compute instance-group list
    +----------------------+---------------+------+
    |          ID          |     NAME      | SIZE |
    +----------------------+---------------+------+
    | cl1s2tu8siei464pv1pn | events-api-ig |    3 |
    +----------------------+---------------+------+
    
    vozerov@mba:~/events/terraform (master *) $ yc compute instance list
    +----------------------+---------------------------+---------------+---------+----------------+-------------+
    |          ID          |           NAME            |    ZONE ID    | STATUS  |  EXTERNAL IP   | INTERNAL IP |
    +----------------------+---------------------------+---------------+---------+----------------+-------------+
    | ef3huodj8g4gc6afl0jg | cl1s2tu8siei464pv1pn-ocih | ru-central1-c | RUNNING | 130.193.44.106 | 172.16.3.3  |
    | epdli4s24on2ceel46sr | cl1s2tu8siei464pv1pn-ipym | ru-central1-b | RUNNING | 84.201.164.196 | 172.16.2.31 |
    | fhmf37k03oobgu9jmd7p | kafka                     | ru-central1-a | RUNNING | 84.201.173.41  | 172.16.1.31 |
    | fhmh4la5dj0m82ihoskd | cl1s2tu8siei464pv1pn-ahuj | ru-central1-a | RUNNING | 130.193.37.94  | 172.16.1.37 |
    | fhmr401mknb8omfnlrc0 | monitoring                | ru-central1-a | RUNNING | 84.201.159.71  | 172.16.1.14 |
    | fhmt9pl1i8sf7ga6flgp | build                     | ru-central1-a | RUNNING | 84.201.132.3   | 172.16.1.26 |
    +----------------------+---------------------------+---------------+---------+----------------+-------------+
    
    vozerov@mba:~/events/terraform (master *) $

    Три ноды с кривыми именами — это наша группа. Проверяем, что приложения на них доступны:

    vozerov@mba:~/events/terraform (master *) $ curl -D - -s http://130.193.44.106:8080/status
    HTTP/1.1 200 OK
    Date: Mon, 13 Apr 2020 16:32:04 GMT
    Content-Length: 3
    Content-Type: text/plain; charset=utf-8
    
    ok
    vozerov@mba:~/events/terraform (master *) $ curl -D - -s http://84.201.164.196:8080/status
    HTTP/1.1 200 OK
    Date: Mon, 13 Apr 2020 16:32:09 GMT
    Content-Length: 3
    Content-Type: text/plain; charset=utf-8
    
    ok
    vozerov@mba:~/events/terraform (master *) $ curl -D - -s http://130.193.37.94:8080/status
    HTTP/1.1 200 OK
    Date: Mon, 13 Apr 2020 16:32:15 GMT
    Content-Length: 3
    Content-Type: text/plain; charset=utf-8
    
    ok
    vozerov@mba:~/events/terraform (master *) $

    К слову, можно зайти на виртуалки с логином ubuntu и посмотреть логи контейнера и как он запущен.

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

    vozerov@mba:~/events/terraform (master *) $ yc load-balancer target-group list
    +----------------------+---------------+---------------------+-------------+--------------+
    |          ID          |     NAME      |       CREATED       |  REGION ID  | TARGET COUNT |
    +----------------------+---------------+---------------------+-------------+--------------+
    | b7rhh6d4assoqrvqfr9g | events-api-tg | 2020-04-13 16:23:53 | ru-central1 |            3 |
    +----------------------+---------------+---------------------+-------------+--------------+
    
    vozerov@mba:~/events/terraform (master *) $

    Давайте уже создадим балансировщик и попробуем пустить на него трафик! Этот процесс описан в load-balancer.tf, ключевые моменты:

    1. Указываем, какой внешний порт будет слушать балансировщик и на какой порт отправлять запрос к виртуальным машинам. Указываем тип внешнего адреса — ip v4. На данный момент балансировщик работает на транспортном уровне, поэтому балансировать он может только tcp / udp соединения. Так что прикручивать ssl придется либо на своих виртуалках, либо на внешнем сервисе, который умеет https, — например, cloudflare.

       listener {
      	  name = "events-api-listener"
      	  port = 80
      	  target_port = 8080
      	  external_address_spec {
      	    ipversion = "ipv4"
      	  }
      	}
    2. healthcheck {
      	  name = "http"
      	  http_options {
      	    port = 8080
      	    path = "/status"
      	  }
              }

      Healthchecks. Здесь мы указываем параметры проверки наших узлов — проверяем по http url /status на порту 8080. Если проверка будет провалена, то машинка будет выкинута из балансировки.

      Подробнее про балансировщик нагрузки — cloud.yandex.ru/docs/load-balancer/concepts. Из интересного — вы можете подключить услугу защиты от DDOS на балансировщике. Тогда на ваши сервера будет приходить уже очищенный трафик.

    Создаем:

    vozerov@mba:~/events/terraform (master *) $ terraform apply -target yandex_lb_network_load_balancer.events_api_lb
    
    ... skipped ...
    
    Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

    Вытаскиваем ip созданного балансировщика и тестируем работу:
    vozerov@mba:~/events/terraform (master *) $ yc load-balancer network-load-balancer get events-api-lb
    id:
    folder_id:
    created_at: "2020-04-13T16:34:28Z"
    name: events-api-lb
    region_id: ru-central1
    status: ACTIVE
    type: EXTERNAL
    listeners:
    - name: events-api-listener
      address: 130.193.37.103
      port: "80"
      protocol: TCP
      target_port: "8080"
    attached_target_groups:
    - target_group_id:
      health_checks:
      - name: http
        interval: 2s
        timeout: 1s
        unhealthy_threshold: "2"
        healthy_threshold: "2"
        http_options:
          port: "8080"
          path: /status

    Теперь можем покидать в него сообщения:

    vozerov@mba:~/events/terraform (master *) $ curl -D - -s -X POST -d '{"key1":"data1"}' http://130.193.37.103/post
    HTTP/1.1 200 OK
    Content-Type: application/json
    Date: Mon, 13 Apr 2020 16:42:57 GMT
    Content-Length: 41
    
    {"status":"ok","partition":0,"Offset":1}
    vozerov@mba:~/events/terraform (master *) $ curl -D - -s -X POST -d '{"key1":"data1"}' http://130.193.37.103/post
    HTTP/1.1 200 OK
    Content-Type: application/json
    Date: Mon, 13 Apr 2020 16:42:58 GMT
    Content-Length: 41
    
    {"status":"ok","partition":0,"Offset":2}
    vozerov@mba:~/events/terraform (master *) $ curl -D - -s -X POST -d '{"key1":"data1"}' http://130.193.37.103/post
    HTTP/1.1 200 OK
    Content-Type: application/json
    Date: Mon, 13 Apr 2020 16:43:00 GMT
    Content-Length: 41
    
    {"status":"ok","partition":0,"Offset":3}
    vozerov@mba:~/events/terraform (master *) $

    Отлично, все работает. Остался последний штрих, чтобы мы были доступны по https — подключим cloudflare с проксированием. Если вы решили обойтись без cloudflare, можете пропустить данный шаг.

    vozerov@mba:~/events/terraform (master *) $ terraform apply -target cloudflare_record.events
    
    ... skipped ...
    
    Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

    Тестируем через HTTPS:

    vozerov@mba:~/events/terraform (master *) $ curl -D - -s -X POST -d '{"key1":"data1"}' https://events.kis.im/post
    HTTP/2 200
    date: Mon, 13 Apr 2020 16:45:01 GMT
    content-type: application/json
    content-length: 41
    set-cookie: __cfduid=d7583eb5f791cd3c1bdd7ce2940c8a7981586796301; expires=Wed, 13-May-20 16:45:01 GMT; path=/; domain=.kis.im; HttpOnly; SameSite=Lax
    cf-cache-status: DYNAMIC
    expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
    server: cloudflare
    cf-ray: 5836a7b1bb037b2b-DME
    
    {"status":"ok","partition":0,"Offset":5}
    vozerov@mba:~/events/terraform (master *) $

    Все наконец-то работает.

    Тестируем нагрузку


    Нам остался, пожалуй, самый интересный шаг — провести нагрузочное тестирование нашего сервиса и получить некоторые цифры — например, 95 персентиль времени обработки одного запроса. Также было бы неплохо протестировать автомасштабирование нашей группы узлов.

    Перед запуском тестирования стоит сделать одну простую штуку — добавить наши application ноды в prometheus, чтобы следить за количеством запросов и временем обработки одного запроса. Поскольку мы пока не добавляли никакого service discovery (мы сделаем это в 5 статье серии), просто пропишем static_configs на нашем monitoring сервере. Узнать его ip можно стандартным способом через yc compute instance list, после чего дописать в /etc/prometheus/prometheus.yml следующие настройки:

      - job_name: api
        metrics_path: /metrics
        static_configs:
        - targets:
          - 172.16.3.3:8080
          - 172.16.2.31:8080
          - 172.16.1.37:8080

    IP-адреса наших машинок также можно взять из yc compute instance list. Рестартуем prometheus через systemctl restart prometheus и проверяем, что ноды успешно опрашиваются, зайдя в веб-интерфейс, доступный на порту 9090 (84.201.159.71:9090).

    Давайте еще добавим дашборд в графану из папки grafana. Заходим в Grafana по порту 3000 (84.201.159.71:3000) и с логином / паролем — admin / Password. Далее добавляем локальный prometheus и импортируем dashboard. Собственно, на этом моменте подготовка завершена — можно закидывать нашу инсталляцию запросами.

    Для тестирования будем использовать yandex tank (https://yandex.ru/dev/tank/) с плагином для overload.yandex.net, который позволит нам визуализировать данные, полученные танком. Все необходимое для работы находится в папке load изначального гит-репозитория.

    Немного о том, что там есть:

    1. token.txt — файл с API ключиком от overload.yandex.net — его можно получить, зарегистрировавшись на сервисе.
    2. load.yml — конфигурационный файл для танка, там прописан домен для тестирования — events.kis.im, тип нагрузки rps и количество запросов 15 000 в секунду в течение 3-х минут.
    3. data — специальный файл для генерации конфига в формате ammo.txt. В нем прописываем тип запроса, url, группу для отображения статистики и собственно данные, которые необходимо отправлять.
    4. makeammo.py — скрипт для генерации ammo.txt файла из data-файла. Подробнее про скрипт — yandextank.readthedocs.io/en/latest/ammo_generators.html
    5. ammo.txt — итоговый ammo файл, который будет использоваться для отправки запросов.

    Для тестирования я взял виртуалку за пределами Яндекс.Облака (чтобы все было честно) и создал ей DNS запись load.kis.im. Накатил туда docker, поскольку танк мы будем запускать, используя образ https://hub.docker.com/r/direvius/yandex-tank/.

    Ну что же, приступаем. Копируем нашу папку на сервер, добавляем токен и запускаем танк:

    vozerov@mba:~/events (master *) $ rsync -av load/ cloud-user@load.kis.im:load/
    
    ... skipped ...
    
    sent 2195 bytes  received 136 bytes  1554.00 bytes/sec
    total size is 1810  speedup is 0.78
    
    vozerov@mba:~/events (master *) $ ssh load.kis.im -l cloud-user
    cloud-user@load:~$ cd load/
    cloud-user@load:~/load$ echo "TOKEN" > token.txt
    cloud-user@load:~/load$ sudo docker run -v $(pwd):/var/loadtest --net host --rm -it direvius/yandex-tank -c load.yaml ammo.txt
    No handlers could be found for logger "netort.resource"
    17:25:25 [INFO] New test id 2020-04-13_17-25-25.355490
    17:25:25 [INFO] Logging handler <logging.StreamHandler object at 0x7f209a266850> added
    17:25:25 [INFO] Logging handler <logging.StreamHandler object at 0x7f209a20aa50> added
    17:25:25 [INFO] Created a folder for the test. /var/loadtest/logs/2020-04-13_17-25-25.355490
    17:25:25 [INFO] Configuring plugins...
    17:25:25 [INFO] Loading plugins...
    17:25:25 [INFO] Testing connection to resolved address 104.27.164.45 and port 80
    17:25:25 [INFO] Resolved events.kis.im into 104.27.164.45:80
    17:25:25 [INFO] Configuring StepperWrapper...
    17:25:25 [INFO] Making stpd-file: /var/loadtest/ammo.stpd
    17:25:25 [INFO] Default ammo type ('phantom') used, use 'phantom.ammo_type' option to override it
    
    ... skipped ...

    Все, процесс запущен. В консоли это выглядит примерно так:



    А мы ждем завершения процесса и наблюдаем за временем ответа, количеством запросов и, конечно, за автоматическим масштабированием нашей группы виртуальных машин. Мониторить группу виртуалок можно через веб-интерфейс, в настройках группы виртуальных машин есть вкладка «Мониторинг».



    Как можно заметить — наши ноды не догрузились даже до 50% CPU, поэтому тест с автомасштабированием придется повторить. А пока глянем на время обработки запроса в Grafana:



    Количество запросов — порядка 3000 на одну ноду — немного до 10 000 не догрузили. Время ответа радует — порядка 11 ms на запрос. Единственный, кто выделяется, — 172.16.1.37 — у него время обработки запроса в два раза меньше. Но это и логично — он находится в той же зоне доступности ru-central1-a, что и kafka, которая сохраняет сообщения.

    Кстати, отчет по первому запуску доступен по ссылке: https://overload.yandex.net/265967.

    Итак, давайте запустим тест повеселее — добавим параметр instances: 2000, чтобы добиться 15 000 запросов в секунду, и увеличим время теста до 10 минут. Итоговый файл будет выглядеть так:

    overload:
      enabled: true
      package: yandextank.plugins.DataUploader
      token_file: "token.txt"
    phantom:
      address: 130.193.37.103
      load_profile:
        load_type: rps
        schedule: const(15000, 10m)
      instances: 2000
    console:
      enabled: true
    telegraf:
      enabled: false

    Внимательный читатель обратит внимание, что я поменял адрес на IP балансировщика — связано это с тем, что cloudflare начал меня блочить за огромное количество запросов с одного ip. Пришлось натравить tank напрямую на балансер Яндекс.Облака. После запуска можно наблюдать такую картину:



    Использование CPU выросло, и планировщик принял решение увеличить количество нод в зоне B, что и сделал. Это можно увидеть по логам instance group:

    vozerov@mba:~/events/load (master *) $ yc compute instance-group list-logs events-api-ig
    2020-04-13 18:26:47    cl1s2tu8siei464pv1pn-ejok.ru-central1.internal  1m AWAITING_WARMUP_DURATION -> RUNNING_ACTUAL
    2020-04-13 18:25:47    cl1s2tu8siei464pv1pn-ejok.ru-central1.internal 37s OPENING_TRAFFIC -> AWAITING_WARMUP_DURATION
    2020-04-13 18:25:09    cl1s2tu8siei464pv1pn-ejok.ru-central1.internal 43s CREATING_INSTANCE -> OPENING_TRAFFIC
    2020-04-13 18:24:26    cl1s2tu8siei464pv1pn-ejok.ru-central1.internal  6s DELETED  -> CREATING_INSTANCE
    2020-04-13 18:24:19    cl1s2tu8siei464pv1pn-ozix.ru-central1.internal  0s PREPARING_RESOURCES -> DELETED
    2020-04-13 18:24:19    cl1s2tu8siei464pv1pn-ejok.ru-central1.internal  0s PREPARING_RESOURCES -> DELETED
    2020-04-13 18:24:15    Target allocation changed in accordance with auto scale policy in zone ru-central1-a: 1 -> 2
    2020-04-13 18:24:15    Target allocation changed in accordance with auto scale policy in zone ru-central1-b: 1 -> 2
    
    ... skipped ...
    
    2020-04-13 16:23:57    Balancer target group b7rhh6d4assoqrvqfr9g created
    2020-04-13 16:23:43    Going to create balancer target group
    

    Также планировщик решил увеличить количество серверов и в других зонах, но у меня закончился лимит на внешние ip-адреса :) Их, кстати, можно увеличить через запрос в техподдержку, указав квоты и желаемые значения.

    Заключение


    Нелегкой выдалась статья — и по объему, и по количеству информации. Но самый трудный этап мы прошли и сделали следующее:

    1. Подняли мониторинг и кафку.
    2. Создали группу виртуалок с автомасштабированием, на которых запускается наше приложение.
    3. Подвязали к load balancer’у cloudflare для использования ssl сертификатов.

    В следующий раз займемся сравнением и тестированием rabbitmq / kafka / yandex queue service.
    Stay tuned!

    *Этот материал есть в видеозаписи открытого практикума REBRAIN & Yandex.Cloud: Принимаем 10 000 запросов в секунду на Яндекс Облако — https://youtu.be/cZLezUm0ekE

    Если вам интересно посещать такие мероприятия онлайн и задавать вопросы в режиме реального времени, подключайтесь к каналу DevOps by REBRAIN.

    Отдельное спасибо хотим сказать Yandex.Cloud за возможность проведения такого мероприятия. Ссылочка на них

    Если вам нужен переезд в облако или есть вопросы по вашей инфраструктуре, смело оставляйте заявку.

    P.S. У нас есть 2 бесплатных аудита в месяц, возможно, именно ваш проект будет в их числе.
    Ребреин
    REBRAIN: Онлайн-практикумы для Инженеров

    Похожие публикации

    Комментарии 3

      +1
      Молодцы. Продолжайте в том же духе.
        +1
        Отличная статья! Замечательная подаача материала :)
          +1
          Прекрасный материал :)

          Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

          Самое читаемое