mmap 사용
메모리 매핑(Mmap)을 사용하면 디스크의 대용량 파일에 직접 메모리에 액세스할 수 있으므로 Milvus는 인덱스와 데이터를 메모리와 하드 드라이브 모두에 저장할 수 있습니다. 이 접근 방식은 액세스 빈도에 따라 데이터 배치 정책을 최적화하여 검색 성능에 큰 영향을 주지 않으면서 컬렉션의 저장 용량을 확장하는 데 도움이 됩니다. 이 페이지에서는 Milvus가 mmap을 사용하여 빠르고 효율적인 데이터 저장 및 검색을 가능하게 하는 방법을 설명합니다.
개요
Milvus는 컬렉션을 사용하여 벡터 임베딩과 해당 메타데이터를 구성하며, 컬렉션의 각 행은 엔티티를 나타냅니다. 아래 왼쪽 그림에서 볼 수 있듯이 벡터 필드에는 벡터 임베딩이 저장되고 스칼라 필드에는 해당 메타데이터가 저장됩니다. 특정 필드에 인덱스를 생성하고 컬렉션을 로드하면 Milvus는 생성된 인덱스와 필드 원시 데이터를 메모리에 로드합니다.
Mmap 예시
Milvus는 메모리 집약적인 데이터베이스 시스템으로, 사용 가능한 메모리 크기에 따라 컬렉션의 용량이 결정됩니다. 데이터 크기가 메모리 용량을 초과하면 대용량의 데이터가 포함된 필드를 메모리에 로드할 수 없는데, 이는 AI 기반 애플리케이션에서 흔히 발생하는 문제입니다.
이러한 문제를 해결하기 위해 Milvus는 컬렉션에서 핫 데이터와 콜드 데이터의 로딩 균형을 맞추기 위해 mmap을 도입했습니다. 위의 오른쪽 그림에서 볼 수 있듯이, 특정 필드의 원시 데이터를 메모리에 완전히 로드하는 대신 메모리 매핑하도록 Milvus를 구성할 수 있습니다. 이렇게 하면 메모리 문제에 대한 걱정 없이 필드에 직접 메모리 액세스를 확보하고 컬렉션의 용량을 확장할 수 있습니다.
왼쪽 그림과 오른쪽 그림의 데이터 배치 절차를 비교하면, 왼쪽 그림에서 메모리 사용량이 오른쪽 그림보다 훨씬 더 많다는 것을 알 수 있습니다. mmap을 활성화하면 메모리에 로드되어야 할 데이터가 하드 드라이브로 오프로드되고 운영 체제의 페이지 캐시에 캐시되어 메모리 사용량이 줄어듭니다. 그러나 캐시 히트 실패로 인해 성능이 저하될 수 있습니다. 자세한 내용은 이 문서를 참조하세요.
Milvus에서 mmap을 구성할 때 항상 지켜야 할 원칙이 있습니다: 자주 액세스하는 데이터와 인덱스는 항상 메모리에 완전히 로드된 상태로 유지하고 나머지 필드에 있는 데이터와 인덱스는 mmap을 사용하세요.
Milvus에서 mmap 사용
Milvus는 글로벌, 필드, 인덱스, 컬렉션 수준에서 계층적 mmap 설정을 제공하며, 인덱스와 필드 수준은 컬렉션 수준보다, 컬렉션 수준은 글로벌 수준보다 우선합니다.
글로벌 맵 설정
클러스터 수준 설정은 전역 설정이며 우선순위가 가장 낮습니다. Milvus는 milvus.yaml 에서 몇 가지 mmap 관련 설정을 제공합니다. 이러한 설정은 클러스터의 모든 컬렉션에 적용됩니다.
...
queryNode:
mmap:
scalarField: false
scalarIndex: false
vectorField: false
vectorIndex: false
# The following should be a path on a high-performance disk
mmapDirPath: any/valid/path
....
구성 항목 |
설명 |
기본값 |
|---|---|---|
|
모든 스칼라 필드의 원시 데이터를 메모리에 매핑할지 여부를 지정합니다. |
|
|
모든 스칼라 필드 인덱스를 메모리에 매핑할지 여부를 지정합니다. 현재 다음 인덱스 유형을 사용하는 스칼라 필드만 지원됩니다:
|
|
|
모든 벡터 필드의 원시 데이터를 메모리에 매핑할지 여부를 지정합니다. 이 값을 |
|
|
모든 벡터 필드 인덱스를 메모리에 매핑할지 여부를 지정합니다. 이를 현재 다음 인덱스 유형을 사용하는 벡터 필드만 지원됩니다:
|
|
|
메모리 매핑된 파일의 경로를 지정합니다. 지정하지 않으면 기본값이 적용됩니다. 기본값의 |
|
위의 설정을 밀버스 클러스터에 적용하려면 헬름으로 밀버스 구성하기 및 밀버스 오퍼레이터로 밀버스 구성하기의 단계를 따르세요.
특정 사용 사례에 직면했을 때 글로벌 mmap 설정이 유연하지 않은 경우가 있습니다. 특정 컬렉션 또는 해당 인덱스에 대체 설정을 적용하려면 컬렉션, 필드 또는 인덱스에 특정한 mmap을 구성하는 것을 고려하세요. 컬렉션을 해제하고 로드해야만 mmap 설정 변경 사항이 적용됩니다.
필드별 mmap 설정
필드별 mmap을 구성하려면 필드를 추가할 때 mmap_enabled 매개 변수를 포함해야 합니다. 이 매개 변수를 True 으로 설정하여 이 특정 필드에서 mmap을 사용하도록 설정할 수 있습니다.
다음 예는 필드를 추가할 때 필드별 mmap을 구성하는 방법을 보여줍니다.
from pymilvus import MilvusClient, DataType
CLUSTER_ENDPOINT="http://localhost:19530"
TOKEN="root:Milvus"
client = MilvusClient(
uri=CLUSTER_ENDPOINT,
token=TOKEN
)
schema = MilvusClient.create_schema()
schema.add_field("id", DataType.INT64, is_primary=True, auto_id=False)
schema.add_field("vector", DataType.FLOAT_VECTOR, dim=5)
schema = MilvusClient.create_schema()
# Add a scalar field and enable mmap
schema.add_field(
field_name="doc_chunk",
datatype=DataType.INT64,
is_primary=True,
mmap_enabled=True,
)
# Alter mmap settings on a specific field
# The following assumes that you have a collection named `my_collection`
client.alter_collection_field(
collection_name="my_collection",
field_name="doc_chunk",
field_params={"mmap.enabled": True}
)
import io.milvus.param.Constant;
import io.milvus.v2.client.ConnectConfig;
import io.milvus.v2.client.MilvusClientV2;
import io.milvus.v2.common.DataType;
import io.milvus.v2.service.collection.request.*;
import java.util.*;
String CLUSTER_ENDPOINT = "http://localhost:19530";
String TOKEN = "root:Milvus";
client = new MilvusClientV2(ConnectConfig.builder()
.uri(CLUSTER_ENDPOINT)
.token(TOKEN)
.build());
CreateCollectionReq.CollectionSchema schema = client.createSchema();
schema.addField(AddFieldReq.builder()
.fieldName("id")
.dataType(DataType.Int64)
.isPrimaryKey(true)
.autoID(false)
.build());
schema.addField(AddFieldReq.builder()
.fieldName("vector")
.dataType(DataType.FloatVector)
.dimension(5)
.build());
Map<String, String> typeParams = new HashMap<String, String>() {{
put(Constant.MMAP_ENABLED, "false");
}};
schema.addField(AddFieldReq.builder()
.fieldName("doc_chunk")
.dataType(DataType.VarChar)
.maxLength(512)
.typeParams(typeParams)
.build());
CreateCollectionReq req = CreateCollectionReq.builder()
.collectionName("my_collection")
.collectionSchema(schema)
.build();
client.createCollection(req);
client.alterCollectionField(AlterCollectionFieldReq.builder()
.collectionName("my_collection")
.fieldName("doc_chunk")
.property(Constant.MMAP_ENABLED, "true")
.build());
import { MilvusClient, DataType } from '@zilliz/milvus2-sdk-node';
const CLUSTER_ENDPOINT="YOUR_CLUSTER_ENDPOINT";
const TOKEN="YOUR_TOKEN";
const client = await MilvusClient({
address: CLUSTER_ENDPOINT,
token: TOKEN
});
const schema = [
{
name: 'vector',
data_type: DataType.FloatVector
},
{
name: "doc_chunk",
data_type: DataType.VarChar,
max_length: 512,
'mmap.enabled': false,
}
];
await client.createCollection({
collection_name: "my_collection",
schema: schema
});
await client.alterCollectionFieldProperties({
collection_name: "my_collection",
field_name: "doc_chunk",
properties: {"mmap_enable": true}
});
// go
#restful
export TOKEN="root:Milvus"
export CLUSTER_ENDPOINT="http://localhost:19530"
export idField='{
"fieldName": "id",
"dataType": "Int64",
"elementTypeParams": {
"max_length": 512
},
"isPrimary": true,
"auto_id": false
}'
export vectorField='{
"fieldName": "vector",
"dataType": "FloatVector",
"elementTypeParams": {
"dim": 5
}
}'
export docChunkField='{
"fieldName": "doc_chunk",
"dataType": "Int64",
"elementTypeParams": {
"max_length": 512,
"mmap.enabled": false
}
}'
export schema="{
\"autoID\": false,
\"fields\": [
$idField,
$docChunkField,
$vectorField
]
}"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--data "{
\"collectionName\": \"my_collection\",
\"schema\": $schema
}"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/fields/alter_properties" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "my_collection",
"fieldName": "doc_chunk",
"fieldParams":{
"mmap.enabled": true
}
}'
대용량 데이터를 저장하는 필드에 mmap을 사용하도록 설정하는 것이 좋습니다. 스칼라 필드와 벡터 필드가 모두 지원됩니다.
그런 다음 위에서 생성한 스키마를 사용하여 컬렉션을 만들 수 있습니다. 컬렉션 로드 요청을 받으면 Milvus는 doc_chunk 필드의 원시 데이터를 메모리로 메모리 매핑합니다.
인덱스별 메모리 맵 설정
인덱스별 mmap을 구성하려면 인덱스를 추가할 때 인덱스 매개변수에 mmap.enable 속성을 포함해야 합니다. 속성을 true 으로 설정하여 이 특정 인덱스에서 mmap을 활성화할 수 있습니다.
다음 예는 인덱스를 추가할 때 인덱스별 mmap을 구성하는 방법을 보여줍니다.
# Add a varchar field
schema.add_field(
field_name="title",
datatype=DataType.VARCHAR,
max_length=512
)
index_params = MilvusClient.prepare_index_params()
# Create index on the varchar field with mmap settings
index_params.add_index(
field_name="title",
index_type="AUTOINDEX",
params={ "mmap.enabled": "false" }
)
# Change mmap settings for an index
# The following assumes that you have a collection named `my_collection`
client.alter_index_properties(
collection_name="my_collection",
index_name="title",
properties={"mmap.enabled": True}
)
schema.addField(AddFieldReq.builder()
.fieldName("title")
.dataType(DataType.VarChar)
.maxLength(512)
.build());
List<IndexParam> indexParams = new ArrayList<>();
Map<String, Object> extraParams = new HashMap<String, Object>() {{
put(Constant.MMAP_ENABLED, false);
}};
indexParams.add(IndexParam.builder()
.fieldName("title")
.indexType(IndexParam.IndexType.AUTOINDEX)
.extraParams(extraParams)
.build());
client.alterIndexProperties(AlterIndexPropertiesReq.builder()
.collectionName("my_collection")
.indexName("title")
.property(Constant.MMAP_ENABLED, "true")
.build());
// Create index on the varchar field with mmap settings
await client.createIndex({
collection_name: "my_collection",
field_name: "title",
params: { "mmap.enabled": false }
});
// Change mmap settings for an index
// The following assumes that you have a collection named `my_collection`
await client.alterIndexProperties({
collection_name: "my_collection",
index_name: "title",
properties:{"mmap.enabled": true}
});
// go
# restful
export TOKEN="root:Milvus"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/indexes/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "my_collection",
"indexParams": [
{
"fieldName": "doc_chunk",
"params": {
"index_type": "AUTOINDEX",
"mmap.enabled": true
}
}
]
}'
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/indexes/alter_properties" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "my_collection",
"indexName": "doc_chunk",
"properties": {
"mmap.enabled": false
}
}'
이는 벡터 및 스칼라 필드 모두의 인덱스에 적용됩니다.
그런 다음 컬렉션에서 인덱스 매개변수를 참조할 수 있습니다. 컬렉션 로드 요청을 받으면 Milvus는 제목 필드의 인덱스를 메모리에 메모리 매핑합니다.
컬렉션별 MMAP 설정
컬렉션 전체 mmap 전략을 구성하려면 컬렉션 생성 요청에 mmap.enabled 속성을 포함해야 합니다. 이 속성을 true 으로 설정하여 컬렉션에 대해 mmap을 사용하도록 설정할 수 있습니다.
다음 예는 my_collection이라는 이름의 컬렉션을 만들 때 mmap을 사용하도록 설정하는 방법을 보여줍니다. 컬렉션 로드 요청을 받으면 Milvus는 모든 필드의 원시 데이터를 메모리로 메모리 매핑합니다.
# Enable mmap when creating a collection
client.create_collection(
collection_name="my_collection",
schema=schema,
properties={ "mmap.enabled": "true" }
)
CreateCollectionReq req = CreateCollectionReq.builder()
.collectionName("my_collection")
.collectionSchema(schema)
.property(Constant.MMAP_ENABLED, "false")
.build();
client.createCollection(req);
await client.createCollection({
collection_name: "my_collection",
scheme: schema,
properties: { "mmap.enabled": false }
});
// go
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/create" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
--data "{
\"collectionName\": \"my_collection\",
\"schema\": $schema,
\"params\": {
\"mmap.enabled\": \"false\"
}
}"
기존 컬렉션의 mmap 설정을 변경할 수도 있습니다.
# Release collection before change mmap settings
client.release_collection("my_collection")
# Ensure that the collection has already been released
# and run the following
client.alter_collection_properties(
collection_name="my_collection",
properties={
"mmap.enabled": false
}
)
# Load the collection to make the above change take effect
client.load_collection("my_collection")
client.releaseCollection(ReleaseCollectionReq.builder()
.collectionName("my_collection")
.build());
client.alterCollectionProperties(AlterCollectionPropertiesReq.builder()
.collectionName("my_collection")
.property(Constant.MMAP_ENABLED, "false")
.build());
client.loadCollection(LoadCollectionReq.builder()
.collectionName("my_collection")
.build());
// Release collection before change mmap settings
await client.releaseCollection({
collection_name: "my_collection"
});
// Ensure that the collection has already been released
// and run the following
await client.alterCollectionProperties({
collection_name: "my_collection",
properties: {
"mmap.enabled": false
}
});
// Load the collection to make the above change take effect
await client.loadCollection({
collection_name: "my_collection"
});
// go
# restful
export CLUSTER_ENDPOINT="http://localhost:19530"
export TOKEN="root:Milvus"
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/release" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "my_collection"
}'
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/alter_properties" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "my_collection",
"properties": {
"mmmap.enabled": false
}
}'
curl --request POST \
--url "${CLUSTER_ENDPOINT}/v2/vectordb/collections/load" \
--header "Authorization: Bearer ${TOKEN}" \
--header "Content-Type: application/json" \
-d '{
"collectionName": "my_collection"
}'
컬렉션의 속성을 변경하려면 컬렉션을 해제하고 변경 사항을 적용하려면 컬렉션을 다시 로드해야 합니다.