21

이것은 모든 문맥 때문에 긴 질문처럼 보입니다. 이 소설에는 2 가지 질문이 있습니다. 이것을 읽고 도움을 주실 시간을내어 주셔서 감사합니다.DB 구현을위한 메모리 매핑 된 MappedByteBuffer 또는 Direct ByteBuffer?

상황

내가 32 비트 또는 64 비트 시스템의 크기에 TB 이상으로 몇 KB의 데이터 파일로 작업 지원할 수있는 확장 가능한 데이터 저장소 구현에 노력하고있다.

데이터 저장소는 Copy-on-Write 설계를 사용합니다. 항상 새 데이터 나 수정 된 데이터를 데이터 파일의 끝에 추가하고 기존 데이터에 대한 내부 편집을 절대로하지 마십시오.

시스템에서 하나 이상의 데이터베이스를 호스팅 할 수 있습니다. 각각은 디스크상의 파일로 표현됩니다.

구현의 세부 사항은 중요하지 않습니다. 유일한 중요한 세부 사항은 파일에 지속적으로 추가하고 KB에서 TB, TB에서 TB로 증가시키면서 동시에 클라이언트 요청에 응답하는 읽기 작업을 위해 파일을 무작위로 건너 뛰는 것입니다.

최초 생각 나는 내가 효율적으로 호스트 OS에과에서 데이터의 메모리 상태를 관리의 부담을 밀어 수 있도록 메모리 매핑 된 파일을 사용하고 싶었 알고 언뜻

내 코드.

내 모든 코드는 append-to-file 조작을 on-write로 직렬화하고 동시에 여러 독자가 요청에 응답하기 위해 파일을 탐색하도록해야합니다.

디자인

개별 데이터 파일이 MappedByteBuffer의 한계는 2GB를 초과 할 수 있기 때문에, 내 디자인이 쓰기 오프셋 소요 오프셋으로 변환하는 추상화 계층을 포함 할 것으로 기대 특정 2GB 세그먼트 내부.

지금까지 너무 좋아

...

문제

내가 너무 신경하기 시작했다 (아래 제안) 다른 디자인으로가는 할 수있는 더 좋은 방법이 될 수 있다고 생각하는 곳입니다 이.

"메모리 맵핑 된"관련 질문은 여기에 있으므로, mmap 호출은 할당시 연속적인 메모리 실행을 원하는 것에 민감합니다. 예를 들어, 32 비트 호스트 OS에서 메모리 조각화 때문에 2GB 파일을 mmap하려고하면 내 매핑이 성공할 가능성이 적어지고 대신 128MB 매핑 시리즈를 사용하여 전체 에 파일.

을 내가 그 디자인을 생각할 때, 심지어 1천24메가바이트의 mmap에 크기를 사용하여 말을하는 DBMS 몇 거대한 데이터베이스를 호스트하는 모든 1TB 파일을 말할으로 표시, 지금 수천 메모리에서 메모리 매핑 지역의이 그리고 Windows 7에서 다중 GB 파일을 통해 몇백 개의 mmap을 만들려고 테스트 한 결과 예외가 발생하지 않았으며 너무 많은 할당을 시도 할 때마다 실제로 segfault에 대한 JVM을 얻었습니다. 내 Windows 7 컴퓨터에서 비디오를 잘라내어 이전에 보지 못했던 OS 오류 팝업으로 다시 초기화했습니다.

"큰 파일"또는 "이것은 인위적인 예제"를 처리하지 않을 것이라는 인수에 관계없이 이러한 부작용 유형으로 코드를 작성할 수 있다는 사실이 내 내부 알람을 켭니다. 하이 - 경고 및 대체 impl (아래) 고려했다.

내 생각에, 메모리 매핑 된 파일에 대한 나의 이해는 파일이 커질 때마다 매핑을 다시 만들어야한다는 것입니다. 따라서 디자인에 추가 전용 인이 파일의 경우에는 문자 그대로 지속적으로 매핑됩니다. 성장.

파일을 청크로 늘리고 (한 번에 8MB) 매핑을 8MB마다 다시 생성하여이 문제를 어느 정도 해결할 수 있습니다. 그러나 이러한 매핑을 계속해서 다시 만들어야 할 필요가 있습니다. 노골적인 unmap feature supported in Java.

질문 # 1 2

이 시점까지 내 결과를 모두 감안할 때, 나는 주로 솔루션 솔루션 무거운를 읽거나 읽기 전용위한 좋은 해결책으로 메모리 매핑 된 파일을 기각 있지만 것 끊임없이 맵핑을 재창조해야 할 필요성을 감안할 때 무거운

그러나 주변의 풍경을 둘러싼 MongoDB를 둘러싼 메모리 매핑 파일을 둘러보고 여기에 핵심 구성 요소가 누락 된 것 같은 느낌이 듭니다. (2GB 익스텐트와 같은 방식으로 할당됩니다. 시간, 그래서 그들은이 논리와 함께 다시 매핑 비용을 해결하고 순차적 실행을 디스크에 유지하는 것을 돕고 있다고 생각합니다.

이 시점에서 문제가 자바의 맵핑 작업이 부족하여 내 용도로 사용하는 데 훨씬 위험하고 부적절하거나 내 이해가 잘못되어 누군가 나를 북쪽으로 가리킬 수 있는지 여부는 알 수 없습니다.

대안 디자인

다음과 같이 내가 mmap에 대한 이해가 맞다면 갈 것 이상으로 제안 메모리 매핑 하나의 대안 설계는 다음과 같습니다

하는 것은 합리적인 구성 크기의 a direct ByteBuffer 정의 (2, 4, 8, 16, 32, 64, 128KB 대략적으로) 어떤 호스트 플랫폼과도 쉽게 호환 될 수 있으며 (DBMS 자체에 대해 걱정할 필요가 없으며 시나리오를 혼란스럽게 만들지 않음) 원래 파일 채널을 사용하여 specific-offset reads 1 개의 버퍼 용량 덩어리 (buffer-capacity-chunk)를 가지고 있으며, 메모리 매핑 된 파일들을 전혀 무시하고있다.

이제 내 코드는 "전체 레코드를로드하기에 파일에서 충분히 읽었습니까?"와 같은 것에 대해 걱정해야합니다.

또 다른 단점은 OS의 가상 메모리 로직을 사용하지 않아 자동으로 더 많은 "핫"데이터를 메모리에 보관할 수 있다는 것입니다. 대신 OS에서 사용하는 파일 캐시 로직이 여기에 도움이 될만큼 커야 만합니다.

질문 # 2

(2) 나는이 모든에 대한 이해의 확인을 받았으면했다.

예를 들어, 파일 캐시가 환상적일 수도 있습니다. 두 경우 모두 (메모리 맵핑 또는 직접 읽기) 호스트 OS는 가능한 한 많은 최신 데이터를 유지하고 대용량 파일의 성능 차이는 무시할 수 있습니다.

메모리 매핑 된 파일 (인접 메모리)에 대한 중요한 요구 사항에 대한 필자의 이해가 잘못되었으며 모든 것을 무시할 수 있습니다.

+0

를 사용했다 (심지어 10 배 메인 메모리 크기 주위 데이터 크기가 아니라 그것을 성능을 발견, 그들을 게시하시기 바랍니다 대답으로. 많은 사람들이이 질문을 읽고 통찰력을 사용할 수 있습니다. http://bugs.sun.com/view_bug.do?bug_id=6893654와 같이 mmapping을 둘러싼 버그 ("JVM segfault 및 그래픽 드라이버 충돌이 더욱 악화 되더라도!")이 많이 있습니다. 우아한 기본 기능은 관리되는 세상에서 복잡하고 추악합니다. –

+0

@AleksandrDubinsky 당신은 (우아함이 우아 해지는 것에 대해) 정확히 맞습니다. - 마지막 결과는 시스템에 심각한 불안정성을 초래하지 않으면 서 mmap'ed 파일을 빨리 만들 수 없다는 것입니다 (이 스레드에서 명확하게했는지는 모르겠지만 나는 블루 스크린 내 윈도우 dev에 기계를 관리). 이 세부 사항은 피터 (아래)가 크로니클에서 상당한 성공을 거두었음에도 불구하고 AsyncFileChannel을 사용하여 파일 I/O를 사용하고 mmap을 피하기를 원했습니다. –

+0

@AleksandrDubinsky 일단 VM과 내 컴퓨터 모두 mmapped 파일의 "잘못된 사용"이있는 무릎에 가져 왔을 때, 나는 그 경로로가는 것으로 끝났습니다. 그것들은 우아하고 환상적인 성능을 제공하지만 AsyncFileChannel에서 더 많이 읽었을 때 동일한 성능 (OS가 FS 및 디스크 컨트롤러와 I/O 순서를 사용하여 요청을 최적화 할 수있게 해줍니다)에 가깝게 느껴질 수 있습니다. 정말로 mmap 경로를 내려가고 싶다면, Peter는 전문가입니다. –

답변

15

당신은 내가 같은 파일을 여러 개의 메모리 매핑 파일은 크기까지 (크기가 될 수 있습니다 (크기가 2까지 GB 1의 힘)를 만들고이에서

https://github.com/peter-lawrey/Java-Chronicle에 관심이있을 수 있습니다 하드 드라이브)

또한 임의의 레코드를 임의로 찾을 수 있도록 인덱스를 생성하며 각 레코드는 모든 크기가 될 수 있습니다.

프로세스간에 공유 될 수 있으며 프로세스 간의 대기 시간이 짧은 이벤트에 사용됩니다.

많은 양의 데이터를 사용하려는 경우 64 비트 OS를 사용한다고 가정합니다. 이 경우 MappedByteBuffer의 List는 당신이 필요로하는 것입니다. 작업에 적합한 도구를 사용하는 것이 좋습니다. 당신은 당신의 질문을하기 때문에 약간의 통찰력을 얻은 경우)

내가 빠른 SSD 드라이브 YMMV 그래서)

+0

은 당신이 크로니클 작성자임을 알지 못했습니다. 답장을 보내 주셔서 감사합니다. 파일에 쓰는 것을 어떻게 처리합니까, MBB를 통하는 것인가, 직접 FileChannel을 호출 할 것인가, 그리고 read op가 들어올 때마다, MBB의 경계선 밖에서 새로운 것을 만들고 그것을 당신의 파일에 추가합니다. dataBuffers 목록? 필자가 놓친 핵심 세부 사항은 큰 매핑 파일 중 * 많은 *이 호스트 OS의 메모리 사용량에 미치는 영향입니다. (다음 댓글에서 cont ...) –

+0

mem-mapping 할 때 "연속 램"의 요구가있는 것 같습니다. 64MB 나 128MB와 같은 안전한 것으로 결정하고 DB 파일이 커지고 요청이 들어올 때 기존 맵핑 된 경계를 넘어서는 데이터.그렇다면 나의 데이터 파일이 GBs의 100s에 도달하고 1000 바이트가 아닌 mem-mapped byte 버퍼가 있다면 100s가 있다고 가정 해 봅시다. VM이 채워지는 것처럼 내 호스트 컴퓨터가 페이징을 시작하도록 설정하는 것 같습니다. 나는 gotcha-cases를 알고 싶다. 그리고 단점은 내가 묻고있는 것의 핵심이다. –

+0

각 메모리 맵 파일은 다소 비쌉니다. (정확한 세부 정보가 없습니다.) 1MB의 매핑을 많이 작성하면 리소스가 매우 빨리 소진됩니다. 그러나 1GB 버퍼를 사용하는 경우 8TB 파일을 만들 수 있습니다. 많은 작은 시스템 (예 : 4KB)을 생성하여 시스템에 너무 많은 양을 결정할 수 있습니다. –

2

mmap'ping 파일에 대해 최대 2GB의 크기를 신경 쓰지 않아도됩니다.

메모리 매핑 된 파일을 사용하는 DB의 예로 MongoDB의 출처를 살펴보면 항상 MemoryMappedFile::mapWithOptions() (MemoryMappedFile::map())의 전체 데이터 파일을 매핑한다는 것을 알 수 있습니다. DB 데이터는 각각 최대 2GB 크기의 여러 파일에 걸쳐 있습니다. 또한 데이터 파일을 미리 할당하므로 데이터가 커짐에 따라 다시 매핑 할 필요가 없으며 이로 인해 파일 조각화가 방지됩니다. 일반적으로이 DB의 소스 코드를 사용하여 자신을 고취시킬 수 있습니다.

+1

@Thomas 링크를 업데이트했지만 코드가 꽤 오래되었다고 생각합니다. MongoDB는 그 이후로 많은 변화를 겪었습니다. – pingw33n

관련 문제