A newer version of this documentation is available.

View Latest

Managing Connections using the Java SDK with Couchbase Server

    This section describes how to connect the Java SDK to a Couchbase cluster and bucket. It contains best practices as well as information on SSL and other advanced connection options.

    Connecting to a Bucket

    Connecting to a bucket is a two-step process: first, a CouchbaseCluster object needs to be initialized, followed by one or more calls to openBucket():

    Cluster cluster = CouchbaseCluster.create();
    Bucket bucket = cluster.openBucket();

    If no further arguments are applied, this code connects to localhost and opens the default bucket. While this is suitable for development, you most probably want to connect to a remote cluster and also a different bucket (with a password):

    Cluster cluster = CouchbaseCluster.create("", "");
    Bucket bucket = cluster.openBucket("myapp", "password");
    Any Cluster nodes addresses passed in to establish (bootstrap) the connection should be for data (KV) nodes.

    Alternatively, a list of nodes can be passed in:

    List<String> nodes = Arrays.asList("", "");
    Cluster cluster = CouchbaseCluster.create(nodes);

    The Java SDK also offers limited support for creating a cluster from a Couchbase connection string:

    String connectionString = "couchbase://,";
    CouchbaseCluster cluster = CouchbaseCluster.fromConnectionString(connectionString);
    When creating a cluster from a connection string, the Java SDK ignores the scheme component; if a secure connection is desired, the Couchbase environment must be configured as described in Connecting with SSL. The Java SDK also ignores any options in the connection string, and will not work with a connection string that specifies a bucket name.

    From Couchbase Java SDK 2.6.0, AlternateAddress is implemented, for connecting to nodes in a NATed environment, such as Docker containers using portmapping. It is on by default, if the server provides a topology that includes a multi-network configuration. Whichever network is selected at bootstrap will be logged.

    If using Docker Swarm, or otherwise running the SDK inside the NAT, then you will want to disable with ?network=default in the connection string, or an environmental setting can be made.

    Note that any SSL/TLS certificates must be set up at the point where the connections are being made. The Couchbase SDKs will honor any valid SSL/TLS certificates.

    It is very important in a production setup to pass in at least two or three nodes of the cluster because if the first one in the list fails the other ones can be tried. After initial contact is made, the bootstrap list provided by the user is thrown away and replaced with a list provided by the server (which contains all nodes of the cluster).

    More buckets can be open at the same time if needed:

    Bucket bucket1 = cluster.openBucket("bucket1", "password");
    Bucket bucket2 = cluster.openBucket("bucket2", "password");

    If more than one bucket is open at a time, the underlying core-io library makes sure to utilize the resources as best as possible, that is sharing sockets, thread pools and so on.

    Here are some very important things to keep in mind:

    • Always create only one instance of a CouchbaseCluster and share it across threads (same with buckets).

    • The SDK is thread-safe, so no additional synchronization is needed when interacting with the SDK.

    • If different clusters need to be accessed, reuse the CouchbaseEnvironment (See Scalability and Concurrency).

    If the underlying environment is not shared the application will continue to work, but a warning is raised in the logs:

    WARNING: More than 1 Couchbase Environments found (N), this can have severe
    impact on performance and stability. Reuse environments!

    In general, this is an indication of misconfiguration, the only exception being unit and integration tests where multiple paths are executed at once and cannot share the ClusterEnvironment for whatever reason.

    You are strongly recommended against using Round Robin DNS, which can return a different address at each connection, as Java uses $host from the Cluster Map — which can cause connection issues. Use of a Service record (SRV record), to provide real hostnames (A records) in the bootstrap list, will ensure consistent connections.

    Disconnecting from a Bucket

    The most common case is to disconnect the whole CouchbaseCluster from the server, which has the same effect as closing all buckets manually and in addition close all underlying resources like thread pools. This also means that once disconnect has happened, you can’t reopen buckets from the same Cluster instance.

    Boolean disconnected = cluster.disconnect();

    If the ClusterEnvironment is shared it needs to be closed manually, but if not (which is the regular case) it gets auto shut down.

    After a disconnect, it is not possible to open buckets again, so only use it when you are sure that you do not need access to a CouchbaseCluster again. If you only want to close a bucket, you can do that without shutting down everything:

    Boolean closed = bucket.close();

    This will release only the resources allocated for this bucket and it is possible to reopen it at a later point.

    All threads used by the SDK are daemon threads, so even if you do not disconnect() manually, your JVM will be able to exit. It is very important that you properly shut down the SDK so that remaining operations are finished and nothing is left behind.

    If no timeout is used for the synchronous disconnect() method, the environment disconnect timeout is used, which defaults to 25 seconds. This holds also true if you call close() on a bucket.

    Connecting Asynchronously

    Every synchronous API is just a wrapper around an asynchronous one. To get to it, you can use one of these methods:

    • Use async() on the interface to access its Async* counterpart.

    • Instantiate a CouchbaseAsyncCluster in the first place.

    So if you are connecting to the bucket synchronously but then want to switch over to asynchronous data operations, you can do it like this:

    Cluster cluster = CouchbaseCluster.create();
    Bucket bucket = cluster.openBucket();
    // Same API as Bucket, but completely async with Observables
    AsyncBucket asyncBucket = bucket.async();

    On the other hand, you can use the Async API right from the beginning:

    AsyncCluster cluster = CouchbaseAsyncCluster.create();
    Observable<AsyncBucket> bucketObservable = cluster.openBucket();

    Scalability and Concurrency

    As mentioned previously, you should create only one instance of a CouchbaseCluster and open buckets from there. If you need to connect to multiple clusters though, this is not going to work. To keep things efficient, you should share the CouchbaseEnvironment object between those instances:

    CouchbaseEnvironment env = DefaultCouchbaseEnvironment.create();
    CouchbaseCluster cluster1 = CouchbaseCluster.create(env, "");
    CouchbaseCluster cluster2 = CouchbaseCluster.create(env, "");

    This ensures that the resources in the environment (thread pools for I/O and computation) are reused. Note that if you pass in your custom environment, it needs to be shut down manually because it’s not under the complete control of any cluster. The recommended approach is to first shut down all clusters and after this is done shut down the environment (here using asynchronous code, but you can also loop synchronously):

        .just(cluster1, cluster2)
        .flatMap(aBoolean -> env.shutdown())
    Connection Limits

    Each Couchbase Data node allows by default, in Couchbase Data Platform 6.0 and earlier, up to 30,000 concurrent key-value connections per port exposed to the user by the Data Service (ports 11210 and 11207). This means that if you are mixing SSL connections (port 11207) and plain connections (port 11210), you can have 30,000 connections on each of these two ports, or up to 60,000 in total. If you are using plain (or SSL) alone, then the limit is 30,000.

    From 6.5 onwards, the default value is 65,000 connections to the server — with 5000 of these reserved for system use. Thus, you can use 60,000 connections even if you only use_ one_ of the two ports (plain or SSL).

    Connecting with SSL

    Couchbase Server EE 3.0 and later supports full encryption of client-side traffic. That includes key-value type operations, queries, and configuration communication. Make sure to have a proper Couchbase Server version installed before proceeding with configuring encryption on the client side.

    To configure encryption for the Java SDK:

    1. Load and import the certificate from the cluster into your JVM keystore

    2. Enable encryption on the client side and point it to the keystore

    The JVM keystore is independent of the Java SDK, so your own setup might look different. It is important to make sure you are transferring the certificate in an encrypted manner from the server to the client side, so either copy it through SSH or through a similar secure mechanism.

    If you are running on localhost and just want to enable it for a development machine, just copying and pasting it suffices. Navigate in the admin UI to Settings  Cluster and copy the input box of the SSL certificate into a file on your machine (here named cluster.cert). It looks similar to this:

    -----END CERTIFICATE-----

    Now, use the keytool command to import it into your JVM keystore.

    Use the -keystore option to specify where to create the keystore. If you don’t use this option, the default location is the .keystore file in user’s home directory.
    $ keytool -importcert -file cluster.cert
    Enter keystore password:
    Owner: CN=*
    Issuer: CN=*
    Serial number: 1381528ec7379f22
    Valid from: Tue Jan 01 01:00:00 CET 2013 until: Sat Jan 01 00:59:59 CET 2050
    Certificate fingerprints:
    	 MD5:  4A:5E:DB:4F:F6:7E:FD:C3:0E:0C:56:C4:05:34:C1:4A
    	 SHA1: 3A:BC:48:3C:0F:36:99:EB:35:76:7C:E5:14:DE:89:DE:AE:79:9B:ED
    	 SHA256: 24:46:59:55:F2:65:23:85:E2:80:9F:CC:D1:EF:41:E9:4E:D8:ED:11:C8:CF:60:C7:C5:AD:63:56:D0:E6:7F:4D
    	 Signature algorithm name: SHA1withRSA
    	 Version: 3
    Trust this certificate? [no]:  yes
    Certificate was added to keystore

    You can verify with keytool -list:

    $ keytool -list
    Enter keystore password:
    Keystore type: JKS
    Keystore provider: SUN
    Your keystore contains 1 entry
    mykey, Aug 18, 2014, trustedCertEntry,
    Certificate fingerprint (SHA1): 3A:BC:48:3C:0F:36:99:EB:35:76:7C:E5:14:DE:89:DE:AE:79:9B:ED

    The next step is to enable encryption and pass it the path and password of the file.

    CouchbaseEnvironment env = DefaultCouchbaseEnvironment

    Alternatively, since 2.3.0 it is possible to point it directly to a keystore that has been previously initialized so it can be created from different sources:

    KeyStore myKeystore = loadKeystore();
    CouchbaseEnvironment env = DefaultCouchbaseEnvironment.builder()

    Depending on the OS used there are different default passwords and paths, so consult the JDK manual if you need further information on keytool (Java 7 for Windows and Unix) and the JVM keystore.

    There are no other application changes needed. If you want to verify it’s actually working ,you can use a tool like tcpdump. For example, an unencrypted upsert request looks like this (using sudo tcpdump -i lo0 -A -s 0 port 11210):


    After enabling encryption, you cannot inspect the traffic in cleartext (same upsert request, but watched on port 11207 which is the default encrypted port):

    ..... ...xuG.O=.#.........?.Q)8..D...S.W.4.-#....@7...^.Gk.4.t..C+......6..)}......N..m..o.3...d.,.	...W.....U..

    Using DNS SRV records

    As an alternative to specifying multiple hosts in your program, you can get the actual bootstrap node list from a DNS SRV record. The following steps are necessary to make it work:

    1. Set up your DNS server to respond properly from a DNS SRV request.

    2. Enable it on the SDK and point it towards the DNS SRV entry.

    Your DNS server should be set up like this (one row for each bootstrap node):

    _couchbase._tcp.example.com.  3600  IN  SRV  0  0  11210  node1.example.com.
    _couchbase._tcp.example.com.  3600  IN  SRV  0  0  11210  node2.example.com.
    _couchbase._tcp.example.com.  3600  IN  SRV  0  0  11210  node3.example.com.
    The ordering, priorities, and weighting are completely ignored and should not be set on the records to avoid ambiguities.

    If you plan to use secure connections, you use _couchbases instead:

    _couchbases._tcp.example.com.  3600  IN  SRV  0  0  11207  node1.example.com.
    _couchbases._tcp.example.com.  3600  IN  SRV  0  0  11207  node2.example.com.
    _couchbases._tcp.example.com.  3600  IN  SRV  0  0  11207  node3.example.com.

    DNS SRV bootstrapping is available in the Java SDK from version 2.1.0. In order to make the SDK actually use the SRV records, you need to enable DNS SRV on the environment and pass in the host name from your records (here example.com):

    CouchbaseEnvironment env = DefaultCouchbaseEnvironment
    Cluster cluster = CouchbaseCluster.create(env, "example.com");

    If the DNS SRV records could not be loaded properly you’ll get the exception logged and the given host name will be used as a A record lookup.

    WARNING: DNS SRV lookup failed, proceeding with normal bootstrap.
    javax.naming.NameNotFoundException: DNS name not found [response code 3];
       remaining name '_couchbase._tcp.example.com'
    	at com.sun.jndi.dns.DnsClient.checkResponseCode(DnsClient.java:651)
    	at com.sun.jndi.dns.DnsClient.isMatchResponse(DnsClient.java:569)

    Also, if you pass in more than one node, DNS SRV bootstrap will not be initiated:

    INFO: DNS SRV enabled, but less or more than one seed node given.
    Proceeding with normal bootstrap.