외부 리소스 프레임워크
외부 리소스 프레임워크
CPU와 메모리 외에도 많은 워크로드는 딥러닝용 GPU 같은 다른 리소스도 필요로 합니다. 외부 리소스를 지원하기 위해 Flink는 외부 리소스 프레임워크를 제공합니다. 이 프레임워크는 하부 리소스 관리 시스템(예: Kubernetes)에서 다양한 유형의 리소스를 요청하는 것을 지원하며, 이러한 리소스를 사용하는 데 필요한 정보를 연산자에 제공합니다. 다양한 리소스 유형을 지원할 수 있습니다. Flink가 제공하는 내장 플러그인(현재는 GPU 지원만)을 활용하거나 사용자 지정 리소스 유형에 대한 자체 플러그인을 구현할 수 있습니다.
출처: 문서
본문
외부 리소스 프레임워크가 하는 일
일반적으로 외부 리소스 프레임워크는 두 가지를 수행합니다.
- 구성에 따라 리소스 요청의 해당 필드를 설정합니다(하부 시스템에서 리소스를 요청하기 위해).
- 연산자에 리소스 사용에 필요한 정보를 제공합니다.
리소스 관리 시스템(Kubernetes / Yarn)에 배포될 때 외부 리소스 프레임워크는 할당된 pod/컨테이너가 원하는 외부 리소스를 포함하도록 보장합니다. 현재 많은 리소스 관리 시스템이 외부 리소스를 지원합니다. 예를 들어 Kubernetes는 v1.10부터 Device Plugin 메커니즘을 통해 GPU, FPGA 등을 지원하고, Yarn은 2.10과 3.1부터 GPU와 FPGA 리소스를 지원합니다. Standalone 모드에서는 사용자가 외부 리소스가 사용 가능함을 보장해야 합니다.
외부 리소스 프레임워크는 해당 정보를 연산자에 제공합니다. 리소스 사용에 필요한 기본 속성을 포함하는 외부 리소스 정보는 구성된 외부 리소스 *드라이버(driver)*에 의해 생성됩니다.
워크로드에 외부 리소스 프레임워크 활성화
외부 리소스 프레임워크로 외부 리소스를 활성화하려면 다음을 수행해야 합니다.
- 외부 리소스 플러그인을 준비합니다.
- 외부 리소스에 대한 구성을 설정합니다.
RuntimeContext에서 외부 리소스 정보를 가져와 연산자에서 사용합니다.
플러그인 준비
외부 리소스 플러그인을 준비하여 Flink 배포판의 plugins/ 폴더에 넣어야 합니다. Flink Plugins 참조. Apache Flink는 GPU 리소스용 퍼스트파티 플러그인을 제공합니다. 사용자 지정 리소스 유형에 대한 플러그인을 구현할 수도 있습니다.
구성
먼저 모든 외부 리소스 유형의 리소스 이름을 **외부 리소스 목록(구성 키 'external-resources')**에 구분자 ";"로 추가해야 합니다. 예: 두 개의 외부 리소스 "gpu"와 "fpga"에 대해 "external-resources: gpu;fpga". 여기 정의된 **<resource_name>**만 외부 리소스 프레임워크에서 유효합니다.
각 외부 리소스에 대해 아래 옵션을 구성할 수 있습니다. 아래 모든 구성 옵션의 **<resource_name>**은 외부 리소스 목록에 나열된 이름에 해당합니다.
- Amount (
external.<resource_name>.amount): 외부 시스템에서 요청해야 하는 외부 리소스의 수량입니다. - Config key in Yarn (
external-resource.<resource_name>.yarn.config-key): 선택. 구성되면 외부 리소스 프레임워크가 이 키를 Yarn의 컨테이너 요청 리소스 프로필에 추가합니다. 값은external-resource.<resource_name>.amount의 값으로 설정됩니다. - Config key in Kubernetes (
external-resource.<resource_name>.kubernetes.config-key): 선택. 구성되면 외부 리소스 프레임워크가 TaskManager의 메인 컨테이너 스펙에resources.limits.<config-key>와resources.requests.<config-key>를 추가하고 값을external-resource.<resource_name>.amount의 값으로 설정합니다. - Driver Factory (
external-resource.<resource_name>.driver-factory.class): 선택 **<resource_name>**으로 식별되는 외부 리소스의 팩토리 클래스 이름을 정의합니다. 구성되면 팩토리가 외부 리소스 프레임워크에서 드라이버를 인스턴스화하는 데 사용됩니다. 구성되지 않으면 관련 옵션이 구성되는 한 요청된 리소스는 여전히TaskManager에 존재합니다. 그러나 그 경우 연산자는RuntimeContext에서 리소스에 대한 어떤 정보도 얻지 못합니다. - Driver Parameters (
external-resource.<resource_name>.param.<param>): 선택 **<resource_name>**으로 지정된 외부 리소스에 대한 사용자 지정 구성 옵션의 명명 패턴입니다. 이 패턴을 따르는 구성만 해당 외부 리소스의 드라이버 팩토리로 전달됩니다.
두 개의 외부 리소스를 지정하는 예시 구성:
external-resources: gpu;fpga # Define two external resources, "gpu" and "fpga".
external-resource.gpu.driver-factory.class: org.apache.flink.externalresource.gpu.GPUDriverFactory # Define the driver factory class of gpu resource.
external-resource.gpu.amount: 2 # Define the amount of gpu resource per TaskManager.
external-resource.gpu.param.discovery-script.args: --enable-coordination # Define the custom param discovery-script.args which will be passed into the gpu driver.
external-resource.fpga.driver-factory.class: org.apache.flink.externalresource.fpga.FPGADriverFactory # Define the driver factory class of fpga resource.
external-resource.fpga.amount: 1 # Define the amount of fpga resource per TaskManager.
external-resource.fpga.yarn.config-key: yarn.io/fpga # Define the corresponding config key of fpga in Yarn.
리소스 사용
리소스를 사용하려면 연산자는 RuntimeContext에서 ExternalResourceInfo 집합을 가져와야 합니다. ExternalResourceInfo는 리소스 사용에 필요한 정보를 감싸며, getProperty로 검색할 수 있습니다. 어떤 속성이 사용 가능하고 속성으로 리소스에 접근하는 방법은 특정 플러그인에 따라 달라집니다.
연산자는 getExternalResourceInfos(String resourceName)으로 RuntimeContext 또는 FunctionContext에서 특정 외부 리소스의 ExternalResourceInfo 집합을 가져올 수 있습니다. 여기의 resourceName은 외부 리소스 목록에 구성된 이름과 같은 값을 가져야 합니다. 다음과 같이 사용할 수 있습니다.
public class ExternalResourceMapFunction extends RichMapFunction<String, String> {
private static final String RESOURCE_NAME = "foo";
@Override
public String map(String value) {
Set<ExternalResourceInfo> externalResourceInfos = getRuntimeContext().getExternalResourceInfos(RESOURCE_NAME);
List<String> addresses = new ArrayList<>();
externalResourceInfos.iterator().forEachRemaining(externalResourceInfo ->
addresses.add(externalResourceInfo.getProperty("address").get()));
// map function with addresses.
// ...
}
}
각 ExternalResourceInfo는 리소스의 서로 다른 차원을 나타내는 키를 가진 하나 이상의 속성을 포함합니다. 모든 유효한 키는 ExternalResourceInfo#getKeys로 얻을 수 있습니다.
참고: 현재 RuntimeContext#getExternalResourceInfos가 반환하는 정보는 모든 연산자에서 사용할 수 있습니다.
사용자 지정 리소스 유형용 플러그인 구현
사용자 지정 리소스 유형용 플러그인을 구현하려면 다음을 수행해야 합니다.
org.apache.flink.api.common.externalresource.ExternalResourceDriver인터페이스를 구현하여 자체 외부 리소스 드라이버를 추가합니다.org.apache.flink.api.common.externalresource.ExternalResourceDriverFactory를 구현하여 드라이버를 인스턴스화하는 드라이버 팩토리를 추가합니다.- 서비스 항목을 추가합니다. 드라이버 팩토리 클래스의 클래스 이름을 포함하는
META-INF/services/org.apache.flink.api.common.externalresource.ExternalResourceDriverFactory파일을 만듭니다(Java Service Loader 문서 참조).
예를 들어 "FPGA"라는 외부 리소스용 플러그인을 구현하려면 먼저 FPGADriver와 FPGADriverFactory를 구현해야 합니다.
public class FPGADriver implements ExternalResourceDriver {
@Override
public Set<FPGAInfo> retrieveResourceInfo(long amount) {
// return the information set of "FPGA"
}
}
public class FPGADriverFactory implements ExternalResourceDriverFactory {
@Override
public ExternalResourceDriver createExternalResourceDriver(Configuration config) {
return new FPGADriver();
}
}
// Also implement FPGAInfo which contains basic properties of "FPGA" resource.
public class FPGAInfo implements ExternalResourceInfo {
@Override
public Optional<String> getProperty(String key) {
// return the property with the given key.
}
@Override
public Collection<String> getKeys() {
// return all property keys.
}
}
META-INF/services/에 이름이 org.apache.flink.api.common.externalresource.ExternalResourceDriverFactory인 파일을 만들고 거기에 팩토리 클래스 이름(예: your.domain.FPGADriverFactory)을 씁니다.
그런 다음 FPGADriver, FPGADriverFactory, META-INF/services/와 모든 외부 의존성을 포함하는 jar를 만듭니다. Flink 배포판의 plugins/에 임의의 이름(예: "fpga")으로 디렉터리를 만들고 jar를 이 디렉터리에 넣습니다. 자세한 내용은 Flink Plugin을 참조하세요.
참고: 외부 리소스는 같은 머신에서 실행되는 모든 연산자가 공유합니다. 커뮤니티는 향후 릴리스에서 외부 리소스 격리를 추가할 수 있습니다.
기존에 지원되는 외부 리소스 플러그인
현재 Flink는 외부 리소스로 GPU를 지원합니다.
GPU 리소스용 플러그인
우리는 GPU 리소스용 퍼스트파티 플러그인을 제공합니다. 이 플러그인은 발견 스크립트를 활용해 GPU 장치의 인덱스를 발견하며, 리소스 정보에서 "index" 속성으로 접근할 수 있습니다. NVIDIA GPU를 발견하는 데 사용할 수 있는 기본 발견 스크립트를 제공합니다. 사용자 지정 스크립트를 제공할 수도 있습니다.
Flink에서 GPU로 행렬-벡터 곱셈을 수행하는 방법을 보여주는 예시를 제공합니다.
참고: 현재 모든 연산자에 대해 RuntimeContext#getExternalResourceInfos는 같은 리소스 정보 집합을 반환합니다. 즉, 같은 TaskManager에서 실행되는 모든 연산자에 항상 같은 GPU 장치 집합이 접근 가능합니다. 현재 연산자 수준 격리는 없습니다.
사전 요구사항
GPU 리소스에 접근 가능하게 하려면 환경에 따라 특정 사전 요구사항이 필요합니다.
- Standalone 모드의 경우 관리자는 NVIDIA 드라이버가 설치되어 있고 클러스터의 모든 노드에서 GPU 리소스에 접근할 수 있도록 해야 합니다.
- Yarn 배포의 경우 관리자는 Yarn 클러스터를 GPU scheduling을 활성화하도록 구성해야 합니다. 필요한 Hadoop 버전은 2.10+ 또는 3.1+입니다.
- Kubernetes 배포의 경우 관리자는 NVIDIA GPU device plugin이 설치되어 있는지 확인해야 합니다. 필요한 버전은 1.10+입니다. 현재 Kubernetes는 NVIDIA GPU와 AMD GPU만 지원합니다. Flink는 NVIDIA GPU용 발견 스크립트만 제공하지만 AMD GPU용 사용자 지정 발견 스크립트를 직접 제공할 수 있습니다. Discovery script 참조.
워크로드에 GPU 리소스 활성화
워크로드에 외부 리소스 활성화에서 언급했듯이 GPU 리소스를 활성화하려면 두 가지를 해야 합니다.
- GPU 리소스를 구성합니다.
- 연산자에서 키가 "index"인 속성으로 GPU 인덱스를 포함하는 GPU 리소스의 정보를 가져옵니다.
구성
GPU 플러그인의 경우 일반 외부 리소스 구성을 지정해야 합니다.
external-resources: GPU 리소스에 대해 리소스 이름(예: gpu)을 추가해야 합니다.external-resource.<resource_name>.amount: TaskManager당 GPU 장치 수입니다.external-resource.<resource_name>.yarn.config-key: Yarn의 경우 GPU의 구성 키는yarn.io/gpu입니다. Yarn은 현재 NVIDIA GPU만 지원합니다.external-resource.<resource_name>.kubernetes.config-key: Kubernetes의 경우 GPU의 구성 키는<vendor>.com/gpu입니다. 현재 "nvidia"와 "amd"가 두 지원 벤더입니다. AMD GPU를 사용하면 발견 스크립트를 직접 제공해야 합니다. Discovery script 참조.- external-resource.<resource_name>.driver-factory.class: org.apache.flink.externalresource.gpu.GPUDriverFactory로 설정해야 합니다.
또한 GPU 플러그인에는 특정 구성이 있습니다.
| Key | Default | Type | Description |
|---|---|---|---|
| external-resource.<resource_name>.param.discovery-script.args | (none) | String | 발견 스크립트에 전달되는 인수입니다. 기본 발견 스크립트의 사용 가능한 매개변수는 Default Script를 참조하세요. |
| external-resource.<resource_name>.param.discovery-script.path | "plugins/external-resource-gpu/nvidia-gpu-discovery.sh" | String | 발견 스크립트의 경로입니다. 절대 경로이거나, 정의된 경우 FLINK_HOME에 대한 상대 경로, 그렇지 않으면 현재 디렉터리에 대한 상대 경로일 수 있습니다. 명시적으로 구성하지 않으면 기본 스크립트가 사용됩니다. |
GPU 리소스에 대한 예시 구성:
external-resources: gpu
external-resource.gpu.driver-factory.class: org.apache.flink.externalresource.gpu.GPUDriverFactory # Define the driver factory class of gpu resource.
external-resource.gpu.amount: 2 # Define the amount of gpu resource per TaskManager.
external-resource.gpu.param.discovery-script.path: plugins/external-resource-gpu/nvidia-gpu-discovery.sh
external-resource.gpu.param.discovery-script.args: --enable-coordination # Define the custom param "discovery-script.args" which will be passed into the gpu driver.
external-resource.gpu.yarn.config-key: yarn.io/gpu # for Yarn
external-resource.gpu.kubernetes.config-key: nvidia.com/gpu # for Kubernetes
발견 스크립트
GPUDriver는 발견 스크립트를 활용해 GPU 리소스를 발견하고 GPU 리소스 정보를 생성합니다.
기본 스크립트
NVIDIA GPU용 기본 발견 스크립트를 제공하며, Flink 배포판의 plugins/external-resource-gpu/nvidia-gpu-discovery.sh에 있습니다. 이 스크립트는 nvidia-smi 명령을 통해 보이는 GPU 리소스의 인덱스를 가져옵니다. 필요한 수량(external-resource.<resource_name>.amount로 지정)의 GPU 인덱스를 목록으로 반환하려고 시도하며, 수량을 충족할 수 없으면 0이 아닌 값으로 종료합니다.
Standalone 모드의 경우 여러 TaskManager가 같은 머신에 함께 배치될 수 있으며, 각 GPU 장치는 모든 TaskManager에 보입니다. 기본 발견 스크립트는 조정(coordination) 모드를 지원합니다. 이 모드에서 조정 파일을 활용해 GPU 장치의 할당 상태를 동기화하고 각 GPU 장치가 하나의 TaskManager 프로세스에만 사용될 수 있도록 합니다. 관련 인수는 다음과 같습니다.
--enable-coordination-mode: 조정 모드를 활성화합니다. 기본적으로 조정 모드는 비활성화되어 있습니다.--coordination-file filePath: GPU 리소스의 할당 상태를 동기화하는 데 사용되는 조정 파일의 경로입니다. 기본 경로는/var/tmp/flink-gpu-coordination입니다.
참고: 조정 모드는 GPU 장치가 같은 Flink 클러스터의 여러 TaskManager에 공유되지 않도록만 보장합니다. 다른 Flink 클러스터(다른 조정 파일 사용)나 비-Flink 애플리케이션이 같은 GPU 장치를 계속 사용할 수 있다는 점에 유의하세요.
사용자 지정 스크립트
AMD GPU 발견 같은 사용자 지정 요구사항을 해결하기 위해 발견 스크립트를 제공할 수도 있습니다. 사용자 지정 스크립트의 경로가 Flink에 접근 가능하고 올바르게 구성(external-resource.<resource_name>.param.discovery-script.path)되었는지 확인하세요. 발견 스크립트의 계약:
GPUDriver는 수량(external-resource.<resource_name>.amount로 지정)을 스크립트의 첫 번째 인수로 전달합니다.external-resource.<resource_name>.param.discovery-script.args의 사용자 정의 인수는 그 뒤에 추가됩니다.- 스크립트는 컴마로 구분된 사용 가능한 GPU 인덱스 목록을 반환해야 합니다. 공백만 있는 인덱스는 무시됩니다.
- 스크립트는 0이 아닌 값으로 종료하여 발견이 제대로 수행되지 않았음을 제안할 수도 있습니다. 그 경우 연산자에 gpu 정보가 제공되지 않습니다.