보라코딩

WW31 본문

개발자가 되었다?

WW31

new 보라 2024. 7. 31. 12:21
240729



* MSA에서 DB 정합성 보장 방법!
https://curiousjinan.tistory.com/entry/spring-event-aws-sns-sqs-msa-data-consistency

* zipkin을 사용해서 카프카는 trace Id가 찍히지 않아 고민했는데 아래 글로 해결함..!
https://curiousjinan.tistory.com/entry/spring-msa-zipkin 

* msa 깃프로젝트(인프런강의)
https://github.com/joneconsulting/toy-msa/blob/springboot3.2/README.md

 

 

240730



- MDC(Mapped Diagnostic Context) : Map 형식으로 이용하여 클라이언트 특징적인 데이터를 저장하기 위한 메커니즘. 현재 실행중인 쓰레드에 메타 정보를 넣고 관리하는 공간


- System.out.println()을 로깅에 사용하면 안좋은 이유?
   ㄴ synchronized 키워드 이용해서 구현되어 있기에 다른 스레드 접근하지 못해 성능 낮춤
   ㄴ Blocking I/O 이기에 해당 I/O가 발생하는 동안 CPU가 놀게 되기 때문에 성능 저하
   

- slf4j : logger의 추상체. 다른 로깅 프레임워크의 인터페이스 역할
- logback : Slf4j의 구현체. spring-boot-starter-web 안에 기본적으로 포함
- log4j2 : Slf4j의 구현체. 멀티 쓰레드 환경에서 비동기 로거를 지원하여 멀티 쓰레드 환경에서의 성능이 다른 로거들에 비해 월등히 좋음.

 

 

240731



- 스레드풀 좋은 내용 
https://velog.io/@sihyung92/how-does-springboot-handle-multiple-requests

 


- 도커 포트 8081:8080와 8082:8080와 8083:8080이 가능한 이유
  ㄴ 컨테이너는 자체적으로 독립적인 네트워크 스택을 가지며, 내부적으로 동일한 포트를 사용할 수 있음. 따라서 동일한 서비스가 각기 다른 설정 없이 쉽게 복제되어 실행 가능
  


- docker replica : docker compose 에서 replica 기능 설정 가능
   ㄴ Docker Swarm(도커 클러스터 관리 도구)에서의 로드 밸런서 개념은 요청을 여러 Replica 간에 부하 분산하는 역할
   ㄴ 실제로는 각 Replica가 동시에 실행되고 있으며, 로드 밸런서가 이들을 조율하여 클라이언트의 요청을 고르게 분산
   
   

ex)
version: '3.7'
services:
  web:
    image: nginx:latest
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: "0.5"
          memory: 512M
      restart_policy:
        condition: on-failure
    ports:
      - "80:80"


  
  
- StringBuffer vs StringBuilder
   ㄴ StringBuffer : 스레드 안전. 여러 스레드 동시 접근 시, 모든 메서드에 동기화 적용(한 번에 하나의 스레드만 접근 가능해서 멀티스레드 환경에서 안전). 단, 단일 스레드 환경에서 불필요한 성능 저하
   ㄴ StringBuilder : 스레드 안전 X. 동기화 지원 안해서 멀티스레드 환경에서 안전하지 않으나 동기화 오버헤드가 없기에 단일 스레드 환경에서 성능은 더 빠름
   

 


MDC : 로그 메세지에 추가적인 컨텍스트 정보를 첨부할 수 있는 기능 제공하여 로그 추적성과 유연성 높임 (SLF4J안에 MDC 기능이 포함됨)

ex)
log4j2.xml 내부에서 아래와 같은 코드가 있을 때
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n - RequestId: %X{requestId}</pattern>



내부적으로 MDC가  MDC.put("requestId", "12345"); 이렇게 값을 설정해서 로그 메세지 생성시 내부적으로 MDC.get("requestId")를 호출하여 현재 스레드의 MDC 컨텍스트에서 "requestId" 값을 가져옴

 



- 스프링빈의 싱글톤
https://velog.io/@s2moon98/%EC%8A%A4%ED%94%84%EB%A7%81%EC%9D%98-bean%EA%B3%BC-%EC%8B%B1%EA%B8%80%ED%86%A4%EC%9D%98-%EC%97%B0%EA%B4%80%EA%B4%80%EA%B3%84
ㄴ @Configuration 클래스에 정의된 @Bean 메서드는 스프링 컨테이너에 의해 관리되며, 기본적으로 싱글톤으로 동작
 ㄴ 즉, 스프링 컨테이너는 @Bean 메서드를 호출하여 생성된 객체의 인스턴스를 단 하나만 유지

 

ex.
@Component
public static class Config {

    @Bean
    public SimpleBean simpleBean() {
        return new SimpleBean(); // 매번 새로운 객체를 생성
    }

    @Bean
    public SimpleBeanConsumer simpleBeanConsumer() {
        return new SimpleBeanConsumer(simpleBean());
    }
}

// Configuration 버전
@Configuration
public static class Config {

    @Bean
    public SimpleBean simpleBean() {
        return new SimpleBean(); // 한번 Bean으로 등록해둔 뒤에 해당 객체 재사용
    }

    @Bean
    public SimpleBeanConsumer simpleBeanConsumer() {
        return new SimpleBeanConsumer(simpleBean());
    }
}


 
 
- 필드 주입 vs 생성자 주입
@Autowired 필드 주입과 생성자 주입 모두 스프링 컨테이너에서 빈을 주입받는 방법입니다.
필드 주입은 스프링이 빈을 생성한 후 필드에 주입하며, 생성자 주입은 빈을 생성하기 전에 생성자를 호출하여 의존성을 주입합니다.
생성자 주입은 불변성을 보장하고, 명시적인 의존성 정의와 테스트 용이성 등 여러 장점을 제공합니다.
필드 주입은 보다 간편하지만, 의존성의 명시성과 객체의 불변성을 보장하는 데 한계가 있을 수 있습니다.



- 스프링 컨테이너 올라가는 순서
:  알아보기! configuration이랑 component랑 autowired랑 생성자랑!!!!

- virtual thread 동작 원리
https://techblog.woowahan.com/15398/



- 아래 코드는 동기 -> 비동기로 멀티스레드를 사용하고, 

   스케쥴러에서 싱글스레드로 진행됨 (리팩터링 시, 스프링 배치 사용해도 됨)

 

private final ExecutorService executorService = Executors.newFixedThreadPool(MAX_CONNECTIONS);

private void scheduleTasks(FTPInfo ftpEnv) {
        List<...> list = ....

        list.stream()
                .filter(....)
                .findFirst()
                .ifPresent(env -> {
                    List<String> ...= .....(); // 여기까지 동기
                    executorService.submit(() -> taskFactory.startScheduler(..)); // 비동기
                });
    }
--------------------------------
이후 스케쥴러에서 싱글스레드로
private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

    public void startScheduler(...) {
        scheduler.scheduleWithFixedDelay(() -> {
            try {
               ...
            } catch (IOException e) {
                ...
            }
        }, 0, ...getDelaySecond(), TimeUnit.SECONDS);
    }

 

 


- 보통 스프링 배치는 대량 데이터 처리 또는 정기적인 작업에 사용되며 카드사 환불이나 재난 문자 등에 사용되기도 함!


- awesome spring 참고
https://github.com/akullpp/awesome-java?tab=readme-ov-file


- 도커엔진 공부하면 좋음!
https://github.com/akullpp/awesome-java?tab=readme-ov-file

 

 

 

 

240801

 



- [Java] Callable, Future 및 Executors, Executor, ExecutorService, ScheduledExecutorService에 대한 이해 및 사용법
https://mangkyu.tistory.com/259


*** 빈 생성
스프링 컨테이너는 등록된 빈의 클래스를 기반으로 실제 빈 객체를 생성한다.  스프링을 실행(run) 하자마자 빈 등록과 빈 생성이 바로 이루어진다.  
이 때, 필드 주입이나 세터 주입 시에는 실행 시에 빈 생성까지만 진행이 되고 , 런 타임 전까지는 의존성 주입이 되지 않는다. 
생성자 주입 시, 빈 생성과 동시에 아래 단계인 의존성이 주입된다.

생성자 주입 시에  의존성 문제 중 하나인 순환 참조가 걸려있으면 실행하자마자 바로 오류가 나는 이유이다. 
실행하자마자 생성자 주입 & 의존성 주입이 이루어지니, 의존성 문제인 순환 참조 문제가 바로 들통나버리게 되는 것이다.
그러므로 실행 자체가 되지 않는다.  APPLICATION FAILED TO START 가 떠 버리는 것이다. 

생성자 주입의 큰 장점이다. 실행하자마자 빈 생성과 동시에 의존성 주입이 된다는 것 !! 


- 프레임워크는 라이브러리의 묶음으로, 객체의 생명주기 등을 자동으로 수행해줍니다.
- 라이브러리는 프로그램의 필요한 기능들의 묶음으로, 프레임워크에 속할 수 있습니다.
쉽게 말해, 프레임워크가 집이라면 라이브러리는 집안의 가구라고 할 수 있습니다.
프레임워크와 라이브러리는 코드 작성에 도움이 되는 타인의 코드의 집합입니다!
프레임워크는 프로그램이 필요한 것을 개발자에게 위임받아 제어권을 역전하고, 라이브러리는 개발자가 필요할 때 호출함으로써 개발자가 능동적으로 사용합니다.

 

 

 

- 스프링 배치 POC Start~~~~

 

 

240802

 

 

 

- 스프링 배치 poc 중

- Axon 이벤트소싱이랑 CQRS 공부해보기 (Read는 NoSQL에 Mybatis로, 나머지는 Jpa로 많이 쓴다고 함)
ㄴ https://saysimple.tistory.com/197
ㄴ https://www.baeldung.com/axon-cqrs-event-sourcing

 

- MSA outbox pattern과 saga 패턴도 공부해야 함!!

- 코드 리뷰 받은거 수정 필요

 

 

 

CGLIB


CGLIB는 자바의 바이트코드를 조작하여 클래스의 서브 클래스를 동적으로 생성할 수 있게 해주는 라이브러리입니다. 주로 메서드 호출을 가로채거나, 동적 프록시를 생성하는 데 사용됩니다.

- 클래스 상속을 통한 프록시 생성:
CGLIB는 원본 클래스를 상속받아 새로운 클래스를 생성합니다. 이 새로운 클래스는 원본 클래스의 모든 메서드를 오버라이드하여, 메서드 호출을 가로채는 기능을 추가할 수 있습니다.

- 사용 예시
1. AOP : AOP 중 트랜잭션 관리도 AOP를 통해 구현되며, CGLIB를 사용하여 메서드 호출 전후에 트랜잭션 처리를 삽입

2. JPA : 엔티티 객체의 지연 로딩 기능을 지원. 데이터베이스에서 엔티티를 처음 요청할 때 모든 데이터를 가져오지 않고, 실제로 필요한 시점에만 데이터를 로드합니다. 구현하기 위해 JPA는 CGLIB를 사용하여 엔티티 클래스를 상속받는 프록시 객체를 생성합니다. 이 프록시는 실제 엔티티 객체를 감싸며, 필요한 경우 실제 데이터베이스 조회를 트리거

'개발자가 되었다?' 카테고리의 다른 글

WW33  (0) 2024.08.14
WW32  (0) 2024.08.08
WW30  (0) 2024.07.25
WW29  (0) 2024.07.18
WW27  (0) 2024.07.02