Couchbase Server 5.0과 5.5는 두 가지 큰 릴리스였습니다. 개발자가 놓쳐서는 안 될 새롭고 멋진 기능 몇 가지를 살펴보겠습니다:
1) 하위 문서
이 기능은 한동안 사용되어 왔지만 여전히 언급할 가치가 있습니다. 일부 키-값 저장소는 전체 문서를 한꺼번에 가져오는 것만 허용하는데, 이는 합리적인 특성입니다. 결국 키-값 저장소이기 때문입니다. 하지만 카우치베이스를 KV로 사용하는 경우에는 문서의 경로를 지정하여 문서의 일부를 조작할 수 있습니다. 예:
다음 문서가 주어집니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
{ "name": "Douglas Reynholm", "email": "douglas@reynholmindustries.com", "addresses": { "billing": { "line1": "123 Any Street", "line2": "Anytown", "country": "United Kingdom" }, "delivery": { "line1": "123 Any Street", "line2": "Anytown", "country": "United Kingdom" } }, "purchases": { "complete": [ 339, 976, 442, 666 ], "abandoned": [ 157, 42, 999 ] } } |
다음과 같이 문서의 경로를 지정하기만 하면 문서의 일부를 조작할 수 있습니다. GET('addresses.billing') 또는 ARRAY_APPEND('purchases.abandoned', 42)
자세한 내용은 다음을 참조하세요. 블로그 게시물 또는 공식 문서.
2) 이벤트
이벤트는 분명히 Couchbase 5.5에서 가장 멋진 기능 중 하나이며, 이미 다음과 같은 블로그 게시물에서 이 기능을 다루고 있습니다. 여기 또는 여기. 아직 들어보지 못한 분들을 위해, 이벤트 서비스를 통해 다음을 작성할 수 있습니다. 서버 측 기능 함수는 문서가 삽입/업데이트/삭제될 때마다 자동으로 트리거됩니다. 이러한 함수는 JavaScript와 유사한 구문을 사용하여 쉽게 작성할 수 있습니다:

또한 애플리케이션에서 curl을 통해 엔드포인트를 호출할 수도 있습니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
function OnUpdate(doc, meta) { if (doc.resourceType != 'Observation') return; let reference = doc.subject.reference; let url = "https://localhost:8080/events/" + reference.substr(9); let data = JSON.stringify({ "reference": doc.subject.reference, "code": doc.code.coding[0].code, "recordedAt": doc.issued, "value": doc.valueQuantity.value }); let curl = SELECT CURL($url, { "request": "POST", "header": [ "Content-Type: application/json", "accept: application/json" ], "data": $data }); curl.execQuery(); } function OnDelete(meta) {} |
3) ANSI 가입
카우치베이스에서는 다음을 사용할 수 있습니다. joins 를 쿼리에서 사용할 수 있도록 오랫동안 지원했지만, 지금까지는 자체 구문을 사용해야만 이 작업을 수행할 수 있었습니다. Couchbase 5.5부터는 ANSI JOIN 구문도 사용할 수 있습니다:
|
1 2 3 4 5 6 7 |
SELECT DISTINCT route.destinationairport FROM `travel-sample` airport JOIN `travel-sample` route ON airport.faa = route.sourceairport AND route.type = "route" WHERE airport.type = "airport" AND airport.city = "San Francisco" AND airport.country = "United States"; |
자세한 내용은 다음과 같이 확인할 수 있습니다. 여기.
4) 전체 텍스트 검색
대부분의 사용자 대면 애플리케이션은 결국 일종의 고급 검색을 구현해야 합니다. 이러한 종류의 기능을 구현하려면 일반적으로 데이터를 Solr 또는 Elastic Search와 같은 타사 도구로 푸시해야 합니다. 그러나 이러한 도구를 추가하면 이러한 도구에 개체/문서 변경 사항을 푸시하는 데 필요한 모든 코드는 말할 것도 없고 인프라의 비용과 복잡성이 크게 증가합니다.
Couchbase 5.0부터는 웹 콘솔에서 간단하게 전체 텍스트 검색 인덱스를 생성하고 데이터베이스에서 바로 전체 텍스트 검색을 시작할 수 있습니다:

검색 결과 강조 표시하기:

SDK를 통해 간단한 검색을 할 수 있습니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
@Override public List<SearchQueryRow> searchQuery(String word) { String indexName = "movies_index"; QueryStringQuery query = SearchQuery.queryString(word); SearchQueryResult result = movieRepository.getCouchbaseOperations().getCouchbaseBucket().query( new SearchQuery(indexName, query).highlight().limit(20)); List<SearchQueryRow> hits = new ArrayList<>(); if (result != null && result.errors().isEmpty()) { Iterator<SearchQueryRow> resultIterator = result.iterator(); while (resultIterator.hasNext()) { hits.add(resultIterator.next()); } } return hits; } |
공식 문서를 볼 수 있습니다. 여기.
5) 더 빠른 쿼리, GROUP BY 및 집계 푸시다운
데이터베이스에 관계없이 집계(최소, 최대, 평균 등) 및 GROUP BY 작업은 성능 측면에서 항상 문제가 되어 왔습니다. 이 문제를 해결하기 위해 Couchbase 5.5에서는 인덱스를 활용하여 이러한 유형의 쿼리 속도를 높일 수 있습니다:
|
1 2 3 4 5 |
SELECT country, state, city, COUNT(1) AS total FROM `travel-sample` WHERE type = 'hotel' and country is not null GROUP BY country, state, city ORDER BY COUNT(1) DESC; |
~90ms - 위 쿼리의 쿼리 계획

~7ms - 이전과 동일한 쿼리이지만 적절한 인덱스를 사용합니다.

자세한 내용은 전체 기사 보기.
6) 역할 기반 액세스 제어 및 X509 인증
데이터베이스는 악의적인 침입자에게는 대박이기 때문에 보안 계층을 추가하는 것은 결코 과한 일이 아닙니다. Couchbase로, X.509 인증서를 사용하여 클라이언트를 인증할 수 있습니다. 역할 기반 액세스 제어(RBAC)를 통해 액세스를 제한합니다:

N1QL을 통해 권한을 부여할 수도 있습니다. 사용자에 대한 SELECT 권한을 부여하는 방법을 살펴보겠습니다. denis 버킷에 일부_버킷 가 어떻게 생겼을까요?
|
1 |
GRANT ROLE query_select(some_bucket) TO denis; |
자세한 내용은 다음과 같이 확인할 수 있습니다. 여기 또는 여기.
7) 필드 암호화
미사용 암호화는 가장 기본적인 보안 형태 중 하나이며, 다음을 사용하여 필드를 쉽게 암호화/복호화할 수 있습니다. Couchbase의 Java 암호화:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public static class Person { @Id public String id; @EncryptedField(provider = "AES") public String password; //The rest will be transported and stored unencrypted public String firstName; public String lastName; public String userName; public int age; } |
8) 반응형 SDK
또한 대부분의 데이터베이스 제공업체에서 쉽게 찾아볼 수 없는 반응형 SDK를 제공합니다. 이는 대부분 저희 SDK 자체가 반응형으로 구현되어 있기 때문입니다.
반응형 프로그래밍은 성능과 리소스 최적화에 매우 중요합니다. 아직 이 개념에 익숙하지 않다면 다음을 적극 권장합니다. 이 문서에서 지속성 계층에 반응형 프로그래밍을 사용하는 이유를 간략하게 살펴볼 수 있습니다.
이 주제에 대한 광범위한 자료가 있습니다. 더 자세히 알고 싶으시면 다음을 시작하세요. 여기 또는 여기.
9) SDK를 통한 '미세 속도 조정'
카우치베이스에서는 개발자가 문서 수준에서도 성능을 미세 조정할 수 있도록 지원하여 개발자가 각 시나리오에 대해 최적의 절충점을 사례별로 결정할 수 있도록 합니다.
예를 들어 Couchbase가 데이터를 저장하는 방식을 살펴봅시다. 기본적으로 서버는 새 문서가 저장되어야 함을 인식하는 즉시 "요청이 성공적으로 수신되었습니다"라는 응답을 클라이언트에 보내고 비동기적으로 문서를 저장 및 복제합니다.
이 방법은 속도에는 매우 좋지만 문서가 서버의 메모리에 남아 있을 때 서버가 충돌하면 데이터가 손실될 가능성이 적습니다. 이를 방지하려면 문서가 복제되거나 디스크에 저장된 후에만 확인을 받도록 SDK를 통해 지정할 수 있습니다:
|
1 2 3 4 5 |
movieRepository.getCouchbaseOperations().save(movie, PersistTo.ONE, ReplicateTo.NONE); //or movieRepository.getCouchbaseOperations().save(movie, PersistTo.ONE, ReplicateTo.TWO); ... movieRepository.getCouchbaseOperations().save(movie, PersistTo.NONE, ReplicateTo.ONE); |
왜 그런 것을 허용할까요? 서버가 다운되어 데이터가 손실될 가능성을 조금만 감수할 수 있다면 성능을 크게 향상시킬 수 있기 때문입니다. 시스템에서 이러한 위험을 감수할 만한 가치가 있는 부분을 결정할 수 있으므로 이것은 전부 아니면 전무의 결정이 아닙니다.
쿼리에서도 비슷한 작업을 수행할 수 있습니다. 이 경우 마지막 변경 사항을 기준으로 인덱스/보기가 업데이트될 때까지 기다리거나 문서의 최신 버전이 반환되지 않을 가능성이 작아도 괜찮은지 여부를 결정할 수 있습니다:
|
1 2 3 4 |
//You can use ScanConsistency.REQUEST_PLUS, ScanConsistency.NOT_BOUNDED or ScanConsistency.STATEMENT_PLUS N1qlParams params = N1qlParams.build().consistency(ScanConsistency.REQUEST_PLUS).adhoc(true); ParameterizedN1qlQuery query = N1qlQuery.parameterized(queryString, JsonObject.create(), params); resourceRepository.getCouchbaseOperations().getCouchbaseBucket().query(query); |
SDK에는 최적화할 수 있는 몇 가지 다른 기능도 있으며, 이러한 작은 결정으로 대규모로 성능을 크게 향상시킬 수 있습니다.
10) 응답 시간 관찰 가능성
이 항목은 이미 이전 블로그 게시물에서도 언급했지만 다시 언급할 가치가 있다고 생각합니다. 버전 5.5부터 응답 시간 관찰 기능이라는 새로운 기능을 도입하여 시스템 개발자가 (조정 가능한) 임계값을 기준으로 응답 시간을 관찰할 수 있는 매우 간단한 방법을 제공하게 되었습니다.
오픈트레이싱 형식을 사용하는 이 기능은 느린 요청과 그에 대한 세부 정보를 시간 간격마다 기록하므로 성능이 저하된 작업을 쉽게 식별할 수 있습니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
Apr 04, 2018 9:42:57 AM com.couchbase.client.core.tracing.ThresholdLogReporter logOverThreshold WARNING: Operations over threshold: [ { "top" : [ { "server_us" : 8, "local_id" : "41837B87B9B1C5D1/000000004746B9AA", "local_address" : "127.0.0.1:55011", "operation_id" : "get:0x6", "dispatch_us" : 315, "remote_address" : "127.0.0.1:11210", "total_us" : 576 }, { "server_us" : 8, "local_id" : "41837B87B9B1C5D1/000000004746B9AA", "local_address" : "127.0.0.1:55011", "operation_id" : "get:0x5", "dispatch_us" : 319, "remote_address" : "127.0.0.1:11210", "total_us" : 599 }, { "server_us" : 8, "local_id" : "41837B87B9B1C5D1/000000004746B9AA", "local_address" : "127.0.0.1:55011", "operation_id" : "get:0x4", "dispatch_us" : 332, "remote_address" : "127.0.0.1:11210", "total_us" : 632 }, { "server_us" : 11, "local_id" : "41837B87B9B1C5D1/000000004746B9AA", "local_address" : "127.0.0.1:55011", "operation_id" : "get:0x3", "dispatch_us" : 392, "remote_address" : "127.0.0.1:11210", "total_us" : 762 }, { "server_us" : 23, "local_id" : "41837B87B9B1C5D1/000000004746B9AA", "local_address" : "127.0.0.1:55011", "operation_id" : "get:0x1", "decode_us" : 9579, "dispatch_us" : 947, "remote_address" : "127.0.0.1:11210", "total_us" : 16533 }, { "server_us" : 56, "encode_us" : 12296, "local_id" : "41837B87B9B1C5D1/000000004746B9AA", "local_address" : "127.0.0.1:55011", "operation_id" : "upsert:0x2", "dispatch_us" : 1280, "remote_address" : "127.0.0.1:11210", "total_us" : 20935 } ], "service" : "kv", "count" : 6 } ] |
응답 시간 관찰 가능성은 기본적으로 켜져 있으며, 정상 요청을 기록하지 않도록 임계값을 이미 정의해 놓았습니다. 클러스터의 한계를 뛰어넘고 싶다면 더 작은 임계값을 수동으로 설정할 수도 있습니다. 자세한 내용은 다음을 참조하세요. 여기.