https://icthuman.tistory.com/entry/AWS-S3-Athena-%EC%82%AC%EC%9A%A9%EC%A4%91-JDBC-Driver%EB%8F%99%EC%8B%9C%EC%84%B1-%EB%AC%B8%EC%A0%9C

 

AWS S3-Athena 사용중 JDBC Driver동시성 문제

<개요> - S3보안버켓으로 파일을 올려서 Athena 작업중 - 1개의 CSV파일(2.65GB) 12개의 컬럼 - AthenaJDBC42.jar 사용 s3.amazonaws.com/athena-downloads/drivers/JDBC/SimbaAthenaJDBC-2.0.16.1000/docs/Simba+..

icthuman.tistory.com

<현상>

- AWS Athena사용시 quota제한 으로 인하여 다음과 같은 문제가 발생하였습니다.

- 동시에 많은 요청이 몰리는 것을 방지하기 위해서 다음과 같이 API호출수를 제한하도록 하였으며 object wait/notify를 활용하였습니다.

 

<로직>

- API 호출시 기본적으로 @Async호출

- API호출전에 현재 호출count를 확인하여 일정수치 이상일 경우 object.wait()로 대기

- 호출이 성공하면 count를 증가

- 비동기호출을 마치고 응답을 받으면 callback으로 호출count를 감소시키고 object.notify

CompletableFuture<Map<String, Integer>> completableFutureForRule;
    ...
    synchronized (this){
		waitBeforeCall();
		completableFutureForRule = apiCallService.call(request);
		resultCount.incrementAndGet();
	}
    
    completableFutureForRule.thenAccept(retMap -> {
    	synchronized (this){
    		notifyAfterCall();
    }
private void waitBeforeCall(){

	try {
  
		while (apiCallService.getCallCount() >= SIZE) {
			this.wait();
		}
	} catch (InterruptedException e) {
		log.error("Interruped");
	}
	apiCallService.incrementAndGet();
}

private void notifyAfterCall(){
	apiCallService.decrementAndGet();
	this.notifyAll();
}

- blocking queue를 구현할때 와 매우 유사한 로직임을 알수 있습니다.

 

<참고사항>

- caller service 와 callee service가 같은 비율로 증가한다면 이론상 문제는 없습니다. (e.g 10, 20, 30)

  그러나 실제는 두 서비스간에 연관관계가 없을 것으로 예상되며, 또한 이 로직은 한 jvm내 단일 service에서만 유용하기 때문에 ECS와 같이 scale out 이 되는 구조에서 전체 API 호출수를 제한하기 위해서는 다른 방법을 사용해야 합니다. 

e.g) A. cluster shared lock

      B. API gateway를 활용한 limit rate

      C. Redis를 활용한 global count개념

 

- wait후 notify의 경우 잠들어 있는 하나의 쓰레드만 깨우기 때문에 여러가지 예외 상황에 대응하거나 개별제어가 어려워서 일반적으로 notifyAll을 많이 사용합니다.

- while()문으로 체크해야 하는 이유는 여러 쓰레드가 다시 lock을 획득하기 위해 경쟁하기 때문입니다. 또한 Spurious wakeups 처럼 이유없이 쓰레드가 깨어난 경우에도 다시 wait로 진입하기 위해서 필요합니다.

- 이와 같이 일정시간 대기하는 로직을 작성할때 sleep을 사용하는 경우를 간혹 볼 수 있는데, sleep의 경우 wait와 다르게 lock을 반환하지 않으므로 주의해서 사용해야 합니다. (stackoverflow 참조)

https://stackoverflow.com/questions/1036754/difference-between-wait-and-sleep

- 로직이 복잡해질 경우 CountDownLatch 를 이용해서 구현하는 것을 권장합니다!

+ Recent posts