[TIL] BullQueue 동시성 제어

김시원·2023년 6월 7일
0

TIL

목록 보기
40/50
post-custom-banner

📌 What I did today

1. Redis docker 써서 연결하기

아래와 같은 방식으로 하면 로컬에서 레디스를 사용할 수 있는데 테스트용으로 일단 로컬에서 레디스 연결을 하였고, 이후 배포 인스턴스에서 사용할때는 docker-compose.yml 파일을 정의해서 설정을 해주어야 한다.

$ docker pull redis
$ docker network create redis-net
$ docker run --name redis -p 6379:6379 --network redis-net -d redis redis-server --appendonly yes

아래 블로그에서 Nest.js에서 BullQueue 사용하는걸 너무 잘 설명해줘서 많이 참고하였다. 또한, 공식 문서도 정리가 잘 되어있어서 많이 참고하였다.

2. 동시성 제어 테스트 w/ Artillery

Artillery를 사용해서 동시성 제어 테스트를 진행해보았다. arrivalRate: 30, duration:1로 주어 30명의 가상 사용자가 동시에 이송 신청 요청 API 호출을 하는걸 테스트 해보았다. 이 지표를 선정한 이유는 저렇게 해주었을때 트랜젝션 없는 API & locking을 위해 트랜젝션을 넣은 API 둘 다에서 실패하였기 때문이다. BullQueue를 적용시키니 제어가 확실하게 되었다. 위의 지표는 계속 증가시켜나갈 예정이고, 어디까지 테스트를 하는게 유의미할지는 아직 모르겠다.

3. Artillery: csv 파일을 이용하여 다양한 body data 전달

config:
  target: "http://localhost:3000"
  phases:
    - arrivalRate: 30
      duration: 5
  payload:
    path: "data.csv"
    order: random
    delimiter: "|"
    skipHeader: true
    fields:
      - "symptoms"
      - "age_range"
scenarios:
  - flow: 
    - log: "증상 보고서 입력 POST 요청 시도"
    - post:
        url: "http://localhost:3000/report"
        json:
          symptoms: "{{symptoms}}"
          age_range: "{{age_range}}"
        capture:
          json: "$.report_id"
          as: "report_id"
    - log: "환자 이송 신청 POST 요청 시도"
    - post:
        url: "http://localhost:3000/request/{{report_id}}/5"

data.csv 파일에 body 데이터로 전달할 value값들을 넣어줘서 각 요청이 랜덤하게 row를 가져갈 수 있도록 설정해주었다.

# data.csv

symptoms|age_range
소실된 의식,심부전,발작,혼란 상태,가슴 통증,뇌경색 증상,사지 마비,의식 변화|임산부
소실된 의식,심부전,발작,혼란 상태,가슴 통증,뇌경색 증상,사지 마비|임산부
청각 손실,소실된 의식,사지 마비,가슴 통증|임산부
음식 섭취 곤란,감각 소실,가슴 통증|임산부
저체온증|임산부
소실된 의식,심부전,발작,혼란 상태,가슴 통증,뇌경색 증상,사지 마비,의식 변화|영유아
소실된 의식,심부전,발작,혼란 상태,가슴 통증,뇌경색 증상,사지 마비|영유아
...

4. Queue에 add되는 job에 우선순위 매기기

각 증상 보고서마다 중증도 레벨이 판정이 되고 해당 레벨이 높을 수록 위급한 환자이므로 queue에서 우선순위를 매겨서 중증도가 높은 환자가 먼저 요청을 할 수 있도록 설정해주고 싶었다.
또한, 중증도 레벨 말고도 환자의 타입 (임산부, 영유아, 성인, 노년, 청소년)도 고려 대상에 넣고 싶어서 symptom_level과 환자 age_range에 각각 가중치를 부여해서 priority를 넘겨주었다.

const job = await this.requestQueue.add(
      'addRequestQueue',
      { report_id, hospital_id, eventName },
      {
        removeOnComplete: true,
        removeOnFail: true,
        priority: this.getPriority(report),
      }, 
);
getPriority = (report: Reports): number => {
    const { symptom_level, age_range } = report;
    const symptomLevel = 6 - symptom_level;

    const ageRangeMap: { [key: string]: number } = {
      임산부: 1,
      영유아: 2,
      노년: 3,
      청소년: 4,
      성인: 5,
    };

    return !age_range ? symptomLevel : symptomLevel * ageRangeMap[age_range];
  };

우선순위 점수 매기는 걸 간단하게만 정해서 테스트만 해보았는데 더 확실한 체계를 위해 의사결정이 필요할듯하다.

post-custom-banner

0개의 댓글