C 프로그램은 Mac OS X Snow Leopard에서 디스크 I/O를 수행하는 동안 무정 상태 대기에 고정되어 있습니다.
문제
배경의 한 줄 : 저는 개발자입니다 NOSQL 데이터베이스 인 Redis. 내가 구현하고있는 새로운 기능 중 하나는 Redis가 메모리에서 모든 데이터를 가져 오기 때문에 가상 메모리입니다. VM 덕분에 Redis는 거의 사용하지 않는 객체를 메모리에서 디스크로 전송할 수 있습니다. OS가 미국 교환을 위해 작업하는 것보다 훨씬 더 잘 작동하는 데는 여러 가지 이유가 있습니다 (Redis 객체는 연속적으로 할당 된 많은 작은 물체로 구축됩니다. 장소, Redis에 의해 디스크로 직렬화되면 거주하는 메모리 페이지에 비해 10 배 적은 공간을 취합니다).
이제 저는 Linux에서 완벽하게 작동하지만 Mac OS X Snow Leopard에서는 잘 작동하지 않는 알파 구현입니다. 때때로 Redis가 메모리에서 디스크로 페이지를 이동하려고하는 동안 Redis 프로세스는 몇 분 동안 무질서 대기 상태로 들어갑니다. 이것을 디버깅 할 수 없었지만 이것은 전화로 발생합니다. fseeko()
또는 fwrite()
. 몇 분 후 전화가 마침내 돌아오고 Redis는 문제없이 계속 일합니다 : 충돌 없음.
전송 된 데이터의 양은 다음과 같습니다 매우 작고 256 바이트와 같은 것. 따라서 매우 많은 양의 I/O의 문제가되어서는 안됩니다.
그러나 쓰기 작업의 대상이되는 스왑 파일에 대한 흥미로운 세부 사항이 있습니다. 큰 파일 (26 기가 바이트)으로 파일을 열었습니다. fopen()
그런 다음 사용을 확대했습니다 ftruncate()
. 마지막으로 파일이 있습니다 unlink()
Redis가 계속 참조 할 수 있도록 Ed는 Redis 프로세스가 종료되면 OS가 실제로 스왑 파일을 제거 할 것이라고 확신합니다.
좋아, 그게 전부이지만 나는 더 자세한 내용을 위해 여기에 있습니다. 그리고 BTW는 Redis Git에서 실제 코드를 찾을 수 있지만 상당히 복잡한 시스템이라는 점에서 5 분 안에 이해하는 것은 아닙니다.
도움을 주셔서 대단히 감사합니다.
해결책
내가 이해 한 바와 같이, HFS+는 희소 파일에 대한 지원이 매우 좋지 않습니다. 따라서 쓰기가 파일의 많은 부분을 초기화/구체화하는 파일 확장을 트리거 할 수 있습니다.
예를 들어, 나는 새로운 큰 빈 파일을 mmap'ing에 넣은 다음 몇몇 임의의 위치에 쓰면 HFS+가있는 디스크에서 매우 큰 파일을 생성한다는 것을 알고 있습니다. MMAP 및 Sparse 파일은 데이터를 사용하는 매우 편리한 방법이므로 사실상 다른 모든 플랫폼/파일 시스템이이를 우아하게 처리하기 때문에 매우 성가신 일입니다.
스왑 파일이 선형으로 기록됩니까? 즉, 기존 블록을 교체하거나 끝에 새 블록을 작성하고 여유 공간 포인터를 증가시킵니다. 그렇다면 파일을 확장하기 위해 더 자주 작은 ftruncate 호출을 수행하면 일시 정지가 짧아집니다.
제쳐두고, Redis VM이 MMAP를 사용하지 않는 이유가 궁금한 점이 있고 뜨거운 블록을 뜨거운 페이지로 집중시키기 위해 블록을 이동합니다.
다른 팁
Antirez, 내 Apple 경험이 Apple ][
, 그러나 나는 그것을 샷을 줄 것이다.
첫 번째는 질문입니다. 가상 메모리의 경우 작동 속도가 디스크 공간보다 더 중요한 측정 값이라고 생각했을 것입니다 (특히 속도가 요점 인 NOSQL DB의 경우 SQL을 사용하지 않습니까?). 그러나 스왑 파일이 26g이면 :-)
시도해야 할 것들 (가능하면).
- 실제로 문제를 찾거나 글을 분리하십시오. 나는 최악의 경우 버퍼 포인터 변경이되어야하기 때문에 추구가 오래 걸릴 수 있다고 믿기 힘들다. 그래도 OSX를 쓰지 않았으므로 확실하지 않습니다.
- 스왑 파일의 크기를 조정하여 문제가 발생하는지 확인하십시오.
- 스왑 파일을 동적으로 확장 한 적이 있습니까 (사전 할당과 달리)? 당신이 그렇게한다면, 그것은 문제를 일으키는 것일 수 있습니다.
- 당신은 항상 당신이 할 수있는만큼 파일에 낮은 글을 쓰나요? 26G 파일을 생성하면 실제로 데이터를 채우지 않을 수 있지만,이를 작성하면 마지막 바이트에 쓰기를하면 OS가 바이트를 제로화해야 할 수도 있습니다 (초기화를 연기).
- 전체 파일을 미리 할당하고 (모든 바이트에 쓰기) 만족하지 않으면 어떻게됩니까? 다시 말해, 프로그램 실행 사이에 파일을 남겨 두십시오 (물론 존재하지 않으면 생성). 그런 다음 Redis의 시작 코드에서 파일 (포인터 등) 만 초기화하십시오. 위의 4 지점에있는 문제와 같은 문제를 제거 할 수 있습니다.
- 다양한 BSD 사이트에 대해서도 문의하십시오. 나는 표지 아래에서 Apple이 얼마나 많이 바뀌 었는지 잘 모르겠지만 OSX는 가장 낮은 수준에서 BSD 일뿐입니다 (Pax Ducks for Covers).
- 또한 애플 사이트에 물어 보는 것을 고려하십시오 (아직 그렇게하지 않은 경우).
글쎄, 그것은 나의 작은 기여입니다. 프로젝트에 행운을 빕니다.
파일에 대한 파일 캐싱을 끄셨습니까? IE fcntl (fd, f_global_nocache, 1)
Linus가 GIT 메일 링리스트에서 한 번 말했듯이 :
"OS X 사람들은 그것을 받아들이는 데 어려움을 겪고 있지만 OS X 파일 시스템은 일반적으로 Windows보다 훨씬 더 많은 문제입니다."