logo
logo
백엔드
Spring
Java를 기반으로 한 대표적인 웹 어플리케이션 프레임워크
StackOverflow 질문 수: 213176
Github Stars : ★ 57677
사용 기업
이커머스
기타
소셜/컨텐츠
여행
부동산/인테리어
푸드테크
헬스케어
금융/보험
패션
모빌리티
종합
인공지능
교육
직장
블록체인
techstack-logo
트렌비
techstack-logo
엔라이튼
techstack-logo
식스샵
techstack-logo
드림어스컴퍼니
techstack-logo
당근
techstack-logo
마이리얼트립
techstack-logo
그린랩스
techstack-logo
버킷플레이스
techstack-logo
와디즈
techstack-logo
버즈빌
techstack-logo
마켓컬리
techstack-logo
티몬
techstack-logo
아이디어스
techstack-logo
힐링페이퍼
techstack-logo
오피지지
techstack-logo
카카오페이
techstack-logo
카카오스타일
techstack-logo
위메프
더 보기
기술 블로그 글
여기어때컴퍼니
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
카카오페이
Spring 기반 멀티모듈 프로젝트 환경변수 설정 방법
roy.ce 카카오페이 서버 개발자가 알려주는 Spring 멀티모듈 환경변수 설정 노하우! 멀티모듈 프로젝트의 복잡성을 줄이고 효율적인 환경 설정을 원한다면 꼭 읽어보세요!zeta.wan 멀티모듈을 잘 활용하면 불필요한 설정을 최소화할 수 있다는 것을 느꼈습니다. 글을 읽는 여러분도 더 나은 방식이 무엇일지 고민하는 시간이 되면 좋겠습니다.안녕하세요. 파트너플랫폼파티에서 서버 개발을 하고 있는 그루(Geuru)입니다. 카카오페이에서는 Spring 기반 멀티모듈 프로젝트로 서비스를 개발하고 있습니다. 그 이유는 요구사항이 여러 가지 추가되면서 특정 목적을 위한 애플리케이션이 필요하거나, 도메인의 확장에 따라 모듈을 추가하기 때문입니다. 모듈을 추가함에 따라 각 모듈별로 필요한 환경변수 설정을 위해 yml 또는 properties 파일을 작성하고 있습니다.입사하고 파트너 도메인에 익숙해지기 위해 여러 프로젝트를 리뷰하면서 알게 된 사실이 있습니다. 팀 내 프로젝트마다 환경변수 설정하는 방법이 미묘하게 다르다는 사실입니다. 더 크게는 팀마다 환경변수 설정하는 방법이 다르고, 취향 차이도 있다는 것입니다.이번 글에서는 제가 사내 여러 프로젝트를 경험해 보면서 알게 된 환경변수 설정방법은 어떤 것들이 있는지 소개해보려고 합니다. 먼저 멀티모듈에서의 환경변수 설정 고민을 말씀드리고, 그 고민을 해결할 수 있는 환경변수 설정 방법 4가지를 알려드리려고 합니다. 그래서 최종적으로 저희는 그 4가지 방법 중 어떤 방법을 선택했으며, 그 이유는 무엇인지 말씀드리려고 합니다.이 글을 읽으시는 독자분께서는 각자의 프로젝트의 환경변수 설정 방법과 본 글에서 소개하는 설정방법을 비교해 보면서, 본인은 어떤 방식을 적용하고 있는지 알아보고 싶은 분들께 이 글을 추천합니다. 또, 이것 외에 다른 방법이 있으면 코멘트도 남겨주세요 😀멀티모듈의 정의와 장점멀티모듈 프로젝트는 여러 개의 모듈로 구성된 프로젝트로, 각 모듈은 독립적으로 빌드되고 배포될 수 있습니다. 멀티모듈로 프로젝트를 구성하는 이유는 코드의 재사용성을 높이고, 모듈 간의 의존성을 명확히 하여 유지보수성을 향상하기 위함입니다.예를 들어, 위와 같이 머니 송금 API를 사용하는 internal-api(사내용 API 모듈), external-api(서비스용 API 모듈)가 있다고 가정하겠습니다. 만약 internal-api, external-api가 각각 단일 모듈로 프로젝트를 구성한다면, 각 프로젝트마다 머니송금용 RestTemplate과 HttpClient 코드와 같은 구현체를 두 번이나 작성하게 될 것입니다.같은 코드 작성 두 번 정도야 할 수 있습니다. 유지보수하거나 신규 서비스 개발 시에는 어떨까요? 만약 머니 송금 API를 사용하는 admin-api(운영자용 API 모듈) 같은 애플리케이션이 늘어난다면, 한 번 더 구현체를 작성해야겠죠? 또, API 버전이 V1에서 V2로 변경되는 스펙 변경이 발생한다면 각 프로젝트마다 해당 내용을 반영해야 합니다.아까 말씀드린 상황을 해결하기 위해 멀티모듈로 구성
spring
연관 기술 스택
techstack-logo
Java
techstack-logo
SpringBoot
Copyright © 2025. Codenary All Rights Reserved.