Hazelcast cache implementation in my application - java

Below is my scenario from Application perspective.
We have 2 applications (.war) files will be running in a same instance of Application server (mostly Tomcat 8), In production we may deploy App1 on 100 servers and App2 only on 50 server out of those 100 (The App2 does not need to be distributed so much)
Now this 2 applications (.war) depends on a common custom jar (some utility classes)
I am planning to use Jcache API and hazelcast implementation in our apps. I have added following dependency in my pom.xml
<!-- JSR 107 JCache -->
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<version>1.0.0</version>
</dependency>
<!-- Hazelcast dependency -->
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
<version>3.4</version>
</dependency>
Plan is to write a utility CacheManager in this common custom jar which will be shared by App1 and App2.
I am planning to use only the hazelcast server provider as I am doing in-memory cluster i.e. the caching will be in application memory.
Below is the snippet of my code.
public class PPCacheManager {
// Loads the default CacheProvider (HazelCast) from hazelcast.xml which is
// in classpath
private static CachingProvider defaultCachingProvider = Caching.getCachingProvider(); //
// Loads the default CacheManager from hazelcast.xml which is in classpath
private static CacheManager defaultCacheManager = defaultCachingProvider.getCacheManager();
// Some more code goes here...
My hazelast.xml
<hazelcast xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.hazelcast.com/schema/config
http://www.hazelcast.com/schema/config/hazelcast-config-3.4.xsd"
xmlns="http://www.hazelcast.com/schema/config">
<cache name="commonClientCache">
<key-type class-name="java.lang.String"></key-type>
<value-type class-name="java.lang.Object"></value-type>
<statistics-enabled>true</statistics-enabled>
<management-enabled>true</management-enabled>
<read-through>true</read-through>
</cache>
</hazelcast>
Now I have several question around this approach.
Is this a good way to implement the in memory caching (currently we are not looking for cluster caching), should this code be in the common custom jar or somewhere else?
There is some master data from DB which I am planning to load (both applications need this data) so not sure how and where I should load this data into memory. Note: I do not want to do lazy loading; I want to load this master data very first.
Where should I add the cache shutdown code to avoid memory leak issues, as this cache is shared by both the applications.
Update
Also by implementing this approach will I have 2 copies of cache each for application or a single copy will be shared across both?
I have already implemented this approach in my application and from Hazelcast management console I can see that there is only 1 cache is created but it says GET is executed on this cache twice.

Hazelcast is the perfect solution for what you are trying to do. Definitely no lazy loading. You don't need anything like that if you have shared memory.
As far, as how many instances you'd have inside one (Tomcat) JVM, you'd have two if you instantiate Hazelcast twice. It'd autoincrement the port. However both will belong to the same cluster (you call "cache"), as long as the cluster name is the same. So other than looking a little silly (sharding on a single JVM), you are fine. To avoid it, you can configure one of the wars to instantiate a HazelcastClient. The utility jar can be the same. It should all be in some e.g. Spring config - which every war would have its own copy of. Or you can put that config into two external directories and add to the catalina classpath.
The shutdown code belongs to the same place you instantiated Hazelcast i.e. your two wars will have two shutdown calls. You can do it in Spring's destroy() of any of your high-level config (or autowired) beans or put it in the Web App session listener.

Related

Hazelcast Client Only Configuration

Is it possible to create a client only hazelcast node? We have hazelcast embedded in our Java Applications and they use a common hazelcast.xml. This works fine, however when one of our JVM's is distressed, it causes the other clustered JVM's to slow down and have issues. I want to run a hazelcast cluster outside of our application stack and update the common hazelcast.xml to point to the external cluster. I have tried various config options but the application JVM's always want to start a listener and become members. I realize I maybe asking for something that defeats the purpose of hazelcast, however I thought it may be possible to configure an instance to be a client only.
Thanks.
You can change your application to use Hazelcast client instances, but it requires a code change.
Instead of
HazelcastInstance hz = Hazelcast.newHazelcastInstance();
you'll need to initialize your instance by requesting a client one:
HazelcastInstance hz = HazelcastClient.newHazelcastClient();
Another option is to keep the code unchanged and configure your embedded members to be "lite" ones. So they don't own any partition (they don't store cluster data).
<hazelcast xmlns="http://www.hazelcast.com/schema/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.hazelcast.com/schema/config
http://www.hazelcast.com/schema/config/hazelcast-config-4.0.xsd">
<!--
===== HAZELCAST LITE MEMBER CONFIGURATION =====
Configuration element's name is <lite-member>. When you want to use a Hazelcast member as a lite member,
set this element's "enabled" attribute to true in that member's XML configuration. Lite members do not store
data and are used mainly to execute tasks and register listeners. They do not have partitions.
-->
<lite-member enabled="true"/>
</hazelcast>

Infinispan Unique Cache Manager for deployed Web Applications

I'm working with Infinispan 8.1 and WildFly 10.
I initialize my CacheManager programmatically using these code lines:
public class SessionManager {
private static DefaultCacheManager cacheManager;
public void initializeCache(){
if (cacheManager ==null){
GlobalConfigurationBuilder gcbLocal = new GlobalConfigurationBuilder();
ConfigurationBuilder builderLocal = new ConfigurationBuilder();
builderLocal.clustering().cacheMode(CacheMode.LOCAL);
cacheManager = new DefaultCacheManager(gcbLocal.build(), builderLocal.build());
cacheManager.getCache();
These code lines belong to a jar imported as dependency in multiple web applications deployed on my server.
So every time i deploy a new application, the initialize method is invoked and infinispan tries to create a new DefaultCacheManager, giving me this exception:
ISPN000034: There's already a JMX MBean instance type=CacheManager,name="DefaultCacheManager" already registered under 'org.infinispan' JMX domain. If you want to allow multiple instances configured with same JMX domain enable 'allowDuplicateDomains' attribute in 'globalJmxStatistics' config element
This issue can be resolved simply adding this code line:
gcbLocal.globalJmxStatistics().allowDuplicateDomains(true);
But now the effect is that Infinispan will create a new domain separated CacheManager. This means that every application will have its own.
My target is to have just 1 DefaultCacheManager serving all the web applications deployed inside the server the way that if WebApplicationA stores some value inside the infinispan cache, the webApplicationB can get it.
Is it possible? How can i obtain a global Cache Manager?
Ernest is right - MBean servers are per JVM not per ClassLoader, so you need to ignore duplicated domains. But what's more interesting - Wildfly uses Infinispan for session clustering, so the default cache manager might be already running. I strongly recommend using your own cache manager name:
new GlobalConfigurationBuilder().globalJmxStatistics()
.cacheManagerName(CACHE_NAME).build();
Ernest also suggested using a HotRod Server cluster and connecting to it using a HotRod client (which is by far faster than using REST interface). This sounds reasonable in scenario you described.
It seems obvious that you're running this code in web modules (.war) -- or in jars bundled in war files. You cannot share instances across web modules as class-loaders are protected (and that's good for you).
You have a few options:
Instead of deploying war files, make a single ear file with multiple web modules, and one EJB that will then create and use the cache manager. Each web module will then get to the cache via the local EJB, with infinispan libs deployed in ear/lib.
Run Infinispan server (standalone wildfly installation for Infinispan) and change your code to use the remote clients:
-- HotRod client to connect to it externally (docs here: http://infinispan.org/docs/8.2.x/getting_started/getting_started.html#_using_hot_rod_to_access_an_infinispan_data_grid).
-- REST client (docs here: http://infinispan.org/docs/8.2.x/user_guide/user_guide.html#_infinispan_rest_server)
Each web module can do this separately.

JamonAdmin in Different Servlet Container

I have a web application running on Weblogic. It has com.jamonapi:jamon:2.81 as maven dependency.
I'm using org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor with aop configuration. For every service/dao method call, jamon interceptor calculates statistics and stores them in memory.
I setup a jetty base for deploying jamon.war and started it. I can access it via http://localhost:3162/jamon/jamonadmin.jsp
However, it shows only local statistics. It doesn't show any statistics from my web application running on Weblogic. This did not suprise me since I didn't do any configuration for this. The question is that how can I do this magic configuration to make jamon.war see the statistics collected in my web application running on weblogic.
Thanks.
You need to define jamon as a provided scope dependency in your webapp's pom.xml.
<dependency>
<groupId>com.jamonapi</groupId>
<artifactId>jamon</artifactId>
<version>2.81</version>
<scope>provided</scope>
</dependency>
This will ensure that your Weblogic webapp uses the jamonapi.jar files in your servlet container (jetty/lib/jamon-2.81.jar) instead of a duplicate copy deployed with the webapp itself.

How to deploy the same web application twice on WebLogic 11g?

We have developed a JEE5 web application (WAR) and running it in production under WebLogic 11g (10.3.5).
Now the same application should be deployed as separate applications for different customers (different URLs, different data) on the same WebLogic.
I managed the first part by setting different context roots after deployment for each of them.
But I have yet to make them use different datasources - and since I want to avoid customer specific builds, the persistence.xml is the same for all applications, thus also the persistence unit name.
What is the best setup for this scenario? Am I forced making separate builds and by that different WARs or do I have to separate Managed Servers or Domains wihtin the server or is there a better way to solve it?
I know this thread is very old,but replying so that it may help someone with the same question stumbling on this thread.
The latest weblogic 12.2.1 comes with Multi-tenancy(add-on I guess) which can let you run same applications in a single domain.
Edit: Weblogic 12.2.1 introduced concept called Partitions. Partitions are both config and run-time subdivision of a weblogic Domain. In a single weblogic domain you can create multiple partitions. Each partition will have one or more resource groups. Resource groups are the logical grouping of weblogic resorces like data sources,jms,Java EE apps ,etc. For example to achieve what the original posts asked for , we create a Resource Group template with the web-application and the datasource as the resources. In the Data source configuration we can provide a place holder variable instead of actual URL as DB URL. Then we can create two partitions that refers to this Resource Group Template(Each partition will now have a separate web application and data source) . Each partition will override the DB URL property there by creating two data sources with same JNDI name.In each Partition we create virtual host/port so that the client can use that to access the application running in the respective partitions.
A better and more detailed information on this can be found in https://blogs.oracle.com/WebLogicServer/entry/domain_partitions_for_multi_tenancy
ServletContextListener.contextInitialized can look at the ServletContext and figure out which deployment is which
in web.xml, define a servlet context listener:
<listener>
<listener-class>com.path.YourServletContextListener</listener-class>
</listener>
and then in YourServletContextListener.java, add a contextInitialized method like this:
public void contextInitialized(ServletContextEvent sce)
{
ServletContext sc = sce.getServletContext();
String name = sc.getContextPath();
...
}
my thought is that you can use that name to select from multiple data sources that you have configured. depending on how you've been deployed, you'll make a different database connection and have the correct application's data.
It seems to me from what I saw in the Oracle documentation, that having several domains is the only way to separate data sources with the same persistence unit name - which is bad, since this basically means running two WLS in parallel.
For this reason I decided to go with building individual WAR files (which I tried to avoid initially), to include customer-specific persistence.xml files and specifying customer-specific datasources in the WLS.

JavaEE solution configuration best practices

We build 3-tier enterprise solutions that typically consists of several webapp and ejbjar modules that all talk to a db and have several external integration points.
Each module typically needs its own configurations that can change over the solution's life time.
Deploying it becomes a nightmare because now we have 18 property files that must be remembered to copied over and configured also setting up data-sources, queues, memory requirements etc.
I'm hopeful but not optimistic that there can be a better way.
Some options we've considered/used, each with it's pros and cons:
Use multiple maven projects and continuous integration (eg. hudson or jenkins) to build a configuration jar that includes all the property files for each environment (dev, qa, prod) and then bundle everything up as an EAR. But then things can't be easily changed in production when needed.
Put most of the settings in the DB and have a simple screen to modify it. Internally we can have a generic configuration service EJB that can read and modify the values. Each module can have a custom extended version that have specific getters and setter.
Version control all the property files then check it out on production and check it into a production branch after making changes.
With all of these you still need to configure data-sources and queues etc. in a container specific way :(
Сonsider binding a custom configuration object to JNDI. Then lookup this object in your apps to configure them. Benefits - you can use custom configuration object instead of rather generic Map or Properties.
Another way is to use JMX to configure applications you need. Benefits - you can bind objects you have to configure directly to MBean Server and then use such a well-known tools as jconsole or visualvm to configure components of your application.
Both ways support dynamic reconfiguration of your applications at runtime. I would prefer using JMX.
I've gone through several cycles of finding ways to do this. I still don't have a definite answer.
The last cycle ended up with a process based on properties files. The idea was that each server instance was configured with a single properties file that configured everything. That file was read by the startup scripts, to set memory parameters, by the app server, and by the application itself.
The key thing, though, was that this file was not managed directly. Rather, it was a product of the build process. We had a range of files for different purposes, kept in version control, and a build step which merged the appropriate ones. This lets you factor out commonalities that are shared along various axes.
For example, we had development, continuous integration, QA, UAT, staging, and production environments, each with its own database. Servers in different environments needed different database settings, but each server in a given environment used the same settings. So, there was something like a development-db.properties, qa-db.properties, and so on. In each environment, we had several kinds of servers - web servers, content management servers, batch process servers, etc. Each had JVM settings, for heap size and so on, that were different to other kinds of servers, but consistent between servers across environments. So, we had something like web-jvm.properties, cms-jvm.properties, batch-jvm.properties, and so on. We also had a way to have overrides for specific systems - production-cms-jvm.properties sort of thing. We also had a common.properties that set common properties, and sensible defaults which could be overridden where needed.
Our build process was actually a bit more complicated than just picking the right options from each set; we had a master file for each server in each environment which specified which other files to include. We allowed files to specify other files to include, so we could build a graph of imports to maximise reuse.
It ended up being quite complicated. Too complicated, i think. But it did work, and it did make it very, very easy to make changes affecting many servers in a controlled way. We even merged a set of input files from development, and another from operations, which contained sensitive information. It was a very flexible approach.
I know this has already been answered and my answer is not necessarily generic, but here's my take on things:
Note, here I'm only considering system/resource properties, not application settings. In my view, application settings (such as a payment threshold or other settings should be stored in a database, so that the system can be reconfigured without having to restart a service or cause downtime by re-deploying or re-reading a properties file).
For settings that impact on how different parts of a system connect with each other (such as web service endpoints, etc), I would make use of the JNDI tree.
Database connectivity and JMS connectivity would then be set-up using the Websphere console and can be managed by the Websphere administrators. These can also be created as JACL scripts which can be put into version control if necessary.
In addition to the JNDI resources, for additional properties, such as usernames for web service calls to a backend, etc, I would use Websphere "Name Space Bindings". These bindings can be edited using the Websphere console and accessed via JNDI using the "cell/persistent/mypassword" name.
So I could create the "mypassword" binding (a string), and the management for it falls to the Websphere admin (away from developer eyes or other people who should not have access to production systems), while the same EAR file can be used on dev, test, preproduction and production (which is preferable to have different EAR files for different systems, as the likelihood of other differences creeping in is reduced).
The Java code would then use a simple JNDI lookup (and possibly cache the value in memory).
Advantages over properties files:
Not having a "vulnerable" file that would need to be secured because system properties contain passwords.
Not having to add Java security policies to allow access to that file location
Advantages over database properties:
Not tied to having one database tied to an application server.
Hope that helps
Use multiple maven projects and continuous integration (eg. hudson or
jenkins) to build a configuration jar that includes all the property
files for each environment (dev, qa, prod) and then bundle everything
up as an EAR. But then things can't be easily changed in production
when needed.
I think the config should be in the database of the application instance. Your local machine config may be diffrent to dev and to QA, PROD , DR etc.
What you need is a way of getting the config out the database in a simple way.
I create a separate project with a provided dependency of Apache commons-configuration
It has many ways of storing data, but I like databases and the configurations lives in the database environment.
import javax.sql.DataSource;
import org.apache.commons.configuration.DatabaseConfiguration;
public class MYConfig extends DatabaseConfiguration {
public MYConfig(DataSource datasource) {
super(datasource, "TABLE_CONFIG", "PROP_KEY", "PROP_VALUE");
}
}
Put most of the settings in the DB and have a simple screen to modify
it. Internally we can have a generic configuration service EJB that
can read and modify the values. Each module can have a custom extended
version that have specific getters and setter.
Commons configurations as a simple API, you may then write the GUI as you wish.
You can do the interface in anyway you wish. Or as a quick win have no interface.
Version control all the property files then check it out on production
and check it into a production branch after making changes.
Version control is great. Add another DatabaseConfiguration using composition. The class you extends is the active config and the composed one being the audit. There is another constructor can can have a version. Just overload the right methods to get the desired effect.
import javax.sql.DataSource;
import org.apache.commons.configuration.DatabaseConfiguration;
public class MYConfig extends DatabaseConfiguration {
final DatabaseConfiguration audit;
public MYConfig(DataSource datasource) {
super(datasource, "TABLE_CONFIG", "PROP_KEY", "PROP_VALUE");
audit = new DatabaseConfiguration("TABLE_CONFIG_AUDIT", "PROP_KEY", "PROP_VALUE");
}
#Override
public void addProperty(String key, Object value) {
Object wasValue = super.getProperty(key);
super.addProperty(key, value);
audit.put(key,wasValue);//add version code
}
}
http://commons.apache.org/proper/commons-configuration/
User a simple database table (Section, Key, Value). Add "Version" if you need it, and wrap the entire thing in a simple ConfigurationService class with methods like getInt(String section, String key)
Not a lot of work, and it makes the application code very neat, and tweaking with the configuration very easy.
Interesting alternative config file format: write a scala trait. Your config file can then just be a scala file that you compile and evaluate when the server starts.
http://robey.lag.net//2012/03/26/why-config.html

Categories