{"id":1548,"date":"2014-12-18T14:22:56","date_gmt":"2014-12-18T14:22:56","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=1548"},"modified":"2017-05-03T13:44:29","modified_gmt":"2017-05-03T20:44:29","slug":"couchbase-java-sdk-internals","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/pt\/couchbase-java-sdk-internals\/","title":{"rendered":"Aspectos internos do Couchbase Java SDK"},"content":{"rendered":"<p><em style=\"line-height: 23px; font-family: ff-meta-serif-web-pro-1, ff-meta-serif-web-pro-2, Georgia, 'Times New Roman', Times, serif;\">[Este blog foi distribu\u00eddo pelo site https:\/\/nitschinger.at\/].<\/em><\/p>\n<h2>Motiva\u00e7\u00e3o<\/h2>\n<p><span style=\"line-height: 1;\">Esta postagem do blog tem como objetivo ser um artigo muito detalhado e informativo para aqueles que j\u00e1 usaram o Couchbase Java SDK e querem saber como funcionam os aspectos internos. N\u00e3o se trata de uma introdu\u00e7\u00e3o sobre como usar o Java SDK, e abordaremos alguns t\u00f3picos bastante avan\u00e7ados no caminho.<\/span><\/p>\n<div><span style=\"line-height: 1;\">Normalmente, quando falamos sobre o SDK, estamos nos referindo a tudo o que \u00e9 necess\u00e1rio para voc\u00ea come\u00e7ar (biblioteca do cliente, documenta\u00e7\u00e3o, notas de vers\u00e3o, etc.). No entanto, neste artigo, o SDK se refere \u00e0 biblioteca do cliente (c\u00f3digo), a menos que seja dito o contr\u00e1rio.<\/span><\/div>\n<div><\/div>\n<div>\n<h2>Introdu\u00e7\u00e3o<\/h2>\n<p><span style=\"line-height: 1;\">Antes de mais nada, \u00e9 importante entender que o SDK envolve e amplia a funcionalidade do <\/span><a style=\"line-height: 1;\" href=\"https:\/\/github.com\/couchbase\/spymemcached\">cache de spymem<\/a><span style=\"line-height: 1;\"> (chamado de \"spy\") memcached library. Um dos protocolos usados internamente \u00e9 o protocolo memcached, e muitas funcionalidades podem ser reutilizadas. Por outro lado, quando come\u00e7ar a remover as primeiras camadas do SDK, voc\u00ea perceber\u00e1 que alguns componentes s\u00e3o um pouco mais complexos devido ao fato de que o spy fornece mais recursos do que o SDK precisa em primeiro lugar. A outra parte \u00e9 lembrar que muitos dos componentes est\u00e3o interligados, portanto, voc\u00ea sempre precisa acertar a depend\u00eancia. Na maioria das vezes, lan\u00e7amos uma nova vers\u00e3o do spy na mesma data em que lan\u00e7amos um novo SDK, porque novas coisas foram adicionadas ou corrigidas.<\/span><\/p>\n<div><span style=\"line-height: 1;\">Portanto, al\u00e9m de reutilizar a funcionalidade fornecida pelo spy, o SDK adiciona principalmente dois blocos de funcionalidade: gerenciamento autom\u00e1tico de topologia de cluster e suporte para visualiza\u00e7\u00f5es desde o servidor 1.1 (e 2.0). Al\u00e9m disso, ele tamb\u00e9m fornece recursos administrativos, como gerenciamento de documentos de design e de balde.<\/span><\/div>\n<div><\/div>\n<div>Para entender como o cliente opera, vamos dissecar todo o processo em diferentes fases do ciclo de vida do cliente. Depois de passarmos por todas as tr\u00eas fases (inicializa\u00e7\u00e3o, opera\u00e7\u00e3o e desligamento), voc\u00ea dever\u00e1 ter uma vis\u00e3o clara do que est\u00e1 acontecendo nos bastidores. Observe que h\u00e1 uma postagem de blog separada em andamento sobre o tratamento de erros, portanto, n\u00e3o abordaremos isso aqui com mais detalhes (que ser\u00e1 publicado algumas semanas depois no mesmo blog aqui).<\/div>\n<p><span style=\"color: #007da4; font-family: inherit; font-size: 23px; font-weight: 600; line-height: 1.4;\">Fase 1: Bootstrap<\/span><\/p>\n<\/div>\n<p><span style=\"line-height: 1;\">Antes que possamos realmente come\u00e7ar a servir opera\u00e7\u00f5es como <\/span><em style=\"line-height: 1;\">get()<\/em><span style=\"line-height: 1;\"> e <\/span><em style=\"line-height: 1;\">set()<\/em><span style=\"line-height: 1;\">precisamos fazer o bootstrap do <\/span><em style=\"line-height: 1;\">Cliente Couchbase<\/em><span style=\"line-height: 1;\"> objeto. A parte importante que precisamos realizar aqui \u00e9 obter inicialmente uma configura\u00e7\u00e3o de cluster (que cont\u00e9m os n\u00f3s e o mapa do vBucket), mas tamb\u00e9m estabelecer uma conex\u00e3o de streaming para receber atualiza\u00e7\u00f5es de cluster em tempo (quase) real.<\/span><\/p>\n<div><span style=\"line-height: 1;\">Pegamos a lista de n\u00f3s que passam durante o bootstrap e iteramos sobre ela. O primeiro n\u00f3 da lista que pode ser contatado na porta 8091 \u00e9 usado para percorrer a interface RESTful no servidor. Se ele n\u00e3o estiver dispon\u00edvel, ser\u00e1 tentado o pr\u00f3ximo. Isso significa que, a partir do n\u00f3 fornecido <\/span><em style=\"line-height: 1;\">https:\/\/host:port\/pools<\/em><span style=\"line-height: 1;\"> URI, eventualmente seguimos os links para a entidade bucket. Tudo isso acontece dentro de um <\/span><em style=\"line-height: 1;\">Provedor de configura\u00e7\u00e3o<\/em><span style=\"line-height: 1;\">que, neste caso, \u00e9 o <\/span><em style=\"line-height: 1;\">com.couchbase.client.vbucket.ConfigurationProviderHTTP<\/em><span style=\"line-height: 1;\">. Se voc\u00ea quiser dar uma olhada nos componentes internos, procure por<\/span><em style=\"line-height: 1;\"> getBucketConfiguration<\/em><span style=\"line-height: 1;\"> e <\/span><em style=\"line-height: 1;\">readPools<\/em><span style=\"line-height: 1;\"> m\u00e9todos.<\/span><\/div>\n<div><\/div>\n<div>Uma caminhada (bem-sucedida) pode ser ilustrada da seguinte forma:<\/div>\n<div><\/div>\n<ol>\n<li>GET \/pools<\/li>\n<li><span style=\"font-family: inherit; font-size: 1em; line-height: 1.4375em;\">procure os pools \"padr\u00e3o\"<\/span><\/li>\n<li><span style=\"font-family: inherit; font-size: 1em; line-height: 1.4375em;\">GET \/pools\/default<\/span><\/li>\n<li><span style=\"font-family: inherit; font-size: 1em; line-height: 1.4375em;\">procure o hash \"buckets\" que cont\u00e9m a lista de buckets<\/span><\/li>\n<li><span style=\"font-family: inherit; font-size: 1em; line-height: 1.4375em;\">GET \/pools\/default\/buckets<\/span><\/li>\n<li><span style=\"font-family: inherit; font-size: 1em; line-height: 1.4375em;\">analisa a lista de buckets e extrai o fornecido pelo aplicativo<\/span><\/li>\n<li><span style=\"font-family: inherit; font-size: 1em; line-height: 1.4375em;\">GET \/pools\/default\/buckets\/<\/span><\/li>\n<\/ol>\n<p><span style=\"line-height: 1;\">Agora estamos no endpoint REST de que precisamos. Dentro dessa resposta JSON, voc\u00ea encontrar\u00e1 todos os detalhes \u00fateis que tamb\u00e9m podem ser usados internamente pelo SDK (por exemplo <\/span><em style=\"line-height: 1;\">streamingUri<\/em><span style=\"line-height: 1;\">, n\u00f3s e <\/span><em style=\"line-height: 1;\">vBucketServerMap<\/em><span style=\"line-height: 1;\">). A configura\u00e7\u00e3o \u00e9 analisada e armazenada. Antes de prosseguirmos, vamos discutir rapidamente a parte dos pools estranhos em nossa caminhada REST:<\/span><\/p>\n<div><span style=\"line-height: 1;\">O conceito de um pool de recursos para agrupar buckets foi projetado para o Couchbase Server, mas atualmente n\u00e3o est\u00e1 implementado. Ainda assim, a API REST foi implementada dessa forma e, portanto, todos os SDKs s\u00e3o compat\u00edveis com ela. Dito isso, embora, teoricamente, pud\u00e9ssemos ir diretamente para <\/span><em style=\"line-height: 1;\">\/pools\/default\/buckets<\/em><span style=\"line-height: 1;\"> e ignorar as primeiras consultas, o comportamento atual \u00e9 \u00e0 prova de futuro, portanto, voc\u00ea n\u00e3o precisar\u00e1 alterar o c\u00f3digo de inicializa\u00e7\u00e3o quando o servidor o implementar.<\/span><\/div>\n<div><\/div>\n<div>Voltamos \u00e0 nossa fase de bootstrap. Agora que temos uma configura\u00e7\u00e3o de cluster v\u00e1lida que cont\u00e9m todos os n\u00f3s (e seus nomes de host ou endere\u00e7os IP), podemos estabelecer conex\u00f5es com eles. Al\u00e9m de estabelecer as conex\u00f5es de dados, tamb\u00e9m precisamos instanciar uma conex\u00e3o de streaming com um deles. Por motivos de simplicidade, apenas estabelecemos a conex\u00e3o de streaming com o n\u00f3 da lista em que obtivemos nossa configura\u00e7\u00e3o inicial.<\/div>\n<div><\/div>\n<div>Isso nos leva a um ponto importante a ser lembrado: se voc\u00ea tiver muitos <em>Cliente Couchbase<\/em> se os objetos forem executados em v\u00e1rios n\u00f3s e todos eles forem inicializados com a mesma lista, eles poder\u00e3o acabar se conectando ao mesmo n\u00f3 para a conex\u00e3o de streaming e criar um poss\u00edvel gargalo. Portanto, para distribuir a carga um pouco melhor, recomendo embaralhar a matriz antes que ela seja passada para o <em>Cliente Couchbase<\/em> objeto. Quando voc\u00ea tem apenas alguns <em>Cliente Couchbase<\/em> conectados ao seu cluster, isso n\u00e3o ser\u00e1 um problema.<\/div>\n<div><\/div>\n<div>\n<div>O URI da conex\u00e3o de streaming \u00e9 retirado da configura\u00e7\u00e3o que obtivemos anteriormente e normalmente tem a seguinte apar\u00eancia:<\/div>\n<div><\/div>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family: monospace;\">streamingUri: \"\/pools\/default\/bucketsStreaming\/default?bucket_uuid=88cae4a609eea500d8ad072fe71a7290\"<\/div>\n<\/div>\n<div><\/div>\n<div>Se voc\u00ea apontar seu navegador para esse endere\u00e7o, tamb\u00e9m receber\u00e1 as atualiza\u00e7\u00f5es da topologia do cluster transmitidas em tempo real. Como a conex\u00e3o de streaming precisa ser estabelecida o tempo todo e pode bloquear um thread, isso \u00e9 feito em segundo plano e tratado por diferentes threads. Estamos usando a estrutura NIO Netty para essa tarefa, que oferece uma maneira muito pr\u00e1tica de lidar com opera\u00e7\u00f5es ass\u00edncronas. Se quiser come\u00e7ar a se aprofundar nessa parte, lembre-se de que todas as opera\u00e7\u00f5es de leitura s\u00e3o completamente separadas das opera\u00e7\u00f5es de grava\u00e7\u00e3o, portanto, voc\u00ea precisa lidar com manipuladores que cuidam do que retorna do servidor. Al\u00e9m de alguns cabos necess\u00e1rios para o Netty, a l\u00f3gica comercial pode ser encontrada em com.couchbase.client.vbucket.BucketMonitor e com.couchbase.client.vbucket.BucketUpdateResponseHandler. Tamb\u00e9m tentamos restabelecer essa conex\u00e3o de streaming se o soquete for fechado (por exemplo, se esse n\u00f3 for rebalanceado para fora do cluster).<\/div>\n<div><\/div>\n<div>Para realmente embaralhar os dados nos n\u00f3s do cluster, precisamos abrir v\u00e1rios soquetes para eles. Observe que n\u00e3o h\u00e1 absolutamente nenhum pooling de conex\u00e3o necess\u00e1rio dentro do cliente, pois gerenciamos todos os soquetes de forma proativa. Al\u00e9m da conex\u00e3o especial de streaming com um dos servidores (que \u00e9 aberta na porta 8091), precisamos abrir as seguintes conex\u00f5es:<\/div>\n<div><\/div>\n<ol>\n<li>Soquete do Memcached: Porta 11210<\/li>\n<li><span style=\"font-family: inherit; font-size: 1em; line-height: 1.4375em;\">Exibir soquete: Porta 8092<\/span><\/li>\n<\/ol>\n<\/div>\n<p><span style=\"font-family: inherit; font-size: 1em; line-height: 1;\">Observe que a porta 11211 n\u00e3o \u00e9 usada dentro dos SDKs do cliente, mas \u00e9 usada para conectar clientes gen\u00e9ricos do memcached que n\u00e3o est\u00e3o cientes do cluster. Isso significa que esses clientes gen\u00e9ricos n\u00e3o recebem topologias de cluster atualizadas.<\/span><\/p>\n<div><span style=\"line-height: 1;\">Portanto, como regra geral, se voc\u00ea tiver um cluster de 10 n\u00f3s em execu\u00e7\u00e3o, um objeto CouchbaseClient abrir\u00e1 cerca de 21 (2*10 + 1) soquetes de cliente. Eles s\u00e3o gerenciados diretamente, portanto, se um n\u00f3 for removido ou adicionado, os n\u00fameros ser\u00e3o alterados de acordo.<\/span><\/div>\n<div><\/div>\n<div>Agora que todos os soquetes foram abertos, estamos prontos para executar opera\u00e7\u00f5es regulares de cluster. Como voc\u00ea pode ver, h\u00e1 muita sobrecarga envolvida quando o objeto CouchbaseClient \u00e9 inicializado. Devido a esse fato, n\u00e3o recomendamos que voc\u00ea crie um novo objeto a cada solicita\u00e7\u00e3o ou execute muitos objetos CouchbaseClient em um servidor de aplicativos. Isso apenas adiciona sobrecarga e carga desnecess\u00e1rias ao servidor de aplicativos e aumenta o total de soquetes abertos no cluster (resultando em um poss\u00edvel problema de desempenho).<\/div>\n<div><\/div>\n<div>Como ponto de refer\u00eancia, com o registro regular de n\u00edvel INFO ativado, \u00e9 assim que deve ser a conex\u00e3o e a desconex\u00e3o de um cluster de 1 n\u00f3 (bucket do Couchbase):<\/div>\n<div><\/div>\n<div>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family: monospace;\">Apr 17, 2013 3:14:49 PM com.couchbase.client.CouchbaseProperties setPropertyFile<br \/>\nINFO: N\u00e3o foi poss\u00edvel carregar o arquivo de propriedades \"cbclient.properties\" porque: Arquivo n\u00e3o encontrado com o carregador de classes do sistema.<br \/>\n2013-04-17 15:14:49.656 INFO com.couchbase.client.CouchbaseConnection:  Adicionado {QA sa=\/127.0.0.1:11210, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} \u00e0 fila de conex\u00e3o<br \/>\n2013-04-17 15:14:49.673 INFO com.couchbase.client.CouchbaseConnection:  Estado da conex\u00e3o alterado para sun.nio.ch.SelectionKeyImpl@2adb1d4<br \/>\n2013-04-17 15:14:49.718 INFO com.couchbase.client.ViewConnection:  Adicionado localhost \u00e0 fila de conex\u00e3o<br \/>\n2013-04-17 15:14:49.720 INFO com.couchbase.client.CouchbaseClient: A propriedade viewmode n\u00e3o est\u00e1 definida. Definindo viewmode para o modo de produ\u00e7\u00e3o<br \/>\n2013-04-17 15:14:49.856 INFO com.couchbase.client.CouchbaseConnection:  Encerrar o cliente Couchbase<br \/>\n2013-04-17 15:14:49.861 INFO com.couchbase.client.ViewConnection:  O n\u00f3 localhost n\u00e3o tem opera\u00e7\u00f5es na fila<br \/>\n2013-04-17 15:14:49.861 INFO com.couchbase.client.ViewNode:  Reator de E\/S encerrado para localhost<\/div>\n<\/div>\n<div><\/div>\n<div>Se voc\u00ea estiver se conectando a um Couchbase Server 1.8 ou a um Memcache-Bucket, n\u00e3o ver\u00e1 conex\u00f5es View sendo estabelecidas:<\/div>\n<div><\/div>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family: monospace;\">INFO: N\u00e3o foi poss\u00edvel carregar o arquivo de propriedades \"cbclient.properties\" porque: Arquivo n\u00e3o encontrado com o carregador de classes do sistema.<br \/>\n2013-04-17 15:16:44.295 INFO com.couchbase.client.CouchbaseConnection:  Adicionado {QA sa=\/192.168.56.101:11210, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} \u00e0 fila de conex\u00e3o<br \/>\n2013-04-17 15:16:44.297 INFO com.couchbase.client.CouchbaseConnection:  Adicionado {QA sa=\/192.168.56.102:11210, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} \u00e0 fila de conex\u00e3o<br \/>\n2013-04-17 15:16:44.298 INFO com.couchbase.client.CouchbaseConnection:  Adicionado {QA sa=\/192.168.56.103:11210, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} \u00e0 fila de conex\u00e3o<br \/>\n2013-04-17 15:16:44.298 INFO com.couchbase.client.CouchbaseConnection:  Adicionado {QA sa=\/192.168.56.104:11210, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} \u00e0 fila de conex\u00e3o<br \/>\n2013-04-17 15:16:44.306 INFO com.couchbase.client.CouchbaseConnection:  Estado da conex\u00e3o alterado para sun.nio.ch.SelectionKeyImpl@38b5dac4<br \/>\n2013-04-17 15:16:44.313 INFO com.couchbase.client.CouchbaseClient: A propriedade viewmode n\u00e3o est\u00e1 definida. Definindo viewmode para o modo de produ\u00e7\u00e3o<br \/>\n2013-04-17 15:16:44.332 INFO com.couchbase.client.CouchbaseConnection:  Estado da conex\u00e3o alterado para sun.nio.ch.SelectionKeyImpl@69945ce<br \/>\n2013-04-17 15:16:44.333 INFO com.couchbase.client.CouchbaseConnection:  Estado da conex\u00e3o alterado para sun.nio.ch.SelectionKeyImpl@6766afb3<br \/>\n2013-04-17 15:16:44.334 INFO com.couchbase.client.CouchbaseConnection:  Estado da conex\u00e3o alterado para sun.nio.ch.SelectionKeyImpl@2b2d96f2<br \/>\n2013-04-17 15:16:44.368 INFO net.spy.memcached.auth.AuthThread:  Autenticado em 192.168.56.103\/192.168.56.103:11210<br \/>\n2013-04-17 15:16:44.368 INFO net.spy.memcached.auth.AuthThread:  Autenticado em 192.168.56.102\/192.168.56.102:11210<br \/>\n2013-04-17 15:16:44.369 INFO net.spy.memcached.auth.AuthThread:  Autenticado em 192.168.56.101\/192.168.56.101:11210<br \/>\n2013-04-17 15:16:44.369 INFO net.spy.memcached.auth.AuthThread:  Autenticado em 192.168.56.104\/192.168.56.104:11210<br \/>\n2013-04-17 15:16:44.490 INFO com.couchbase.client.CouchbaseConnection:  Encerrar o cliente Couchbase<\/div>\n<\/div>\n<\/div>\n<p><span style=\"color: #007da4; font-size: 23px; font-weight: 600; line-height: 1.4; font-family: inherit;\">Fase 2: Opera\u00e7\u00f5es<\/span><br \/>\n<span style=\"font-family: inherit; font-size: 1em; line-height: 1;\">Quando o SDK \u00e9 inicializado, ele permite que seu aplicativo execute opera\u00e7\u00f5es no cluster anexado. Para os fins desta postagem do blog, precisamos distinguir entre opera\u00e7\u00f5es que s\u00e3o executadas em um cluster est\u00e1vel e opera\u00e7\u00f5es em um cluster que est\u00e1 passando por alguma forma de altera\u00e7\u00e3o de topologia (seja ela planejada devido \u00e0 adi\u00e7\u00e3o de n\u00f3s ou n\u00e3o planejada devido a uma falha de n\u00f3). Vamos abordar primeiro as opera\u00e7\u00f5es regulares.<\/span><\/p>\n<h3>Opera\u00e7\u00f5es em um cluster est\u00e1vel<\/h3>\n<div>Embora n\u00e3o seja diretamente vis\u00edvel em primeiro lugar, dentro do SDK precisamos distinguir entre opera\u00e7\u00f5es de memcached e opera\u00e7\u00f5es de visualiza\u00e7\u00e3o. Todas as opera\u00e7\u00f5es que t\u00eam uma chave exclusiva em sua assinatura de m\u00e9todo podem ser tratadas como opera\u00e7\u00f5es de memcached. Todas elas acabam sendo canalizadas por meio do spy. As opera\u00e7\u00f5es de visualiza\u00e7\u00e3o, por outro lado, s\u00e3o implementadas completamente dentro do pr\u00f3prio SDK.<\/div>\n<div><\/div>\n<div>As opera\u00e7\u00f5es do View e do memcached s\u00e3o ass\u00edncronas. Dentro do spy, h\u00e1 um thread (chamado de thread de E\/S) dedicado a lidar com as opera\u00e7\u00f5es de E\/S. Observe que, em ambientes de alto tr\u00e1fego, n\u00e3o \u00e9 incomum que esse thread esteja sempre ativo. Ele usa os mecanismos de NIO do Java sem bloqueio para lidar com o tr\u00e1fego e faz loops em torno de \"seletores\" que s\u00e3o notificados quando os dados podem ser gravados ou lidos. Se voc\u00ea tra\u00e7ar o perfil do seu aplicativo, ver\u00e1 que esse thread passa a maior parte do tempo aguardando um m\u00e9todo select, o que significa que ele est\u00e1 ocioso, esperando ser notificado sobre um novo tr\u00e1fego. Os conceitos usados no spy para lidar com isso s\u00e3o de conhecimento comum do Java NIO, portanto, talvez voc\u00ea queira dar uma olhada na se\u00e7\u00e3o<a href=\"https:\/\/www.ibm.com\/developerworks\/java\/tutorials\/j-nio\/\"> Internos da NIO<\/a> antes de se aprofundar nesse caminho de c\u00f3digo. Bons pontos de partida s\u00e3o os <em>net.spy.memcached.MemcachedConnection<\/em> e <em>net.spy.memcached.protocol.TCPMemcachedNodeImpl<\/em> classes. Observe que, dentro do SDK, substitu\u00edmos o MemcachedConnection para conectar nossa pr\u00f3pria l\u00f3gica de reconfigura\u00e7\u00e3o. Essa classe pode ser encontrada dentro do SDK em <em>com.couchbase.client.CouchbaseConnection<\/em> e para buckets do tipo memcached em <em>com.couchbase.client.CouchbaseMemcachedConnection<\/em>.<\/div>\n<div><\/div>\n<div>Portanto, se uma opera\u00e7\u00e3o do memcached (como <em>get()<\/em>) \u00e9 emitido, ele \u00e9 passado para baixo at\u00e9 chegar ao thread de E\/S. O thread de IO o colocar\u00e1 em uma fila de grava\u00e7\u00e3o em dire\u00e7\u00e3o ao n\u00f3 de destino. Ele acaba sendo gravado e, em seguida, o thread de E\/S adiciona informa\u00e7\u00f5es a uma fila de leitura para que as respostas possam ser mapeadas adequadamente. Essa abordagem \u00e9 baseada em futuros, portanto, quando o resultado realmente chega, o futuro \u00e9 marcado como conclu\u00eddo, o resultado \u00e9 analisado e anexado como objeto.<\/div>\n<div><\/div>\n<div>\n<div>O SDK usa apenas o protocolo bin\u00e1rio do memcached, embora o spy tamb\u00e9m ofere\u00e7a suporte a ASCII. O formato bin\u00e1rio \u00e9 muito mais eficiente e algumas das opera\u00e7\u00f5es avan\u00e7adas s\u00e3o implementadas somente nele.<\/div>\n<div><\/div>\n<div>Voc\u00ea pode se perguntar como o SDK sabe para onde enviar a opera\u00e7\u00e3o? Como j\u00e1 temos o mapa do cluster atualizado, podemos fazer o hash da chave e, com base na lista de n\u00f3s e no vBucketMap, determinar qual n\u00f3 acessar. O vBucketMap n\u00e3o cont\u00e9m apenas as informa\u00e7\u00f5es do n\u00f3 mestre da matriz, mas tamb\u00e9m as informa\u00e7\u00f5es de zero a tr\u00eas n\u00f3s de r\u00e9plica. Veja este exemplo (resumido):<\/div>\n<div><\/div>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family: monospace;\">vBucketServerMap: {<br \/>\nhashAlgorithm: \"CRC\",<br \/>\nnumReplicas: 1,<br \/>\nserverList: [<br \/>\n&#8220;192.168.56.101:11210&#8221;,<br \/>\n&#8220;192.168.56.102:11210&#8221;<br \/>\n],<br \/>\nvBucketMap: [<br \/>\n[0,1],<br \/>\n[0,1],<br \/>\n[0,1],<br \/>\n[1,0],<br \/>\n[1,0],<br \/>\n[1,0]<br \/>\n\/\/&#8230;..<br \/>\n},<\/div>\n<\/div>\n<div><\/div>\n<div>O serverList cont\u00e9m nossos n\u00f3s, e o vBucketMap tem ponteiros para a matriz serverList. Temos 1024 vBuckets, portanto, apenas alguns deles s\u00e3o mostrados aqui. Voc\u00ea pode ver que todas as chaves que est\u00e3o no primeiro vBucket t\u00eam seu n\u00f3 mestre no \u00edndice 0 (ou seja, o n\u00f3 .101) e sua r\u00e9plica no \u00edndice 1 (ou seja, o n\u00f3 .102). Quando o mapa do cluster mudar e os vBuckets se movimentarem, s\u00f3 precisaremos atualizar nossa configura\u00e7\u00e3o e saberemos o tempo todo para onde direcionar nossas opera\u00e7\u00f5es.<\/div>\n<div><\/div>\n<div>As opera\u00e7\u00f5es de visualiza\u00e7\u00e3o s\u00e3o tratadas de forma diferente. Como as visualiza\u00e7\u00f5es n\u00e3o podem ser enviadas a um n\u00f3 espec\u00edfico (porque n\u00e3o temos uma maneira de fazer o hash de uma chave ou algo assim), fazemos um rod\u00edzio entre os n\u00f3s conectados. A opera\u00e7\u00e3o \u00e9 atribu\u00edda a um com.couchbase.client.ViewNode quando ele tem conex\u00f5es livres e, em seguida, \u00e9 executada. O resultado tamb\u00e9m \u00e9 tratado por meio de futuros. Para implementar essa funcionalidade, o SDK usa a biblioteca Apache HTTP Commons (NIO) de terceiros.<\/div>\n<\/div>\n<p><span style=\"font-family: inherit; font-size: 1em; line-height: 1;\">Toda a API View fica oculta na porta 8092 em cada n\u00f3 e \u00e9 muito semelhante a <\/span><a style=\"font-family: inherit; font-size: 1em; line-height: 1;\" href=\"https:\/\/couchdb.apache.org\/\">CouchDB<\/a><span style=\"font-family: inherit; font-size: 1em; line-height: 1;\">. Ele tamb\u00e9m cont\u00e9m uma API RESTful, mas a estrutura \u00e9 um pouco diferente. Por exemplo, voc\u00ea pode acessar um documento de design em <\/span><em style=\"font-family: inherit; font-size: 1em; line-height: 1;\">\/_design\/<\/em><span style=\"font-family: inherit; font-size: 1em; line-height: 1;\">. Ele cont\u00e9m as defini\u00e7\u00f5es de visualiza\u00e7\u00e3o em JSON:<\/span><\/p>\n<div><\/div>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family: monospace;\">{<br \/>\nlinguagem: \"javascript\",<br \/>\nvisualiza\u00e7\u00f5es: {<br \/>\ntodos: {<br \/>\nmap: \"function (doc) { if(doc.type == \"city\") {emit([doc.continent, doc.country, doc.name], 1)}}\",<br \/>\nreduzir: \"_sum\"<br \/>\n}<br \/>\n}<br \/>\n}<\/div>\n<\/div>\n<div><\/div>\n<div>Em seguida, voc\u00ea pode descer mais um n\u00edvel, como \/_design\/_view\/, para consult\u00e1-lo de fato:<\/div>\n<div><\/div>\n<div class=\"geshifilter\">\n<div class=\"csharp geshifilter-csharp\" style=\"font-family: monospace;\"><span style=\"color: #008000;\">{<\/span><span style=\"color: #666666;\">\"total_rows\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #ff0000;\">9<\/span>,<span style=\"color: #666666;\">\"rows\" (linhas)<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #008000;\">[<\/span><br \/>\n<span style=\"color: #008000;\">{<\/span><span style=\"color: #666666;\">\"id\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #666666;\">\"city:shanghai\"<\/span>,<span style=\"color: #666666;\">\"chave\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #008000;\">[<\/span><span style=\"color: #666666;\">\"asia\"<\/span>,<span style=\"color: #666666;\">\"china\"<\/span>,<span style=\"color: #666666;\">\"Xangai\"<\/span><span style=\"color: #008000;\">]<\/span>,<span style=\"color: #666666;\">\"valor\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #ff0000;\">1<\/span><span style=\"color: #008000;\">}<\/span>,<br \/>\n<span style=\"color: #008000;\">{<\/span><span style=\"color: #666666;\">\"id\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #666666;\">\"city:tokyo\"<\/span>,<span style=\"color: #666666;\">\"chave\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #008000;\">[<\/span><span style=\"color: #666666;\">\"asia\"<\/span>,<span style=\"color: #666666;\">\"jap\u00e3o\"<\/span>,<span style=\"color: #666666;\">\"tokyo\"<\/span><span style=\"color: #008000;\">]<\/span>,<span style=\"color: #666666;\">\"valor\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #ff0000;\">1<\/span><span style=\"color: #008000;\">}<\/span>,<br \/>\n<span style=\"color: #008000;\">{<\/span><span style=\"color: #666666;\">\"id\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #666666;\">\"city:moscow\"<\/span>,<span style=\"color: #666666;\">\"chave\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #008000;\">[<\/span><span style=\"color: #666666;\">\"asia\"<\/span>,<span style=\"color: #666666;\">\"R\u00fassia\"<\/span>,<span style=\"color: #666666;\">\"moscou\"<\/span><span style=\"color: #008000;\">]<\/span>,<span style=\"color: #666666;\">\"valor\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #ff0000;\">1<\/span><span style=\"color: #008000;\">}<\/span>,<br \/>\n<span style=\"color: #008000;\">{<\/span><span style=\"color: #666666;\">\"id\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #666666;\">\"city:vienna\"<\/span>,<span style=\"color: #666666;\">\"chave\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #008000;\">[<\/span><span style=\"color: #666666;\">\"europa\"<\/span>,<span style=\"color: #666666;\">\"austria\"<\/span>,<span style=\"color: #666666;\">\"viena\"<\/span><span style=\"color: #008000;\">]<\/span>,<span style=\"color: #666666;\">\"valor\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #ff0000;\">1<\/span><span style=\"color: #008000;\">}<\/span>,<br \/>\n<span style=\"color: #008000;\">{<\/span><span style=\"color: #666666;\">\"id\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #666666;\">\"city:paris\"<\/span>,<span style=\"color: #666666;\">\"chave\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #008000;\">[<\/span><span style=\"color: #666666;\">\"europa\"<\/span>,<span style=\"color: #666666;\">\"Fran\u00e7a\"<\/span>,<span style=\"color: #666666;\">\"paris\"<\/span><span style=\"color: #008000;\">]<\/span>,<span style=\"color: #666666;\">\"valor\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #ff0000;\">1<\/span><span style=\"color: #008000;\">}<\/span>,<br \/>\n<span style=\"color: #008000;\">{<\/span><span style=\"color: #666666;\">\"id\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #666666;\">\"city:rome\"<\/span>,<span style=\"color: #666666;\">\"chave\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #008000;\">[<\/span><span style=\"color: #666666;\">\"europa\"<\/span>,<span style=\"color: #666666;\">\"it\u00e1lia\"<\/span>,<span style=\"color: #666666;\">\"roma\"<\/span><span style=\"color: #008000;\">]<\/span>,<span style=\"color: #666666;\">\"valor\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #ff0000;\">1<\/span><span style=\"color: #008000;\">}<\/span>,<br \/>\n<span style=\"color: #008000;\">{<\/span><span style=\"color: #666666;\">\"id\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #666666;\">\"city:amsterdam\"<\/span>,<span style=\"color: #666666;\">\"chave\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #008000;\">[<\/span><span style=\"color: #666666;\">\"europa\"<\/span>,<span style=\"color: #666666;\">\"Pa\u00edses Baixos\"<\/span>,<span style=\"color: #666666;\">\"amsterdam\"<\/span><span style=\"color: #008000;\">]<\/span>,<span style=\"color: #666666;\">\"valor\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #ff0000;\">1<\/span><span style=\"color: #008000;\">}<\/span>,<br \/>\n<span style=\"color: #008000;\">{<\/span><span style=\"color: #666666;\">\"id\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #666666;\">\"city:new_york\"<\/span>,<span style=\"color: #666666;\">\"chave\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #008000;\">[<\/span><span style=\"color: #666666;\">\"north_america\"<\/span>,<span style=\"color: #666666;\">\"EUA\"<\/span>,<span style=\"color: #666666;\">\"new_york\"<\/span><span style=\"color: #008000;\">]<\/span>,<span style=\"color: #666666;\">\"valor\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #ff0000;\">1<\/span><span style=\"color: #008000;\">}<\/span>,<br \/>\n<span style=\"color: #008000;\">{<\/span><span style=\"color: #666666;\">\"id\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #666666;\">\"city:san_francisco\"<\/span>,<span style=\"color: #666666;\">\"chave\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #008000;\">[<\/span><span style=\"color: #666666;\">\"north_america\"<\/span>,<span style=\"color: #666666;\">\"EUA\"<\/span>,<span style=\"color: #666666;\">\"san_francisco\"<\/span><span style=\"color: #008000;\">]<\/span>,<span style=\"color: #666666;\">\"valor\"<\/span><span style=\"color: #008000;\">:<\/span><span style=\"color: #ff0000;\">1<\/span><span style=\"color: #008000;\">}<\/span><br \/>\n<span style=\"color: #008000;\">]<\/span><br \/>\n<span style=\"color: #008000;\">}<\/span><\/div>\n<\/div>\n<div><\/div>\n<div>Depois que a solicita\u00e7\u00e3o \u00e9 enviada e uma resposta \u00e9 recebida, depende do tipo de solicita\u00e7\u00e3o de visualiza\u00e7\u00e3o para determinar como a resposta ser\u00e1 analisada. Isso faz diferen\u00e7a, pois as consultas de visualiza\u00e7\u00e3o reduzidas s\u00e3o diferentes das n\u00e3o reduzidas. O SDK tamb\u00e9m inclui suporte para visualiza\u00e7\u00f5es espaciais e elas tamb\u00e9m precisam ser tratadas de forma diferente.<\/div>\n<div><\/div>\n<div>Toda a implementa\u00e7\u00e3o da an\u00e1lise da resposta do View pode ser encontrada dentro do <em>com.couchbase.client.protocol.views<\/em> namespace. L\u00e1 voc\u00ea encontrar\u00e1 classes abstratas e interfaces como ViewResponse e, em seguida, suas implementa\u00e7\u00f5es especiais como ViewResponseNoDocs, ViewResponseWithDocs ou ViewResponseReduced. Tamb\u00e9m faz diferen\u00e7a se setIncludeDocs() for usado no objeto Query, porque o SDK tamb\u00e9m precisa carregar os documentos completos usando o protocolo memcached nos bastidores. Isso tamb\u00e9m \u00e9 feito durante a an\u00e1lise das visualiza\u00e7\u00f5es.<\/div>\n<div><\/div>\n<div>Agora que voc\u00ea tem uma compreens\u00e3o b\u00e1sica de como o SDK distribui suas opera\u00e7\u00f5es em condi\u00e7\u00f5es est\u00e1veis, precisamos abordar um t\u00f3pico importante: como o SDK lida com as altera\u00e7\u00f5es na topologia do cluster.<\/div>\n<div><\/div>\n<div>\n<div>\n<h3>Opera\u00e7\u00f5es em um cluster de rebalanceamento<\/h3>\n<\/div>\n<div>Observe que h\u00e1 uma postagem separada no blog que trata de todos os cen\u00e1rios que podem surgir quando algo d\u00e1 errado no SDK. Como o rebalanceamento e o failover s\u00e3o partes essenciais do SDK, esta postagem trata mais do processo geral de como isso \u00e9 feito.<\/div>\n<div><\/div>\n<div>Conforme mencionado anteriormente, o SDK recebe atualiza\u00e7\u00f5es de topologia por meio da conex\u00e3o de streaming. Deixando de lado o caso especial em que esse n\u00f3 \u00e9 realmente removido ou falha, todas as atualiza\u00e7\u00f5es ser\u00e3o transmitidas quase em tempo real (em uma arquitetura eventualmente consistente, pode levar algum tempo at\u00e9 que as atualiza\u00e7\u00f5es do cluster sejam preenchidas para esse n\u00f3). Os blocos que chegam pelo fluxo s\u00e3o exatamente iguais aos que vimos ao ler a configura\u00e7\u00e3o inicial. Depois que esses blocos foram analisados, precisamos verificar se as altera\u00e7\u00f5es realmente afetam o SDK (como h\u00e1 muito mais par\u00e2metros do que o SDK precisa, n\u00e3o faz sentido ouvir todos eles). Todas as altera\u00e7\u00f5es que afetam a topologia e\/ou o mapa do vBucket s\u00e3o consideradas importantes. Se os n\u00f3s forem adicionados ou removidos (seja por falha ou planejados), precisaremos abrir ou fechar os soquetes. Esse processo \u00e9 chamado de \"reconfigura\u00e7\u00e3o\".<\/div>\n<div><\/div>\n<div>Quando essa reconfigura\u00e7\u00e3o \u00e9 acionada, muitas a\u00e7\u00f5es precisam acontecer em v\u00e1rios lugares. O Spymemcached precisa lidar com seus soquetes, os View nodes precisam ser gerenciados e a nova configura\u00e7\u00e3o precisa ser atualizada. O SDK garante que apenas uma reconfigura\u00e7\u00e3o possa ocorrer ao mesmo tempo por meio de bloqueios, para que n\u00e3o haja condi\u00e7\u00f5es de corrida.<\/div>\n<div><\/div>\n<div>O BucketUpdateResponseHandler baseado em Netty aciona o m\u00e9todo CouchbaseClient#reconfigure, que ent\u00e3o come\u00e7a a despachar tudo. Dependendo do tipo de bucket usado (ou seja, os buckets do tipo memcached n\u00e3o t\u00eam visualiza\u00e7\u00f5es e, portanto, n\u00e3o t\u00eam ViewNodes), as configura\u00e7\u00f5es s\u00e3o atualizadas e os soquetes s\u00e3o fechados. Depois que a reconfigura\u00e7\u00e3o \u00e9 feita, ele pode receber novas configura\u00e7\u00f5es. Durante as altera\u00e7\u00f5es planejadas, tudo deve ser praticamente controlado e nenhuma opera\u00e7\u00e3o deve falhar. Se um n\u00f3 estiver realmente inoperante e n\u00e3o puder ser acessado, essas opera\u00e7\u00f5es ser\u00e3o canceladas. A reconfigura\u00e7\u00e3o \u00e9 complicada porque a topologia muda enquanto as opera\u00e7\u00f5es est\u00e3o fluindo pelo sistema.<\/div>\n<div><\/div>\n<div>Por fim, vamos abordar algumas diferen\u00e7as entre os buckets do tipo Couchbase e Memcache. Todas as informa\u00e7\u00f5es que voc\u00ea leu anteriormente se aplicam apenas aos buckets do Couchbase. Os buckets do Memcache s\u00e3o bastante b\u00e1sicos e n\u00e3o t\u00eam o conceito de vBuckets. Como voc\u00ea n\u00e3o tem vBuckets, tudo o que o cliente precisa fazer \u00e9 gerenciar os n\u00f3s e seus soquetes correspondentes. Al\u00e9m disso, um algoritmo de hash diferente \u00e9 usado (principalmente o Ketama) para determinar o n\u00f3 de destino para cada chave. Al\u00e9m disso, os buckets do memcache n\u00e3o t\u00eam exibi\u00e7\u00f5es, portanto, n\u00e3o \u00e9 poss\u00edvel usar a API de exibi\u00e7\u00e3o e n\u00e3o faz muito sentido manter os soquetes de exibi\u00e7\u00e3o. Portanto, para esclarecer a afirma\u00e7\u00e3o anterior, se voc\u00ea estiver executando em um bucket de memcache, em um cluster de 10 n\u00f3s, voc\u00ea ter\u00e1 apenas 11 conex\u00f5es abertas.<\/div>\n<div><\/div>\n<div>\n<h2>Fase 3: Desligamento<\/h2>\n<div>Quando o m\u00e9todo CouchbaseClient#shutdown() \u00e9 chamado, n\u00e3o \u00e9 permitido adicionar mais opera\u00e7\u00f5es ao CouchbaseConnection. At\u00e9 que o tempo limite seja atingido, o cliente quer ter certeza de que todas as opera\u00e7\u00f5es foram realizadas adequadamente. Todos os soquetes das conex\u00f5es do memcached e do View s\u00e3o fechados quando n\u00e3o h\u00e1 mais opera\u00e7\u00f5es na fila (ou s\u00e3o descartados). Observe que os m\u00e9todos de desligamento nesses soquetes tamb\u00e9m s\u00e3o usados quando um n\u00f3 \u00e9 removido do cluster durante as opera\u00e7\u00f5es normais, portanto, \u00e9 basicamente a mesma coisa, mas apenas para todos os n\u00f3s conectados ao mesmo tempo.<\/div>\n<div><\/div>\n<h2>Resumo<\/h2>\n<div>Depois de ler esta publica\u00e7\u00e3o do blog, voc\u00ea deve ter uma ideia muito mais clara de como o SDK do cliente funciona e por que ele foi projetado dessa forma. Temos muitos aprimoramentos planejados para vers\u00f5es futuras, principalmente para melhorar a experi\u00eancia direta com a API. Observe que esta postagem do blog n\u00e3o abordou como os erros s\u00e3o tratados dentro do SDK; isso ser\u00e1 publicado em uma postagem separada do blog porque tamb\u00e9m h\u00e1 muitas informa\u00e7\u00f5es a serem abordadas.<\/div>\n<\/div>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>[This blog was syndicated from https:\/\/nitschinger.at\/] Motivation This blog post is intended to be a very detailed and informative article for those who already have used the Couchbase Java SDK and want to know how the internals work. This is [&hellip;]<\/p>","protected":false},"author":19,"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":[8987],"class_list":["post-1548","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.2 (Yoast SEO v26.2) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Couchbase Java SDK Internals - 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\/pt\/couchbase-java-sdk-internals\/\" \/>\n<meta property=\"og:locale\" content=\"pt_BR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Couchbase Java SDK Internals\" \/>\n<meta property=\"og:description\" content=\"[This blog was syndicated from https:\/\/nitschinger.at\/] Motivation This blog post is intended to be a very detailed and informative article for those who already have used the Couchbase Java SDK and want to know how the internals work. This is [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/pt\/couchbase-java-sdk-internals\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2014-12-18T14:22:56+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2017-05-03T20:44:29+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=\"Michael Nitschinger\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@daschl\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Michael Nitschinger\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"16 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/\"},\"author\":{\"name\":\"Michael Nitschinger\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/e5d4d332756da6f361dd88c1576de61d\"},\"headline\":\"Couchbase Java SDK Internals\",\"datePublished\":\"2014-12-18T14:22:56+00:00\",\"dateModified\":\"2017-05-03T20:44:29+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/\"},\"wordCount\":3329,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"articleSection\":[\"Uncategorized\"],\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/\",\"name\":\"Couchbase Java SDK Internals - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2014-12-18T14:22:56+00:00\",\"dateModified\":\"2017-05-03T20:44:29+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/#breadcrumb\"},\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/#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\/couchbase-java-sdk-internals\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Couchbase Java SDK Internals\"}]},{\"@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\":\"pt-BR\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@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\/e5d4d332756da6f361dd88c1576de61d\",\"name\":\"Michael Nitschinger\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/95e178617974d46e3b02dd1754a3f60b\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/dad99b5e02a74ca4bec14352e9da710160647a97290814b669babb3aac0ea675?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/dad99b5e02a74ca4bec14352e9da710160647a97290814b669babb3aac0ea675?s=96&d=mm&r=g\",\"caption\":\"Michael Nitschinger\"},\"description\":\"Michael Nitschinger works as a Principal Software Engineer at Couchbase. He is the architect and maintainer of the Couchbase Java SDK, one of the first completely reactive database drivers on the JVM. He also authored and maintains the Couchbase Spark Connector. Michael is active in the open source community, a contributor to various other projects like RxJava and Netty.\",\"sameAs\":[\"https:\/\/nitschinger.at\",\"https:\/\/x.com\/daschl\"],\"url\":\"https:\/\/www.couchbase.com\/blog\/pt\/author\/michael-nitschinger\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Couchbase Java SDK Internals - 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\/pt\/couchbase-java-sdk-internals\/","og_locale":"pt_BR","og_type":"article","og_title":"Couchbase Java SDK Internals","og_description":"[This blog was syndicated from https:\/\/nitschinger.at\/] Motivation This blog post is intended to be a very detailed and informative article for those who already have used the Couchbase Java SDK and want to know how the internals work. This is [&hellip;]","og_url":"https:\/\/www.couchbase.com\/blog\/pt\/couchbase-java-sdk-internals\/","og_site_name":"The Couchbase Blog","article_published_time":"2014-12-18T14:22:56+00:00","article_modified_time":"2017-05-03T20:44:29+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":"Michael Nitschinger","twitter_card":"summary_large_image","twitter_creator":"@daschl","twitter_misc":{"Written by":"Michael Nitschinger","Est. reading time":"16 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/"},"author":{"name":"Michael Nitschinger","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/e5d4d332756da6f361dd88c1576de61d"},"headline":"Couchbase Java SDK Internals","datePublished":"2014-12-18T14:22:56+00:00","dateModified":"2017-05-03T20:44:29+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/"},"wordCount":3329,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","articleSection":["Uncategorized"],"inLanguage":"pt-BR","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/","url":"https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/","name":"Couchbase Java SDK Internals - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2014-12-18T14:22:56+00:00","dateModified":"2017-05-03T20:44:29+00:00","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/#breadcrumb"},"inLanguage":"pt-BR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/"]}]},{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/www.couchbase.com\/blog\/couchbase-java-sdk-internals\/#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\/couchbase-java-sdk-internals\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Couchbase Java SDK Internals"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"Blog do Couchbase","description":"Couchbase, o banco de dados NoSQL","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":"pt-BR"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"Blog do Couchbase","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"pt-BR","@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\/e5d4d332756da6f361dd88c1576de61d","name":"Michael Nitschinger","image":{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/95e178617974d46e3b02dd1754a3f60b","url":"https:\/\/secure.gravatar.com\/avatar\/dad99b5e02a74ca4bec14352e9da710160647a97290814b669babb3aac0ea675?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/dad99b5e02a74ca4bec14352e9da710160647a97290814b669babb3aac0ea675?s=96&d=mm&r=g","caption":"Michael Nitschinger"},"description":"Michael Nitschinger trabalha como engenheiro de software principal na Couchbase. Ele \u00e9 o arquiteto e mantenedor do Couchbase Java SDK, um dos primeiros drivers de banco de dados totalmente reativos na JVM. Ele tamb\u00e9m \u00e9 o autor e mantenedor do Couchbase Spark Connector. Michael participa ativamente da comunidade de c\u00f3digo aberto e contribui para v\u00e1rios outros projetos, como RxJava e Netty.","sameAs":["https:\/\/nitschinger.at","https:\/\/x.com\/daschl"],"url":"https:\/\/www.couchbase.com\/blog\/pt\/author\/michael-nitschinger\/"}]}},"authors":[{"term_id":8987,"user_id":19,"is_guest":0,"slug":"michael-nitschinger","display_name":"Michael Nitschinger","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/dad99b5e02a74ca4bec14352e9da710160647a97290814b669babb3aac0ea675?s=96&d=mm&r=g","author_category":"","last_name":"Nitschinger, Principal Software Engineer, Couchbase","first_name":"Michael","job_title":"","user_url":"https:\/\/nitschinger.at","description":"Michael Nitschinger trabalha como engenheiro de software principal na Couchbase. Ele \u00e9 o arquiteto e mantenedor do Couchbase Java SDK, um dos primeiros drivers de banco de dados totalmente reativos na JVM. Ele tamb\u00e9m \u00e9 o autor e mantenedor do Couchbase Spark Connector. Michael participa ativamente da comunidade de c\u00f3digo aberto e contribui para v\u00e1rios outros projetos, como RxJava e Netty."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/1548","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/users\/19"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/comments?post=1548"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/1548\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/media?parent=1548"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/categories?post=1548"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/tags?post=1548"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/ppma_author?post=1548"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}