
언어
Java
사용 기업

트렌비

플렉스

렌딧

엔라이튼

토스랩

핀다

드라마앤컴퍼니

딜리셔스

식스샵

드림어스컴퍼니

스푼

클래스101

바로고

직방

당근

마이리얼트립

그린랩스

와디즈
더 보기
쏘카
로그 파이프라인 개선기 - 기존 파이프라인 문제 정의 및 해결 방안 적용
안녕하세요. 쏘카 데이터엔지니어링팀 삐약, 루디입니다.내용을 시작하기에 앞서, 저희 팀의 업무와 역할에 대해 간략히 소개해 드리겠습니다.데이터엔지니어링팀은 신뢰할 수 있는 데이터를 쏘카 구성원들이 안정적으로 활용할 수 있도록 기반을 마련하고, 이를 실제 비즈니스에 적용할 수 있는 서비스를 개발하며 환경을 구축하고 있습니다. 데이터 마트 관리, 데이터 인프라 구축, 그리고 데이터 제품(Data as a Product) 개발 등 폭넓은 업무를 수행하고 있습니다.특히 주요 업무로는 배치 및 실시간 스트리밍 파이프라인을 설계하고 개발하여, 쏘카의 모든 서비스에서 발생하는 데이터를 비즈니스 분석에 효과적으로 활용할 수 있도록 지원하는 역할을 하고 있습니다.이번 글에서는 저희 팀이 관리 및 운영하는 데이터 파이프라인 중, 비즈니스 의사 결정 시 지표로 사용되는 서버 로그를 데이터 웨어하우스로 사용하고 있는 BigQuery에 적재하는 로그 파이프라인 개선 과정을 소개드리고자 합니다개선을 하게 된 가장 주요 이유 중 하나는 데이터 스키마 변경으로 인해 겪는 어려움 이었습니다. 이를 해결하기 위해 데이터 컨트랙트를 도입하게 되었고, 이 과정에서 얻은 경험을 나누고자 합니다. 이번 시리즈는 비슷한 문제를 겪고 계신 분들께 도움이 되길 바랍니다.• 데이터 파이프라인을 구축하거나 개선하고자 하는 데이터 엔지니어• 데이터 컨트랙트를 도입하려는 개발자• 데이터 엔지니어의 업무에 대해 궁금한 분2. 기존 로그 파이프라인 현황기존 파이프라인을 설명하기에 앞서, 아키텍처의 문제를 더 명확히 이해하기 위해 원본 데이터의 구조와 요구사항을 먼저 살펴보겠습니다.원본 데이터에서 하나의 로그 파일은 다음과 같은 형식으로 제공됩니다.하나의 파일에는 여러 종류의 로그 데이터가 섞여 있으며, 모든 데이터에는 로그의 종류(type)와 생성 시간(timeMs) 같은 공통 필드가 포함되어 있습니다. 또한 각 로그 타입마다 고유한 필드도 존재합니다.파이프라인의 요구사항은 아래와 같습니다.• BigQuery 테이블화: 로그 데이터는 타입별로 구분된 BigQuery 테이블에 저장되어야 하며, 이를 통해 조회 및 분석이 가능해야 합니다.• 특정 타입 데이터 적재: 요청한 타입의 데이터만 BigQuery에 적재해야합니다.• 배치성 처리: 데이터 처리와 적재는 최소 2시간 이내에 이루어져야 하며, 가능하면 더 빠르게 처리되어야 합니다.이러한 데이터 구조와 요구사항을 바탕으로, 기존 파이프라인이 어떻게 구성되어 있는지 살펴보겠습니다.2-2. 기존 파이프라인 아키텍처우선 어떻게 데이터 파이프라인을 개선할 것인가에 대한 질문에 대한 답을 하기에 앞서 기존 아키텍처에 대하여 이해하고 어떤 부분에서의 문제가 발생하고 있는지의 파악이 필요합니다.기존 파이프라인 설계 당시의 상황과 고려 사항을 살펴보면, 이미 Amazon Kinesis Data Stream(KDS)과 Firehose를 통해 AWS S3에 데이터가 적재되고 있는 환경이었습니다. 더불어 로그 데이터는 주로 분석 용도로 활용될 예정이었기에 실시간성
airflow
googlebigquery
java
kafka
python
여기어때컴퍼니
Kafka Message Conversion (Serial/Deserializing)
안녕하세요. 여기어때컴퍼니 주문결제개발팀 애쉬입니다.프로젝트 진행 도중 ‘Kafka Message를 Consume할 때 Json Value를 Parsing하는 과정이 좀 이상한데?’에서 시작한 짧은 이야기를 들려 드릴까 합니다. 한 편의 수필이라 생각하고 봐주시면 감사하겠습니다.Project versionsjava openjdk 17spring boot 2.7.18apache kafka 3.1.2spring kafka 2.8.11Json과 함께하는 Kafka 여행Kafka 메세지 변환 관련 설정을 뜯어보게 된 이유?기존에 Kafka Message를 Consume하는 우리 서비스들은 대부분 메세지를 Key 없이 Value를 String으로 받아서 ObjectMapper를 활용해서 변환을 하고 있었어.private ConsumerFactory setConsumerFactory(final KafkaProperties.ConsumerConfig consumerConfig) { Map configProps = new HashMap<>(); ... 중략 configProps.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); configProps.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); ... 중략 return new DefaultKafkaConsumerFactory<>(configProps);}@KafkaListener(containerFactory = "testKafkaListenerContainerFactory", topics = "${spring.kafka.consumer.test.topic}")public void consumeTest(ConsumerRecord consumerRecord) { try { TestDTO testDTO = objectMapper.readValue(consumerRecord.value(), TestDTO.class); // do something with DTO } catch (Exception e) { // do something with exception }}그래서 아 Producer 쪽에서 Json String으로 모델을 Converting해서 보내고 있나 보다! 하고 Producer 서비스를 열어보았는데 웬걸 Message Value를 JsonSerializer를 통해서 (objectMapper를 통한 jsonString 생성 후 전달이 아닌) 직변환해서 사용 중이었더라고?@Beanpublic ProducerFactory producerFactory() { KafkaProperties.ProducerCommonConfig config = kafkaProperties.getProducer().getCommonConfig(); M
java
kafka
spring
현대자동차그룹
VM Blue-Green 전환으로 효율적인 개발 환경 만들기 (feat. Property 주입)
안녕하세요, 현대오토에버 CCS정보팀 장성호 책임입니다. 현대자동차그룹 커넥티드 카 서비스(CCS) 시스템 중, 글로벌 CCS1.0 코어 시스템 개발 및 운영을 맡고 있습니다. 담당 시스템의 VM Blue-Green 전환 프로젝트를 맡게 되어, 이에 대한 경험을 공유하고자 합니다. 프로젝트 배경CCS 1.0의 CI/CD는 주로 VM 환경에 Artifact를 배포하는 방식입니다. 또한 Property 주입은 FreeMarker를 활용해 .ftl 확장자에 JSON 값을 배치하는 방식으로 사용되고 있었습니다.그림 1. 기존 CCS 1.0 CI/CD이러한 구조는 다음과 같은 문제점이 있었습니다.FreeMarker 기반 Maven plugin 사용으로 빌드 도구가 maven에 종속Property 주입이 빌드 시점에 이루어져, Property 변경시 항상 CI/CD 파이프라인 전체 재실행 필요War 파일 중 최신 버전만 가져와 Rollback에 취약개발자가 VM에 접속해 일일이 chef-client 명령어를 실행시켜줘야 배포 진행*Chef - Ruby DSL를 활용해 인프라를 코드로 작성하는 IT 자동화 플랫폼. 작성된 코드는 cookbook이라고 부른다. *chef-client - Chef 플랫폼 배포 명령어. Chef cookbook에 명시되어 있는대로 명령어를 수행한다.FreeMarker그림 2. FreeMarker 구조FreeMarker에 대해 간단히 소개하자면, 변경되는 데이터를 템플릿에 따라 텍스트 출력(HTML, XML, 메일 등)으로 만들어주는 Java 라이브러리입니다. MVC 패턴이 익숙하시다면 Model을 View에 표출해주기 위한 템플릿 엔진이라고 이해하셔도 무방합니다. Freemarker Template Language(FTL)에 따라 템플릿을 작성해놓고 동적 데이터를 HTML로 변환하기 위해 만들어졌으나, HTML이나 웹에만 국한되진 않고 다양하게 사용가능합니다.기존 CI/CD에서도 FTL 템플릿에 JSON 값을 배치하고 나면, 텍스트 출력으로 properties.xml 이라는 파일이 만들어지는 구조였습니다. 이러한 로직을 빌드 시점에 사용하기 위해서 maven plugin으로 만들어놓은 상태였죠. 아쉽게도 maven에 대한 종속성이 생겨 gradle로 이관하기 쉽지 않은 상태였습니다.*MVC 패턴 - 하나의 애플리케이션를 구성할 때 Model, View, Controller 세가지 역할로 구분한 패턴. *Maven - pom.xml 기반으로 작성하는 Java 빌드 자동화 도구.*Gradle - Groovy/Kotlin DSL로 작성하는 Java 빌드 자동화 도구개편 방향VM Blue-Green 전환 프로젝트는 기존 문제점을 개선하기 위해 CI/CD를 선언적 방식으로 개편하였습니다.Git repository를 활용해 Property 관리Container Image을 활용한 Artifact 버전 관리Blue-Green 배포로 Production 환경에서 배포 테스트 수행 후, 실 트래픽을 받도록 전환Volume mount를 활용해 Property 주입을 배포 시점으로 변경이를 위해서 아래처럼 Harbor, AWX, Envoy, Docker compose와 같은 기술 스택이 추가되었습니다. 이러한 CI/CD 툴 변경은 인포테이먼트CCS개발팀에서 담당해주셨습니다. 그림 3. 신규 CCS 1.0 CI/CD*Blue-Green 배포 - 기존 버전인 Blue container에서 신규 버전인 Green container로 트래픽을 전환하는 무중단 배포 방식*Harbor - Container image를 저장하는 저장소 기능을 하는 오픈소스 프로젝트*AWX - Ansible 프로젝트 관리를 위한 웹 기반 사용자 인터페이스, REST API 및 Task 엔진 제공하는 툴. Ansible은 Python을 활용해 인프라를 코드로 작성하는 IT 자동화 플랫폼*Envoy - Lyft에서 c++로 개발한 Proxy. Side car로 배포되어 Application 간 트래픽이 Envoy를 거치게 해 트래픽 조정 및 Observability 확보에 유용하다.Volume mount를 통한 Property 주입컨테이너 환경으로 전환하면서 Docker compose로 편리하게 컨테이너 안에 필요한 파일을 주입할 수 있게 되었습니다. 외장 Tomcat + Spring war 조합을 사용하고 있었기에, 아래 경로에 resource 파일을 위치시키면 서버에서 필요한 파일을 불러올 수도 있었죠./usr/local/tomcat/webapps/MY_SERVER/WEB-INF/classes따라서 docker-compose.yaml 에서 다음처럼 기입하면 컨테이너 내에 properties.xml 파일을 위치시킬 수 있습니다. CICD 파이프라인을 잘만 구성한다면 Dev / Staging / Production에 따라 알맞는 property 파일을 주입할 수 있습니다.version: '3.8'services: my-app-blue: image: ${DOCKER_REGISTRY}/${DOCKER_APP_NAME}:${DOCKER_APP_VERSION} container_name: ${DOCKER_APP_NAME}-blue restart: always volumes: - /path/host/properties.xml:/usr/local/tomcat/webapps/MY_SERVER/WEB-INF/classes/properties.xml로컬 개발도 편리하도록 개선하기하지만 문제되는 것은 로컬 개발 환경입니다. 보통은 IntelliJ IDEA 같은 개발 툴을 사용할텐데, 매번 로컬 컴퓨터에 있는 Tomcat에 properties.xml을 옮기는 것은 여간 귀찮은게 아닙니다. 특히나 환경이 바뀐다면 일일이 주석을 바꿔야하는 불편함이 있었습니다.그림 4. Property 주입을 위한 properties.xml물론 소스 코드 내부에 환경별로 Property 파일을 만들 수도 있습니다. 그치만 값을 수정하고 배포하려면 Jenkins 부터 AWX 까지 전체 CICD 파이프라인을 실행해야해, 간단한 변경사항임에도 시간이
docker
java
spring
하이퍼커넥트
Spring Transactional Rollback Deep Dive
안녕하세요. Azar API Dev Team의 Ledger입니다. 이번 글에서는 Spring Transactional 동작에서 Checked Exception과 Unchecked Exception의 롤백(rollback) 처리에 관한 내용을 다뤄보겠습니다. 여러 사례를 통해 예외 처리 코드를 작성해 보고, 자주 혼동되는 부분들을 정리해 보았습니다.트랜잭션 범위 내에서 예외가 발생하면 롤백 되는건 익히 알고 있지만, 예외 처리를 해도 롤백 될 때가 있습니다. 정확히 언제 롤백이 될까요? 보통 Unchecked Exception과 Checked Exception 관련된 내용을 위주로 떠올리지만, 앞으로 나올 문제들을 모두 해결하려면 트랜잭션 프록시의 세부 동작이나 트랜잭션과 스레드의 상관관계와 같은 더 많은 내용을 이해하고 있어야 합니다.먼저 Unchecked Exception과 롤백 마킹에 대해서 간단히 살펴보겠습니다.Spring에서는 트랜잭션 진행 중 예외가 발생할 경우 rollbackOn에서 Unchecked 인지 체크합니다. Unchecked일 경우 processRollback 부분에서 각 기본 설정값의 영향으로 참여 중인 트랜잭션을 로 마킹합니다. 의도를 이해해 보자면 일부 트랜잭션이 실패할 경우, 전체 트랜잭션을 롤백 하는 것입니다. Checked Exception은 예상된 예외로 이를 처리하도록 의도된 것이고, Unchecked Exception은 예상치 못한 예외로 발생 시 롤백을 시도합니다.롤백 마킹에 대한 설정은 Spring 의 설정을 보면 확인할 수 있고, default 설정은 Unchecked Exception인 RuntimeException과 Error입니다.그렇다면 Unchecked Exception은 try catch로 잡아도 무조건 롤백이 될까요? 그렇지 않습니다. 이걸 이해하려면 롤백이 마킹된다는 개념을 이해하고 있어야 합니다. 이어서 아래 문제들을 통해 확인해 보겠습니다. 아래 문제들은 @Transactional 메소드를 제외하고 별도로 설정된 Transaction Advice는 없다고 가정합니다.같은 서비스 내에서 @Transactional 호출 시 동작문제 1. eatPizza 메소드 내의 pizza가 호출되면 새로운 트랜잭션이 열릴까요?정답은 X입니다. 이유는 스프링 어노테이션은 Spring AOP 기반으로 동작하는데 동일한 클래스 내에서 이 적용된 내부 메서드를 호출하는 경우, 호출되는 메서드는 프록시 객체를 거치지 않고 직접 호출되기 때문에 프록시(TransactionInterceptor)가 동작하지 않습니다.위 트랜잭션을 실행시키고 싶다면 pizza를 별도의 서비스로 분리하거나 트랜잭션 템플릿을 사용해 직접 트랜잭션을 열고 닫게 구현하면 됩니다. 아래 그림 1은 프록시 호출 구조에 대해 간단히 정리합니다.그림 1에서 프록시 동작을 코드로 간단히 표현하면 아래와 같습니다.위의 방법 대신 AspectJ를 활용할 수도 있지만, 본문에서는 Spring AOP 사용 사례에 대해서만 다룹니다. 이어서 아래 문
java
kotlin
spring