Fireball: 고성능 대용량 파일 전송 서비스

주싱·2023년 6월 10일
0

Network Programming

목록 보기
21/21

1. Overview

Fireball 프로젝트는 대용량 파일을 빠르게 전송할 수 있는 작은 독립 서비스를 제공합니다. 어떤 언어, 어떤 프레임워크를 사용하든지 간단한 HTTP 요청을 통해 원격지와 파일을 빠르게 교환할 수 있습니다.

Method: POST
URL: http://localhost:58080/api/upload
Content-Type: application/json

{
  "source": {
    "file": "source.dat"
  },
  "destination": {
    "ip": "127.0.0.1",
    "port": 50711,
    "file": "destination.dat"
  }
}

2. Problem

누구나 네트워크를 통해 파일을 교환하는 코드를 어렵지 않게 작성할 수 있습니다. 그러나 어떤 도구를 사용하고, 도구를 얼마나 최적화하느냐에 따라 처리 성능에 큰 차이를 보입니다.

Many Methods, Difference Performance

저는 몇몇 대표적인 방법(Fireball 포함)을 사용해 1GB 크기의 파일을 루프백 네트워크로 전송하는 테스트를 진행했습니다. 50회 반복 테스트 수행 후 평균치를 측정했고 테스트에는 일반적인 성능의 홈 노트북(Acer Swift 5 Notebook)을 사용했습니다. 1회 측정 시간은 파일을 읽고, 네트워크로 전송하며, 수신된 파일을 다시 저장한 후, 응답이 완료되기까지의 시간을 포함합니다. 아래의 테스트 결과를 보면 동일한 조건에서 동일한 파일을 처리하지만 어떤 방법을 사용하느냐에 따라 큰 성능 차이를 가져온다는 것을 알 수 있습니다.

3. Goal

위 테스트 결과를 보면 최고의 성능을 보여주는 방법이 Fireball은 아닙니다. 위 방법들 중에서는 윈도우 FTP 서버를 띄우고 .NET API를 사용했을 때 최고의 성능을 보여줍니다. Fireball 프로젝트는 앞으로 더 나은 성능을 지속적으로 추구할 것입니다. 또한 다음과 같은 핵심가치를 함께 제공하고자 합니다.

  • 파일 전송에 집중하는 작고 독립적인 서비스
  • 어떤 언어, 어떤 프레임워크, 어떤 플랫폼에서도 사용할 수 있는 서비스
  • 단순한 프로그래밍 API
  • 서버와 클라이언트를 통합하는 단일 애플리케이션

4. Build

Fireball은 Spring Boot 프로젝트이며 빌드툴로 Maven을 사용합니다. 이제 프로젝트를 clone하고 루트 경로(mvnw 파일이 존재하는 경로)로 이동한 다음 mvnw(maven wrapper)를 사용해 프로젝트를 빌드할 수 있습니다. 빌드 결과 파일은 ./target/fireball-0.0.1.final.jar 에 존재합니다.

> git clone https://github.com/joosing/fireball.git
> cd fireball
> chmod 744 mvnw
> ./mvnw clean package -DskipTests

5. Install

Fireball을 사용해 서로 다른 네트워크 호스트 간 파일을 교환하려면 양 쪽 호스트 모두에 Fireball 서비스가 설치되고 실행되어야 합니다.

  • 먼저 Java 17 버전이 설치되어 있는지 확인합니다.
> java --version 
  • 빌드된 JAR 파일을 원하는 경로에 복사합니다.
> cp ./target/fireball-0.0.1.final.jar /app/fireball/fireball-0.0.1.final.jar

6. Run

다음 설정과 함께 Fireball을 실행합니다.

  • file.client.root : 클라이언트의 파일 루트 경로 지정 (필수)
  • file.server.root : 서버의 파일 루트 경로 지정 (필수)
  • server.port : API 서버 포트 지정 (Optional, 미지정 시 58080 포트 사용)
  • file.server.port : 파일 서버 포트 지정 (Optional, 미지정 시 50711 포트 사용)
> java -Dfile.server.root="/app/files" -Dfile.client.root="/app/files" -jar fireball-0.0.1.final.jar

7. Usage

Fireball은 파일 업로드와 다운로드 두 가지 REST API를 제공합니다. 다음은 Fireball을 사용해 시스템을 구성한 예시입니다. 이 예시에서는 호스트 A(192.168.10.10)에 사용자 서비스가 설치되고, 호스트 B(192.168.100.10)와 C(192.168.100.11)에 Fireball서비스가 설치되었습니다. 사용자는 호스트 B에게 파일 교환 요청을 보냅니다. 이런 경우 호스트 B의 Fireball 서비스는 파일 클라이언트 역할이 되고 호스트 C의 Fireball은 파일 서버 역할이 됩니다. 다음 절에서는 이 구성 안에서 호스트 B와 C 사이에 파일 업로드와 다운로드를 수행하는 요청 예시를 설명합니다.

A. Upload

다음과 같은 간단한 HTTP 요청을 통해 호스트 B에서 C로 파일을 업로드 할 수 있습니다. 예시에서는 호스트 B의 source.dat 파일을 호스트 C의 /parent/destination.dat 파일로 업로드합니다. 각 파일 경로는 설정된 루트 경로를 기준합니다. 만약 /parent 디렉토리가 존재하지 않는 경우 자동으로 디렉토리를 생성하고 destination.dat 파일이 이미 존재하는 경우 기존 파일을 덮어쓰며 새로운 파일을 생성합니다.

Method: POST
URL: http://192.168.100.10:58080/api/upload
Content-Type: application/json

{
  "source": {
    "file": "source.dat"
  },
  "destination": {
    "ip": "192.168.100.11",
    "port": 50711,
    "file": "/parent/destination.dat"
  }
}

B. Download

다음과 같은 간단한 HTTP 요청을 통해 호스트 C에서 B로 파일을 다운로드 할 수 있습니다. 예시에서는 호스트 C의 source.dat 파일을 호스트 B의 /parent/destination.dat 파일로 다운로드합니다. 각 파일 경로는 설정된 루트 경로를 기준합니다. 만약 /parent 디렉토리가 존재하지 않는 경우 자동으로 디렉토리를 생성하고 destination.dat 파일이 이미 존재하는 경우 기존 파일을 덮어쓰며 새로운 파일을 생성합니다.

Method: POST
URL: http://192.168.100.10:58080/api/download
Content-Type: application/json

{
  "source": {
    "ip": "192.168.100.11",
    "port": 50711,
    "file": "source.dat"
  },
  "destination": {
    "file": "/parent/destination.dat"
  }
}

Response

Fireball은 커스텀 HTTP 응답 헤더(“Error-No”, “Error-Message”)를 사용해 상세한 오류 상태를 공유합니다.

Error-No: 1
Error-Message: The file does not exist.

8. Design

Fireball은 대용량 파일을 일련의 작은 청크(5MB)로 분할하여 전송합니다. 수신측에서는 하나의 청크를 네트워크로부터 수신하여 메모리에 버퍼링한 다음 한 번에 파일로 씁니다. 이를 위해 다음과 같은 애플리케이션 메시지 프로토콜을 구성합니다.

  • length : 청크 메시지 길이 (id 부터 chunk contents 끝까지 길이)
  • id : 메시지 ID
  • chunk type : 파일 내 청크의 위치를 나타냄 (시작, 중간, 끝)
  • chunk contents : 청크 파일의 컨텐츠

9. Fireball

“빠르다”라는 개념은 “불타다”라는 개념과 잘 어울립니다. "파일"을 전송한다는 개념은 "볼"을 던진다는 개념과 역시 잘 어울린다고 생각했습니다. 여러가지 공 중에서 농구공을 선택한 이유는 제가 그것을 좋아하기 때문이기도 하지만 프로젝트가 가진 개념을 잘 표현하기 때문입니다. 농구공은 야구공이나 다른 공들에 비해 무겁습니다. 그래서 빨리 멀리 던지기가 쉽지 않죠. Fireball 프로젝트는 이 농구공 같은 대용량 파일을 불타오르듯이 빠르게 전송해 보고자 합니다.

10. Plan

Fireball 프로젝트는 다음 작업들을 우선적으로 계획하고 있습니다.

  • 가치있는 단위 테스트 스위트 구축
  • 채널 암호화 및 사용자 인증
  • 배치 파일 처리 API 지원

11. Contact

사용 중에 문제가 있거나 더 나은 개선 포인트가 있다면 저에게 언제든지 알려주십시요. 저는 당신이 필드에서 겪는 문제나 필요에 대해 더 알고 싶고, 그에 맞게 Fireball 서비스를 더 개선하고 싶습니다. 그리고 저는 유사한 형태의 작업이나 협업이 필요하다면 전세계 어느 곳에서든 풀타임 잡으로 일할 수 있습니다. (리모트잡도 가능합니다)

🚩 GitHub Link

profile
소프트웨어 엔지니어, 일상

0개의 댓글