운영 체제 성능 향상을 위한 커널 잠금 최적화

성능이 가장 중요하며 시스템 성능 개선은 모든 엔지니어가 추구하는 것입니다. 현재 성능 최적화는 시스템 소프트웨어 스택의 비효율성을 제거하거나 오버헤드가 높은 시스템 작업을 우회하는 데 중점을 둡니다. 예를 들어 커널 바이패스는 사용자 공간에서 여러 작업을 이동하고 특정 클래스의 응용 프로그램에 대한 기본 운영 체제를 리팩터링하여 이 목표를 달성합니다.

많은 영역에서 전문화는 응용 프로그램과 커널 모두에서, 심지어 서로 다른 커널 하위 시스템 간에 더 나은 성능을 위한 해답인 것 같습니다. 특히 전문화는 애플리케이션이 시스템에서 특정 기능을 요청하는 컨텍스트를 구축할 수 있습니다. 응용 프로그램 전문화와 커널이 스토리지, 네트워킹 및 가속기를 우회하는 동안 커널의 동시성 제어는 전반적인 성능에 중요할 수 있습니다.

af6e92d3997d53bd27210b0d7a3e1f7f.jpeg

1. 운영 체제의 성능: 커널 잠금

커널 잠금은 공유 리소스에 대한 프로세스 액세스를 제어하기 위한 메커니즘입니다. Linux 커널에서 커널 잠금은 프로세스 생성 시 특수 잠금을 할당하여 구현됩니다. 프로세스가 공유 리소스에 액세스해야 하는 경우 커널은 프로세스가 이미 잠금을 보유하고 있는지 여부를 확인하고 그렇지 않은 경우 해당 프로세스는 잠금을 기다리는 큐에 추가하고 다른 프로세스가 잠금을 해제할 때까지 기다립니다.

커널 잠금은 응용 프로그램의 우수한 성능과 확장성을 달성하는 데 매우 중요하지만 커널 동기화 프리미티브는 일반적으로 보이지 않으며 응용 프로그램 개발자의 손이 닿지 않는 곳에 있습니다. 잠금 알고리즘을 설계하고 그 정확성을 검증하는 것은 이미 어려운 일이며 하드웨어 이질성이 증가함에 따라 더욱 어려워지고 있습니다. 잠금이 작동하는 환경에 대한 개발자의 인식 부족, 우선 순위 반전 및 잠금 소유자 우선 순위와 같은 문제는 본질적으로 컨텍스트 부족입니다.

사용자 공간 애플리케이션이 커널에서 동시성 제어를 조정할 수 있는 방법이 있습니까?

예를 들어 사용자는 일련의 잠금을 보유하는 특정 작업 또는 시스템 호출의 우선 순위를 지정할 수 있습니다. 사용자는 비대칭 다중 처리 인식 잠금과 같은 하드웨어별 정책을 시행할 수 있으며 주어진 워크로드를 기반으로 읽기 및 쓰기의 우선 순위를 지정할 수 있습니다. 개발자가 커널의 다양한 잠금을 조정하고, 해당 매개변수와 동작을 변경하고, 다른 잠금 구현 간에도 변경할 수 있는 경우 시스템 성능을 더욱 향상시킬 수 있습니다.

소프트웨어 스택 전문화는 애플리케이션 성능을 개선하는 새로운 방법으로, 성능을 위해 코드를 코어에 푸시하고 코어 수 증가로 인한 병목 현상을 방지하여 애플리케이션 확장성을 개선할 것을 제안합니다. 시간이 지남에 따라 Linux와 같은 모놀리식 커널도 사용자 공간 응용 프로그램에서 커널 동작을 사용자 정의할 수 있게 되었습니다. 개발자는 eBPF를 사용하여 추적, 보안 및 성능 목적을 위해 커널을 사용자 정의할 수 있습니다.

eBPF 외에도 Linux 개발자는 사용자 공간과 커널 간의 공유 메모리 링 버퍼인 io_uring을 사용하여 비동기 IO 작업 속도를 높이고 있습니다. 또한 오늘날의 애플리케이션은 온디맨드 페이징을 사용자 공간에서 완전히 처리할 수 있습니다.

응용 프로그램은 잠금 설계자와 응용 프로그램 개발자에게 다양한 기회를 제공하는 기본 커널의 동시성 메커니즘을 제어합니다.

30c0203fd2d8ff2a815ff370069c651b.jpeg

2. 자물쇠: 과거, 현재, 미래

하드웨어는 잠금의 확장성을 결정하는 주요 요소이므로 애플리케이션 확장성에 영향을 미칩니다. 예를 들어 대기열 기반 잠금을 사용하면 여러 스레드가 동시에 잠금을 획득할 때 과도한 트래픽을 줄일 수 있습니다. 동시에 계층적 잠금은 일괄 처리를 사용하여 캐시 라인 스래싱 문제를 최소화합니다.

SHFLLock은 커널 메모리 오버헤드와 성능 저하를 줄이기 위해 잠금 전략과 구현을 분리하여 잠금 알고리즘을 설계하는 새로운 아이디어를 제안합니다. 대기열을 재정렬하거나 대기 중인 스레드의 상태를 수정하는 shuffler 프로그램의 개념을 주로 소개합니다. ShflLocks는 정책을 적용하는 방법을 제공하지만 간단한 잠금 획득/해제 API 세트보다 공통 정책에 집중하려는 시도도 있습니다. 응용 프로그램 요구 사항을 충족하기 위해 응용 프로그램 개발자는 지정된 워크로드에 영향을 미치는 특정 커널 잠금을 분석하여 제어되고 안전한 방식으로 정책을 정의하고 셔플러를 사용하여 잠금 획득 정책을 동적으로 업데이트하여 정책을 시행해야 합니다.

3 일반적인 시나리오: 잠금을 기다리는 스레드 예약

잠금을 기다리는 스레드는 두 가지 방법으로 예약할 수 있습니다. 잠금이 획득된 순서에 기반한 획득 인식 스케줄링과 스레드가 임계 영역 내에서 소비하는 시간에 기반한 점유 인식 스케줄링입니다.

3.1 획득 인식 스케줄링

개발자가 다양한 잠금 알고리즘 간에 전환할 수 있도록 하는 잠금 스위치. 눈에 띄는 세 가지 상황이 있습니다.

  1. 읽기 집약적인 워크로드를 위해 중립적인 리더-작성기 잠금 디자인에서 CPU당 또는 NUMA 기반 리더 디자인으로 전환합니다.예를 들어, 페이지 폴트 및 디렉토리의 파일 열거 다른 경우는 중립적인 읽기-쓰기 잠금 스위치에서 발생합니다. 순수한 쓰기 잠금으로, 예를 들어 디렉토리에 여러 파일을 생성합니다.

  2. Numa 기반 잠금 설계에서 잠금 보유자가 대기 중인 스레드를 대신하여 작업을 수행하는 Numa 인식과 결합된 접근 방식으로 전환합니다. 이 접근 방식은 적어도 하나의 캐시된 전송을 제거하므로 더 나은 성능을 제공합니다.

  3. 예를 들어 SHFLLock의 셔플러 기능의 중지/깨우기 전략을 끄고 차단 읽기를 비차단 읽기-쓰기 잠금(rwlock)으로 전환하여 차단 잠금과 비차단 잠금 사이를 전환하거나 그 반대로 전환합니다.

이 접근 방식은 두 가지 이점을 제공합니다. 첫째, 개발자는 Btrfs 파일 시스템에서 일반적으로 사용되는 중지/깨우기 전략을 구현하기 위해 비차단 잠금 사용 및 대기 이벤트 사용과 같은 임시 동기화를 제거할 수 있습니다. 둘째, 개발자가 여러 정책을 동적으로 다중화하여 잠금 설계를 통합할 수 있습니다.

e6c71a7665fc272339fd56b12058c7d4.png

3.1.1 잠금 상속

프로세스는 작업을 수행하기 위해 여러 잠금을 획득할 수 있습니다. 예를 들어 Linux의 프로세스는 메모리 또는 파일 메타데이터 관리 작업을 수행하기 위해 최대 12개의 잠금(예: 이름 바꾸기 작업) 또는 평균 4개의 잠금을 획득할 수 있습니다.

불행하게도 이 잠금 모드는 대기열 기반 잠금의 문제를 야기합니다. 여기서 일부 스레드는 다른 잠금을 기다리는 다른 스레드가 만든 최상위 잠금을 획득하기 위해 더 오래 기다려야 합니다. 예를 들어 스레드 t1이 L1과 L2라는 두 개의 잠금을 하나의 작업으로 획득하려고 하고 t2는 L1에 대한 작업만 회수하려고 한다고 가정합니다. 이러한 잠금 프로토콜은 fifo 기반이므로 t2가 L1을 얻기 위해 대기하는 동안 t1은 대기열 끝에서 L2를 얻을 수 있습니다. 개발자는 커널에 더 많은 컨텍스트를 제공할 수 있습니다. t1이 모든 잠금을 함께 획득하거나 t1이 이미 보유하고 있는 잠금을 선언하여 다음 잠금 L2를 획득하는 데 더 높은 우선 순위를 부여할 수 있습니다.

응용 프로그램은 성능 향상을 위해 시스템 호출 경로 또는 일련의 작업에 우선 순위를 지정하려고 할 수 있습니다. 개발자는 작업 우선 순위 컨텍스트를 인코딩하고 이 정보를 영향을 받는 잠금에 전달하여 이를 수행할 수 있습니다. 시스템 호출의 경우 개발자는 중요 경로의 잠금 및 우선순위 스레드에 대한 정보를 공유할 수 있습니다. shuffler 프로그램은 지정된 응용 프로그램의 잠금을 기다리는 다른 스레드보다 이러한 스레드의 우선 순위를 지정합니다.

3.1.2 스케줄러의 의미 노출

일반적으로 CPU 또는 메모리와 같은 하드웨어 리소스를 초과 할당하면 사용자 공간 런타임 시스템과 가상 머신 모두에서 리소스 활용도가 향상됩니다. 초과 구독은 하드웨어 활용도를 개선하지만 이중 스케줄링 문제도 야기합니다. 하이퍼바이저는 잠금 보유자 또는 VM의 다음 잠금 역할을 하도록 vCPU를 예약할 수 있습니다. 하이퍼바이저는 vCPU 일정 정보를 shuffler 프로그램에 노출하여 런타임 할당량을 기반으로 서비스의 우선 순위를 지정할 수 있습니다.

3.1.3 적응형 중지/웨이크 전략

모든 닫힌 잠금 장치는 회전 후 주차하는 전략을 따릅니다. 즉, 일정 시간 동안 회전한 후 스스로 정지합니다. 이 회전 시간은 대부분 임시적입니다. 즉, 웨이터는 시간 할당량에 따라 일정 시간 동안 회전하거나 수행할 작업이 없으면 계속 회전합니다. 응용 프로그램 개발자는 이제 중요 섹션의 길이를 분석하여 시간적 컨텍스트를 노출하여 에너지 소비를 최소화하고 깨우기 정보를 통해 다음 대기자를 정시에 예약하여 깨우기 대기 시간을 최소화할 수 있습니다. 또한 개발자는 긴 웨이크업 지연을 줄이기 위해 잠그기 전에 웨이터를 깨우기 위해 수면 정보를 추가로 인코딩할 수 있습니다. 이 접근 방식은 반가상화 스핀록과 함께 작동하여 호송 효과를 방지합니다.

3.2 점유 일정

3.2.1 우선순위 상속

우선 순위 역전은 잠금을 보유한 낮은 우선 순위 작업이 동일한 잠금을 기다리도록 일반 우선 순위 작업에 의해 예약될 때 발생합니다. 문제는 Linux IO 스택에 명시되어 있습니다. IO 요청을 예약할 때 잠금을 획득하려는 일반 작업은 동일한 잠금을 보유하는 우선 순위가 낮은 백그라운드 작업을 예약할 수 있습니다. 잠금 스케줄링은 백그라운드 작업으로, IO 성능이 저하됩니다.

3.2.2 업무 공정성을 위한 협력 일정

이것은 두 작업이 서로 다른 시간에 잠금을 획득하는 스케줄러 전복 문제로 알려진 새로운 종류의 문제를 소개합니다. 오랜 시간 동안 보류된 작업은 운영 체제의 일정 목표를 파괴합니다. 운영 체제는 중요한 영역 크기를 추적하고 장기 실행 작업에 페널티를 주어 이 문제를 해결합니다. 이 솔루션은 문제를 해결하지만 혜택을 받지 못할 수 있는 애플리케이션에 대해서도 일정 공정성을 적용합니다.

3.2.3 AMP(Asymmetric Multiprocessor) 머신에서 태스크 페어 잠금

하나의 프로세서에 서로 다른 연산 능력을 가진 코어가 있는 경우, 이 아키텍처에 사용되는 기본 잠금 프리미티브는 약한 코어의 느린 연산 능력으로 인해 애플리케이션 처리량이 붕괴될 수 있는 스케줄러 전복 문제로 어려움을 겪습니다. 더 빠른 프로세스를 달성하기 위해 개발자는 더 빠른 코어에 중요한 잠금을 할당하거나 전체 잠금을 개선하기 위해 잠금을 획득하기 위해 대기 중인 스레드 대기열을 재정렬할 수 있습니다.

3.2.4 실시간 스케줄링

실시간 시스템의 예약과 유사하게 애플리케이션 개발자는 SLO를 보장하기 위해 항상 스레드를 예약하는 잠금 정책을 만들 수 있습니다. 여기에서 잠금은 위상 공정성에 기반한 알고리즘으로 설계할 수 있습니다. 이 접근 방식은 지터를 제거하고 대기 시간이 중요한 애플리케이션에 대한 테일 대기 시간의 상한을 보장합니다.

3.3 동적 잠금 분석

응용 프로그램 개발자는 모든 커널 잠금에 대한 파일 정보를 구성할 수 있습니다. 구성할 잠금을 선택하면 개발자가 다양한 세분성 수준에서 구성할 수 있습니다. 예를 들어 커널에서 실행되는 모든 스핀록, 특정 기능의 잠금, 코드 경로 또는 네임스페이스 또는 개별 잠금 인스턴스까지 구성할 수 있습니다. 이 접근 방식은 관심 있는 부분만 분석하여 기본 동기화를 더 잘 이해할 수 있으므로 응용 프로그램 개발자에게 도움이 됩니다.

또한 개발자는 다양한 셔플러 정책 또는 일련의 정책에서 제공하는 특정 보증을 기반으로 애플리케이션 성능에 영향을 미치는 성능 계약에 대해 추론할 수 있습니다.

4. 커널 잠금을 위한 최적화 프레임워크

커널 잠금에 사용되는 결정 및 동작을 재정의하고 이를 API로 노출합니다. 사용자 정의 코드는 이러한 노출된 API를 대체하며 사용자는 필요에 따라 잠금 기능을 사용자 정의할 수 있습니다. 예를 들어 대기 대기열에 합류하기 전에 회전할지 여부는 사용자가 결정할 수 있도록 API가 될 수 있습니다. 사용자는 먼저 자신의 코드를 작성하여 사용 사례에 따라 커널의 잠금 프로토콜을 수정한 다음 운영 체제가 커널 내부의 주석이 달린 잠금 기능을 대체합니다.흐름도는 다음과 같습니다.

2fd18abff7b3d53a0c78a0c8f97412c0.jpeg

사용자는 잠금 정책(1)을 지정하고 eBPF 검증자는 컴파일 후 eBPF 제한 및 상호 배제 보안 속성(2, 3)을 고려하여 이를 검증합니다. 그런 다음 검증자는 검증 결과를 사용자에게 알리고(4) 성공하면 컴파일된 eBPF 코드를 파일 시스템에 저장합니다(5). 마지막으로 잠금(6)을 지정하는 주석이 달린 함수를 필드 패치 모듈로 바꿉니다.

4.1 API

다양한 API는 보안을 보장하면서 잠금 정책의 유연한 구현을 지원합니다. 운영 체제의 기본 구현은 eBPF를 사용하여 커널 잠금을 수정합니다. eBPF 및 잠금 API를 사용하여 커널의 잠금 인스턴스 집합에 대해 원하는 정책이 구현됩니다. 사용자는 네이티브 코드로 변환되고 eBPF 검증자가 보안을 확인하는 여러 정책을 인코딩할 수 있습니다. 검증자는 커널에 네이티브 코드를 로드하기 전에 메모리 액세스 제어 또는 화이트리스트 도우미 기능과 같은 기호 실행을 수행합니다.

a3dc3db3218f5db4a677093b2e205839.jpeg

4.2 보안

eBPF 유효성 검사기 외에도 ShflLocks에는 잠금 획득을 위한 별도의 단계와 대기 대기열 재정렬을 위한 단계가 있습니다. 사용자는 API 기능을 사용하여 현재 노드와 셔플러 노드를 비교하고 현재 노드를 재정렬할지 여부를 확인하고 스케줄러 협력 잠금을 설계하여 임계 슬라이스 길이가 더 작은 노드의 우선 순위를 지정하여 노드의 우선 순위를 낮출 수 있습니다. 수업.

잘못된 사용자 구현이 공정성 보장 정책을 위반할 수 있지만 런타임 시 mutex 속성을 확인하고 보장할 수 있습니다. 또한 커널에는 교착 상태 문제가 없으며 API는 잠금 동작을 수정하지 않고 노드 이동 결정만 반환합니다. 개발자는 각 호출에 대해 원하는 동작을 구현하여 세밀한 방식으로 잠금을 구성할 수 있습니다. 잠금 기능의 동작을 변경하지 않는 동안 가중치 프로파일 분석 전략은 임계 섹션의 길이를 증가시켜 성능 저하를 유발할 수 있습니다.

또한 eBPF는 사용자가 정책을 작성하는 데 사용할 수 있는 여러 eBPF 프로그램을 연결하는 기능을 제공합니다. 마지막으로, 잠금 프리미티브가 사용하는 데이터 구조를 수정하기 위해 필드 디스패치 데이터 구조에 의존합니다. 예를 들어 대기열 기반 잠금 노드 데이터 구조는 특정 사용 사례에 대한 정보를 인코딩하는 데 사용되는 추가 정보로 확장될 수 있습니다. 사용자 공간 코드를 실행하지 않는 최악의 경우 잠금 알고리즘을 동적으로 수정하면 최대 20%의 오버헤드가 발생할 수 있습니다.

4.3 조합 전략

커널 동시성 제어를 조정하면 응용 프로그램이 소프트웨어 스택을 더 많이 제어할 수 있습니다. 애플리케이션 개발자는 애플리케이션 잠금이 필요한 일련의 정책을 제공합니다. 여러 전략을 결합하는 것은 특히 일부 전략이 충돌할 수 있는 경우 어려운 작업입니다. 프로그램 구성을 활용하여 이 프로세스를 자동화하면 보안 속성을 사용자 공간의 검증으로 완전히 이동하고 충돌하는 정책을 구성하는 안전한 방법을 제공할 수 있습니다.

실행이 중요한 경로에 속할 수 있으므로 사용자는 너무 많은 정책을 추가할 수 없습니다. 권한이 있는 한 명의 사용자가 커널 잠금을 수정할 수 있도록 허용하며, 모델은 전체 시스템을 사용하는 한 명의 사용자만을 위한 것입니다. 그러나 클라우드 환경에서 멀티 테넌시를 처리하기 위해서는 사용자 간 격리를 위반하지 않는 테넌트 인식 정책 작성기가 필요합니다. 이러한 충돌을 피하기 위해 사용자 공간에서 정책을 합성하고 정책이 특정 동작에 영향을 줄 수 있는 경우에만 사용되는 잠금 알고리즘에 런타임 검사를 추가합니다.

잠금 외에도 RCU, seqlocks, 대기 이벤트 및 응용 프로그램의 성능을 더욱 향상시킬 수 있는 기타 확장과 같이 커널에서 많이 사용되는 다른 동기화 메커니즘이 있습니다. 즉, 사용자 공간 응용 프로그램에는 본질적으로 일반적인 자체 잠금도 있습니다. 반대로 라이브러리 보간과 같은 기존 기술은 응용 프로그램이 실행되기 시작할 때 다른 잠금 구현에 대한 단일 변경만 허용합니다.

5. 요약

커널 잠금 동기화 프리미티브는 일부 애플리케이션의 성능과 확장성에 큰 영향을 미치지만 애플리케이션 개발자는 커널 동기화 프리미티브를 제어할 수 없습니다. 상황별 동시성 제어를 사용하면 사용자 공간 응용 프로그램이 커널 동시성 프리미티브를 미세 조정할 수 있습니다. 이는 부분적으로 코어 동기화 영역의 혁신을 가속화하는 소프트웨어 스택의 전문화에 대해 생각하는 방식입니다.

[참고 자료 및 관련 자료]

추천

출처blog.csdn.net/wireless_com/article/details/131160180