T_era

Spring API와 Postman으로 네트워크 오버헤드 실험하기 본문

Programing/Spring

Spring API와 Postman으로 네트워크 오버헤드 실험하기

블스뜸 2025. 6. 24. 18:56

1. 실험 목적

API를 설계할 때 “오버헤드”라는 말을 자주 듣지만, 실제로 얼마나 영향을 미치는지 체감하기 어렵다.
이번 글에서는 Spring Boot APIPostman을 이용해

  • 단건 조회 N번 vs 전체 조회 1번
  • 헤더 크기 변화
    등이 네트워크 오버헤드에 어떤 영향을 주는지 직접 실험해보자.

2. 실험 환경 및 준비

2-1. 실험용 Spring 코드

Comment 엔티티

@Entity
@Getter
@Setter
@Table(name = "comments")
public class Comment {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String content;

    public Comment(String content) {
        this.content = content;
    }
    public Comment() {}
}

CommentService

@Service
public class CommentService {
    private final CommentRepository commentRepository;

    public CommentService(CommentRepository commentRepository) {
        this.commentRepository = commentRepository;
    }

    public List<Comment> findAll() {
        return commentRepository.findAll();
    }

    public Comment findById(Long id) {
        return commentRepository.findById(id).orElse(null);
    }

    public void create() {
        for(int i = 0; i < 100; i++) {
            Comment comment = new Comment("test");
            commentRepository.save(comment);
        }
    }
}

CommentController

@RestController
@RequestMapping("/api/comments")
@RequiredArgsConstructor
public class CommentController {
    private final CommentService commentService;

    @PostMapping("/createTest")
    public ResponseEntity<Void> create() {
        commentService.create();
        return ResponseEntity.ok().build();
    }

    @GetMapping("/all")
    public ResponseEntity<List<Comment>> getAllComments() {
        List<Comment> comments = commentService.findAll();
        return ResponseEntity.ok(comments);
    }

    @GetMapping("/{id}")
    public ResponseEntity<Comment> getComment(@PathVariable Long id) {
        Comment comment = commentService.findById(id);
        return ResponseEntity.ok(comment);
    }

    @GetMapping("/test-header")
    public ResponseEntity<String> testHeader(@RequestHeader Map<String, String> headers) {
        int totalHeaderSize = headers.entrySet().stream()
                .mapToInt(e -> e.getKey().length() + e.getValue().length())
                .sum();
        return ResponseEntity.ok("Total header size: " + totalHeaderSize + " bytes");
    }
}

요청/응답 오버헤드 측정용 필터

@Component
public class LoggingFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;

        int requestHeaderSize = Collections.list(req.getHeaderNames()).stream()
                .mapToInt(name -> name.length() + req.getHeader(name).length())
                .sum();

        System.out.println("=== 요청 정보 ===");
        System.out.println("URL: " + req.getRequestURL());
        System.out.println("Method: " + req.getMethod());
        System.out.println("Request Header Size: " + requestHeaderSize + " bytes");

        long startTime = System.currentTimeMillis();
        chain.doFilter(request, response);
        long endTime = System.currentTimeMillis();

        int responseHeaderSize = res.getHeaderNames().stream()
                .mapToInt(name -> name.length() + res.getHeader(name).length())
                .sum();

        System.out.println("=== 응답 정보 ===");
        System.out.println("Status: " + res.getStatus());
        System.out.println("Response Header Size: " + responseHeaderSize + " bytes");
        System.out.println("Processing Time: " + (endTime - startTime) + "ms");
        System.out.println("Total Overhead: " + (requestHeaderSize + responseHeaderSize) + " bytes");
        System.out.println("========================\n");
    }
}

3. 실험 방법

3-1. 데이터 준비

  • /api/comments/createTest 엔드포인트로 100개의 테스트 댓글을 DB에 저장

3-2. Postman에서 실험

A. 전체 조회 1회

  • GET /api/comments/all
  • 한 번의 요청으로 100개의 댓글을 모두 조회

B. 단건 조회 100회

  • GET /api/comments/{id}
  • Postman Collection Runner로 id=1~100까지 100번 반복 호출

C. 헤더 오버헤드 실험

  • GET /api/comments/test-header
  • Authorization, Cookie 등 긴 헤더를 추가해서 요청

4. 실험 결과

4-1. 전체 조회 1회

  • Postman
    • Iterations: 1
    • Duration: 683ms
    • Avg. Resp. Time: 9ms
    • Response Size: 3.04KB (Headers: 423B, Body: 2.63KB)
    • Request Size: 295B (Headers: 295B)
  • 서버 로그
    === 요청 정보 ===
    URL: http://localhost:8081/api/comments/all
    Method: GET
    Request Header Size: 229 bytes
    Hibernate:
        select c1_0.id, c1_0.content from comments c1_0
    === 응답 정보 ===
    Status: 200
    Response Header Size: 301 bytes
    Processing Time: 5ms
    Total Overhead: 530 bytes
    ========================

4-2. 단건 조회 1회

  • 서버 로그
    === 요청 정보 ===
    URL: http://localhost:8081/api/comments/1
    Method: GET
    Request Header Size: 229 bytes
    Hibernate:
        select c1_0.id, c1_0.content from comments c1_0 where c1_0.id=?
    === 응답 정보 ===
    Status: 200
    Response Header Size: 301 bytes
    Processing Time: 30ms
    Total Overhead: 530 bytes
    ========================

4-3. 단건 조회 100회 (Postman Runner)

  • Iterations: 100
  • Duration: 1s 293ms
  • Avg. Resp. Time: 3ms

4-4. 헤더 오버헤드 실험

  • Postman
    • Authorization, Cookie 등 긴 헤더 추가
    • 응답: Total header size: 459 bytes
  • 서버 로그
    === 요청 정보 ===
    URL: http://localhost:8081/api/comments/test-header
    Method: GET
    Request Header Size: 459 bytes
    === 응답 정보 ===
    Status: 200
    Response Header Size: 301 bytes
    Processing Time: 4ms
    Total Overhead: 760 bytes
    ========================

5. 결과 분석 및 인사이트

5-1. 전체 조회 1회 vs 단건 조회 100회

  • 전체 조회 1회는 오버헤드(헤더 등)가 1번만 발생
  • 단건 조회 100회는 오버헤드가 100번 누적 발생
    • 530B x 100 = 53KB의 오버헤드가 발생
    • 실제 데이터(Body)는 작지만, 네트워크 트래픽은 오히려 더 많아질 수 있음

실제 N+1 문제의 핵심은 DB 쿼리뿐 아니라 네트워크 오버헤드까지 누적된다는 점!

5-2. 헤더 오버헤드

  • 불필요하게 긴 헤더(Authorization, Cookie 등)가 있으면
    • Request Header Size, Total Overhead가 크게 증가
    • 네트워크 효율이 떨어짐

5-3. 실무에서의 시사점

  • API 설계 시
    • 한 번에 필요한 데이터를 묶어서 보내는 것이 효율적
    • 불필요한 헤더, 쿠키, 토큰은 최소화해야 함
  • N+1 문제는 단순히 DB 쿼리만의 문제가 아니라,
    네트워크 오버헤드까지 합쳐서 전체 시스템 성능에 큰 영향을 미침

6. 마치며

이번 실험을 통해

  • 네트워크 오버헤드가 실제로 얼마나 누적될 수 있는지
  • API 설계에서 오버헤드를 줄이는 것이 왜 중요한지
    직접 체감할 수 있었다.