분류 전체보기

개요기존의 Spring Batch를 통해 음료 데이터를 초기화하기 위해서 AWS Lambda에 Python 코드(Crawling + OCR)를 활용하여 수동 트리거 로직을 구현했었다. 그러던 중 클라우드 비용을 최소화하고 짧은 피드백 루프(개선속도를 높이기 위해)를 위해 로컬 Python 서버에서 크롤링과 OCR 로직을 수정하며 사용하고 있었다. 하지만, 개선작업이 끝난 이후 한 가지 실수를 하게되었는데 Spring Batch에 사용되는 URL을 localhost 주소로 기입하여 Batch가 Connection refused: localhost:8000 에러를 발생시키게 되었다. 이러한 경험을 계기로 Spring Batch의 기본 동작 흐름에 대해 톺아보려고한다.Batch의 동작흐름Spring Batch..
· Project
개요정상적으로 동작하던 배포 파이프라인에 난데 없이 마주치게 된 에러 문구 에러의 내용은 현재 VM 머신의 디스크에 공간이 부족하다는 에러였다. 이게 무슨소리지??? 싶어 VM 인스턴스에 접속하여 현재 디스크 상태를 확인했다. 그런데 맙소사 현재 10GB짜리 머신에서 99%가량의 디스크 공간을 Docker가 사용하는 것을 확인할 수 있었다.이를 개선하는 짧은 기술 챌린지를 가져보고자 한다.현재현재 아맞당의 배포 파이프라인은 다음과 같은 구조를 가지고 있다.Gihub Action을 통해 운영 브랜치인 main에 코드가 병합되는 순간을 기점으로 파이프라인이 동작파이프라인에선 제일 먼저 Ubuntu, Docker, Gradle을 build하는데 필요한 정보들을 환경변수로 받고 이를 바탕으로 배포를 준비gr..
탄생 배경Redis는 메모리 기반의 캐시저장소로, Spring에서는 Spring Cache를 도입해서 읽기 작업의 성능을 높이는 작업을 수행할 수 있다. 하지만 메모리라는 한정된 자원에서 데이터가 계속해서 쌓이다 보면 Redis는 새로운 데이터를 저장하기 위해 기존 데이터를 삭제해야 하는 문제에 봉착하게 된다. 아니면 애플리케이션 성능에 문제를 일으킬 수도 있다.Redis의 메모리 관리 방법Redis는 RAM의 용량보다 더 많은 데이터를 저장하게 되는 경우 Swap이 발생하며 Redis의 성능 저하를 일으킬 수 있다. 물리 메모리의 용량보다 더 많은 데이터가 들어오면 swap이 발생한다. 운영체제에서 Swap space의 주요 기능은 물리메모리(RAM)의 양이 가득 차고 더 많은 메모리의 양이 필요할 때..
· JVM
1. Serial GC단일 스레드로 동작하며 모든 애플리케이션 스레드를 중단(stop-the-world) 한 스레드가 메모리를 정리주로 메모리가 작거나 단일 코어 환경에서 사용한다.2. Parallel GC여러 개의 GC 스레드를 통해 stop-the-world 를 빠르게 처리오래된 Java(8 이하)에서 기본 GC로 많이 쓰였으며, 현재도 고성능 환경에서 선호될 수 있음3. CMS(Concurrent Mark-Sweep)애플리케이션과 병렬적으로 안쓰는 메모리를 수거했다.Java 8버전에서 주로 사용했으며 이후 Java 9부터는 G1 버전 사용CMS의 단편화 이슈CMS는 힙(old)을 Mark & Sweep 알고리즘 방식으로만 회수하기 때문에 사용이 끝난 객체 영역을 연속적으로 압축하진 못한다.그 결과 ..
만약 서비스를 운영중인데 사용자가 계속해서 증가한다면? 우리는 당연하게도 서버 증설을 고민할 수 밖에 없을 것이다. 요지는 사용자가 점점 늘어남에 따라 트래픽이 몰리게 된다면 서버를 어떤 식으로 확장 해야할까? 아마 제일 먼저 생각나는 단어가 Scale-Up 과 Scale-Out 일 것이다.물리적으로 생각해도 사용자가 늘어난다면 그만큼 서버의 크기 또한 늘려야한다.Scale-Up? 수직적 확장을 의미하며, 말 그대로 추가적인 RAM, CPU 등을 컴퓨터에 달아 업그레이드 하는 방식이다.현재 서버의 성능을 향상하기위해 자원을 증가시키는 방법이다. 하지만 계속해서 추가적인 부품을 달아 해결할 수 없듯이 지속적인 확장이 불가하다. (가능할 수 있지만, 비용적인 지출이 상당해지기에 사실상 불가) 해결책으로는 새..
JPA에서 제공하는 ID(PK)를 생성하는 방법은 두가지가 있다.직접할당자동할당직접할당@Id 어노테이션으로 ID 값을 직접적으로 할당하는 방식자동할당가장 흔하게 사용되는 방식으로 Id @GenratedValue 의 stretagy 옵션을 통해 설정하는 방식이다.여기에는 총 4가지방식이 존재한다.IDENTITY기본 키 생성 방식을 DB의 DBMS에 생성 전략에 위임하는 방법이다. 해당 전략을 사용하면 엔티티를 생성할 때 쓰기 지연이 적용되지 않는다.그 이유로는 JPA에선 엔티티를 영속하기 위해, 고유 식별자가 필요한데, IDENTITY 전략에선 식별자가 DB에 저장되어야 할당되기때문이다.(엔티티 생성시 즉시 INSERT 쿼리 발생)이때 하이버네이트를 사용하는 경우에는 INSERT 쿼리의 결과를 다시 조회하..
예시JPA의 N + 1 문제는 연관 관계가 설정된 엔티티를 조회할 경우에, 조회된 데이터 개수(N)만큼 연관관계의 조회 쿼리가 추가로 발생하는 현상이다. 블로그 게시글과 댓글이 있는 경우, 게시글을 조회한 후 각 게시글마다 댓글을 조회하기 위해 추가 쿼리가 발생한다면 N + 1 문제가 발생한다. 블로그 게시글이 10개라면 총 11개의 쿼리(게시글 조회 1개 + 각 게시글의 댓글 조회 10개)가 실행문제 발생 원인패치 전략을 Eager Loding(즉시로딩) 으로 가져갔을때 발생하는 문제이다. 이중 Data JPA에서 제공하는 findAll 메서드를 수행할 경우 내부적으로는 select e from Entity e 라는JPQL을 생성하는데, JPQL의 특성상 글로벌 패치 전략을 고려하지 않고 쿼리를 수행한..
자바에서 문자열을 다루는 방법으로는 문자열 리터럴을 사용하는 방법과 새로운 객체를 생성하는 방법이 있다. 두 방법에는 문자 데이터를 다루는 방식에서 차이가 있다. 자바는 문자열 리터럴을 String Pool 내에 저장하고 동일한 문자열 리터럴에 대해서는 하나의 참조를 재사용하기 때문인데 예를들어 아래와 같은 코드가 있다고 생각해보자String str1 = "Hello";String str2 = "Hello"; 여기서 str1과 str2는 동일한 문자열 리터럴 "Hello"를 참조한다. 따라서 str1과 str2는 같은 메모리 주소를 가리키게 되기에 참조비교인 == 을 사용할 경우 이는 참이된다. System.out.println(str1 == str2); // true 그렇기에 String Pool에 저..
LEE티씨
'분류 전체보기' 카테고리의 글 목록