올리브영 테크블로그 포스팅 AWS MSK Connect 효과적으로 운영하기
B2B Logistics

AWS MSK Connect 효과적으로 운영하기

AWS MSK Connect 이해와 효과적인 운영 전략 소개

2023.10.04

안녕하세요. B2B 물류 스쿼드의 백엔드 개발자, 시나브로우입니다.

저희 B2B 물류 스쿼드에서는 올리브영의 오프라인 발주와 물류 시스템을 담당하고 있습니다.

오프라인 개발 환경에서는 모놀리식 기반의 레거시 시스템에서 MSA 기반의 신규 서비스로 계속해서 개편 중입니다.


현재 발주와 물류 프로세스 개선의 일환으로 AWS MSK Connect 도입을 하고 있습니다.

오프라인 환경에서 AWS MSK Connect를 중심으로 한 비동기 통신 메세지 큐(Asynchronous Communication)와 CDC(Change Data Capture)의 도입은 큰 변화를 가져왔습니다.


이 변화는 일부에서 우려의 목소리도 있었습니다만

이번에는 내부 우려를 완화하고 AWS MSK Connect 에 대한 이해를 돕기 위해 저희 스쿼드에서 진행하고 있는 효과적인 운영 전략을 소개하겠습니다.



MSK 와 MSK Connect 의 기본 구조

MSK 에 대한 우려와 운영 전략을 소개하기에 앞서, MSK 를 이해하는데 도움이 되도록 간략하게 설명드리겠습니다.

MSK(Amazon Managed Streaming for Apache Kafka) 는 AWS에서 제공하는 완전 관리형 서비스인 'Apache Kafka' 를 지칭합니다.

MSK 를 제대로 이해하기 위해서는 Kafka 의 구조에 대한 이해가 필요합니다.


Kafka 기본 구조 b2b msk 01


Kafka 는 Broker, Producer, Consumer 로 구성되어있습니다.

Producer 는 메세지를 Kafka Cluster 에 전송하는 역할을 담당합니다. 여기서 메세지는 데이터를 의미합니다.

Kafka Cluster 는 여러 Broker 들로 구성되어 있으며, 각 Broker 내부에는 각각의 Topic 이 있습니다.

이 Topic 을 통해 메세지를 주고받을 수 있습니다.


마지막으로, Consumer 는 이 메세지를 받아들이는 역할을 하며, 받은 메세지를 처리하고 소모합니다.


MSK(Kafka) 의 특징을 간략하게 정리하면 다음과 같습니다.

  • Data Consistency (데이터 일관성)
    • 애플리케이션은 토픽을 통해 데이터를 주고받기 때문에 데이터 무결성을 보장.
  • Asynchronous Communication (비동기 통신)
    • Produce to Broker, Broker To Consumer 비동기 통신 지원.
  • Message Persistence (메시지 유지)
    • Topic Message 기본 7일 저장, re-read 또는 재처리 가능.
  • 대량의 데이터 송수신에 유리
    • Peak Throughput(MB/s): 605MB/s
    • P99 Latency(ms): 5ms(200MB/s load)

다음으로 MSK Connect에 대해 말씀드리겠습니다.

MSK Connect는 외부 시스템과 Kafka 클러스터 간 데이터를 손쉽게 주고받을 수 있는 서비스입니다.

MSK Connect는 CDC(Change Data Capture) 기능을 제공하는데,

CDC는 데이터베이스의 변경된 데이터를 추출하여 비동기적으로 복제하는 기법입니다.

CDC 기능은 MSK Connect를 도입하는 데 있어 주요 동기 중 하나였습니다.



MSK Connect 구조 b2b msk 02


Source Connector 는 Producer 의 역할을 합니다.

그리고 Sink Connector 는 Consumer 의 역할을 합니다.

Connect 가 제공하는 플러그인을 활용하면, 다른 시스템 간의 호환성을 최대화하며, 이들 시스템을 쉽게 연동하여 사용할 수 있습니다.


글 작성 시점을 기준으로, Connect 가 제공하는 플러그인은 총 197개이며,

Debzium CDC 플러그인 외에도 Elasticsearch, MongoDB, S3, Datadog, BigQuery, Redshift 등과 같은 잘 알려진 외부 자원과 연동할 수 있는 플러그인들을 제공합니다.


Connect 의 특징을 간략하게 정리하면 다음과 같습니다.

  • RDMS, NoSQL 에 대한 Source/Sink Connector 지원
  • 이기종 간 CDC 지원
  • 시스템 간 호환성이 좋음

저희 스쿼드는 이러한 특성을 활용하여 MSK Connect를 도입하고,

CDC 기법으로 데이터를 실시간으로 추출하며 Consumer 에서 데이터를 처리함으로써 배치 시스템의 사용을 줄이고 있습니다.

다음 세션에서는 본격적으로 MSK에 대한 내부 우려를 완화하고, 효과적인 운영 전략을 소개하도록 하겠습니다.


MSK 가 죽는다면?

MSK 클러스터는 여러 broker 로 구성되며, 다중 가용 영역(Multi-AZ)에서 Kafka broker 를 운영합니다.

특정 broker 에 문제가 발생해도 다른 broker 에는 영향을 주지 않고, broker 장애 발생 시, 해당 broker 는 자동으로 복구됩니다.


Topic 을 생성할 때 'Replication Factor' 를 설정하면,

하나의 브로커에 문제가 발생하더라도 다른 브로커에 복제본이 존재해 데이터 손실을 막을 수 있습니다.

예를 들어, 'Replication Factor' 를 3으로 설정하면,

Topic은 'Leader Partition' 1개와 'Follower Partition' 2개로 구성됩니다.


여기서 Topic의 원본이 'Leader Partition'이며, 복제본은 'Follower Partition'입니다.

Partition 은 다수의 브로커에 분산 저장되고, 'Leader Partition'이 저장된 브로커에 장애가 발생하면,

다른 브로커에 저장된 'Follower Partition' 이 'Leader Partition' 으로 승격됩니다.


이 'Leader Partition' 으로 승격과정에서 해당 Partition 이 위치한 브로커 또한 Topic 의 리더 브로커로 변환됩니다.

'Leader Partition' 으로 승격된 'Follower Partition' 은 장애가 발생한 'Leader Partition' 을 대체, 서비스를 계속 유지할 수 있습니다.


또한, 'Leader Partition' 으로 승격 후, 'Leader Epoch' 가 발생하며,

변경된 리더의 정보가 복구된 팔로워로 전달되고, 장애 시간 동안 소실된 데이터도 변경된 리더를 통해 복구가 가능합니다.

쉽게 말하면, 'Leader Epoch' 를 통해 장애 후 복구 과정에서 리더와 팔로워 간의 메시지 일관성을 유지하며 데이터 손실을 방지합니다.


정리하면, MSK 클러스터와 'Replication Factor' 설정을 통해 데이터를 여러 브로커에 분산 저장하며,

장애 발생 시 다른 브로커에 저장된 'Follower Partition' 을 'Leader Partition' 으로 승격하여 대체함으로써, 서비스를 지속적으로 유지할 수 있습니다.

그렇지만, 'Replication Factor' 설정 시 주의가 필요하며, 'Partitions' 설정과의 관계도 함께 고려해야 합니다.



Topic 의 Partitions 과 Replication 의 연관 관계

Topic 은 레코드를 논리적으로 저장하는 단위로, 하나의 Topic 은 최소 하나 이상의 Partition 으로 구성됩니다.

앞서 언급했듯이, Replication Factor 를 설정해 MSK를 안정적으로 운영할 수 있지만, 복제본이 저장될 용량도 염두에 둬야 합니다.

설정한 Replication Factor 값 만큼의 배수로 저장 공간이 필요하게 됩니다.

예시로, Replication Factor가 2라면 저장 공간이 2배, 3이라면 3배 필요합니다.


또한, Partitions 설정도 Replication Factor 설정과 함께 고려되어야 합니다.

데이터의 양이 많은 Topic의 경우, Partitions 설정을 통해 여러 저장 공간으로 데이터를 분산 저장하며, 이를 통해 전체 처리율을 향상시킬 수 있습니다.

여기서 Topic 의 Partitions 설정은 Replication Factor(복제 계수) 와 상호 작용하며, 총 저장소 개수(Segment Size)를 결정합니다.

예를 들어, Partitions 가 4 이고 Replication Factor 가 2인 경우, 총 8개의 저장소가 생성되는 방식입니다.

간단히 말해, 두 설정이 곱해져 총 저장소 개수가 결정됩니다.


따라서, 데이터의 특성과 크기에 따라 Partitions 설정과 Replication Factor 설정이 적절히 이루어져야 합니다.

또한, Replication Factor 설정에 의해 늘어나는 Topic 데이터 용량 문제를 해결하기 위한 데이터 경량화 작업도 필요합니다.

저희 스쿼드는 Topic 데이터 용량을 줄이기 위해 Avro 포맷을 활용하고 있습니다.

Avro 포맷을 이용한 데이터 경량화 작업에 대해서는 뒷 세션에서 좀 더 상세히 다루도록 하겠습니다.



MSK Connect 가 죽는다면?

CDC(Change Data Capture) 수행 중 MSK Connect가 실패할 경우, '장애 시간 동안 대상 데이터가 소실되지 않을까?' 라는 우려가 있었습니다.

Oracle을 기준으로, CDC를 사용하면 DB의 SCN(System Change Number) 정보가 Connect에 저장됩니다.

SCN 정보는 amazon_msk_connect_offsets[CONNECTOR_NAME][CONNECTOR_ID] 와 같은

connect-offsets internal topic으로 저장되며, 이는 internal topic으로 관리됩니다.


SCN (System Change Number) 는 Oracle 데이터베이스의 모든 트랜잭션을 일련번호로 나타낸 CDC 데이터 버전 값이라고 보면 됩니다.

Oracle 데이터의 변경 정보는 이 고유한 SCN을 통해 알 수 있게 됩니다.


MSK Connect가 장애 이후 복구되면, MSK Connect 는 저장된 SCN 값을 기준으로 마지막으로 처리된 이후의 변경 내용을 재처리합니다.

이러한 방식으로 MSK Connect는 장애 발생 시에도 데이터 소실 없이 CDC를 지속적으로 수행할 수 있습니다.



Avro Format 과 AWS Glue Schema Registry 를 사용한 효과적인 데이터 압축

앞서 언급했듯이, Replication Factor를 통해 복제본을 저장하게 되면 데이터 저장 용량이 증가합니다.

또한 대량의 데이터를 일반적인 Json Format으로 저장하면, MSK에 상당한 저장 공간이 필요합니다.

따라서 MSK에 저장되는 데이터는 경량화할 필요가 있습니다.

저희 스쿼드는 데이터를 효율적으로 경량화하고 저장하기 위해 Avro Format 과 AWS Glue Schema Registry 를 활용하고 있습니다.


MSK Connect 에 저장된 Avro Format 메세지 b2b msk 03

직렬화해서 저장된 데이터의 형태는 위의 그림과 같습니다.

MSK Connect 의 CDC 로 추출한 데이터의 메타 정보는 AWS Glue Schema Registry 에 저장합니다.

메타 정보 이외의 데이터의 실제 값은 binary 형태로 위와 같이 topic 에 저장됩니다.



MSK Connect 의 데이터 저장 및 데이터의 메타 정보 저장에 대한 자세한 플로우는 아래 그림과 링크를 참조하세요.

b2b msk 04
출처: (aws-glue-schema-registry-integrations)

데이터의 메타 정보는 AWS Glue Schema Registry 의 Schema 로 생성되며, 이 Schema 정보는 고유 Schema Id 를 통해 호출이 가능합니다.

Schema 와 Schema Id 는 캐시되기 때문에 MSK Connect 를 통해 동일한 Schema 로

이벤트를 계속 생성하는 한 Schema Registry 와 다시 통신할 필요가 없습니다.

topic 에는 데이터와 함께 Schema Id 가 저장되기 때문에

실제 Schema 정보를 레코드 마다 저장하지 않는다는 점에서 Json Format 보다 데이터 압축효과가 큽니다.



Avro 와 Schema Registry 를 활용한 자세한 정보는 Confluent 공식 문서를 참조하는 것이 좋습니다.

https://www.confluent.io/blog/schemas-contracts-compatibility/


b2b msk 05

실제 topic 에 저장되는 데이터 크기를 비교해보았습니다.

동일한 데이터 약 238만 건을 기준으로, Json Format 은 12G이며 Avro Format 은 538MB로 확인되었습니다.

Avro Format 으로 데이터를 24배 압축한 셈이죠.

물론 topic 에 저장되는 메세지 크기는 필드의 수, 명칭의 길이, 값의 길이 등에 따라 변할 수 있지만,

Json Format 과 Avro Format 간의 용량 차이는 뚜렷하게 나타났습니다.


Avro Format 이점을 간략하게 정리하면 다음과 같습니다.
  • 메세지 용량 감소
  • Json Format 보다 빠른 전송 가능
  • 스키마 중복 제거


Topic 메세지 Dead Letter 처리

'Broker에서 Consumer 로 메세지를 전달하는 과정에서 네트워크 문제로 메세지 소실될 수 있지 않을까?' 라는 우려도 있었습니다.

그러나, Consumer는 메세지를 정상적으로 받으면 Ack(Acknowledgment)을 보내며, 받지 못했을 경우 Broker가 메세지를 재전송할 수 있습니다.


'enable.auto.commit' 옵션을 이용해 Ack를 자동 또는 수동으로 처리할 지 선택이 가능합니다.

'enable.auto.commit' 값을 false 로 지정하여, 저희 스쿼드에서는 수동 Ack 전략을 사용해서

Consumer 가 메세지를 정상적으로 전송받은 시점에서 명시적이고 안전한 Ack 처리를 하고 있습니다.


또한, Consumer에서 'isolation.level' 을 'read_committed' 로 설정해 커밋된 트랜잭션만 읽도록 구성하고 있습니다.

이러한 설정을 통해서 메시지 전달의 정확도를 높이며, 메시지가 한 번만 전송되고 처리될 수 있도록 하고 있습니다.


네트워크 이슈로 발생하는 Dead Letter는 Ack 설정을 통해 재처리가 가능합니다.

그렇다면 네트워크 이슈 외에 Dead Letter는 어떤 상황에서 발생할까요?

Connect 에서 발생 가능한 오류는 대개 직렬화 및 역직렬화(Serde) 오류입니다.

Consumer로 메세지가 전달될 때 발생하는 Dead Letter의 대부분은 Serde 오류인 경우가 많습니다.

Serde 오류는 개발 및 테스트 단계에서 캐치할 수 있지만,

만일을 대비해 DLQ(Dead Letter Queue)를 설정하여 모든 Dead Letter 발생을 처리하도록 했습니다.


DLQ 는 메시지 처리에 실패하거나 처리되지 않은 메시지를 별도로 관리하기 위한 대기열(queue)을 의미합니다.

errors.tolerance = all
errors.log.enable = [true|false]
errors.deadletterqueue.context.headers.enable = ture
errors.deadletterqueue.topic.name = <DLQTopicName>

'errors.tolerance = all' 및 'errors.deadletterqueue.topic.name = <DLQTopicName>' 설정을 통해 실패한 데이터를 지정된 DLQ로 전달하고, 이후의 메시지는 정상적으로 처리됩니다.

또한, 'errors.deadletterqueue.context.headers.enable = true' 설정을 활성화하면, 메시지 헤더에 실패 원인을 저장할 수 있습니다.

정리하자면, Consumer 가 메시지를 수신할 때 Json Format과 Avro Format 간의 포맷 불일치 또는 Serde 오류가 발생할 경우,

오류 레코드를 DLQ(Dead Letter Queue) 로 전송하여 Consumer나 Connect 가 서비스를 지속적으로 중단 없이 제공할 수 있습니다.

그 밖에, 비즈니스 로직으로 인해 오류가 발생한 데이터는 S3에 엑셀 파일로 백업하여 관리하고 있습니다.


보다 상세한 내용은 아래의 블로그 내용을 참조해주세요.

https://www.confluent.io/blog/kafka-connect-deep-dive-error-handling-dead-letter-queues/



MSK Connect 모니터링

AWS MSK를 사용하면 Amazon CloudWatch와 기본 연동이 가능해, 주요 지표를 모니터링할 수 있습니다.

그러나 올리브영에서는 더 효율적인 운영을 위해 DataDog 와 AWS MSK 를 연동하여 모니터링하고 있습니다.

AWS MSK 에서 제공하는 Prometheus 와 Prometheus Exporter를 이용하면, MSK의 지표를 DataDog으로 전달할 수 있습니다.

Prometheus Exporter 에서 JmxExporter, NodeExporter 를 활성화하여 DataDog 과 연동해서 수집할 수 있는 지표는 다음과 같습니다.

  • JMX Exporter - Apache Kafka JMX 지표를 표시합니다.
  • Node Exporter - CPU 및 디스크 지표를 표시합니다.

Metric Name Discription
aws.kafka.bw_in_allowance_exceeded 브로커의 최대 수신 대역폭이 초과되어 패킷이 제한된 횟수
aws.kafka.bw_out_allowance_exceeded 브로커의 최대 송신 대역폭이 초과되어 패킷이 제한된 횟수
aws.kafka.bytes_in_per_sec 클라이언트로부터 초당 수신되는 바이트 수
aws.kafka.bytes_out_per_sec 클라이언트로 초당 송신되는 바이트 수
aws.kafka.consumer_response_send_time_ms_mean 소비자가 응답을 보내는 데 걸리는 평균 시간
aws.kafka.cpu_credit_balance 브로커의 CPU 크레딧 잔액
aws.kafka.cpu_system 커널 공간에서 CPU 사용량의 비율
aws.kafka.cpu_user 사용자 공간에서 CPU 사용량의 비율
aws.kafka.fetch_consumer_local_time_ms_mean 리더에서 소비자 요청이 처리되는 데 걸리는 평균 시간(밀리초)
aws.kafka.fetch_consumer_request_queue_time_ms_mean 소비자 요청이 요청 대기열에서 기다리는 평균 시간(밀리초)
aws.kafka.fetch_consumer_response_queue_time_ms_mean 소비자 요청이 응답 대기열에서 기다리는 평균 시간(밀리초)
aws.kafka.fetch_consumer_total_time_ms_mean 소비자가 브로커로부터 데이터를 가져오는 데 걸리는 평균 총 시간(밀리초)
aws.kafka.fetch_follower_local_time_ms_mean 리더에서 팔로워 요청이 처리되는 데 걸리는 평균 시간(밀리초)
aws.kafka.fetch_follower_request_queue_time_ms_mean 팔로워 요청이 요청 대기열에서 기다리는 평균 시간(밀리초)
aws.kafka.fetch_follower_response_queue_time_ms_mean 팔로워 요청이 응답 대기열에서 기다리는 평균 시간(밀리초)
aws.kafka.fetch_follower_response_send_time_ms_mean 팔로워가 응답을 보내는 데 걸리는 평균 시간(밀리초)
aws.kafka.fetch_follower_total_time_ms_mean 팔로워가 브로커로부터 데이터를 가져오는 데 걸리는 평균 총 시간(밀리초)
aws.kafka.fetch_message_conversions_per_sec 브로커에서 초당 패치 메시지 변환 수
aws.kafka.fetch_throttle_byte_rate 초당 제한된 바이트 수
aws.kafka.fetch_throttle_queue_size 제어 대기열에 있는 메시지의 수
aws.kafka.global_partition_count 클러스터 전체 브로커에서의 파티션 총 개수
aws.kafka.global_partition_count.maximum 클러스터 전체 브로커에서의 최대 파티션 총 개수
aws.kafka.global_topic_count 클러스터의 브로커 수로 평균화된 토픽 총 개수
aws.kafka.global_topic_count.maximum 클러스터의 브로커 수로 평균화된 최대 토픽 총 개수
aws.kafka.kafka_app_logs_disk_used 응용 프로그램 로그에 사용되는 디스크 공간의 백분율
aws.kafka.kafka_data_logs_disk_used 데이터 로그에 사용되는 디스크 공간의 백분율
aws.kafka.leader_count 리더 복제본의 수
aws.kafka.max_offset_lag 토픽 내 모든 파티션에서의 최대 오프셋 지연
aws.kafka.memory_buffered 브로커를 위한 버퍼 메모리의 크기
aws.kafka.memory_free 브로커를 위해 사용 가능한 여유 메모리의 크기
aws.kafka.memory_heap_after_gc 가비지 컬렉션 후 사용 가능한 총 힙 메모리의 백분율
aws.kafka.memory_used 브로커에서 사용 중인 메모리의 크기
aws.kafka.messages_in_per_sec 초당 클라이언트로부터 받는 메시지의 수
aws.kafka.network_processor_avg_idle_percent 네트워크 프로세서가 유휴 상태인 시간의 평균 백분율
aws.kafka.network_rx_dropped 드롭된 수신 패키지의 수
aws.kafka.network_rx_errors 브로커의 네트워크 수신 에러 수
aws.kafka.network_rx_packets 브로커가 받은 패키지 수
aws.kafka.network_tx_dropped 드롭된 송신 패키지의 수
aws.kafka.network_tx_errors 브로커의 네트워크 송신 에러 수
aws.kafka.network_tx_packets 브로커가 전송한 패키지 수
aws.kafka.offline_partitions_count 클러스터 내에서 오프라인 상태인 파티션의 총 수
aws.kafka.offset_lag 파티션 수준의 소비자 지연(오프셋 수)
aws.kafka.partition_count 브로커의 파티션 수
aws.kafka.produce_local_time_ms_mean 팔로워가 응답을 보내는 데 걸린 평균 시간
aws.kafka.produce_message_conversions_per_sec 브로커의 초당 생산 메시지 변환 수
aws.kafka.produce_message_conversions_time_ms_mean 메시지 형식 변환에 소요되는 평균 시간
aws.kafka.produce_request_queue_time_ms_mean 요청 메시지가 대기열에서 보내는 데 걸리는 평균 시간
aws.kafka.produce_response_queue_time_ms_mean 응답 메시지가 대기열에서 보내는 데 걸리는 평균 시간
aws.kafka.produce_response_send_time_ms_mean 응답 메시지를 보내는 데 걸리는 평균 시간
aws.kafka.produce_total_time_ms_mean 평균 생산 시간
aws.kafka.replication_bytes_in_per_sec 브로커 원본에서 복사본으로 초당 받는 바이트 수
aws.kafka.replication_bytes_out_per_sec 브로커 원본에서 복사본으로 초당 전송되는 바이트 수
aws.kafka.request_bytes_mean 브로커의 평균 요청 바이트 수
aws.kafka.request_throttle_queue_size 제어 대기열의 메시지 수
aws.kafka.request_throttle_time 평균 요청 제어 시간
aws.kafka.sum_offset_lag 토픽 내 모든 파티션에 대한 총 오프셋 지연
aws.kafka.swap_free 브로커를 위해 사용 가능한 스왑 메모리의 크기
aws.kafka.swap_used 브로커에서 사용 중인 스왑 메모리의 크기
aws.kafka.traffic_bytes 클라이언트(생산자 및 소비자)와 브로커 간의 전체 네트워크 트래픽(바이트), 브로커 간의 트래픽은 제외
aws.kafka.volume_queue_length 지정된 시간 동안 완료를 기다리는 읽기 및 쓰기 작업 요청의 수
aws.kafka.volume_read_bytes 지정된 시간 동안 읽은 바이트 수
aws.kafka.volume_read_ops 지정된 시간 동안의 읽기 작업 수
aws.kafka.volume_total_read_time 지정된 시간 동안 완료된 모든 읽기 작업에 소요된 총 시간(초)
aws.kafka.volume_total_write_time 지정된 시간 동안 완료된 모든 쓰기 작업에 소요된 총 시간(초)
aws.kafka.volume_write_bytes 지정된 시간 동안 쓴 바이트 수
aws.kafka.volume_write_ops 지정된 시간 동안의 쓰기 작업 수

더욱 상세한 지표 내용을 확인하고 싶으시다면, DataDog의 공식 문서를 참조해주세요.

https://docs.datadoghq.com/ko/integrations/amazon_msk/



위의 지표 외에도, 저희 스쿼드는 DataDog의 Kafka 관련 플러그인을 활용하여 Metrics 지표를 수집하며,

커스텀 Metrics 지표와 결합하여 더욱 풍부한 모니터링 대시보드를 구성하여 운영하고 있습니다.



끝으로

지금까지 올리브영 B2B 물류 스쿼드의 AWS MSK Connect 효과적으로 운영 방법을 소개하였습니다.

MSK Connect 에 대한 궁금증과 우려를 해소하고자 하며, MSK Connect 도입을 고려하시는 분들을 위해 이 글을 작성하였습니다.

글이 예상보다 길어져서 다큐멘터리가 된 것 같습니다.

그럼에도 불구하고 이 글이 누군가에게 유용한 정보가 되길 바라며, 여기서 마무리하겠습니다.


신기술에 관심 많으시고 저희 스쿼드와 함께 오프라인 서비스를 개선하고 싶은 분이라면, 채용공고를 확인해주세요!

더 발전된 모습으로 다시 만나 뵙겠습니다.

지금까지 올리브영 B2B 물류 스쿼드, 시나브로우였습니다.

감사합니다.




mskconnectavro
올리브영 테크 블로그 작성 AWS MSK Connect 효과적으로 운영하기
🌟
시나브로우 |
Back-end Engineer
빛과 소금이 되고 싶은 개발자입니다.