{"id":1655,"date":"2014-12-16T19:35:27","date_gmt":"2014-12-16T19:35:27","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=1655"},"modified":"2017-05-03T13:26:40","modified_gmt":"2017-05-03T20:26:40","slug":"introducing-libcouchbase-24-0","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/ko\/introducing-libcouchbase-24-0\/","title":{"rendered":"libcouchbase 2.4 \uc18c\uac1c"},"content":{"rendered":"<p><em>libcouchbase<\/em><span style=\"font-family: inherit; font-size: 1em;\">\u00a02.4.0 is here. It offers large architectural improvements and several new features, improving over previous versions.<\/span><\/p>\n<p><em>This blog was originally written for the 2.4.0 DP1 version, it has been modified to reflect the differences between the developer preview and the current GA release (2.4.0)<\/em><\/p>\n<p><span style=\"font-family: inherit; font-size: 1em; line-height: 1.4375em;\"><strong>Direct download links<\/strong>:\u00a0<\/span><a style=\"font-family: inherit; font-size: 1em; line-height: 23px;\" href=\"https:\/\/packages.couchbase.com\/clients\/c\/index.html\">https:\/\/packages.couchbase.com\/clients\/c\/index.html<\/a><\/p>\n<p><strong>API Documentation:\u00a0<\/strong><a href=\"https:\/\/docs.couchbase.com\/sdk-api\/couchbase-c-client-2.4.0\/\">https:\/\/docs.couchbase.com\/sdk-api\/couchbase-c-client-2.4.0\/<\/a><\/p>\n<p><span style=\"color: #007da4; font-size: 23px; font-weight: 600; line-height: 1.4;\">Internal Improvements<\/span><\/p>\n<h3><span style=\"color: #be2228; font-size: 23px;\">Packet Structures<\/span><\/h3>\n<p>Codenamed\u00a0<em>packet-ng<\/em>, this version of libcouchbase started out as an attempt to refactor packet handling in such a way that packets were considered first class objects. The request packet is the core currency of the library as it binds the user requested cookie together with the server reply.<\/p>\n<p>In 2.4, request packets are encapsulated in the\u00a0<em>mc_PACKET<\/em>\u00a0structure which contains information about the cookie, the buffers for the packet itself, and the state of the packet (i.e. received, flushed, retried, errored, pending). The packet structure comes along with the\u00a0<em>mcreq<\/em>\u00a0module which provides a unified API for allocating, freeing, analyzing, and rescheduling packets to individual servers.<\/p>\n<h3>Packet Queues and Buffers<\/h3>\n<p>Packets are now inserted into a queue (or an\u00a0<em>mc_PIPELINE<\/em>) structure which contains the ordering of the packets as a linked list. Packets are added to the queue in the order they are scheduled.<\/p>\n<p>Since I\/O efficiency is better with contiguous buffers, the\u00a0<em>mc_PACKET<\/em>\u00a0structure itself does not contain the buffer within its own object, but rather a special pointer to a region within a contiguous buffer managed by a special in-order contiguous allocator. This allows packets to live as &#8220;independent&#8221; objects while having their actual network data be tightly packed in sequence. Like the network buffers themselves, each packet object is also allocated using a separate instance of this allocator.<\/p>\n<p>The allocator lives in the\u00a0<em>netbuf<\/em>\u00a0system which also contains structures and routines for efficiently handling buffer fragments and properly preparing them for being sent to the network, while handling conditions such as partial sends.<\/p>\n<h3>I\/O Improvements<\/h3>\n<p>The I\/O system has been refactored and modularized within the\u00a0<em>lcbio<\/em>\u00a0module (<em>src\/lcbio<\/em>). The notable addition is that of the\u00a0<em>lcbio_CTX<\/em>\u00a0structure which contains efficient and unified routines for socket reads, writes, and error handling, abstracting the underlying I\/O model (e.g. completion-based like IOCP or libuv; or event-based like select or libevent) from its API.<\/p>\n<h3>Robustness during Configuration Changes and Failures<\/h3>\n<p>Configuration changes and failures are now handled gracefully. When a new configuration is received and the related server object (<em>mc_SERVER)<\/em>\u00a0needs to change positions, its TCP connection is kept in tact, and it is traversed for any commands (packets) which are no longer mapped to it. For each of those commands, the mc_PACKET structure is duplicated and placed in the proper queue, while the possibly underlying send buffer is still sent out to the network and its response ignored. This allows us to keep the TCP stream in tact and simply swallow the related (and anticipated) error response coming from the server.<\/p>\n<p>If a TCP connection is suddenly broken and no new configuration has arrived, the related packets may be placed inside a retry queue\u00a0<em>or<\/em>\u00a0immediately failed. Which commands are retried and which commands are failed can be configured by the user.<\/p>\n<p>Behavior while operating under a degraded cluster has also been improved. Now operations which are routed to missing nodes are placed in the queue and the library will transparently issue a configuration request to the cluster, thus allowing the application to retry the item without performing extra steps.<\/p>\n<h3>More Tests<\/h3>\n<p>As this version of the library has been refactored to modularize as many systems as possible, it means that testing each of the modules becomes simpler as they have more well defined behavior and fewer dependencies. Many new tests have been added dedicated to buffer management, packet handling, and raw I\/O handling. All of these tests make no use of the <em>CouchbaseMock<\/em> server or any external resources but are entirely contained and deterministic.<\/p>\n<h2>New API Documentation<\/h2>\n<p>API documentation is now generated via <em>Doxygen<\/em>. Doxygen is an open source cross platform documentation generator which generate API documentation based on source code comments. This will allow our API documentation to be more up to date &#8211; so that as long as a new API is added and it contains comments, it will feature inside the API documentation, and if an older API is removed, it will disappear from it.<\/p>\n<p>Additionally we&#8217;ve formally added\u00a0<em>interface attributes\u00a0<\/em>to all of our APIs to help you determine the stability and roadmap for a particular API call. This allows us to clearly convery if a specific interface is experimental (or\u00a0<em>volatile<\/em>), or if it may be used in production code with confidence that it will not be modified or removed in later versions.<\/p>\n<h2>New Features<\/h2>\n<h3>SSL Support for Couchbase Enterprise 3.0<\/h3>\n<p>Version 2.4 contains support (via <em>OpenSSL<\/em>) for communicating with the server using the SSL protocol. SSL support is implemented entirely in one of the layers inside\u00a0<em>lcbio<\/em>\u00a0and thus resides\u00a0<em>underneath<\/em>\u00a0<em>lcbio_CTX<\/em>. As such, SSL support is virtually transparent to most systems in the library. By default the library will still connect in a non-encrypted mode (your SASL password will still be encrypted if possible, though)<\/p>\n<h3>Connection String Support<\/h3>\n<p>Also new is support for a new way of specifying how to connect to the cluster. As more and more connection options are added to the library it was necessary to provide a uniform format for users to declare how and what they want to use when connecting to the cluster. <a href=\"https:\/\/docs.google.com\/document\/d\/172ausWsYt3eYYOZ1lYHVS8ccbrrVJaGwHIRsf_O_Hyc\/edit?disco=AAAAAHZn6S4#\">Brett Lawson proposed a new URI-like<\/a>\u00a0format which allows one to specify connection options in a clear, concise, and unambiguous format. Using a URI format allows things such as being able to specify these settings inside a configuration file (so you don&#8217;t have to manually parse multiple settings and then match them to appropriate struct fields).<\/p>\n<p>Since libcouchbase is mostly used as a core layer of higher level libraries (such as Python, Node.JS and Ruby), exposing a string connection option makes it easy for all these languages to share a common interface and a common codebase when specifying how to connect to the cluster.<\/p>\n<p>As a demonstration, a connection string like\u00a0<em><span style=\"font-family: courier new,courier,monospace;\">couchbase:\/\/foo.com,bar.com,baz.com\/mybucket?operation_timeout=5000000&amp;detailed_errcodes=true<\/span>\u00a0<\/em>\u00a0will use\u00a0<em>foo.com<\/em>,\u00a0<em>bar.com<\/em>, and\u00a0<em>baz.com<\/em>\u00a0as nodes to connect to the bucket\u00a0<em>mybucket<\/em>, applying an operation timeout of 5 seconds and enabling detailed error codes (another new feature in the library).<\/p>\n<h3>New Common Operation API<\/h3>\n<p>A new set of (volatile) request APIs were added in this version to form the basis of the APIs of the next major release of the library. These APIs operate on a single command at a time and follow an enter\/leave pattern, where a user &#8220;enters&#8221; a scheduling context, schedules a bunch of commands, and then &#8220;leaves&#8221;. In contrast to the 2.x APIs where each command would implicitly schedule a flush to the network, these new APIs will only schedule a flush when &#8220;leaving&#8221; their current context. This allows efficient construction of multiple batched operations without having to allocate an array of command structures to do so; thus for example.<\/p>\n<p>Additionally, the new request and response APIs allow code reuse in common operations by making a common ABI for the request and response structures. In this new API all request structures are layout-compatible with the\u00a0<em>lcb_CMDBASE\u00a0<\/em>\u00a0structure and all response structures are layout-compatible with the\u00a0<em>lcb_RESPBASE<\/em>\u00a0structure. Likewise the new callback mechanism allows a single callback to handle more than one kind of operation, wherein the callback is passed an integer constant indicating the type of operation, and an\u00a0<em>lcb_RESPBASE<\/em>\u00a0structure which may be casted to the appropriate operation-specific response structure if needed.<\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family: monospace;\">#include &lt;libcouchbase\/couchbase.h&gt;<br \/>\n#include<br \/>\n#include<br \/>\n#includestatic void<br \/>\nop_callback(lcb_t instance, int cbtype, const lcb_RESPBASE *resp)<br \/>\n{<br \/>\nfprintf(stderr, &#8220;Got result for key %.*s with code 0x%xn&#8221;,<br \/>\n(int)resp-&gt;nkey, resp-&gt;key, resp-&gt;rc);<br \/>\nif (resp-&gt;rc != LCB_SUCCESS) {<br \/>\nreturn;<br \/>\n}<\/p>\n<p>if (cbtype == LCB_CALLBACK_GET) {<br \/>\nconst lcb_RESPGET *gresp = (const lcb_RESPGET *)resp;<br \/>\nfprintf(stderr, &#8220;RETRIEVED ITEMn&#8221;);<br \/>\nfprintf(stderr, &#8220;VALUE: %.*snFLAGS: 0x%xnCAS=0x%lxn&#8221;,<br \/>\n(int)gresp-&gt;nvalue, gresp-&gt;value, gresp-&gt;itmflags, gresp-&gt;cas);<br \/>\n} else if (cbtype == LCB_CALLBACK_STORE) {<br \/>\nfprintf(stderr, &#8220;STORED ITEMn&#8221;);<br \/>\nfprintf(stderr, &#8220;CAS: 0x%lxn&#8221;, resp-&gt;cas);<br \/>\n}<br \/>\n}<\/p>\n<p>int main(void)<br \/>\n{<br \/>\nlcb_t instance;<br \/>\nunsigned ii;<br \/>\nstruct lcb_create_st cropts = { 0 };<br \/>\nlcb_error_t err;<\/p>\n<p>cropts.v.v3.connstr = &#8220;couchbase:\/\/10.0.0.99\/default&#8221;;<br \/>\nlcb_create(&amp;instance, &amp;cropts);<br \/>\nlcb_connect(instance);<br \/>\nlcb_wait(instance);<br \/>\nlcb_install_callback3(instance, LCB_CALLBACK_GET, op_callback);<br \/>\nlcb_install_callback3(instance, LCB_CALLBACK_STORE, op_callback);<\/p>\n<p>for (ii = 0; ii &lt; 10; ii++) {<\/p>\n<p>lcb_CMDSTORE store_cmd = { 0 };<br \/>\nlcb_CMDGET get_cmd = { 0 };<br \/>\nchar buf[1024];<br \/>\nsize_t nbuf;<\/p>\n<p>sprintf(buf, &#8220;Key_%d&#8221;, ii);<br \/>\nnbuf = strlen(buf);<\/p>\n<p>LCB_CMD_SET_KEY(&amp;store_cmd, buf, nbuf);<br \/>\nLCB_CMD_SET_VALUE(&amp;store_cmd, &#8220;Value&#8221;, strlen(&#8220;Value&#8221;));<br \/>\nstore_cmd.operation = LCB_SET;<br \/>\nerr = lcb_store3(instance, NULL, &amp;store_cmd);<br \/>\nif (err != LCB_SUCCESS){<br \/>\nbreak;<br \/>\n}<br \/>\nLCB_CMD_SET_KEY(&amp;get_cmd, buf, nbuf);<br \/>\nerr = lcb_get3(instance, NULL, &amp;get_cmd);<br \/>\nif (err != LCB_SUCCESS) {<br \/>\nbreak;<br \/>\n}<br \/>\n}<br \/>\nif (err == LCB_SUCCESS) {<br \/>\nlcb_sched_leave(instance);<br \/>\nlcb_wait(instance);<br \/>\n} else {<br \/>\nlcb_sched_fail(instance);<br \/>\n}<br \/>\nlcb_destroy(instance);<br \/>\nreturn 0;<br \/>\n}<\/p>\n<\/div>\n<\/div>\n<h3>Efficient Payload Handling<\/h3>\n<p>Several features have been introduced into the 2.4 client to allow for more efficient payload handling between the application and the library. By default the library will copy the value for a\u00a0<em>set<\/em>\u00a0operation so as to not require the passed-in value buffer to remain in valid memory for the duration of the entire operation. Likewise for\u00a0<em>get<\/em>\u00a0responses, the application must copy the value buffer if it wishes for the data to persist outside of the callback.<\/p>\n<p>Experimental support has been added that enables you to indicate to the library\u00a0<em>not<\/em>\u00a0to copy the value buffer (for\u00a0<em>set<\/em>) operations via the\u00a0<em><a href=\"https:\/\/docs.couchbase.com\/sdk-api\/couchbase-c-client-2.4.0\/kvbuf_8h.html#structlcb___v_a_l_b_u_f\">lcb_VALBUF<\/a> structure\u00a0<\/em>(provided as a field within the\u00a0<em>lcb_CMDSTORE<\/em>) structure:.<\/p>\n<p>Likewise, an additional field exists within the\u00a0<em>lcb_RESPGET<\/em>\u00a0structure called <em>bufh<\/em>. This field\u00a0contains an opaque pointer to a\u00a0<em>buffer handle<\/em>. This buffer handle can be <a href=\"https:\/\/docs.couchbase.com\/sdk-api\/couchbase-c-client-2.4.0\/group___l_c_b___p_k_t_f_w_d.html#ga05147342799a9423d2eb71786e192af4\">set to persist\u00a0<em>outside\u00a0<\/em>of the callback<\/a>, allowing the response data to remain valid until the buffer handle itself is\u00a0<em>released<\/em>. Internally this uses a reference counting<\/p>\n<h3>Raw Packet Dispatching<\/h3>\n<p><span style=\"font-family: inherit; font-size: 1em; line-height: 1.4375em;\">You may now give libcouchbase raw memcached packets to dispatch to a server and receive a raw memcached packet in reply. This allows lower level access to packet functionality and allows you to build a proxy server. The feature is implemented in such a way that the response buffers are not copied over to the callback and may be kept alive outside the callback, so that you do not need to copy over GET responses into a temporary buffer for processing. Likewise the request packet itself can also optionally not be copied, but have a callback invoked when it is no longer needed by the library.<\/span><\/p>\n<p><span style=\"color: #be2228; font-size: 23px; font-weight: 600; line-height: 1.4;\">New Cluster Configuration APIs<\/span><\/p>\n<p><span style=\"font-family: inherit; font-size: 1em; line-height: 1.4375em;\">A new callback has been added to the library notifying the user if the inital bootstrap has succeeded or failed. This was previously done using the\u00a0<\/span><em style=\"font-family: inherit; font-size: 1em; line-height: 1.4375em;\">error callback (lcb_set_error_callback()<\/em><span style=\"font-family: inherit; font-size: 1em; line-height: 1.4375em;\">) and the\u00a0<\/span><em style=\"font-family: inherit; font-size: 1em; line-height: 1.4375em;\">configuration callback\u00a0<\/em><em style=\"font-family: inherit; font-size: 1em; line-height: 1.4375em;\">(lcb_set_configuration_callback)<\/em><span style=\"font-family: inherit; font-size: 1em; line-height: 1.4375em;\">, where the error callback would be invoked upon an initial error, and the configuration callback invoked when the cluster received a new configuration. The error callback however would also be invoked each time a specific node failed, making clients fail prematurely if multiple nodes were passed and only the first one in the list failed. The new\u00a0<\/span><em style=\"font-family: inherit; font-size: 1em; line-height: 1.4375em;\">bootstrap callback<\/em><span style=\"font-family: inherit; font-size: 1em; line-height: 1.4375em;\">\u00a0is invoked only once, and only during the initial creation with a definite error code indicating either bootstrap success or failure. For non asynchronous clients you can simply use\u00a0<\/span><em style=\"font-family: inherit; font-size: 1em; line-height: 1.4375em;\">lcb_get_bootstrap_status()<\/em><span style=\"font-family: inherit; font-size: 1em; line-height: 1.4375em;\">\u00a0and not need to rely on a callback:<\/span><\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family: monospace;\">lcb_t instance;<br \/>\nstruct lcb_create_st cropt = {<br \/>\n.version = 3,<br \/>\n.v.3.dsn = &#8220;couchbase:\/\/cbnode1,cbnode2\/mybucket&#8221;<br \/>\n};<br \/>\nlcb_error_t err = lcb_create(&amp;instance, &amp;cropt);<br \/>\nif (err != LCB_SUCCESS) {<br \/>\n\/\/ handle error;<br \/>\n}<br \/>\n#if I_AM_BLOCKING<br \/>\nerr = lcb_connect(instance);<br \/>\nlcb_wait(instance);<br \/>\nif ((err = lcb_get_bootstrap_status(instance)) != LCB_SUCCESS)<br \/>\n{<br \/>\nprintf(&#8220;Failed to bootstrap: %sn&#8221;, lcb_strerror(instance, err));<br \/>\n}<br \/>\n\/\/ do commands<br \/>\n#else \/* I AM ASYNC *\/<br \/>\nstatic void bootstrap_callback(lcb_t instance, lcb_error_t err) {<br \/>\nif (err != LCB_SUCCESS) {<br \/>\nprintf(&#8220;Couldn&#8217;t bootstrap&#8221;);<br \/>\n} else {<br \/>\nlcb_GETCMD gcmd = { 0 };<br \/>\nLCB_KREQ_SIMPLE(&amp;req.key, &#8220;foo&#8221;, 3);<br \/>\nlcb_sched_enter(instance);<br \/>\nlcb_get3(instance, NULL, &amp;gcmd);<br \/>\nlcb_sched_leave(instance);<br \/>\n}<br \/>\n}<br \/>\nlcb_set_bootstrap_callback(instance, bootstrap_callback);<br \/>\nlcb_connect(instance); \/\/ Return to event loop, or call lcb_wait()<br \/>\n#endif<\/div>\n<\/div>\n<p><span style=\"font-family: inherit; font-size: 1em;\">Additionally, an <\/span><em>lcb_refresh_config()<\/em><span style=\"font-family: inherit; font-size: 1em;\">\u00a0callback has been added to forcefully make the client request a new configuration from the cluster. This is useful to &#8220;force&#8221; a reconfiguration in cases where many timeouts are being encountered, or to enforce a customized refresh policy within the application.<\/span><\/p>\n<p><span style=\"font-family: inherit; font-size: 1em;\">Finally, the <\/span><em>vbucket<\/em><span style=\"font-family: inherit; font-size: 1em;\">\u00a0API has been exposed, allowing inspection of the current configuration being used by the library. The new API is located in\u00a0<\/span><em>libcouchbase\/vbucket.h<\/em><span style=\"font-family: inherit; font-size: 1em;\">\u00a0(inside the headers directory).\u00a0<\/span><\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family: monospace;\">#include &lt;libcouchbase\/vbucket.h&gt;<br \/>\nlcbvb_CONFIG *config;<br \/>\nlcb_error_t err;<br \/>\nerr = lcb_cntl(instance, LCB_CNTL_GET, LCB_CNTL_VBCONFIG, &amp;config);<br \/>\n\/\/ Check error<br \/>\nprintf(&#8220;Revision of current config is %dn&#8221;, lcbvb_get_revision(config));<br \/>\nprintf(&#8220;Cluster has %u serversn&#8221;, lcbvb_get_nservers(config));<\/div>\n<\/div>\n<p><span style=\"font-family: inherit; font-size: 1em;\">You may also use the\u00a0<\/span><em>revision<\/em><span style=\"font-family: inherit; font-size: 1em;\">\u00a0to determine if the client has received a new configuration.<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>libcouchbase\u00a02.4.0 is here. It offers large architectural improvements and several new features, improving over previous versions. This blog was originally written for the 2.4.0 DP1 version, it has been modified to reflect the differences between the developer preview and the [&hellip;]<\/p>\n","protected":false},"author":38,"featured_media":13873,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1],"tags":[],"ppma_author":[8997],"class_list":["post-1655","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.3 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Introducing libcouchbase 2.4 - The Couchbase Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/ko\/introducing-libcouchbase-24-0\/\" \/>\n<meta property=\"og:locale\" content=\"ko_KR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Introducing libcouchbase 2.4\" \/>\n<meta property=\"og:description\" content=\"libcouchbase\u00a02.4.0 is here. It offers large architectural improvements and several new features, improving over previous versions. This blog was originally written for the 2.4.0 DP1 version, it has been modified to reflect the differences between the developer preview and the [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/ko\/introducing-libcouchbase-24-0\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2014-12-16T19:35:27+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2017-05-03T20:26:40+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2022\/11\/couchbase-nosql-dbaas.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1800\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Mark Nunberg, Software Engineer, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Mark Nunberg, Software Engineer, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11\ubd84\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/introducing-libcouchbase-24-0\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/introducing-libcouchbase-24-0\\\/\"},\"author\":{\"name\":\"Mark Nunberg, Software Engineer, Couchbase\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/person\\\/76a75284da32b6f257c8e5e156e6e016\"},\"headline\":\"Introducing libcouchbase 2.4\",\"datePublished\":\"2014-12-16T19:35:27+00:00\",\"dateModified\":\"2017-05-03T20:26:40+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/introducing-libcouchbase-24-0\\\/\"},\"wordCount\":2254,\"commentCount\":3,\"publisher\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/introducing-libcouchbase-24-0\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2022\\\/11\\\/couchbase-nosql-dbaas.png\",\"articleSection\":[\"Uncategorized\"],\"inLanguage\":\"ko-KR\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/introducing-libcouchbase-24-0\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/introducing-libcouchbase-24-0\\\/\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/introducing-libcouchbase-24-0\\\/\",\"name\":\"Introducing libcouchbase 2.4 - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/introducing-libcouchbase-24-0\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/introducing-libcouchbase-24-0\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2022\\\/11\\\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2014-12-16T19:35:27+00:00\",\"dateModified\":\"2017-05-03T20:26:40+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/introducing-libcouchbase-24-0\\\/#breadcrumb\"},\"inLanguage\":\"ko-KR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/introducing-libcouchbase-24-0\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"ko-KR\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/introducing-libcouchbase-24-0\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2022\\\/11\\\/couchbase-nosql-dbaas.png\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2022\\\/11\\\/couchbase-nosql-dbaas.png\",\"width\":1800,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/introducing-libcouchbase-24-0\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Introducing libcouchbase 2.4\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"ko-KR\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ko-KR\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/2023\\\/04\\\/admin-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/2023\\\/04\\\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/person\\\/76a75284da32b6f257c8e5e156e6e016\",\"name\":\"Mark Nunberg, Software Engineer, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ko-KR\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/d5a465565eb8a3990192957806a9bc2989ba9f52a5f953d988b5e8afff3b6dc7?s=96&d=mm&r=g895cad0986a0ab674fda857b6ba71ce0\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/d5a465565eb8a3990192957806a9bc2989ba9f52a5f953d988b5e8afff3b6dc7?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/d5a465565eb8a3990192957806a9bc2989ba9f52a5f953d988b5e8afff3b6dc7?s=96&d=mm&r=g\",\"caption\":\"Mark Nunberg, Software Engineer, Couchbase\"},\"description\":\"Mark Nunberg is a software engineer working at Couchbase. He maintains the C client library (libcouchbase) as well as the Python client. He also developed the Perl client (for use at his previous company) - which initially led him to working at Couchbase. Prior to joining Couchbase, he worked on distributed and high performance routing systems at an eCommerce analytics firm. Mark studied Linguistics at the Hebrew University of Jerusalem.\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/ko\\\/author\\\/mark-nunberg\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Introducing libcouchbase 2.4 - The Couchbase Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/ko\/introducing-libcouchbase-24-0\/","og_locale":"ko_KR","og_type":"article","og_title":"Introducing libcouchbase 2.4","og_description":"libcouchbase\u00a02.4.0 is here. It offers large architectural improvements and several new features, improving over previous versions. This blog was originally written for the 2.4.0 DP1 version, it has been modified to reflect the differences between the developer preview and the [&hellip;]","og_url":"https:\/\/www.couchbase.com\/blog\/ko\/introducing-libcouchbase-24-0\/","og_site_name":"The Couchbase Blog","article_published_time":"2014-12-16T19:35:27+00:00","article_modified_time":"2017-05-03T20:26:40+00:00","og_image":[{"width":1800,"height":630,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2022\/11\/couchbase-nosql-dbaas.png","type":"image\/png"}],"author":"Mark Nunberg, Software Engineer, Couchbase","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Mark Nunberg, Software Engineer, Couchbase","Est. reading time":"11\ubd84"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/introducing-libcouchbase-24-0\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/introducing-libcouchbase-24-0\/"},"author":{"name":"Mark Nunberg, Software Engineer, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/76a75284da32b6f257c8e5e156e6e016"},"headline":"Introducing libcouchbase 2.4","datePublished":"2014-12-16T19:35:27+00:00","dateModified":"2017-05-03T20:26:40+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/introducing-libcouchbase-24-0\/"},"wordCount":2254,"commentCount":3,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/introducing-libcouchbase-24-0\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","articleSection":["Uncategorized"],"inLanguage":"ko-KR","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/introducing-libcouchbase-24-0\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/introducing-libcouchbase-24-0\/","url":"https:\/\/www.couchbase.com\/blog\/introducing-libcouchbase-24-0\/","name":"Introducing libcouchbase 2.4 - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/introducing-libcouchbase-24-0\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/introducing-libcouchbase-24-0\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2014-12-16T19:35:27+00:00","dateModified":"2017-05-03T20:26:40+00:00","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/introducing-libcouchbase-24-0\/#breadcrumb"},"inLanguage":"ko-KR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/introducing-libcouchbase-24-0\/"]}]},{"@type":"ImageObject","inLanguage":"ko-KR","@id":"https:\/\/www.couchbase.com\/blog\/introducing-libcouchbase-24-0\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","width":1800,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/introducing-libcouchbase-24-0\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Introducing libcouchbase 2.4"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"\uce74\uc6b0\uce58\ubca0\uc774\uc2a4 \ube14\ub85c\uadf8","description":"NoSQL \ub370\uc774\ud130\ubca0\uc774\uc2a4, Couchbase","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"ko-KR"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"\uce74\uc6b0\uce58\ubca0\uc774\uc2a4 \ube14\ub85c\uadf8","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"ko-KR","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/76a75284da32b6f257c8e5e156e6e016","name":"\ub9c8\ud06c \ub10c\ubc84\uadf8, \uc18c\ud504\ud2b8\uc6e8\uc5b4 \uc5d4\uc9c0\ub2c8\uc5b4, \uce74\uc6b0\uce58\ubca0\uc774\uc2a4","image":{"@type":"ImageObject","inLanguage":"ko-KR","@id":"https:\/\/secure.gravatar.com\/avatar\/d5a465565eb8a3990192957806a9bc2989ba9f52a5f953d988b5e8afff3b6dc7?s=96&d=mm&r=g895cad0986a0ab674fda857b6ba71ce0","url":"https:\/\/secure.gravatar.com\/avatar\/d5a465565eb8a3990192957806a9bc2989ba9f52a5f953d988b5e8afff3b6dc7?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/d5a465565eb8a3990192957806a9bc2989ba9f52a5f953d988b5e8afff3b6dc7?s=96&d=mm&r=g","caption":"Mark Nunberg, Software Engineer, Couchbase"},"description":"\ub9c8\ud06c \ub10c\ubc84\uadf8\ub294 \uce74\uc6b0\uce58\ubca0\uc774\uc2a4\uc5d0\uc11c \uc77c\ud558\ub294 \uc18c\ud504\ud2b8\uc6e8\uc5b4 \uc5d4\uc9c0\ub2c8\uc5b4\uc785\ub2c8\ub2e4. \uadf8\ub294 C \ud074\ub77c\uc774\uc5b8\ud2b8 \ub77c\uc774\ube0c\ub7ec\ub9ac(libcouchbase)\uc640 Python \ud074\ub77c\uc774\uc5b8\ud2b8\ub97c \uc720\uc9c0 \uad00\ub9ac\ud569\ub2c8\ub2e4. \ub610\ud55c \uc774\uc804 \ud68c\uc0ac\uc5d0\uc11c \uc0ac\uc6a9\ud558\ub358 Perl \ud074\ub77c\uc774\uc5b8\ud2b8\ub3c4 \uac1c\ubc1c\ud588\ub294\ub370, \uc774\uac83\uc774 Couchbase\uc5d0\uc11c \uc77c\ud558\uac8c \ub41c \uacc4\uae30\uac00 \ub418\uc5c8\uc2b5\ub2c8\ub2e4. Couchbase\uc5d0 \uc785\uc0ac\ud558\uae30 \uc804\uc5d0\ub294 \uc804\uc790\uc0c1\uac70\ub798 \ubd84\uc11d \ud68c\uc0ac\uc5d0\uc11c \ubd84\uc0b0\ud615 \uace0\uc131\ub2a5 \ub77c\uc6b0\ud305 \uc2dc\uc2a4\ud15c\uc744 \uac1c\ubc1c\ud588\uc2b5\ub2c8\ub2e4. Mark\ub294 \uc608\ub8e8\uc0b4\ub818 \ud788\ube0c\ub9ac \ub300\ud559\uad50\uc5d0\uc11c \uc5b8\uc5b4\ud559\uc744 \uc804\uacf5\ud588\uc2b5\ub2c8\ub2e4.","url":"https:\/\/www.couchbase.com\/blog\/ko\/author\/mark-nunberg\/"}]}},"acf":[],"authors":[{"term_id":8997,"user_id":38,"is_guest":0,"slug":"mark-nunberg","display_name":"Mark Nunberg, Software Engineer, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/d5a465565eb8a3990192957806a9bc2989ba9f52a5f953d988b5e8afff3b6dc7?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/posts\/1655","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/users\/38"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/comments?post=1655"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/posts\/1655\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/media?parent=1655"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/categories?post=1655"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/tags?post=1655"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/ko\/wp-json\/wp\/v2\/ppma_author?post=1655"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}