환경 :
    기존 : Local 에서 Spring Boot 2.5.4  Spring Security 사용 Redis로 세션관리
    신규 : Local 에서 Spring Boot 3.2.5  Spring Security 사용 Redis로 세션관리

1. 로컬에서 웹 기동시 Redis deserialize  오류 발생
2. 오류 발생 이유는 Spring Security는 다른 버전간에 직렬화가 되지 않는다고 합니다. 
3. 이전 시큐리티에서 생성된 Redis에 등록된 정보를 신규 버전에서 deserialize  를 못하면서 생기는 문제.
4. 기존 프로젝트로 사용해야 하고 신규 프로젝트도 사용 해야 함
5. 기존 프로젝트는  Redis database는 0번 사용 신규 프로젝트는   Redis database는 1번사용으로 설정 변경

org.springframework.data.redis.serializer.SerializationException: Cannot deserialize  
 org.springframework.data.redis.serializer.JdkSerializationRedisSerializer.deserialize(JdkSerializationRedisSerializer.java:108)

참고: https://github.com/spring-projects/spring-boot/issues/38959

반응형

1. CompletableFuture.supplyAsync 사용하여 동기 처럼 사용 도전(결과 완료를 확인하고 진행)
2. 난 공통 스레드풀을 많들어 사용 예정이다. 그래서 공통 쓰레드풀 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
 
@EnableAsync
@Configuration
public class AsyncConfig extends AsyncConfigurerSupport {
 
 
    @Bean("threadPoolTaskExecutorA")
    public Executor threadPoolTaskExecutorMember() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
 
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(5);
        executor.setQueueCapacity(99999);
        executor.setThreadNamePrefix("a-thread-");
        return executor;
    }
 
    @Bean("threadPoolTaskExecutorB")
    public Executor threadPoolTaskExecutorBill() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
 
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(99999);
        executor.setThreadNamePrefix("b-thread-");
        return executor;
    }
 
}
cs


3. 스레드로 메서드 실행 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private final Executor threadPoolTaskExecutorA;
private final Executor threadPoolTaskExecutorB;
 
// 스레드 처리 요청목록(ThreadVO: 메서드의 리턴타입)
List<CompletableFuture<ThreadVO>> futures = new ArrayList<>();    
 
// 스레드 메서드 실행 처리
CompletableFuture<ThreadVO> future = CompletableFuture.supplyAsync(() ->
                                this.insertAAAAAProc(excelRows, custPaymentsServiceFlag, custInfo, isAutoMemNoMode, custUniqNo
                                        , custUsrUniqNo, usrId, isAllMember, rowIdxf, excelProgressCount, excelProcessId)
                        , threadPoolTaskExecutorA);
                futures.add(future);    
 
// 스레드 메소드 실행결과 
// allOf, join() 을 하면 스레드가 결과가 모두 콜백 될때까지 기다림.
List<ThreadVO> result = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
                    .thenApply(v -> futures.stream()
                            .map(CompletableFuture::join)
                            .collect(Collectors.toList()))
                    .join();                    
cs

 

4. 이렇게 진행을 했는데. 음. 공통 스레드를 사용하다 보니 스레드가 처리를 못하면 뒤에 들어온 업무는 큐에 계속 쌓이고
    이미 큐에 많이 있는 경우 신규 등록 시 너무 오래 기다림 ㅠㅠ

5. 공통 스레드를 사용하지 않고 등록이 들어오면 스레드를 신규 생성하고 끝나면 지우는 걸로 변경

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 큐가 쌓이는 곳
BlockingQueue<Runnable> blockingQueue = new LinkedBlockingQueue<>();
// 스레드 풀 생성
threadPoolExecutor = new ThreadPoolExecutor(333, TimeUnit.SECONDS, blockingQueue);
 
// 스레드 처리 요청목록(ThreadVO: 메서드의 리턴타입)
List<CompletableFuture<ThreadVO>> futures = new ArrayList<>();    
 
// 스레드 메서드 실행 처리
// 끝에 새로 생긴 스레드풀에 하라고 설정
CompletableFuture<ThreadVO> future = CompletableFuture.supplyAsync(() ->
                                this.insertAAAAAProc(excelRows, custPaymentsServiceFlag, custInfo, isAutoMemNoMode, custUniqNo
                                        , custUsrUniqNo, usrId, isAllMember, rowIdxf, excelProgressCount, excelProcessId)
                        , threadPoolExecutor);
futures.add(future);    
 
// 스레드 메소드 실행결과 
// allOf, join() 을 하면 스레드가 모무 끝날 때까지 기다림.
List<ThreadVO> result = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
                    .thenApply(v -> futures.stream()
                            .map(CompletableFuture::join)
                            .collect(Collectors.toList()))
                    .join();    
 
// 스레드풀 정리
threadPoolExecutor.shutdown();
cs

맞는건지 모르겠으나... 모 이렇게.....
스레드 생성시 많은 비용이 든다고 하는데 모름(무시, 모르는척?)!

JAVA 21에서 Virtual thread 라는 좋은 기능이 들어 왔다고 합니다.
전 21버전이 아니라. ㅜㅜ 

https://devel-repository.tistory.com/71

 

spring boot 가상 스레드 적용해보기

JDK 21부터 가상 스레드(virtual thread)가 정식 릴리즈 되었다. 또한 spring boot 3.2부터는 가상 스레드가 지원되어 spring boot 애플리케이션에서 가상 스레드를 시험해 볼 수 있게 되었다. 이번 포스팅에

devel-repository.tistory.com

https://techblog.woowahan.com/15398/

반응형

1. Redis 서버는 있다고 가정.
2.  build.gradle 에 의존성 추가.

1
2
// redis 접속
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
cs

3. application.yml Redis 정보 설정 
     - 현재 단독 구성
     - sentinel, cluster로도 구성 가능

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
spring:
  # Redis
  redis:
    database: 0
  # 단독구성 접속설정  
    host: 127.0.0.1
    password: 
    port: 6379
  # sentinel구성 접속설정
#    sentinel: 
#      master: springboot
#      nodes:
#        - 127.0.0.1:16379
#        - 127.0.0.1:16380
#        - 127.0.0.1:16381
  # cluster구성 접속설정
    cluster:
      nodes: #
#        - 10.123.1.88:16400
#        - 10.123.1.88:16401
#        - 10.123.1.88:16402
#    lettuce:
#      pool:
#        max-active: 8 #Maximum number of connections
#        max-idle: 8 #Maximum Idle Connection
#        min-idle: 0 #Minimum idle connection
      #shutdown-timeout: 200ms
cs

4. RedisConfig  설정. ㅁㄴㅇㄹ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@Configuration
@EnableRedisRepositories
@RequiredArgsConstructor
public class RedisConfig {
 
    @Value("${spring.redis.host}")
    private String redisHost;
 
    @Value("${spring.redis.port}")
    private int redisPort;
 
    @Value("${app-config.config.key-profile}")
    private String keyProfile;
 
    @Value("${spring.redis.cluster.nodes}")
    @Null
    private List<String> clusterNodes;
 
    /** Redis 접속 */
    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        // cluster 사용인 경우
        if( keyProfile.equals("clusterNodes")) {
            RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(clusterNodes);
            return new LettuceConnectionFactory(redisClusterConfiguration);
        } else {
            // 
            return new LettuceConnectionFactory(redisHost, redisPort);
        }
    }
 
    /** redisTemplate */
    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
 
        return redisTemplate;
    }
 
}
cs


5. Redis 사용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 
private final RedisTemplate<String, Object> redisTemplate;
 
// 데이터 저장 (Expire 설정)
ValueOperations<String, Object> values = redisTemplate.opsForValue();
values.set(key, value, duration);
 
// 데이터 저장 (Expire 미설정)
ValueOperations<String, Object> values = redisTemplate.opsForValue();
values.set(key, value);
 
// 데이터 조회
ValueOperations<String, Object> values = redisTemplate.opsForValue();
if (values.get(key) == null) {
    값이 없음
}
 
// 데이터 삭제
redisTemplate.delete(key);
 
// Expire 시간 재설정
redisTemplate.expire(key, timeout, TimeUnit.MILLISECONDS);
cs

끝!!! ^_^

 

 

 

 

 

 

 

 

 

 

 

 

반응형

+ Recent posts