Skip navigation.

Notes to self

Whatever I feel like writing

Posts tagged with "deployment"

Permgen: Our Workable solution.

, , , ...

The majority of the visitors to this blog, I just noticed, come here because they are interested in my permgen saga:

  1. Good Riddance, PermGen OutOfMemoryError!
  2. PermGen Strikes Back!
  3. Return of the PermGen


The last installment concluded with newfound hope in the JDK6 profiling tools and a promise to post back as more knowledge was uncovered. Well... that was a while ago.

So, why haven't I spent time blogging about all of the exciting findings I must have made along my quest to solve this problem, since the 29th of September, 2007? The answer is simple: I have not spent any time at all on this problem. The reason for this lack of effort is simple: permgens have not been a problem to me since about that time.

To properly explain what has happened, let me draw a parallel to writing code - multi-threaded code, to be presice: What is the primary concern in multi-threaded/concurrent code? Shared mutable state. The easiest way to solve this problem? Do not share state, or make shared state immutable.

Neither of these proposed solutions actually solve the problem of shared mutable state. Instead they remove it; make the problem moot - a non-issue.

I have not solved the permgen problem; I have made it moot. Well, the operations department have made it moot and I have been cheering from the side-line.

The Moot Permgen:

Recall the original problem: every so often we redeploy a Java web application on our application servers, without restarting said servers. An intricate object graph prevents the old class files from being unloaded, this equates to a memory leak in the permanent generation of the JVM that eventually causes the server to die with an OutOfMemoryError.

The thing that gets the hair ball rolling here, is the deployment without restarting the server. To make this problem moot, all we have to do is to always restart the server every time we deploy an application.

Simple, right?

It's like when you go to the doctor and say "It hurts when I do this" and the doctor says "Well, don't do that." Same exact thing. Deployment without a restart: Just stop it!

The Other Way around the problem:

We basically changed the way we deploy applications. Not in a big way, just some small adjustments.

First and foremost, we don't deploy anything without restarting the server - but you already knew that.

Second, we deploy less stuff on our servers - the fewer apps you run on a server, the faster it'll restart. Preferably, we would only run one application per JVM- this way, the restartes would only affect a single application.

Lastly, we're moving our production systems to load-balanced setups. When an application is running on two (or more) servers behind a load-balancer, then restarting a server won't incur any down-time.

It's not rocket science. It's a practical and workable way to simply avoid having to deal with the dreaded OutOfMemoryError: permgen.

Fabric 0.0.2 Released.

, ,

Here's a sorry-for-previous-release-not-working-release; It's Fabric 0.0.2.

Hopefully it won't crash and burn as much...

Here's what's new:
  • lots of minor tweaks to the innards to make it a little less hacky (still plenty to do in that regard).
  • added a new download() operation; like put, but the other way around.
  • local() and local_per_host() operations now halt fabric if whatever they happen to be executing terminates with an exit_code != 0.
  • load() shoul now print a nicer message if no fabfile is found.
Appart from that, I've done work on a new and improved (!) shell command, but it's not ready for this version (maybe next). Also worked a little on unittesting this baby, but I haven't got much to show for that, either.

Fabric 0.0.1 Released!

, ,

Last Sunday, after little more than two weeks of work, Fabric version 0.0.1 was been released. The main goal of this the very first release was to just get something out the door, and I must admit that some pretty horroble bugs made it through the cracks.

Fabric had most of its core functionality in place after just three days. Then came a period of polishing and bug squashing, and finally a lot of work on the help system and the distribution tool-chain these past four days.

I'll be celebrating this first release by transitioning Fabric from Pre-Alpha to Alpha. Also, I'de like to state my intend on release the cycles; that if anything at all has happened on Fabric since last release, then push a new version out the door every two weeks. The big idea is, that if I can just maintain this rythm, then the project is bound to move forward and not die out, regardless of how fast or slow the work progresses.

I'de like to make clear what version-numbering scheme I intend to use:
Before 1.0:
0.0.1 = First release
0.-.X = Backwards compatible update
0.X.0 = Backwards incompatible update

After 1.0:
-.-.X = Update without interface changes
-.X.0 = Update with backwards compatible interface additions
X.0.0 = Backwards incompatible update

And that's it for now. See you in two weeks, if not sooner.

ANN: Fabric - Simple pythonic remote deployment tool.

, , ,

Deployment woes.

I code in Java at work, and all of my projects can be divided into two camps:
  1. Those that build to .jar files and deploy to our maven2 repo.
  2. And those that build to .war files and are deployed to some application server.


Once configured, maven itself is pretty good at making case #1 run smoothly - "mvn deploy" is all it really takes. But do I have anything similar for case #2?

Well, not quite. I tried banging something together with Capistrano, but that didn't work. For one thing, Capistrano expects you to be deploying a Rails application and these are typically all deployed in the same way, which is very different from deploying a .war file. Secondly, I had a build/compile step in my process that I needed to do locally (because compiling on the server is troublesome and a bad idea), this meant that I had to use the put function to upload my .war file. Put worked nicely for small text files (ie. my project.properties file), but failed miserably when the payload war a near 20 MB heavy .war file.
Googling and tweaking the flags on the File object didn't work. It simply refused to upload that damn .war file.

Itch-scratchers mentality.

I suppose I could have written a shell script and leveraged the existing scp and ssh tool chain. And I did throw a pebble down this route to see how it felt, but eventually rejected the idea. The reason is that I'm deploying to multiple hosts simultaneously. I tried looking at clusterssh to see if it would help me in this regard, but it turned out to be odd, klonky and basicly not designed for such a task. I also took a look at Dancer's Shell, dsh, which was a lot closer to home, but my username contains a backslash and dsh meticulously stripped it out prior to logging in, foiling any and all of my attempts at tricking it into taking it at face value.

What was I suppose to do? I had pretty much given up on automating the process and started to accept defeat, when I happened upon the paramiko module for python. Paramiko is a pure python implementation of the SSH 2 protocol, and lets you log into servers, execute commands and upload files. It prompted me to the idea to write my own pythonic version of a Capistrano like tool, and then use that for deployment. It could be made open source and a perfect oppotunity try out Git on a real project.

Birth of Fabric.

So I swiftly went to work. In two days, I had written the first prototype. It supported the most basic operations such as running remote shell commands, sudo'ing and uploading files. Then I registered my project on nongnu.org (chosen because of their Git support). And ba-da-bim, Fabric became an open source project: https://savannah.nongnu.org/projects/fab/

Fabric looks, on the surface at least (or for those who've only spent a short while with either), a lot like Capistrano. You have a fabfile (as oppose to a capfile) in you project directory, and that file describes all of your deployment tasks (or commands, in Fabric speak).

Commands are really just regular python functions (and you're allowed to call it fabfile.py if you like) that simply makes calls to some other, more magical, functions called operations. Operations are magical because they just sort of exist; you don't import them from a module and don't find them in an object - you just call them.

So, to get the feet wet, here's a hello-world'ish simple fabfile:
set(
    fab_user = 'joe.shmoe',
    fab_mode = 'rolling', # run stuff on one host at a time
    fab_hosts = ['node1.servers.com', 'node2.servers.com'],
)

def deploy():
    "Build and deploy a war file to our app. servers."
    local("mvn clean package")
    put("target/myapp.war", "myapp.war")
    run("mkdir /rollback/$(fab_timestamp)")
    run("cp /$(fab_host)/deply/myapp.war /rollback/$(fab_timestamp)/myapp.war")
    sudo("cp myapp.war /$(fab_host)/deploy/myapp.war")
    sudo("$(fab_host) restart")


Then, all it takes to deploy is a "fab deploy" in the directory where the above file is found. It's still pretty basic, low-level and imparative, but it's a good start.

Fabric also has a built in help system that is powered by your doc-strings; try typing "fab help:deploy" for instance. If you want to see what other commands are availble to you, then simply type "fab list". You can also get a list of operations (the local(), put(), run(), sudo() kind of things) by typing "fab help:ops" and get more details about the individual operation with, for instance, "fab help:put".

And that's basically it for today.