Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

과거의 내가 미래의 나에게

chunked에 대한 활용법 공부 본문

카테고리 없음

chunked에 대한 활용법 공부

양바삭 2024. 8. 11. 01:17

개발하고 있는 플랫폼 중에 필터값을 입력하고 검색 버튼을 누르면 백엔드에서 해당 필터에 맞게 데이터를 넘겨주고 이를 화면에 뿌리는 기능이 있다.

흔한 기능이지만 백엔드에서 데이터의 가공시간이 상당히 오래걸리는 작업이었고 그만큼 화면에서는 한 번 검색 시 로딩 시간이 무척 길어서 사용성이 꽤나 저해되고 있었다.

 

그러던 와중 문득 헤더에 transfer-encoding: chunked가 있다는 것을 떠올렸고, 이를 보니 큰 데이터를 클라이언트에 쪼개서 보낼 수 있다는 것을 생각해냈다. 이를 직접 테스트해보기 위해 프론트는 vue로 백엔드는 express로 하여 이것저것 테스트해보았다. 이 과정에서 배운 것들을 기록해보겠다.

 

 

먼저 Transfer-encoding: chunked가 무엇이냐?

Transfer-encoding은 HTTP 메시지 바디의 전송 코딩 형식을 지정하는 경우 사용된다. 그 값에는 chunked, compress, deflate, gzip이 있는데 이 중 chunked를 제외한 나머지는 바디 내용을 압축하여 보내는 것이고 chunked는 분할해서 보내는 것이다.

여기서 chunked는 서버에서 보낼 메시지를 일정 크기의 청크로 쪼개고 순서대로 클라이언트에 보내는 전송방식이다.

보통 HTTP 요청이 보내고자하는 데이터의 사이즈를 Content-Length라는 헤더를 통해 먼저 알려준 후 데이터를 전달하는데, 이 때 용량이 큰 데이터라면 데이터 사이즈를 계산하는 것 자체가 오래걸릴테고 이는 전송이 느려지는 원인이 된다.

하지만 chunked를 사용한다면 데이터를 일정 덩어리로 나눠 보내기에 서버가 데이터의 전체 사이즈를 구할 필요가 없다. 따라서 용량이 큰 데이터라도 더 빠른 속도로 클라이언트에게 보낼 수 있게 되는 것이다.

 

 

이를 위한 테스트

실제로 할 때는 뭔가 이해를 잘못해서 삽질을 엄청했다. 쪼개서 전송이 안되어서 curl -N API 주소 명령어로 데이터를 청크로 받는 대로 바로 표시하도록 해보기도 하고, node에서 Stream의 개념을 공부하기도 하고(익히진 못함) 엄청 갈아 엎었는데 알고나니 간단했던... 아래에는 성공한 코드만 적어놓는다.

const datas = [
    { id: 1, name: '이름1' },
    { id: 2, name: '이름2' },
    { id: 3, name: '이름3' },
    { id: 4, name: '이름4' },
    { id: 5, name: '이름5' }
];

app.get("/api/chunked", async (req, res) => {
  for (let i = 0; i < datas.length; i++) {
    await new Promise((resolve) => setTimeout(resolve, 500)); //데이터 가공하는 시간 대신
    res.write(JSON.stringify(datas[i])); //전송
  }
  res.end();//완료 처리
});

 

위와 같이 코드를 구성함으로써 데이터가 하나하나 넘어가는 것을 확인했다.

처음엔 res.set('Transfer-Encoding', 'chunked')를 통해 chunked를 직접 넣어 봤는데 뭔가 느낌이 쎄해서 이걸 빼보니 그래도 동일하게 동작해서 뭔가 잘못한 줄 알았다. 알고보니 node에서 res.write()가 곧 chunked 방식을 쓰겠다는 의미였고 이를 사용하면 node에서 알아서 chunked라고 나타낸다고 한다.

 

 

chunked 방식의 최종 정리

chunked는 큰 용량의 데이터를 쪼개서 보낼 수 있도록 하는 것이다. 이 데이터를 쪼개는 기준은 서버에서 정하는데 일정 크기로 나눌수도 있고 개발자가 직접 나눌 수도 있다. 

나의 경우에는 문제 상황이 일정 크기별로 쪼개서 보내면 안되는 경우였기에 직접 쪼갰는데 이를 직접 쪼개는 방식은 각 서버나 라이브러리마다 지원하는 방식이 다르기에 본인이 사용하는 언어나 프레임워크에 따라 그 방식은 다를 것이다. 

node의 경우는 res.write()를 통해서 지원됐고 자바의 경우 ResponseBodyEmitter를 통해 지원된다고 한다(자바는 전혀 몰라서 GPT한테 물어봤다)

 

일정 크기로 나누어서 사용하는 것은 보통 큰 다운로드 파일을 한번에 받을 때 사용되는데 지정된 크기만큼 나눠보내기에 얼마만큼 다운로드 되었는지 활용할 수 있는 지표로 사용될 수도 있고 또 다운로드 받는 속도도 향상되는 효과를 가질 것이다.

 

 

 

마무리

가정했던 생각을 플랫폼에 적용할 수 있을 것 같아 기쁘다. 물론 백엔드 코드는 내가 다루지 않기때문에 그들과 많은 이야기를 나눠봐야겠지만 검색 속도가 매우 느린 것은 모두의 공통 고민이었기에 같이 한 번 이야기 해봐야겠다!

 

 

추가

여기서 프론트는 사실 그냥 받아서 표출만 하는 거라서 별도로 말은 안하지만 코드는 기록해두고 싶어서 일단 아래에 써놓는다.

 async fetchChunked() {
      const response = await fetch("/api/chunked");
      const reader = response.body.getReader();
      const decoder = new TextDecoder();

      let done = false;

      while (!done) {
        const { value, done: streamDone } = await reader.read();
        done = streamDone;

        if (value) {
          const chunk = decoder.decode(value, { stream: true });
          this.chunks.push(chunk); //데이터를 화면으로 밀어넣는 것
        }
     }
},

 

Comments