> For the complete documentation index, see [llms.txt](https://wannaqueen.gitbook.io/spring5/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wannaqueen.gitbook.io/spring5/spring-5.0/7.-by-ks.md).

# 7. 데이터 버퍼와 코덱 by ks

Java NIO는 `ByteBuffer`많은 라이브러리가 자신의 바이트 버퍼 API를 빌드합니다. 특히 **네트워크 작업에서 버퍼를 재사용하거나 직접 버퍼를 사용하면 성능에 도움이됩니다**. 예를 들어, Netty는 `ByteBuf`계층 구조를 가지고 있고 , Undertow는 XNIO를 사용하고, Jetty는 콜백이있는 풀링 된 바이트 버퍼를 사용합니다. **이 `spring-core`모듈은 다음과 같이 다양한 바이트 버퍼 API로 작업 할 추상화 집합을 제공합니다.**

* [`DataBufferFactory`](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#databuffers-factory) 데이터 버퍼 생성을 추상화합니다.
* [`DataBuffer`](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#databuffers-buffer)[풀](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#databuffers-buffer-pooled) 될 수있는 바이트 버퍼를 나타냅니다 .
* [`DataBufferUtils`](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#databuffers-utils) 데이터 버퍼 용 유틸리티 메소드를 제공합니다.
* [코덱은](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#codecs) 스트림 데이터 버퍼 스트림을 상위 수준의 객체로 디코딩하거나 인코딩합니다.

{% hint style="info" %}
nio란?? 자바의 능이 상대적으로 좋지 않은 부분은 스윙과 I/O인데, 이를 메모리 직접 접근하는 것처럼 보이게 해서 개선하려고 했는데, 그게 nio 패키지이다!

참조 : <https://jeong-pro.tistory.com/145>
{% endhint %}

{% hint style="info" %}
Netty의 데이터 컨테이너 - ByteBuf

* 별도의 `Read Index` / `Write Index`가 있다.
* 위의 이유로 `flip()` 메소드를 사용하지 않아도 된다.
* 가변 바이트 버퍼를 사용할 수 있다.
* 바이트 버퍼 풀 기능을 제공한다.
* 복합 버퍼 사용이 가능하다.(`Heap` + `Direct`)
* Java의 ByteBuffer와 Netty의 ByteBuf의 상호 변환이 가능하다.

참조 : <https://koda93.github.io/Netty%EC%9D%98-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%BB%A8%ED%85%8C%EC%9D%B4%EB%84%88(ByteBuf)/>
{% endhint %}

{% hint style="info" %}
Undertow XNIO

JBoss에서 사용하는 WEB/Servlet 컨테이너. 자바 언어로 작성된 웹서버. Undertow I/O는 JBoss 의 XNIO를 이용하여 처리하고, blocking/non-blocking API 를 제공한다.

참조 : <http://www.opennaru.com/jboss/undertow-is-web-server-in-wildfly-and-jboss-eap7/>
{% endhint %}

{% hint style="info" %}
Jetty

서블릿과 JSP 를 지원하는 자바기반의 WAS
{% endhint %}

## 7.1 DataBufferFactory

`DataBufferFactory` 는 다음 두 가지 방법 중 하나로 데이터 버퍼를 만드는 데 사용됩니다.

(org.springframework.core.io.buffer Interface DataBufferFactory)

1. 데이터 버퍼를 할당 해, **필요에 따라서 용량을 사전에 지정**합니다. 필요에 따라서 DataBuffer의 구현이 확장 및 축소 할 수 있어, 보다 효율적입니다.
2. **기존의 byte \[] 또는 java.nio.ByteBuffer를 wrap**합니다. 이것은, DataBuffer 구현으로 지정된 데이터를 장식 해, 할당을 포함하지 않습니다.

WebFlux 응용 프로그램은 `DataBufferFactory`직접 만들지 않고 대신 클라이언트 측 `ServerHttpResponse`또는 `ClientHttpRequest`에서 엑세스합니다. 팩토리 유형은 기본 클라이언트 또는 서버 (예 : `NettyDataBufferFactory`Reactor Netty) `DefaultDataBufferFactory`에 따라 달라집니다 .

{% hint style="info" %}
WebFlux : reactive 기반의 웹 프레임워크. 5.0부터 Spring framework에 추가되었고 non-blocking reactive(비동기) stream 프로세스를 지원하고 Netty, Undertow, Servlet 3.1+ 컨테이너 같은 방식으로 서버에서 동작하는 웹 프레임워크이다.

참조 : <https://ztkmkoo.github.io/2017/12/13/spring-webflux/>
{% endhint %}

## 7.2 DataBuffer

(org.springframework.core.io.buffer Intaerface DataBuffer)

DataBuffer 인터페이스는 java.nio.ByteBuffer와 비슷한 작업을 제공하지만 Netty ByteBuf에서 영감을 얻은 몇 가지 추가 이점을 제공합니다. 다음은 혜택의 일부 목록입니다.

* **읽기와 쓰기를 번갈아 수행하기 위해 flip ()을 호출 할 필요가없는 독립적 인 위치에서 읽고 쓰기.**
* 용량은 java.lang.StringBuilder 에서처럼 필요에 따라 확장&#x20;
* 풀링된 버퍼 및 PooledDataBuffer를 통한 참조 계산&#x20;
* 버퍼를 java.nio.ByteBuffer, InputStream, OutputStream으로 봄&#x20;
* 지정된 바이트에 대한 인덱스 또는 마지막 인덱스를 결정

## 7.3 PooledDataBuffer

(org.springframework.core.io.buffer Interface PooledDataBuffer)

[ByteBuffer](https://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html) 용의 Javadoc로 설명했듯이 , **바이트 버퍼는 직접 또는 간접 일 수 있습니다. 직접 버퍼는 Java 힙 외부에 상주 할 수 있으므로 원시 I / O 작업을 복사 할 필요가 없습니다.** **따라서 직접 버퍼는 소켓을 통해 데이터를주고받는 데 특히 유용하지만 버퍼를 풀링한다는 아이디어로 이어지기 때문에 생성 및 릴리스 비용도 높아집니다.**

**PooledDataBuffer는 바이트 버퍼 풀링에 필수적인 참조 카운팅에 도움이되는 DataBuffer의 확장**입니다. 어떻게 작동합니까? PooledDataBuffer가 할당 될 때, 참조 카운트는 1입니다. retain () 호출은 count를 증가시키고 release () 호출은 감소시킵니다. 카운트가 0 이상이면, 버퍼는 해제되지 않는 것이 보증됩니다. 카운트가 0으로 감소하면 풀링 된 버퍼가 해제 될 수 있습니다. **실제로 버퍼의 예약 된 메모리가 메모리 풀로 반환 될 수 있습니다**.

**PooledDataBuffer로 직접 조작하는 대신, 대부분의 경우, PoolBuffer의 인스턴스 인 경우에 한해 DataBuffer에 release 또는 retain을 적용하는 DataBufferUtils의 편리한 메소드를 사용하는 것이 더 좋습니다**.

## 7.4 DataBufferUtils

(org.springframework.core.io.buffer Class DataBufferUtils)

`DataBufferUtils` 는 데이터 버퍼에서 작동하는 여러 가지 유틸리티 메소드를 제공합니다.

* 데이터 버퍼의 트릠을 단일 복사 (예 : 0복사) 에 결합합니다. 예를 들어서 기본 바이트 버퍼 API에서 지원하는 경우 복합 버퍼를 통해서 결합합니다.&#x20;
* InputStream 또는 NIO 채널을 Flux 로 바꾸고, Publisher 를 OutputStream 또는 NIO 채널로 바꿉니다.
* 버퍼가 PooledDataBuffer의 인스턴스의 경우, DataBuffer를 릴리즈 또는 보관 유지하기위한 메소드.
* 특정 바이트 수가 될 때까지 바이트 스트림을 건너 뛰거나 가져옵니다.

## 7.5 코덱

#### 이 `org.springframework.core.codec`패키지는 다음과 같은 전략 인터페이스를 제공합니다. <a href="#codecs" id="codecs"></a>

* `EncoderPublisher<T>`데이터 버퍼의 스트림 으로 인코딩 합니다.
* `DecoderPublisher<DataBuffer>`더 높은 레벨의 객체들의 스트림 으로 디코딩 한다.

`spring-core`모듈을 제공하고 `byte[]`, `ByteBuffer`, `DataBuffer`, `Resource`, 및 `String`인코더와 디코더 구현. 이 `spring-web`모듈에는 Jackson JSON, Jackson Smile, JAXB2, 프로토콜 버퍼 및 기타 인코더 및 디코더가 추가되었습니다. WebFlux 섹션의 [코덱](https://docs.spring.io/spring/docs/current/spring-framework-reference/web-reactive.html#webflux-codecs) 을 참조하십시오 .

## 7.6 DataBuffer 사용

\
**데이터 버퍼로 작업 할 때, 버퍼가** [**풀 (pool)**](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#databuffers-buffer-pooled) **될 수 있기 때문에 버퍼가 풀어 지도록 특별한주의를 기울여야한다** . 코덱을 사용하여 작동 방식을 설명하지만 개념이 더 일반적으로 적용됩니다. 데이터 버퍼를 관리하기 위해 코덱이 내부적으로 수행해야하는 작업을 살펴 ​​보겠습니다.

`Decoder`는 상위 수준의 객체를 만들기 전에 입력 데이터 버퍼를 마지막으로 읽으므로 다음과 같이 해제해야합니다.

1. 디코더가 각 입력 버퍼를 읽어 들여 즉시 풀 준비가되어있는 경우는, DataBufferUtils.release (dataBuffer)를 개입시켜 디코더가 그렇게 할 수 있습니다.
2. 디코더가 flatMap, reduce 등의 Flux 또는 Mono 연산자를 사용하여 데이터 항목을 내부적으로 프리 페치 및 캐시하거나 필터, 건너 뛰기 및 항목을 제외하는 연산자를 사용하는 경우 doOnDiscard (PooledDataBuffer.class, DataBufferUtils :: release)를 삭제해야 구성 요소 체인에 버퍼를 추가해야 폐기 될 수 있으며, 결과적으로 오류 또는 취소 신호가 발생할 수 있습니다.
3. 디코더가 다른 방법으로 하나 이상의 데이터 버퍼를 유지하는 경우 완전히 읽혀 지거나 캐시 된 데이터 버퍼를 읽고 해제하기 전에 오류나 취소 신호가 발생하는 경우 디코더가 해제되는지 확인해야합니다.

DataBufferUtils # join은 데이터 버퍼 스트림을 단일 데이터 버퍼로 모으는 안전하고 효율적인 방법을 제공합니다. 마찬가지로 skipUntilByteCount 및 takeUntilByteCount는 디코더가 사용할 수있는 안전한 추가 메서드입니다.

인코더는 다른 사람들이 읽고 받아야하는 데이터 버퍼를 할당합니다. 따라서 인코더는 할 일이 많지 않습니다. 그러나 데이터를 버퍼에 채우는 동안 직렬화 오류가 발생하면 인코더는 데이터 버퍼를 해제해야합니다. 예 :

```java
DataBuffer buffer = factory.allocateBuffer();
boolean release = true;
try {
    // serialize and populate buffer..
    release = false;
}
finally {
    if (release) {
        DataBufferUtils.release(buffer);
    }
}
return buffer;
```

소비자는 소비자가 `Encoder`받는 데이터 버퍼를 공개해야합니다. WebFlux 응용 프로그램에서의 출력은 `Encoder`HTTP 서버 응답 또는 클라이언트 HTTP 요청에 쓰는 데 사용됩니다.이 경우 데이터 버퍼를 해제하는 것은 서버 응답 또는 클라이언트 요청에 대한 코드 작성의 책임입니다 .

Netty에서 실행할 때 [버퍼 누수 문제](https://github.com/netty/netty/wiki/Reference-counted-objects#troubleshooting-buffer-leaks) 를 [해결](https://github.com/netty/netty/wiki/Reference-counted-objects#troubleshooting-buffer-leaks) 하기위한 디버깅 옵션이 있습니다 .
