{"id":5378,"date":"2018-06-21T03:29:16","date_gmt":"2018-06-21T10:29:16","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=5378"},"modified":"2023-06-13T02:09:24","modified_gmt":"2023-06-13T09:09:24","slug":"inside-the-java-sdk-bootstrap","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/pt\/inside-the-java-sdk-bootstrap\/","title":{"rendered":"Por dentro do Java SDK: Bootstrap"},"content":{"rendered":"<p>De tempos em tempos, recebemos perguntas sobre t\u00f3picos que n\u00e3o se encaixam diretamente na documenta\u00e7\u00e3o, pois se aprofundam nos aspectos internos das bibliotecas de clientes. Nesta s\u00e9rie, abordaremos diferentes temas de interesse - neste caso, como o SDK se inicializa sozinho.<\/p>\n<p>Observe que esta postagem foi escrita tendo em mente as vers\u00f5es 2.5.9 \/ 2.6.0 do Java SDK. As coisas podem mudar com o tempo, mas a abordagem geral deve permanecer praticamente a mesma.<\/p>\n<h2>Primeiros passos<\/h2>\n<p>Para saber quais hosts remotos devem solicitar uma configura\u00e7\u00e3o em geral, contamos com a lista de nomes de host que o usu\u00e1rio fornece por meio do comando <span class=\"lang:default decode:true crayon-inline\">CouchbaseCluster<\/span>\u00a0 API. Assim, por exemplo, se este c\u00f3digo for fornecido:<\/p>\n<pre class=\"lang:java decode:true\">CouchbaseCluster cluster = CouchbaseCluster.create(\"node1\", \"node2\", \"node3\");<\/pre>\n<p>Em seguida, usaremos <span class=\"lang:default decode:true crayon-inline\">n\u00f31<\/span>\u00a0, <span class=\"lang:default decode:true crayon-inline\">n\u00f32<\/span>\u00a0 e <span class=\"lang:default decode:true crayon-inline\">n\u00f33<\/span>\u00a0 como parte do processo inicial de bootstrap. \u00c9 importante entender, neste ponto, que nenhuma conex\u00e3o real foi estabelecida ainda. O c\u00f3digo apenas armazena esses tr\u00eas hosts na tabela <a href=\"https:\/\/github.com\/couchbase\/couchbase-jvm-core\/blob\/1.5.9\/src\/main\/java\/com\/couchbase\/client\/core\/config\/ConfigurationProvider.java#L48\">Provedor de configura\u00e7\u00e3o<\/a>\u00a0como hosts semente. No entanto, eles n\u00e3o s\u00e3o armazenados como cadeias de caracteres, mas sim como um <a href=\"https:\/\/github.com\/couchbase\/couchbase-jvm-core\/blob\/1.5.9\/src\/main\/java\/com\/couchbase\/client\/core\/utils\/NetworkAddress.java\">Endere\u00e7o de rede<\/a>\u00a0cada um dos quais fornece um inv\u00f3lucro conveniente e mais rico em recursos sobre o JDK simples <span class=\"lang:default decode:true crayon-inline\">InetAddress<\/span>\u00a0. Por exemplo, ele pode ser modificado por meio das propriedades do sistema para n\u00e3o permitir pesquisas de DNS reverso ou for\u00e7ar IPv4 sobre IPv6, mesmo que o JDK esteja configurado de forma diferente.<\/p>\n<p>Se nenhum host for fornecido, <span class=\"lang:default decode:true crayon-inline\">127.0.0.1<\/span>\u00a0 ser\u00e1 definido como um host semente.<\/p>\n<p>Para os leitores que tamb\u00e9m est\u00e3o usando um SDK que depende do <a href=\"https:\/\/github.com\/couchbaselabs\/sdk-rfcs\/blob\/master\/rfc\/0011-connection-string.md\">string de conex\u00e3o<\/a> para configura\u00e7\u00e3o: o Java SDK analisar\u00e1 essa string quando fornecida, mas n\u00e3o usar\u00e1 nenhuma das defini\u00e7\u00f5es de configura\u00e7\u00e3o al\u00e9m da lista de n\u00f3s de inicializa\u00e7\u00e3o. Toda configura\u00e7\u00e3o deve ser aplicada por meio da fun\u00e7\u00e3o <span class=\"lang:default decode:true crayon-inline\">CouchbaseEnvironment<\/span>\u00a0 e seu construtor ou por meio das propriedades do sistema, quando dispon\u00edveis.<\/p>\n<p>H\u00e1 um \u00faltimo aspecto que precisamos abordar antes de abrirmos um balde e come\u00e7armos a trabalhar com as ervas daninhas. Se o <span class=\"lang:default decode:true crayon-inline\">CouchbaseEnvironment<\/span>\u00a0 est\u00e1 configurado com <span class=\"lang:default decode:true crayon-inline\">dnsSrvEnabled<\/span>\u00a0Durante a fase de constru\u00e7\u00e3o do cluster, o c\u00f3digo executar\u00e1 uma pesquisa no DNS SRV para recuperar os hosts reais em vez do host de refer\u00eancia do DNS SRV. O c\u00f3digo utiliza classes JVM para fazer isso; o c\u00f3digo pode ser encontrado em <a href=\"https:\/\/github.com\/couchbase\/couchbase-java-client\/blob\/2.5.9\/src\/main\/java\/com\/couchbase\/client\/java\/util\/Bootstrap.java#L88\">aqui<\/a>.<\/p>\n<h2>Obtendo uma configura\u00e7\u00e3o<\/h2>\n<p>Agora que temos uma lista de n\u00f3s-semente com os quais trabalhar, assim que um balde \u00e9 aberto, o verdadeiro trabalho come\u00e7a. Vamos considerar o seguinte trecho de c\u00f3digo como ponto de partida:<\/p>\n<pre class=\"lang:java decode:true\">Bucket bucket = cluster.openBucket(\"travel-sample\");<\/pre>\n<p>O ato de abrir um bucket tem muitas etapas pequenas que precisam ser conclu\u00eddas, mas a primeira e mais importante etapa \u00e9 buscar uma configura\u00e7\u00e3o inicial boa de um dos n\u00f3s do cluster.<\/p>\n<p>O <a href=\"https:\/\/github.com\/couchbase\/couchbase-jvm-core\/blob\/1.5.9\/src\/main\/java\/com\/couchbase\/client\/core\/config\/ConfigurationProvider.java\">Provedor de configura\u00e7\u00e3o<\/a> constr\u00f3i uma cadeia de carregadores de configura\u00e7\u00e3o, em que cada carregador tem um mecanismo diferente para tentar obter uma configura\u00e7\u00e3o. Atualmente, h\u00e1 dois carregadores diferentes em funcionamento:<\/p>\n<p>&#8211; <a href=\"https:\/\/github.com\/couchbase\/couchbase-jvm-core\/blob\/1.5.9\/src\/main\/java\/com\/couchbase\/client\/core\/config\/loader\/CarrierLoader.java\">Carregador de transportadora<\/a>KV: tenta obter a configura\u00e7\u00e3o por meio do protocolo bin\u00e1rio memcache do servi\u00e7o KV (porta <span class=\"lang:default decode:true crayon-inline\">11210<\/span>\u00a0 por padr\u00e3o).<br \/>\n&#8211; <a href=\"https:\/\/github.com\/couchbase\/couchbase-jvm-core\/blob\/1.5.9\/src\/main\/java\/com\/couchbase\/client\/core\/config\/loader\/HttpLoader.java\">Carregador http<\/a>Tenta obter a configura\u00e7\u00e3o do gerenciador de cluster (porta <span class=\"lang:default decode:true crayon-inline\">8091<\/span>\u00a0 por padr\u00e3o).<\/p>\n<p>O <span class=\"lang:default decode:true crayon-inline\">Carregador de transportadora<\/span>\u00a0 tem preced\u00eancia, pois \u00e9 a op\u00e7\u00e3o mais escal\u00e1vel (o servi\u00e7o KV \u00e9 capaz de lidar com solicita\u00e7\u00f5es muito mais altas por segundo do que o gerenciador de cluster) e, se n\u00e3o estiver dispon\u00edvel, o SDK voltar\u00e1 para o <span class=\"lang:default decode:true crayon-inline\">Carregador http<\/span>\u00a0. Um dos motivos pelos quais ele pode falhar \u00e9 que determinadas vers\u00f5es (mais antigas) do Couchbase Server n\u00e3o oferecem suporte a esse mecanismo. Outras falhas em geral incluem a porta <span class=\"lang:default decode:true crayon-inline\">11210<\/span>\u00a0 sendo bloqueados por firewalls (o que, de qualquer forma, leva a outros problemas no futuro...) ou soquetes com tempo limite.<\/p>\n<p>O <span class=\"lang:default decode:true crayon-inline\">Carregador http<\/span>\u00a0 tamb\u00e9m tem dois pontos de extremidade HTTP para buscar (dependendo da vers\u00e3o do Couchbase Server novamente para compatibilidade com vers\u00f5es anteriores), um que fornece uma configura\u00e7\u00e3o mais concisa e outro que fornece uma configura\u00e7\u00e3o detalhada. A configura\u00e7\u00e3o detalhada \u00e9 a que existe desde a \u00e9poca do Couchbase Server 1.8\/2.0 e tem garantia de funcionamento, mas os recursos mais recentes provavelmente n\u00e3o est\u00e3o expostos nela.<\/p>\n<p>Voc\u00ea entendeu o tema aqui: as abordagens mais novas\/mais escalon\u00e1veis s\u00e3o tentadas primeiro com op\u00e7\u00f5es de fallback para clientes mais antigos e configura\u00e7\u00f5es personalizadas. Em geral, o gerenciador de cluster \u00e9 sempre respons\u00e1vel por gerenciar e fornecer a configura\u00e7\u00e3o atualizada, mas ela tamb\u00e9m \u00e9 enviada ao servi\u00e7o KV para que os SDKs possam recuper\u00e1-la com um comando especial.<\/p>\n<p>Como um caso especial para servidores mais antigos, se a configura\u00e7\u00e3o foi carregada por meio do <span class=\"lang:default decode:true crayon-inline\">Carregador http<\/span>\u00a0Se o SDK estiver conectado a um dos endpoints HTTP, o SDK anexar\u00e1 uma conex\u00e3o de streaming para receber atualiza\u00e7\u00f5es de configura\u00e7\u00e3o. Se a conex\u00e3o <span class=\"lang:default decode:true crayon-inline\">Carregador de transportadora<\/span>\u00a0 for bem-sucedido, continuaremos a sondar com um intervalo de sondagem configur\u00e1vel para uma configura\u00e7\u00e3o por meio do protocolo bin\u00e1rio, pois \u00e9 mais eficiente em termos de recursos no lado do servidor (o servi\u00e7o KV \u00e9 muito mais adequado para lidar com muitas solicita\u00e7\u00f5es em potencial do que o gerenciador de cluster, raz\u00e3o pela qual o carregamento de portadora foi implementado em primeiro lugar).<\/p>\n<p>Abordaremos os diferentes casos de erro mais adiante. Por enquanto, suponhamos que conseguimos obter uma configura\u00e7\u00e3o v\u00e1lida de um dos carregadores. Nesse ponto, ela \u00e9 enviada de volta para o provedor de configura\u00e7\u00e3o, que \u00e9 verificado e enviado para o <a href=\"https:\/\/github.com\/couchbase\/couchbase-jvm-core\/blob\/1.5.9\/src\/main\/java\/com\/couchbase\/client\/core\/RequestHandler.java\">Solicitador<\/a>.<\/p>\n<p>\u00c9 poss\u00edvel que o provedor de configura\u00e7\u00e3o n\u00e3o esteja encaminhando a configura\u00e7\u00e3o, sendo que o principal motivo \u00e9 que ela est\u00e1 desatualizada ou n\u00e3o \u00e9 nova o suficiente. Toda configura\u00e7\u00e3o tem uma revis\u00e3o que a acompanha e o SDK rastreia internamente esse n\u00famero de revis\u00e3o para propagar apenas as configura\u00e7\u00f5es mais recentes do que as j\u00e1 processadas. Durante uma opera\u00e7\u00e3o de rebalanceamento, isso pode acontecer com bastante frequ\u00eancia e, se voc\u00ea tiver o registro de depura\u00e7\u00e3o ativado, poder\u00e1 detectar isso procurando uma linha de registro com a mensagem: <span class=\"lang:default decode:true crayon-inline\">Not applying new configuration, older or same rev ID<\/span>\u00a0.<\/p>\n<p>Assim que o <span class=\"lang:default decode:true crayon-inline\">Solicitador<\/span>\u00a0 recebe uma nova configura\u00e7\u00e3o e inicia um <a href=\"https:\/\/github.com\/couchbase\/couchbase-jvm-core\/blob\/1.5.9\/src\/main\/java\/com\/couchbase\/client\/core\/RequestHandler.java#L434\">reconfigura\u00e7\u00e3o<\/a>. A reconfigura\u00e7\u00e3o tem apenas uma fun\u00e7\u00e3o: pegar a configura\u00e7\u00e3o fornecida pelo servidor e alterar o estado interno do SDK para espelh\u00e1-la. Isso pode significar adicionar ou remover refer\u00eancias de n\u00f3s, pontos de extremidade de servi\u00e7os ou soquetes. O SDK espelha a linguagem comum do servidor, portanto, gerencia <a href=\"https:\/\/github.com\/couchbase\/couchbase-jvm-core\/blob\/1.5.9\/src\/main\/java\/com\/couchbase\/client\/core\/node\/Node.java\">N\u00f3s<\/a>\u00a0que fornecem <a href=\"https:\/\/github.com\/couchbase\/couchbase-jvm-core\/blob\/1.5.9\/src\/main\/java\/com\/couchbase\/client\/core\/service\/Service.java\">Servi\u00e7os<\/a> que pode ter um ou mais <a href=\"https:\/\/github.com\/couchbase\/couchbase-jvm-core\/blob\/1.5.9\/src\/main\/java\/com\/couchbase\/client\/core\/endpoint\/Endpoint.java\">Pontos finais<\/a>.<\/p>\n<p>Se voc\u00ea ativar o registro de depura\u00e7\u00e3o, poder\u00e1 ver durante a inicializa\u00e7\u00e3o como os diferentes n\u00f3s, servi\u00e7os e pontos de extremidade s\u00e3o ativados com base na configura\u00e7\u00e3o fornecida:<\/p>\n<pre class=\"lang:default decode:true\">[cb-computations-8] 2018-06-20 17:43:55 DEBUG RequestHandler:435 - Starting reconfiguration.\r\n[cb-computations-8] 2018-06-20 17:43:55 DEBUG RequestHandler:527 - Starting reconfiguration for bucket travel-sample\r\n[cb-computations-8] 2018-06-20 17:43:55 DEBUG RequestHandler:292 - Node NetworkAddress{localhost\/127.0.0.1, fromHostname=false, reverseDns=true} already registered, skipping.\r\n[cb-computations-8] 2018-06-20 17:43:55 DEBUG RequestHandler:352 - Got instructed to add Service BINARY, to Node NetworkAddress{localhost\/127.0.0.1, fromHostname=false, reverseDns=true}\r\n[cb-computations-8] 2018-06-20 17:43:55 DEBUG Node:273 - [127.0.0.1\/localhost]: Adding Service BINARY\r\n[cb-computations-8] 2018-06-20 17:43:55 DEBUG Node:276 - [127.0.0.1\/localhost]: Service BINARY already added, skipping.\r\n...<\/pre>\n<p>Voc\u00ea tamb\u00e9m pode ver que ele simplesmente ignora determinadas opera\u00e7\u00f5es se o resultado desejado j\u00e1 tiver sido alcan\u00e7ado. Voc\u00ea ver\u00e1 a maioria dessas mensagens quando novas configura\u00e7\u00f5es chegarem, ou seja, durante o bootstrap, o rebalanceamento ou o failover.<\/p>\n<p>A reconfigura\u00e7\u00e3o, assim como o rebalanceamento no servidor, \u00e9 uma opera\u00e7\u00e3o \"on-line\". Isso significa que as opera\u00e7\u00f5es em andamento n\u00e3o s\u00e3o afetadas na maior parte do tempo e, se forem, s\u00e3o reprogramadas e colocadas de volta no ringbuffer at\u00e9 que sejam bem-sucedidas ou atinjam o tempo limite.<\/p>\n<p>Assim que a primeira reconfigura\u00e7\u00e3o for bem-sucedida, nossa solicita\u00e7\u00e3o de abertura do bucket ser\u00e1 conclu\u00edda e o <span class=\"lang:default decode:true crayon-inline\">Balde<\/span>\u00a0 \u00e9 retornado na API s\u00edncrona. Aqui reside uma troca n\u00e3o \u00f3bvia: poder\u00edamos retornar a solicita\u00e7\u00e3o de balde aberto imediatamente, mas n\u00e3o detectar\u00edamos nenhum erro durante o bootstrap. Esperar pela conclus\u00e3o da primeira reconfigura\u00e7\u00e3o nos permite detectar mais erros imediatamente, mas tamb\u00e9m significa que quanto mais n\u00f3s forem adicionados ao cluster, mais tempo levar\u00e1 - certifique-se de medir o desempenho do bootstrap do seu cluster. O tempo limite padr\u00e3o de 5 segundos deve ser suficiente para a maioria dos casos, mas, em implanta\u00e7\u00f5es de nuvem grandes e mais lentas, pode fazer sentido aumentar esse tempo limite.<\/p>\n<p>Voc\u00ea pode fazer isso modificando o ambiente:<\/p>\n<pre class=\"lang:java decode:true\">CouchbaseEnvironment env = DefaultCouchbaseEnvironment.builder()\r\n.connectTimeout(TimeUnit.SECONDS.toMillis(10)) \/\/ set to 10s from 5\r\n.build();<\/pre>\n<p>ou diretamente no <span class=\"lang:default decode:true crayon-inline\">openBucket<\/span>\u00a0 ligar:<\/p>\n<pre class=\"lang:java decode:true\">Bucket bucket = cluster.openBucket(\"travel-sample\", 10, TimeUnit.SECONDS);<\/pre>\n<h2>Falhas e configura\u00e7\u00e3o de bootstrap<\/h2>\n<p>O que acontece se um ou todos os hosts semente fornecidos n\u00e3o estiverem dispon\u00edveis? Para responder a essa pergunta, precisamos dar uma olhada r\u00e1pida em como o carregador tenta obter as configura\u00e7\u00f5es.<\/p>\n<p>Para cada host na lista de n\u00f3s semente, um carregador prim\u00e1rio e um de reserva s\u00e3o montados e todos eles disparam em paralelo tentando obter uma configura\u00e7\u00e3o adequada. Quando a primeira \u00e9 encontrada, a sequ\u00eancia observ\u00e1vel \u00e9 cancelada e apenas uma configura\u00e7\u00e3o \u00e9 usada daqui para frente. Usar essa abordagem, em vez de sequenciar, proporciona tempos de inicializa\u00e7\u00e3o mais r\u00e1pidos, mas tamb\u00e9m pode levar a mais erros no registro se um ou mais n\u00f3s n\u00e3o forem acess\u00edveis. No entanto, como estamos otimizando para o caso positivo (no caso de falha, algo est\u00e1 errado de qualquer forma), essa parece ser uma troca aceit\u00e1vel.<\/p>\n<p>Essencialmente, desde que haja um bom n\u00f3 para inicializa\u00e7\u00e3o na lista de n\u00f3s semente, o SDK poder\u00e1 pegar uma configura\u00e7\u00e3o. Vamos considerar um caso especial em que em um n\u00f3 <a href=\"https:\/\/www.couchbase.com\/blog\/pt\/multi-dimensional-scalability-overview\/\">MDS<\/a>\u00a0configura\u00e7\u00e3o, voc\u00ea instrui o SDK a fazer o bootstrap somente de um n\u00f3 que n\u00e3o contenha o servi\u00e7o KV (digamos, somente a consulta e, \u00e9 claro, o gerenciador de cluster).<\/p>\n<p>Se o registro de depura\u00e7\u00e3o estiver ativado, voc\u00ea ver\u00e1 o SDK tentando obter uma configura\u00e7\u00e3o do servi\u00e7o KV, mas ela est\u00e1 sendo rejeitada com algum erro:<\/p>\n<pre class=\"lang:default decode:true\">[cb-computations-7] 2018-06-21 10:53:48 DEBUG Loader:178 - Could not add service on NetworkAddress{10.142.175.102\/10.142.175.102, fromHostname=false, reverseDns=true} because of com.couchbase.client.core.endpoint.kv.AuthenticationException: Bucket not found on Select Bucket command, removing it again.<\/pre>\n<p>O erro espec\u00edfico n\u00e3o importa, mas mais adiante no registro voc\u00ea pode ver como o carregador muda para o fallback HTTP que est\u00e1 dispon\u00edvel:<\/p>\n<pre class=\"lang:default decode:true\">[cb-computations-2] 2018-06-21 10:53:48 DEBUG Loader:196 - Successfully enabled Service CONFIG on Node NetworkAddress{10.142.175.102\/10.142.175.102, fromHostname=false, reverseDns=true}\r\n[cb-computations-2] 2018-06-21 10:53:48 DEBUG HttpLoader:69 - Starting to discover config through HTTP Bootstrap\r\n...\r\n[cb-computations-4] 2018-06-21 10:53:48 DEBUG HttpLoader:93 - Successfully loaded config through HTTP.\r\n[cb-computations-4] 2018-06-21 10:53:48 DEBUG Loader:203 - Got configuration from Service, attempting to parse.<\/pre>\n<p>Uma implica\u00e7\u00e3o disso \u00e9 que, mesmo que em outro n\u00f3 o servi\u00e7o KV possa estar dispon\u00edvel, nesse caso o carregador HTTP ainda instruir\u00e1 a conex\u00e3o de streaming a ser aberta para buscar as configura\u00e7\u00f5es subsequentes.<\/p>\n<p>\u00c9 poss\u00edvel personalizar o comportamento do bootstrap por meio de configura\u00e7\u00f5es de ambiente:<\/p>\n<ul>\n<li><span class=\"lang:default decode:true crayon-inline\">bootstrapHttpEnabled<\/span>\u00a0: Se o HttpLoader estiver ativado (true por padr\u00e3o).<\/li>\n<li><span class=\"lang:default decode:true crayon-inline\">bootstrapCarrierEnabled<\/span>\u00a0: Se o CarrierLoader estiver ativado (verdadeiro por padr\u00e3o).<\/li>\n<li><span class=\"lang:default decode:true crayon-inline\">bootstrapHttpDirectPort<\/span>\u00a0: Qual porta o HttpLoader deve contatar inicialmente se o SSL n\u00e3o estiver ativado (padr\u00e3o 8091).<\/li>\n<li><span class=\"lang:default decode:true crayon-inline\">bootstrapHttpSslPort<\/span>\u00a0: Qual porta o HttpLoader deve contatar inicialmente se o SSL estiver ativado (padr\u00e3o 18091).<\/li>\n<li><span class=\"lang:default decode:true crayon-inline\">bootstrapCarrierDirectPort<\/span>\u00a0: Qual porta o CarrierLoader deve contatar inicialmente se o SSL n\u00e3o estiver ativado (padr\u00e3o 11210).<\/li>\n<li><span class=\"lang:default decode:true crayon-inline\">bootstrapCarrierSslPort<\/span>\u00a0: Qual porta o CarrierLoader deve contatar inicialmente se o SSL estiver ativado (padr\u00e3o 11207).<\/li>\n<\/ul>\n<p>Essas configura\u00e7\u00f5es t\u00eam padr\u00f5es s\u00e3os e, em geral, n\u00e3o precisam ser modificadas. Elas podem se tornar \u00fateis em cen\u00e1rios de depura\u00e7\u00e3o ou se forem testadas compila\u00e7\u00f5es personalizadas dentro do Couchbase.<\/p>\n<h2>Considera\u00e7\u00f5es finais<\/h2>\n<p>Normalmente, a inicializa\u00e7\u00e3o \u00e9 tranquila e resiliente a falhas de n\u00f3s individuais, mas se algo der errado e o bucket n\u00e3o abrir corretamente, a primeira ordem de a\u00e7\u00e3o \u00e9 sempre examinar os logs no n\u00edvel INFO\/WARN e, se poss\u00edvel, ativar o registro DEBUG. Isso geralmente fornece informa\u00e7\u00f5es sobre quais soquetes n\u00e3o se conectaram corretamente ou onde, na fase de inicializa\u00e7\u00e3o, o cliente teve que parar (devido a erros ou tempos limite).<\/p>\n<p>Lembre-se tamb\u00e9m de que, se voc\u00ea executar clusters grandes, especificar um tempo de abertura de bucket maior do que os 5 segundos habituais pode fazer sentido se a rede for lenta ou tiver uma varia\u00e7\u00e3o de lat\u00eancia maior do que o normal.<\/p>","protected":false},"excerpt":{"rendered":"<p>From time to time we get questions on topics that do not directly fit into the documentation since they dig deeper into the internals of the client libraries. In this series we&#8217;ll cover different themes of interest &#8211; in this [&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":[1821,1818,2201],"tags":[],"ppma_author":[8987],"class_list":["post-5378","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-couchbase-architecture","category-java","category-tools-sdks"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.0 (Yoast SEO v26.0) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Inside the Java SDK: Bootstrap - 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\/inside-the-java-sdk-bootstrap\/\" \/>\n<meta property=\"og:locale\" content=\"pt_BR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Inside the Java SDK: Bootstrap\" \/>\n<meta property=\"og:description\" content=\"From time to time we get questions on topics that do not directly fit into the documentation since they dig deeper into the internals of the client libraries. In this series we&#8217;ll cover different themes of interest &#8211; in this [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/pt\/inside-the-java-sdk-bootstrap\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2018-06-21T10:29:16+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-06-13T09:09:24+00:00\" \/>\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=\"9 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/\"},\"author\":{\"name\":\"Michael Nitschinger\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/e5d4d332756da6f361dd88c1576de61d\"},\"headline\":\"Inside the Java SDK: Bootstrap\",\"datePublished\":\"2018-06-21T10:29:16+00:00\",\"dateModified\":\"2023-06-13T09:09:24+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/\"},\"wordCount\":1750,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"articleSection\":[\"Couchbase Architecture\",\"Java\",\"Tools &amp; SDKs\"],\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/\",\"name\":\"Inside the Java SDK: Bootstrap - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2018-06-21T10:29:16+00:00\",\"dateModified\":\"2023-06-13T09:09:24+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/#breadcrumb\"},\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/#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\/inside-the-java-sdk-bootstrap\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Inside the Java SDK: Bootstrap\"}]},{\"@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":"Inside the Java SDK: Bootstrap - 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\/inside-the-java-sdk-bootstrap\/","og_locale":"pt_BR","og_type":"article","og_title":"Inside the Java SDK: Bootstrap","og_description":"From time to time we get questions on topics that do not directly fit into the documentation since they dig deeper into the internals of the client libraries. In this series we&#8217;ll cover different themes of interest &#8211; in this [&hellip;]","og_url":"https:\/\/www.couchbase.com\/blog\/pt\/inside-the-java-sdk-bootstrap\/","og_site_name":"The Couchbase Blog","article_published_time":"2018-06-21T10:29:16+00:00","article_modified_time":"2023-06-13T09:09:24+00:00","author":"Michael Nitschinger","twitter_card":"summary_large_image","twitter_creator":"@daschl","twitter_misc":{"Written by":"Michael Nitschinger","Est. reading time":"9 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/"},"author":{"name":"Michael Nitschinger","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/e5d4d332756da6f361dd88c1576de61d"},"headline":"Inside the Java SDK: Bootstrap","datePublished":"2018-06-21T10:29:16+00:00","dateModified":"2023-06-13T09:09:24+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/"},"wordCount":1750,"commentCount":2,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","articleSection":["Couchbase Architecture","Java","Tools &amp; SDKs"],"inLanguage":"pt-BR","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/","url":"https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/","name":"Inside the Java SDK: Bootstrap - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2018-06-21T10:29:16+00:00","dateModified":"2023-06-13T09:09:24+00:00","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/#breadcrumb"},"inLanguage":"pt-BR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/"]}]},{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/www.couchbase.com\/blog\/inside-the-java-sdk-bootstrap\/#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\/inside-the-java-sdk-bootstrap\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Inside the Java SDK: Bootstrap"}]},{"@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\/5378","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=5378"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/5378\/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=5378"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/categories?post=5378"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/tags?post=5378"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/ppma_author?post=5378"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}