>  기사  >  데이터 베이스  >  MySQL · 엔진 기능 · InnoDB IO 하위 시스템에 대한 자세한 소개

MySQL · 엔진 기능 · InnoDB IO 하위 시스템에 대한 자세한 소개

黄舟
黄舟원래의
2017-03-06 11:59:231251검색

머리말

성숙한 크로스 플랫폼 데이터베이스 엔진인 InnoDB는 동기식 비동기 IO, IO 병합 등을 포함하여 효율적이고 사용하기 쉬운 IO 인터페이스 세트를 구현합니다. 이 기사에서는 내부 구현을 간략하게 소개합니다. 주요 코드는 os0file.cc 파일에 집중되어 있습니다. 본 글의 분석은 기본적으로 MySQL 5.6, CentOS 6, gcc 4.8을 기준으로 작성되었으며, 그 외 버전에 대한 내용은 별도로 기술한다.

기본 지식

WAL 기술: 로그 우선 기술, 기본적으로 모든 데이터베이스가 이 기술을 사용합니다. 간단히 말하면, 데이터 블록을 써야 할 때 데이터베이스 프런트 엔드 스레드는 먼저 해당 로그(일괄 순차 쓰기)를 디스크에 쓴 다음 클라이언트에게 작업이 성공했음을 알려줍니다. 데이터 블록의 (이산적 무작위 쓰기) 그런 다음 이를 백그라운드 IO 스레드에 넣습니다. 이 기술을 사용하면 디스크 쓰기 작업이 1회 더 발생하더라도 로그를 일괄적으로 순차적으로 쓰기 때문에 효율성이 매우 높아 클라이언트가 빠른 응답을 얻을 수 있다. 또한 실제 데이터 블록이 디스크에 기록되기 전에 데이터베이스가 충돌하는 경우 데이터베이스는 다시 시작할 때 데이터 손실을 초래하지 않고 충돌 복구를 위해 로그를 사용할 수 있습니다.
데이터 사전 읽기: 데이터 블록 A에 '인접한' 데이터 블록 B와 C도 A를 읽을 때 큰 차이가 있으므로 확률은 다음과 같습니다. B를 읽으면 미리 메모리에 읽어 들일 수 있는 것이 바로 데이터 사전 읽기 기술입니다. 여기서 말하는 인접성은 물리적 인접성과 논리적 인접성의 두 가지 의미를 갖는다. 기본 데이터 파일의 인접 항목을 물리적 인접 항목이라고 합니다. 데이터 파일이 인접하지 않지만 논리적으로 인접하는 경우(id=1인 데이터와 id=2인 데이터가 논리적으로 인접하지만 반드시 물리적으로 인접하지는 않으며 동일한 파일 내에서 서로 다른 위치에 존재할 수 있음) 논리적 인접성이라고 합니다.
파일 열기 모드: 개방형 시스템 호출에는 O_DIRECT, O_SYNC 및 기본 모드의 세 가지 주요 공통 모드가 있습니다. O_DIRECT 모드는 파일에 대한 후속 작업이 파일 시스템 캐시를 사용하지 않음을 의미하며, 다른 관점에서는 O_DIRECT 모드를 사용하여 파일을 작성합니다. 성공하면 데이터가 실제로 디스크에 기록되며(디스크와 함께 제공되는 캐시에 관계없이) O_DIRECT 모드는 파일을 읽는 데 사용됩니다. 각 읽기 작업은 실제로 디스크에서 읽혀지지 않습니다. 파일 시스템의 캐시. O_SYNC는 운영 체제 캐시를 사용하고 파일 읽기 및 쓰기가 커널을 통해 수행됨을 의미하지만 이 모드는 데이터가 매번 디스크에 기록된다는 것을 보장합니다. 기본 모드는 데이터를 쓴 후 데이터가 디스크에 남아 있을 수 있다는 점을 제외하면 O_SYNC 모드와 유사합니다. 길을 잃다.
또한 쓰기 작업을 수행하려면 수정되거나 추가된 데이터를 디스크에 기록해야 할 뿐만 아니라 파일 메타정보도 디스크에 기록해야 합니다. 두 부분을 모두 디스크에 기록해야 데이터가 손실되지 않습니다. O_DIRECT 모드는 파일 메타 정보가 디스크에 기록된다는 것을 보장하지 않으므로(그러나 대부분의 파일 시스템은 그렇습니다, Bug #45892), 다른 작업을 수행하지 않으면 O_DIRECT로 파일을 쓴 후 손실될 위험이 있습니다. O_SYNC는 데이터와 메타정보가 모두 디스크에 저장되도록 보장합니다. 기본 모드에서는 두 데이터 모두 보장되지 않습니다.
fsync 함수를 호출한 후에는 데이터와 로그가 디스크에 기록되었는지 확인할 수 있습니다. 따라서 O_DIRECT 및 기본 모드를 사용하여 파일을 여는 경우 데이터를 쓴 후 fsync 함수를 호출해야 합니다.
동기식 IO: Linux에서 일반적으로 사용되는 읽기/쓰기 함수는 이러한 유형의 IO입니다. 특징은 함수가 실행될 때 호출자가 대기한다는 것입니다. , 메시지 알림 메커니즘이 없습니다. 왜냐하면 함수가 반환되면 작업이 완료되었음을 의미하며 나중에 반환 값을 직접 확인하여 작업의 성공 여부를 알 수 있기 때문입니다. 이러한 유형의 IO 작업은 프로그래밍하기가 상대적으로 간단하고 동일한 스레드에서 모든 작업을 완료할 수 있지만 호출자가 기다려야 합니다. 데이터베이스 시스템에서는 특정 데이터가 긴급하게 필요할 때 호출하는 것이 더 적합합니다. 다운로드하기 전에 WAL을 클라이언트에 반환해야 합니다. 동기식 IO 작업이 수행됩니다.
비동기 IO: 데이터베이스에서 백그라운드에서 데이터 블록을 플러시하는 IO 스레드는 기본적으로 비동기 IO를 사용합니다. 데이터베이스 프런트엔드 스레드는 다른 작업을 수행하기 위해 돌아가기 전에 브러시 블록 요청을 비동기 IO 대기열에 제출하기만 하면 되는 반면, 백그라운드 스레드 IO 스레드는 제출된 요청이 완료되었는지 정기적으로 확인하고 완료되면 몇 가지 작업을 수행합니다. 후속 처리 작업. 동시에 비동기 IO는 일괄 요청으로 제출되는 경우가 많습니다. 서로 다른 요청이 동일한 파일에 액세스하고 연속적인 오프셋이 있는 경우 하나의 IO 요청으로 병합될 수 있습니다. 예를 들어, 첫 번째 요청은 오프셋 100에서 시작하는 200바이트의 데이터인 파일 1을 읽고, 두 번째 요청은 오프셋 300에서 시작하는 100바이트의 데이터인 파일 1을 읽습니다. 그런 다음 두 요청을 파일 1, 300바이트 읽기로 병합할 수 있습니다. 오프셋 100에서 시작하는 데이터입니다. 데이터 사전 읽기의 논리적 사전 읽기도 종종 비동기 IO 기술을 사용합니다.
현재 Linux의 비동기 IO 라이브러리에서는 파일을 O_DIRECT 모드로 열어야 하며, 데이터 블록이 저장된 메모리 주소, 파일 읽기 및 쓰기의 오프셋, 읽고 쓰는 데이터의 양은 다음과 같아야 합니다. 파일 시스템 논리 블록 크기의 정수 배수입니다. sudo blockdev --getss /dev/sda5과 유사한 문을 사용하여 파일 시스템 논리 블록 크기를 쿼리할 수 있습니다. 위의 세 개가 파일 시스템 논리 블록 크기의 정수 배가 아닌 경우 읽기 및 쓰기 기능을 호출할 때 EINVAL 오류가 보고됩니다. 그러나 파일이 O_DIRECT를 사용하여 열리지 않으면 프로그램은 계속 실행될 수 있지만 동기식 IO로 저하되고 io_submit 함수 호출을 차단합니다.

InnoDB 일반 IO 작업 및 동기 IO

InnoDB에서 시스템에 pread/pwrite 기능(os_file_read_funcos_file_write_func)이 있으면 이를 읽고 쓰기 위해 사용하고, 그렇지 않으면 lseek+read/를 사용합니다. 구성표를 작성하십시오. 이것이 InnoDB 동기 IO입니다. pread/pwrite 문서를 보면 이 두 함수는 파일 핸들의 오프셋을 변경하지 않고 스레드로부터 안전하므로 다중 스레드 환경에서 권장되는 것을 볼 수 있습니다. lseek+read/write 솔루션에는 자체적인 솔루션이 필요합니다. 뮤텍스 보호 동시 조건에서 빈번한 커널 상태 오류는 성능에 일정한 영향을 미칩니다.

InnoDB에서는 파일을 열기 위해 open 시스템 콜(os_file_create_func)을 사용한다. 모드 측면에서는 O_RDONLY(읽기 전용), O_RDWR(읽기-쓰기), O_CREAT(파일 생성)이 있다. ), O_EXCL(이 파일을 생성한 것이 이 스레드임을 보장) 및 O_TRUNC(파일 지우기)입니다. 기본적으로(데이터베이스는 읽기 전용 모드로 설정되지 않음) 모든 파일은 O_RDWR 모드로 열립니다. innodb_flush_method의 매개변수가 더 중요합니다.

  • innodb_flush_method가 O_DSYNC를 설정하면 O_SYNC를 사용하여 로그 파일(ib_logfileXXX)이 열리므로 함수를 호출할 필요가 없습니다. fsync는 데이터를 쓴 후 디스크를 플러시합니다. 파일(ibd)은 기본 모드로 열리므로 데이터를 쓴 후 디스크를 플러시하려면 fsync를 호출해야 합니다.

  • innodb_flush_method가 O_DIRECT를 설정하면 로그 파일(ib_logfileXXX)이 기본 모드로 열립니다. 데이터 파일을 플러시하려면 fsync 함수를 호출해야 합니다. ibd)는 O_DIRECT 모드로 열립니다. 쓰기 후에는 fsync 함수를 호출하여 데이터를 플러시해야 합니다.

  • innodb_flush_method를 fsync로 설정하거나 설정하지 않으면 데이터 파일과 로그 파일이 기본 모드로 열리고, 데이터 쓰기 후 디스크를 플러시하려면 fsync가 필요합니다.

  • innodb_flush_method가 O_DIRECT_NO_FSYNC로 설정된 경우 파일 열기 방법은 O_DIRECT 모드와 유사하지만 데이터 파일이 작성된 후에는 fsync 함수를 호출하여 플러시하지 않습니다. 이는 주로 O_DIRECT가 파일이 메타데이터도 파일 시스템의 디스크에 배치되도록 보장하기 때문입니다.
    InnoDB는 현재 O_DIRECT 모드를 사용하여 로그 파일을 열거나 O_SYNC 모드를 사용하여 데이터 파일을 여는 것을 지원하지 않습니다.
    Linux 기본 AIO를 사용하는 경우(자세한 내용은 다음 섹션 참조) innodb_flush_method를 O_DIRECT로 구성해야 합니다. 그렇지 않으면 동기 IO로 저하됩니다(오류 로그에 작업 프롬프트가 표시되지 않음).

InnoDB는 파일 시스템의 파일 잠금을 사용하여 하나의 프로세스만 파일을 읽고 쓸 수 있도록 하고(os_file_lock), 강제 잠금(Mandatory 잠금) 대신 권고 잠금(Advisory 잠금)을 사용합니다. 잠금), 필수 잠금에는 Linux를 포함한 많은 시스템에 버그가 있기 때문입니다. 읽기 전용 모드가 아닌 경우 모든 파일은 열린 후 파일 잠금으로 잠깁니다.

InnoDB의 디렉토리는 재귀적으로 생성됩니다(os_file_create_subdirs_if_neededos_file_create_directory). 예를 들어 /a/b/c/ 디렉터리를 생성해야 하는 경우 먼저 c, b, a 순으로 디렉터리를 생성하고 mkdir 함수를 호출합니다. 또한 상위 디렉터리를 생성하려면 os_file_create_simple_func 대신 os_file_create_func 함수를 호출해야 합니다.

InnoDB에도 임시 파일이 필요합니다. 임시 파일 생성 로직은 비교적 간단합니다(os_file_create_tmpfile). 즉, tmp 디렉터리에 파일을 성공적으로 생성한 후 unlink 함수를 직접 사용하여 핸들을 해제하면 됩니다. 프로세스가 종료되면(정상 종료 여부에 관계없이) 이 파일이 자동으로 해제됩니다. InnoDB는 임시 파일을 생성할 때 먼저 서버 계층 함수 mysql_tmpfile의 논리를 재사용하고 나중에 리소스를 해제하려면 서버 계층 함수를 호출해야 하기 때문에 dup 함수를 호출하여 핸들을 복사합니다.

파일 크기를 구해야 할 경우 InnoDB는 파일의 메타데이터(stat 함수)를 확인하지 않고 lseek(file, 0, SEEK_END) 메소드를 사용하여 파일 크기를 구합니다. 메타데이터 정보 업데이트 지연으로 인해 잘못된 파일 크기가 검색되는 것을 방지하기 위한 것입니다.

InnoDB는 새로 생성된 모든 파일(데이터 및 로그 파일 포함)에 크기를 사전 할당합니다. 사전 할당된 파일의 내용은 현재 파일이 0(os_file_set_size)으로 설정됩니다. 가득 차면 확장됩니다. 또한, 로그 파일이 생성될 때, 즉 install_db 단계에서 할당 진행 상황이 100MB 간격으로 오류 로그에 출력됩니다.

일반적으로 기존 IO 연산과 동기 IO는 상대적으로 단순하지만, InnoDB에서는 기본적으로 데이터 파일 쓰기에 비동기 IO를 사용합니다.

InnoDB 비동기 IO

MySQL은 Linux 네이티브 aio 이전에 탄생했기 때문에 MySQL 비동기 IO 코드에서 비동기 IO를 구현하는 두 가지 솔루션이 있습니다.
첫 번째는 원래 Simulated aio입니다. InnoDB는 Linux 기본 air를 가져오기 전과 air를 지원하지 않는 일부 시스템에서 aio 메커니즘을 시뮬레이션했습니다. 비동기식 읽기 및 쓰기 요청이 제출되면 단순히 대기열에 넣은 다음 반환되며 프로그램은 다른 작업을 수행할 수 있습니다. 백그라운드에는 이 대기열에서 지속적으로 요청을 가져오는 여러 비동기 IO 처리 스레드(innobase_read_io_threads 및 innobase_write_io_threads 두 매개변수로 제어됨)가 있으며 동기 IO를 사용하여 읽기 및 쓰기 요청을 완료하고 읽기 및 쓰기 이후의 작업은 다음과 같습니다. 완전한.
다른 하나는 Native Aio입니다. 현재 Linux에서 io_submit, io_getevents 및 기타 기능을 사용하여 완료됩니다(glibc aio는 사용되지 않으며 이 역시 시뮬레이션됩니다). io_submit을 사용하여 요청을 제출하고 io_getevents를 사용하여 요청을 기다립니다. 또한 윈도우 플랫폼에는 자체 aio가 있는데 여기서는 소개하지 않습니다. 윈도우 기술 스택을 사용하는 경우 데이터베이스는 sqlserver를 사용해야 합니다. 현재 다른 플랫폼(Linux 및 window 제외)에서는 Simulate aio만 사용할 수 있습니다.

먼저 몇 가지 일반적인 기능과 구조를 소개한 후 Linux에서 Simulate alo 및 Native aio를 자세히 소개하겠습니다.
전역 배열은 os_aio_array_t 유형의 os0file.cc에 정의되어 있습니다. 이러한 배열은 Simulate aio에서 읽기 및 쓰기 요청을 캐시하는 데 사용되는 대기열입니다. 이는 각 IO를 기록합니다. 요청 유형, 파일의 fd, 오프셋, 읽을 데이터 양, IO 요청이 시작된 시간, IO 요청 완료 여부 등. 또한 Linux 네이티브 io의 구조체 iocb도 os_aio_slot_t에 있습니다. 배열 구조 os_aio_slot_t에는 얼마나 많은 데이터 요소(os_aio_slot_t)가 사용되었는지, 비어 있는지, 가득 찼는지 등과 같은 일부 통계 정보가 기록됩니다. 이러한 전역 배열은 총 5개가 있으며 비동기 데이터 파일 읽기 요청(os_aio_slot_t), 데이터 파일 쓰기 비동기 요청(os_aio_read_array), 로그 파일 쓰기 비동기 요청(os_aio_write_array) 및 삽입에 사용됩니다. 버퍼 비동기 쓰기 요청(os_aio_log_array), 데이터 파일 동기화 읽기 및 쓰기 요청(os_aio_ibuf_array). 로그 파일의 데이터 블록 쓰기는 동기식 IO인데 여기서 로그 쓰기에 비동기 요청 큐(os_aio_sync_array)를 할당해야 하는 이유는 무엇입니까? 그 이유는 체크포인트 정보를 InnoDB 로그 파일의 로그 헤더에 기록해야 하기 때문이다. 현재 체크포인트 정보 읽기 및 쓰기는 그다지 긴급하지 않기 때문에 여전히 비동기식 IO를 사용해 구현되고 있다. 윈도우 플랫폼에서는 특정 파일에 대해 비동기 IO를 사용하면 해당 파일은 동기 IO를 사용할 수 없으므로 데이터 파일 동기 읽기 및 쓰기 요청 큐(os_aio_log_array)가 도입됩니다. 로그는 응급 복구 중에만 읽어야 하기 때문에 비동기 요청 큐에서 로그 파일을 읽을 필요가 없으며, 응급 복구를 수행하는 경우 데이터베이스를 아직 사용할 수 없으므로 비동기 읽기 모드로 들어갈 필요가 없습니다. . 여기서 주목해야 할 점은 innobase_read_io_threads 및 innobase_write_io_threads 변수의 두 매개변수가 무엇이든 os_aio_sync_arrayos_aio_read_array은 하나만 있지만 Linux에서는 데이터의 os_aio_write_array 요소가 그에 따라 증가한다는 것입니다. 변수는 1씩 증가하고, 요소의 개수는 256씩 증가합니다. 예를 들어 innobase_read_io_threads=4인 경우 os_aio_read_array 배열은 4개의 부분으로 나뉘며 각 부분에는 256개의 요소가 있습니다. 각 부분에는 4개의 스레드를 시뮬레이션하는 데 사용되는 자체 독립 잠금, 세마포어 및 통계 변수가 있습니다. innobase_write_io_threads도 비슷합니다. 여기에서 각 비동기 읽기/쓰기 스레드가 캐시할 수 있는 읽기 및 쓰기 요청의 상한선(256)이 있음을 알 수 있습니다. 이 숫자를 초과하면 후속 비동기 요청은 대기해야 합니다. 256은 비동기 IO 동시성 수에 대한 InnoDB 계층의 제어로 이해될 수 있으며, 파일 시스템 계층과 디스크 수준에도 길이 제한이 있는데, 이는 각각 os_aio_slot_tcat /sys/block/sda/queue/nr_requests를 사용하여 쿼리할 수 있습니다. cat /sys/block/sdb/queue/nr_requests
은 위에서 언급한 전역 배열은 물론 Simulate aio에서 사용되는 잠금 및 뮤텍스를 포함한 다양한 구조를 초기화하기 위해 InnoDB가 시작될 때 호출됩니다. os_aio_init 해당 구조를 해제합니다. os_aio_free 일련의 함수는 aio 하위 시스템의 상태를 출력하는 데 사용되며 주로 os_aio_print_XXX 문에서 사용됩니다. show engine innodb status

Simulate aio

InnoDB가 자체 시뮬레이션 메커니즘 세트를 구현하기 때문에 Simulate aio는 Native aio에 비해 상대적으로 복잡합니다.

  • 입력 기능은

    입니다. 디버그 모드에서는 데이터 블록이 저장된 메모리 주소, 파일 읽기 및 쓰기 오프셋, 읽고 쓴 데이터의 양이 OS_FILE_LOG_BLOCK_SIZE의 정수배인지 여부. 그러나 Simulate aio는 궁극적으로 동기 IO를 사용하고 O_DIRECT를 사용하여 열 필요가 없기 때문에 파일 열기 모드에서 O_DIRECT가 사용되는지 여부를 확인하지 않습니다. 파일. os_aio_func

  • 검증이 통과된 후 os_aio_array_reserve_slot이 호출되어 이 IO 요청을 특정 백그라운드 IO 처리 스레드(innobase_xxxx_io_threads에 의해 할당되지만 실제로는 동일한 전역 배열에 있음)에 할당됩니다. 백그라운드 io 스레드 처리를 용이하게 하기 위해 io 요청의 관련 정보를 기록합니다. IO 요청 유형이 동일하고 동일한 파일이 요청되고 오프셋이 상대적으로 가까운 경우(기본적으로 오프셋 차이는 1M 이내) InnoDB는 후속 단계를 용이하게 하기 위해 두 요청을 동일한 io 스레드에 할당합니다. 병합.

  • IO 요청을 제출한 후 백그라운드 IO 처리 스레드를 깨워야 합니다. 백그라운드 스레드가 IO 요청이 없음을 감지하면 대기 상태(os_event_wait).

  • 이 시점에서 함수는 반환되고 프로그램은 다른 작업을 수행할 수 있으며 후속 IO 처리는 백그라운드 스레드로 넘겨집니다.
    백그라운드 IO 스레드가 처리되는 방식을 소개합니다.

  • InnoDB가 시작되면 백그라운드 IO 스레드가 시작됩니다(io_handler_thread). os_aio_simulated_handle을 호출하여 전역 배열에서 IO 요청을 가져온 다음 동기 IO를 사용하여 이를 처리한 후 마무리 작업을 수행해야 합니다. 예를 들어 쓰기 요청인 경우 해당 데이터 페이지입니다. 버퍼 풀의 더티 페이지에서 제거해야 합니다.

  • os_aio_simulated_handle먼저 실행할 배열에서 IO 요청을 선택해야 합니다. 선택 알고리즘은 단순한 선입선출 방식이 아닙니다. 모든 요청 중에서 가장 작은 오프셋을 먼저 처리합니다. 이는 후속 IO 병합 계산을 용이하게 하기 위해 수행됩니다. 그러나 이로 인해 특히 큰 오프셋이 있는 일부 격리된 요청이 오랫동안 실행되지 않을 수도 있습니다. 즉, 이 문제를 해결하기 위해 InnoDB는 IO 요청을 선택하기 전에 먼저 순회를 수행합니다. 요청이 2초 전에 발견되었지만 푸시되었지만(즉, 2초 동안 대기) 아직 실행되지 않은 경우, 요청이 두 개 있는 경우 이러한 요청이 중단되는 것을 방지하기 위해 가장 오래된 요청이 먼저 실행됩니다. 대기 시간이 동일하면 오프셋이 더 작은 요청이 선택됩니다.

  • os_aio_simulated_handle다음 단계는 IO 병합을 수행하는 것입니다. 예를 들어 읽기 요청 1은 offset100부터 200바이트인 file1을 요청하고, 읽기 요청 2는 file1부터 100바이트를 요청합니다. offset300에서 이 두 요청을 하나의 요청(offset100부터 시작하는 300바이트인 file1)으로 병합할 수 있습니다. IO가 반환된 후 데이터를 원래 요청의 버퍼에 복사하면 됩니다. 쓰기 요청도 쓰기 작업 전에 쓸 데이터를 임시 공간에 복사한 후 한꺼번에 쓰는 방식과 비슷합니다. 오프셋이 연속적인 경우에만 IO가 병합됩니다. 중단이나 중복이 있는 경우 동일한 IO 요청은 병합되지 않으므로 이는 최적화 지점으로 간주될 수 있습니다.

  • os_aio_simulated_handle지금 IO 요청이 없는 것으로 확인되면 대기 상태로 진입하여 깨어날 때까지 기다립니다

요약하자면, 나가는 IO 요청은 하나씩 푸시하는 것과 반대되는 것을 볼 수 있습니다. 각 푸시는 백그라운드 스레드에 들어가서 처리됩니다. 백그라운드 스레드 우선 순위가 상대적으로 높으면 IO 병합 효과가 좋지 않을 수 있습니다. 이 문제에 대해 Simulate aio는 유사한 그룹 제출 기능을 제공합니다. 즉, IO 요청 그룹이 제출된 후 백그라운드 스레드가 활성화되어 균일하게 처리되므로 IO 병합 효과가 더 좋습니다. 그러나 여기에는 여전히 약간의 문제가 있습니다. 백그라운드 스레드가 상대적으로 바쁜 경우 대기 상태로 들어가지 않습니다. 즉, 요청이 대기열에 들어가는 한 처리됩니다. 이 문제는 아래 Native aio에서 해결 가능합니다.
일반적으로 InnoDB에서 구현하는 시뮬레이션 메커니즘은 비교적 안전하고 안정적입니다. 플랫폼이 Native aio를 지원하지 않는 경우 이 메커니즘을 사용하여 데이터 파일을 읽고 씁니다.

Linux 네이티브 aio

시스템에 libaio 라이브러리가 설치되어 있고 구성 파일에 innodb_use_native_aio=on이 설정되어 있으면 시작 시 네이티브 aio가 사용됩니다.

  • 입력 기능은 여전히 ​​os_aio_func입니다. 디버그 모드에서도 들어오는 매개변수가 O_DIRECT 모드에서 열리는지 확인하지 않습니다. 약간 위험합니다. 사용자가 Linux 기본 aio가 aio를 활용하기 위해 파일을 열려면 O_DIRECT 모드를 사용해야 한다는 사실을 모른다면 성능이 기대에 미치지 못할 것입니다. 여기를 확인하고 문제가 있으면 오류 로그에 출력하는 것이 좋습니다.

  • 검사가 통과된 후 Simulated aio와 마찬가지로 os_aio_array_reserve_slot을 호출하여 IO 요청을 백그라운드 스레드에 할당합니다. 할당 알고리즘은 Simulated와 마찬가지로 후속 IO 병합도 고려합니다. 아이오. 주요 차이점은 IO 요청의 매개변수를 사용하여 iocb 구조를 초기화해야 한다는 것입니다. iocb를 초기화하는 것 외에도 주로 os_aio_print_XXX 일련의 기능에서 통계의 편의를 위해 IO 요청 관련 정보도 전역 배열의 슬롯에 기록해야 합니다.

  • 요청을 제출하려면 io_submit을 호출하세요.

  • 이 시점에서 함수는 반환되고 프로그램은 다른 작업을 수행할 수 있으며 후속 IO 처리는 백그라운드 스레드로 넘겨집니다.
    다음은 백그라운드 IO 스레드입니다.

  • Simulate aio와 유사하게 InnoDB가 시작되면 백그라운드 IO 스레드도 시작됩니다. Linux 네이티브 aio라면 이 함수 os_aio_linux_handle가 나중에 호출될 것입니다. 이 함수의 기능은 os_aio_simulated_handle과 유사하지만 기본 구현은 IO 요청이 완료될 때까지 기다리는 io_getevents 함수만 호출합니다. 시간 제한은 0.5초입니다. 즉, 0.5초 내에 IO 요청이 완료되지 않으면 함수가 반환되고 계속해서 io_getevents를 호출하여 대기합니다. 물론 기다리기 전에 서버가 닫혔는지 확인하고, 그렇다면 출구.

IO 스레드를 배포할 때 인접한 IO를 하나의 스레드에 넣으려고 합니다. 이는 Simulate aio와 유사하지만 후속 IO 병합 작업의 경우 Simulate aio가 자체적으로 구현하며 Native aio는 커널에 의해 완성되므로 코드는 비교적 간단합니다.
또 다른 차이점은 IO 요청이 없으면 Simulate aio가 대기 상태로 들어가는 반면 Native aio는 0.5초마다 깨어나 몇 가지 검사를 한 후 계속 대기한다는 것입니다. 따라서 새 요청이 오면 Simulated aio는 사용자 스레드를 깨워야 하지만 Native aio는 그렇지 않습니다. 또한 Simulate aio도 서버가 종료되면 깨어나야 하지만 Native aio는 그렇지 않습니다.

Native aio는 Simulate aio와 유사하다는 것을 알 수 있습니다. 요청이 하나씩 제출된 후 하나씩 처리되므로 IO 병합 효과가 떨어집니다. Facebook 팀은 네이티브 aio 그룹 제출 최적화를 제출했습니다. 먼저 IO 요청을 캐시한 다음 io_submit 함수를 호출하여 모든 이전 요청을 한 번에 제출하므로(io_submit은 한 번에 여러 요청을 제출할 수 있음) 커널이 더 편리해졌습니다. IO 최적화를 수행합니다. Simulate aio가 IO 스레드에 큰 압력을 받고 있는 경우 그룹 제출 최적화는 실패하지만 Native aio는 그렇지 않습니다. 그룹 제출은 최적화되어 있으며 한 번에 너무 많은 것을 제출할 수 없습니다. aio 대기 대기열 길이가 초과되면 io_submit이 강제로 시작됩니다.

요약

이 글에서는 InnoDB에서 IO 서브시스템을 구현하는 방법과 이를 사용할 때 주의해야 할 점을 자세히 소개한다. InnoDB 로그는 동기 IO를 사용하고, 데이터는 비동기 IO를 사용하며, 비동기 IO의 쓰기 순서는 선입선출 모드가 아닙니다. 이러한 점에 주의해야 합니다. Simulate aio는 상대적으로 학습 가치가 크지만 최신 운영 체제에서는 Native aio를 사용하는 것이 좋습니다.

위 내용은 MySQL · 엔진 기능 · InnoDB IO 하위 시스템에 대한 자세한 소개입니다. 더 많은 관련 내용은 PHP 중국어 홈페이지(www.php.cn)를 참고해주세요!


성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.