아래와 같은 방식으로 하면 로컬에서 레디스를 사용할 수 있는데 테스트용으로 일단 로컬에서 레디스 연결을 하였고, 이후 배포 인스턴스에서 사용할때는 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 사용하는걸 너무 잘 설명해줘서 많이 참고하였다. 또한, 공식 문서도 정리가 잘 되어있어서 많이 참고하였다.
Artillery를 사용해서 동시성 제어 테스트를 진행해보았다. arrivalRate: 30
, duration:1
로 주어 30명의 가상 사용자가 동시에 이송 신청 요청 API 호출을 하는걸 테스트 해보았다. 이 지표를 선정한 이유는 저렇게 해주었을때 트랜젝션 없는 API & locking을 위해 트랜젝션을 넣은 API 둘 다에서 실패하였기 때문이다. BullQueue를 적용시키니 제어가 확실하게 되었다. 위의 지표는 계속 증가시켜나갈 예정이고, 어디까지 테스트를 하는게 유의미할지는 아직 모르겠다.
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
소실된 의식,심부전,발작,혼란 상태,가슴 통증,뇌경색 증상,사지 마비,의식 변화|임산부
소실된 의식,심부전,발작,혼란 상태,가슴 통증,뇌경색 증상,사지 마비|임산부
청각 손실,소실된 의식,사지 마비,가슴 통증|임산부
음식 섭취 곤란,감각 소실,가슴 통증|임산부
저체온증|임산부
소실된 의식,심부전,발작,혼란 상태,가슴 통증,뇌경색 증상,사지 마비,의식 변화|영유아
소실된 의식,심부전,발작,혼란 상태,가슴 통증,뇌경색 증상,사지 마비|영유아
...
각 증상 보고서마다 중증도 레벨이 판정이 되고 해당 레벨이 높을 수록 위급한 환자이므로 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];
};
우선순위 점수 매기는 걸 간단하게만 정해서 테스트만 해보았는데 더 확실한 체계를 위해 의사결정이 필요할듯하다.