해당 내용의 글을 작성하며
1. Kafka를 로컬에서 SSL 인증을 경유하게 설정하는 방식.
2. Kafka의 시스템 콜 로그를 찍는 방식.
2가지에 대해 AI를 사용하였습니다. 짧은 지식으로 작성한 내용이기에 AI 사용 부분 혹은, 그 외의 어느 부분에서라도 오류가 존재한다면 댓글에 남겨주시면 감사하겠습니다.
접근
카프카는 왜 빠를까?
카프카를 한 번이라도 사용해 본 적이 있는 사람이라면, 그 사람이 개발자라면 반드시 궁금했을만한 내용이다.
카프카는 메모리도 아니고, 디스크를 사용한다는데 어떻게 그렇게 빠를까? 디스크는 느린 거 아닌가?
라는 궁금증이 들어 내용을 찾아보았다.
수많은 블로그, 그리고 공식 docs 까지 모두 대략 3가지의 근거를 들었다.
1. Sequential I/O
데이터를 읽거나 쓸 때 Random Access I/O가 아닌 Sequential I/O를 제공함으로써, 디스크 헤드 동선을 최적화한다는 것이다.

2. 파일 시스템을 사용하고 페이지 캐시에 의존한다.
Kafka는 데이터를 JVM 힙 캐시로 들고 있기보다 디스크 로그 + OS 페이지 캐시에 맡김으로써, 더 큰 캐시 효과를 얻고 GC 문제를 줄이며 높은 처리량을 유지하려는 설계를 택한 것이라고 이해하면 된다.
문서의 내용을 GPT가 요약한 것이다. 자세한 내용이 궁금하면 위의 docs를 참고하자.
3. zero copy
![]() |
![]() |
| 기존 방식 | 제로카피 방식 |
제로 카피를 사용하면 컨텍스트 스위칭 비용이 줄어들고, 복사가 줄어든다. 심지어 제로카피 업그레이드 버전까지 사용한다면 복사가 2번만 일어난다.
제로카피는 이러한 비용을 절감시킴으로서 성능 개선을 이루어낸다.

정리
카프카 성능의 핵심은 배치, 공통 메시지 포맷, 압축 쪽이 더욱 본질적이다. zero-copy의 경우 브로커가 디스크의 데이터를 네트워크로 내보내는 특정 경로에서 CPU 복사 비용을 줄여주는 중요한 최적화이긴 하지만, Kafka 전체 처리량을 성립시키는 근본 설계라기보다 이미 효율적으로 쌓인 데이터를 더 싸게 전달하기 위한 전송 최적화에 가깝다.
문제의식
잘 알았다. 카프카는 빠르다. 세가지 이유가 있다. 그렇다. 이해는 했지만, 어려운 내용이다. 특히 너무나도 OS, 컴퓨터 구조적이다. 외우자.
Q : 카프카는 왜 빠른가요?
A : 카프카가 빠른 이유는 대략 세가지가 있습니다~
하지만 면접은 무섭다. 공식 문서라도 한번 제대로 읽어보자.
TLS/SSL libraries operate at the user space (in-kernel SSL_sendfile is currently not supported by Kafka). Due to this restriction, sendfile is not used when SSL is enabled. For enabling SSL configuration, refer to security.protocol and security.inter.broker.protocol
TLS/SSL 라이브러리는 사용자 공간에서 작동합니다(SSL_sendfile 현재 Kafka는 커널 내 실행을 지원하지 않습니다). 이러한 제약으로 인해 SSL이 활성화된 경우 해당 라이브러리는 사용되지 않습니다. SSL 구성 활성화에 대한 자세한 내용 은 및 을 sendfile 참조하십시오. security.protocol security.inter.broker.protocol
TLS/SSL이 활성화된 경우 zero copy가 동작하지 않는다는 것이다.
kafka:
bootstrap-servers: ${kafka.servers:localhost:29092}
properties:
security.protocol: SASL_SSL
sasl.mechanism: AWS_MSK_IAM
sasl.jaas.config: software.amazon.msk.auth.iam.IAMLoginModule required;
sasl.client.callback.handler.class: software.amazon.msk.auth.iam.IAMClientCallbackHandler
AWS MSK를 사용하며, 해당 설정을 활성화해두었다.
보안을 위해 IAM을 통해 kafka에 접근하고, 일반 메세지도 암호화된다.
하지만 난 zero copy의 혜택을 누리지 못하는 건가?
접근
이렇게나 좋은 zero copy를 사용하지 못한다니..
그럼 내 카프카는 느린 걸까?
AWS MSK의 공식 문서에 따르면 암호화 설정을 활성화하면 CPU 오버헤드가 증가하고 몇 밀리초의 지연 시간이 발생할 수 있다고 한다.
하지만 대부분의 사용 사례에서는 이러한 차이가 크게 중요하지 않다고 한다.
그렇다 하더라도 메서드를 직접 살펴보자.
SslTransportLayer vs PlaintextTransportLayer
kafka/clients/src/main/java/org/apache/kafka/common/network/SslTransportLayer.java at trunk · apache/kafka
Apache Kafka - A distributed event streaming platform - apache/kafka
github.com
SslTransportLayer의 내용이다.
@Override
public long transferFrom(FileChannel fileChannel, long position, long count) throws IOException {
if (state == State.CLOSING)
throw closingException();
if (state != State.READY)
return 0;
if (!flush(netWriteBuffer))
return 0;
long channelSize = fileChannel.size();
if (position > channelSize)
return 0;
int totalBytesToWrite = (int) Math.min(Math.min(count, channelSize - position), Integer.MAX_VALUE);
if (fileChannelBuffer == null) {
int transferSize = 32768;
fileChannelBuffer = ByteBuffer.allocateDirect(transferSize);
fileChannelBuffer.position(fileChannelBuffer.limit());
}
int totalBytesWritten = 0;
long pos = position;
try {
while (totalBytesWritten < totalBytesToWrite) {
if (!fileChannelBuffer.hasRemaining()) {
fileChannelBuffer.clear();
int bytesRemaining = totalBytesToWrite - totalBytesWritten;
if (bytesRemaining < fileChannelBuffer.limit())
fileChannelBuffer.limit(bytesRemaining);
int bytesRead = fileChannel.read(fileChannelBuffer, pos);
if (bytesRead <= 0)
break;
fileChannelBuffer.flip();
}
int networkBytesWritten = write(fileChannelBuffer);
totalBytesWritten += networkBytesWritten;
if (fileChannelBuffer.hasRemaining())
break;
pos += networkBytesWritten;
}
return totalBytesWritten;
} catch (IOException e) {
if (totalBytesWritten > 0)
return totalBytesWritten;
throw e;
}
}
write(fileChannleBuffer)을 잘 보자.
@Override
public int write(ByteBuffer src) throws IOException {
if (state == State.CLOSING)
throw closingException();
if (!ready())
return 0;
int written = 0;
while (flush(netWriteBuffer) && src.hasRemaining()) {
netWriteBuffer.clear();
SSLEngineResult wrapResult = sslEngine.wrap(src, netWriteBuffer);
netWriteBuffer.flip();
// reject renegotiation if TLS < 1.3, key updates for TLS 1.3 are allowed
if (wrapResult.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING &&
wrapResult.getStatus() == Status.OK &&
!sslEngine.getSession().getProtocol().equals(TLS13)) {
throw renegotiationException();
}
if (wrapResult.getStatus() == Status.OK) {
written += wrapResult.bytesConsumed();
} else if (wrapResult.getStatus() == Status.BUFFER_OVERFLOW) {
// BUFFER_OVERFLOW means that the last `wrap` call had no effect, so we expand the buffer and try again
netWriteBuffer = Utils.ensureCapacity(netWriteBuffer, netWriteBufferSize());
netWriteBuffer.position(netWriteBuffer.limit());
} else if (wrapResult.getStatus() == Status.BUFFER_UNDERFLOW) {
throw new IllegalStateException("SSL BUFFER_UNDERFLOW during write");
} else if (wrapResult.getStatus() == Status.CLOSED) {
throw new EOFException();
}
}
return written;
}
해당 메서드를 보면 알 수 있는 것이 SSL 래핑이 진행된다.
이를 보면 알 수 있듯이 Ssl 전송을 진행할 때는 zero copy가 되는 것이 아닌, ssl처리로 인한 로직이 들어간다.
PlaintextTransportLayer의 메서드이다.
@Override
public long transferFrom(FileChannel fileChannel, long position, long count) throws IOException {
return fileChannel.transferTo(position, count, socketChannel);
}
zero copy를 위한 java.nio의 메서드를 그대로 사용하는 것을 볼 수 있다.
즉, 응용계층과 전송계층 사이에서 동작하는 독립적인 SSL/TLS 프로토콜로 인해 zero copy가 동작하지 못하고 별도의 처리가 필요한 것이다.
확인
sudo docker exec -u 0 -it kafka sh
microdnf install -y strace
sudo docker exec -u 0 -it kafka sh -lc 'id && ps -o pid,user,comm -p 1 && strace -fp 1 -e trace=sendfile,sendfile64'
docker에 kafka를 동작시킨 뒤 브로커를 plaintext와 ssl 방식으로 모두 동작시켜 보았다.
plaintext로 동작시키면

zero copy 메서드가 정확히 동작함을 알 수 있다.
반면, ssl로 동작시키면 sendfile 시스템콜이 발생하지 않는다.
즉, zero copy가 동작하지 않는 것이다.
그렇다면 성능은?
로컬에서 실행된 매우 불확실한 테스트였으나, 큰 차이는 존재하지 않았다.
plaintext가 약간의 성능상 우위를 보이긴 했으나, 필자의 능력이 부족하여 이것이 ssl 처리에 의한 것인지 zero copy에 의한 것인지는 명확하게 정리하지 못했다.
결론
plaintext가 성능상 이점이 있는 것은 분명하다. zero copy를 지원하고, 암호화가 적용되지 않기에 가볍다.
하지만 암호화가 중요한 우리는 Kafka의 zero copy를 쓸 수 없는 것일까?
공식 문서를 참고한 필자 나름의 결론은 아래와 같다.
Kafka는 SSL listener와 PLAINTEXT listener를 동시에 운영할 수 있으며, 운영의 기본 방향은 TLS/SSL 중심으로 가져가되, 내부적으로 충분히 신뢰할 수 있는 네트워크 구간에 한해서는 PLAINTEXT를 선택해 성능 개선을 도모할 수 있다.
다만 이 경우에도 PLAINTEXT는 무분별하게 확장하기보다 내부 전용 listener로 역할을 명확히 분리하고, 외부 또는 민감한 트래픽은 반드시 SSL/SASL_SSL로 보호하는 방식이 바람직하다.
즉, 실무적으로는 보안을 기본값으로 두되, 성능과 운영 효율이 극적으로 중요한 경우 내부 신뢰망에 한해 제한적으로 PLAINTEXT를 활용하는 전략이 현실적인 절충안이라고 볼 수 있다.
출처
https://kafka.apache.org/42/design/design/#efficiency
https://aws.amazon.com/ko/blogs/tech/amazon-msk-topic-iam-access-control/
https://developer.ibm.com/articles/j-zerocopy/
https://docs.aws.amazon.com/msk/latest/developerguide/msk-encryption.html
https://github.com/apache/kafka
https://docs.confluent.io/platform/current/kafka/listeners.html
https://docs.oracle.com/en/java/javase/24/docs/api/java.base/java/nio/channels/FileChannel.html
'카프카' 카테고리의 다른 글
| [Kafka] Parallel-Consumer을 통한 알림 성능 개선 과정 요약 (0) | 2026.03.22 |
|---|---|
| [Kafka] Parallel-Consumer을 통한 알림 성능 개선 과정(3(완)) (0) | 2026.03.21 |
| [Kafka] Parallel-Consumer을 통한 알림 성능 개선 과정(2) (0) | 2026.03.21 |
| [Kafka] Parallel-Consumer을 통한 알림 성능 개선 과정(1) (0) | 2026.03.21 |
| [Kafka] Group, Topic, Record, Consumer, Partition 총 정리 (0) | 2026.01.05 |

