NestJs + Prisma 조합으로 신규 프로젝트를 진행하던 중 매일 새벽 1시마다 해당 날짜의 유가/최저가 주유소 관련 정보를 각각 Opinet의 API로 조회해서 저장하는 독립된 배치 2개를 구현하였었다. 유가 정보 조회/저장 배치가 스테이지 환경에서 정상적으로 동작하는 것을 확인하고, 최저가 주유소 관련 배치를 스테이지 환경에 배포해둔 상황이었다. DB 최저가 주유소 관련 테이블에 row들이 정상적으로 저장된 것을 확인하고, 해당 배치 기능은 완료된 것으로 생각하고 있었다.
유가 정보를 저장하고 있는 테이블과 최저가 주유소 정보를 저장하고 있는 테이블이 서로 연관이 없고, 독립된 배치에서 실행되고 있는 상황이라 insert 관련 락이나 PK 관련 이슈가 없을 거라고 생각하면서 DB와 서버 로그를 확인해보았는데 DB의 경우, 스테이지에 최저가 주유소 관련 배치를 배포해둔 이후로 유가 정보 테이블에 변경 사항이 없고, 최저가 주유소 테이블에만 꾸준히 변경사항이 적용되고 있었다. 서버 로그를 확인해보니 아래와 같은 이유로 트랜잭션 생성에 실패하였다는 로그만 남아있었다.
prisma transaction api error: unable to start a transaction in the given time.
해당 로그를 확인해보면 주어진 시간(default 5s)내에 prisma orm이 트랜잭션을 시작하지 못해 prisma 단에서 timeout 에러가 발생하고 있었다. 기존에 유가 정보 로직만 배치가 실행될 때는 상관이 없었지만, 최저가 주유소 관련 로직이 추가되면서 독립된 2개의 배치가 동일한 시간에 default 기준 5s의 텀도 없이 prisma의 $transaction api를 2번 호출해서 첫 번째 $transaction api에서 timeout 에러가 발생한 것으로 예상되어 2개의 독립된 배치를 하나의 배치로 통합하여 동일한 시간에 $transaction api가 호출되는 일을 방지시키는 것으로 해당 이슈를 해결하였다.
이슈 해결 이후, Prisma 공식 문서에서 $transction 메소드의 옵션에 maxWait과 timeout 값의 할당을 통해 트랜잭션 생성을 대기할 수 있는 방법을 찾았지만, 해당 방법의 사용시 쿼리 생성 시간이 현저히 늘어나 INSERT 관련 성능에 이슈가 발생할 가능성을 배제할 수 없다는 문제가 있을 거 같다.
개인적인 의견으로는 Prisma를 사용하면서 개발 단계에서의 생산성/편의성은 높인 대신 ORM의 성능을 너무 많이 트레이드오프 해버린 느낌을 떨쳐낼 수 없었는데 이번에 해당 이슈를 거치면서 MVP 단계 이상에서 실프로덕션용으로의 사용에는 부적합할 거 같은 느낌이 들었다.
[Prisma] prisma.$transction api 성능 이슈
NestJs + Prisma 조합으로 신규 프로젝트를 진행하던 중 매일 새벽 1시마다 해당 날짜의 유가/최저가 주유소 관련 정보를 각각 Opinet의 API로 조회해서 저장하는 독립된 배치 2개를 구현하였었다. 유가 정보 조회/저장 배치가 스테이지 환경에서 정상적으로 동작하는 것을 확인하고, 최저가 주유소 관련 배치를 스테이지 환경에 배포해둔 상황이었다. DB 최저가 주유소 관련 테이블에 row들이 정상적으로 저장된 것을 확인하고, 해당 배치 기능은 완료된 것으로 생각하고 있었다.
유가 정보를 저장하고 있는 테이블과 최저가 주유소 정보를 저장하고 있는 테이블이 서로 연관이 없고, 독립된 배치에서 실행되고 있는 상황이라 insert 관련 락이나 PK 관련 이슈가 없을 거라고 생각하면서 DB와 서버 로그를 확인해보았는데 DB의 경우, 스테이지에 최저가 주유소 관련 배치를 배포해둔 이후로 유가 정보 테이블에 변경 사항이 없고, 최저가 주유소 테이블에만 꾸준히 변경사항이 적용되고 있었다. 서버 로그를 확인해보니 아래와 같은 이유로 트랜잭션 생성에 실패하였다는 로그만 남아있었다.
해당 로그를 확인해보면 주어진 시간(default 5s)내에 prisma orm이 트랜잭션을 시작하지 못해 prisma 단에서 timeout 에러가 발생하고 있었다. 기존에 유가 정보 로직만 배치가 실행될 때는 상관이 없었지만, 최저가 주유소 관련 로직이 추가되면서 독립된 2개의 배치가 동일한 시간에 default 기준 5s의 텀도 없이 prisma의 $transaction api를 2번 호출해서 첫 번째 $transaction api에서 timeout 에러가 발생한 것으로 예상되어 2개의 독립된 배치를 하나의 배치로 통합하여 동일한 시간에 $transaction api가 호출되는 일을 방지시키는 것으로 해당 이슈를 해결하였다.
이슈 해결 이후, Prisma 공식 문서에서 $transction 메소드의 옵션에 maxWait과 timeout 값의 할당을 통해 트랜잭션 생성을 대기할 수 있는 방법을 찾았지만, 해당 방법의 사용시 쿼리 생성 시간이 현저히 늘어나 INSERT 관련 성능에 이슈가 발생할 가능성을 배제할 수 없다는 문제가 있을 거 같다.
개인적인 의견으로는 Prisma를 사용하면서 개발 단계에서의 생산성/편의성은 높인 대신 ORM의 성능을 너무 많이 트레이드오프 해버린 느낌을 떨쳐낼 수 없었는데 이번에 해당 이슈를 거치면서 MVP 단계 이상에서 실프로덕션용으로의 사용에는 부적합할 거 같은 느낌이 들었다.
'개발 > NestJS' 카테고리의 다른 글