git clone git://github.com/infinispan/infinispan-labs.git
This lab was developed for Devoxx 2011, by Pete Muir, Mircea Markus and Sanne Grinovero. It is designed to last around 1h 45m, and has an accompanying introduction and conclusion. Full slide deck is attached.
The lab has been updated by Galder Zamarreño for Infinispan 5.1 and has been featured in the Neuchatel JBUG and JUDCon India 2012
presented by Pete
5 minutes
Using Infinispan 5.1.0.FINAL
Download the lab zip from
[...]
Unzip the lab to your disk to a location of your choice
If you are a git user, you can clone the repository:
git clone git://github.com/infinispan/infinispan-labs.git
each stage of this lab has a checkpoint which is a branch, you can check out the code for each Checkpoint using. Checkpoints are mentioned in these instructions:
git checkout -b checkpointX checkpointX
Download JBoss AS 7.1.0.CR1b from http://jboss.org/jbossas/downloads
Unzip JBoss AS to your disk to a location of your choice
slides, presented by Pete
20 minutes
presented by Pete
5 minutes
The lab is a simple ticket allocation and booking system
lab1 contains a project skeleton with the relevant dependencies available. It is a war, that can be deployed on JBoss AS 7. It also use CDI to wire together the app, and JSF for the view layer. JMS is used to provide messaging and EJB to provide a listener for messages we send via JMS.
In another console, start JBoss AS - $JBOSS_HOME/bin/standalone.sh
Deploy the project to JBoss AS 7 using mvn clean package jboss-as:deploy
All cache operations hidden by service layer to allow us to swap out caching impls
Starts with a HashMap and builds on that
Import the project into your IDE, we use Eclipse with m2eclipse installed.
Show project
Checkpoint 1
presented by Pete
5 minutes
Topics covered include:
TODO
presented by Sanne
10 minutes
In LAB_HOME/nic_test there is the the test-network script. Run it.
If all goes well, you'll get two windows in which you can draw up on your screen. Draw on one, see it in both.
Topics covered include:
what is JGroups? library for reliable multicasting ...
main features: fragmentation, retransmission, flow control, reordering, group membership (notifications)
LAN/WAN based: multicast or TCP for transport
presented by Sanne
10 minutes
Use Case: Take advantage of the features of Infinispan
Uncomment the Infinispan dependencies in pom.xml
Copy in Resources.java and TicketAllocationCache.java and explain what they are doing; you will find them in LAB_HOME/lab1/src/samples/java
Explain about configuring caches programmatically with qualifier
Copy SimpleTicketService to InfinispanTicketService
Make SimpleTicketService an alternative
private final List<TicketAllocation> tickets = new ArrayList<TicketAllocation>();
with
@Inject @TicketAllocationCache private Cache<String, TicketAllocation> tickets;
to inject the Infinispan cache. Change the allocateTicket method to:
TicketAllocation allocation = new TicketAllocation(allocatedTo, event); tickets.put(allocation.getId(), allocation);
and change the getAllocatedTickets() method to
return new ArrayList<TicketAllocation>(tickets.values());
and change the getTicketAllocation(String id) method to:
return tickets.get(id);
Implement getNodeId() properly:
if (tickets.getConfiguration().getCacheMode() != CacheMode.LOCAL) return tickets.getAdvancedCache().getCacheManager().getAddress().toString(); else return "local cache";
Implement getOwners() properly:
if (tickets.getConfiguration().getCacheMode() != CacheMode.LOCAL) { return asCommaSeparatedList(tickets.getAdvancedCache().getDistributionManager().locate(key)); } else { return "local"; }
Use Case: Can see how our cache is performing
Enable JMX - add .jmxStatistics().enable() to the fluent configuration in Resources.
Redeploy, and use the app
We can see the cache starting in the console
Run jconsole or jvisualvm, and select the "jboss-modules" process
Open up the Infinispan statistics (via MBeans tab in jvisualvm - you might need to install the MBeans plugin first)
Allocate a ticket, show the stores change
Checkpoint 2
presented by Mircea
10 minutes
Topics covered include:
API
Configuration
Use cases
Available eviction mechanisms
Use Case: Have ticket allocations freed up after a period of time*
Add expiration to allocateTicket(), so you end up with
tickets.put(allocation.getId(), allocation, 10, TimeUnit.SECONDS);
Run the demo, and you can see that entries disappear after 10s
Checkpoint 3
presented by Mircea
10 minutes
Use case: Prevent known ticket touts from using the system
First, copy in the AbuseListener in
Now, we need to register it
Add
@Inject public void registerAbuseListener(@New AbuseListener abuseListener) { tickets.addListener(abuseListener); }
to the InfinispanTicketService.
this code simply creates a new abuse listener (injected by CDI with a logger!) and registers it with Infinispan. It will do it automatically when the InfinispanTicketService is created
Increase expiration to 3 minutes, otherwise the demo will get tiresome!
Checkpoint 4
presented by Mircea
15 minutes
Use Case: When ticket is booked, need to atomically take payment and book ticket, and rollback if any errors
The webapp collects all the data from the user to process the booking, and then sends the booking to the backend using JMS.
JBoss comes with a "test" queue, we'll abuse that so we don't have to configure messaging (not what we are here to talk about).
Go to the pom.xml and uncomment JMS dependency
Copy the PaymentProcessor into .services
Inject JMS into InfinispanTicketService
@Resource(mappedName="/ConnectionFactory") private ConnectionFactory cf; @Resource(mappedName = "queue/test") private Queue queue;
Implement the bookTicket method
try { Connection connection = cf.createConnection(); Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE); MessageProducer publisher = session.createProducer(queue); connection.start(); TextMessage message = session.createTextMessage("Book ticket for " + id); publisher.send(message); connection.close(); session.close(); } catch (JMSException e) { throw new RuntimeException(e); }
This code is in bookTicket.txt in the samples
Run the example, show it in action.
Checkpoint 5a
Use case: Introduce XA transactions
Add to the configuration (Resources.configureCache):
.transaction().transactionMode(TransactionMode.TRANSACTIONAL) .transaction().transactionManagerLookup(new GenericTransactionManagerLookup())
Replace the injection of the Connection Factory with
@Resource(mappedName="/JmsXA") private XAConnectionFactory cf; @Resource(mappedName = "java:jboss/TransactionManager") private TransactionManager tm;
finally, upgrade the bookTicket method:
try { XAConnection connection = null; try { connection = cf.createXAConnection(); connection.start(); XASession xaSession = connection.createXASession(); Session session = xaSession.getSession(); MessageProducer publisher = session.createProducer(queue); TextMessage message = session.createTextMessage("Book ticket for " + id); tm.begin(); tm.getTransaction().enlistResource(xaSession.getXAResource()); //following two ops need to be atomic (XA) tickets.remove(id); publisher.send(message); tm.commit(); } finally { if (connection != null) connection.close(); } } catch (Throwable e) { // ignore - don't do this at home :) e.printStackTrace(); }
Interlude - Transactions deep dive
Topics discussed include
Transaction types
Locking
Deadlock detection
15 minutes
presented by Sanne
15 minutes
Use case: we have so many tickets being allocated we've run out of heap on one machine, so add some more!
During the break we added support for distribution. Take you through the changes now
Enable distribution mode in Resources
.clustering() .mode(CacheMode.DIST_SYNC) .l1().disable()
Make JGroups use the loopback interface to avoid network problems! Add
@Produces @ApplicationScoped public EmbeddedCacheManager configureCacheManager() { return new DefaultCacheManager( GlobalConfigurationBuilder.defaultClusteredBuilder() .transport() .addProperty("configurationFile", "jgroups.xml") .build()); }
Add jgroups.xml from src/sample to src/main/resources (directory needs creating)
Explain that this JGroups file is exactly as normal for UDP, except that the jgroups.bind_addr is set to the loopback interface
Topics discussed include:
Introduce AS7
Cover domain mode vs standalone
Domain mode a great way to stand up a cluster of nodes!
Explain management options (CLI, web, maven plugin, XML, filesystem)
Talk about Infinispan as managed service in AS7 vs embedded - we could have used either, but to get started quickly it's easy to embed!
Show 5 servers configured in $JBOSS_HOME/domain/configuration/host.xml - explain about port bindings. If you are following along, add only these servers
<servers> <server name="server-one" group="main-server-group"> <!-- server-one inherits the default socket-group declared in the server-group --> </server> <server name="server-two" group="main-server-group" auto-start="true"> <!-- server-two avoids port conflicts by incrementing the ports in the default socket-group declared in the server-group --> <socket-binding-group ref="standard-sockets" port-offset="100"/> </server> <server name="server-three" group="main-server-group" auto-start="true"> <!-- server-two avoids port conflicts by incrementing the ports in the default socket-group declared in the server-group --> <socket-binding-group ref="standard-sockets" port-offset="200"/> </server> <server name="server-four" group="main-server-group" auto-start="true"> <!-- server-two avoids port conflicts by incrementing the ports in the default socket-group declared in the server-group --> <socket-binding-group ref="standard-sockets" port-offset="300"/> </server> <server name="server-five" group="rest-server-group" auto-start="true"> <!-- server-two avoids port conflicts by incrementing the ports in the default socket-group declared in the server-group --> <socket-binding-group ref="standard-sockets" port-offset="1000"/> </server> </servers>
Now, define the server groups. We'll also add server group for the REST interface which we'll see in a minute:
<server-groups> <server-group name="main-server-group" profile="default"> <jvm name="default"> <heap size="64m" max-size="512m"/> <permgen size="128m"/> </jvm> <socket-binding-group ref="standard-sockets"/> </server-group> <server-group name="rest-server-group" profile="default"> <jvm name="default"> <heap size="64m" max-size="512m"/> <permgen size="128m"/> </jvm> <socket-binding-group ref="standard-sockets"/> </server-group> </server-groups>
Note that nodes don't get much memory by default, we need to increase it
Start up 4 JBoss AS 7 nodes with domain.sh. Why? See the JBoss 7 Getting Started guide
Build latest using mvn package and in another terminal change into the project and bring up JBoss AS CLI $JBOSS_HOME/bin/jboss-admin.sh --connect
Deploy app from console using deploy target/lab1.war --server-groups=main-server-group
App now deployed to each node
bring up all 4 nodes in a web browser (port offset 100)
show each node starting in the console log
the contents list now just shows whats locally in the cache
explain that as each node comes up, the entries are rehashed to distribute the contents, so we see entries disappear from a node
show that we can still find any entry, it's just not local any more
show that we can put an entry, and then find it in one of the caches in Infinispan (10 mins)
Topics discussed include:
What are the different modes?
When would you use the modes?
How does distribution work?
Explain CH, benefits and problems
Talk about vnodes to even distribution
presented by Sanne
5 minutes
Explain benefits (TODO)
Start up 4 JBoss AS 7 nodes with $JBOSS_HOME/bin/domain.sh
Build latest using mvn package and in another terminal change into the project and bring up JBoss AS CLI jboss-admin.sh --connect
Deploy app from console using deploy target/lab1.war --server-groups=main-server-group
App now deployed to each node
bring up all 4 nodes in a web browser (port offset 100)
Just like before, except that nodes 1 & 2 are still showing all entries locally (they kept them in their cache)
Find a node that doesn't have all entries, and query for an entry that isn't on that node. Then hit refresh. Show that this time it's now local (L1 cache)
Show the same for putting a new entry - keep adding until you get one that isn't owned by the current node - show that it is in the local node still.
Checkpoint 6
presented by Mircea
10 minutes
We have a server group set up in JBoss AS 7 that contains a single server. We'll use this for the rest server - no need to have one on each node!
Enter jboss admin console and connect to the local server: $JBOSS_HOME/bin/jboss-admin.sh. The type "connect".
Deploy infinispan-server-rest.war from the lab to JBoss AS 7 using the JBoss AS 7 CLI deploy <path/to/>infinispan-server-rest.war --server-groups=rest-server-group
REST server actually joins the Infinispan cluster as a node, and it needs to know which caches to use, so we added this to the war, and we also needed to add the domain class* * * Visit a couple of the UIs to seed data and start caches
check that connection REST is correctly deployed: http://localhost:8080/infinispan-server-rest/
Use a rest client to GET http://localhost:9080/infinispan-server-rest/rest/ticketAllocationCache/manik-Best%20of%20Abba
Topics discussed include:
various server endpoints
benefits of Hot Rod
presented by Mircea
10 minutes
Use case: Persist your data to disk in case of node restart
paste the JDBC cache config method from src/sample/java/jdbc.txt
Walk through the JDBC cache store set up code
Add this to the configuration:
.loaders() .shared(true) .addCacheLoader() .cacheLoader(new JdbcStringBasedCacheStore()) .addProperty("connectionFactoryClass", "org.infinispan.loaders.jdbc.connectionfactory.ManagedConnectionFactory") .addProperty("datasourceJndiLocation", "java:jboss/datasources/ExampleDS") .addProperty("idColumnType", "VARCHAR(255)") .addProperty("idColumnName", "ID_COLUMN") .addProperty("dataColumnType", "BINARY") .addProperty("dataColumnName", "DATA_COLUMN") .addProperty("timestampColumnName", "TIMESTAMP_COLUMN") .addProperty("timestampColumnType", "BIGINT") .addProperty("stringsTableNamePrefix", "persistentStore") .addProperty("userName", "sa") .addProperty("password", "sa") .async().threadPoolSize(10)
Run mvn clean package
Deploy the app using deploy lab1/target/lab1.war --server-groups=main-server-group
Explain we are using the JBoss AS 7 built in example data source for H2 - configuration found in domain.xml.
Vist a node or two to setup some caches and data
Explain we are using the h2console.war. Needed a couple of changes to make it run, documentation coming soon
Deploy it using deploy h2console.war --server-groups=main-server-group - each node in the cluster owns some data, each h2 database will back that up
Log in sa with password sa
execute select * from persistentstore_ticketallocationcache
Checkpoint 7
Topics discussed include:
Modes of cache store usage
CacheStores available as built in
presented by Sanne
8 minutes
Topics discussed include:
TODO
presented by Sanne
2 minutes
Topics discussed include:
TODO
presented by Pete
5 minutes
Topics discussed include:
TODO
Introducing project Radargun
presented by Mircea
5 minutes
presented by Pete
10 minutes