Как стать автором
Обновить

Кто такая эта Ваша Pandora и при чем здесь Tarantool

Высокая производительность *Тестирование IT-систем *Lua *Go *
Tutorial


Привет, меня зовут Иван, и я занимаюсь разработкой высоконагруженных решений на Tarantool. Я расскажу про то, как и почему мы выбрали Pandora для нагрузочного тестирования приложения на Tarantool, а также покажу пример, как ей воспользоваться.


Описание тестируемого приложения


Протестируем модуль распределенной очереди sharded-queue на предмет того, как быстро можно вставлять и забирать задачи очереди. API приложения основано на бинарном протоколе, который позволяет совершать базовые операции с данными, вызывать функции (RPC), а также выполнять пользовательский код на lua. В нашем случае это две функции: queue.tube_name:put и queue.tube_name:take.


Выбор инструмента для тестирования


Инструментов для тестирования существует очень много, но нам нужно выбрать среди них подходящие. Подбирать будем по следующим критериям:


  1. Нужно ходить по бинарному протоколу. Поэтому придется писать код на языке программирования, для которого есть коннектор к Tarantool. На это способны Jmeter, bfg, Pandora и Gatling.
  2. Нужно уметь создавать относительно высокую нагрузку со скромными ресурсами. Здесь могут подойти Phantom, wrk, Jmeter, Pandora и Gatling.
  3. Хотим тестировать сложные сценарии взаимодействия. Также полезно управлять характеристиками нагрузки, например, создавать резкий рост или поддерживать постоянное значение.Уверенно могут это делать bfg, Pandora и Gatling.
  4. Хотим видеть информативные красивые графики. Они полезны для выявления зависимостей между нагрузкой и возникающими ошибками. Их умеют отдавать в influxdb, например, Jmeter и Gatling. Вместе с Taurus может работать куча всего (полный список тут). Вместе с Яндекс.Танком это могут делать Jmeter, Pandora, bfg и Phantom.
  5. Не хотим тратить время на разработку нового решения или серьезные доработки существующего. Писать хорошее решение, которое удовлетворит наши потребности и найдёт применение в других проектах — себе дороже.

Если сопоставить возможные варианты по всем пунктам, у нас останутся следующие претенденты: Яндекс.Танк вместе с Jmeter и Pandora, или Taurus вместе с Jmeter и Gatling.


Что не так с Jmeter или Gatlling?


Это Java-стек, а Java, Groovy и Scala не очень близки нашей команде. Чтобы начать писать код на них, потребуется намного больше сил и времени, чем, например на Go.


Остается Pandora — нагрузчик, написанный на Go для Яндекс.Танка.


Почему Go — это хорошо?


Он простой, быстрый, и поддерживает асинхронность на уровне языка. Tarantool дружит с Go: есть коннектор и опыт его использования.


Почему Pandora — это хорошо?


В коробке идет удобный интерфейс для написания своих тестов на Go.


Почему Яндекс.Танк — это хорошо?


Это известный, проверенный временем инструмент с русскоязычным сообществом, c обширными возможностями для анализа производительности приложений, который, к тому же, используется у нашего клиента.


Кастомная пушка и тесты as code


Давайте приоткроем, наконец, ящик Пандоры и напишем первый тест для нашего приложения.


Что для этого нужно?


Конечно, зависимости.


go get github.com/tarantool/go-tarantool \
    github.com/spf13/afero          \
    github.com/yandex/pandora

И необходимые компоненты пушки: структуры и методы для конфигурации, соединения с приложением и стрельбы.


  • Патроны:


    type Ammo struct {
        Method   string
        TubeName string
        Params   map[string] interface {}
    }

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


    Для нашего теста предусмотрены два типа запросов: добавление в очередь и взятие из очереди.
    Опишем их в файле tnt_queue_ammo.json:


    {"Method": "put", "TubeName": "test-tube", "Params": {"data": "task"}}
    {"Method": "take", "TubeName": "test-tube"}

    TubeName — название очереди в терминах sharded-queue.


  • Конфигурация пушки:


    type GunConfig struct {
        Target []string `validate:"required"`
        User   string   `validate:"required"`
        Pass   string   `validate:"required"`
    }

    Параметры пушки в этом формате нужно описывать в yaml-файле с конфигурацией нагрузочного тестирования Pandora в разделе gun:


    gun:
        type: tnt_queue_gun
        target:
            - localhost:3301
            - localhost:3302
        user: admin
        pass: queue-app-cluster-cookie

    В нашем случае это список целевых узлов для запросов и параметры подключения к кластеру. type задается при регистрации пушки.


  • Пушка:


    type Gun struct {
        conn *tarantool.Connection
        conf GunConfig
        aggr core.Aggregator
    }

    Она хранит конфигурацию и агрегирует результаты, а также может содержать пользовательские поля (у нас это соединение с Tarantool).


    Для инициализации пушки нам нужно определить метод Bind. В нем мы создадим соединение с одним из роутеров приложения. Выберем его случайно.


    func (g *Gun) Bind(aggr core.Aggregator, deps core.GunDeps) error {
        conn, err := tarantool.Connect(
            g.conf.Target[rand.Intn(len(g.conf.Target))],
            tarantool.Opts{
                User: g.conf.User,
                Pass: g.conf.Pass,
            },
        )
    
        if err != nil {
            log.Fatalf("Error: %s", err)
        }
        g.conn = conn
        g.aggr = aggr
    
        return nil
    }

    Для выстрела из пушки нужно определить метод Shoot. Именно он содержит логику выбора сценария и выполнения запроса. Внутри, в зависимости от поданного снаряда, мы либо положим в тарантульную очередь новую задачу, либо попробуем взять уже существующую.


    За методом queueCall скрыт вызов через к Tarantool через go-tarantool:


    func (g *Gun) Shoot(coreAmmo core.Ammo) {
        ammo := coreAmmo.(*Ammo)
        sample := netsample.Acquire(ammo.Method)
    
        code := 200
        var err error
    
        startTime := time.Now()
        switch ammo.Method {
        case "put":
            _, err = g.queueCall(ammo.TubeName, "put", ammo.Params["data"])
        case "take":
            _, err = g.queueCall(ammo.TubeName, "take")
        }
        sample.SetLatency(time.Since(startTime))
        if err != nil {
            log.Printf("Error %s task: %s", ammo.Method, err)
            code = 500
        }
    
        defer func() {
            sample.SetProtoCode(code)
            sample.AddTag(ammo.TubeName)
            g.aggr.Report(sample)
        }()
    }

    Для мониторинга используются следующие метрики:


    • Задержка.
    • Код возврата (мимикрируем под HTTP).
    • Тег с названием трубы, в которую происходит запись.

    Можно расширить этот набор, а полный список параметров есть здесь. Однако не все из них можно замерять. При необходимости, добавить поддержку интересующего параметра можно так.



Стрельба по распределенной очереди


Перед началом обстрела укажем нужный нам характер нагрузки: линейный рост с 20 тыс. до 25 тыс. запросов в секунду и продолжительностью 60 секунд. Количество виртуальных пользователей (экземпляров нагрузчика) установим 1 тыс.


rps:
    duration: 60s
    type: line
    from: 20000
    to: 25000
startup:
    type: once
    times: 1000

Остается только подключить к Танку нашу новую пушку:


pandora:
    enabled: true
    package: yandextank.plugins.Pandora
    pandora_cmd: ./tnt_queue_gun
    config_file: ./tnt_queue_load.yaml

И начать стрелять:


docker run -v $(pwd):/var/loadtest   \
        -v $SSH_AUTH_SOCK:/ssh-agent \
        -e SSH_AUTH_SOCK=/ssh-agent  \
        --net host                   \
        -it direvius/yandex-tank

Результаты увидим в красивой консоли:



Итоги


Нам удалось относительно просто и быстро написать нагрузочный тест в виде Go-кода для приложения на Tarantool, с большими возможностями по кастомизации.


Например, можно добавить сценарий с операцией queue.tube_name:ack, сохраняя ID взятых задач. Если нужны графики, то можно настроить запись результатов в InfluxDB и подключить Grafana-дашборд или просто воспользоваться сервисом Overload.


Полный код пушки, все конфиги и инструкции по сборке и запуску можно найти в этом репозитории.


За более подробной информацией об архитектуре и возможностях Pandora можно обратиться к докладу ее создателя на конференции Heisenbug .

Теги:
Хабы:
Всего голосов 9: ↑6 и ↓3 +3
Просмотры 4.3K
Комментарии 0
Комментарии Комментировать

Публикации