• 비동기 방식은 무조건 좋은것인지?

    • 무조건 좋다 보다는 기능 개발을 하면서 상황에 따라 동기방식으로 처리를 해야하는 경우가 있고 비동기 방식을 활용해도 되는 경우가 있기 때문에 상황에 맞게 사용하는게 맞다고 생각합니다.
    • 또한 비동기 방식으로 동기 방식 모두 성능상 차이가 있는 성능 확인도 필요하다고 생각합니다.
  • 비동기 방식을 사용하면서 고려한 부분은?

    • 예외처리는 어떻게 하였는지? / 비동기 처리시 실패한 케이스에 대한 시나리오는?

    • 왜 기본 common pool이 아닌 별도에 thread pool 설정을 하였는지?

      • 왜 별도에 thread pool을 설정하는지?
        • 잠재적인 리소스 경쟁
          • 공통 풀은 특정 **Executor**를 지정하지 않고 CompletableFuture API를 통해 제출된 모든 작업에서 사용되는 공유 풀입니다. 이러한 격리 부족은 예측할 수 없는 동작 및 잠재적인 리소스 경쟁으로 이어질 수 있습니다.
        • 유연한 대처에 어려움
          • 공통 풀을 조정하는 것은 제한적이며, 특정 작업 또는 워크로드에 대한 성능 최적화를 위해 스레드 풀의 크기 또는 다른 특성을 조정할 수 없을 수 있습니다. 전용 스레드 풀을 사용하면 작업 및 작업 부하의 특성에 따라 스레드 풀 매개변수를 미세 조정할 수 있습니다.
    • Thread pool을 따로 설정하였다면 스래드 갯수는 무슨 기준으로 한 것인지?

      • 고려 요소
        • 프로세서 수

          • 보통은 스레드 풀의 크기를 프로세서 수나 코어 수와 관련시킵니다. 이는 대부분의 CPU 작업이 병렬로 처리될 수 있도록 하는데 도움이 됩니다. **Runtime.getRuntime().availableProcessors()**를 사용하여 사용 가능한 프로세서 수를 얻을 수 있습니다.
          int processors = Runtime.getRuntime().availableProcessors();
          
        • 작업의 성격

          • 애플리케이션의 작업이 CPU 바운드인지 I/O 바운드인지에 따라 스레드 풀의 크기를 조정해야 합니다. CPU 바운드 작업은 CPU 리소스를 많이 사용하므로 프로세서 수에 근접한 수의 스레드를 사용하는 것이 좋습니다. 반면 I/O 바운드 작업은 주로 대기 시간이 발생하므로 더 많은 스레드를 사용하여 대기 시간을 최소화할 수 있습니다.
        • 메모리 사용

          • 각 스레드는 메모리를 소비합니다. 스레드 풀의 크기를 결정할 때 메모리 사용도 고려해야 합니다. 많은 스레드를 사용하면 메모리 소비가 늘어날 수 있습니다.
        • 컨텍스트 전환 비용

          • 스레드 간의 전환은 비용이 발생합니다. 스레드 풀의 크기를 너무 크게 설정하면 스레드 간의 전환 비용이 늘어날 수 있습니다.
    • 작업하신 발송 관련 기능은 그렇다면 CPU 바운드 I/O 바운드중에 어디에 해당하는지?

      1. CPU 바운드 작업:
        • 계산이나 데이터 처리가 많이 필요한 작업은 CPU 바운드 작업일 가능성이 높습니다.
        • 병렬로 실행되는 연산이 많아 CPU 사용률이 높을 때 CPU 바운드로 간주할 수 있습니다.
      2. I/O 바운드 작업:
        • 외부 API 호출, 데이터베이스 쿼리, 파일 시스템 액세스 등과 같이 대기 시간이 발생하는 작업은 I/O 바운드 작업일 가능성이 높습니다.
        • 네트워크 통신이나 디스크 I/O 등을 수반하는 작업은 주로 I/O 바운드로 간주됩니다.
      3. 작업 특성 분석:
        • API 호출이나 데이터 전송 등의 외부 작업이 주로 발생하는지 살펴봅니다. 이러한 작업은 대개 I/O 작업의 특성을 갖습니다.
        • 대용량 데이터를 계산하거나 정렬하는 작업은 CPU 작업의 특성을 갖을 수 있습니다.

      일반적으로 네트워크 호출은 I/O 바운드 작업으로 간주됩니다. 외부 API 호출은 해당 API 응답을 기다리는 동안 대기 상태에 있기 때문입니다. 따라서, 외부 API 호출이 주된 작업이라면 해당 부분은 I/O 바운드로 판단할 수 있습니다.

      그러나 세밀한 판단을 위해서는 애플리케이션의 동작을 프로파일링하거나 성능 분석 도구를 사용하여 CPU 및 I/O 사용률을 모니터링하는 것이 좋습니다. 이러한 도구를 사용하면 어떤 종류의 작업이 시스템 자원을 어떻게 사용하는지에 대한 통계를 확인할 수 있으며, 이를 기반으로 작업이 CPU 바운드인지 I/O 바운드인지 더 정확하게 결정할 수 있습니다.

      이메일 발송에 Executors.newFixedThreadPool, Executors.newCachedThreadPool, 또는 Executors.newScheduledThreadPool 중 어떤 것을 선택할지는 상황과 요구사항에 따라 다릅니다.

      1. newFixedThreadPool:
        • 쓰레드 풀의 크기를 고정합니다.
        • 메일 발송이 많이 발생하고, 발송 작업에 대한 쓰레드 풀의 크기를 제한하고 싶을 때 사용할 수 있습니다.
        • 쓰레드의 생성 비용이 크지 않고 고정된 수의 쓰레드가 항상 활성화되어 있어야 할 때 적합합니다.
      2. newCachedThreadPool:
        • 쓰레드 풀의 크기를 동적으로 조정합니다.
        • 메일 발송이 가변적이거나 순간적으로 많은 발송이 예상될 때 유용합니다.
        • 발송이 적은 경우에는 쓰레드 풀이 작은 크기로 유지됩니다.
      3. newScheduledThreadPool:
        • 스케줄된 작업을 위한 쓰레드 풀을 생성합니다.
        • 특정 시간에 메일 발송이 필요하거나 주기적인 작업이 필요한 경우 사용할 수 있습니다.
        • **ScheduledExecutorService**를 이용하여 작업을 일정 시간마다 또는 특정 시간에 실행할 수 있습니다.

      추천: 일반적으로 이메일 발송은 비교적 무거운 I/O 작업이므로 **newCachedThreadPool**이나 newFixedThreadPool 중 하나를 선택하는 것이 좋습니다. 둘 다 적절한 사용 사례가 있으며, 발송되는 이메일의 양과 특성에 따라 선택할 수 있습니다.

      만약 이메일 발송뿐만 아니라 예약된 작업이나 주기적인 작업도 필요하다면 **newScheduledThreadPool**을 고려할 수 있습니다.