결산
tech BE microservice project

개요


1주차 주요 이슈

1. API Gateway가 각각의 서비스에 통신할 API 구조 정리

MSA를 구성하는 서비스를 아래의 분리 원칙을 참고하여 분리 및 API 통신 구조를 설계

1. 각 서비스는 하나의 역할만 수행해야 한다.
    
    Image -> mask를 만드는 기능, mask->mask를 만드는 기능, mask-> 3d obj를 만드는 기능 등등

2. 추후 오케스트레이션의 관리르 편하게 하기 위해 어떤 자원을 얼마나 소모하느냐 등의 공통점도 서비스 분리 기준으로 삼는다.
    
    I/O가 많이 필요하다, CPU 사용량이 많다, GPU 사용량이 많다 등등

3. 각 서비스는 같은 분류에 기능에 대해 확장성에 문제가 없어야한다.

    코드 설계 원칙을 참고해 각 서비스별 주요 코드를 라이브러리로 정리함으로써, 추후 해당 서비스에 추가 기능이 발생하더라도, 같은 구조 내부에서 쉽게 추가될 수 있도록 서비스를 구성
Service EndPoint Parameter(request) Parameter(response) Detail Constraints
nnUNet inference/totalseg image_path : str mask_path : str totalSegmentator를 실행시켜, 해당 이미지에 대한 Organ Mask를 저장하고, 저장한 Path를 반환 1mm보다 high resoulution을 가지는 이미지에 대해서는 더 나은 결과를 낼 수 없다
nnUNet inference/vessel image_A_path : str, image_P_path : str mask_path : str 2개 이미지의 파일 경로를 받아 image_A_path와 같은 물리적 공간을 가지는 신장,동맥,정맥 mask를 저장하고 해당 주소를 반환 A, P Phase에 해당하는 CT 이미지에 대해서만 유효한 결과를 낼 수 있다
nnUNet inference/ureter image_D_path : str mask_path : str 이미지 파일경로를 받아, 같은 물리적 공간을 가지는 요관, 신장 mask를 저장하고 해당 주소를 반환 D Phase .nii.gz에만 유효한 결과를 낼 수 있다
nnUNet inference/tumor image_path : str mask_path : str 이미지의 파일 경로를 받아, 같은 물리적 공간을 가지는 신장, 종양 mask를 저장하고 해당 주소를 반환  
Smoothing smoothing/base mask_path : str obj_path : str 마스크의 파일 경로를 받아, 해당 마스크에 대한 3d obj파일을 만들고, 그 주소를 반환 mask의 label number가 사전에 약속된 규칙을 따라야함
postprocess postprocess/fat mask_path : str mask_path : str kidney, tumor, total 마스크를 기반으로 Fat mask를 생성해주고, 해당 경로를 반환 사전에 약속된 mask 규칙을 따라야함
postprocess postprocess/sample mask_path : str, templete_path : str mask_path : str 템플릿과 환자 mask(kidney, tumor가 있는)를 기반으로 빠른 mask를 생성해주고, 해당 경로를 반환 사전된 약속된 mask label number를 따라야함
postprocess postprocess/vessel mask_path : str mask_path : str 결과 마스크를 기반으로 떨어진 artery를 자동 연결하는 후처리 기능을 적용 후 저장, 그 경로를 반환 사전에 약속된 mask label number 규칙을 따라야함
postprocess postprocess/ureter mask_path : str mask_path : str 결과 마스크를 기반으로 떨어진 ureter를 자동 연결하는 후처리 기능을 적용 후 저장, 그 경로를 반환 사전에 약속된 mask label number 규칙을 따라야함

2. Clean code를 위한 원칙 설정

  1. Single Responsibility

    • 정의

      하나의 클래스나 모듈은 오직 하나의 책임(변경 이유) 만 가져야 한다.

    • 문제점

      기존 코드에서 nnUNet 실행, preprocessing, 이미지 처리 등 여러 기능이 하나의 파일에 혼재되어 있다. → 재사용성과 유지보수성 저하

    • 개선방향

      각 모듈을 인공지능을 실행하는 모듈, 이미지와 메타데이터 정보를 얻는 모듈, 인공지능 실행 클래스를 생성하는 모듈 등 하나의 역할만 수행하도록 구조를 변경한다.
      코드의 가독성과 재사용성을 강화

  2. Dependency Inversion Principle(의존성 역전 원칙)

    • 정의

      상위 모듈은 하위 모듈의 구현이 아니라, 추상화(인터페이스/프로토콜) 에 의존해야 함.

    • 문제점

      nnUNet 사용 시, network, Predictor 등 객체를 직접 생성하고, 하드코딩된 파라미터를 사용하는 부분이 존재한다.

    • 개선방향

      config.yaml을 통해 하드 코딩되는 원인인 공통된 파라매터를 한 곳에 관리한다.
      팩토리 패턴 또는 DI 컨테이너를 이용해 객체를 생성하여 공통된 모듈을 활용하더라도 다른 모델이나 구조를 쉽게 교체 가능하게 설계한다.

  3. Interface 통일 (프로토콜 정형화)

    • 정의

      여러 서비스가 공통된 메서드/구조/데이터 포맷을 따라야 함.

    • 문제점

      nnUNet과 달리 post-processing 서비스는 mask 이미지 -> mask 이미지를 생성하는 구조는 동일하지만, 해당 내용을 구현하는 코드 등에서 각각의 연구 내용에 따라 실행되는 로직이 상당히 다르다. 하지만 백엔드 입장에서는 마스크 -> 마스크를 생성하며 그때 마다 요구하는 label_name:label_num이 달라진다는 공통된 특징을 가지고 있다.
      그렇기에 서로 다른 로직의 모듈을 관리하는 post-processing 서비스에서 프로토콜 정형화가 필요하다.

    • 개선방향

      공통 부모 클래스/프로토콜 정의
      run(), save_output(), load_input() 등의 인터페이스 통일

  4. Fali Fast & Logging

    • 정의

      오류가 발생하면 빠르게 실패하고, 즉시 원인을 알려야 함.

    • 문제점

      의료 데이터는 실행시간이 길고 리소스 소모가 큼
      중간 실패를 늦게 알아채면 자원 낭비 발생

    • 개선방향

      초기 유효성 검사 강화 (파일 경로, config 유효성 등)
      예외 발생 즉시 서비스 종료 및 명확한 로그 출력
      로그는 표준화된 포맷과 단계별(Level별) 로깅 적용 (INFO, WARNING, ERROR)
      모니터링 도구와 연계할 수 있도록 구조화된 로그(JSON 등) 제공 검토

3. MSA를 만들기 위해 고려되야할 추가적인 요소

  1. Fail Fast 및 Logging을 전체 서비스 단위로 실행될 수 있게하는 logging 및 benchmark 시스템의 구성

    MSA로 서비스가 변경되면서, 각 구조가 서로 다른 코드 환경이 gRPC로 통신하기에, 오류가 발생할 시 디버깅이 어려워지고, 문제가 발생했을 때 바로 알아차리기가 어려워진다.
    이 점을 해결하기 위해 각 코드를 설계할 때 문제가 발생하면 대처할 수 있는 방안이 녹아드러야 하며, 전체 서비스 환경에서 log를 모으고 볼 수 있어야 한다.

  2. Orchstration

    nnUNet 서비스를 구현하며, API Gateway에서 각 서비스로 요청하고 각각의 기능을 각 AI의 inference 및 결과 저장까지 추상화를 완료하였지만, 실제 BE 서버가 요청하는 것은 하나의 이미지를 추론하여 저장하는 요청이 아닌, 하나의 케이스를 전달했을 때 각 AI 모델을 모두 활용하여 완전한 결과를 만드는 것이다.
    이를 위해 API Gateway에서 각 기본 기능을 요청하는 것과, 이를 실제 BE 요청에 맞추어 통합실행하는 오케스트레이션 모듈을 생성하여, 이 곳에서 추상화를 통해 각 기능을 통합하는 모듈을 완성해야한다.

  3. 문서화

    MSA를 구현하면서, 서비스끼리의 통신, 모듈끼리의 추상화를 통한 연결관계 등 재사용성을 위해 하나에 모여있던 코드들을 분리하고, 의존성 주입을 통해 생성하게 함로써 이러한 전체적인 구조가 정리될 필요성을 느꼈다. 그렇기에 시스템 흐름도 등 소프트웨어 공학에서 배운 각 모듈들의 의존관계 및 파라매터를 정리하는 과정이 필요하다.

  4. docker-compose화

    현재의 시스템은 DockerFile을 만들어 두고 사전에 마운트 정보다, 연결된 docker network 이름 등을 사전에 미리 적어둔 shell 파일인 run.sh 파일을 실행시킴으로써 이미지 빌드와 컨테이너 실행에 필요한 정보를 재사용한다. 하지만 MSA로 만들어서 이런 기능등을 k8s같은 오케스트레이션 시스템이 관리하기 위해선 이를 docker-compose로 변경하여 관리를 해야한다.

완성된 기능

  1. gRPC를 통한 통신 기능

    proto 파일을 통해서 통신 구조를 정의하고, 공유된 data 마운트에서 통신한 경로 정보를 활용해 데이터를 가져오는 구조를 완성

  2. nnUNet 서비스 <-> API Gateway 기본 통신

    totalsegmentator 기능이 통신을 통해 실행되고, 결과를 저장하고, 저장된 파일 경로를 응답하는 구조의 완성
    그리고 다른 vessel, ureter, tumor가 통신할 구조의 완성