티스토리 뷰
그럼 이제 Zipkin을 활용해서, 저희가 만든 Application의 분산 추적을 하려 합니다. 분산 추적을 통해서 서비스가 어디로 이동하고 있는지, 어떤 이슈가 발생했는지 쉽게 파악 할 수 있습니다. 이런 걸 Console창을 바꿔가며 보려면, 너무 힘들잖아요 😭
#개요
이번 시간에는, Zipkin을 설치했으니 실제로 사용해보려 합니다. Spring Cloud Sleuth를 이용해, Spring Project에서 발생하는 요청을 Zipkin에 연동 될 수 있도록 하고, 실제로 Zipkin을 사용해보려 합니다. 지금까지 잘 따라오셨다면 금방 끝날 수 있는 내용이니 천천히 따라와주세요!
#UserService
먼저 Dependency를 추가해줍니다. Sleuth 와 Zipkin의 Dependency 정보 입니다
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
<version>2.2.8.RELEASE</version>
</dependency>
다음으로는 application.yml 파일을 조금 수정해주려 합니다. Zipkin과 Sleuth 관련 설정을 추가해줄게요
#Application.yml
server:
port: 0
spring:
application:
name: user-service
zipkin:
base-url: http://127.0.0.1:9411
enabled: true
sleuth:
sampler:
probability: 1.0
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
h2:
console:
enabled: true
settings:
web-allow-others: true
path: /h2-console
eureka:
instance:
instance-id: ${spring.application.name}:${spring.application.instance_id:${random.value}}
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8761/eureka
logging:
level:
com.example.userservice.client: DEBUG
management:
endpoints:
web:
exposure:
include: refresh,health,beans,busrefresh #현재 서버가져올 Config 정보를 Refresh 하겠다는 의미
#token:
# expiration_time: 86400000
# secret: ggpark_token
바뀐 부분은 아래와 같습니다.
zipkin:
base-url: http://127.0.0.1:9411
enabled: true
sleuth:
sampler:
probability: 1.0
사실 단순하게 Port를 맞춰주고 사용해주기위한 작업입니다. 따로 설명하기 힘들정도네요.
#UserServiceImpl
다음으로 저번에 CircuitBreaker를 작성한 곳에서 Log를 찍어줍니다.
/* ErrorDecoder */
log.info("Before call orders microservice");
CircuitBreaker circuitBreaker = circuitBreakerFactory.create("circuitbreaker");
List<ResponseOrder> orderList = circuitBreaker.run(()->orderServiceClient.getOrders(userId),
throwable -> new ArrayList<>());
log.info("After called orders microservice");
#OrderService
OrderService도 마찬가지로 같은 작업을 해줍니다.
#Dependency 추가
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
<version>2.2.8.RELEASE</version>
</dependency>
#Application.yml 파일 수정
zipkin:
base-url: http://127.0.0.1:9411
enabled: true
sleuth:
sampler:
probability: 1.0
#OrderController 수정
일단 로그를 사용할 예정이기 때문에 최상단에 @Sl4fj를 등록해줍니다.
@Slf4j
처음으로는 /{userId}/orders로 POST Mapping된 부분에 Log를 두개 찍어줍니다. (주문등록 시 진입점)
@PostMapping("/{userId}/orders")
public ResponseEntity<ResponseOrder> createOrder(@PathVariable("userId") String userId,
@RequestBody RequestOrder orderDetails){
log.info("Before create orders data");
ModelMapper mapper = new ModelMapper();
mapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
OrderDto orderDto = mapper.map(orderDetails, OrderDto.class);
orderDto.setUserId(userId);
OrderDto createdOrder = orderService.createOrder(orderDto);
ResponseOrder responseOrder = mapper.map(createdOrder,ResponseOrder.class);
// /*kafka*/
// orderDto.setOrderId(UUID.randomUUID().toString());
// orderDto.setTotalPrice(orderDetails.getQty() * orderDetails.getUnitPrice());
//
// /* send this order */
// kafkaProducer.send("example-catalog-topic",orderDto);
// orderProducer.send("orders", orderDto);
//
//
// ResponseOrder responseOrder = mapper.map(orderDto,ResponseOrder.class);
log.info("Create orders data");
return ResponseEntity.status(HttpStatus.CREATED).body(responseOrder);
}
그 다음에 /{userId}/orders 로 GET Mapping된 부분에 Log를 두개 찍어줍니다. (주문 조회시 진입점)
@GetMapping("/{userId}/orders")
public ResponseEntity<List<ResponseOrder>> getOrder(@PathVariable("userId") String userId){
log.info("Before retrieve orders data");
Iterable<OrderEntity> orderList = orderService.getOrdersByUserId(userId);
List<ResponseOrder> result = new ArrayList<>();
orderList.forEach(v->{
result.add(new ModelMapper().map(v,ResponseOrder.class));
});
log.info("Add retrieved orders data");
return ResponseEntity.status(HttpStatus.OK).body(result);
}
#Test
Test를 위해서 Service를 실행하려 합니다. 필요한 서비스 목록은 아래와 같으니 참고한 뒤 해당 프로젝트를 실행합니다.
- 해당 Service들은 모두 기존에 작성한 것을 기반으로 실행해야합니다. 해당 Project 파일입니다.-
🚀Read Me
1. 두 폴더 모두 D드라이브 최상위에 위치시키는 것을 추천드립니다. 아닐경우 Config에서 yml파일을 통해 위치 정보를 수정해야 합니다.
2. Sprong_cloud는 Work Space입니다. MSA는 각 서비스가 분리된 Spring Project로 되어있으니. IntelliJ 환경 기준 각 서비스는 따로 실 행 시켜야합니다. spring_cloud를 실행시켜선 안됩니다!
🚀 Config - Service ( Configuration을 관리하는 Service)
🚀 Eureka - Server ( Eureka - Server 기동 / Project Name : Ecommerce)
🚀 Order - Service
🚀 User - Service
#회원등록
POST 방식으로 회원등록 URL을 보냅니다. Body에 정보를 꼭 입력해주세요.
UserId를 복사해줍니다.
#주문등록
localhost:8000/order-service/{user-id}/orders 형태로 주문을 등록합니다.마찬가지로 주문정보를 잊지 말고 입력해주세요
다음으로는 Log가 정상출력되는지 확인해봅니다.
Log는 정상적으로 출력되는 것 같습니다.이제 포스팅 주제에 걸맞게 Zipkin을 활용해서, 해당 내용을 확인해볼까요?
Zipkin에서 해당 내용을 확인하기 위해선 TraceID가 필요합니다.
Console에 출력되는 TraceID 복사해야 합니다. Console에서 해당 빨간색 박스 부분을 복사해주세요.
접속Port 9411이 Default 값이니 아래의 URL로 접속해주세요.
http://127.0.0.1:9411
-만약 접속오류가 발생하면 Zipkin이 실행 중인지 확인해줍니다.-
실행커맨드
java -jar zipkin.jar
접속 후 오른쪽 상단에 TraceID를 붙혀넣기 한 후 엔터를 눌러줍니다.
그럼 다음과 같이 해당 요청에 대한 정보를 확인 할 수 있습니다.
해당 요청이 실행까지 걸린 시간부터, Method 타입과 Path값 그리고 호출 클래스 부터 Mapping된 Controller에 Method명까지, 다양한 정보를 확인할 수 있습니다.
조금 더 나아가서 이번엔 User 정보를 호출하려합니다. 해당 User 정보는 Order-Service까지 연결되어 있으니 Log는 아마 4개가 찍힐겁니다. 한번 요청을 전송해볼게요
#Login
먼저 로그인을 진행해줘야합니다. 유저정보조회는 토큰값으로 인증받지 않으면 조회할 수 없도록 설정이 되어 있어서 번거롭지만 ㅜ.. 해야하는 작업입니다. tokenVALUE를 복사하는 것 잊지말아주세요!
#회원정보 조회
다음과 같이 URL을 보내며 주문정보가 등록된 USERID를 붙히고, Token을 입력 후 요청을 보내봅니다.
#Console(User Service)
다음으로 User Service를 확인해보면 다음과 같은 정보가 출력되는데 먼저 Before Call Orders microService라는 로그메시지가 출력된 로그에 traceID를 복사후 Zipkin에서 확인해 볼게요.
다음과 같은 화면이 출력된텐데 User-Service에서 User 정보를 불러올때 Order-Service에서 주문정보를 조회하는 것을 알 수 있습니다. User-Serivce에서 Order-Service를 호출했기에, TracingID를 조회하면 위와 같이 추적되는 것을 확인 할 수 있습니다.
TraceID를 이용할 수도 있지만, ServiceName으로도 검색 할 수 있습니다.
먼저 상단에 Find a Trace메뉴에서 ➕ 버튼을 눌러 추가를 해봅시다.
다음과 같이 serviceName 탭에 User-Service를 클릭해줍니다.
Run Query로 시작하시고, 만약 관련 정보가 보이지 않는다면, 너무 오래된 추적내용일 수도 있어서 톱니바퀴를 눌러 탐색할 시간을 지정해줍니다. 그럼 아래와 같이 User-Service에 대한 Tracing 내용이 출력이 되게 됩니다.
다음으로는 Dependencies 탭입니다. 해당 탭에서는 날짜별로 어떤 서비스에서 어떤 서비스로 통신이 오고 갔는지 확인 할 수 있습니다. 그리고 해당 응답에서 에러여부가 있었는지 쉽게 체크 할 수 있는 대쉬보드 입니다.
#OrderController
이번엔 의도한 에러를 만들려합니다. try ~ catch문 작성후 아래와 같이 입력해주세요.
Exception에 원하는 Error 메시지를 입력한 뒤 Service를 다시 실행해줍니다.
@GetMapping("/{userId}/orders")
public ResponseEntity<List<ResponseOrder>> getOrder(@PathVariable("userId") String userId) throws Exception{
log.info("Before retrieve orders data");
Iterable<OrderEntity> orderList = orderService.getOrdersByUserId(userId);
List<ResponseOrder> result = new ArrayList<>();
orderList.forEach(v->{
result.add(new ModelMapper().map(v,ResponseOrder.class));
});
try{
Thread.sleep(1000);
throw new Exception("엄...");
}catch(InterruptedException ex){
log.warn(ex.getMessage());
}
log.info("Add retrieved orders data");
return ResponseEntity.status(HttpStatus.OK).body(result);
}
#주문정보 입력
User-Service는 아직 기동중이니 아까 복사해둔 ID를 그대로 써서 아무 주문이나 보냅니다.
#정보 조회
다시 조회를 해보면 Orders가 비어있습니다. 아까 저희가 의도된 오류를 출력했기 때문입니다.
그럼 해당 요청을 Tracing ID를 통해 조회해보겠습니다.
그럼 다음과 같이 어디서 Error가 발생했는지 확인 할 수 있고 Error Message도 Tags를 통해 확인 할 수 있습니다.
또한 Find a Trace 에서도 어디서 에러가 났는지 한눈에 파악 할 수 있습니다.
Dependencies 탭에서도 Error 발생횟수를 쉽게 파악할 수 있습니다.
마치며...
이번 시간에는 Zipkin과 Spring Cloud Sleuth를 활용해서 분산추적을 해봤습니다. 해당 기능을 사용하게 되면, 복잡한 콘솔에서 고생하지 않아도, 쉽게 추적을 할 수 있습니다. 그리고 가장 핵심인, Zipkin을 사용하는 이유는, 저희가 MSA를 사용하기 때문입니다. MSA는 분산되어 있는 서비스를 제공하기 떄문에, 서비스의 이동이나, 로그등을 확인하기가 쉽지 않습니다. 이를 Zipkin을 활용해 중앙화를 이루면, 관리 측면에서 엄청난 효율을 가집니다.
감사합니다.
'웹 프로그래밍 > MSA 학개론' 카테고리의 다른 글
[Docker] Docker 설치&환경 설정 그리고 Container 생성 (0) | 2022.05.04 |
---|---|
[MSA] Micrometer 구현 (0) | 2022.05.04 |
[MSA] Zipkin 개요 & 설치방법 (0) | 2022.05.03 |
[MSA] Orders Microservice 고도화 - Order Kafka Producer TEST (0) | 2022.05.03 |
[MSA] Orders Microservice 고도화 - Order Kafka Producer (0) | 2022.05.03 |
- Total
- Today
- Yesterday
- 빅-오
- github
- 운동일기
- 오늘저녁 삼겹살
- MSA
- ACTUATOR
- consumer
- Logstash 활용
- MariaDB
- rabbitmq
- JWT
- 운동
- prometheus
- kafka
- git
- Kafka Connect
- zipkin
- 미래의나에게동기부여
- springcloud
- Gateway
- UserService
- Logstash to ElasticSearch
- 루틴기록
- LoadBalancer
- producer
- docker
- Spring + ELK
- config
- elasticSearch
- Feign
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |