어제 드디어 개발이 끝나버렸다! 와아아ㅏㅇ!!!
이제 우리에겐 리팩토링, 테스트코드 추가하기 등이 남아있다. 그리하여 나는 아래의 코멘트를 반영하여 조회수 카운트를 AOP로 만드는 작업을 해보기로 했다.
이거... 정말 생각 이상으로 괜찮을지도 모른다. 지금 내가 고민하던 부분 중에 하나가 API 하나에 조회, 리다이렉트, 조회수 카운팅까지 하다보니까 리다이렉트에서 타임아웃이 발생하는 경우가 정말 많다는 점이었는데 AOP로 분리하면 이 부분이 좀 개선되지 않을까?
일단 기존 로직에서 AOP로 분리를 해야하는데, 흠... 생각보다 처음이라서 어려울지도 모르겠다.
AOP는 Around만 써봤고, 중간중간 로깅을 해주는 역할이라던가 아니면 권한을 부여하는 역할로만 써봤는데 After로 로직 자체를 옮겨오는 건 처음이기 때문이다.
찾아보니 Around와 달리 After는 예외일 때, 예외 아닐 때, 예외와 무관하게 그냥 실행되기 등... 여러 종류가 있는 거 같다.
그러면 페이지 리다이렉팅이 성공했을 때만 조회 수를 올리는 로직을 해야하는 것이라 생각되어 예외가 아닐 때만 실행하는 After Returning
을 실행해야 한다고 생각이 든다.
그래도 리다이렉트 실패 시 조회 수까지 누락이 될 테니까.. 일단 처음부터 이걸 하지는 않고, 다른 걸 먼저 적용해봐야겠다.
예외와 무관하게 돌아가는 일반 After를 먼저 적용해봤다.
@Aspect
@Component
@RequiredArgsConstructor
public class ViewCountAspect {
private final RedisViewCountManager redisViewCountManager;
@After("execution(* com.project.cheerha.domain.jobopening.controller.JobOpeningController.getRedirectedView(..))")
public void increaseViewCount(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
Long id = (Long) args[0];
redisViewCountManager.increaseViewCount(id);
}
}
이런 느낌?
정말 별 거 없다;; ㅋㅋㅋ
근데 이제 속도는 AOP 분리 전보다 훨씬 빨라진 걸 알 수 있었다.
조회 수 카운트와 페이지 리다이렉트를 동시해 했을 때 속도
에러율이 높은 이유는 페이지 리다이렉트로 인한 타임아웃 때문이다.
위와 같이 타임 아웃이 원인으로 누락되는 것이다. 일단 이 부분 때문에 타임아웃이어도 조회 수를 카운팅하고, 속도만 체크해 본 것이다.
AOP로 조회 수 카운트 분리 후 속도
음? 예상과는 달리 속도는 비슷하고 어째 에러율이 더 높아졌다. 실제 있는 페이지로 해서 그런건가!?
이걸 Postman으로 했을 때도 별 차이가 없다. 음... 이거를 이론적으로 생각해 본 것과 현실이 다른 문제가 있는 듯 하다.
그래서 이번에는 실제 네이버 주소가 아닌 가짜 주소로 404를 반환하는 걸로 해서 실험을 다시 해봤다.
2차 조회 수 카운트 분리 전 속도
2차 AOP로 조회 수 카운트 분리 후 속도
여전히 비슷하므로, 일단 패스!!
하지만 그럼에도, 가짜 페이지나 페이지 정보가 없을 때도 조회 수가 카운팅된다는 사실을 알아버렸기에, 나는 페이지 정보가 없거나 타임아웃으로 못 들어갔을 때는 조회 수가 안 나오도록 After Returning Advice
를 사용해보기로 했다.
이제 나는 누락을 시켜야한다.
현재 로직은 아래와 같다.
@GetMapping("/{id}")
public RedirectView getRedirectedView(@PathVariable Long id) {
// jobOpeningService.redirectAndJobOpeningViewCount(id);
return new RedirectView(jobOpeningService.getJobOpeningUrl(id));
}
따라서 return으로 어떤 페이지가 오더라도 리턴이 되었으면 누락이 아니게 되는 맹점이 있었다.
그렇기 때문에 나는 페이지 리다이렉트 뷰를 컨트롤러 내부에서 작동시키고 return을 status로 바꿔보고 재실험을 해보기로 했다.
이렇게 해도 안 되는 걸 보고 절망하다가, 서비스 단에서 예외처리를 위해 체크하는 메서드를 추가해주는 방법을 사용해봤다.
try {
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(3000);
connection.setReadTimeout(3000);
int statusCode = connection.getResponseCode();
return statusCode >= 200 && statusCode < 400; // 200~300대에서는 true 반환
} catch (IOException e) {
return false; // 페이지가 존재하지 않으면 false 반환
}
이런 식으로 try-catch 문을 사용하여 예외가 발생했을 경우 false를 적용할 수 있게 고쳤다.
그리고 jmeter를 돌려보니 아래와 같은 결과가 나왔다.
8번 채용공고(더미데이터)를 조회했더니 2000개가 다 돌아가도 오른쪽에 있는 레디스에 8번은 추가되지 않는 걸 볼 수 있었다.
그리고 4번에서는 실제 네이버 포털사이트 링크가 적용되어 있었기에 4번으로 돌리면 아래와 같은 결과가 나왔다.
부하테스트이므로 리다이렉트 확률은 매우 낮아졌고, 그로 인해 53개 밖에 카운팅되지 않았지만 결과적으로 리다이렉트가 제대로 된 페이지일 경우 조회수가 카운팅 되는 것에 성공했다는 걸 알 수 있었다.
<출처>
https://pamyferret.tistory.com/51
https://steady-record.tistory.com/entry/Spring-Spring-AOP-기초-및-예제
https://velog.io/@choidongkuen/Spring-AOP-프로그래밍
https://rlawo32.tistory.com/entry/JAVA-HttpURLConnection-HttpClient-사용하기
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/net/HttpURLConnection.html#method.summary
https://blog.naver.com/websearch/220996691589