최근 프로젝트에서 우리는 솔루션 인터페이스에 인코딩된 이미지를 메시지에 포함시켜 Kafka를 통해 전송해야 하는 과제에 직면했습니다. 그러나 이미지 데이터의 특성상 메시지 크기가 너무 커져 전송 효율성과 시스템 성능에 문제가 발생했습니다. 이 글에서는 이 문제를 어떻게 정의하고 해결했는지, 그리고 각 압축 방식에 대한 비교를 통해 최적의 솔루션을 선택한 과정을 공유하고자 합니다.
우선 현재 시스템에서 메시지가 어떻게 전송되고 있는지, 그리고 그로 인해 어떤 문제가 발생하는지 상세히 분석했습니다.
문제 해결을 위해 여러 가지 접근 방안을 고려했습니다.
사실 외부 스토리지 사용을 하고 싶지만, 솔루션에서 제공하는 스펙이라 맞출 수 밖에 없었습니다.
따라서 Kafka의 메시지 압축 기능을 활용하였습니다.
부가적으로 얻을 수 있는 장점은..
Kafka가 지원하는 압축 방식에 대한 성능과 압축률을 비교하여 최적의 옵션을 선택하고자 했습니다.
압축 방식 | 압축률 | 압축 속도 | 해제 속도 | CPU 사용량 | 특징 |
---|---|---|---|---|---|
GZIP | 높음 | 느림 | 느림 | 높음 | 높은 압축률, CPU 부하 큼 |
Snappy | 낮음 | 매우 빠름 | 매우 빠름 | 낮음 | 빠른 속도, 낮은 압축률 |
LZ4 | 중간 | 빠름 | 빠름 | 낮음 | 속도와 압축률의 균형 |
Zstd | 매우 높음 | 빠름 | 빠름 | 중간 | 높은 압축률과 속도 |
Kafka 메시지 압축을 적용하기 위해 Spring Boot와 Kotlin을 사용하여 간단한 예제 코드를 작성했습니다.
import org.springframework.kafka.core.KafkaTemplate
import org.springframework.stereotype.Service
import java.util.*
@Service
class ImageProducer(private val kafkaTemplate: KafkaTemplate<String, ByteArray>) {
fun sendImage(imageData: ByteArray) {
val topic = "image-topic"
val key = UUID.randomUUID().toString()
kafkaTemplate.send(topic, key, imageData)
}
}
import org.springframework.kafka.annotation.KafkaListener
import org.springframework.stereotype.Service
@Service
class ImageConsumer {
@KafkaListener(topics = ["image-topic"], groupId = "image-group")
fun consumeImage(imageData: ByteArray) {
// 이미지 데이터를 처리하는 로직
println("Received image data of size: ${imageData.size} bytes")
}
}
이미지를 전송하기 전에 추가로 압축하고 싶다면, 이미지 데이터를 GZIP 등으로 압축할 수 있습니다. 그러나 Kafka의 LZ4 압축을 활용하기 때문에 추가적인 압축은 필요하지 않았습니다.
Kafka의 LZ4 메시지 압축 기능을 활용하여 대용량 이미지 데이터를 효율적으로 전송할 수 있었습니다. 이를 통해 시스템 성능 저하 문제를 해결하고, 네트워크 및 시스템 자원을 효율적으로 사용할 수 있게 되었습니다.
이번 경험을 통해 시스템 설계 시 데이터 크기와 전송 효율성에 대한 고려가 얼마나 중요한지 다시 한 번 깨달을 수 있었습니다. 앞으로도 이러한 문제에 직면했을 때 근본적인 원인을 파악하고, 효율적인 해결책을 찾아나갈 것입니다.