libcouchbase 2.4.0이 출시되었습니다. 이전 버전에 비해 크게 개선된 아키텍처와 몇 가지 새로운 기능을 제공합니다.
이 블로그는 원래 2.4.0 DP1 버전용으로 작성되었으며, 개발자 프리뷰와 현재 GA 릴리스(2.4.0)의 차이점을 반영하기 위해 수정되었습니다.
직접 다운로드 링크: https://packages.couchbase.com/clients/c/index.html
API 문서: https://docs.couchbase.com/sdk-api/couchbase-c-client-2.4.0/
내부 개선 사항
패킷 구조
코드명 packet-ng와 같이 패킷을 일급 객체로 간주하는 방식으로 패킷 처리를 리팩터링하려는 시도에서 출발한 libcouchbase 버전입니다. 요청 패킷은 사용자가 요청한 쿠키와 서버 응답을 함께 묶는 라이브러리의 핵심 통화입니다.
2.4에서는 요청 패킷이 캡슐화되어 mc_PACKET 구조에 쿠키, 패킷 자체의 버퍼, 패킷 상태(수신, 플러시, 재시도, 오류, 보류 중)에 대한 정보가 포함됩니다. 패킷 구조는 mcreq 모듈은 개별 서버에 패킷을 할당, 해제, 분석 및 일정 변경을 위한 통합 API를 제공합니다.
패킷 대기열 및 버퍼
이제 패킷이 대기열(또는 mc_PIPELINE) 구조로 패킷의 순서를 링크된 목록으로 포함합니다. 패킷은 예약된 순서대로 대기열에 추가됩니다.
연속 버퍼를 사용하면 I/O 효율이 더 좋기 때문에 mc_PACKET 구조체 자체는 자체 객체 내에 버퍼를 포함하지 않고 특수 순서 내 연속 할당자에 의해 관리되는 인접 버퍼 내의 영역에 대한 특수 포인터를 포함합니다. 이를 통해 패킷은 "독립적인" 객체로 존재하면서 실제 네트워크 데이터는 순서대로 촘촘하게 패킹할 수 있습니다. 네트워크 버퍼 자체와 마찬가지로 각 패킷 객체도 이 얼로케이터의 별도 인스턴스를 사용하여 할당됩니다.
할당자는 netbuf 시스템에는 버퍼 조각을 효율적으로 처리하고 부분 전송과 같은 조건을 처리하면서 네트워크에 전송할 수 있도록 적절하게 준비하는 구조와 루틴도 포함되어 있습니다.
I/O 개선 사항
I/O 시스템이 리팩터링되고 모듈화되었습니다. lcbio 모듈 (src/lcbio). 주목할 만한 추가 사항은 lcbio_CTX 구조는 소켓 읽기, 쓰기 및 오류 처리를 위한 효율적이고 통합된 루틴을 포함하고 있으며, API에서 기본 I/O 모델(예: IOCP나 libuv와 같은 완료 기반 또는 select나 libevent와 같은 이벤트 기반)을 추상화합니다.
구성 변경 및 장애 시 견고성
이제 구성 변경 및 실패가 정상적으로 처리됩니다. 새 구성이 수신되고 관련 서버 개체(mc_SERVER) 의 위치를 변경해야 하는 경우, 해당 TCP 연결은 그대로 유지되며 더 이상 매핑되지 않은 모든 명령(패킷)에 대해 트래버스됩니다. 이러한 각 명령에 대해 mc_PACKET 구조가 복제되어 적절한 대기열에 배치되는 반면, 기본 전송 버퍼는 여전히 네트워크로 전송되고 해당 응답은 무시됩니다. 이렇게 하면 TCP 스트림을 재치 있게 유지하고 서버에서 오는 관련(및 예상되는) 오류 응답을 간단히 삼킬 수 있습니다.
TCP 연결이 갑자기 끊어지고 새 구성이 도착하지 않은 경우 관련 패킷이 재시도 대기열에 배치될 수 있습니다. 또는 즉시 실패합니다. 재시도되는 명령과 실패하는 명령은 사용자가 구성할 수 있습니다.
성능이 저하된 클러스터에서 작동하는 동안의 동작도 개선되었습니다. 이제 누락된 노드로 라우팅되는 작업은 대기열에 배치되고 라이브러리가 클러스터에 구성 요청을 투명하게 발행하여 애플리케이션이 추가 단계를 수행하지 않고도 항목을 다시 시도할 수 있습니다.
더 많은 테스트
이 버전의 라이브러리는 최대한 많은 시스템을 모듈화하도록 리팩터링되었기 때문에, 각 모듈의 동작이 더 잘 정의되고 종속성이 줄어들어 테스트가 더 간단해졌습니다. 버퍼 관리, 패킷 처리, 원시 I/O 처리를 위한 새로운 테스트가 다수 추가되었습니다. 이러한 모든 테스트는 카우치베이스 모의 서버 또는 외부 리소스에 완전히 포함되어 있고 결정론적입니다.
새로운 API 문서
API 문서는 이제 다음을 통해 생성됩니다. Doxygen. Doxygen은 소스 코드 주석을 기반으로 API 문서를 생성하는 오픈 소스 크로스 플랫폼 문서 생성기입니다. 이를 통해 API 문서를 최신 상태로 유지할 수 있으므로 새 API가 추가되고 여기에 코멘트가 포함되면 API 문서에 표시되고, 이전 API가 제거되면 문서에서 사라집니다.
또한 다음과 같은 기능이 공식적으로 추가되었습니다. 인터페이스 속성 를 모든 API에 추가하여 특정 API 호출의 안정성과 로드맵을 결정할 수 있도록 지원합니다. 이를 통해 특정 인터페이스가 실험적인지(또는 휘발성) 또는 이후 버전에서 수정되거나 제거되지 않을 것이라는 확신을 가지고 프로덕션 코드에서 사용할 수 있는 경우입니다.
새로운 기능
카우치베이스 엔터프라이즈 3.0에 대한 SSL 지원
버전 2.4에는 다음과 같은 지원이 포함되어 있습니다( OpenSSL)를 사용하여 SSL 프로토콜을 사용하여 서버와 통신할 수 있습니다. SSL 지원은 전적으로 내부의 레이어 중 하나에서 구현됩니다. lcbio 에 상주합니다. 아래에 lcbio_CTX. 따라서 SSL 지원은 라이브러리 내 대부분의 시스템에서 사실상 투명하게 제공됩니다. 기본적으로 라이브러리는 여전히 비암호화 모드로 연결됩니다(하지만 가능한 경우 SASL 비밀번호는 여전히 암호화됩니다).
연결 문자열 지원
클러스터에 연결하는 방법을 지정하는 새로운 방법도 새롭게 지원됩니다. 라이브러리에 점점 더 많은 연결 옵션이 추가됨에 따라 사용자가 클러스터에 연결할 때 사용할 방법과 대상을 선언할 수 있는 통일된 형식을 제공해야 했습니다. 브렛 로슨은 새로운 URI와 유사한 형식을 사용하면 명확하고 간결하며 모호하지 않은 형식으로 연결 옵션을 지정할 수 있습니다. URI 형식을 사용하면 구성 파일 내에서 이러한 설정을 지정할 수 있으므로 여러 설정을 수동으로 파싱한 다음 적절한 구조체 필드에 일치시킬 필요가 없습니다.
libcouchbase는 주로 상위 수준 라이브러리(예: Python, Node.JS, Ruby)의 핵심 계층으로 사용되므로 문자열 연결 옵션을 노출하면 이러한 모든 언어가 클러스터에 연결하는 방법을 지정할 때 공통 인터페이스와 공통 코드베이스를 쉽게 공유할 수 있습니다.
데모로 다음과 같은 연결 문자열을 예로 들어 보겠습니다. couchbase://foo.com,bar.com,baz.com/mybucket?operation_timeout=5000000&detailed_errcodes=true 는 foo.com, bar.com및 baz.com 를 버킷에 연결할 노드로 mybucket를 사용하여 5초의 작업 타임아웃을 적용하고 자세한 오류 코드를 활성화합니다(라이브러리의 또 다른 새로운 기능).
새로운 공통 작업 API
이번 버전에서는 라이브러리의 다음 주요 릴리스 API의 기초가 되는 새로운 (휘발성) 요청 API 세트가 추가되었습니다. 이러한 API는 한 번에 하나의 명령에 대해 작동하며 사용자가 스케줄링 컨텍스트에 '진입'하고 여러 개의 명령을 예약한 다음 '종료'하는 진입/퇴장 패턴을 따릅니다. 각 명령이 암시적으로 네트워크에 플러시를 예약했던 2.x API와 달리, 이 새로운 API는 현재 컨텍스트를 "떠날" 때만 플러시를 예약합니다. 따라서 명령 구조의 배열을 할당할 필요 없이 여러 개의 일괄 처리 작업을 효율적으로 구성할 수 있습니다.
또한 새로운 요청 및 응답 API는 요청 및 응답 구조에 대한 공통 ABI를 만들어 공통 작업에서 코드를 재사용할 수 있도록 합니다. 이 새로운 API에서 모든 요청 구조는 레이아웃 호환이 가능합니다. lcb_CMDBASE 구조와 모든 응답 구조는 레이아웃 호환이 가능합니다. lcb_RESPBASE 구조체를 사용할 수 있습니다. 마찬가지로 새로운 콜백 메커니즘을 사용하면 단일 콜백이 두 가지 이상의 연산을 처리할 수 있으며, 콜백에는 연산 유형을 나타내는 정수 상수가 전달되고 lcb_RESPBASE 구조로 캐스팅할 수 있으며, 필요한 경우 적절한 작업별 응답 구조로 캐스팅할 수 있습니다.
#포함
#포함
1TP5정적 공백 포함
op_callback(lcb_t 인스턴스, int cbtype, const lcb_RESPBASE *resp)
{
fprintf(stderr, "코드 0x%xn으로 키 %.*s에 대한 결과를 얻었습니다."),
(int)resp->nkey, resp->key, resp->rc);
if (resp->rc != LCB_SUCCESS) {
반환합니다;
}
if (cbtype == LCB_CALLBACK_GET) {
const lcb_RESPGET *gresp = (const lcb_RESPGET *)resp;
fprintf(stderr, "RETRIEVED ITEMn");
fprintf(stderr, "VALUE: %.*snFLAGS: 0x%xnCAS=0x%lxn",
(int)gresp->nvalue, gresp->value, gresp->itmflags, gresp->cas);
} else if (cbtype == LCB_CALLBACK_STORE) {
fprintf(stderr, "STORED ITEMn");
fprintf(stderr, "CAS: 0x%lxn", resp->cas);
}
}
int main(void)
{
lcb_t 인스턴스;
서명되지 않은 II;
구조체 lcb_create_st cropts = { 0 };
lcb_error_t err;
cropts.v.v3.connstr = "couchbase://10.0.0.99/default";
lcb_create(&인스턴스, &크롭트);
lcb_connect(인스턴스);
lcb_wait(인스턴스);
lcb_install_callback3(instance, LCB_CALLBACK_GET, op_callback);
lcb_install_callback3(instance, LCB_CALLBACK_STORE, op_callback);
for (ii = 0; ii < 10; ii++) {
lcb_CMDSTORE store_cmd = { 0 };
lcb_CMDGET get_cmd = { 0 };
char buf[1024];
size_t nbuf;
sprintf(buf, "Key_%d", ii);
nbuf = strlen(buf);
LCB_CMD_SET_KEY(&store_cmd, buf, nbuf);
LCB_CMD_SET_VALUE(&store_cmd, "Value", strlen("Value"));
store_cmd.operation = LCB_SET;
err = lcb_store3(인스턴스, NULL, &store_cmd);
if (err != LCB_SUCCESS){
break;
}
LCB_CMD_SET_KEY(&get_cmd, buf, nbuf);
err = lcb_get3(인스턴스, NULL, &get_cmd);
if (err != LCB_SUCCESS) {
break;
}
}
if (err == LCB_SUCCESS) {
lcb_sched_leave(인스턴스);
lcb_wait(인스턴스);
} else {
lcb_sched_fail(인스턴스);
}
lcb_destroy(인스턴스);
0을 반환합니다;
}
효율적인 페이로드 처리
2.4 클라이언트에는 애플리케이션과 라이브러리 간에 페이로드를 보다 효율적으로 처리할 수 있도록 몇 가지 기능이 도입되었습니다. 기본적으로 라이브러리는 라이브러리에서 set 연산에 전달된 값 버퍼가 전체 연산 기간 동안 유효한 메모리로 유지될 필요가 없도록 합니다. 마찬가지로 get 응답을 반환하는 경우, 데이터가 콜백 외부에서 유지되려면 애플리케이션이 값 버퍼를 복사해야 합니다.
라이브러리에 표시할 수 있는 실험적 지원이 추가되었습니다. not 를 사용하여 값 버퍼를 복사합니다( set) 작업을 통해 lcb_VALBUF 구조 ( lcb_CMDSTORE) 구조:.
마찬가지로, 추가 필드가 내부에 존재합니다. lcb_RESPGET 구조라는 bufh. 이 필드에는 불투명 포인터가 포함되어 있습니다. 버퍼 핸들. 이 버퍼 핸들은 지속으로 설정 외부 콜백의를 사용하여 응답 데이터가 버퍼 핸들 자체가 출시. 내부적으로는 참조 카운팅을 사용합니다.
원시 패킷 디스패치
이제 서버로 전송할 원시 멤캐시드 패킷을 libcouchbase에 전달하고 응답으로 원시 멤캐시드 패킷을 받을 수 있습니다. 이를 통해 패킷 기능에 대한 하위 수준의 액세스를 허용하고 프록시 서버를 구축할 수 있습니다. 이 기능은 응답 버퍼가 콜백으로 복사되지 않고 콜백 외부에 유지될 수 있도록 구현되어 있으므로 처리를 위해 GET 응답을 임시 버퍼로 복사할 필요가 없습니다. 마찬가지로 요청 패킷 자체도 선택적으로 복사하지 않고 라이브러리에서 더 이상 필요하지 않을 때 콜백을 호출하도록 할 수 있습니다.
새로운 클러스터 구성 API
초기 부트스트랩이 성공했는지 실패했는지 사용자에게 알려주는 새로운 콜백이 라이브러리에 추가되었습니다. 이 작업은 이전에는 오류 콜백(lcb_set_error_callback()) 및 구성 콜백 (lcb_set_configuration_callback)에서 초기 오류가 발생하면 오류 콜백이 호출되고 클러스터가 새 구성을 수신하면 구성 콜백이 호출됩니다. 그러나 오류 콜백은 특정 노드가 실패할 때마다 호출되어, 여러 노드가 전달되고 목록의 첫 번째 노드만 실패하면 클라이언트가 조기에 실패하게 됩니다. 새로운 부트스트랩 콜백 는 부트스트랩 성공 또는 실패를 나타내는 명확한 오류 코드와 함께 초기 생성 중에 한 번만 호출됩니다. 비동기식 클라이언트가 아닌 경우 lcb_get_bootstrap_status() 콜백에 의존할 필요가 없습니다:
구조체 lcb_create_st 크롭 = {
.version = 3,
.v.3.dsn = "couchbase://cbnode1,cbnode2/mybucket"
};
lcb_error_t err = lcb_create(&instance, &cropt);
if (err != LCB_SUCCESS) {
// 오류를 처리합니다;
}
#if I_AM_BLOCKING
err = lcb_connect(인스턴스);
lcb_wait(인스턴스);
if ((err = lcb_get_bootstrap_status(instance)) != LCB_SUCCESS)
{
printf("부트스트랩에 실패했습니다: %sn", lcb_strerror(instance, err));
}
// do 명령
#else /* 나는 동기화 */
static void bootstrap_callback(lcb_t 인스턴스, lcb_error_t err) {
if (err != LCB_SUCCESS) {
printf("부트스트랩할 수 없습니다");
} else {
lcb_GETCMD gcmd = { 0 };
LCB_KREQ_SIMPLE(&req.key, "foo", 3);
lcb_sched_enter(인스턴스);
lcb_get3(인스턴스, NULL, &gcmd);
lcb_sched_leave(인스턴스);
}
}
lcb_set_bootstrap_callback(인스턴스, 부트스트랩_콜백);
lcb_connect(instance); // 이벤트 루프로 돌아가거나 lcb_wait()을 호출합니다.
#endif
또한 lcb_refresh_config() 콜백이 추가되어 클라이언트가 클러스터에서 새 구성을 강제로 요청하도록 합니다. 이 기능은 시간 초과가 많이 발생하는 경우 재구성을 '강제'하거나 애플리케이션 내에서 사용자 정의된 새로 고침 정책을 적용하는 데 유용합니다.
마지막으로 vbucket API가 노출되어 라이브러리에서 사용 중인 현재 구성을 검사할 수 있습니다. 새로운 API는 libcouchbase/vbucket.h (헤더 디렉토리 내부).
lcbvb_CONFIG *config;
lcb_error_t err;
err = lcb_cntl(instance, LCB_CNTL_GET, LCB_CNTL_VBCONFIG, &config);
// 오류 확인
printf("현재 구성의 개정판은 %dn입니다.", lcbvb_get_revision(config));
printf("클러스터에 %u 서버가 있습니다.", lcbvb_get_nservers(config));
또한 개정 를 사용하여 클라이언트가 새 구성을 받았는지 확인합니다.
좋아 보이네요. 맥시/맥로더를 다시 작성해보고 싶어요. 하지만 시간을 낼 수 있을지는 모르겠습니다.
새로운 기능으로 쑥뜸을 다시 해보는 것을 추천하고 싶습니다. 저는 실제로 \"에폭시\"라는 작은 쑥뜸 클론을 C++로 작성해본 적이 있습니다: https://github.com/mnunberg/ep...
[...] 지난 달에 라이브러리의 개발자 프리뷰 버전이 출시되었습니다. 여기에는 여러 가지 개선 사항이 포함되어 있으며 여기에서 읽어보실 수 있습니다. [...]