Java client is the most full featured client. It is offered both with Hazelcast and Hazelcast Enterprise. Main idea behind the Java client is to provide the same Hazelcast functionality by proxying each operation through a Hazelcast node. It can be used to access and change distributed data or listen distributed events of an already established Hazelcast cluster from another Java application.
There are two dependencies that you should include in your classpath to start using Hazelcast client: hazelcast.jar
and hazelcast-client.jar
.
After adding these dependencies, you can start using Hazelcast client as if you are using Hazelcast API. The differences will be extracted throughout the below sections.
If you prefer to use maven, simply add below lines to your pom.xml
.
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-client</artifactId>
<version>$LATEST_VERSION$</version>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
<version>$LATEST_VERSION$</version>
</dependency>
First step is configuration. Java client can be configured declaratively or programmatically. We will use the programmatic approach throughout this tutorial. Please refer to Java Client Declarative Configuration for details.
ClientConfig clientConfig = new ClientConfig();
clientConfig.getGroupConfig().setName("dev").setPassword("dev-pass");
clientConfig.getNetworkConfig().addAddress("10.90.0.1", "10.90.0.2:5702");
Second step is the initialization of HazelcastInstance to be connected to the cluster.
HazelcastInstance client = HazelcastClient.newHazelcastClient(clientConfig);
This client interface is your gateway to access all Hazelcast distributed objects.
Let's create a map and populate with some data;
IMap<String, Customer> mapCustomers = client.getMap("customers");//creates the map proxy
mapCustomers.put("1", new Customer("Joe", "Smith"));
mapCustomers.put("2", new Customer("Ali", "Selam"));
mapCustomers.put("3", new Customer("Avi", "Noyan"));
As a final step, if you are done with your client, you can just shut it down as shown below. This will release all used resources and close connections to cluster.
client.shutdown();
Client has two operation modes because of the distributed nature of the data and cluster.
In this mode, clients connect to each cluster node. As each data partition uses the well known consistent hashing algorithm, each client can send operation to the relevant cluster node which will increase the overall throughput and efficiency. This mode is the default.
For some cases, the clients can be required to connect to a single node instead of each node in the cluster. Firewalls, security or some custom networking issues can be the reason for that.
In this mode, client will only connect to one of the configured addresses. This single node will behave as a gateway to other nodes. For any operation requested from the client, it will redirect the request to the relevant node and return the response back to the client returned from this node.
There are two main failure cases to be aware of and configured to achieve a proper behavior.
While client is trying to connect initially to one of the members in the ClientNetworkConfig.addressList
, all members might be not available. Instead of giving up, throwing an exception and stopping the client, it will attempt to retry as much as connectionAttemptLimit
times. Please see Connection Attempt Limit.
Client executes each operation through the already established connection to cluster. If this connection(s) disconnects or drops, client will try to reconnect as configured.
While sending the requests to related nodes, it is possible that operation fails due to various reasons. For any read only operations, you can have your client retrying to send the operation by enabling redoOperation
. Please see Redo Operation.
And, the number of retries is given with the property hazelcast.client.request.retry.count
in ClientProperties
. It will resend the request as many as RETRY-COUNT then it will throw an exception. Please see Client Properties.
Most of the Distributed Data Structures are supported by the client. Please check for the exceptions for the clients in other languages.
As a general rule, these data structures are configured on the server side and simply accessed through a proxy on the client side.
You can use any Distributed Map object with client as shown below.
Imap<Integer, String> map = client.getMap(“myMap”);
map.put(1, “Ali”);
String value= map.get(1);
map.remove(1);
As Locality is ambiguous for the client, addEntryListener
and localKeySet
are not supported. Please see Distributed Map for more information.
A sample usage is shown below.
MultiMap<Integer, String> multiMap = client.getMultiMap("myMultiMap");
multiMap.put(1,”ali”);
multiMap.put(1,”veli”);
Collection<String> values = multiMap.get(1);
As Locality is ambiguous for the client, addEntryListener
, localKeySet
and getLocalMultiMapStats
are not supported. Please see Distributed MultiMap for more information.
A sample usage is shown below.
IQueue<String> myQueue = client.getQueue(“theQueue”);
myQueue.offer(“ali”)
getLocalQueueStats
is not supported as locality is ambiguous for the client. Please see Distributed Queue for more information.
getLocalTopicStats
is not supported as locality is ambiguous for the client.
Below distributed data structures are also supported by the client. Since their logic is the same in both the node side and client side, you can refer to their sections as listed below.
Below services are provided for some common functionalities on the client side.
This service is for distributed computing. It can be used to execute tasks on the cluster on designated partition or even on all partitions. It can also be used to process entries. Please see Distributed Executor Service for more information.
IExecutorService executorService = client.getExecutorService("default");
After getting an instance of IExecutorService
, it can be used as the interface with the one provided on the server side. Please see Distributed Computing chapter for detailed usage.
NOTE: This service is only supported by the Java client.
If you need to track clients and want to listen their connection events, see the below code.
final ClientService clientService = client.getClientService();
final Collection<Client> connectedClients = clientService.getConnectedClients();
clientService.addClientListener(new ClientListener() {
@Override
public void clientConnected(Client client) {
//Handle client connected event
}
@Override
public void clientDisconnected(Client client) {
//Handle client disconnected event
}
});
Partition service is used to find the partition of a key. It will return all partitions. See the below code.
PartitionService partitionService = client.getPartitionService();
//partition of a key
Partition partition = partitionService.getPartition(key);
//all partitions
Set<Partition> partitions = partitionService.getPartitions();
Lifecycle handling is to;
LifecycleService lifecycleService = client.getLifecycleService();
if(lifecycleService.isRunning()){
//it is running
}
//shutdown client gracefully
lifecycleService.shutdown();
Listeners can be configured to listen to various event types on the client side. Global events not relating to any distributed object can be configured through ListenerConfig. Whereas, distributed object listeners like map entry listeners or list item listeners should be configured through their proxies. You can refer to the related sections under each distributed data structure in this reference manual.
Transactional distributed objects are supported on the client side. Please see Transactions chapter on how to use them.
ClientConfig clientConfig = new ClientConfig();
ClientNetworkConfig networkConfig = clientConfig.getNetworkConfig();
Address List is the initial list of cluster addresses to which the client will connect. Client uses this list to find an alive node. Although it may be enough to give only one address of a node in the cluster (since all nodes communicate with each other), it is recommended to give all nodes’ addresses.
If the port part is omitted then 5701, 5702, and 5703 will be tried in a random order.
clientConfig.getNetworkConfig().addAddress("10.1.1.21", "10.1.1.22:5703");
You can provide multiple addresses with ports provided or not as seen above. The provided list is shuffled to try them in a random order.
Default value is localhost.
This parameter defines whether the client is smart or a dummy one.
//sets client to dummy client mode
clientConfig.getNetworkConfig().setSmartRouting(false);
Default is smart client mode.
Enables/disables redo-able operations as described in Retry-able Operation Failure.
//enables redo
clientConfig.getNetworkConfig().setRedoOperation(true);
Default is disabled.
Timeout value in milliseconds for nodes to accept client connection requests.
//enables redo
clientConfig.getNetworkConfig().setConnectionTimeout(1000);
Default value is 5000 milliseconds.
While client is trying to connect initially to one of the members in the ClientNetworkConfig.addressList
, all might be not available. Instead of giving up, throwing exception and stopping the client, it will attempt to retry as much as ClientNetworkConfig.connectionAttemptLimit
times.
//enables redo
clientConfig.getNetworkConfig().setConnectionAttemptLimit(5);
Default value is 2.
The duration in milliseconds between connection attempts defined by ClientNetworkConfig.connectionAttemptLimit
.
//enables redo
clientConfig.getNetworkConfig().setConnectionAttemptPeriod(5000);
Default value is 3000.
Client configuration to set a socket intercepter. Any class implementing com.hazelcast.nio.SocketInterceptor
is a socket Interceptor.
public interface SocketInterceptor {
void init(Properties properties);
void onConnect(Socket connectedSocket) throws IOException;
}
Socket interceptor has two steps. First, it will be initialized by the configured properties. Second, it will be informed just after socket is connected using onConnect
.
SocketInterceptorConfig socketInterceptorConfig = clientConfig
.getNetworkConfig().getSocketInterceptorConfig();
MyClientSocketInterceptor myClientSocketInterceptor = new MyClientSocketInterceptor();
socketInterceptorConfig.setEnabled(true);
socketInterceptorConfig.setImplementation(myClientSocketInterceptor);
If you want to configure it with a class name instead of an instance;
SocketInterceptorConfig socketInterceptorConfig = clientConfig
.getNetworkConfig().getSocketInterceptorConfig();
MyClientSocketInterceptor myClientSocketInterceptor = new MyClientSocketInterceptor();
socketInterceptorConfig.setEnabled(true);
//These properties are provided to interceptor during init
socketInterceptorConfig.setProperty("kerberos-host","kerb-host-name");
socketInterceptorConfig.setProperty("kerberos-config-file","kerb.conf");
socketInterceptorConfig.setClassName(myClientSocketInterceptor);
Please see Socket Interceptor section for more information.
Network socket options can be configured using SocketOptions
. It has below methods.
socketOptions.setKeepAlive(x)
: Enables/disables SO_KEEPALIVE socket option. Default is true
.
socketOptions.setTcpNoDelay(x)
: Enables/disables TCP_NODELAY socket option. Default is true
.
socketOptions.setReuseAddress(x)
: Enables/disables SO_REUSEADDR socket option. Default is true
.
socketOptions.setLingerSeconds(x)
: Enables/disables SO_LINGER with the specified linger time in seconds. Default is 3
.
socketOptions.setBufferSize(x)
: Sets the SO_SNDBUF and SO_RCVBUF options to the specified value in KB for this Socket. Default is 32
.
SocketOptions socketOptions = clientConfig.getNetworkConfig().getSocketOptions();
socketOptions.setBufferSize(32);
socketOptions.setKeepAlive(true);
socketOptions.setTcpNoDelay(true);
socketOptions.setReuseAddress(true);
socketOptions.setLingerSeconds(3);
SSL can be used to secure the connection between client and the nodes. Please see SSLConfig section on how to configure it.
Below sample declarative and programmatic configurations show how to configure a Java client for connecting to a Hazelcast cluster in AWS.
Declarative Configuration:
<aws enabled="true">
<!-- optional default value is false -->
<inside-aws>false</inside-aws>
<access-key>my-access-key</access-key>
<secret-key>my-secret-key</secret-key>
<!-- optional, default is us-east-1 -->
<region>us-west-1</region>
<!-- optional, default is ec2.amazonaws.com. If set, region shouldn't be set
as it will override this property
-->
<host-header>ec2.amazonaws.com</host-header>
<!-- optional -->
<security-group-name>hazelcast-sg</security-group-name>
<!-- optional -->
<tag-key>type</tag-key>
<!-- optional -->
<tag-value>hz-nodes</tag-value>
</aws>
Programmatic Configuration:
ClientConfig clientConfig = new ClientConfig();
ClientAwsConfig clientAwsConfig = new ClientAwsConfig();
clientAwsConfig.setInsideAws( false )
.setAccessKey( "my-access-key" )
.setSecretKey( "my-secret-key" )
.setRegion( "us-west-1" )
.setHostHeader( "ec2.amazonaws.com" )
.setSecurityGroupName( ">hazelcast-sg" )
.setTagKey( "type" )
.setTagValue( "hz-nodes" );
clientConfig.getNetworkConfig().setAwsConfig( clientAwsConfig );
HazelcastInstance client = HazelcastClient.newHazelcastClient( clientConfig );
Note: If inside-aws
parameter is not set, private addresses of nodes will always be converted to public addresses. And, client will use public addresses to connect to nodes. In order to use private adresses, you should set it to true
. Also note that, when connecting outside from AWS, setting inside-aws
parameter to true
will cause the client not to be able to reach to the nodes.
LoadBalancer
allows you to send operations to one of a number of endpoints(Members). Its main purpose is to determine the next Member
if queried. It is up to the implementation to use different load balancing policies. The interface com.hazelcast.client.LoadBalancer
sould be implemented for that purpose.
If the client is configured as a smart one, only the operations that are not key based will be routed to the endpoint returned by the LoadBalancer. If it is not a smart client, LoadBalancer
will be ignored.
TODO
Hazelcast distributed map has a Near Cache feature to reduce network latencies. As the client always requests data from the cluster nodes, it can be helpful for some use cases to configure a near cache on the client side. The client supports the exact same near cache used in Hazelcast distributed map.
If SSL is desired to be enabled for the client-cluster connection, this parameter should be set. Once set, the connection (socket) is established out of an SSL factory defined either by a factory class name or factory implementation. Please see SSLConfig class in com.hazelcast.config
package at the JavaDocs page of Hazelcast Documentation web page.
Hazelcast Java client can be configured in two ways, declaratively or programmatically.
Java client can be configured using an XML configuration file. Below is a generic template of a declarative configuration.
<hazelcast-client xsi:schemaLocation=
"http://www.hazelcast.com/schema/client-config hazelcast-client-config-3.3.xsd"
xmlns="http://www.hazelcast.com/schema/client-config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<!--Cluster name to connect-->
<group>
<name>GROUP_NAME</name>
<password>GROUP_PASS</password>
</group>
<!--client properties-->
<properties>
<property name="hazelcast.client.connection.timeout">10000</property>
<property name="hazelcast.client.retry.count">6</property>
</properties>
<!--Network configuration details-->
<network>
<cluster-members>
<!--initial cluster members to connect-->
<address>127.0.0.1</address>
<address>127.0.0.2</address>
</cluster-members>
<smart-routing>true</smart-routing>
<redo-operation>true</redo-operation>
<socket-interceptor enabled="true">
<!--socket-interceptor configuration details-->
</socket-interceptor>
<aws enabled="true" connection-timeout-seconds="11">
<!--AWS configuration details-->
</aws>
</network>
<!--local executor pool size-->
<executor-pool-size>40</executor-pool-size>
<!--security credentials configuration-->
<security>
<credentials>com.hazelcast.security.UsernamePasswordCredentials</credentials>
</security>
<listeners>
<!--listeners-->
</listeners>
<serialization>
<!--serialization configuration details-->
</serialization>
<proxy-factories>
<!--ProxyFactory configuration details-->
</proxy-factories>
<!--load balancer configuration-->
<load-balancer type="random"/>
<near-cache name="mapName">
<!--near cache configuration details of a map-->
</near-cache>
</hazelcast-client>
Using the configuration API, a ClientConfig
configured as required. Please refer to the related sections and JavaDocs for more information.
ClientNetworkConfig includes the below listed configuration options, which are explained under Network Configuration Options section.
Clients should provide group name and password in order to connect to the cluster.
It can be configured using GroupConfig
, as shown below.
clientConfig.setGroupConfig(new GroupConfig("dev","dev-pass"));
In the cases where the security established with GroupConfig
is not enough and you want your clients connecting securely to the cluster, ClientSecurityConfig
can be used. This configuration has a credentials
parameter with which IP address and UID are set. Please see ClientSecurityConfig.java
in our code.
For the client side serialization, Hazelcast configuration is used. Please refer to Serialiazation chapter.
To Do
Global event listeners can be configured using ListenerConfig
as shown below.
ClientConfig clientConfig = new ClientConfig();
ListenerConfig listenerConfig = new ListenerConfig(LifecycleListenerImpl);
clientConfig.addListenerConfig(listenerConfig);
ClientConfig clientConfig = new ClientConfig();
ListenerConfig listenerConfig = new ListenerConfig("com.hazelcast.example.MembershipListenerImpl");
clientConfig.addListenerConfig(listenerConfig);
There are three types of event listeners that can be added.
RELATED INFORMATION
Please refer to Hazelcast JavaDocs and see LifecycleListener, MembershipListener and DistributedObjectListener in com.hazelcast.core
package.
A near cache on the client side can be configured by providing a configuration per map name, as shown below.
ClientConfig clientConfig = new ClientConfig();
CacheConfig nearCacheConfig = new NearCacheConfig();
nearCacheConfig.setName("mapName");
clientConfig.addNearCacheConfig(nearCacheConfig);
Wildcards can be used for the map name. See below samples.
nearCacheConfig.setName("map*");
nearCacheConfig.setName("*map");
A custom classLoader
can be configured. It will be used by serialization service and to load any class configured in configuration like event listeners or ProxyFactories.
Hazelcast has an internal executor service (different from the data structure Executor Service) that has threads and queues to perform internal operations such as handling responses. This parameter specifies the size of the pool of threads which perform these operations laying in the executor's queue. If not configured, this parameter has the value as 5 * core size of the client (i.e. it is 20 for a machine that has 4 cores).
To Do (advanced)
To Do (advanced)
There are some advanced client configuration properties to tune some aspects of Hazelcast Client. These can be set as property name and value pairs through declarative configuration, programmatic configuration or JVM system property. Please see Advanced Configuration Properties section to learn how to set these properties.
Below table lists the client configuration properties with their descriptions.
Property Name | Default Value | Type | Description |
---|---|---|---|
hazelcast.client.heartbeat.timeout |
300000 | string | Timeout for the heartbeat messages sent by the client to members. If there is no any message passing between client and member within the given time via this property in milliseconds the connection will be closed. |
hazelcast.client.heartbeat.interval |
10000 | string | The frequency of heartbeat messages sent by the clients to members. |
hazelcast.client.max.failed.heartbeat.count |
3 | string | When the count of failed heartbeats sent to members reaches this value, the cluster is deemed as dead by the client. |
hazelcast.client.request.retry.count |
20 | string | The retry count of the connection requests by the client to the members. |
hazelcast.client.request.retry.wait.time |
250 | string | The frequency of the connection retries. |
hazelcast.client.event.thread.count |
5 | string | Thread count for handling incoming event packets. |
hazelcast.client.event.queue.capacity |
1000000 | string | Default value of the capacity of executor that handles incoming event packets. |
Please refer to Client Code Samples.