Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor/#34 주차장 데이터 삽입 성능개선 및 외부 api 장애 발생시 처리 로직 추가 #86

Merged
merged 19 commits into from
Jun 13, 2024

Conversation

This2sho
Copy link
Contributor

@This2sho This2sho commented Jun 9, 2024

👍관련 이슈

🤔세부 내용

  1. 주차장 batch insert 쿼리로 변경
    • 기존 저장 시간 16초에서 4초로 개선
  2. 주차장 데이터 읽어올 때 api 비동기 처리로 변경
    • 전국 주차장 데이터 기준 약 2분 30초에서 23초로 개선
  3. 외부 api 장애 발생시 처리
    • 커낵션 타임 아웃, 리드 타임 아웃 설정
    • 재시도 처리 추가
    • 본 요청 시작 전, 헬스 체크 요청
    • 요청의 특정 %가 예외로 처리되면 해당 api 요청 중지, 이후 특정 시간이 지나면 다시 요청 보낼 수 있도록 설정

🫵리뷰 중점사항

@This2sho This2sho added 🪓refactor 기능 수정 🎅🏼deploy 해당 PR 머지시 배포 labels Jun 9, 2024
@This2sho This2sho requested review from youngh0 and jundonghyuk June 9, 2024 10:46
@This2sho This2sho self-assigned this Jun 9, 2024
Copy link

github-actions bot commented Jun 9, 2024

Test Results

135 tests   135 ✅  14s ⏱️
 32 suites    0 💤
 32 files      0 ❌

Results for commit 879a941.

♻️ This comment has been updated with latest results.

Copy link

@jobisDonghyuk jobisDonghyuk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

건호형 고생하셨습니당!_!

Comment on lines 5 to 9
private final double MIN_TOTAL_COUNT;

private double totalCount;
private double errorCount;
private boolean isClosed;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

double 인 이유가 있을까요? 정수형 같아보여서용!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그렇네여.. 수정했습니다!

Comment on lines 25 to 32
public synchronized void countUp() {
totalCount++;
}

public synchronized void errorCountUp() {
totalCount++;
errorCount++;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

synchronized keyword vs AtomicInteger 어떤 차이가 있고 성능적으로 차이가 날까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

서버 한대 상황에서 synchronized를 사용하면 간단할거 같아서 이렇게 적용했는데
찾아보니 AtomicInteger를 사용하면 락 없이도 여러 스레드에서 사용할 수 있네요!
AtomicInteger로 수정했습니다~!

Comment on lines 8 to 20
public class AsyncApiExecutor {

private static final ExecutorService executorService = Executors.newFixedThreadPool(100, (Runnable r) -> {
Thread thread = new Thread(r);
thread.setDaemon(true);
return thread;
}
);

public static <U> CompletableFuture<U> executeAsync(Supplier<U> supplier) {
return CompletableFuture.supplyAsync(supplier::get, executorService);
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 부분 configuration으로 정의하고 bean으로 써도 되지 않을까요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋습니다~!

Comment on lines 61 to 78
public void saveAllWithBulk(List<Parking> parkingLots) {
String sql = "INSERT INTO parking "
+ "(base_fee, base_time_unit, extra_fee, extra_time_unit, day_maximum_fee, "
+ "capacity, current_parking, "
+ "holiday_begin_time, holiday_end_time, holiday_free_begin_time, holiday_free_end_time, "
+ "saturday_begin_time, saturday_end_time, saturday_free_begin_time, saturday_free_end_time, "
+ "weekday_begin_time, weekday_end_time, weekday_free_begin_time, weekday_free_end_time, "
+ "created_at, updated_at, "
+ "address, name, tel, operation_type, parking_type, pay_types, location) "
+ "VALUES "
+ "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ST_GeomFromText(?))";

jdbcTemplate.batchUpdate(
sql,
parkingLots,
parkingLots.size(),
PARKING_PARAMETERIZED_PREPARED_STATEMENT_SETTER
);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

굿 이네요 이런식으로 많이 배치인서트 하는 것 같아요

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

근데 이렇게 하면 문자열이 문자열 풀에 넣어서 쓸때 마다 가져다 쓰나요? 아니면 항상 힙에 새로 할당하나요 ?

  • 연산이 들어가 있어서 궁금하네요.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • 이어지는것들이 새로운 String 변수로 만들어진다고 해도 처음 생성된 다음에는 다 풀에서 가져올거같은 느낌적인 느낌이 드는데요

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

전체 다 합쳐진 sql은 풀에 들어가서 새로 생성하진 않네유

Copy link
Contributor

@youngh0 youngh0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨슴다~

Comment on lines 13 to 16
this.totalCount = 0;
this.errorCount = 0;
this.isClosed = false;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

얘네는 private double totalCount = 0; 이렇게 선언해도 무방할듯하네요. 이렇게 가도 좋습니다~

Comment on lines 48 to 54
public boolean isErrorRateOverThan(double errorRate) {
if (totalCount < MIN_TOTAL_COUNT) {
return false;
}
double currentErrorRate = errorCount / totalCount;
return currentErrorRate >= errorRate;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요 부분에서 사용하는 totalCount 를 다른 메서드에서 조작하기 때문에 syncronized 하게 실행해도 괜찮을거같네요.

예를 들어, if 문을 통과하고 return false; 를 하기 전에 다른 스레드에서 countUp 을 호출하는 경우??

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 케이스를 생각 못했네유..
synchronized 키워드 대신 AtomicInteger 이점이 많은 거 같아서 요걸로 수정했습니다.

errorCount++;
}

public void reset() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

요게 서킷 open 하는 역할인가요??

Copy link
Contributor Author

@This2sho This2sho Jun 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넴 초기(정상) 상태로 돌리는 용도입니다

@Around("@annotation(annotation)")
public Object around(ProceedingJoinPoint proceedingJoinPoint, CircuitBreaker annotation) {
ApiCounter apiCounter = getApiCounter(proceedingJoinPoint, annotation.minTotalCount());
if (apiCounter.isClosed()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 알기론 close 가 정상상태로 알고 있습니다. 그래서 isOpen() 이 일반적인 서킷브레이커 패턴에서 사용하는 네이밍일거같슴다

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오홍 그렇네요! 수정했습니다~

@This2sho This2sho added the 🪲bugfix 버그 수정 label Jun 13, 2024
@This2sho This2sho merged commit a138079 into main Jun 13, 2024
3 checks passed
@This2sho This2sho deleted the Refactor/#34_주차장_데이터_삽입_성능개선 branch June 13, 2024 18:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🪲bugfix 버그 수정 🎅🏼deploy 해당 PR 머지시 배포 🪓refactor 기능 수정
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

refactor: 주차장 저장 쿼리 변경
3 participants