SW/마이크로서비스

병행성과 병렬성의 이해: Temporal을 이용한 분산 시스템 구현

얇은생각 2024. 7. 8. 07:30
반응형

컴퓨팅이 시작될 때는 단일 일련의 연산으로 모든 것을 이해하는 것이 상대적으로 쉬웠습니다. 그러나 시간이 지남에 따라 동시에 여러 작업을 수행할 수 있는 능력을 도입했습니다. 오늘날 컴퓨터가 멀티태스킹을 수행할 수 있다는 사실을 당연하게 여깁니다. 멀티 코어, CPU, 서버 덕분에 이 모든 것이 가능하다는 것을 알고 있습니다. 그렇다면 자바스크립트나 파이썬과 같은 "단일 스레드" 언어가 어떻게 "동시에 여러 일을 하는 것처럼 보이게" 할 수 있을까요?

여기에는 병행성과 병렬성이라는 두 가지 다른 개념이 있습니다. 이 둘은 종종 혼동되지만, 완전히 구별되는 개념입니다. 간단히 정의하자면:

  • 병렬성(Parallelism): 실제로 동시에 여러 작업이 실행되는 것.
  • 병행성(Concurrency): 여러 작업을 정의되지 않은 순서로 처리할 수 있는 능력.

다시 말해, 병행성은 프로그램이나 런타임 환경이 설계된 방식에 따라 여러 작업이 동시에 진행되는 것처럼 보이게 하는 반면, 병렬성은 실제로 여러 작업이 동시에 실행되는 것을 의미합니다.

 

병행성과 병렬성의 이해: Temporal을 이용한 분산 시스템 구현

 

 

병행성

병행성은 "시분할 다중화(Time-Division Multiplexing)"라는 개념을 통해 가장 쉽게 이해할 수 있습니다. 예를 들어, 이 글을 몇 분 동안 쓰다가 슬랙 메시지를 확인하고, 뉴스를 읽고, 다시 글쓰기로 돌아옵니다. 모든 작업이 완료되기 전에 진행되고 있지만, 동시에 모든 작업을 수행할 수는 없습니다. 이것이 바로 병행성입니다: 한 작업을 일시 중지하고 다른 작업을 수행한 후 다시 돌아올 수 있는 능력입니다.

비유적으로 말하자면, 제가 이메일을 확인하면서 블로그 글을 쓰지 못한다고 해서 다른 사람이 글을 쓰는 동안 이메일을 확인하지 못하는 것은 아닙니다. 이는 병렬성의 예입니다. 우리는 모두 동일한 기술을 사용하고 있지만, 동시에 작업을 수행할 수 있습니다. 마찬가지로 잘 구성된 프로그램은 피보나치 수를 계산하는 함수와 프랙탈 시퀀스를 계산하는 다른 함수를 가질 수 있습니다. 이 프로그램은 하나의 함수를 일시 중지하고 다른 함수를 일정 시간 동안 실행할 수 있도록 설계될 수 있습니다. 이것이 병행성입니다.

하지만 이러한 함수를 별도의 스레드로 분리하거나 다른 프로세스로 포크하여 멀티 코어 머신에서 실행하면, 병렬성도 얻게 됩니다.

 

 

병렬성

따라서 병렬성은 때때로 병행성을 의미할 수 있지만, "병행성"이 반드시 "병렬성"을 의미하지는 않습니다. 주요 차이점은 병렬성은 실제로 동시에 작업이 실행되지만, 병행성은 작업이 인터리브 방식으로 실행된다는 것입니다.

병렬성은 달성하기 매우 쉽지만 동시에 매우 복잡합니다. 거의 모든 현대 컴퓨팅 장치는 멀티 코어 프로세서를 가지고 있으며, 이를 통해 우리는 병렬성을 무료로 얻습니다. 슬랙이 제가 글을 작성하는 구글 문서 탭과 동시에 실행되고 있는 것이 그 예입니다.

컴퓨터 전체가 단일 "프로그램"이라면, 서로 다른 기능을 독립적으로 구축하는 과정에서 병행성을 자연스럽게 구축하는 작업이 포함되었을 것입니다. 그리고 그것이 병렬로 실행되는 것은 실행되는 하드웨어 덕분입니다.

 

 

병행성과 병렬성의 결합

이제부터는 조금 더 복잡해집니다. 스레드, 하이퍼스레드, 보조 프로세서(GPU 또는 VPU), 또는 전체 다른 머신을 추가하면 여러 수준의 병렬성과 병행성을 얻을 수 있습니다. 이러한 개념을 전체 시스템 내에서 구별하는 것은 종종 어렵습니다. 이는 이들이 혼동되고 자주 교환되는 큰 이유 중 하나입니다.

독립적인 프로세스가 동시에 실행되도록 설계된 분산 시스템을 생각해 보십시오. 이러한 프로세스가 서로 다른 서버에서 실행되면서 통신해야 한다면, 우리는 병렬성과 병행성의 복잡한 조합을 다루게 됩니다.

 

 

분산 시스템과 Temporal

분산 시스템의 복잡성은 단순히 병렬 환경일 뿐만 아니라 자원을 중재하는 시스템이 본질적으로 존재하지 않다는 점에 있습니다. 이는 하드웨어와 네트워크, 모든 것이 결국 실패하게 마련이기 때문에 중요합니다. 이 실패로 인해 작업이 손실될 수 있으며, 이는 "좋은" 자원에서 다시 스케줄링되어야 합니다.

이 문제를 해결하기 위해 우리는 결국 실패로부터 복구할 수 있거나 이러한 실패를 처음부터 견딜 수 있는 무언가를 구축해야 합니다. 마이크로서비스 대 모놀리식, 이벤트 소싱과 CQRS, 메시지 큐와 생산자/소비자와 같은 시스템 설계 패턴은 다양한 실패를 견디고 복구할 수 있도록 하기 위해 나타납니다.

 

 

Temporal을 이용한 병행성과 병렬성

Temporal은 매우 병렬적인 시스템에서 발생하는 모든 문제를 해결하지는 않지만, 대부분을 완화시켜줍니다. Temporal을 사용하여 애플리케이션을 구축하면 병렬성, 병행성, 그리고 내결함성을 무료로 얻을 수 있습니다.

예를 들어 온라인 음식 주문 및 배달 애플리케이션을 생각해 보십시오. 여기서 주요 "비즈니스 단위"는 주문입니다. 이는 시스템 내에서 한 항목의 상태에 대한 고수준 개념적 뷰일 뿐입니다. 주문의 각 단계는 다른 단계와 독립적이며, 일단 작업 요청을 받으면 추가 통신 없이 작업을 완료할 수 있습니다. 그러나 전체 라이프사이클은 고객에게 중요한 사항입니다.

Temporal은 기본적으로 자바스크립트의 이벤트 루프와 유사하게 작동합니다. Temporal SDK는 주어진 워크플로우에 대해 한 번에 하나의 작업만 실행됩니다. 중요한 차이점은 준비된 작업의 큐가 메모리에 저장되지 않고 Temporal 서버에 저장된다는 것입니다. 이렇게 하면 많은 "메인 스레드"를 가질 수 있으며, 이는 Temporal 워커의 형태로 존재합니다.

 

 

결론

병행성과 병렬성은 자주 혼동되는 개념입니다. 병렬성을 효과적으로 활용하도록 설계된 단일 프로그램이 동시에 병행성을 가지기도 하기 때문에 그렇습니다. 그러나 자바스크립트나 Temporal 워커와 같은 환경은 내부적으로 병렬성을 가지지 않고 높은 수준의 병행성을 가지고 있습니다.

병행성은 프로그램이 다른 구성 요소를 처리하는 능력을 의미하며, 병렬성은 환경이 동시에 여러 작업을 실행할 수 있는 능력을 의미합니다. 이 두 개념을 구별하고 Temporal 애플리케이션에서 어떻게 활용되는지 이해하는 데 도움이 되었기를 바랍니다.

반응형