~/brunosong
← 프로젝트 목록

Pipeline

대량 문서 변환 처리 파이프라인

운영자가 어드민에서 자료를 골라 변환 버튼을 누르면, 어드민이 변환 솔루션을 직접 호출해 이미지와 PDF를 만드는 기능이었습니다. 한 건씩 걸면 늘 됐습니다. 그런데 한 번에 수백 건을 걸면 되는 것과 안 되는 것이 섞였고, 무엇이 안 됐는지도 남지 않았습니다. 제가 왜 대량에서만 깨지는지를 여덟 단계로 나눠 조사해 문제 20건을 뽑고, 접수와 처리를 끊는 변환 시스템을 따로 만들었습니다.

실무 프로젝트Java · Spring Boot · MySQL

등장인물

운영자
어드민에서 변환할 자료를 골라 버튼을 누르는 사람
사람
어드민
운영자가 보는 관리자 화면. 자료를 등록하고 변환을 건다
원래 있던 것
게이트웨이
어드민과 변환 솔루션 사이의 로드밸런서. 60초가 지나면 연결을 끊고 504를 만든다
원래 있던 것
변환 솔루션
문서를 실제로 이미지와 PDF로 바꿔주는 프로그램
사서 쓰는 것
API 서비스
변환 결과를 받아 어드민 DB 에 적는 창구. 원래 어드민 화면 안에 묻혀 있던 저장 로직을 꺼낸 자리
있던 프로젝트에 제가 엔드포인트를 더한 것
변환 시스템
변환 요청을 받아 두었다가 워커가 대신 솔루션을 불러주는 것
제가 이번에 만든 것

한 건은 되는데 수백 건은 안 됐습니다

운영자가 자료를 하나씩 걸면 변환은 늘 됐습니다. 그런데 한 번에 수백 건을 걸면 되는 것과 안 되는 것이 섞이고, 무엇이 안 됐는지는 아무도 몰랐습니다. 운영자가 다시 걸어도 또 일부만 됐습니다. 같은 기능인데 규모가 커지는 순간 다르게 굴었습니다.

한 건씩 걸 때수백 건을 한 번에 걸 때
변환 결과건 상관없이 다 됩니다되는 것과 안 되는 것이 섞입니다
걸리는 시간한 건에 10초에서 30초서로 밀려 60초를 넘기고 끊깁니다
안 됐을 때운영자가 화면에서 바로 압니다무엇이 안 됐는지 아무 데도 안 남습니다
다시 걸면그대로 됩니다또 일부만 되고, 부하만 더 늘어납니다

왜 대량에서만 깨졌나

한 건씩 걸 때 안 보이던 것이 수백 건에서 드러납니다. 누가 무엇을 해서 다음이 어떻게 되는지 한 단계씩 이어보면 이렇습니다.

  1. 01운영자어드민에서 수백 건을 한 번에 겁니다
  2. 02어드민몇 건씩 보낼지 정해둔 값이 없어 들어온 만큼 그대로 동시에 호출합니다
  3. 03변환 솔루션줄을 세우지 않고 들어온 것을 다 받습니다. 가벼운 6건을 동시에 던져보니 여섯이 60ms 안에 다 같이 끝났습니다. 줄을 섰다면 나올 수 없는 결과입니다
  4. 04IIS코어 하나만 쓰도록 잡혀 있습니다. 받은 건들이 그 한 코어에 다 몰리고 나머지 코어는 놉니다
  5. 05변환 솔루션무거운 자료로 바뀌면 그 성질이 해가 됩니다. 줄을 섰다면 앞의 것부터 끝나 일부는 살아남을 텐데, 다 같이 조금씩 진행하니 다 같이 느려집니다. 동시 11건부터 60초를 넘기기 시작했습니다
  6. 06게이트웨이60초가 지나자 연결을 끊고 504를 만듭니다. 한 건이 아니라 묶음이 통째로입니다
  7. 07어드민그 뒤에 하려던 일을 하나도 못 합니다. 결과도 실패 기록도 남지 않습니다
  8. 08어드민 화면남은 기록이 없으니 실패를 처리중으로 보여줍니다
  9. 09운영자아직 도는 줄 알고 다시 겁니다. 동시 호출이 더 늘어 처음으로 돌아갑니다

마지막 단계가 첫 단계로 돌아갑니다. 시스템이 힘들 때 운영자가 더 세게 누르는 방향으로 도는 고리였습니다. 게이트웨이 타임아웃 한도를 늘리는 건 이 고리 중 한 칸을 잠시 미루는 것뿐이라, 제가 구조를 건드리는 쪽으로 갔습니다.

재 본 값 셋이 이 연쇄를 받칩니다

10% 미만

어드민에 504가 쏟아지는 동안 변환 솔루션 서버 CPU

서버가 터질 듯이 돌다 뻗은 게 아닙니다. 과부하로 생긴 일이 아니었습니다

60ms

어드민이 6건을 동시에 던졌을 때 솔루션이 전부 끝낸 시간

여섯 건이 다 같이 끝납니다. 솔루션이 줄을 안 세우고 다 받는다는 뜻입니다

11건

솔루션이 60초를 넘기기 시작하는 동시 호출 수

한 코어를 나눠 쓰며 다 같이 느려지므로 묶음이 통째로 끊깁니다

504 가 대량으로 나면 보통 서버가 감당을 못 하고 있다고 봅니다. 그런데 변환 솔루션 서버는 그 시간 내내 CPU 가 10% 를 넘지 않았습니다. 미친 듯이 돌다가 뻗은 게 아니라 거의 놀고 있었습니다. 솔루션이 올라간 IIS 가 코어 하나만 쓰도록 잡혀 있어서, 요청은 그 한 코어에 다 몰리고 나머지 코어는 그대로 남아 있었습니다. 그래서 증설은 답이 아니었습니다. 장비를 늘려도 IIS 는 여전히 코어 하나만 씁니다. 여기에 IIS 스레드가 다 차서 뒤의 요청이 밀린 것도 겹쳤다고 봅니다. 이 부분은 확인하지 못해 추정으로 남겨둡니다.

문제 20건을 뿌리 6갈래로 묶었습니다

제가 변환이 도는 과정을 여덟 단계로 나누고, 단계마다 무엇이 잘못될 수 있는지를 코드와 실제 운영 기록으로 확인했습니다. 여기에 개발자가 감춰둔 화면을 열어 운영자가 600건을 한꺼번에 돌리면 어떻게 되는지를 가정한 시나리오도 하나 더 봤습니다.

뿌리건수결과
어드민이 변환 솔루션에 한 번에 몇 건을 보낼지 아무도 정해두지 않았다3해결
게이트웨이가 60초에 연결을 끊으면 어드민이 하려던 나머지 단계가 통째로 사라졌다4해결
어드민은 변환이 실패하면 기록을 아무 데도 남기지 않았다4해결
운영자가 버튼을 한 번 누르면 이미지 변환과 PDF 변환이 한 호출에 붙어 나갔다4해결
어드민이 재변환할 때 지우고 새로 넣는데, 넣기가 실패해도 예외가 안 나 멀쩡하던 자료까지 사라졌다2해결
어드민 화면이 운영자에게 사실과 다른 상태를 보여줬다32건 해결, 1건 일부

제가 번호순으로 훑지 않고 뿌리별로 묶은 게 이 단계에서 가장 중요했습니다. 하나씩 찾아 고치는 게 아니라 구조를 바꿔서 그 문제가 생기던 상황 자체를 없애는 방향이었기 때문에, 묶어서 봐야 무엇이 왜 풀리는지가 보입니다.

다섯 번째가 조사에서 제일 급했습니다. 자료가 실제로 없어지는 자리는 여기 하나뿐이었습니다. 재변환은 이미 잘 되어 있는 자료에 하는 작업인데, 넣기가 실패해도 코드가 예외를 안 던지고 오류 코드만 담아 정상으로 끝나서 데이터베이스가 되돌릴 계기를 못 얻습니다. 지운 것만 확정되고 그 자료는 다시 성공할 때까지 서비스에서 빈 상태로 보입니다.