Fair Call Queue 가이드

Fair Call Queue 가이드

이 문서는 Hadoop용 **Fair Call Queue(공정 호출 큐)**를 구성하고 관리하는 방법을 설명합니다.

출처: Fair Call Queue 가이드

전제 조건 (Prerequisites)

Hadoop이 올바르게 설치·구성·설정되었는지 확인하세요. 자세한 내용은 다음을 참고하면 됩니다.

  • 처음 사용자는 Single Node Setup.
  • 대규모 분산 클러스터는 Cluster Setup.

개요 (Overview)

Hadoop 서버 구성요소, 특히 HDFS NameNode는 클라이언트로부터 매우 많은 RPC 부하를 받습니다. 기본적으로 모든 클라이언트 요청은 선입선출(FIFO) 큐로 라우팅되어 도착한 순서대로 처리됩니다. 이는 매우 많은 요청을 제출하는 단일 사용자가 쉽게 서비스를 압도해 다른 모든 사용자에게 열악한 서비스를 초래할 수 있음을 뜻합니다. Fair Call Queue와 관련 구성요소는 이런 영향을 완화하는 것을 목표로 합니다.

설계 세부 사항 (Design Details)

IPC 스택에는 서로 복잡하게 상호작용하는 몇 가지 구성요소가 있으며, 각각 고유한 튜닝 파라미터를 가집니다. 아래 이미지는 이들의 상호작용에 대한 개략적 개요를 보여주며, 자세한 내용은 아래에서 설명합니다.

다음 설명에서 굵은 글씨는 명명된 개체 또는 구성 가능 항목을 가리킵니다.

클라이언트가 IPC 서버에 요청을 보내면 이 요청은 먼저 **리스닝 큐(listen queue)**에 들어갑니다. **리더 스레드(Reader thread)**는 이 큐에서 요청을 꺼내 구성 가능한 RpcScheduler에 전달해 우선순위를 할당받고 **호출 큐(call queue)**에 넣습니다. 이 자리에 FairCallQueue가 플러그형 구현으로 있습니다(기존의 다른 구현은 FIFO 큐). **핸들러 스레드(Handler thread)**는 호출 큐에서 요청을 꺼내 처리하고 클라이언트에 응답합니다.

FairCallQueue와 함께 기본적으로 사용되는 RpcScheduler 구현은 DecayRpcScheduler입니다. 이는 각 사용자에 대해 받은 요청 수를 유지합니다. 이 수는 시간이 지나며 감소(decay)합니다. 매 스윕(sweep) 주기(기본 5초)마다 사용자별 요청 수에 감쇠 인자(decay factor, 기본 0.5)를 곱합니다. 이렇게 하여 사용자별 요청 수의 가중/이동 평균을 유지합니다. 스윕이 수행될 때마다 알려진 모든 사용자의 호출 수가 높은 순에서 낮은 순으로 정렬됩니다. 각 사용자는 해당 사용자로부터 발생한 호출 비율에 따라 우선순위(기본 0-3, 0이 최고 우선순위)를 할당받습니다. 기본 우선순위 임계값은 (0.125, 0.25, 0.5)로, 호출이 전체의 50% 이상을 차지하는 사용자(그런 사용자는 최대 한 명일 수 있음)는 가장 낮은 우선순위에, 총 호출의 25%~50%를 차지하는 사용자는 두 번째로 낮은 우선순위에, 12.5%~25%를 차지하는 사용자는 두 번째로 높은 우선순위에, 그 외 모든 사용자는 가장 높은 우선순위에 놓입니다. 스윕이 끝나면 각 알려진 사용자는 캐시된 우선순위를 가지며, 이는 다음 스윕까지 사용됩니다. 스윕 사이에 나타난 새 사용자는 우선순위가 즉석(on-the-fly)에서 계산됩니다.

FairCallQueue 내부에는 여러 우선순위 큐가 있으며 각각 가중치(weight)가 지정됩니다. 요청이 호출 큐에 도착하면 RpcScheduler가 할당한 현재 우선순위에 따라 이 우선순위 큐 중 하나에 배치됩니다. 핸들러 스레드가 호출 큐에서 항목을 가져오려고 할 때 어느 큐에서 가져올지는 RpcMultiplexer가 결정합니다. 현재 이는 **WeightedRoundRobinMultiplexer(WRRM)**로 하드코딩되어 있습니다. WRRM은 가중치에 따라 큐에서 요청을 처리합니다. 기본 4개 우선순위 레벨의 기본 가중치는 (8, 4, 2, 1)입니다. 따라서 WRRM은 최고 우선순위 큐에서 8개, 두 번째로 높은 큐에서 4개, 세 번째로 높은 큐에서 2개, 가장 낮은 큐에서 1개를 처리한 다음 다시 최고 우선순위 큐에서 8개를 처리하는 식입니다.

위에서 논의한 우선순위-가중치 메커니즘 외에도 구성 가능한 백오프(backoff) 메커니즘이 있습니다. 서버가 요청을 처리하는 대신 클라이언트에 예외를 던지고, 클라이언트는 다시 시도하기 전에 잠시 기다려야(예: 지수 백오프) 합니다. 일반적으로 백오프는 FCQ의 우선순위 큐에 요청을 넣으려고 시도할 때 그 큐가 가득 찬 경우 트리거됩니다. 이는 영향력 있는 클라이언트를 더 밀어내 부하를 줄여 상당한 이점을 얻을 수 있습니다. 또한 응답 시간에 의한 백오프(backoff by response time) 기능이 있는데, 이는 더 높은 우선순위 레벨의 요청이 너무 느리게 처리되고 있을 때 더 낮은 우선순위 레벨의 요청이 백오프하도록 합니다. 예를 들어 우선순위 1의 응답 시간 임계값이 10초로 설정되었지만 해당 큐의 평균 응답 시간이 12초라면, 우선순위 2 이하의 수신 요청은 백오프 예외를 받고 우선순위 0과 1의 요청은 정상적으로 진행됩니다. 의도는 전체 시스템 부하가 높은 우선순위 클라이언트에 영향을 줄 만큼 높을 때 더 무거운 클라이언트를 강제로 백오프시키는 것입니다.

위 논의는 스로틀링을 위해 요청을 그룹화하는 방법과 관련해 요청의 사용자를 언급했습니다. 이는 **identity provider(식별자 제공자)**를 통해 구성 가능하며 기본값은 UserIdentityProvider입니다. 사용자 식별자 제공자는 단순히 요청을 제출하는 클라이언트의 사용자 이름을 사용합니다. 그러나 사용자 지정 identity provider를 사용해 다른 그룹을 기준으로 스로틀링하거나 외부 identity provider를 사용할 수 있습니다.

특정 사용자가 중요한 요청을 제출해 제한하고 싶지 않다면 이를 **service-users(서비스 사용자)**로 설정할 수 있습니다. 이들은 항상 높은 우선순위 큐로 스케줄링되며 일반 사용자 호출의 우선순위 계산에 포함되지 않습니다.

비용 기반 Fair Call Queue (Cost-based Fair Call Queue)

fair call queue 자체는 매우 많은 수의 요청을 제출하는 사용자의 영향을 완화하는 데 좋은 역할을 하지만, 각 요청을 처리하는 데 얼마나 비용이 드는지는 고려하지 않습니다. 따라서 HDFS NameNode를 고려할 때 1000개의 "getFileInfo" 요청을 제출하는 사용자와, 매우 큰 디렉터리에서 1000개의 "listStatus" 요청을 제출하는 사용자, 또는 네임시스템에 대한 배타적 잠금이 필요해 더 비싼 1000개의 "mkdir" 요청을 제출하는 사용자는 동일하게 우선순위가 매겨집니다. 사용자 요청의 우선순위를 고려할 때 연산의 비용을 반영하기 위해, 사용자의 연산 총 처리 시간을 사용해 그 사용자가 어떻게 우선순위가 매겨질지 결정하는 "비용 기반" 확장이 Fair Call Queue에 있습니다. 기본적으로 큐 시간(처리 대기 시간)과 잠금 대기 시간(잠금 획득 대기 시간)은 비용에 포함되지 않고, 잠금 없이 처리하는 시간은 중립적으로(1x) 가중되며, 공유 잠금으로 처리하는 시간은 10배 더 높게, 배타적 잠금으로 처리하는 시간은 100배 더 높게 가중됩니다. 이는 사용자들이 서버에 실제로 가하는 부하에 따라 사용자 우선순위를 정하려는 시도입니다. 이 기능을 활성화하려면 아래 설명처럼 costprovider.impl 설정을 org.apache.hadoop.ipc.WeightedTimeCostProvider로 설정하세요.

설정 (Configuration)

이 절에서는 fair call queue를 구성하는 방법을 설명합니다.

설정 접두사 (Configuration Prefixes)

모든 호출 큐 관련 설정은 단일 IPC 서버에만 관련됩니다. 이를 통해 단일 설정 파일로 서로 다른 구성요소, 또는 구성요소 내의 서로 다른 IPC 서버가 고유하게 구성된 호출 큐를 갖도록 구성할 수 있습니다. 각 설정은 ipc.<port_number>로 접두사가 붙으며, 여기서 <port_number>는 구성할 IPC 서버가 사용하는 포트입니다. 예를 들어 ipc.8020.callqueue.impl는 포트 8020에서 실행되는 IPC 서버의 호출 큐 구현을 조정합니다. 이 절의 나머지에서는 이 접두사를 생략합니다.

전체 설정 목록

설정 키 (Configuration Key) 적용 구성요소 설명 기본값
backoff.enable General Whether or not to enable client backoff when a queue is full. false
callqueue.impl General The fully qualified name of a class to use as the implementation of a call queue. Use org.apache.hadoop.ipc.FairCallQueue for the Fair Call Queue. java.util.concurrent.LinkedBlockingQueue (FIFO queue)
scheduler.impl General The fully qualified name of a class to use as the implementation of the scheduler. Use org.apache.hadoop.ipc.DecayRpcScheduler in conjunction with the Fair Call Queue. org.apache.hadoop.ipc.DefaultRpcScheduler (no-op scheduler) If using FairCallQueue, defaults to org.apache.hadoop.ipc.DecayRpcScheduler
scheduler.priority.levels RpcScheduler, CallQueue How many priority levels to use within the scheduler and call queue. 4
faircallqueue.multiplexer.weights WeightedRoundRobinMultiplexer How much weight to give to each priority queue. This should be a comma-separated list of length equal to the number of priority levels. Weights descend by a factor of 2 (e.g., for 4 levels: 8,4,2,1)
identity-provider.impl DecayRpcScheduler The identity provider mapping user requests to their identity. org.apache.hadoop.ipc.UserIdentityProvider
cost-provider.impl DecayRpcScheduler The cost provider mapping user requests to their cost. To enable determination of cost based on processing time, use org.apache.hadoop.ipc.WeightedTimeCostProvider. org.apache.hadoop.ipc.DefaultCostProvider
decay-scheduler.period-ms DecayRpcScheduler How frequently the decay factor should be applied to the operation counts of users. Higher values have less overhead, but respond less quickly to changes in client behavior. 5000
decay-scheduler.decay-factor DecayRpcScheduler When decaying the operation counts of users, the multiplicative decay factor to apply. Higher values will weight older operations more strongly, essentially giving the scheduler a longer memory, and penalizing heavy clients for a longer period of time. 0.5
decay-scheduler.thresholds DecayRpcScheduler The client load threshold, as an integer percentage, for each priority queue. Clients producing less load, as a percent of total operations, than specified at position i will be given priority i. This should be a comma-separated list of length equal to the number of priority levels minus 1 (the last is implicitly 100). Thresholds ascend by a factor of 2 (e.g., for 4 levels: 13,25,50)
decay-scheduler.backoff.responsetime.enable DecayRpcScheduler Whether or not to enable the backoff by response time feature. false
decay-scheduler.backoff.responsetime.thresholds DecayRpcScheduler The response time thresholds, as time durations, for each priority queue. If the average response time for a queue is above this threshold, backoff will occur in lower priority queues. This should be a comma-separated list of length equal to the number of priority levels. Threshold increases by 10s per level (e.g., for 4 levels: 10s,20s,30s,40s)
decay-scheduler.metrics.top.user.count DecayRpcScheduler The number of top (i.e., heaviest) users to emit metric information about. 10
decay-scheduler.service-users DecayRpcScheduler Service users will always be scheduled into the highest-priority queue and won’t be included in the priority computation of normal user calls. They are specified as a comma-separated list.
weighted-cost.lockshared WeightedTimeCostProvider The weight multiplier to apply to the time spent in the processing phase which holds a shared (read) lock. 10
weighted-cost.lockexclusive WeightedTimeCostProvider The weight multiplier to apply to the time spent in the processing phase which holds an exclusive (write) lock. 100
weighted-cost.{handler,lockfree,response} WeightedTimeCostProvider The weight multiplier to apply to the time spent in the processing phases which do not involve holding a lock. See org.apache.hadoop.ipc.ProcessingDetails.Timing for more details on each phase. 1

예시 설정 (Example Configuration)

다음은 포트 8020의 IPC 서버가 FairCallQueue와 DecayRpcScheduler를 사용하고 우선순위 레벨이 2개뿐이도록 구성하는 예시입니다. 가장 무거운 사용자 10%는 크게 불이익을 받아 처리되는 총 요청의 1%만 부여받습니다.

<property>
     <name>ipc.8020.callqueue.impl</name>
     <value>org.apache.hadoop.ipc.FairCallQueue</value>
</property>
<property>
     <name>ipc.8020.callqueue.capacity.weights</name>
     <value>7,3</value>
</property>
<property>
     <name>ipc.8020.scheduler.impl</name>
     <value>org.apache.hadoop.ipc.DecayRpcScheduler</value>
</property>
<property>
     <name>ipc.8020.scheduler.priority.levels</name>
     <value>2</value>
</property>
<property>
     <name>ipc.8020.faircallqueue.multiplexer.weights</name>
     <value>99,1</value>
</property>
<property>
     <name>ipc.8020.decay-scheduler.thresholds</name>
     <value>90</value>
</property>

더 알아보기 (Learn more)