비동기 방식이란?

동기 VS 비동기

비동기 방식에 대해서 이야기하기전에 동기와 비동기의 차이부터 짚고 넘어가야 할 것 같다.

1. 동기(Synchronous : 동시에 일어나는)

동기는 말 그대로 동시에 일어난다는 뜻입니다. 요청과 그 결과가 동시에 일어난다는 것입니다.

장점

  • 설계가 간단하고 직관적이다.

단점

  • 결과가 주어질 때까지 아무것도 못하고 대기해야 한다.

2. 비동기(Asynchronous : 동시에 일어나지 않는)

비동기는 동시에 일어나지 않는다는 뜻입니다. 요청과 결과가 동시에 일어나지 않은것이라는 하나의 약속입니다.

단점

  • 설계가 동기방식보다 비교적 복잡하다.

장점

  • 결과가 주어지는데 시간이 걸리더라도 그 시간 동안 다른 작업을 할 수 있다.

동기 방식을 비동기 방식으로 바꾸다

AliExpress 크롤링프로젝트

  1. Issue - CPU 점유율 증가

    • 해당 프로젝트는 초기에 동기방식으로 설계를 진행했는데, CPU 사용량 이슈때문에 비동기방식으로 튜닝을 진행했다.
  2. Approach - Cycle 속도를 늦춰보자

    • 초기 동기방식 설계의 프로그램은 평균 CPU 점유율이 50% 내외를 유지하였다. 이러한 문제 때문에, 실사용에서 프로그램을 구동중에는 다른 작업을 하기 힘들었다. 문제를 해결하기 위해서 Thread.sleep(long delay) 를 이용해서 사이클 속도를 늦추면 어떨까라는 생각에 적용 및 테스트를 진행하였는데 당연하게도 CPU 점유율은 낮아졌다. 30%내외를 유지하였으며 Main thread를 제외하고 3개의 thread가 동작하고 있기 때문에 눈에띄는 효과를 얻을 수 있었다.
  3. Another Issue - 전체 속도 저하

    • Cycle 속도 저하를 통해서 첫 번째 이슈는 처리했다. 하지만, 이 때문에 다른 문제가 생겼다. 자연스레 처리 속도까지 저하된 것이다. 하지만 처리속도를 높이자니 CPU 점유율 issue를 되돌릴 수는 없는 노릇이다.
  4. Approach - 비동기 설계로의 튜닝

    • 처리 속도는 유지하면서, 점유율 문제까지 해결해보자. Java에서는 Thread에 wait과 notify라는 형태의 비동기 방식을 지원한다. 쓰레드와 상태제어 - programmers 를 참고해보면 ‘wait과 notify는 동기화된 블록안에서 사용해야 한다. wait를 만나게 되면 해당 쓰레드는 해당 객체의 모니터링 락에 대한 권한을 가지고 있다면 모니터링 락의 권한을 놓고 대기한다.’

비동기 설계로 바꾼 후

1
2
3
4
5
6
7
8
9
10
11
/*Crawler.java*/
+ private static Crawler instance;

public Crawler() {
setDaemon(true);
+ instance = this;
}

+ public static Crawler getInstance() {
+ return instance;
+ }

+는 Git의 commit 기록을 보며 추가된 부분을 표시한 것이다.
위의 Crawler.java를 보면 어딘가 친숙한 코드를 볼 수 있다. 바로 Singleton pattern이다. 좀 더 정확하게 하자면, Singleton pattern 을 변형하여 같은 코드블럭에 있지 않더라도 접근 할 수 있도록 설계를 수정한 것이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/*Writer.java*/

@Override
public void run() {
while (crawlerAlive.get() || !crawledData.isEmpty()) {
+ synchronized (Crawler.getInstance()) {
+ try {
+// asynchronous control
+ if(crawledData.isEmpty())
+ Crawler.getInstance().wait(1000 * 30);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
Data d = crawledData.poll();
if (d != null) {
if (wroteCount.get() % 500 == 0)
copyExcel();
writeExcel(d);
wroteCount.getAndIncrement();
}
}
writerAlive = false;
}
dev
Powered by Hexo
Original Theme Weightless
Owner Dev.secr3t