728x90
반응형
728x90
반응형
반응형

환경: windows11, springboot2.7.6, java17

 

2024.02.12 - [서버 세팅 & tool/docker] - [windows] 네트워크 세팅, rabbitmq 세팅, config server 세팅

 

[windows] 네트워크 세팅, rabbitmq 세팅, config server 세팅

환경: windows11, springboot2.7.6, java17 2024.02.10 - [서버 세팅 & tool/docker] - [windows] docker 이미지 만들고 올리고 실행 [windows] docker 이미지 만들고 올리고 실행 환경: windows11, 아래 설치 진행 2024.02.10 - [서버

bangpurin.tistory.com

 

eureka discovery service를 도커에 배포하기

1. Dockerfile 생성

FROM openjdk:17-ea-slim-buster
VOLUME /tmp
COPY target/discoveryservice-1.0.jar discoveryservice.jar
ENTRYPOINT ["java", "-jar", "discoveryservice.jar"]

 

2. 도커이미지 생성

 mvn clean compile package -DskipTests=true
 docker build -t haileyjhbang/discovery-service:1.0 .  //도커이미지생성

도커 이미지 생성 확인 

 

3. 레파지토리 푸시

도커 이미지를 허브 사이트에 올려보기

docker push haileyjhbang/discovery-service:1.0

 

4. 도커 실행

해당 config server 정보는 도커에서는 다르게 적용되어야 하므로 실행 시 정보 추가 필요

docker run -d -p 8761:8761 --network ecommerce-network \
 -e "spring.cloud.config.uri=http://config-service:8888" \
 --name discovery-service haileyjhbang/discovery-service:1.0
 //포트 포워딩; 네트워크 설정
 //설정 추가; 같은 네트워크로 묶여있기 때문에 컨테이너 이름을 명시해도 문제없음
 //네임, 이미지 이름 명시

 

5. 상태 확인 및 추가 기동

4번처럼 실행하고 도커 상태를 보면 다른 것들은 죽어있는 상태

네트워크 상태를 봐도 죽어있음

docker network inspect ecommerce-network

 

그래서 아래처럼 추가 기동 해줌

다시 상태를 확인해 보면 다 떠있음 

로컬에서 유레카 확인

728x90
반응형
반응형

환경: springboot2.7.6. java11,  mysql5.7

 

문제 상황

endDate에 23:59:59를 세팅하는 게 귀찮고 반복적이라 느껴져서 LocalTime.MAX를 사용하는 방향으로 구현하고 있었다.

private LocalDateTime endDate;

//
endDate.toLocalDate().atTime(LocalTime.MAX) 
//위와 동일
endDate.withHour(23).withMinute(59).withSecond(59).withNano(999999999)

 

디버그 시 endDate에 23:59:59:99999.. 로 잘 들어가는 것을 확인하고 entity.save를 진행하였는데

디비에 들어가는 값은 그 다음날 00:00:00으로 들어가 있었다.

즉, 2024-01-01 23:59:59.9999999.. 로 저장을 해도 디비에는 2024-01-02 00:00:00으로 들어가는 상황

java단에서 오류가 아님을 확인하니 mysql 단에서 자체 처리하는 것이라는 생각이 들었다.

 

원인 확인

LocalTime.MAX는 초 이하 9자리까지 지원한다.

즉, 23:59:59.999999999 로 처리한다.

 

현재 해당 디비 콜롬은 아래처럼 datetime으로 정의되어 있다.

초 단위 미만을 지원하지 않는 datetime은 초 단위 아래 값이 오면 반올림해버린다.

하여 초 단위 보다 더 정밀한 시간 값이 필요하면 MySQL5.7에 추가된 fractional second를 이용한 datetime(6) 등을 사용해야 한다.

하지만 MySQL이 지원하는 Fractional Seconds의 최대 자릿수는 6자리고 이를 초과했기 때문에 LocalTime.MAX를 담으면 자동으로 반올림 처리된다.

 

  • mysql datetime과 정밀도(fractional second) 비교

https://lenditkr.github.io/MySQL/fractional-seconds-rouding-problem/

 

아니 시간도 반올림이 된다고?

니가 지정한 내가 아냐~ - Soo

lenditkr.github.io

 

그리고 JPA/mysql-connector 내부적으로도 반올림하는 부분이 있어 시간에 민감한 데이터인 경우 LocalDateTime.now()를 사용하는 것도 문제가 될 수 있다고 한다. 이럴 땐 DB connect 시 설정에 sendFractionalSeconds=false를 추가해줘야 한다.

https://medium.com/naverfinancial/%EC%98%A4%EB%8A%98%EC%9E%90-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%A5%BC-%EC%A1%B0%ED%9A%8C%ED%96%88%EB%8A%94%EB%8D%B0-%EB%8B%A4%EC%9D%8C%EB%82%A0-%EB%8D%B0%EC%9D%B4%ED%84%B0%EA%B0%80-%EB%94%B8%EB%A0%A4%EC%99%80%EC%9A%94-mysql-ae9b0f696742

 

오늘자 데이터를 조회했는데 다음날 데이터가 딸려와요 (MySQL)

안녕하세요. 네이버 파이낸셜 내자산&증권개발팀의 이정빈입니다.

medium.com

 

그래서

  • 날짜 저장 시 mysql의 콜롬 타입을 고려해야 하며
  • LocalTime.MAX 대신 LocalTime.of(23, 59, 59) / LocalTime.of(23, 59, 59, 999_999) 등으로 써야 한다..

 

728x90
반응형
반응형

환경: java11

 

java8이후로 java.util.Date, Calendar가 deprecated되고 LocalDateTime, ZonedDateTime, OffsetDateTime이 등장하였다. 각각 어떤 것인지 살펴보자.

 

LocalDateTime

날짜와 시간에 대한 정보만 있지 zone이나 offset에 대한 정보는 없다. zone에 상관없이 그냥 시간 그 자체를 담는 용도이다.

따라서 LocalDateTime을 아래처럼 포매팅하면 에러가 난다.

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX") 
private LocalDateTime endRegDate;
Unsupported field: OffsetSeconds

 

 

지금 시간 가져오기

LocalDateTime now = LocalDateTime.now();

서울에서, 현재 시각이 2024-02-14 11:00:00 이면 위 결과값도 동일하게 11시이다.

 

특정 시간 가져오기

LocalDateTime now = LocalDateTime.of(2024, 1, 1, 0, 0, 0);

ZonedDateTime

LocalDateTime에 zone이 들어간 형태(UTC/Greenwich)

서머타임(Daylight Saving Time): 시간대 변환 시 서머타임을 고려해야!! ZonedDateTime은 서머타임을 자동으로 처리함

 

지금 시간 가져오기

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX") 
ZonedDateTime now = ZonedDateTime.now();
//"2024-02-14T11:57:23.797+09"

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX") 
ZonedDateTime.now(ZoneId.of("UTC"));
//"2024-02-14T02:57:23.797Z"

그냥 now는 서버 시스템 존(Asia/Seoul)을 기반으로 가져오고, zone id를 주면 변환된다.

포매팅할 때 X를 추가하면(Z아님..) 끝에 존 정보 +09 혹은 UTC면 Z가 들어간다.

 

특정 시간 가져오기

ZonedDateTime zonedDateTime = ZonedDateTime.of(2023, 12, 25, 10, 30, 0, 0, ZoneId.of("America/New_York"));

zone 정보를 줘야 한다.

참고: https://www.baeldung.com/java-format-zoned-datetime-string


OffsetDateTime

ZonedDateTime 처럼 zone을 기반으로 움직이는 데이터이지만 zoneId가 아닌 offset("+02:00", "-08:00")을 기반으로 한다.

특정 zone id를 모를 때 사용하기 좋음

 

현재 시간 가져오기

OffsetDateTime.now();
//"2024-02-14T12:10:05.884+09"
OffsetDateTime.now(ZoneId.of("UTC"));
//"2024-02-14T03:10:05.884Z"

사용법은 ZonedDateTime과 동일하다. 심지어 zone id로도 세팅 가능.

특정 시간 가져오기

OffsetDateTime offsetDateTime = OffsetDateTime.of(2023, 12, 25, 10, 30, 0, 0, ZoneOffset.ofHours(-5));

zone offset으로 시간을 줘야 한다.

 

Instant:

  • Instant는 시간대와 상관없이 UTC 시간을 기준으로 시간을 관리할 때 유용
  • 타임존 정보를 포함하지 않는 가장 기본적인 시간 표현 방식
  • 즉, 1970-01-01T00:00:00Z(Epoch Time) 이후의 시간을 초 또는 나노초 단위로 계산한 시간
  • 타임존과 무관하게 시간의 순간을 표현할 때 사용
  • 네트워크 요청, 로그 등 글로벌 시스템에서 시간대를 고려하지 않고 순수 시간을 기록할 때 사용
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class TimeZoneConversionExample {
    public static void main(String[] args) {
        // 서버에서 UTC 시간으로 받은 Instant
        Instant serverTime = Instant.now();
        System.out.println("Server Time (UTC): " + serverTime);

        // 사용자 시간대 (예: 아시아/서울 시간대)
        ZonedDateTime userTime = serverTime.atZone(ZoneId.of("Asia/Seoul"));
        System.out.println("User Time (Asia/Seoul): " + userTime);
    }
}
728x90
반응형
반응형

환경: windows11, springboot2.7.6, java17

2024.02.10 - [서버 세팅 & tool/docker] - [windows] docker 이미지 만들고 올리고 실행

 

[windows] docker 이미지 만들고 올리고 실행

환경: windows11, 아래 설치 진행 2024.02.10 - [서버 세팅 & tool/docker] - [windows] docker; 컨테이너 가상화 [windows] docker; 컨테이너 가상화 virtualization 물리적인 컴퓨터 리소스를 다른 시스템이나 애플리케이

bangpurin.tistory.com

 

docker networks

bridge network

docker network create --driver bridge 브릿지이름
docker network is

host network

  • 네트워크를 호스트로 설정하면 호스트의 네트워크 환경을 그대로 사용 가능
  • 포트 포워딩 없이 내부 애플리케이션 사용

none network

  • 네트워크 사용하지 않음
  • IO네트워크만 사용, 외부와 단절

네트워크 세팅

docker desktop을 실행하여 docker daemon을 실행하고 초기화

docker container ls -a // 꺼진 컨테이너들까지 확인
docker system prune // 이미지와 남는 것들 까지 다 삭제

 

docker network create --gateway 172.18.0.1 --subnet 172.18.0.0/16 ecommerce-network
// docker network create ecommerce-network
// gateway와 subnet 정보를 안주면 랜덤으로 되긴하는데 설정해주는게 관리가 편함
// 이름은 꼭 주도록; 그러면 ip가 바뀌어도 이름으로 접근가능
docker network ls
// 네트워크 리스트
docker network inspect 네트워크이름
// 네트워크 상세 정보

 

rabbitmq 도커 세팅

docker run -d --name rabbitmq --network ecommerce-network \
 -p 15672:15672 -p 5672:5672 -p 15671:15671 -p 5671:5671 -p 4369:4369 \
 -e RABBITMQ_DEFAULT_USER=guest \
 -e RABBITMQ_DEFAULT_PASS=guest rabbitmq:management
 
 //도커를 백그라운드에서 돌리고 이름을 부여하고 특정 네트워크 안에서 돌 수 있게 지정
 //rabbitmq 내부에서 사용하는 포트 포워딩
 //환경변수
 //이미지 이름이 rabbitmq:management

run으로 실행하면 기존에  rabbitmq:management 라는 이미지가 없으므로 다운로드하는 작업이 포함됨

실행 후 네트워크 안에 잘 포함되었는지 확

port forwarding

잘 떴는지 확인

 

configuration service 도커화

기존에 사용하던 암호화 키파일 확인

jks 파일을 복사하여 프로젝트 루트로 붙여 넣고 Dockerfile 작성

FROM openjdk:17-ea-slim-buster
VOLUME /tmp
COPY apiEncryptionKey.jks apiEncryptionKey.jks
COPY target/config-server-1.0.jar config-server.jar
ENTRYPOINT ["java", "-jar", "config-server.jar"]

해당 파일 경로가 바뀌고 remote에서는 본 파일로 실행해야 하기 때문에 아래처럼 설정파일 경로도 수정해야 함.

참고로 맥에서는 file:/ 의 슬래시도 지워야 된다는 말이 있는데 나는 우선 이걸로 성공..

jar 파일 빌드

 mvn clean compile package -DstkpTests=true

도커 빌드; 현재 디렉터리 안에서 실행한다는 의미의 점 꼭..!

docker build -t haileyjhbang/config-service:1.0 .

기존 application.yml 설정을 확인해 보면 rabbitmq 설정이 로컬 테스트용으로 되어있음. 이를 도커에 그대로 올리면 당연히 안될 거고 도커의 rabbitmq로 바꿔줘야 함.

물론 설정 자체를 수정(docker ip를 넣고 저장)해서 그대로 jar을 말아줄 수도 있지만, docker ip는 바뀔 수 있음. 따라 jar는 그대로 말고 실행 시 도커의 이름으로 주입해 주는 게 편함.

docker run -d -p 8888:8888 --network ecommerce-network \
 -e "spring.rabbitmq.host=rabbitmq" \
 -e "spring.profiles.active=default" \
  --name config-service haileyjhbang/config-service:1.0
  // 포트 포워딩, 기존의 네트워크 안에 포함
  // 설정 변경사항 추가
  // 이름 주고 이미지 주고

실행 후 네트워크 검사하면 3번으로 실행됨 

docker network inspect ecommerce-network

잘 떠있는지 로그 확인

docker logs config-service

에러가 있음

Unsatisfied dependency expressed through method 'searchPathCompositeEnvironmentRepository' parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'defaultEnvironmentRepository' defined in class path resource [org/springframework/cloud/config/server/config/DefaultRepositoryConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: You need to configure a uri for the git repository.

??

git repository 설정하라는 이상한 에러.

구글링 해보니 property 옵션을 native로 주라고.. 하여 native로 시작해 봄.

docker run -d -p 8888:8888 --network ecommerce-network -e "spring.rabbitmq.host=rabbitmq" -e "spring.profiles.active=native" --name config-service haileyjhbang/config-service:1.0

성공..?

그러나 서버는 잘 뜨지만, 설정파일을 잘 읽어오지 못하는 문제가 생긴다.

왜냐면.. search-location 이 위처럼 로컬 경로이기 때문..

그래서 다시 git 정보를 가져오도록 주석을 해제한다. native이면 native.search-locations를 따라가는 것 같고 default 면 git을 바라보는 듯..

 

프로퍼티 수정 후 다시 mvn compile 하고 docker build 하고 run 하면 아래처럼 잘 나온다.

 url의 대소문자 주의..

728x90
반응형
반응형

환경: windows11, 아래 설치 진행

2024.02.10 - [서버 세팅 & tool/docker] - [windows] docker; 컨테이너 가상화

 

[windows] docker; 컨테이너 가상화

virtualization 물리적인 컴퓨터 리소스를 다른 시스템이나 애플리케이션에서 사용할 수 있도록 제공 플랫폼 가상화 리소스 가상화 하이퍼바이저(hypervisor) Virtual machine manager(VMM) 다수의 운영체제를

bangpurin.tistory.com

도커 기본 명령어

docker run -d -p 3306:3306 -e MYSQL_ALLOW_EMPTY_PASSWORD=true --name mysql mysql:5.7
//도커로 mysql:5.7을 백그라운드로 실행하는데 
//포트 포워딩으로 호스트의 3306이랑 도커의 3306이랑 연결
//mysql5.7실행 시 필요한 설정을 -e옵션으로 주고
//이름을 mysql로 설정(아니면 랜덤)

실행 확인

docker ps -a

백그라운드라 로그가 안뜨는데, 지나간 로그를 보려면

docker logs 이름/컨테이너id

잘 뜬건 확인했고 terminal로 실행하려면

 docker exec -it mysql /bin/bash

그러면 터미널로 붙어서 쓰는것과 동일한 효과

여기서  mysql -uroot -p -h127.0.0.1 써서 접속해서 디비 사용하면 됨

삭제 시 중지하고 삭제 해야 

 

서비스를 jar이미지 만들어보기

0. 사용하고자 하는 이미지가 있으면 docker hub에서 확인

1. 아래 경로에 Dockerfile 작성

1-1. Dockerfile 내용물

FROM openjdk:17-ea-slim-buster
VOLUME /tmp
COPY target/user-service-0.0.1-SNAPSHOT.jar user-service.jar
ENTRYPOINT ["java", "-jar", "user-service.jar"]

2. 빌드

1. jar 최신화; Dockerfile 과 동일한 이름으로 jar 생성되었는지 확인 

 mvn clean compile package -DskipTests=true

2. 이미지 올릴 나의 docker hub 계정 확인

3. docker 이미지 만들라는 명령어 실행

맨 마지막에 . 찍어서 현재 폴더임을 나타냄 

 docker build --tag haileyjhbang/user-service:1.0 .

4. repository에 push

docker push haileyjhbang/user-service:1.0

1.0 태그 안주면 latest 를 찾기 때문에 에러가 남 

5. repository 확인 

 

만든 이미지 설치

1. 기존 이미지 삭제(확인 용)

docker rmi 4c828476b26a

2. 이미지 id로 삭제

 docker pull haileyjhbang/user-service:1.0

3. 실행

docker run haileyjhbang/user-service:1.0

728x90
반응형
반응형

환경: windows11

 

virtualization

  • 물리적인 컴퓨터 리소스를 다른 시스템이나 애플리케이션에서 사용할 수 있도록 제공
  • 플랫폼 가상화
  • 리소스 가상화

하이퍼바이저(hypervisor)

  • Virtual machine manager(VMM)
  • 다수의 운영체제를 동시에 실행하기 위한 논리적 플랫폼
  • type1(native / bare metal): 하드웨어에 직접 하이퍼바이저를 설치해서 가상화 운영
  • type2(hosted): 하드웨어 위에 os가 있고 그 위세 하이퍼바이저를 설치해서 가상화 운영
    • 보통 사용 방식

OS virtualization; os 가상화

  • host os 위에 guest os 전체를 가상화
  • VMware, VirtualBox
  • 자유도가 높으나 시스템에 부하가 많고 느려
  • 여러 vm을 띄우면 중복적인 리소스가 반복적으로 사용하게 될 수도 있음 

container virtualization; 컨테이너 가상화

  • host os가 가진 리소스를 적게 사용하며 필요한 프로세스 실행
  • 최소한의 라이브러리와 도구만 포함
  • container의 생성 속도 빠름
  • 중복 리소스 제거 가능. 도커 엔진이 가진 리소스 사용

컨테이너 이미지

  • 컨테이너 실행에 필요한 설정 값 모두
  • 이미지 안에 의존성을 이미 다 가지고 있기 때문에 별도 설치할게 없음 
  • 이미지를 가지고 실체화 한 것이 컨테이너 
  • 이미지 저장소: registry
    • public registry: docker hub
    • private registry 운영 가능 
  • 도커 호스트: 이미지를 실행할 수 있는 곳; 레지스트리에서 다운로드한 이미지를 실행 
    • run: create + start

dockerfile

  • 도커 이미지를 생성하기 위한 스크립트 파일 
  • 자체 문법 DSL(domain specific language) 언어 사용하여 이미지를 생성하기 위한 과정을 기술 
  • docker desktop -> docker container 사용

docker desktop download

docker cmd를 사용하기 위해서는 docker desktop을 실행하여 docker daemon을 실행하여야 함

run 해보고 이상없는지 확인하기 위해 아무 cmd 열어서 아래 명령어 입력

docker info

현재 docker가 가지고 있는 image 확인

docker image ls

현재 docker실행중인 container

docker container ls

명령어

  • create
  • start 실행
  • run = create + start 이미지 없으면 다운로드까지
  • tag: version같은 것; 혹은 용도별 마킹/없으면 자동으로 lastest
  • --name 이름 안 넣으면 랜덤 하게 됨; 중복 안됨, --rm 컨테이너 stop 하고 나서, -it iternative terminal,  --link....
  • 호스트=pc 

 

https://hub.docker.com/

 

Docker Hub Container Image Library | App Containerization

Increase your reach and adoption on Docker Hub With a Docker Verified Publisher subscription, you'll increase trust, boost discoverability, get exclusive data insights, and much more.

hub.docker.com

도커 이미지 관리; 다운로드 가능

docker pull ubuntu:16.04 //down
docker images | grep 16.04 //검색
docker run ubuntu:16.04 //실행 but 바로 종료
docker ps // 도커 컨테이너 실행중인것 확인
docker container ls -a //전체 히스토리 확인
docker container rm 컨테이너ID //컨테이너 삭제
728x90
반응형
반응형

환경: windows11, springboot2.7.6, java17

 

prometheus(저장 서버)

  • metrics를 수집하고 모니터링 및 알람에 사용되는 오픈소스 애플리케이션
  • 시간순으로 데이터가 남음(time series database; TSDB)
  • pull 방식의 구조와 다양한 metric exporter 제
  • 시계열 DB에 metrics 저장 -> 조회가능(query)

grafana(시각화)

  • 데이터 시각화, 모니터링 및 분석을 위한 오픈소스 애플리케이션
  • 시계열 데이터를 시각화하기 위한 대시보드 제공

 

prometheus 다운로드

https://prometheus.io/download/

 

os에 맞는 파일을 다운로드하고 압축을 푼다.

1. 폴더 안의 prometheus.yml 수정하여 수집하고자 하는 서비스를 등록 

8000번은 gateway

2. prometheus 실행 

9090포트로 실행됨

http://localhost:9090/graph

 

grafana 다운로드

https://grafana.com/grafana/download?platform=windows

 

os에 맞는 파일을 다운로드하고 압축을 푼다.

bin 폴더 안에 grafana-server.exe파일 실행(공식 문서에서 실행 가이드 확인)

http://localhost:3000/ (admin / admin으로 로그인)

 

연동

grafana 로그인 후

save & test 클릭

이미 다른사람들이 만들어 놓은 dashboard 불러오기

 

아래 사이트 방문하여 대시보드 다운로드

https://grafana.com/grafana/dashboards/?pg=docs-grafana-latest-dashboards

id를 복사하여 아래 창의 id 넣는 부분에 붙여 넣기 하면 import 가능 

아까 등록한 prometheus 선택하고 import

아래는 대표적인 대시보드

https://grafana.com/grafana/dashboards/3662-prometheus-2-0-overview/

https://grafana.com/grafana/dashboards/4701-jvm-micrometer/

https://grafana.com/grafana/dashboards/11506-spring-cloud-gateway/

 

import 후 metrics 설정을 다시 해야 제대로 된 결과가 나온다. 각 그래프를 edit 하여 지표를 최신화한다.

sum 부분에는 prometheus 에서 검색가능한 지표를 넣어야 하고

job 부분에는 아까 prometheus.yml 에 넣은 job name을 써야 한다.

비슷한 지표를 찾기위해 지구본으로 검색해야한다.. 매 버전?마다 다른 것 같다.

여기에 없는 것도 되긴 함.. 따로 찾아봐야 할 듯.

프로메테우스 서버 설정 참고

 

되는 거 하나.. 이거 설정하고 관련 서비스 api 몇 번 쏘고 새로고침하니까 나온다..

spring_cloud_gateway_requests_seconds_count{outcome="SUCCESSFUL", routeId=~"user-service", job=~"apigateway-service"}

728x90
반응형
반응형

환경: springboot2.7.6, java17

 

micrometer

  • jvm 기반의 애플리캐이션 metrics 제공
  • springboot2 +
  • premetheus 등 다양한 모니터링 시스템 지원
  • (구) turbine server -> hystrix client

 

timer

  • 짧은 지연 시간, 이벤트의 사용 빈도 측정
  • 시계열로 이벤트의 시간, 호출 빈도 등 제공
  • @Timed 제공

 

서비스 연동

1. dependency 추가

<!-- micrometer -->
<dependency>
    <groupId>io.micrometer</groupId>
    <artifactId>micrometer-registry-prometheus</artifactId>
</dependency>

<!-- actuator -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator </artifactId>
</dependency>

2. application.yml actuator 정보 추가

management:
  endpoints:
    web:
      exposure:
        include: info, metrics, prometheus #추가

3. @Timed 어노테이션으로 metrics 마킹

    @GetMapping("/welcome")
    @Timed(value = "users.welcome", longTask = true)
    public String welcome(){
//        return environment.getProperty("greeting.message");
        return greeting.getMessage();
    }

4. 추가한 metrics는 사용을 하면 /actuator/metrics 에 표기됨

4. 그리고 실제 호출정보는 /actuator/premetheus 에 남음

728x90
반응형
반응형

환경: springboot2.7.6, spring cloud2021.0.8, java17

 

zipkin

  • 분산 환경의 데이터 수집, 추적 시스템(오픈소스, 트위터 시작, google drapper에서 발전)
  • 분산 환경에서의 시스템 병목 현상 파악
  • collector, query service, database, webui 로 구성
  • span : 하나의 요청에 사용되는 작업 단위; 64bit unique ID(in msa component)
  • trace: 트리 구조로 이뤄진 span set; 하나의 요청에 같은 trace ID 발급(in total flow)
  • spring cloud sleuth; zipkin 서버와 연동, trace/span id를 로그에 추가 가능 

 

다운로드

 

로컬 터미널로 실행을 하고 http://127.0.0.1:9411/zipkin/ 들어가면 웹화면이 나온다.

 

서비스에서 사용하기(양쪽 모두에 세팅)

1. dependency 추가

<!-- zipkin -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>

2. application.yml 추가

spring:
  zipkin:
    base-url: http://localhost:9411
    enabled: true
  sleuth:
    sampler:
      probability: 1.0

3. 재시작하고 연동되어있는 api를 날려보면

첫번째 서버

2024-02-08 15:54:27.101  INFO [user-service,89bf1666da761e42,89bf1666da761e42] 27456 --- [o-auto-1-exec-5] c.e.userservice.service.UserServiceImpl  : before call orders msa
2024-02-08 15:54:27.210 DEBUG [user-service,89bf1666da761e42,cc4d64c75759fa06] 27456 --- [pool-4-thread-1] c.e.u.client.OrderServiceClient          : [OrderServiceClient#getOrders] ---> GET http://order-service/order-service/fcb59ec4-b2d6-4fd2-aefd-c1004542c801/orders HTTP/1.1
2024-02-08 15:54:27.211 DEBUG [user-service,89bf1666da761e42,cc4d64c75759fa06] 27456 --- [pool-4-thread-1] c.e.u.client.OrderServiceClient          : [OrderServiceClient#getOrders] ---> END HTTP (0-byte body)
2024-02-08 15:54:28.095 DEBUG [user-service,89bf1666da761e42,cc4d64c75759fa06] 27456 --- [pool-4-thread-1] c.e.u.client.OrderServiceClient          : [OrderServiceClient#getOrders] <--- HTTP/1.1 200 (883ms)
2024-02-08 15:54:28.095 DEBUG [user-service,89bf1666da761e42,cc4d64c75759fa06] 27456 --- [pool-4-thread-1] c.e.u.client.OrderServiceClient          : [OrderServiceClient#getOrders] connection: keep-alive
2024-02-08 15:54:28.095 DEBUG [user-service,89bf1666da761e42,cc4d64c75759fa06] 27456 --- [pool-4-thread-1] c.e.u.client.OrderServiceClient          : [OrderServiceClient#getOrders] content-type: application/json
2024-02-08 15:54:28.096 DEBUG [user-service,89bf1666da761e42,cc4d64c75759fa06] 27456 --- [pool-4-thread-1] c.e.u.client.OrderServiceClient          : [OrderServiceClient#getOrders] date: Thu, 08 Feb 2024 06:54:28 GMT
2024-02-08 15:54:28.096 DEBUG [user-service,89bf1666da761e42,cc4d64c75759fa06] 27456 --- [pool-4-thread-1] c.e.u.client.OrderServiceClient          : [OrderServiceClient#getOrders] keep-alive: timeout=60
2024-02-08 15:54:28.096 DEBUG [user-service,89bf1666da761e42,cc4d64c75759fa06] 27456 --- [pool-4-thread-1] c.e.u.client.OrderServiceClient          : [OrderServiceClient#getOrders] transfer-encoding: chunked
2024-02-08 15:54:28.096 DEBUG [user-service,89bf1666da761e42,cc4d64c75759fa06] 27456 --- [pool-4-thread-1] c.e.u.client.OrderServiceClient          : [OrderServiceClient#getOrders] 
2024-02-08 15:54:28.097 DEBUG [user-service,89bf1666da761e42,cc4d64c75759fa06] 27456 --- [pool-4-thread-1] c.e.u.client.OrderServiceClient          : [OrderServiceClient#getOrders] [{"productId":"Catalog3","qty":1,"unitPrice":2000,"totalPrice":2000,"createdAt":"2024-02-08T15:51:49","orderId":"17af8280-b028-42d6-b590-594578c75d4c"},{"productId":"Catalog3","qty":2,"unitPrice":2000,"totalPrice":4000,"createdAt":"2024-02-08T15:52:28","orderId":"765e3a28-c6ae-4e48-a4a3-dd2cc73d3caa"}]
2024-02-08 15:54:28.097 DEBUG [user-service,89bf1666da761e42,cc4d64c75759fa06] 27456 --- [pool-4-thread-1] c.e.u.client.OrderServiceClient          : [OrderServiceClient#getOrders] <--- END HTTP (303-byte body)
2024-02-08 15:54:28.138  INFO [user-service,89bf1666da761e42,89bf1666da761e42] 27456 --- [o-auto-1-exec-5] c.e.userservice.service.UserServiceImpl  : after call orders msa

user-service,89bf1666da761e42,89bf1666da761e42

user-service,89bf1666da761e42,cc4d64c75759fa06

  • traceId: 89bf1666da761e42
  • spanId: cc4d64c75759fa06
  • 처음엔 tId랑 같은걸로 시작했다가 새로운 커낵션이 맺어지면 새로운 spanId를 딴다.

 

두번째 서버

2024-02-08 15:54:27.567  INFO [order-service,89bf1666da761e42,730648c3fe5dad8a] 4968 --- [o-auto-1-exec-4] c.e.o.controller.OrderController         : before get orders
Hibernate: select order0_.id as id1_0_, order0_.created_at as created_2_0_, order0_.order_id as order_id3_0_, order0_.product_id as product_4_0_, order0_.qty as qty5_0_, order0_.total_price as total_pr6_0_, order0_.unit_price as unit_pri7_0_, order0_.user_id as user_id8_0_ from orders order0_ where order0_.user_id=?
2024-02-08 15:54:28.069  INFO [order-service,89bf1666da761e42,730648c3fe5dad8a] 4968 --- [o-auto-1-exec-4] c.e.o.controller.OrderController         : after call orders msa

order-service,89bf1666da761e42,730648c3fe5dad8a

  • traceId: 89bf1666da761e42
  • spanId: 730648c3fe5dad8a

4. 해당 값을 가지로 웹으로 들어가서 검색

http://localhost:9411/zipkin/traces/89bf1666da761e42

msa component, 시간 등등 해당 요청으로 연결된 모든 정보를 알 수 있다.

어떤 서비스에서 에러가 발생하면 아래처럼 에러를 표시해준다.

728x90
반응형
반응형

환경: springboot2.7.6, java11

 

circuit breaker

  • 장애가 발생하는 서비스에 반복적인 호출이 되지 못하게 차단
  • 특정 서비스가 정상적으로 동작하지 않을 경우 다른 기능으로 대체수행하여 장애를 회피함
  • open이 되었을 때 우회수행
  • spring cloud netflix hystrix(19년 deprecated)
  • resilience 4j ; 경량/자바 8 이상 지원

 

1. pom.xml 에 의존성 추가

<!-- resilience4j -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-circuitbreaker-resilience4j</artifactId>
</dependency>

2. open feign 을 통해 다른 msa component로 통신하던 부분을 circuit breaker로 변경

우선 기본적으로 제공하는 circuitBreakerFactory을 사용해본다.

//클래스 상단에 주입
    private final CircuitBreakerFactory circuitBreakerFactory;
    
    ...

//함수 안
		//open-feign with error decoder
        //orders = orderServiceClient.getOrders(userId);

        CircuitBreaker circuitBreaker =circuitBreakerFactory.create("circuitbreaker");
        orders = circuitBreaker.run(() -> orderServiceClient.getOrders(userId), throwable -> new ArrayList<>());

3. 이렇게 해두고 해당 msa component를 down 시킨상태에서 api 요청.

로그에는 접속 불가가 뜨지만 결과는 빈 array 반환됨

4. 기본 세팅말고 설정을 상세하게 바꾸고 싶다면 아래처럼 custom하여 빈으로 등록하면 됨

각 설정 의미는 공식 문서 참고

@Configuration
public class Resilience4Config {

    @Bean
    public Customizer<Resilience4JCircuitBreakerFactory> globalCustomConfig(){
        TimeLimiterConfig timeLimiterConfig = TimeLimiterConfig.custom().timeoutDuration(Duration.ofSeconds(4)).build();
        CircuitBreakerConfig circuitBreakerConfig = CircuitBreakerConfig.custom()
                .failureRateThreshold(4)
                .waitDurationInOpenState(Duration.ofMillis(1000))
                .slidingWindowType(CircuitBreakerConfig.SlidingWindowType.COUNT_BASED) //기본값임
                .slidingWindowSize(2)
                .build();
        return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
                                                            .timeLimiterConfig(timeLimiterConfig)
                                                            .circuitBreakerConfig(circuitBreakerConfig)
                                                            .build());
    }
}
728x90
반응형

+ Recent posts