При разработке теста задержки для бессерверных баз данных (DynamoDB, FaunaDB, Upstash) я хотел, чтобы был API, где я буду записывать цифры задержки и получать гистограмму. В этом уроке я создам такой API, в котором вы сможете записывать значения задержки из любого приложения. Это будет бессерверный REST API со следующими методами:

  • запись: записывает числовые значения в гистограмму.
  • get: возвращает объект гистограммы.

Мотивация

Я покажу, как легко разработать общий API с помощью AWS Lambda и Serverless Redis.

Step-1: Создайте базу данных Redis (Upstash)

Создайте базу данных, как указано в разделе Начало работы.

Step-2: Настройка бессерверного проекта

Если у вас его еще нет, установите бессерверную структуру через:

npm install -g serverless

В любой папке запустите serverless, как показано ниже:

>> serverless

Serverless: No project detected. Do you want to create a new one? Yes
Serverless: What do you want to make? AWS Node.js
Serverless: What do you want to call this project? histogram-api

Project successfully created in 'histogram-api' folder.

You can monitor, troubleshoot, and test your new service with a free Serverless account.

Serverless: Would you like to enable this? No
You can run the “serverless” command again if you change your mind later.

Внутри папки проекта создайте проект узла с помощью команды:

npm init

Затем установите клиент Redis и библиотеку гистограмм с помощью:

npm install ioredis

npm install hdr-histogram-js

Обновите serverless.yml, как показано ниже. Скопируйте URL-адрес Redis из консоли и замените ниже:

service: histogram-api
frameworkVersion: '2'

provider:
  name: aws
  runtime: nodejs12.x
  lambdaHashingVersion: 20201221
  environment:
    REDIS_URL: REPLACE_YOUR_URL_HERE

functions:
  record:
    handler: handler.record
    events:
      - httpApi:
          path: /record
          method: post
          cors: true
  get:
    handler: handler.get
    events:
      - httpApi:
          path: /get
          method: get
          cors: true

Шаг 3: Код

Отредактируйте handler.js, как показано ниже:

const hdr = require("hdr-histogram-js");
const Redis = require("ioredis");
if (typeof client === 'undefined') {
    var client = new Redis(fixUrl(process.env.REDIS_URL));
}
const headers = {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Credentials': true,
};
const SIZE = 10000;

module.exports.get = async (event) => {
    if (!event.queryStringParameters || !event.queryStringParameters.name) {
        return {
            statusCode: 400,
            headers: headers,
            body: JSON.stringify(
                {
                    message: 'Invalid parameters. Name is needed.',
                }
            ),
        };
    }
    const name = event.queryStringParameters.name;
    const data = await client.lrange(name, 0, SIZE);
    const histogram = hdr.build();
    data.forEach(item => {
        histogram.recordValue(item);
    })

    return {
        statusCode: 200,
        body: JSON.stringify(
            {
                histogram: histogram
            }
        ),
    };
};

module.exports.record = async (event) => {
    let body = JSON.parse(event.body)
    if (!body || !body.name || !body.values) {
        return {
            statusCode: 400,
            headers: headers,
            body: JSON.stringify(
                {
                    message: 'Invalid parameters. Name and values are needed.',
                }
            ),
        };
    }
    const name = body.name;
    const values = body.values;
    await client.lpush(name, values)
    return {
        statusCode: 200,
        body: JSON.stringify(
            {
                message: 'Success',
                name: name
            }
        ),
    };
};


function fixUrl(url) {
    if (!url) {
        return ''
    }
    if (url.startsWith('redis://') && !url.startsWith('redis://:')) {
        return url.replace('redis://', 'redis://:')
    }
    if (url.startsWith('rediss://') && !url.startsWith('rediss://:')) {
        return url.replace('rediss://', 'rediss://:')
    }
    return url
}

У нас есть две бессерверные функции выше. get принимает name в качестве параметра и загружает список из Redis. Затем строит гистограмму, используя значения в списке.

Функция record принимает name и values в качестве параметров. Он добавляет values в список Redis с именем name.

Функция get вычисляет гистограмму по последним 10000 записям задержки. Обновите параметр SIZE, чтобы изменить это число.

fixUrl — это вспомогательный метод, который исправляет формат URL-адреса Redis.

Шаг 4. Разверните свои функции

Разверните свои функции с помощью:

serverless deploy

Команда развернет две функции и выведет две конечные точки. Попробуйте конечные точки с настройкой параметров, как показано ниже:

Запишите значения задержки в perf-test-1:


curl --header "Content-Type: application/json" -d "{\"name\":\"perf-test-1\", \"values\": [90,80,34,97,93,45,49,57,99,12]}" https://v7xx4aa2ib.execute-api.us-east-1.amazonaws.com/record

Получите гистограмму для perf-test-1:

curl https://v7xx4aa2ib.execute-api.us-east-1.amazonaws.com/get?name=perf-test-1

Дозирование

Каждый раз вызывать удаленную функцию для расчета задержки может быть дорого. В вашем приложении вы должны хранить массив или очередь в качестве буфера для значений задержки, а затем отправлять их пакетами в API, когда массив достигает размера пакета. Что-то вроде ниже:

Первоначально опубликовано на https://docs.upstash.com.