디자인 문서 관리
IBM Cloudant에 대한 확장 가능 JSON 데이터 저장소에는 몇 가지 조회 메커니즘이 존재하며, 이러한 조회 메커니즘은 모두 코어 데이터로부터 별도로 작성 및 유지보수되는 인덱스를 생성합니다.
IBM Cloudant의 개발자 지원 담당인 Glynn Bird(glynn@cloudant.com)가 기고한 문서
인덱싱은 문서 저장 시 즉시 수행되지 않습니다. 대신 인덱싱은 빠르고 막힘 없는 쓰기 처리량을 위해 나중에 수행되도록 스케줄링됩니다.
- MapReduce 뷰는 키 또는 키 범위를 사용한 효율적인 검색을 위해 B-트리에 저장된 키 값 쌍이 있는 데이터 세트에 대한 인덱스입니다.
- 검색 인덱스는 자유 텍스트 검색, 다면화 및 복잡한 임시 조회를 수행할 수 있도록 하기 위해 Apache Lucene을 사용하여 생성됩니다.
IBM® Cloudant® for IBM Cloud®의 검색 인덱스 및 MapReduce 뷰는 데이터베이스에 디자인 문서를 추가하여 구성됩니다. 디자인 문서는 뷰 또는 인덱스를 빌드하는 방식에 대한 지시사항을 포함하는 JSON 문서입니다. 간단한 예를 들어 보겠습니다. 다음 예와 같은 간단한 데이터 문서 콜렉션이 있다고 가정해 보십시오.
다음과 같이 단순 데이터 문서 예제를 참조하십시오.
{
"_id": "23966717-5A6F-E581-AF79-BB55D6BBB613",
"_rev": "1-96daf2e7c7c0c277d0a63c49b57919bc",
"doc_name": "Markdown Reference",
"body": "Lorem Ipsum",
"ts": 1422358827
}
각 데이터 문서에는 이름, 본문 및 시간소인이 포함되어 있습니다. 여기서는 시간소인으로 문서를 정렬하기 위해 MapReduce 뷰를 작성할 수 있습니다.
map 함수를 작성하여 문서를 시간소인에 따라 정렬할 수 있습니다.
다음과 같이 존재하는 경우 문서의 시간소인 필드를 리턴하는 map 함수 예제를 참조하십시오.
function(doc) {
if (doc.ts) {
emit( doc.ts, null);
}
}
이 함수는 인덱스에 대한 키로 사용할 수 있도록 문서의 시간소인을 생성합니다. 인덱스의 값에는 관심이 없으니까요,
null
is emitted. 이 함수의 효과는 문서 세트에 대한 시간 순서 인덱스를 제공하는 것입니다.
이 뷰를 by_ts
부르고 fetch
디자인 문서에 넣겠습니다.
다음과 같이 map 함수를 사용하여 보기를 정의하는 디자인 문서 예제를 참조하십시오.
{
"_id": "_design/fetch",
"views": {
"by_ts": {
"map": "function(doc) {
if (doc.ts) {
emit( doc.ts, null);
}
}"
}
},
"language": "javascript"
}
결과적으로 map 코드가 JSON 호환 문자열로 변환되어 디자인 문서에 포함되었습니다.
일단 디자인 문서가 저장되면, IBM Cloudant에서는 fetch/by_ts
뷰를 빌드하기 위해 서버측 프로세스를 트리거합니다. 이는 데이터베이스에 있는 모든 문서에 대해 반복한 후 각 항목을 JavaScript map 함수에 전송하여 뷰를 작성합니다. 이 함수에서는 생성된 key-value
쌍을 리턴합니다. 반복이 계속되면서 각각의 key-value
쌍이 B-트리
인덱스에 저장됩니다. 인덱스가 처음으로 빌드되고 나면 후속 재인덱싱은 신규 또는 업데이트된 문서에 대해서만 수행됩니다. 삭제된 문서는 인덱싱이 해제됩니다. 다음 다이어그램에 표시된 것과 같이 이 시간 절약 프로세스를 증분 MapReduce라고 합니다.
다음 항목은 기억해 두는 편이 좋습니다.
- 인덱스 구축은 비동기로 수행됩니다. IBM Cloudant는 디자인 문서가 저장되었는지 확인합니다. 인덱스 생성의 진행상태를 확인하려면 IBM Cloudant의
_active_tasks
엔드포인트를 폴링해야 합니다. - 데이터가 많을수록 인덱스가 준비되는 데 오랜 시간이 소요됩니다.
- 초기 인덱스 빌드가 진행 중인 동안에는 해당 인덱스에 대한 모든 조회가 차단됩니다.
- 뷰를 조회하면 아직 증분 인덱싱되지 않은 모든 문서의 '맵핑'이 트리거됩니다. 이 방법은 항상 최신 데이터를 볼 수 있게 해 줍니다. 이 규칙에 대한 예외는 다음
stale
매개변수 해설을 참조하십시오.
동일한 디자인 문서 내의 여러 뷰
동일한 디자인 문서에서 여러 뷰를 정의하면, 이들은 효율적으로 동시에 빌드됩니다. 각 문서는 한 번만 읽힌 후 각 뷰의 map 함수를 거칩니다. 이 접근법을 사용하는 경우 디자인 문서 수정 시 해당 문서에 정의된 기존의 모든 MapReduce 보기가 무효화된다는 점을 기억하십시오. 이 프로세스는 일부 보기가 변경되지 않은 상태로 유지되는 경우에도 MapReduce 보기를 무효화합니다.
MapReduce 뷰를 개별적으로 변경해야 하는 경우에는 이들의 정의를 각각 별도의 디자인 문서에 배치하십시오.
이 동작은 Lucene 검색 인덱스에는 적용되지 않습니다. 이들은 동일한 디자인 문서에 있는 다른 변경되지 않은 인덱스를 무효화시키지 않으면서 변경될 수 있습니다.
디자인 문서에 대한 변경사항 관리
미래의 한 시점에 뷰의 디자인을 변경하기로 결정했다고 가정해 보십시오. 이제는 실제 시간소인 결과를 리턴하는 대신 기준과 일치하는 문서의 개수에만 관심이 있습니다. 이 개수를 얻기 위해, map 함수는 그대로 두고 reduce
라는 _count
함수를 사용합니다.
다음과 같이 reduce 함수를 사용하는 디자인 문서 예제를 참조하십시오.
{
"_id": "_design/fetch",
"_rev": "2-a2324c9e74a76d2a16179c56f5315dba",
"views": {
"by_ts": {
"map": "function(doc) {
if (doc.ts) {
emit( doc.ts, null);
}
}
}",
"reduce": "_count"
},
"language": "javascript"
}
이 디자인 문서가 저장될 때 IBM Cloudant에서는 이전 인덱스를 완전히 무효화하고 처음부터 새 인덱스 빌드를 시작하며, 차례로 모든 문서를 반복합니다. 원래 빌드와 마찬가지로, 소요되는 시간은 데이터베이스에 있는 문서의 수에 따라 달라집니다. 빌드는 또한 완료될 때까지 해당 뷰에 대한 수신 조회를 차단합니다.
그러나 여기에는 문제점이 있습니다.
실시간으로 이 보기에 액세스하는 애플리케이션이 존재하는 경우 배치 딜레마가 발생할 수 있습니다.
- 이전 뷰가 무효화되었으므로 원래 디자인 문서에 의존하던 코드 버전 1이 더 이상 작동하지 않을 수 있습니다.
- 코드 버전 2는 새 디자인 문서를 사용합니다. 새 보기의 빌드가 아직 완료되지 않았기 때문에 이 버전을 즉시 릴리스할 수 없습니다. 데이터베이스에 대량의 문서가 포함되어 있는 경우 빌드 프로세스에 더 많은 시간이 소요된다는 점을 기억하십시오.
- 코드에 영향을 미치는 더 미묘한 문제는 버전 1과 2가 뷰에서 서로 다른 결과 데이터를 예상한다는 점입니다. 버전 1은 일치하는 문서 목록을 예상하는 반면, 버전 2는 '감소된' 결과 수를 예상합니다.
디자인 문서에 대한 변경사항 조율
이 변경 제어 문제점은 두 가지 방법으로 해결할 수 있습니다.
버전화된 디자인 문서
한 가지 해결책은 버전화된 디자인 문서 이름을 사용하는 것입니다.
- 코드가 처음에
_design/fetchv1
이라는 뷰를 사용하도록 작성되었다고 가정해 보십시오. - 새 버전을 릴리스하면
_design/fetchv2
라는 새 뷰가 작성되며, 빌드가 확실히 진행되도록 하기 위해 뷰가 조회됩니다. - IBM Cloudant는 새 인덱스 빌드 작업이 완료될 때까지
_active_tasks
를 폴링합니다. - 이제 두 번째 뷰에 의존하는 코드를 릴리스할 준비가 되었습니다.
_design/fetchv1
가 더 이상 필요하지 않은 것이 확실하면 이를 삭제하십시오.
버전화된 디자인 문서 사용은 디자인 문서의 변경 제어를 관리하는 간단한 방법이지만, 나중에 이전 버전을 제거하는 것은 잊지 말아야 합니다.
Move and switch
이동 및 전환
다른 접근법은 IBM Cloudant가 두 개의 동일한 디자인 문서가 있는 경우를 인식하고 이미 있는 뷰를 다시 빌드하는 데 시간과 리소스를 낭비하지 않는다는 점을 이용합니다. 즉, 디자인 문서 _design/fetch
의 정확한 복제인 _design/fetch_OLD
를 작성하면 두 엔드포인트는 재인덱싱을 트리거하지 않으면서 교환 가능하게 작동합니다.
새 뷰로 전환하려면 다음 단계를 따르십시오.
- 변경하려는 디자인 문서의 중복 사본을 작성하십시오(예: 이름에
_OLD
추가)._design/fetch_OLD
. - 접미부
_NEW
가 있는 이름(_design/fetch_NEW
)을 사용하여 신규 또는 "수신" 디자인 문서를 데이터베이스에 저장합니다. fetch_NEW
뷰를 조회하여 이 뷰의 빌드가 시작되도록 합니다._active_tasks
엔드포인트를 폴링하고 인덱스 빌드가 완료될 때까지 기다립니다.- 새 디자인 문서의 복제본을
_design/fetch
에 저장합니다. - 디자인 문서
_design/fetch_NEW
를 삭제합니다. - 디자인 문서
_design/fetch_OLD
를 삭제합니다.
Move and switch
도구
명령행 Node.js couchmigrate
스크립트는 Move and switch
프로시저를 자동화합니다. 이 스크립트는 다음 명령을 사용하여 설치할 수 있습니다.
npm install -g couchmigrate
To use the couchmigrate
script, first define the URL of the CouchDB/IBM Cloudant instance by setting an environment variable called COUCH_URL
. IBM Cloudant 인스턴스의 URL을 정의하려면 다음 명령을 실행하십시오.
export COUCH_URL=https://127.0.0.1:5984
URL은 https://
시작해야 하며 인증 자격 증명을 포함할 수 있습니다. 인증용 인증 정보를 포함하는 IBM Cloudant 인스턴스의 URL을 정의하려면 다음 명령을 실행하십시오.
export COUCH_URL="https://$ACCOUNT:$PASSWORD@$HOST.cloudant.com"
파일에 저장된 JSON 형식의 디자인 문서가 있는 경우에는 마이그레이션 명령을 실행할 수 있습니다.
이 예에서,
db
specifies the name of the database to change, and dd
specifies the path to the design document file. couchmigrate
명령을 실행하십시오.
couchmigrate --db mydb --dd /path/to/my/dd.json
이 스크립트는 Move and switch
프로시저를 조율하며 리턴하기 전에 뷰가 빌드되기를 기다립니다. 수신 디자인 문서가 현재 디자인 문서와 동일한 경우에는 스크립트가 거의 즉시 리턴됩니다.
이 스크립트의 소스 코드는 다음에서 사용 가능합니다.
couchmigrate
.
'stale
' 매개변수
인덱스가 완료된 상태에서 새 레코드가 데이터베이스에 추가되면 인덱스가 백그라운드에서 업데이트되도록 스케줄됩니다. 데이터베이스의 상태는 다음 다이어그램에 표시되어 있습니다.
보기를 조회하는 경우 다음과 같은 선택사항이 존재합니다.
- 기본 동작은 응답을 리턴하기 전에 인덱스가 데이터베이스의 최신 문서에 대해 최신 상태가 되도록 하는 것입니다. 뷰를 쿼리할 때 IBM Cloudant에서는 먼저 250개의 새 문서를 색인화한 후 응답을 리턴합니다.
- 대체 방법은
stale=ok
매개변수를 API 호출에 추가하는 것입니다. 이 매개변수는 다음을 의미합니다.return me the data that is already indexed. I don't care about the latest updates.
In other words, when you query the view withstale=ok
, IBM Cloudant에서 추가 재색인화 없이 즉시 응답을 리턴합니다. - 두 번째 대체 방법은
stale=update_after
매개변수를 API 호출에 추가하는 것입니다. 이 매개변수는 다음을 의미합니다.return me the data that is already indexed, and then reindex any new documents.
In other words, when you query the view withstale=update_after
, IBM Cloudant에서 응답을 즉시 리턴한 후 백그라운드 태스크를 스케줄하여 새 데이터를 인덱스화합니다.
stale=ok
또는 stale=update_after
를 추가하는 것은 뷰로부터 응답을 더 빨리 받는 좋은 방법이지만 데이터가 최신 상태가 아닐 수 있습니다.
기본 동작은 IBM Cloudant 클러스터에 속한 노드 전체에 로드를 균등하게 분배하는 것입니다. 대체 방법인 stale=ok
또는 stale=update_after
옵션을 사용하면 결과적으로 일관된 세트로부터 일관된 결과를 리턴하기 위해 클러스터 노드의 특정 서브세트에 로드가 집중될 수 있습니다. stale
매개변수가 모든 유스 케이스에 대한 완벽한 해결책은
아닙니다. 그러나 애플리케이션에서 시간이 경과된(stale) 결과를 수신해도 괜찮은 경우에는 이를 통해 빠르게 변경되는 데이터 세트에 대해 적시에 응답을 제공받을 수 있습니다. 데이터의 변경 속도가 느린 경우에는 stale=ok
또는 stale=update_after
를 추가해도 성능 이점이 없을 수 있으며, 대규모 클러스터에서 로드가 균등하지 않게 분배될 수 있습니다.
기본 동작에서 최신 데이터를 제공하고 클러스터 내에서 데이터를 분배하므로 가능한 경우 stale=ok
또는 stale=update_after
를 사용하지 마십시오. 이 시간 중에 임시로 stale=ok
로 전환하여 클라이언트 앱에 대량의 데이터 처리 태스크(예: 정기적인 대량 데이터 업데이트)가 진행 중인지 감지하도록 할 수 있습니다. 그리고 태스크가 완료되고 나면
기본 동작으로 되돌아 갈 수 있습니다.
stale
옵션은 여전히 사용할 수 있지만 더 유용한 옵션인 stable
과 update
가 사용 가능하며 필요한 경우에는 이들을 대신 사용해야 합니다. 자세한 정보는 시간이 경과된(stale) 뷰에 액세스를 참조하십시오.