오늘은 내가 프로젝트의 전반적인 기능이 완성되고 성능을 개선시킨 부분에 대해 말해보고자 한다.
일단 어느정도 개발이 완료 되고난후, 직접 Grafana로 각 API 요청시 발생하는 CPU 사용량이나 Memory 사용량에 대해 추적해보았다.
그러던중... 다음과 같은 이슈를 마주했다.
이슈
👉 현재 작업하던 Post Service의 CPU 및 Memory 사용량이 다른 MSA 환경의 Service들보다 매우 높다는 것을 **[Grafana monitoring]**을 통해 확인이 되었다.
문제
👉 실제로 Jmeter로 서버 성능을 측정을 해보고 프론트에서도 요청을 보냈을때 시간이 매우 오래걸리는 것으로 보아 백엔드 비즈니스 로직자체가 무겁고 어딘가 불필요하게 시간이 소요된다는 것을 알 수 있었다.
해결
👉 최대한 MSA 서비스들 사이의 요청과 응답을 최대한 줄여주고, 불필요한 메모리 소모 혹은 데이터베이스 테이블 같은 것은 속성으로 변경
1. 명령형 API(RestTemplate)을 Openfeign 연결로 변경
Before
String updateURL = recUrl + "/recommends/editings";
String jsonBody;
ObjectMapper objectMapper = new ObjectMapper();
String token = jwtProvider.parseToken(request);
try {
Map<String, Object> docFields = new HashMap<>();
docFields.put("changedHashtag", hashtags);
docFields.put("blogId", blogId);
System.out.println("docFields = " + docFields);
jsonBody = objectMapper.writeValueAsString(docFields);
HttpRequest updateRequest = HttpRequest.newBuilder()
.uri(URI.create(updateURL))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + token)
.POST(HttpRequest.BodyPublishers.ofString(jsonBody))
.build();
HttpClient client = HttpClient.newHttpClient();
HttpResponse<String> updateResponse = client.send(updateRequest,
HttpResponse.BodyHandlers.ofString());
if (updateResponse.statusCode() == 200) {
System.out.println("업데이트 완료");
} else {
System.out.println("업데이트 도중 오류가 발생하였습니다: " + updateResponse);
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
Map<String, Object> docFields = new HashMap<>();
docFields.put("changedHashtag", hashtags);
docFields.put("blogId", blogId);
System.out.println("docFields = " + docFields);
recommendClient.sendAllHashtags(docFields, "Bearer " + token);
}
원래는 이렇게 HTTP Client 요청을 해주었으나
@FeignClient(name ="recommend-service", url = "${application.config.recommend-url}")
public interface RecommendClient {
@PostMapping("/hashtags")
void sendNewHashtags(@RequestBody Map<String, Object> docFields, @RequestHeader("Authorization") String token);
@PostMapping("/editings")
void sendAllHashtags(@RequestBody Map<String, Object> docFields, @RequestHeader("Authorization") String token);
}
이렇게 openfeign Client 연결로 변경해주었다!
2. 불필요한 테이블 속성값으로 대체
프로젝트 전체를 살펴보던중, 과도한 쿼리가 발생하는 영역을 분석한 후 테이블 정규화를 해제 시켜줬어. 요청이 잦은 서버 간의 두 테이블을 적절히 조인하여, 주로 발생하는 쿼리 수를 크게 줄일 수 있었다!
해결 결과
결과적으로, CPU 사용량을 0.699에서 0.129로 대폭 감소시키는 데 성공했으며, 코드의 품질과 유지보수성 또한 크게 개선할 수 있었다. 특히 명령형 API를 사용하지 않고 비동기 호출 방식을 활용해 서버 간 요청 대기 시간을 줄이고, 인터페이스 기반의 호출 규격을 명확히 정의할 수 있어 개발 생산성과 유지보수성을 동시에 향상시킬 수 있었다!
CPU 사용량 대폭 감소: 0.699 → 0.129
'Springboot' 카테고리의 다른 글
SpringBoot: TDD(Test-Driven-Development)란? (2) | 2025.01.03 |
---|---|
Spring Batch 활용 (1) | 2024.12.09 |
Spring boot: DDD(Domain Driven Design)란? (0) | 2024.09.23 |
Spring Boot 순환 참조 오류(Error creating bean with name) (0) | 2024.06.18 |
SpringBoot Builder 패턴의 이해 (0) | 2024.04.03 |