[Node.js_4기] 최종프로젝트 2주차_day5_부하테스트와 정신나갈것 같은 api 요청 한계 (24/04/07)

2024. 4. 7. 16:36공부/내배캠 TIL

목차

 

1. 문제

2. 시도

3. 결과

4. 배운점

 

1. 문제 

 

이전에 작성했던 코드가 artillery 시나리오 테스트를 전혀 통과하지 못하는 문제 발생.

  public async processImageAndManageDiet(
    processImageAndManageDietDto: ProcessImageAndManageDietDto,
  ): Promise<string> {
    const imageText = await imageToText(this.openai, {
      prompt: processImageAndManageDietDto.imageUrl,
    });

    const csvDataArray = await this.readLocalCsv();
    const csvDataString = JSON.stringify(csvDataArray);

    const dietResponse = await dietManagerWithCsv(this.openai, {
      prompt: imageText.content,
      csvData: csvDataString,
    });

    return dietResponse.content;
  }

해당 코드는 매 호출마다 38kb의 csv파일을 불러와 stringfy 과정까지 거쳐 gpt에 넣어주고 있음.

  private async readLocalCsv(): Promise<any[]> {
    const filePath = 'food_ai_db.csv';
    return new Promise((resolve, reject) => {
      const results = [];
      fs.createReadStream(filePath)
        .pipe(csv())
        .on('data', (data) => {
          const extractedData = {
            foodName: data['\ufeff음 식 명'],
            calories: data['에너지(kcal)'],
            carbs: data['탄수화물(g)'],
            protein: data['단백질(g)'],
          };
          results.push(extractedData);
        })
        .on('end', () => resolve(results))
        .on('error', (error) => reject(error));
    });
  }

또, csv 파일을 읽어오는 과정에서도 

file IO -> fileblocking 발생.

stream을 생성하고 있기 때문에, 해당 stream이 닫힐때 까지 다른 stream 생성이 불가.

동시성을 막고있는 가장 큰 문제는 이 로직으로 보인다.

 

2. 시도 

   

그래서 해당 데이터들을 db에 올려버리고, 쿼리를 통해 가져온 뒤, gpt에 넣어주는 방식으로 문제를 해결하고자 한다.

private async getFoodItemData(): Promise<string[]> {
    const foodItems = await this.foodItemRepository
      .createQueryBuilder('foodItem')
      .select([
        'foodItem.foodName',
        'foodItem.energy',
        'foodItem.carbohydrate',
        'foodItem.fat',
        'foodItem.protein',
      ])
      .getMany();

    return foodItems.map(
      (item) =>
        `${item.foodName} : energy:${item.energy} kcal, carbohydrate:${item.carbohydrate} g, fat:${item.fat} g, protein:${item.protein} g`,
    );
  }

중간에, 최대 토큰 16355에 16685만큼의 토큰을 넣어 오류가 나서 map된 string을 조금 손봐주었다.

public async processImageAndManageDietDB(
    processImageAndManageDietDto: ProcessImageAndManageDietDto,
  ): Promise<string> {
    const imageText = await imageToText(this.openai, {
      prompt: processImageAndManageDietDto.imageUrl,
    });

    const csvDataArray = await this.getFoodItemData();
    const csvDataString = JSON.stringify(csvDataArray);

    const dietResponse = await dietManagerWithCsv(this.openai, {
      prompt: imageText.content,
      csvData: csvDataString,
    });

    return dietResponse.content;
  }

넣어주는 csvData를 받아오는 함수가, readLocalCsv()에서 getFoodItemData()로 바뀌었다.

 

3. 결과 

 

insomenia 테스트 결과는 성공했다.

 

그러나...

config:
  target: 'http://localhost:3001'
  phases:
    - duration: 60
      arrivalRate: 1
      rampTo: 3
      name: Warm up phase
scenarios:
  - flow:
      - post:
          url: '/gpt/processImageAndManageDietDB'
          json:
            imageUrl: 'https://upload.wikimedia.org/wikipedia/commons/b/ba/Chicken_slider_combo_from_Dave%27s_Hot_Chicken.jpg'
  • 전체 요약:
    • 총 120개의 가상 사용자(vusers) 세션이 생성되었으며, 그 중 83개가 실패했습니다 (타임아웃 오류).
    • HTTP 요청은 총 120건으로, 이 중 3건은 201(생성됨) 상태 코드를, 34건은 500(서버 오류) 상태 코드를 받았습니다.
    • 평균 응답 시간은 6273.2ms로, 응답 시간 범위는 최소 1596ms에서 최대 9954ms였습니다.
    • 사용자 세션 길이도 비슷한 패턴을 보여주었으며, 평균은 6277ms였습니다.
  • 중간 데이터 분석:
    • 여러 시간대의 성능 데이터가 있으며, 각각의 기간에 대해 생성된 사용자 수, HTTP 요청 수, 오류 수 등의 정보가 포함되어 있습니다.
    • 특정 기간 동안의 평균 응답 시간, 최소/최대 응답 시간, 세션 길이 등 세부적인 성능 지표도 제공됩니다.

artillery run --output report.json ./test-script.yaml로 테스트한 결과를 gpt에 요약해달라고 한 내용. 

성공 3회, 서버오류 34회, 타임아웃 83회라는 기록할만한 실패 결과를 보여줍니다.

 
오류코드에 대한 질문.

[프로젝트이름] Error    2024. 4. 7. 오후 4:12:57 [ExceptionsHandler] 429 Rate limit reached for gpt-4-vision-preview in organization org-9KnKHH9296Sz56s3nZmokcKv on tokens per min (TPM): Limit 10000, Used 9952, Requested 1484. Please try again in 8.616s. Visit https://platform.openai.com/account/rate-limits to learn more. - {
  stack: [
    'Error: 429 Rate limit reached for gpt-4-vision-preview in organization org-9KnKHH9296Sz56s3nZmokcKv on tokens per min (TPM): Limit 10000, Used 9952, Requested 1484. Please try again in 8.616s. Visit https://platform.openai.com/account/rate-limits to learn more.\n' +
      '    at Function.generate (C:\\Users\\DongWon\\Desktop\\sparta\\_Final\\project\\be\\node_modules\\openai\\src\\error.ts:91:14)\n' +
      '    at OpenAI.makeStatusError (C:\\Users\\DongWon\\Desktop\\sparta\\_Final\\project\\be\\node_modules\\openai\\src\\core.ts:383:21)\n' +
      '    at OpenAI.makeRequest (C:\\Users\\DongWon\\Desktop\\sparta\\_Final\\project\\be\\node_modules\\openai\\src\\core.ts:446:24)\n' +
      '    at processTicksAndRejections (node:internal/process/task_queues:95:5)\n' +
      '    at imageToText (C:\\Users\\DongWon\\Desktop\\sparta\\_Final\\project\\be\\src\\gpt\\use-cases\\imageToText.use-case.ts:8:22)\n' +
      '    at GptService.processImageAndManageDietDB (C:\\Users\\DongWon\\Desktop\\sparta\\_Final\\project\\be\\src\\gpt\\gpt.service.ts:70:23)\n' +
      '    at C:\\Users\\DongWon\\Desktop\\sparta\\_Final\\project\\be\\node_modules\\@nestjs\\core\\router\\router-execution-context.js:46:28\n' +
      '    at C:\\Users\\DongWon\\Desktop\\sparta\\_Final\\project\\be\\node_modules\\@nestjs\\core\\router\\router-proxy.js:9:17'
  ]
}


OpenAI의 GPT-4 Vision API를 사용할 때 발생한 오류를 나타냅니다. 구체적으로, API 요청이 조직의 토큰당 분(TPM) 속도 제한을 초과했다는 내용입니다. 요약하자면:
오류 유형: 429 Rate Limit 오류
시간: 2024년 4월 7일 오후 4:12:57
세부 정보:
사용된 API: gpt-4-vision-preview
조직 ID: org-9KnKHH9296Sz56s3nZmokcKv
TPM 제한: 10,000
사용된 토큰 수: 9,952
요청된 토큰 수: 1,484
해결 조치: 8.616초 후에 다시 시도하시기 바랍니다.
추가 정보 링크: OpenAI Platform Rate Limits
이 로그는 프로젝트가 짧은 시간에 많은 양의 API 요청을 보내면서 속도 제한에 도달했음을 의미합니다. 

 

4. 배운점 

 

일단 해당사항은 해결하지 못했습니다.

월요일, 튜터님과의 면담을 통해 해결책을 강구해볼 생각입니다. 아마 추가 과금을 통해 티어를 높이는 등의 방안을 생각해야 하거나, 요청 데이터를 더욱 줄이거나 해야 할 것 같습니다.(칼로리의 경우 그냥 계산을 때려버린다거나...)

 

최대 요청 가능 토큰 수 자체가 낮아서 생기는 문제로, 해결하기 힘들어 보입니다.