분류 전체보기 (236) 썸네일형 리스트형 스프링 스케줄러(@Scheduled) 사용 시 주의사항 1. 여러 스케줄링 작업이 있을 때 싱글 스레드로 인한 문제* 참고: https://olsohee.tistory.com/239 스프링은 스케줄링 작업을 위한 TaskScheduler라는 인터페이스를 제공하고, 구현체로는 다음 두가지가 사용된다.가상 스레드가 활성화된 경우(Java 21 이상 및 spring.threads.virtual.enabled가 true로 설정된 경우), SimpleAsyncTaskScheduler가상 스레드가 활성화되지 않은 경우, ThreadPoolTaskScheduler그리고 ThreadPoolTaskScheduler는 기본적으로 하나의 스레드를 사용하며, spring.task.scheduling을 통해 설정 값을 변경할 수 있다. If virtual threads are en.. 레디스에서 다중 명령에 대한 원자성을 보장하는 방법 레디스는 싱글 스레드로 동작하므로 동시성 제어를 위한 복잡한 설계와 오버헤드가 적다. 그러나 싱글 스레드는 parallel 할 수 없는 것이지 concurrent 할 수 있다. 즉, 여러 레디스 클라이언트가 있고, 각 클라이언트가 여러 개의 명령을 한 번에 보낸다면, 레디스의 싱글 스레드는 여러 클라이언트들의 명령을 번갈아 하나씩 실행하게 되며 동시성 문제가 발생할 수 있다. 이를 방지하기 위해 크게 Redis Transaction과 Lua Script 2가지를 사용할 수 있다.Redis Transaction트랜잭션은 주로 관계형 데이터베이스에서 많이 쓰이는 용어인데, 레디스에서도 트랜잭션을 사용할 수 있다. 레디스에서 트랜잭션을 사용하면 여러 개의 커맨드에 대해 원자성이 보장된다. 따라서 concurr.. 게시글 목록 조회 시 좋아요 수를 보여주는 구현 전략 0. 개요이 글은 프로젝트를 진행하며 게시글 목록 조회 시 좋아요 수를 함께 반환해야 하는 상황에서 어떤식으로 구현했는지 기록한 글이다.1. 문제 상황프로젝트에서 게시글 목록 조회 시 좋아요 수를 함께 반환해야 했다. 따라서 게시글과 연관된 좋아요 테이블을 함께 조회하면서 n+1 문제가 발생했다. 즉, 게시글 n개를 조회할 때 실행되는 쿼리는 다음과 같다.post 테이블에 쿼리 1개(post n개 조회)likes 테이블에 쿼리 n개 또한 좋아요 수를 기준으로 정렬 조회할 경우 다음과 같이 JPQL을 작성해줘야 하는데, 게시글 테이블과 좋아요 테이블의 모든 데이터 간 조인, 그룹화, 정렬이 발생한다. 즉, 게시글과 좋아요가 많아질수록 성능이 매우 저하될 것으로 예상된다.2. 해결 방안2-1. 반정규화와 동.. 반정규화를 통한 조회 성능 개선 프로젝트에서 게시글 페이징 조회 시 게시글 데이터 뿐만 아니라 게시글의 좋아요, 댓글, 북마크 수를 함께 반환해야 했다. 따라서 게시글과 연관된 좋아요/댓글/북마크 엔티티를 함께 조회하면서 N+1 문제가 발생했다. N+1 문제를 해결한 과정은 다음과 같다.1. 페치 조인가장 대표적인 N+1 문제 해결 방안으로 패치 조인이 있다. 그러나 일대다, 다대다 관계인 컬렉션 페치 조인은 주의할 점이 있다. 바로 offset, limit 등의 키워드를 통한 페이징 처리가 DB에서 이뤄지지 않고, 조인 결과 전체가 메모리로 로드되고 애플리케이션 단에서 페이징 처리가 이뤄진다는 점이다. 그 이유는, 컬렉션 페치 조인 시 데이터 수가 의도치 않게 증가하게 되기 때문이다. 예를 들어, 게시글 1에 좋아요가 2개, 게시글 .. 자바의 동기화 메커니즘(volatile, synchronized, Lock(ReentrantLock), Atomic/CAS, 동기화 컬렉션) volatile멀티스레드 환경에서 한 스레드가 변경한 값을 다른 스레드가 제대로 볼 수 있는지에 대한 문제를 메모리 가시성이라고 한다. 즉, 메모리에 변경한 값이 보이는가, 보이지 않는가의 문제이다. 메모리 가시성 문제는 캐시 메모리로 인해 발생한다. CPU 입장에서 메인 메모리는 거리도 멀고 속도도 상대적으로 느리다. CPU 연산은 매우 빠르기 때문에 CPU 연산의 빠른 성능을 따라가려면, CPU와 가까이 있으며 매우 빠른 메모리가 필요하다. 이것이 캐시 메모리이다. 캐시 메모리는 메인 메모리보다 CPU와 가까이 있으면서 속도도 더 빠르다. 현대의 대부분의 CPU는 각 코어마다 캐시 메모리를 갖는다. (참고로 여러 코어가 공유하는 캐시 메모리도 있다.) 예를 들어, 다음 그림처럼 main 스레드가 CP.. 자바에서의 모니터(synchronized, wait() & notify(), Condition)와 생산자-소비자 문제 동기화여러 스레드가 동시에 공유 자원에 접근할 때, 접근 순서에 따라 결과 값이 달라지는 현상을 경쟁 상태(race condition)이라 한다. 이런 문제를 방지하고 데이터의 일관성과 무결성을 보장하기 위해 각 스레드가 공유 자원에 접근할 때 동시에 접근하지 못하도록 접근 순서를 제어하는 것을 동기화라고 한다. 그리고 이때 데이터 일관성을 보장하기 위해 하나의 프로세스만 접근해야 하는 영역을 임계 영역(critical section)이라 한다. 따라서 동기화는 경쟁 상태를 방지하고 여러 스레드가 임계 영역에 안전하게 접근할 수 있도록 실행 순서를 조정하는 것이다. 대표적인 동기화 기법으로 뮤텍스, 세마포어, 모니터가 있다.뮤텍스(Mutex)뮤텍스는 임계 영역에 하나의 스레드만 접근하도록 한다. 그리고 .. @Async, @Scheduled의 스레드에 대해 비동기 작업을 위한 스레드스프링은 비동기 작업을 위한 TaskExecutor라는 인터페이스를 제공한다. 스프링의 TaskExecutor 인터페이스는 자바의 Executor 인터페이스와 동일하다. 그리고 스프링이 제공하는 TaskExecutor의 구현체는 다음과 같다.SyncTaskExecutorSimpleAsyncTaskExecutorConcurrentTaskExecutorThreadPoolTaskExecutorDefaultManagedTaskExecutor...@EnableAsync의 JavaDoc을 살펴보면 다음과 같이 설명되어 있다.By default, Spring will be searching for an associated thread pool definition:* either a uniqu.. ExecutorService의 스레드 풀 관리 ExecutorService의 스레드 풀 관리ExecutorService의 기본 구현체인 ThreadPoolExecutor의 생성자는 다음 속성들을 사용한다.corePoolSize: 스레드 풀에서 관리되는 기본 스레드 수maximumPoolSize: 스레드 풀에서 관리되는 최대 스레드 수keepAliveTime, TimeUnit unit: 기본 스레드 수를 초과해서 만들어진 초과 스레드가 생존할 수 있는 대기 시간, 이 시간 동안 처리하는 작업이 없으면 초과 스레드는 제거된다.BlockingQueue workQueue: 작업을 보관할 블로킹 큐corePoolSize와 maximumPoolSize의 차이를 알아보기 위해 다음 예제를 살펴보자. printState() 메서드는 스레드 풀 관련 정보를 확인하기.. 이전 1 2 3 4 5 6 ··· 30 다음