Redis로 서버리스 히스토그램 API 구축

18208 단어 serverlessredisawsnode
개발하는 동안the latency benchmark for the serverless databases (DynamoDB, FaunaDB, Upstash), 지연 시간을 기록하고 히스토그램을 다시 가져오는 API가 있었으면 했습니다. 이 자습서에서는 모든 애플리케이션의 대기 시간 값을 기록할 수 있는 API를 빌드합니다. 다음 메소드를 사용하는 REST API가 됩니다.
  • 레코드: 히스토그램에 숫자 값을 기록합니다.
  • get: 히스토그램 개체를 반환합니다.

  • 동기 부여



    AWS Lambda와 Serverless Redis를 사용하여 일반 API를 개발하는 것이 얼마나 쉬운지 보여드리겠습니다.

    code 을 참조하십시오.

    1 Redis(Upstash) 데이터베이스 생성



    getting started으로 데이터베이스 생성

    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를 아래와 같이 업데이트합니다. 콘솔에서 Redis URL을 복사하고 아래를 바꿉니다.

    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
    }
    


    위의 두 가지 서버리스 기능이 있습니다. getname를 매개변수로 사용하고 Redis에서 목록을 로드합니다. 그런 다음 목록의 값을 사용하여 히스토그램을 작성합니다.
    record 함수는 namevalues를 매개변수로 사용합니다. 이름이 values 인 Redis 목록에 name 를 추가합니다.
    get 함수는 최근 10000개의 대기 시간 레코드에 대한 히스토그램을 계산합니다. 이 숫자를 변경하려면 SIZE 매개변수를 업데이트하십시오.
    fixUrl는 Redis URL 형식을 수정하는 도우미 메서드입니다.

    4 API 배포 및 시도



    다음을 사용하여 기능을 배포합니다.

    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에 배치로 제출해야 합니다. 아래와 같은 것:

    let records = [];
    let batchSize = 1000;
    function recordLatency(value) {
        records.push(value);
       if(records.length >= batchSize) {
           // the below submits the records to the API then empties the records array.
           submitToAPI(records);
       } 
    }
    

    좋은 웹페이지 즐겨찾기