본문 바로가기

전체 글

(38)
[Spring Boot] 트랜잭션 롤백과 전파 속성 은행 앱에서 A가 B에게 10만 원을 송금하는 상황을 상상해 봅시다. 서버는 두 가지 쿼리를 실행합니다.1. A의 통장에서 10만 원 차감 (UPDATE)2. B의 통장에 10만 원 증가 (UPDATE)그런데 1번 쿼리가 성공한 직후, 갑자기 데이터베이스 서버의 전원이 나갔습니다! A의 돈은 10만 원이 증발했는데, B는 돈을 받지 못했습니다. 뉴스에 대서특필될 만한 엄청난 사고입니다. 이런 대형 사고를 막기 위해 데이터베이스는 "1번과 2번 쿼리를 하나로 묶어라. 둘 다 성공할 때만 최종 반영(Commit)하고, 하나라도 실패하면 1번 쿼리도 아예 없었던 일로 롤백(Rollback) 시켜라!"라는 논리적 작업 단위를 제공하는데, 이것이 바로 트랜잭션(Transaction)입니다. 스프링 부트(Sprin..
[Spring Boot] OAuth 2.0 소셜 로그인 구현(카카오 네이버 구글 로그인) 인터넷 쇼핑몰이나 새로운 서비스에 접속했을 때, 여러분은 긴 회원가입 폼을 성실하게 채우시나요, 아니면 "카카오로 1초 만에 시작하기" 버튼을 누르시나요? 바쁘고 귀찮은 것을 극도로 싫어하는 현대의 유저들에게 자사몰의 독자적인 회원가입(ID/PW)을 강요하는 것은 곧 '고객 이탈'을 의미합니다. 이러한 이탈을 막기 위해 구글, 카카오, 네이버 같은 거대 IT 기업들이 유저의 신원을 대신 확인해 주고 우리 서버에 "이 사람 진짜 맞아!"라고 보증을 서주는 기술이 등장했습니다.바로 OAuth 2.0 (Open Authorization) 프로토콜입니다. 그리고 스프링 부트(Spring Boot) 진영에는 이 복잡한 프로토콜 통신을 아주 우아하게 캡슐화해 놓은 spring-boot-starter-oauth2-c..
[Spring Boot] Spring Security - JSON Web Token 구현 앞선 에서 우리는 스프링 시큐리티(Spring Security)의 위대한 필터 체인(Filter Chain)과 전통적인 폼 로그인(Session/Cookie 방식)을 마스터했습니다. 세션 기반 로그인은 보안성이 높고 구현이 편하지만, 현대의 트렌드인 '모바일 앱(iOS/Android) 통신'과 서버 수십 대를 띄우는 '마이크로서비스(MSA) 스케일 아웃' 환경을 만나면 치명적인 약점을 드러냅니다. 사용자가 서버 A에 로그인하여 세션을 만들었는데, 다음 요청이 서버 B로 향하면 서버 B는 "너 누구야?" 라며 로그아웃 시켜버리기 때문입니다(세션 불일치).이 골치 아픈 '상태 유지(Stateful)'의 사슬을 끊어내고, 서버가 사용자 정보를 기억할 필요 없이 "네가 가진 암호화된 방문증(Token)만 보여주..
[Jenkins] Timeout의 파이프라인 무한 루프 방어 "어? 어제 퇴근할 때 걸어놓은 배포가 오늘 아침까지 안 끝나고 계속 돌아가고 있네?" CI/CD 인프라를 운영하다 보면 누구나 한 번쯤 마주치게 되는 소름 돋는 상황입니다. 쉘 스크립트 안에 잘못 작성된 while(true) 무한 루프 버그, 혹은 외부 API 서버가 죽어서 응답을 주지 않아 무한 대기(Hang)에 빠지는 경우 등 원인은 다양합니다. 문제는 이렇게 '에러를 뿜으며 실패(Failure)하지도 않고, 그렇다고 성공(Success)하지도 않은 채 영원히 멈춰있는 좀비(Zombie) 빌드'들이 젠킨스의 가장 큰 적이라는 점입니다. 이번 글에서는 소중한 젠킨스의 워커(Worker) 자원을 갉아먹는 좀비 빌드들을 제거하는 'Timeout(타임아웃) 제어를 통한 파이프라인 무한 대기 방어 기술'에 ..
[Jenkins] Maven Gradle 빌드 캐시 최적화 빌드 시간 10배 단축의 비밀 "코드는 고작 한 줄 수정했는데, 젠킨스 빌드 시간은 무려 15분이나 걸려?"자바(Java/Spring Boot) 프로젝트나 Node.js 프로젝트의 파이프라인을 운영하다 보면 가장 많이 듣게 되는 불만 중 하나입니다. 코드를 컴파일하고 테스트하는 데 걸리는 시간은 1분도 안 되지만, 스프링 프레임워크와 수많은 서드파티 라이브러리(.jar 파일들)를 Maven Central이나 원격 저장소에서 다운로드하는 데 14분이 걸리기 때문입니다. 특히 앞서 우리가 칭송했던 'Docker Agent(1회용 멸균 빌드 환경)'를 사용할 경우, 이 문제는 최악의 형태로 발현됩니다. 컨테이너가 뜰 때마다 백지상태이므로 매 빌드마다 수백 메가바이트의 라이브러리를 인터넷에서 새로 받아와야 하니까요. 이번 글에서는 인프라 병..
[Spring Boot] Redis 캐싱(Caching)을 이용하여 응답 속도 단축하기 스타트업이 처음 런칭했을 때는 유저가 적어 데이터베이스(RDB) 하나만으로도 충분히 서비스가 잘 돌아갑니다. 하지만 마케팅이 대박 나서 '초당 1만 건'의 요청이 쏟아지기 시작하면 상황은 달라집니다. 여러분이 앞선 에서 HikariCP 커넥션 풀을 아무리 완벽하게 튜닝해 놓았더라도, 물리적인 디스크(Disk)를 긁어서 데이터를 읽어오는 관계형 데이터베이스(MySQL, Oracle)는 태생적으로 속도의 한계가 있습니다. 특히 '쇼핑몰 메인 페이지의 배너 이미지 목록'이나 '오늘의 인기 검색어'처럼 수많은 유저가 똑같이 조회하지만, 데이터는 하루에 한두 번만 변하는 정보를 매번 느린 디스크 DB까지 내려가서 읽어오는 것은 엄청난 리소스 낭비입니다.이를 해결하기 위해 백엔드 진영이 도입한 궁극의 마법, "디스..
[Spring Boot] QueryDSL 입문 / 타입 세이프(Type safe) 동적 쿼리 Spring Data JPA의 Query Method와 @Query는 훌륭했지만, 실무의 거친 요구사항을 만나면 한계가 명확하게 드러납니다. 쇼핑몰의 상품 검색창을 생각해 봅시다. 사용자는 '상품명'만 검색할 수도 있고, '가격 범위'만 필터링할 수도 있으며, '카테고리'와 '브랜드'를 동시에 선택할 수도 있습니다.즉, 조건이 있을 수도 있고 없을 수도 있는 '동적 쿼리(Dynamic Query)'가 필요합니다. 과거 MyBatis 시절에는 XML 파일에 같은 태그를 수십 개 도배하여 쿼리 문자열(String)을 조립했습니다. JPA @Query에서 문자열로 동적 쿼리를 짜다 보면 띄어쓰기 하나 잘못해서 서버가 켜진 뒤 고객이 검색 버튼을 누르는 순간 에러가 터집니다(런타임 에러). 자바 코드로 쿼리..
[Spring Boot] Spring Data JPA 쿼리메서드(QueryMethod)로 검색과 페이징을 구현하기 과거 JPA(Hibernate)만 순수하게 쓰던 시절에는 개발자가 직접 EntityManager를 불러와서 em.persist(), em.find() 같은 코드를 짰습니다. 이 정도만 해도 SQL을 안 짜서 행복했지만, 스프링 진영은 여기서 만족하지 않았습니다. "아니, 저장하고 찾고 삭제하는 CRUD 코드는 전 세계 모든 프로젝트가 다 똑같은데, 개발자가 왜 굳이 그 코드를 또 짜야 해? 우리가 다 만들어 줄게!"라는 발상에서 만들어진것이 바로 Spring Data JPA입니다. 이제 우리는 그저 JpaRepository라는 인터페이스 하나를 상속받는 것만으로 수십 개의 기본 쿼리 기능이 하늘에서 뚝 떨어지는 기적을 맛봅니다. 하지만 진짜 마법은 지금부터입니다. 만약 "나이가 20살 이상이고 이름이 '..
[Jenkins] Jenkins 백업 스크립트 복구 데브옵스(DevOps) 엔지니어의 가장 큰 덕목은 배포 속도를 빠르게 만드는 것도 중요하지만, '최악의 장애 상황에서도 인프라를 신속하게 복구(Disaster Recovery)해 내는 것'입니다. 수십 개의 프로젝트 파이프라인과 플러그인, 계정 정보, 복잡한 인증키(Credentials)들이 세팅된 젠킨스 서버의 하드디스크가 어느 날 갑자기 물리적 장애로 뻗어버린다면 어떻게 될까요? 백업이 없다면 전사의 배포 프로세스는 수일 동안 올스톱되며 당신은 시말서를 피할 수 없을 것입니다.1. 무엇을 백업하고, 무엇을 버릴 것인가? (용량 최적화)초보 인프라 관리자들은 "백업? 그냥 /var/jenkins_home 디렉토리 전체를 통째로 압축해서 보관하면 되잖아?"라고 생각합니다. 이는 매우 무식하고 위험한 발상..
[Jenkins] 쿠버네티스(KubernetesK8s) 완벽 연동 무중단 배포 자동화 앞선 를 통해 애플리케이션 코드를 아름다운 도커 이미지(Docker Image)로 굽고 레지스트리에 푸시(Push)하는 것까지 성공하셨습니다. 이제 남은 과제는 단 하나, "이 이미지를 실서비스가 돌아가고 있는 운영 서버들에 띄워서 고객들에게 선보이는 것"입니다.현대의 대규모 인프라에서는 이 서버들을 지휘하기 위해 Kubernetes(쿠버네티스, 이하 K8s)라는 막강한 오케스트레이션 툴을 사용합니다. 젠킨스가 빌드마스터라면, K8s는 함대 사령관입니다. 이번에는 젠킨스가 원격 K8s 클러스터에 접속하여 새로운 버전의 이미지를 무중단(Rolling Update)으로 교체하라고 명령을 내리는 완벽한 배포 연동 전략에 대하여 다뤄보겠습니다.1. Kubeconfig 보안과 원격 접속 인증우리가 터미널에서 ku..