소개
카우치베이스는 쓰기 속도가 매우 빠르고, 빠르게 확장할 수 있으며, 노드를 쉽게 추가할 수 있지만, 객체 모델이 좋지 않으면 이러한 특성이 방해가 될 수 있습니다. 일부 데이터베이스에서는 쓰기 속도가 매우 빠르면 읽기 속도가 저하되는 경우도 있지만, Couchbase는 이 두 가지를 모두 효과적으로 지원하기 위해 NoSQL 공간에서 상당히 독특한 기능을 갖추고 있습니다. 이 블로그 게시물에서는 로깅 및 이벤트 데이터에 대해 이러한 기능을 활용하면서 N1QL로 쉽게 검색할 수 있는 객체 모델을 설계하는 데 필요한 사항에 대해 설명합니다.
최근 대화에서 접한 사용 사례는 네트워크 장비, 서버 또는 로그 데이터와 같은 외부 시스템에서 다양한 유형의 이벤트를 수집하기 위한 운영 데이터베이스로 Couchbase를 사용하는 것입니다. 그런 다음 서비스에는 일종의 시간별 롤업 방식으로 UI에서 이벤트 수를 매우 빠르게 확인할 수 있는 기능이 필요합니다. 또 다른 요구 사항은 해당 번호를 클릭해 해당 이벤트 유형의 목록으로 드릴다운할 수 있어야 한다는 것입니다. 예를 들어 2015년 6월 22일 16:00에 발생한 모든 라우터 오류 이벤트를 표시합니다.
한 가지 더 기억해야 할 점은 이 블로그 게시물은 좀 더 발전된 개념과 이를 적용하는 방법을 보여드리기 위한 것입니다. 제가 설명하는 것과 비슷할지라도 여러분의 사용 사례에 정확히 맞는 방법이라는 의미는 아닙니다. 이 글은 Couchbase의 고급 객체 모델링에 대해 생각해보고, 모든 사람에게 분명하지 않을 수 있는 방식으로 그 기능을 최대한 활용하기 위해 어떻게 하면 더 효과적으로 사용할 수 있는지에 대해 생각해보도록 하기 위한 것입니다.
시간당 이벤트 및 카운트를 읽는 증분 카운터
이 접근 방식을 사용하면 뷰 쿼리로 작업을 수행하는 대신 한 시간 동안의 마지막 N개의 이벤트 또는 이벤트 유형을 쉽게 읽을 수 있습니다. 또는 특정 날짜의 모든 이벤트를 읽을 수도 있습니다. 이 방법은 매우 높은 쓰기 속도에 최적화되어 있으며 적절한 수준의 세분성 내에서 데이터를 쉽게 조회할 수 있습니다. 이에 대해 개략적으로 설명한 다음 구체적인 예제를 통해 더 자세히 설명하겠습니다.
이를 위해 버킷에 두 가지 오브젝트 유형이 필요합니다.
- 카운터 객체 - 키/값 객체이며 정수를 보유합니다. 이 정수는 해당 이벤트 유형 및 시간에 대한 객체 수의 최상단을 나타내거나 다른 방식으로 말하면 이벤트 배열의 최상단입니다. 또한 해당 유형/시간 조합에 대한 이벤트 수를 표시하기 위해 읽게 될 객체이기도 합니다. 여기서는 카운터 연산이라는 Couchbase SDK의 특수하고 구체적인 메서드를 사용할 것입니다. 각 SDK에는 이러한 메서드의 고유한 버전이 있습니다. 다음은 node.js 버전의 예시입니다..
- 이벤트 객체 - JSON 문서 객체이며 캡처하려는 이벤트에 대한 실제 데이터를 담고 있습니다.
카운터 오브젝트
각 이벤트 유형과 시간 조합에 대해 카운터 개체를 만듭니다. 우리가 만들 문서에 대한 연산 객체처럼 생각하면 됩니다. 이상하게 들릴 수도 있지만 이해해 주세요. 이 카운터 객체는 JSON이 아닌 키/값 객체이며 값은 정수가 됩니다. 이러한 유형의 객체를 위한 카운터 오퍼레이션이 Couchbase SDK에 있으며 매우 효율적이고 일관성을 유지하기 위해 빠른 읽기 쓰기 기능을 제공합니다. 카운터 연산은 Couchbase SDK에서 단일 원자 연산이므로 매우 쉽고 빠르게 사용할 수 있습니다. 다음은 문서에 있는 node.js 버전의 예시입니다.. 우리의 경우 이 카운터는 새 이벤트를 추가할 때마다 증가합니다. 각 이벤트 유형과 시간에는 고유한 카운터가 있으므로 해당 유형과 시간에 대한 모든 이벤트를 읽어야 하는 경우 이벤트 수를 쉽게 읽을 수 있으며 이 숫자가 배열의 상한이 됩니다.
또 다른 중요한 부분은 객체의 키입니다. 애플리케이션이 필요한 키를 쉽게 구성할 수 있도록 키를 선택한 다음 키별로 데이터를 수집하여 이벤트 수뿐만 아니라 주어진 기간 동안의 이벤트도 표시하고자 합니다. 키로 개체를 가져오는 것이 쿼리하는 것보다 항상 더 빠릅니다. 답을 이미 알고 있는 경우와 답을 찾기 위해 질문을 해야 하는 경우의 차이입니다. 키를 알면 데이터베이스에 데이터를 검색하라고 지시하기만 하면 됩니다. 간단하고 효과적이며 매우 빠릅니다.
다음은 카운터의 키/값 예시입니다:
개체 키:
ObjectID를 예로 들 수 있습니다:
|
||||
값: 293
여기서 293은 카운터의 가장 최근 증분 값입니다. |
키의 타임스탬프는 4자리 연도, 2자리 월, 요일, 시간(24시간 기준)으로 만들었습니다. 저는 분이나 초 단위까지 내려갈 필요는 없었지만 여러분은 그럴 수 있습니다. UNIX 타임스탬프도 사용할 수 있었지만 이 특정 사용 사례에서는 불필요하게 세분화되어 있었습니다.
위의 예에서 2015년은 연도, 2월은 월, 20일은 요일, 오후 4시는 시간입니다. 따라서 이벤트 유형과 특정 날짜에 대한 모든 카운터를 읽으려면 애플리케이션에서 해당 카운터의 개체 ID를 쉽게 조합하여 일괄적으로 읽을 수 있습니다.
한 가지 더, 저는 구분 기호로 이중 콜론을 사용하지만 여러분은 어떤 것이든 사용해도 됩니다.
이벤트 개체
각 이벤트 객체에 대해 객체 ID는 다음과 같이 표시됩니다:
여기서 293은 해당 시간에 대한 카운터 개체의 가장 최근 증분 값입니다. |
||
|
이 스키마를 사용하면 특정 시간 동안 해당 이벤트 유형에 대한 항목 수를 검색하려면 하나의 연산 객체만 읽으면 됩니다.
간단히 말해, 카운터의 값은 해당 이벤트 유형 개체의 상한입니다. 한 시간 동안 해당 이벤트 유형의 마지막 10개의 이벤트를 원한다면 카운터를 읽고 9개를 뺀 다음 다음 개체에 대해 Couchbase에서 병렬화된 대량 읽기를 수행하면 됩니다:
|
따라서 쿼리, 인덱스, 조회 없이 병렬화된 대량 읽기를 통해 10개의 이벤트를 모두 매우 빠른 속도로 읽을 수 있습니다. 나열된 개체가 300개가 넘는 경우에도 Couchbase에서 대량 읽기는 매우 빠릅니다.
이 접근 방식의 한 가지 사소한 문제는, 가능성은 매우 낮지만 카운트 개체가 실제 카운트 개체와 일치하지 않을 수 있다는 것입니다. 예를 들어 누군가가 카운트 객체를 반복한 다음 해당 객체로 이벤트 문서를 만들지 않을 수 있습니다. 즉, 대량 작업을 사용 중인데 존재하지 않는 객체를 요청하면 단순히 미스를 수신하고 전체 작업에는 문제가 발생하지 않습니다. 이와 같은 모델이 확장할 수 있는 성능을 고려하면 이 정도는 괜찮다고 생각합니다. 더 좋은 방법이 있다면 댓글로 알려주시면 감사하겠습니다.
애플리케이션 코드
이 객체 모델을 읽고 쓰기 위해 애플리케이션 코드가 어떻게 배치되는지 살펴봅시다. 특정 언어를 사용하지 않기 위해 의사 코드를 사용하겠습니다. 이에 대한 자세한 내용은 선택한 언어와 Couchbase SDK에 맡기겠습니다.
1 2 3 4 5 6 7 8 9 10 11 |
함수 writeNewEvent() { 읽기 현재 날짜 그리고 시간. 통화 반복 함수 on 카운터 객체 와 함께 an 이니셜 값 의 0 그리고 읽기 뒤로 의 값. (당신 should 읽기 의 값 뒤로 왜냐하면 만약 it 이미 존재 당신 will get 의 대부분 현재 값, 만약 당신 그냥 갔다 와 함께 0, 당신 might 원인 a 문제. 만약 의 카운터 객체 에 대한 이 이벤트 그리고 시간 기간 does not 존재, it will be 생성 by 의 SDK.) 만들기 new 이벤트 와 함께 의 날짜/시간 그리고 카운터 숫자 as part 의 의 키 } |
1 2 3 4 5 6 7 8 |
읽기 카운터 날짜 개체() Do a loop 에 생성 의 목록 의 키 당신 필요 에 읽기 기반 on 의 이벤트 유형, 날짜 그리고 시간 그리고 의 값 의 의 카운터 객체 당신 받은. (당신 could 심지어 say 무언가 같은 "그냥 의 마지막 10" 그리고 생성 그 키 in 이. 귀하의 통화.) 사용 그 목록 에 do a 병렬화 대량 읽기 작동 그리고 가져오다 뒤로 그냥 의 키 우리 want. } |
1 2 3 4 5 |
함수 readEventCount() { 반환 의 값 의 의 이벤트/날짜 카운터 객체. } |
요약
위에서 설명한 일련의 객체 모델링 기법을 사용하면 처리량과 성능을 극대화하는 방식으로 데이터를 구조화할 수 있습니다. 처음에는 직관적이지 않을 수도 있지만, 기본 애플리케이션 기능을 위해 보조 인덱스 기반 쿼리 대신 추가적인 키/값 조회를 사용하면 상당한 이점을 얻을 수 있습니다. 많은 시스템에서 복잡한 인덱스 기반 조회는 이 설계 전체에서 사용되는 간단한 키-값 조회보다 완료하는 데 훨씬 더 오래 걸릴 수 있습니다. 올바른 시스템 아키텍처에서 Couchbase는 이러한 조회에 대해 밀리초 미만의 일관된 응답 시간을 쉽게 제공할 수 있습니다. 그런 다음 실제 쿼리 기능이 필요할 때는 N1QL을 사용합니다. Couchbase가 제공하는 기능을 어디에서 활용할지는 사용자가 직접 선택할 수 있습니다.
또한, Couchbase의 자동 샤딩 아키텍처로 인해 쿼리와 수집에 대한 부하가 클러스터 전체에 고르게 분산됩니다. 시간이 지남에 따라 애플리케이션 사용량과 운영 수요가 증가하면 온라인 운영에서 Couchbase 노드를 추가하여 애플리케이션 계층에서 변경 없이 수요를 충족하면서 확장할 수 있습니다.
쿼리 관련 포스트 스크립트
여기까지 읽으셨다면 마지막으로 한 가지 더 말씀드리겠습니다. 이렇게 말할 수도 있겠지만, 이 모든 것을 하면서 데이터베이스를 쿼리하지 않습니다. N1QL을 사용하지 않는 이유는 무엇인가요? 이 사용 사례에서는 N1QL을 사용하지 않을 것이라고 말하지 않았으며 이 문서에서 N1QL을 사용하는 데 방해가 되는 것은 없습니다. 제가 생각하는 N1QL은 Couchbase와 상호 작용하기 위한 도구 상자의 또 다른 도구라는 것입니다. 키/값 액세스는 항상 더 빠릅니다. 이것이 바로 현실입니다. 그래서 제가 사람들에게 홍보하는 것은 언제 어디서나 필요한 성능과 기능을 얻기 위해 Couchbase가 제공하는 강력한 성능과 유연성을 사용하라는 것입니다. 여기에는 키/값, 기존 Couchbase 보기, 글로벌 보조 인덱스(GSI) 및 N1QL이 혼합되어 있습니다.
이 특정 사용 사례에서는 매우 빠른 속도로 데이터를 쓰고, 매우 특정한 방식으로 일부 데이터만 조회할 수 있어야 하며, 데이터 계층을 선형적으로 확장하여 복잡성을 최소화하면서 이를 처리할 수 있어야 했습니다. 키/값은 올바른 객체 키 패턴으로 이를 해결해 주었습니다. 이러한 이벤트를 쿼리하거나 이 스키마를 어떻게 설계했는지 기록하기 위해 N1QL을 사용하는 데 방해가 되는 것은 아무것도 없습니다. JSON 문서 객체 모델링 자체에 대해서는 별로 언급하지 않았습니다. 제가 보여주고자 하는 것은 중요하지 않았고 쿼리에 관해서는 도구 가방에서 해당 도구가 필요하지 않았기 때문입니다.
이 객체 모델에 대한 다음 블로그에서는 N1QL과 GSI를 사용하여 동일한 이벤트를 어떻게 파쇄할 수 있는지 살펴볼 것입니다.