심각한 장애는 시스템에서 유용한 결과를 산출할 수 없게 합니다. 예를 들어 전자 상거래 웹 사이트에서 상품 정보에 대한 데이터베이스 쿼리가 실패하면 웹 사이트에서 상품 페이지를 제대로 표시할 수 없습니다. 아마존 서비스는 안정성을 위해 심각한 장애를 대부분 처리해야 합니다. 심각한 장애를 처리하기 위한 전략은 크게 4가지 범주로 나뉩니다.

재시도: 실패한 작업을 즉시 또는 일정한 지연 시간 후에 다시 처리합니다.
선제적 재시도: 작업을 여러 번 병렬적으로 실행하여 첫 번째로 완료된 작업을 사용합니다.
장애 조치: 엔드포인트의 여러 사본에 대해 작업을 다시 수행하거나, 가능하면 성공 확률을 높이기 위해 작업의 병렬 사본을 여러 번 수행합니다.
폴백: 동일한 결과를 얻기 위해 여러 가지 메커니즘을 사용합니다.

이 기사에서는 여러 가지 폴백 전략에 대해 소개하고 아마존에서 이러한 전략을 사용하지 않는 이유를 설명합니다. 놀라운 내용을 접하실 수 있습니다. 엔지니어들은 실제 세상을 설계의 시작점으로 여기는 경우가 많습니다. 실제 세상에서 폴백 전략은 사전에 계획되어 필요한 시점에 사용되어야 합니다. 공항의 전광판이 꺼졌다고 생각해 보십시오. 탑승객들이 게이트를 제대로 찾을 수 있도록 상황에 대처할 수 있는 사고 대비 계획(예: 사람이 직접 화이트보드에 운항 정보 기록)이 이행되어야 합니다. 그러나 사고 대비 계획이 적절하지 않은 경우, 예를 들면 화이트보드의 글자를 읽기가 어렵거나, 정보를 지속적으로 업데이트하기 어렵거나, 담당자가 부정확한 정보를 기록하는 등의 문제가 있을 수 있습니다. 화이트보드 폴백 전략이 반드시 필요기는 하지만 문제는 여전히 발생할 수 있습니다.

분산 시스템의 세계에서 폴백 전략은 가장 다루기 어려운 전략 중 하나입니다. 특히 시간이 중요한 서비스의 경우에 그렇습니다. 이러한 어려움을 가중시키는 것은 나쁜 폴백 전략이 영향을 미치는 데 오랜 시간(몇 년이 소요될 수도 있음)이 걸릴 수 있으며, 좋은 전략과 나쁜 전략의 구분도 쉽지 않다는 점입니다. 이 기사에서 핵심은 폴백 전략이 해결할 수 있는 것보다 더 많은 문제를 양산할 수 있다는 점입니다. 앞으로, 아마존에서 문제를 일으켰던 폴백 전략의 예를 몇 가지 살펴보겠습니다. 그리고 마지막에는 아마존에서 폴백을 대체해 사용하고 있는 방안에 대해 논의할 것입니다.

서비스에 대한 폴백 전략을 분석하는 것은 직관적으로 이루어질 수 없으며 분산 시스템에서의 파급 효과를 예측하는 것도 쉽지 않습니다. 따라서 단일 시스템 애플리케이션을 위한 폴백 전략을 먼저 살펴보겠습니다.

단일 시스템 폴백

많은 애플리케이션에서 메모리 할당 오류를 처리하는 공통적인 패턴을 보여 주는 다음 C 코드 조각을 생각해 보십시오. 이 코드는 malloc() 함수를 사용하여 메모리를 할당한 다음 일부 유형의 전송을 수행하는 동안 메모리에 이미지 버퍼를 복사합니다.
pixel_ranges = malloc(image_size); // allocates memory
if (pixel_ranges == NULL) {
  // On error, malloc returns NULL
  exit(1);
}
for (i = 0; i < image_size; i++) {
  pixel_ranges[i] = xform(original_image[i]);
}

malloc이 실패한 경우 이 코드는 점진적으로 복구하지 않습니다. 실제로 malloc에 대한 호출이 실패하는 경우는 거의 없으며 개발자들은 코드에서 실패가 발생한 경우 이를 무시하는 경우가 많습니다. 이 전략이 일반적으로 사용되는 이유는 무엇일까요? 단일 시스템에서 malloc이 실패한 경우 해당 시스템은 아마도 메모리가 부족한 상태일 것이기 때문입니다. 따라서 하나의 malloc 호출이 실패하는 것보다 큰 문제가 있을 수 있으며 이러한 경우 시스템은 곧 작동을 멈추게 됩니다. 이것은 대부분 단일 시스템에서 합당한 추론입니다. 이러한 까다로운 문제를 해결하기 위해 노력할 가치가 있는 애플리케이션은 많지 않습니다. 이러한 오류를 처리하기를 원하지 않는다면 어떨까요? 이 상황에서 유용한 무엇인가를 하려고 시도하는 것은 미묘한 문제입니다. 메모리를 다른 방식으로 할당하는 두 번째 방법으로 malloc2를 구현한다고 생각해 보십시오. 우리는 기본 malloc 구현이 실패한 경우 malloc2를 호출할 것입니다.

pixel_ranges = malloc(image_size);
if (pixel_ranges == NULL) {
  pixel_ranges = malloc2(image_size);
}

한눈에 보기에는 이 코드가 제대로 작동할 수 있을 것 같지만 상대적으로 불명확한 문제가 몇 가지 있습니다. 폴백 로직은 처음 시작할 때 테스트가 쉽지 않습니다. malloc에 대한 호출을 가로채 실패 상황을 주입할 수 있지만, 프로덕션 환경에서 일어날 수 있는 상황을 정확하게 시뮬레이션하지는 못합니다. 프로덕션에서 malloc이 실패한 경우 시스템은 대부분 메모리 부족 또는 소진 상태입니다. 이처럼 광범위한 메모리 문제를 어떻게 시뮬레이션하시겠습니까? 메모리 부족 환경을 시뮬레이션할 수 있다고 해도 메모리 부족 조건을 malloc2 폴백 코드 실행 시점과 일치시키려면 어떻게 해야 할까요?

또 다른 문제는 폴백 자체가 실패할 수 있다는 점입니다. 앞의 폴백 코드는 malloc2의 실패를 처리하지 못하기 때문에 프로그램은 생각만큼의 혜택을 제공하지 못합니다. 이 폴백 전략으로 완전히 실패할 가능성이 낮아지지만 불가능하지는 않습니다. 아마존에서는 드물게 사용되는 폴백 전략에 투자하는 것보다 기본(폴백이 아닌) 코드의 안정성을 높이기 위해 엔지니어링 리소스를 투입하는 것이 성공 확률이 높다는 것을 확인했습니다.

더 나아가, 가용성을 최우선 과제로 삼는 경우 폴백 전략은 위험을 감수할 가치가 없을 수 있습니다. malloc2의 성공 가능성이 높은 경우 malloc으로 씨름해야 할 이유가 있을까요? 논리적으로 malloc2는 높은 가용성을 위해 절충할 필요가 있습니다. 지연 시간이 길지만 더 큰 SSD 스토리지에 메모리를 할당할 수도 있습니다. 그러나 malloc2로 절충안을 내야 하는 이유에 대한 의문이 대두될 수 있습니다. 이 폴백 전략으로 발생할 수 있는 일련의 잠재적인 이벤트를 고려해 보십시오. 먼저 고객이 애플리케이션을 사용하고 있습니다. malloc의 실패로 인해 갑자기 malloc2가 실행되고 애플리케이션이 느려집니다. 바람직하지 않은 현상입니다. 이렇게 더 느려져도 될까요? 문제는 여기서 그치지 않습니다. 시스템의 메모리가 소진(또는 매우 부족)된 경우를 생각해 보십시오. 이제 고객은 한 가지가 아닌 두 가지 문제를 경험하게 됩니다(느려진 애플리케이션과 느려진 시스템). malloc2로 전환 시 부작용으로 인해 전체적인 문제가 더욱 악화될 수도 있습니다. 예를 들어 다른 하위 시스템이 동일한 SSD 스토리지와 경합할 수 있습니다.

폴백 로직은 시스템에도 예기지 않은 부하를 생성할 수 있습니다. 스택 추적으로 로그에 오류 메시지를 작성하는 것과 같이 단순한 일반 로직조차도 표면적으로는 무해하지만, 갑자기 어떤 변화로 인해 오류가 빠른 속도로 발생하면 CPU 바인딩 애플리케이션이 I/O 바인딩 애플리케이션을 모핑할 수 있습니다. 디스크가 이러한 속도로 쓰기를 처리거나 해당하는 양의 데이터를 저장하도록 프로비저닝되지 않은 경우 애플리케이션이 느려지거나 작동이 중단될 수 있습니다.

폴백 전략이 문제를 악화시킬 뿐 아니라 잠재적 버그로 대두될 수 있습니다. 프로덕션에서 거의 실행되지 않는 폴백 전략을 개발하는 것은 쉽습니다. 앞에서 설명한 malloc2로 폴백하여 특정 코드 행을 실행할 수 있는 바로 그 순간에 고객의 시스템에서 실제로 메모리가 부족해질 때까지 몇 년이 걸릴 수도 있습니다. 폴백 로직에 버그가 있거나 전체적인 문제를 악화시키는 일정 유형의 부작용이 있는 경우 코드를 작성한 엔지니어가 처음에 코드가 어떤 식으로 작동했는지 잊어버려 수정이 쉽지 않을 수도 있습니다. 단일 시스템 애플리케이션의 경우 허용 가능한 수준의 비즈니스적인 절충이 필요할 수 있으며 나중에 설명하겠지만 분산 시스템에서 이러한 결론은 더 큰 의미를 가질 수 있습니다.

이러한 모든 문제가 까다롭기는 하지만, 우리의 경험에 따르면 단일 시스템 애플리케이션에서는 특별한 문제 없이 쉽사리 무시할 수 있는 경우도 종종 있습니다. 가장 일반적인 해결 방법은 앞에서 설명한 방법으로, 메모리 할당 오류로 인해 시스템이 멈추게 하는 것입니다. 메모리를 할당하는 코드는 나머지 시스템과 운명을 공유하며, 이 경우 나머지 시스템이 실패할 가능성이 높습니다. 운명을 공유하지 않는 경우에도 애플리케이션이 예상치 못한 상태가 될 수 있으므로 빠르게 실패하도록 하는 것이 좋은 전략입니다. 비즈니스적인 절충이 합리적입니다.

메모리 할당 오류가 발생한 경우에도 반드시 작동해야 하는 중요한 단일 시스템 애플리케이션의 경우, 적용할 수 있는 한 가지 해결 방법은 시작할 때 모든 힙 메모리를 사전 할당하고 오류 조건을 포함하여 다시는 malloc에 의존하지 않도록 하는 것입니다. 아마존에서는 고객의 CPU 버스트를 모니터링하는 Amazon Elastic Compute Cloud(Amazon EC2) 데몬과 프로덕션 서버에서 실행되는 데몬을 모니터링할 때와 같은 경우, 여러 번 이러한 전략을 구현했습니다.

분산 폴백

아마존에서는 분산 시스템, 특히 실시간으로 응답해야 하는 시스템에서는 단일 시스템 애플리케이션과 동일한 절충안을 적용하지 않습니다. 그 이유 중 하나는 고객과 운명을 공유할 수 없기 때문입니다. 고객 앞에 놓인 시스템에서 실행되는 애플리케이션을 생각해 보십시오. 애플리케이션의 메모리가 부족할 경우 고객은 아마 애플리케이션이 계속 실행될 것으로 기대하지 않을 것입니다. 그러나 서비스는 고객이 직접 사용하는 시스템에서 실행되지 않으며 기대치도 다소 다릅니다. 고객들은 일반적으로 단일 서버에서 애플리케이션을 실행하는 것보다 가용성이 높다는 이유에서 서비스를 사용하기 때문에 이러한 기대를 충족해야 합니다. 이론적으로는 이러한 경우 서비스를 보다 안정적으로 실행하기 위한 방법으로 폴백을 구현할 수 있습니다. 불행히도 중요한 시스템 장애가 발생했을 때는 분산 폴백에도 완전히 동일한 문제가 나타납니다.

분산 폴백은 테스트가 더 어렵습니다. 서비스 폴백은 여러 대의 시스템과 다운스트림 서비스가 장애 요인으로 작용하기 때문에단일 시스템 애플리케이션의 경우보다 복잡합니다. 오버로드 상황처럼 장애 모드 자체를 테스트에서 복제하기가 어렵습니다. 복수 시스템 간 테스트 오케스트레이션을 지속적으로 사용 가능한 경우에도 마찬가지입니다. 여러 상황이 조합된 경우 테스트할 사례의 수가 증가하기 때문에 더 많은 테스트가 필요하며 설정은 훨씬 더 어렵습니다.

분산 폴백 전략 자체가 실패할 수 있습니다. 폴백 전략이 성공을 보장하는 것으로 보일 수 있지만, 우리의 경험에 따르면 성공 가능성을 높여 줄 뿐입니다.

분산 폴백 전략은 가동 중단 문제를 악화시키는 경우가 많습니다. 경험상 복구 시간이 길어질수록 폴백 전략의 장애로 인해 영향을 받는 범위가 늘어납니다.

분산 폴백 전략은 위험을 감수할 가치가 없는 경우가 많습니다. malloc2의 경우처럼 폴백 전략에는 일정 유형의 절충이 필요합니다. 그렇지 않다면 우리는 항상 이 전략을 사용할 것입니다. 이미 문제가 발생했는데 더 악화시키는 폴백을 사용하는 이유는 무엇일까요?

분산 폴백 전략은 처음 나타난 후 몇 개월 또는 몇 년이 지나서 우연의 일치가 발생할 때만 나타나는 잠재적 버그를 양산하는 경우가 많습니다.
아마존 소매 웹 사이트의 폴백 메커니즘으로 인해 실제로 발생한 주요 가동 중단 사례는 이러한 문제점을 현실적으로 보여 줍니다. 가동 중단은 2001년 가량 발생했으며, 이 문제는 웹 사이트에서 표시되는 모든 제품의 최신 배송 속도를 제공하는 새로운 기능에 의해 촉발되었습니다. 새로운 기능은 다음과 같은 것이었습니다.

당시, 웹 사이트에는 두 개의 티어만이 있었으며, 데이터가 공급망 데이터베이스에 저장되었기 때문에 웹 서버가 데이터베이스를 직접 쿼리해야 했습니다. 그러나 데이터베이스는 웹 사이트의 많은 요청을 처리할 수 없었습니다. 웹 사이트의 트래픽이 너무 많았고 일부 페이지에는 25개 이상의 제품이 각 제품의 배송 속도와 함께 표시되었습니다. 따라서 우리는 각 웹 서버에 개별 프로세스로 실행되는 캐싱 레이어를 추가하였습니다(Memcached와 유사한 방식).

모두 제대로 작동했지만 팀에서는 특정한 이유로 인해 캐시가 실패한 경우 이를 처리하는 것 또한 시도했습니다(개별 프로세스). 이 방식에서 웹 서버는 데이터베이스를 직접 쿼리하는 방식으로 돌아갔습니다. 유사 코드로 우리는 다음과 같은 것을 작성했습니다.

if (cache_healthy) {
  shipping_speed = get_speed_via_cache(sku);
} else {
  shipping_speed = get_speed_from_database(sku);
}

직접 데이터베이스 쿼리로 폴백한 것은 몇 달 동안 유효했던 직관적인 해결 방법이었습니다. 그러나 결국에는 모든 캐시가 거의 동시에 실패하여 각 웹 서버가 데이터베이스에서 직접 검색해야 했습니다. 이는 데이터베이스가 완전히 잠길 수 있는 정도의 부하를 양산했습니다. 모든 웹 서버 프로세스가 데이터베이스에서 차단되었기 때문에 전체 웹 사이트가 멈추었습니다. 이 공급망 데이터베이스는 주문 처리 센터에도 필수적이었기 때문에 가동 중단은 더욱 확산되어 문제가 해결될 때까지 모든 주문 처리 센터가 멈추었습니다.

단일 시스템에서 나타났던 모든 문제는 분산 시스템에서 더 심각한 결과를 초래했습니다. 분산 폴백 케이스를 테스트하는 것은 어려운 일이었습니다. 캐시 실패를 시뮬레이션했더라도 여러 시스템 간에 장애가 발생했을 때 나타날 수 있는 문제를 발견하지 못했을 것입니다. 이 경우 폴백 전략이 문제를 증폭시켰으며 폴백 전략을 구현하지 않았을 때보다 상황은 더욱 악화되었습니다. 폴백은 부분적인 웹 사이트 가동 중단(배송 속도가 표시되지 않음)을 전면 가동 중단(페이지가 전혀 로드되지 않음)으로 바꾸어 놓았으며 전체 아마존 주문 처리 네트워크가 백엔드에서 멈추었습니다.

이 경우 폴백 전략에 대한 생각은 논리적이지 않았습니다. 데이터베이스를 직접 검색하는 것이 캐시를 뒤지는 것보다 안정적이었다면 왜 처음에는 캐시를 사용했을까요? 캐시를 사용하지 않으면 데이터베이스 오버로드가 발생할 수 있다는 점이 걱정스러웠지만 그렇게 유해할 수 있는 폴백 코드를 사용해야 하는 이유는 무엇이었을까요? 초기에 오류를 눈치챘어야 했지만 잠재적 버그였기 때문에 가동 중단을 야기하는 상황은 출시 후 몇 달이 지나 나타났습니다.

아마존이 폴백을 피하는 방법

분산 폴백에서 마주치게 되는 이러한 함정을 감안할 때 이제는 대개 폴백의 대체 방안을 선호합니다. 간단히 설명하겠습니다.

폴백이 아닌 안정성 향상 사례

앞에서 언급했듯이 폴백 전략은 단지 완전한 실패 가능성을 줄여 줄 뿐입니다. 기본(폴백이 아닌) 코드가 보다 강력해지면 서비스의 가용성이 훨씬 향상됩니다. 예를 들어, 서로 다른 두 데이터 저장소 간에 폴백 로직을 구현하는 대신 Amazon DynamoDB와 같이 기본적으로 고가용성을 제공하는 데이터베이스에 투자할 수 있습니다. 이 전략은 아마존 전체에서 빈번하게 사용됩니다. 여기에서는 Prime Day 2017에 amazon.com을 지원하기 위해 DynamoDB를 사용한 방식에 대해 설명하겠습니다.

호출자가 오류 처리

심각한 시스템 장애에 대한 한 가지 해결 방법은 폴백이 아니라 호출 시스템이 장애를 처리하도록 하는 것입니다(예를 들면, 재시도를 통해). 이것은 CLI 및 SDK에 이미 재시도 로직이 기본적으로 구축되어 있는 AWS 서비스에서 선호되는 전략입니다. 가능한 경우, 특히 운명을 공유하고 주요 사례의 실패 가능성을 줄이기 위해 충분한 노력을 기울인 상황에서(폴백 로직이 가용성을 전혀 향상시키지 못할 가능성이 높은 경우) 이 전략이 선호됩니다. 

선제적으로 데이터 푸시

폴백을 사용하기 위해 우리가 채택하는 또 다른 전술은 요청에 응답하는 구성 부분의 수를 줄이는 것입니다. 예를 들어 서비스가 요청을 충족하기 위해 데이터를 필요로 하는 경우 해당 데이터가 이미 로컬에 존재하면(페치할 필요가 없음) 장애 조치 전략을 사용할 필요가 없습니다. 이를 위한 성공적인 예는 Amazon EC2의 AWS Identity and Access Management(IAM) 역할 구현입니다. IAM 서비스는 서명된 순환 자격 증명을 EC2 인스턴스에서 실행되는 코드에 제공해야 합니다. 폴백할 필요가 없도록 자격 증명은 모든 인스턴스에 선제적으로 푸시되며 여러 시간 동안 유효합니다. 따라서 설사 푸시 메커니즘이 중단되더라도 IAM 역할 관련 요청은 제대로 동작할 수 있게 됩니다. 

폴백을 장애 조치로 전환

폴백의 가장 큰 단점 중 하나는 주기적으로 실행되지 않으며, 가동 중단 중에 실행되면 영향 범위가 증가하거나 실패할 가능성이 있다는 점입니다. 폴백을 발생시키는 상황은 몇 달, 심지어는 여러 해 동안이나 자연적으로 발생하지 않을 수 있습니다! 폴백 전략의 잠재적 장애 문제를 해결하기 위해서는 프로덕션에서 정기적으로 실행하는 것이 중요합니다. 서비스는 폴백 및 폴백이 아닌 로직을 모두 지속적으로 실행해야 합니다. 단순히 폴백 사례를 실행하는 것뿐 아니라 유효한 데이터 소스로 동등하게 취급해야 합니다. 예를 들어 서비스는 폴백과 폴백이 아닌 응답(둘 다 돌아올 경우) 간에 무작위로 선택하여 둘 다 작동하는지 확인합니다. 그러나 이 지점에서 이 전략은 더 이상 폴백을 고려하지 않으며 확실한 장애 조치 범주로 넘어갑니다.

재시도와 시간 제한이 폴백이 되지 않도록 보장

재시도와 시간 제한에 대한 내용은 시간 제한, 재시도 및 지터를 사용한 백오프 기사에서 설명합니다. 이 기사에서는 재시도가 일시적이면서도 무작위로 발생하는 오류에 대응하여 고가용성을 제공하기 위한 강력한 메커니즘이라고 말합니다. 달리 말하면 재시도와 시간 제한은 가짜 패킷 손실, 연관되지 않은 단일 시스템 장애 등과 같은 사소한 문제로 인해 이따금씩 발생하는 장애에 대한 보험으로 작용할 수 있습니다. 그러나 재시도와 시간 제한은 쉽게 잘못될 수 있습니다. 서비스는 여러 달 이상 여러 번의 재시도 없이 실행되는 경우가 많으며 결국 팀이 테스트해 보지 않은 상황에서 폴백이 시작될 수 있습니다. 이러한 이유 때문에 우리는 재시도가 자주 발생하는 경우 팀에 경고를 보낼 수 있도록 전체 재시도 비율과 경보를 모니터링하기 위한 지표를 유지 관리합니다.

재시도가 폴백으로 바뀌지 않도록 하는 다른 방법은 항상 선제적 재시도(헤징(hedging) 또는 병렬 요청이라고도 함)와 함께 실행하는 것입니다. 이 기술은 기본적으로 쿼럼 읽기 또는 쓰기를 수행하는 시스템에 구현되며, 시스템이 응답하기 위해서는 3대 중 2대의 서버 응답이 필요할 수 있습니다. 선제적 재시도는 지속 작업의 설계 패턴을 따릅니다. 항상 중복 요청이 이루어지기 때문에 중복 요청의 필요성이 증가할 때 재시도로 인한 추가적인 부하가 시스템에 추가되지는 않습니다.

결론

아마존에서는 효용성을 검증하기 어려우며 테스트가 어렵다는 점에서 시스템에 폴백을 적용하지 않으려고 합니다. 폴백 전략은 모든 것이 멈추는 가장 혼란스러운 순간에만 시스템에 작동 모드를 적용하며 이 모드로 전환할 경우 혼란이 커질 뿐입니다. 폴백 전략의 구현 시점과 프로덕션 환경에 들어가는 시점 간에는 긴 시간차가 있는 경우가 많습니다.

우리는 이따금씩이 아닌 지속적으로 프로덕션에서 실행되는 코드 경로를 선호합니다. 우리는 중요한 시점에 원격 호출을 가져와 실패 위험을 감수하는 대신 데이터를 필요한 시스템에 데이터를 푸시하는 것 같은 패턴을 사용함으로써 기본 시스템의 가용성 향상에 집중하고 있습니다. 결국 우리는 너무 많은 재시도를 수행하는 것처럼 폴백과 유사한 운영 모드로 전환될 수 있는 코드의 미묘한 동작에 집중합니다.

폴백이 시스템에서 핵심적인 역할을 하는 경우에는 폴백이 기본 운영 모드처럼 예측 가능하며 안정적으로 동작할 수 있도록 프로덕션에서 가능하면 자주 실행해야 합니다.


저자에 대하여

Jacob Gabrielson은 Amazon Web Services의 선임 수석 엔지니어입니다. 그는 Amazon에서 17년 동안 주로 내부 마이크로서비스 플랫폼과 관련된 작업을 해 왔습니다. 지난 8년 동안 소프트웨어 배포 시스템, 컨트롤 플레인 서비스, 스팟 시장, Lightsail, 그리고 최근에는 컨테이너를 포함하여 EC2 및 ECS에도 참여하고 있습니다. Jacob은 시스템 프로그래밍, 프로그래밍 언어 및 분산 컴퓨팅에 열정적으로 임하고 있습니다. 가장 싫어하는 것은 특히 실패 조건에서 이원화된 시스템 동작입니다. 그는 시애틀의 워싱턴 주립 대학에서 컴퓨터 공학 학사 학위를 갖고 있습니다.

시간 제한, 재시도 및 지터를 사용한 백오프 캐싱 관련 당면 과제 및 전략