Neo4j 성능 – 속도를 고려한 설계
Neo4j 성능 을 포함하여 일반적으로 데이터베이스 성능에 대한 경험이 있는 사람은 성능 에 영향을 미치기 위해 사용할 수 있는 레버와 어떤 방식으로 사용할 수 있는지 이해하기 위해 시스템에 기계적 공감 을 갖는 것이 중요하다고 말할 것입니다 . 그래프 세계에는 성능에 중요한 영향을 미치는 두 가지 주요 범주의 데이터베이스가 있습니다.
첫째, 다중 모델 또는 유사한 접근 방식의 일부 변형을 활용하는 비원시 그래프 데이터베이스 옵션이 많이 있습니다. 그래프의 논리적 표현의 일종으로 파사드 가 있는 단일 데이터 저장소(예: Oracle, MongoDB 등) 인지 또는 RDF 트리플을 자주 저장하는 실제 다중 모델 데이터베이스(예: ArangoDB, MarkLogic 등)인지 여부(대부분은 아니지만) 이러한 비네이티브 그래프 데이터베이스는 모두 성능 저하를 일으킬 수 있는 일종의 중간 계층을 추가합니다. 이 간접 계층은 데이터베이스가 기본 데이터 저장소와 그래프로 상호 작용할 수 있도록 하는 일종의 논리적 그래프 모델 역할을 합니다.
두 번째 범주는 기본 그래프 데이터베이스입니다 . 이는 본질적으로 개조가 아니라 아래에 더 자세히 설명된 몇 가지 핵심 아키텍처 마커가 있는 그래프 사용 사례를 위해 특별히 제작되었음을 의미합니다. Neo4j는 진정한 네이티브 그래프 데이터베이스의 몇 안 되는 예 중 하나이며 규모에 따라 고유하게 수행할 수 있습니다. 기본 아키텍처는 조직이 무결성, 일관성 및 성능을 유지하면서 거의 실시간으로 연결된 데이터로 애플리케이션을 구축할 수 있도록 하는 몇 가지 기본적인 이점을 외부에서 제공한다는 것을 의미합니다.
시간을 거슬러 올라가 Neo4j 아키텍처 이해하기
Neo4j는 그래프 데이터 구조를 생성 및 저장하기 위한 임베디드 Java 라이브러리( Neo4j 끝에 있는 " 4j" 는 "for Java"를 나타냄)로 시작했으며, 초기 트랜잭션에 중점을 둔 독립형 그래프 데이터베이스 시스템으로 시간이 지남에 따라 진화했습니다. 거의 실시간으로 처리되는 사용 사례에서도 성능(즉, OLTP 사용 사례). 시간이 지남에 따라 그래프 분석 의 출현 으로 Neo4j의 초점은 그래프 데이터 과학 및 분석(즉, OLAP 사용 사례)과 관련된 강력한 기능도 포함하도록 이동하기 시작했으며, 이제 이를 하이브리드 트랜잭션 및 분석 처리 범주에 정확히 넣습니다. (HTAP) 시스템.
조직은 기존의 연결된 사용 사례든 그래프 데이터베이스 에서 상당한 이점을 얻을 수 있는 다른 많은 사용 사례든 상관없이 데이터 집약적 트랜잭션 시스템에 대한 필요성을 계속해서 개발하고 있습니다 . 이러한 사용 사례는 종종 (RDBMS 시스템에서와 같이) 나중 분석을 위해 데이터를 복사 및 재구성할 필요 없이 보장된 데이터 일관성을 필요로 하고 다른 한편으로 진행 중인 임베디드 분석을 필요로 합니다. Neo4j는 트랜잭션 및 분석 사용 사례를 단일 HTAP 시스템으로 통합하여 단일 데이터베이스 내에서 우아하고 결합된 아키텍처를 가능하게 하는 그래프 데이터베이스 공간의 초기 리더였습니다.
먼저 서로 다른 부품이 함께 작동하는 방식을 이해함으로써 Neo4j 플랫폼에 기계적 공감을 얻을 수 있는 기회를 갖게 되며, 이를 통해 성능을 추가로 조정할 때 해당 지식을 사용할 수 있습니다. 따라서 먼저 일반적으로 데이터베이스 관리 시스템의 높은 수준의 아키텍처를 이해한 다음 Neo4j가 인덱싱에서 스토리지에 이르기까지 모든 것을 살펴보고 다양한 그래프 워크로드를 처리하도록 구축된 방법을 더 깊이 살펴보겠습니다.
데이터베이스 관리 시스템 – 고급 아키텍처
네이티브 프로세싱과 스토리지를 포함한 Neo4j 아키텍처의 고유성을 파헤치기 전에 먼저 시작점으로 사용할 일반화된 데이터베이스 관리 시스템(DBMS)의 상위 수준 아키텍처를 이해합시다. 데이터베이스 아키텍처가 예상치 못한 제약 조건이 나타나며 진화하고 경계가 종종 독립적인 구성 요소가 다양한 성능 최적화를 추진하기 위해 밀접하게 결합되어 명확하게 묘사하기 어렵기 때문에 이것이 가장 간단한 작업은 아닙니다.
가장 높은 수준에서 DBMS 시스템은 클라이언트/서버 모델을 따르며 데이터베이스는 서버로, 애플리케이션 인스턴스 또는 인터페이스는 클라이언트로 작동합니다. 또한 DBMS 시스템은 기본적으로 데이터를 저장하기 위해 여전히 파일을 사용하고 있지만 이를 저장하기 위해 고전적인 폴더/파일 시스템 접근 방식에 의존하는 대신 데이터베이스별(종종 독점) 형식을 사용하여 파일을 구성한다는 점을 이해하는 것이 도움이 됩니다. 이러한 광범위한 아키텍처 요소 외에도 아래 이미지에서 참조 프레임으로 사용할 DBMS 아키텍처의 가장 일반적인 구성 요소로 간주될 수 있는 것을 추상화하기 위해 최선을 다합니다.
일반 DBMS 아키텍처 구성 요소와 Neo4j의 고유한 접근 방식
전송: 데이터베이스와의 상호 작용이 시작되면 클라이언트 쿼리가 전송 하위 시스템을 통해 도착하여 쿼리 프로세서로 전달됩니다.
- Neo4j는 같은 방식으로 작동합니다.
쿼리 프로세서: 쿼리 프로세서는 해석, 유효성 검사 등을 위해 쿼리를 구문 분석한 후 쿼리 최적화 프로그램(예: 쿼리 플래너)이 담당하여 데이터를 처리하고 검색하는 가장 효율적인 방법을 찾습니다.
- Neo4j는 특히 대부분의 쿼리 플래너와 마찬가지로 내부 통계, 인덱스, 제약 조건, 데이터 배치 등을 기반으로 하는 Cypher 쿼리 플래너를 사용합니다.
실행 엔진: 모든 데이터베이스 시스템의 쿼리 프로세서에서 나오는 출력은 수행될 작업의 시퀀스인 실행 계획입니다. 이 실행 계획은 결과를 수행하고 집계하는 실행 엔진으로 전달됩니다.
- Neo4j는 쿼리를 연산자라고 부르는 개별 요소로 분해하며, 이는 실행 계획인 트리와 같은 구조(아래에서 더 자세히 설명됨)로 결합됩니다. 또한 Neo4j에서 리프 노드는 궁극적으로 레코드로 확인되고 출력은 트리 위로 파이프되는 반면 비 리프 노드는 업스트림 분기에서 하위 선택 출력 세트가 필요합니다.
- 팁 1: Neo4j 성능 조정의 경우 쿼리를 더 잘 이해하기 위해 개발자는 Cypher EXPLAIN 쿼리 를 사용하여 실행 계획을 확인하고 Cypher PROFILE 쿼리 를 사용하여 행이 연산자를 통해 전달되는 방식을 추적할 수 있습니다.
데이터베이스 인덱싱 및 Neo4j 인덱스 성능
DBMS 시스템의 경우 인덱싱 은 읽기 성능을 향상시키는 데 중요한 기능입니다. 새로 고침으로써 데이터베이스 인덱스는 검색을 용이하게 하고 레코드 키를 디스크의 위치에 매핑하는 방식으로 디스크의 데이터 레코드를 구성하는 구조(예: 책의 인덱스와 매우 유사)입니다. 그러나 데이터베이스가 성장함에 따라 인덱스도 커지고 시간이 지남에 따라 특히 쓰기 성능(예: 삽입, 업데이트, 삭제)에 영향을 줄 수 있으며 상당한 양의 디스크 공간을 차지할 수도 있습니다.
Neo4j 인덱스 성능(또는 모든 기본 그래프 데이터베이스)은 성능에 상당한 부정적인 영향을 미칠 수 있는 기존 인덱싱에 의존하지 않습니다. 대신 인덱스가 없는 인접성(index-free adjacency)이라는 것을 활용합니다. 즉, Neo4j에서는 단일 연결 목록만 있는 모든 노드가 인접/다음 노드를 직접 참조하며, 이는 노드 자체에 저장된 일종의 마이크로 인덱스 역할을 합니다. . Neo4j의 에지는 항상 다음 노드뿐만 아니라 이전 노드도 참조하는 이중 연결 목록 입니다.
이 인덱스 없는 인접성을 사용하는 것이 실제로 네이티브 그래프 처리를 정의하는 것입니다. 네이티브 그래프 쿼리 및 처리가 데이터 크기에 관계없이 일정한 속도로 수행되기 때문에 고성능 그래프 쿼리에도 중요합니다(예: 쿼리 시간은 항상 검색되는 그래프의 양/순회 크기에 비례합니다. O(1) " 대 그래프 크기 " O(log n) "), 데이터가 증가함에 따라 더 오래 걸리는 기존 인덱싱을 사용하는 것과 비교됩니다. 아래 이미지는 그래프의 가장자리에 대한 이중 연결 목록과 각 노드가 인접 노드를 참조하는 인접성을 시각적으로 보여줍니다.
더 깊이 파고들기 위해, 아래 표는 바이트 자체가 노드 에 어떻게 분배되고 해당 노드의 모든 요소가 인덱스에 의해 사용되는지를 보여줍니다.
아래 이미지는 인덱스에서도 사용되는 노드와 관계 모두에 대한 정확한 저장소 파일 레코드 구조를 보여줍니다.
다음은 Neo4j가 그래프 조회 및 순회를 수행하는 데 사용하는 단계입니다.
- 조회 요청은 포인터를 전역 인덱스의 첫 번째 레코드로 이동합니다.
- 그런 다음 시작 노드(또는 다른 개체) 바이트 크기 또는 관계 ID 바이트 크기에 노드 저장소 레코드 크기(바이트 단위)를 곱하여 오프셋을 바이트 단위로 계산하여 시작 노드 주소를 찾습니다.
- 그런 다음 조회 요청에서 관련 에지 및 속성에 대한 바이트 크기 주소도 조회합니다.
관계에 대한 위의 파일 레코드 구조 그림을 보면 그래프 관계가 레코드 구조의 시작 노드(첫 번째 노드), 끝 노드(두 번째 노드), 관련 관계 및 속성 블록에 대한 주소를 보유하지만 두 가지 모두에서 방향(다음 및 이전).
메모리에서 데이터를 참조하고 포인터를 사용하여 직접적으로 포인터 에서 포인터로 이동하는 다양한 객체(예: 노드, 에지 등)의 연결 목록을 반복함으로써(자바에서는 이를 "참조"라고 하며 Neo4j는 종종 " chasing pointers”), 쿼리에 필요한 실제 디스크 읽기 횟수를 줄여 Neo4j 성능을 크게 향상시킵니다.
Neo4j 글로벌 인덱스 유형
Neo4j 인덱스 성능은 제공하는 3가지 글로벌 레지스트리 인덱스 유형 ( b-tree , 전체 텍스트 및 다양한 사용 사례에 대한 토큰 조회 )을 기반으로 합니다.
- B-트리 인덱스 는 속성을 노드 또는 에지에 매핑하여 모든 유형에 대해 정확한 인덱스 조회를 수행합니다. B-트리 인덱스는 대부분의 다른 데이터베이스에 공통적으로 가장 많이 사용되는 저장소 구조 중 하나이며 하드웨어의 효율적인 운영과 사용을 제공하는 것으로 알려져 있습니다. 그것들은 트리 높이를 줄이는 경향이 있으며, 또한 정렬된 순차 액세스를 가능하게 합니다. Neo4j의 컨텍스트에서 정확한 속성 값을 노드 또는 관계에 매핑하여 더 빠른 탐색을 가능하게 하도록 설계되었습니다.
- 토큰 조회 색인 은 이제 Neo4j 4.3부터 모든 노드 레이블 및 관계 유형에 대해 기본적으로 생성됩니다. 종종 최적화된 b-트리 인덱스를 선택하고 사용하는 것이 더 성능이 좋지만 이제 기본적으로 토큰 인덱스를 항상 사용할 수 있습니다. 이 인덱스를 사용하면 모든 노드 레이블을 스캔하고 필터링하는 것을 방지하는 레이블을 통해 노드를 일치시킬 수 있습니다. 팁 2: 토큰 인덱스를 삭제할 때 쓰기에 대한 관련 성능 향상에도 불구하고 인덱스는 다른 인덱스 옵션을 채우는 효율성을 개선하고 읽기 쿼리를 개선하는 데에도 사용되므로 유지하는 데 시간을 할애할 가치가 있습니다.
- 전체 텍스트 인덱스 는 텍스트 검색( Apache Lucene 사용 )과 관련된 사용 사례에 대해 구현됩니다.
아래는 B-tree 인덱스의 구조를 나타낸 그림이다. 단일 링크 구조에서 부모 노드가 자식 노드를 가리키는 식으로 트리 아래로 내려가는 것을 볼 수 있습니다(여기에는 표시되지 않았지만 각 노드는 키/값 쌍을 보유함).
위에서 설명한 인덱싱 및 조회 접근 방식은 성능 향상에 강력하지만 이를 지원하는 스토리지 아키텍처와 함께 작동해야 합니다. 다음으로, 네이티브 그래프 데이터베이스를 진정한 네이티브로 만드는 다른 측면인 스토리지 엔진 에 대해 자세히 살펴보겠습니다 .
네이티브 그래프 스토리지 엔진
기본 그래프 스토리지 엔진이 무엇인지 요약하는 가장 쉬운 방법은 스토리지 구조가 그래프 최적화 상호 작용을 위해 특별히 제작되었다는 것입니다. Neo4j의 경우 이 네이티브 그래프 스토리지는 노드, 에지 등의 고정된 레코드 구조와 레코드를 포함하는 스토어 파일에서 다음과 같이 입증됩니다. 다른 데이터베이스와 마찬가지로 Neo4j의 경우 물리적 스토리지와 메모리의 두 가지 주요 스토리지 유형이 있습니다(아래에서 더 자세히 설명).
물리적 스토리지
Neo4j 에서 물리 디스크 에 저장된 데이터는 인덱스 없는 인접 원칙에 따라 저장됩니다. 그래프는 아래 표와 같이 일반적으로 레코드 유형(이전에 설명한 고정 크기 레코드 형식 포함)별로 분류되는 저장 파일이라고 하는 파일 세트로 구성됩니다.
팁 3: Neo4j 성능 조정의 경우 EXT4 및 XFS를 사용하고 NFS 또는 NAS 파일 시스템 을 사용하지 마십시오 .
팁 4: 또 다른 Neo4j 성능 조정 옵션은 데이터와 트랜잭션 로그를 별도의 드라이브에 저장하여 경합을 피하고 I/O가 둘 다 동시에 발생하도록 하는 것입니다.
메모리
Neo4j는 데이터 저장을 위해 디스크 기반 접근 방식을 사용하지만 성능을 위해(또는 임시 저장으로) 디스크 내용을 캐싱하기 위해 메모리에 크게 의존합니다. 예상대로 Neo4j 는 디스크 I/O 비용을 크게 줄여주기 때문에 메모리에 캐시된 데이터를 최대한 활용할 때 최상의 성능을 발휘합니다.
팁 5: Neo4j는 Java 기반이므로 추가 옵션은 neo4j.conf 파일을 통해 직접 개체 메모리를 구성하는 것입니다. 이러한 방식으로 개발자는 JVM을 활용하여 다른 조정 옵션 중에서 가비지 수집기 사용과 JVM 힙 공간의 균형을 조정하여 성능을 최대화하도록 메모리 구성을 조정할 수 있습니다.
그러나 실제로, 특히 지난 10년 동안 메모리 비용이 크게 낮아졌기 때문에 프로덕션 용도로 전체 그래프를 메모리에 저장하는 것이 이제는 매우 일반적입니다.
팁 6: Neo4j 메모리 설정의 크기를 적절하게 조정하기 위한 메모리 계산 규칙은 다음과 같습니다. Total Physical Memory = Heap + Page Cache + OS Memory . 모든 레코드의 크기가 고정되어 있으므로 핵심 데이터에 필요한 공간을 정확하게 계산할 수도 있습니다.
Neo4j 메모리 사용에 더 익숙해지기 위해 아래 그림은 상황에 맞게 설명합니다.
하드웨어 스케일링 을 통한 Neo4j 성능 (Neo4j 배포)
대규모 확장성은 여전히 모든 그래프 데이터베이스의 과제이며 neo4j의 한계 중 하나로 제시되었지만 시장과 기술이 성숙해짐에 따라 Neo4j는 문제를 창의적이고 잘 해결하고 있습니다. 주요 문제는 아래에 설명된 그래프 데이터의 고유성을 감안할 때 확장하는 동안 동기화를 유지하기 위해 많은 서버에서 상태를 유지 관리하는 문제입니다.
최근까지 Neo4j는 복제(여러 서버에 하나의 데이터베이스 콘텐츠 복사)를 사용한 다음 각 요청을 원하는 부분을 보유하는 데이터베이스 인스턴스로 라우팅 하는 해결 방법 호출 캐시 샤딩을 통해 Neo4j 샤딩 (확장)을 사용하여 수평으로 확장할 수 있었습니다. 이미 메모리에 있는 그래프의 반대로, 샤딩에 대한 표준 접근 방식은 데이터를 서로 다른 클러스터 노드에 배포하며, 각 노드는 자체 읽기 및 쓰기를 수행할 수 있으며 종종 서로 다른 사용자가 중복된 별도의 데이터 세트에 액세스합니다.
그렇다면 샤딩에 대한 표준 접근 방식을 사용하지 않는 이유는 무엇입니까? 그 이유는 속성 그래프 모델이 쿼리의 기반으로 노드와 노드 간의 물리적 연결에 의존한다는 사실에서 찾을 수 있습니다. 쿼리가 네트워크 경계를 넘어 하위 그래프를 관리해야 하고 여전히 모든 관계, 데이터 일관성 및 무결성과 함께 ACID 준수 를 유지하려고 시도해야 하는 경우 고유하게 해결하기 어려운 문제가 됩니다. 사실 이를 푸는 어려움이 너무 커서 NP-hard 문제 범주로 분류 된다.
Neo4j 확장성 제한이 있습니까? Neo4j 샤딩 작업 만들기
그렇다면 이것이 Neo4j 확장성 한계를 나타내는 것입니까? 전혀. 버전 4.0이 출시됨에 따라 Neo4j는 이제 진정한 Neo4j 분산 데이터베이스 접근 방식을 제공하는 경로에 있음이 분명하며, 이를 통해 표준 샤딩 방식에 접근할 수 있습니다.
그렇다면 샤딩에 대한 Neo4j 접근 방식은 어떻게 발전했을까요? 버전 4.0부터 Neo4j는 서버 및 네트워크 전반에 걸쳐 서로 다른 Neo4j 데이터베이스 인스턴스에 하위 그래프를 분산하여 분할합니다. 엔티티 간의 관계를 유지하기 위해 두 샤드에서 두 샤드 간의 관계를 유지하는 노드를 복제합니다. 이것이 의미하는 바는 이제 개발자가 데이터 세트를 샤딩할 수 있지만 이 시점에서 샤드를 순회할 수 없기 때문에 여전히 관계를 샤딩할 수 없다는 것입니다 .
서버와 네트워크 전반의 상태 문제를 관리하기 위해 Neo4j는 이제 Neo4j Fabric을 제공하여 쿼리 프로세스를 관리합니다. 항상 모든 샤드를 인식하면서 데이터베이스 엔터티 및 위치의 마스터 표현을 유지하여 모든 샤드에서 요청 및 연결 정보를 관리하는 프록시로 생각할 수 있습니다. Neo4j Fabric 자체는 데이터를 보유하지 않습니다.
일반적으로 샤딩할 때 여전히 남아 있는 문제 중 하나는 이러한 맥락에서 분산 컴퓨팅의 오류도 존재하기 때문에 액세스 패턴을 미리 계획해야 한다는 것입니다. 이러한 위험에 효과적으로 대응하기 위해 Neo4j는 일관성을 유지하기 위해 인과 관계 클러스터링 을 제공했습니다.
인과적 클러스터는 통신이 중단될 수 있는 경우에도 단일 서버 단위(클러스터)가 복제본 간에 상태를 유지할 수 있도록 설계되었습니다. 인과적 일관성 과 합의 알고리즘 을 적용하여 확장하면서 많은 서버에서 상태를 동기화하는 솔루션을 제공합니다 .
인과적 일관성 모델은 원인과 결과를 정의합니다. 즉, 인과 관계가 있는 작업이 처리되는 순서(종종 인과 순서 라고 함)를 보면 발생하는 것과 동일한 순서로 동시 쓰기가 적용됩니다 . 이러한 방식으로 분산 일관성을 위해 읽기-쓰기 를 보장합니다.
합의 알고리즘의 경우 또한 분산 컨텍스트에서 상태 동의를 용이하게 합니다. 이를 달성하기 위해 Neo4j는 Raft 프로토콜 을 활용하여 마스터 선택을 처리하고 클러스터 전체에서 일관된 로그를 유지합니다. 이는 분산 컨텍스트에서 ACID 호환 샤딩을 활용할 수 있는 중요한 단계를 나타냅니다. Raft 프로토콜 을 더 자세히 설명하는 이 대화형 프레젠테이션을 확인하십시오 .
Neo4j의 한계가 있습니까?
모든 데이터베이스와 마찬가지로 각 데이터베이스에 가장 적합한 사용 사례가 있습니다. 따라서 모든 데이터베이스 사용 사례가 그래프용이 아니라는 점에서 Neo4j의 제한 사항은 다른 모든 데이터베이스와 동일합니다. 일반적으로 이 질문이 나오면 Neo4j 확장성 제한에 관한 것이며 플랫폼이 성숙해짐에 따라 이 질문은 무의미해지고 있습니다. 사실, 분할 문제가 창의적으로 해결되는 과정에 있는 Neo4j 4.0에서 수직 및 수평 확장의 조합은 상상할 수 있는 모든 규모에서 거의 모든 그래프 사용 사례를 가능하게 합니다.
Neo4j 성능: 결론
Neo4j의 기본 그래프 아키텍처의 성능 이점을 탐색함으로써 데이터베이스 시스템으로서 Neo4j 성능 튜닝은 여러 면에서 바로 아키텍처의 일부일 뿐이라는 것이 분명해졌습니다. 여기에는 몇 가지 유용한 팁이 포함되어 있지만 Neo4j 성능에 긍정적이고 직접적인 영향을 미치는 추가 방법으로 neo4j 그래프 모델링 및 neo4j 쿼리 설계 최적화에 대한 향후 기사를 살펴보십시오.
[광고] STEEM 개발자 커뮤니티에 참여 하시면, 다양한 혜택을 받을 수 있습니다.
Downvoting a post can decrease pending rewards and make it less visible. Common reasons:
Submit