DBMS의 성능에 가장 많이 영향을 미치는 config는 아무래도 메모리 일 것이다. 그렇기에 오늘은 Neo4j의 메모리 configuration을 공부해보고자 한다. 다음 글은 Neo4j 공식문서를 바탕으로 구성한 글이다.
Neo4j Memory Mangement
OS memory
OS를 위해 남겨놓는 memory 공간을 의미한다. 이는 Neo4j가 사용하는 memory가 swap되지 않게 하기 위해서 남겨놓아야 한다.
JVM heap
Neo4j는 java기반 언어이기 때문에 JVM Heap을 위한 메모리가 존재해야한다. JVM Heap이란 Java에서 동적으로 생성되는 객체들이 저장되는 공간이다. 해당 메모리는 JVM Heap영역이기 때문에 Neo4J가 관리하지 않고 Java의 garbage collector가 메모리 해제를 전담한다.
Neo4j서버에서 이러한 JVM Heap에 대한 메모리 공간을 파악하기 위해서는 다음과 같은 configuration을 참고하면 된다.
다음은 아무런 configuration 설정 조정 없이 실행한 Neo4j의 docker에서 관련 설정에 대해서 찾아 본 것이다.
공식 문서에서는 initial_size와 max_size를 같게 하지 않기를 권유하는데 이는 heap 영역이 고정되어 있어 있어 전체 garbage collector가 멈추고 해제를 시킬 메모리 공간을 찾기 위해 heap영역에 대한 전체 탐색을 진행한다면 이는 성능적으로 저하가 일어나기 때문이다.
Transaction
해당 메모리 영역은 Neo4j의 트랜잭션에 사용되는 메모리 영역이다. Neo4j는 ACID한 트랜잭션을 지원하기 때문에 트랜잭션마다 고유의 메모리 영역을 가지게 된다. 물론 모든 트랜잭션에 대해서 메모리 영역이 할당되어지는 것은 아니다. 읽기만 하는 트랜잭션은 Transaction memory가 할당되지 않는다. 그렇기 때문에 해당 영역은 Neo4j를 어떻게 사용하는지에 따라 종속적으로 크기가 정해진다.
위의 그림을 다시 살펴보자. Transaction Memory에 해당하는 박스의 크기가 JVM heap과 Native Memory에 걸쳐있는 것을 알 수 있다. Transaction memory는 기본적으로 on-heap에 할당이 되지만 트랜잭션의 쿼리가 길거나 복잡하여 많은 메모리가 필요로 해진다면 on-heap과 더불어 off-heap에 메모리를 할당할 수 있다. 물론 disk I/O보다는 속도가 off-heap이 빠르지만 on-heap에 모두 할당되는 것과 비교하면 성능 저하가 일어난다. 따라서 Neo4j의 공식문서에서는 되도록이면 모든 Transaction memory가 on-heap에 할당 되는 것을 권장한다.
관련 설정은 다음과 같이 확인이 가능하다.
1) 트랜잭션 메모리 최대 용량
2) 트랜잭션 메모리 중 off-heap 메모리로 할당될 수 있는 최대 용량
기본적으로 설정이 되어 있지 않지만 다음과 같은 설정을 추가하면 이에 대한 용량 제한이 가능하다.
dbms.tx_state.max_off_heap_memory
Native memory
OS로부터 Neo4j 프로세스를 위해서 할당 받은 메모리 공간을 의미한다. 이들은 garbage collector에 의해서 해제가 되지 않기 때문에 off-heap memory라고도 불린다.
Page cache
page cache는 disk에 있는 데이터를 메모리에 저장하여 caching을 진행하는 것을 의미한다. 이들은 기본적으로 Native Memory, 즉 off-heap에 할당이 되면 이에 대한 설정을 하는 configuration은 다음과 같이 확인할 수 있다.
Network buffers
Neo4j가 데이터를 보내고 받을 때 사용되는 buffer로써 해당 buffer의 용량이 커지게 되면 Network로 주고받는 데이터를 Java계열의 언어와 Native 언어로 구동되는 프로세스들이 copy과정 없이 직접적으로 공유가 가능하다. 따라서 만약 Network로 주고 받는 데이터에 대한 access가 여러 프로세스에서 일어난다면 Network buffer의 size를 조절하는게 맞을 것이다. 하지만 해당 메모리 영역을 할당하는 것에 대한 cost가 높기 때문에 재사용성이 높은 메모리 영역이다.
JVM overhead
JVM이 구동되기 위해서 필요한 부가적인 영역을 의미한다. 해당 영역에서 관리되는 데이터들은 Thread stacks, Metaspace, Code cache등이 존재한다.
부가적인 팁
Initial memory recommendation
만약 메모리 설정을 처음에 어떻게 하면 좋을지에 대한 추천을 받고 싶다면 다음과 같은 방식으로 자신의 machine의 스펙에 따라 메모리 영역 추천을 받을 수 있다.
root@ecb9297bd880:~# neo4j-admin server memory-recommendation
# Memory settings recommendation:
#
# Assuming the system is dedicated to running Neo4j and has 7.666GiB of memory,
# we recommend a heap size of around 3500m, and a page cache of around 1900m,
# and that about 2500m is left for the operating system, and the native memory
# needed by Lucene and Netty.
#
# Tip: If the indexing storage use is high, e.g. there are many indexes or most
# data indexed, then it might advantageous to leave more memory for the
# operating system.
#
# Tip: Depending on the workload type you may want to increase the amount
# of off-heap memory available for storing transaction state.
# For instance, in case of large write-intensive transactions
# increasing it can lower GC overhead and thus improve performance.
# On the other hand, if vast majority of transactions are small or read-only
# then you can decrease it and increase page cache instead.
#
# Tip: The more concurrent transactions your workload has and the more updates
# they do, the more heap memory you will need. However, don't allocate more
# than 31g of heap, since this will disable pointer compression, also known as
# "compressed oops", in the JVM and make less effective use of the heap.
#
# Tip: Setting the initial and the max heap size to the same value means the
# JVM will never need to change the heap size. Changing the heap size otherwise
# involves a full GC, which is desirable to avoid.
#
# Based on the above, the following memory settings are recommended:
server.memory.heap.initial_size=3500m
server.memory.heap.max_size=3500m
server.memory.pagecache.size=1900m
#
# It is also recommended turning out-of-memory errors into full crashes,
# instead of allowing a partially crashed database to continue running:
server.jvm.additional=-XX:+ExitOnOutOfMemoryError
#
# The numbers below have been derived based on your current databases located at: '/var/lib/neo4j/data/databases'.
# They can be used as an input into more detailed memory analysis.
# Total size of lucene indexes in all databases: 0k
# Total size of data and native indexes in all databases: 624k
다음 결과에서 추가적으로 눈여겨봐야 하는 값들이 있다.
1) Lucend index 사용량
Neo4j는 Apache의 Lucence index를 통해 full-text search를 지원하는데 이를 위해 사용되는 Lucene index 사용량을 확인 할 수 있다.
# Total size of lucene indexes in all databases: 0k
2) 전체 데이터 사용량
전체 데이터 및 인덱스 사용량 또한 확인이 가능하다.
# Total size of data and native indexes in all databases: 624k
Page Cache 용량 산정 방법
공식 문서에서는 Page Cache 크기를 전체 데이터 사용량의 1.2배로 산정하라는 설명이 존재한다.
트랜잭션 메모리 제한
트랜잭션 메모리에 대한 상한선이 존재하지 않다면 OOM 에러로 프로세스가 종료될 수 있다. 따라서 이러한 트랜잭션에 대한 메모리 제한을 공식문서에서는 제안한다.
관련 설정에는 다음 2가지가 존재한다.
1) DB당 트랜잭션 메모리 상한선
db.memory.transaction.total_max
2) 트랜잭션당 상한선
db.memory.transaction.max
출처
https://neo4j.com/docs/operations-manual/current/performance/memory-configuration/
긴 글 읽어주셔서 감사합니다.
틀린 부분이 있으면 댓글을 달아주시면 감사하겠습니다.
📧 : realhwan1202@gmail.com
'개발 > Neo4j' 카테고리의 다른 글
[Neo4j] Cypher Query - (1) (1) | 2023.05.04 |
---|---|
[Neo4j] Neo4j Docker Compose (0) | 2023.05.03 |
[Neo4j] 그래프 데이터베이스란? (0) | 2023.05.03 |