카우치베이스는 다음과 같은 용도로 널리 사용되고 있습니다. IoT 사용 사례유연한 다중 모델 데이터 관리 기능.

최근 저는 크루즈 업계의 한 고객과 함께 일하고 있었는데, 이 고객은 선박의 수치를 기록하는 여러 센서로부터 자주 업데이트를 수신하고 저장하기 위해 Couchbase가 필요했습니다. 이러한 판독값이 시간 순서가 아닌 다른 순서로 카우치베이스에 전송될 가능성이 있었습니다. 새로운 센서 수치가 이전 수치보다 타임스탬프가 늦은 경우에만 저장될 수 있도록 하려면 어떻게 해야 할까요?

각 센서에는 최신 센서 판독값에 해당하는 고유 키가 있습니다. 오전 10:43:00의 판독값은 오전 10:42:30의 판독값을 덮어쓸 수 없으며, 후자가 나중에 수신되었더라도 덮어쓸 수 없습니다. 다음은 몇 가지 샘플 판독값과 그 처리 순서입니다(타임스탬프가 반드시 시간 순서가 아닌 점에 유의하세요):

이 블로그 게시물에서는 Couchbase의 다중 모델 옵션이 이러한 시나리오를 해결하고 센서 데이터 업데이트를 효율적으로 관리하는 데 어떻게 도움이 되는지 살펴봅니다.

멀티 모델이란 무엇인가요?

메모리 우선 캐싱과 JSON 데이터 지속성을 결합하여 데이터 관리에 대한 유연한 접근 방식을 제공하는 Couchbase는 최초의 다중 모델 데이터베이스라고 할 수 있습니다. Couchbase는 동일한 데이터베이스 인스턴스에서 정형, 반정형, 비정형 데이터와 같은 여러 데이터 유형을 처리할 수 있습니다.

시간이 지남에 따라 카우치베이스는 다음과 같은 기능을 추가했습니다. SQL++, 전체 텍스트 검색(FTS), 이벤트, 분석 도구: 동일한 데이터 풀에 액세스하고, 색인하고, 상호 작용하기 위한 여러 모델. 이러한 다중 모델 접근 방식은 Couchbase를 기존 데이터베이스보다 더 유연하게 만들 수 있지만, 데이터와 상호 작용하는 방법이 한 가지뿐인 레거시 시스템에 비해 장단점에 대해 조금 더 고민해야 할 수도 있습니다.

센서 판독값 업데이트를 위한 다중 모델 옵션

Couchbase의 다중 모델 데이터베이스에서 이 사용 사례에 대한 센서 판독값을 업데이트할 때 고려해야 할 몇 가지 접근 방식이 있습니다:

    1. 낙관적 또는 비관적 잠금 기능을 갖춘 키-값 API
    2. ACID 트랜잭션이 포함된 키-값 API
    3. SQL++ 업데이트 문
    4. 온업데이트 기능 이벤트

이러한 모든 옵션에는 성능, 복잡성 및 요구 사항 측면에서 고유한 장점과 장단점이 있습니다. 가장 적합한 접근 방식을 선택하는 것은 업데이트의 크기와 빈도, 동시성 수준, 전반적인 성능 요구 사항 등의 요인에 따라 달라집니다.

궁극적으로 가장 좋은 접근 방식은 실제 데이터 또는 실제 데이터의 근사치를 사용한 실제 테스트를 통해서만 결정할 수 있습니다. 개발자는 장단점을 검토하고 다양한 옵션을 실험함으로써 Couchbase의 다중 모델 데이터베이스에서 센서 판독값을 업데이트하는 가장 효과적인 방법을 파악할 수 있습니다.

이러한 시나리오의 대부분은 센서 문서가 이미 존재한다고 가정한다는 점에 유의하세요(정상 상태에서는 가장 일반적인 시나리오입니다). 그렇지 않은 경우, 센서 문서가 존재하지 않는다면 대체 또는 업데이트 작업으로 업서트 를 사용하여 문서가 없는 경우 문서가 생성되었는지 확인합니다. (또는 각 센서에 대한 문서로 컬렉션을 '시드'할 수도 있습니다).

이제 각 가능성을 살펴 보겠습니다.

낙관적 또는 비관적 잠금 기능을 갖춘 키-값 API

Couchbase의 다중 모델 데이터베이스에서 센서 판독값을 업데이트하는 한 가지 방법은 낙관적 또는 비관적 잠금을 사용하는 것입니다. 이 잠금 메커니즘은 Couchbase에 오랫동안 존재해 왔으며, 다음과 같은 기술을 사용합니다. CAS(비교 및 스왑) 를 사용하여 개별 문서의 조건부 업데이트를 보장합니다.

CAS 값은 문서가 변경될 때마다 변경되는 임의의 숫자입니다. 개발자는 CAS 값을 일치시킴으로써 최소한의 오버헤드로 센서 데이터를 조건부로 업데이트할 수 있습니다. 이 섹션에서는 이 센서 데이터 사용 사례에 낙관적 잠금과 비관적 잠금을 어떻게 사용할 수 있는지 살펴보겠습니다.

낙관적 잠금

낙관적 잠금은 Couchbase에서 센서 데이터를 업데이트하는 간단한 접근 방식으로, 단 세 단계만 거치면 됩니다:

그리고 첫 번째 단계 는 문서 값과 해당 메타데이터(CAS 값 포함)를 포함하는 키로 문서를 검색하는 작업을 포함합니다.

검색이 완료되면 두 번째 단계 는 타임스탬프가 들어오는 타임스탬프보다 오래된 것인지 확인하는 것입니다.

그렇다면 세 번째 단계 는 문서를 새 값으로 바꾸고 CAS 값을 함께 제출하는 작업을 포함합니다.

여기서 "낙관적인" 부분이 등장합니다. CAS 값이 일치하면 작업이 성공한 것이고 센서 데이터가 업데이트됩니다. 그러나 CAS 값이 일치하지 않으면 마지막 읽기 작업 이후 센서 데이터가 (다른 스레드/프로세스에 의해) 업데이트되었음을 의미합니다. 이 경우 다음과 같은 옵션이 있습니다. 작업을 다시 시도합니다. 를 설정하는 것이 좋습니다. 특정 센서 문서가 자주 업데이트될 것으로 예상하지 않는다면 낙관적 잠금을 사용하는 것이 좋습니다(재시도가 드물기 때문에).

다음은 간단한 재시도 로직을 사용한 낙관적 잠금의 예시입니다:

비관적 잠금

비관적 잠금 는 같은 문제에 접근하는 또 다른 방법입니다. 낙관적 잠금과 마찬가지로 세 단계로 구성되지만 약간의 차이가 있습니다.

그리고 첫 번째 단계가져오기 및 잠금 키별로 문서를 잠그고 CAS 값을 기록합니다. 문서를 단순히 읽는 낙관적 잠금과 달리, 비관적 잠금에서는 문서가 명시적으로 잠깁니다. 즉, 문서가 잠금 해제될 때까지 다른 프로세스가 문서를 변경할 수 없습니다.

에서 두 번째 단계낙관적 잠금과 마찬가지로 타임스탬프가 들어오는 타임스탬프보다 오래되었는지 확인합니다.

그렇다면 세 번째 단계를 입력하면 문서가 새 값으로 대체되고 CAS 값과 함께 제출됩니다.

비관적 잠금의 1단계에서는 타임아웃 기간도 지정해야 합니다. 왜 그럴까요? 오류나 충돌로 인해 3단계가 발생하지 않을 수 있으며, 결국 문서가 잠금 해제되어야 하기 때문입니다.

센서 문서가 많이 업데이트될 것으로 예상한다면 비관적으로 접근하는 것이 더 나을 수 있습니다. 하지만 잠금으로 인해 문서가 잠금 해제되기를 기다리는 다른 프로세스의 지연 시간이 단축될 수 있습니다.

비관적 잠금의 예를 들어 설명하자면 다음과 같습니다:

CAS 잠금 트레이드 오프

CAS 잠금과 관련해서는 고려해야 할 장단점이 있습니다. 낙관적 잠금은 충돌이 드물 때 잘 작동하지만 재시도 가능성을 처리하기 위해 적절한 재시도 로직을 구현해야 합니다.

이러한 절충점을 위해 고급 또는 특수 재시도를 사용할 수 있습니다. 예를 들어, 이 사용 사례에서는 재시도 횟수가 많거나 판독값이 매우 오래된 경우 수신 센서 판독값을 '포기'하고 폐기하는 것이 허용될 수 있습니다.

반면 비관적 잠금은 '더 안전한' 접근 방식이지만 잠금이 성능에 미치는 영향을 명확히 이해해야 합니다. 잠그면 문서가 잠금 해제될 때까지 기다려야 하는 다른 프로세스의 대기 시간이 늘어날 수 있습니다.

산 거래

센서 업데이트 문제에 대한 또 다른 잠재적 해결책은 ACID 트랜잭션을 사용하는 것입니다. 이 접근 방식은 이 사용 사례에서 단일 문서를 업데이트하는 데는 과도할 수 있지만 여러 문서를 원자 단위로 업데이트해야 하는 다른 사용 사례에서는 유용할 수 있습니다.

센서 데이터의 문제점은 빠른 속도로 들어올 수 있다는 것입니다. 현재 데이터를 확인하고 들어오는 센서 데이터로 업데이트하는 사이에 다른 수치가 들어올 수 있습니다. 이 문제를 방지하기 위해 ACID 트랜잭션을 사용하여 데이터를 조건부로 업데이트할 수 있습니다.

아래 샘플 코드는 ACID 트랜잭션을 사용하여 센서 문서를 업데이트하는 방법을 보여줍니다. 이 트랜잭션은 센서당 한 번에 하나의 업데이트 작업만 수행할 수 있도록 하여 여러 개의 수신 센서 판독값이 서로 간섭하는 것을 방지합니다.

산 거래 트레이드 오프

성능을 극대화하려면 가능한 한 키-값 API를 사용해야 합니다. 그러나 Couchbase에서 분산 ACID 트랜잭션을 사용하면 트랜잭션을 조정하기 위해 (백그라운드에서) 추가로 키-값 작업이 실행되기 때문에 약간의 오버헤드가 발생할 수 있습니다. Couchbase의 데이터는 자동으로 분산되므로 네트워크를 통해 여러 서버로 작업이 조정될 가능성이 높습니다.

CAS 작업보다 ACID 트랜잭션을 사용하면 얻을 수 있는 한 가지 이점은 Couchbase 트랜잭션 라이브러리에 이미 정교한 재시도 로직이 내장되어 있다는 점입니다. 이는 재시도 로직을 직접 작성하지 않아도 되는 방법이 될 수 있습니다. 또한 사용 사례에 여러 센서 문서를 업데이트하는 것이 포함된 경우 ACID 트랜잭션이 권장됩니다(실제로는 필수일 수도 있습니다).

SQL++ 업데이트 작업

조건부 업데이트를 수행하는 또 다른 접근 방식은 SQL++ UPDATE 쿼리를 사용하는 것입니다.

다음은 구현 예시입니다:

(참고로 에포크 타임스탬프를 사용하면 성능이 향상될 가능성이 높습니다).

코드에서 짐작할 수 있듯이, SQL++ 쿼리는 앞서 KV API 예제에서와 마찬가지로 실제로 뒤에서 CAS를 사용하고 있습니다.

SQL++ 트레이드 오프

조건부 업데이트를 위한 SQL++ 접근 방식에는 몇 가지 단점이 있습니다. 비록 사용 키 절을 사용하면 인덱스가 필요하지 않지만 쿼리는 여전히 쿼리 서비스에서 구문 분석해야 합니다. 많은 단계가 포함됩니다.. 다른 컴포넌트가 이미 쿼리 서비스를 사용하고 있는 경우 시스템에 추가적인 부담을 줄 수 있습니다.

전반적으로 SQL++ 접근 방식은 쿼리 구문 분석에 대한 오버헤드가 추가된다는 점에서 KV API와 매우 유사하므로, SQL++로 표현되는 복잡한 로직이 특별히 필요하거나 KV API를 사용할 수 없는 경우가 아니라면 최선의 선택이 아닐 수 있습니다.

이벤트

마지막으로 다루고자 하는 접근 방식은 이벤트 활용입니다.

CouchBase의 이벤트는 데이터 변경 이벤트에 비동기적으로 응답하는 JavaScript 함수를 작성하고 이를 CouchBase 클러스터에 배포하는 것으로 구성됩니다.

이 특정 사용 사례의 경우, 처음에는 센서 판독값의 위치로 '스테이징' 컬렉션을 사용하는 것이 가장 좋은 방법이라고 생각합니다. 순서는 다음과 같습니다:

    1. 수신되는 센서 판독값은 '스테이징' 컬렉션에 기록됩니다.
    2. 이벤트 온업데이트 함수는 새로운 센서 판독값에 응답합니다.
    3. 그리고 온업데이트 함수는 "현재" 컬렉션의 해당 문서에 대해 타임스탬프를 확인합니다.
    4. 타임스탬프가 더 최신인 경우 '현재' 컬렉션의 문서가 업데이트됩니다.

온업데이트 문서가 생성되면 실행됩니다. 또는 업데이트되므로 이전 문서를 스테이징 상태로 두어도 괜찮습니다(이렇게 하면 이벤트 코드가 간소화됩니다). 또한 컬렉션에 TTL을 설정하여 한동안 센서 수치가 업데이트되지 않으면 자동으로 정리되도록 할 수 있습니다.

다음은 이 디자인과 함께 작동하는 이벤트 함수의 예시입니다:

해당 이벤트 함수에 대한 구성은 다음과 같습니다:

Eventing configuration window in Couchbase

이벤트 트레이드 오프

이 코드에서 낙관적인 CAS 잠금이 사용되고 있음을 다시 한 번 주목하세요. 사실 이 코드는 앞서 KV API를 사용한 코드의 자바스크립트 버전이라고 할 수 있습니다.

한 가지 중요한 차이점은 이 기능이 Couchbase 클러스터 자체에서 실행된다는 것입니다. 이것이 바로 이벤트 기능의 핵심 이점입니다. 센서 데이터의 출처가 어디든 상관없이 Couchbase의 이벤트 기능은 데이터가 처리되도록 보장합니다. 로직을 데이터에 가깝게 유지합니다. 대신 KV API를 사용하는 클라이언트가 두 개 이상이라면 동일한 코드를 두 개 이상 구현해야 한다는 뜻입니다. 이렇게 하면 로직을 여러 곳에서 업데이트해야 하므로 로직이 변경될 때 문제가 발생할 수 있습니다.

그러나 SQL++와 마찬가지로 이벤트에도 약간의 오버헤드가 발생합니다. 이 경우에는 여러 컬렉션과 이벤트 서비스 자체입니다. 일반적으로 프로덕션 환경에서 Couchbase의 추가 노드가 필요할 수 있습니다. 또한 현재 Couchbase Server 커뮤니티에서는 Eventing을 사용할 수 없습니다.

요약

Couchbase는 사용 사례에 맞는 옵션과 절충안을 제공하는 다중 모델 데이터베이스입니다. 이 게시물에서는 센서 데이터 업데이트의 사용 사례에 대해 4가지 데이터 액세스 패턴과 각각의 장단점을 다루었습니다:

    • KV API - 성능이 뛰어나고 간단하지만 일부 재시도 로직이 필요할 수 있습니다.
    • ACID 트랜잭션 - 안정적이지만 오버헤드가 있습니다.
    • SQL++ - 친숙하고 선언적이지만 쿼리 구문 분석 및 실행 오버헤드가 있습니다.
    • 이벤트 처리 - 데이터에 가깝고 로직을 통합하지만 이벤트 처리 서비스 및 추가 수집에 대한 오버헤드가 있습니다.

모든 코드 샘플은 다음과 같습니다. GitHub에서 사용 가능.

다른 접근 방식을 생각해 보셨나요? 아래에 댓글을 남기거나 공유해 주세요. 카우치베이스 디스코드.

 

작성자

게시자 매튜 그로브스

Matthew D. Groves는 코딩을 좋아하는 사람입니다. C#, jQuery, PHP 등 무엇이든 풀 리퀘스트를 제출할 정도로 코딩을 좋아합니다. 90년대에 부모님의 피자 가게를 위해 QuickBASIC POS 앱을 만든 이후로 전문적으로 코딩을 해왔습니다. 현재 Couchbase의 선임 제품 마케팅 관리자로 일하고 있습니다. 여가 시간에는 가족과 함께 축구 경기를 관람하고 개발자 커뮤니티에 참여하며 시간을 보냅니다. 그는 .NET의 AOP, .NET의 프로 마이크로서비스, Pluralsight 저자, Microsoft MVP의 저자이기도 합니다.

댓글 남기기