see me rollin, they hatin

Posted by Dick on August 09, 2008

(I have avoided that cliche all year, give me a break)

I’ve run various releases of Roller on various Glassfish versions, and am pretty happy with what I’ve settled on.

Here are some gotchas it’s taken me a while to Google fixes for.

Glassfish v2

Glassfish v3 is going to be awesome when it’s done, but it’s not a production release.
Get the Sun-branded release – it’s the same codebase, but has a pretty installer and the
option of commercial support down the line if you ever need it.

Roller bowler bowler penny a pitch

Roller 3 is obsolete now and clanky to setup. 4.0 is much much easier to deploy (the install guide even has instructions for Glossfish2), but JavaMail only works on 4.0.1. Dave Johnson (snoopdave, Roller developer) made a pre-built Roller 4.0.1 tarball available a while back.

It’s good, you should use it.

friends don’t let friends use DB2

No-one uses DB2 unless they’re forced to (no-one you’d want to talk to, anyway).
Roller hates it even more than I do. Avoid it unless you enjoy pain.

Better options I’ve tried are:

  • PostgreSQL works fine with Roller I love it (but it can be tricky to cluster)
  • MySQL is what most Roller guys use. I can’t bring myself to recommend it (we have previous) but I’d expect less Roller bugs talking to it.
  • we’re currently on an Oracle 10g backend, it works so far. Someone else supports it, so that’s ok with me.
  • Derby/JavaDB worked well enough, but it’s CLI is pretty dreadful (cheers IBM) and you might need to shell into it one day. Good within NetBeans, when you’re too lazy to install a real DB (did I mention the PostgreSQl installer yet)?

fustercluck

Glassfish clusters are easy to setup and actually fun to look after.
Roller clusters are a different kind of fun.

Out of the box, Roller will do horrible things to you if you try to cluster it.
My favourites (so far)

  • search is broken
  • caching doesn’t work (well, it caches, it jut does it inconsistently on random nodes)
  • scheduled tasks get run twice or not at all, often corrupting your schedule as they do it
  • file uploads need a shared filestore.

I got round these with the following roller-custom.properties:


# hook in an external search engine instead
search.enabled=false

# these should be mounted from a reliable fileserver
uploads.dir=/glassfish/uploads
planet.aggregator.cache.dir=/glassfish/planet

# memcache instead of file-cache, scales better anyway
#
# see my last post for details
#
cache.defaultFactory=net.java.roller.tools.cache.memcached.MemcachedLRUCacheFactoryImpl
cache.memcached.default.servers=clusternode1:11211,clusternode2:11211
# it's a bit verbose by default
log4j.category.net.java.roller.tools.cache.memcached=INFO

# give each node a unique clientId - see below
config.expandedProperties=uploads.dir,search.index.dir,tasks.clientId
tasks.clientId=${roller.nodename}

wait, what?

tasks.clientId needs to be unique for each node in your Roller cluster.
Since we run the same WARfile on each node, we make that an alias to a JVM system property, ‘roller.nodename’, that’s different on each cluster node.

In Glassfish, you can do this by creating a cluster-wide JVM option which is set to a system property, and give each server instance a different value for system property.

Assuming we have a cluster called ‘rollercluster’ with 2 server instances ‘instance01’ and ‘instance02’, this should do the trick:

asadmin create-jvm-options --target roller-cluster '-Droller.nodename=${NODENAME}'
Command create-jvm-options executed successfully.
asadmin create-system-properties --target instance01 NODENAME=instance01
Command create-system-properties executed successfully.
asadmin create-system-properties --target instance02 NODENAME=instance02
Command create-system-properties executed successfully.

Restart your server instances, and
‘ps’ should show ‘-Droller.nodename=instance02’ on the server running instance02.

(Thanks to Anil Gangolli and Kedar Mhaswade on the roller and glassfish lists for helping figure this out)

memcached on solaris 10 for Roller4

Posted by Dick on August 08, 2008

I have a 2-node Glassfishv2 cluster running Roller 4 on Solaris 10
and discovered (the hard way) that memcached is the only safe caching option .

If you’re trying to run Roller on a Glassfish cluster, do yourself a favour and skim over
this checklist. You’ll thank me later, honest.

install memcached

(If you’re running Solaris Express or OpenSolaris, you can skip this bit.)

It’s part of Coolstack now (ignore the page banners, it’s for Solaris Intel as well).
They have a boatload of other things too
(Squid, Ruby, lighttpd and – ooh! – nginx), but I’m trying to stay focussed here.

I pkgadded CSKmemcached_1.3RC1_i386.pkg.bz2 on both nodes.
Bizarrely, the package didn’t include SMF bits, so I tweaked the ones from SXCE.
Help yourself:

curl -O http://files.hellooperator.net/solaris/smf/memcached
cp memcached /lib/svc/method
chmod +x memcached
curl -O http://files.hellooperator.net/solaris/smf/memcached.xml
cp memcached.xml /var/svc/manifest/application/database
svccfg import /var/svc/manifest/application/database/memcached.xml

tweak and enable memcached

I’m giving it 1 Gb of RAM for starters, tweak the “setprop” line below if you want to change it.

bash-3.00# svccfg -s memcached
svc:/application/database/memcached> setprop memcached/options=("-u" "nobody" "-m" "1024")
svc:/application/database/memcached> quit
bash-3.00# svcadm refresh memcached
bash-3.00# svcadm enable memcached

hook up Roller

First, add the roller memcached plugin to your WARfile:

wget https://roller.dev.java.net/files/documents/190/88023/roller-memcached-4.0.tar.gz
gzip -dc roller-memcached-4.0.tar.gz | tar xf -
cp roller-memcached/* $ROLLER_DIR/WEB-INF/lib

Then add this to $ROLLER_DIR/WEB-INF/class/roller-custom.properties


# Rollers caches aren't cluster safe, so use memcache instead
cache.defaultFactory=net.java.roller.tools.cache.memcached.MemcachedLRUCacheFactoryImpl
# any whitespace in this line will waste your afternoon
cache.memcached.default.servers=clusternode1:11211,clusternode2:11211
#debugging
log4j.category.net.java.roller.tools.cache.memcached=DEBUG

The other howtos I’ve seen all specify MemcachedLRUCacheFactory, which gave me ClassNotFoundExceptions (probably because it doesn’t exist?) -
the one above works fine.

Then rebuild your WARfile and redeploy.

Requests/sec has shot up from about 25/sec to over 350/sec, and it can stand a much higher concurrency level now (if you need a quick benchmarking tool, Siege builds well on OSX).
I trashed the webapp and rebuilt it yesterday (swapped out our awful DB2 backend for a proper database) and needed to svcadm restart memcached, but other than that it’s fire-n-forget.

 

(Credits : Dave Johnson is the Roller God, Trond Norbye wrote the SXCE SMF bits)

Roller 4 on Glassfish v3

Posted by Dick on May 20, 2008

I did Roller 3 on Glassfish 2 a while back
so thought that’d be the simplest thing to put on Glassfish3. The process has got quite a bit easier.

get roller

curl -O http://www.mirrorservice.org/sites/ftp.apache.org/roller/roller-4/v4.0.0/bin/apache-roller-4.0.zip
unzip apache-roller-4.0.zip

If you want to be able to send mail you’ll need Roller 4.0.1 (a bug in 4.0 breaks JavaMail on Glassfish).

setup an empty database

Roller4 isn’t perfect, but it kicks ass when it comes to auto-generating its
own database tables. It still needs the actual database to exist, though:

asadmin create-jdbc-connection-pool \
--datasourceclassname org.apache.derby.jdbc.EmbeddedDataSource \
--property databaseName=\$\{com.sun.aas.instanceRoot\}/databases/rollerdb:\
connectionAttributes=\;create\\=true rollerpool
asadmin ping-connection-pool rollerpool
asadmin create-jdbc-resource --connectionpoolid=rollerpool jdbc/rollerdb

(those of you playing along at home on an embedded database should look at upping your PermGen space at this point).

tweak roller

Roller 4 uses JNDI to find its DB by default, so there isn’t much to tweak:

cd ~/apache-roller-4.0/webapp/roller/WEB-INF/classes
curl -O http://files.hellooperator.net/glassfish/webapps/roller-custom.properties

You’ll want to change the mailserver to one you can use.

The full bewildering list of possible roller properties is in the Install Guide

You should make these changes to security.xml, too (unless you’re on Debian in which case, why bother?hee hee).

make and deploy a WAR

cd ~/apache-roller-4.0/webapp/roller
jar cvf ~/roller.war *
asadmin deploy ~/roller.war

Browse to http://localhost:8080/roller and try it out.

The database is created when you first connect, and the first user you make is the site admin.

passing JVM options to Glassfish

Posted by Dick on May 20, 2008

One downside to embedding your database server is that Glassfish needs more memory.

I’d been messing around with a few webapps and yesterday got Roller4 running. After a few clicks around the app, I started to see ‘PermGen space: java.lang.OutOfMemoryError’ errors. 

 

More power, Doctor

The fix is pretty obvious : have the JVM allocate more PermGen space.

It’s simple to do this through the admin UI ( ‘Application Server’ -> ‘JVM Settings’ -> ‘JVM Options’).

Or you can do it on the command line:

 hypnotoad:~ $ asadmin create-jvm-options \-XX\\:MaxPermSize=128m
created 1 option(s)
Command create-jvm-options executed successfully.
hypnotoad:~ $ 

You need to restart the server for it to actually take effect.

 

JavaDB and Glassfish v3 : to embed or not to embed

Posted by Dick on May 15, 2008

Since writing this, I’ve realised JavaDB is pretty crap. Do yourself a favour and try the decent PostgreSQL installer I found.

 

Glassfish v3 ships with JavaDB (aka Apache Derby aka Cloudscape).
I’ll be using this for trying out Rails and JRuby, but it’s also handy
for things like authentication via JDBC Realms.

A JavaDB database is essentially a directory that only one process can access at a time (a bit like sqlite). This can be Glassfish itself (an embedded database) or a standalone database process (that serves SQL clients over TCP/IP).

Both have pros and cons. I’ll take you through creating both.

option 1: standalone database server

You sure you want JavaDB? There are better options (sorry, can’t help it).

The main benefit to running a network server process is that it’s the only way for multiple clients to access the database simultaneously

(it’s also the only option that makes sense if you were clustering Glassfish).

If you need to create a schema before you deploy a webapp (with NetBeans or ‘rake migrate’)
you’ll have to stop Glassfish first unless you go down this route.

hypnotoad:databases $ asadmin start-database --dbhost 127.0.0.1
Database started in Network Server mode on host 127.0.0.1 and port 1527.
Could not connect to Derby Network Server on host 127.0.0.1 port 1527.
Starting database in the background.
Log redirected to /Users/dick/Applications/glassfishv3-tp2/glassfish/databases/derby.log.
Command start-database executed successfully.

( –dbhost defaults to ‘0.0.0.0’ but this causes problems if you change IP . Stick to 127.0.0.1).

Next, create the connection pool (and associated database - see later).
It’s simplest to do this on the command line (partly due to bug 4889 ):

hypnotoad:databases $ asadmin create-jdbc-connection-pool \
--datasourceclassname=org.apache.derby.jdbc.ClientConnectionPoolDataSource\
--isconnectvalidatereq=true --validationmethod=meta-data \
--property user=GFv3:password=GFv3:databaseName=railsdb:\
connectionAttributes=\;create\\=true \
railspool
Command create-jdbc-connection-pool executed successfully.
  • The ’;create=true’ option tells JavaDB to create the ‘railsdb’ database on demand
  • host:port defaults to localhost:1527
  • username and password can be anything, but are required

We now ‘ping’ the pool. This checks our network connection is good, and has the side-effect
of creating the ‘railsdb’ database:

hypnotoad:databases $ asadmin ping-connection-pool railspool
Command ping-connection-pool executed successfully.
hypnotoad:databases $ ls
derby.log railsdb

option 2. embed Derby in Glassfish

This is my preferred option for several reasons:

  1. it saves having to run 2 JVMs
  2. in development, I don’t mind stopping Glassfish
  3. for production, I want webapps to create their own schema anyway
  4. connection validation and authentication is no longer an issue
  5. sorry to bang on about it, but if you want a standalone database there are much better options

One side effect is that Glassfish is going to use more memory (especially if you have several connection pools configured). You might want to tweak your JVM .

There’s no need to ‘start-database’ in this case – just go ahead and make the pool:

hypnotoad:glassfishv3-tp2 $ asadmin create-jdbc-connection-pool \
--datasourceclassname org.apache.derby.jdbc.EmbeddedDataSource \
--property databaseName=\$\{com.sun.aas.instanceRoot\}/databases/railsdb:\
connectionAttributes=\;create\\=true \
railspool
Command create-jdbc-connection-pool executed successfully.
  • the different DataSource class is what makes it embedded
  • provide a full path in the databaseName attribute to avoid current working directory hell
  • since Glassfish is the database server, we can skip username,password and connection validation options

If we ping the pool, we can see Glassfish creates derby.log and the database dir

hypnotoad:glassfishv3-tp2 $ asadmin ping-connection-pool railspool
Command ping-connection-pool executed successfully.
hypnotoad:glassfishv3-tp2 $ tail derby.log
2008-05-15 11:12:48.770 GMT:
Booting Derby version The Apache Software Foundation – Apache Derby – 10.2.2.1 – (538595): instance c013800d-0119-ec48-424c-000001a39158
on database directory /Users/dick/Applications/glassfishv3-tp2/glassfish/domains/domain1/databases/railsdb
Database Class Loader started – derby.database.classpath=’‘
hypnotoad:glassfishv3-tp2 $

Butler Lampsons mamma didn’t raise no fools

Whichever option you choose, the command to give the pool a JNDI name is the same:

hypnotoad:glassfishv3-tp2 $ asadmin create-jdbc-resource --connectionpoolid=railspool jdbc/railspool
Command create-jdbc-resource executed successfully.

And we’re done. Now simply write a webapp to use the damn thing.