Previous releases of WSO2 Application Server had lazy loading support for Services only. But from WSO2 Application Server 5.0.0 onwards, lazy loading support is added for Applications as-well. This support includes WebApps, JAX-WS/RS Apps and Jaggery Apps.
In a previous post, I explained the importance of maximum utilization of available resources in a multi-tenant cloud environment, which helps fulfill many tenant needs. To achieve this task, the commonly used pattern is Lazy loading. This post explains how lazy loading is implemented in WSO2 Stratos.
As explained in the above post, if the number of artifacts increase, the response time for the first request increases and eventually it gets timeout. Now lets see how the normal deployment works
A set of deployers for all three application types (webapps, jax*-apps, jaggerry-apps) are registered at server startup. The DeploymentEngine of Carbon maintains a collection of those deployers, and then when the tenant initially becomes active, it will call all the deployers to load all the artifacts found in the repository. Then those deployers will deploy all the applications frond in the repository.
As we can see that, this will take a long time if the number of artifacts in the repository is large. To reduce this initial loading time, the GhostDeployment pattern for all artifact types is introduced in WSO2 Application Server from 4.1.2 onwards.
The following diagram depicts the flow of how the Ghost Deployment (GD) works for all Application types. Since all three applications (webapps, jax*-apps, jaggery-apps) are actually Web Applications, their deployers extends from a common deployer called, AbstractWebappDeployer. This deployer handles the deployment or un-deployment of those artifacts. When the GD is enabled, this deployer also acts as the GhostDeployer.
Now lets look at the flow of events of applications when GD is in use.
1. When a new application is deployed, the AbstractWebappDeployer gets invoked and it will first deploy that application using the deploy method of correct deployer.
2. The AbstractWebappDeployer will then pick up that application, and create a simple metadata file which has some basic information needed to create a Ghost Application. This will mainly contain the application name & context name, application type etc. These informations are useful in identifying and dispatching requests at TomcatValve level.
3. The subsequent deployments (on server restart, etc) of the application which was first created in step 2, the AbstractWebappDeployer will pick it up from the metadata file created in step 2 above, and use that for deployment.
4. Using the metafile, the AbstractWebappDeployer will create a Ghost Application which will contain a special parameter (Ghost Parameter) which will identify the appliaction as a Ghost Application, and register that Application into the WebappsHolder. Here the webapps holder is used to store all the current applications that are deployed with the server instance.
5. A request comes in for the application, which at the moment is deployed in Ghost form.
6. There is a special Tomcat Valve called the GhostWebappDeployerValve, which is registered with all other TomcatValves. It will first intercept the request and check the Ghost Parameter added to the application in step 4 above to check whether the Actual application deployment needs to take place, if the current application is a Ghost Application.
7. If the Application is found to be in Ghost form in step 6 above, the GhostWebappDeployerValve will call the AbstractWebappdeployer to carry out the actual application deployment. The AbstractWebappdeployer will do the actual deployment of that artifact.
Apart from this, if some applications are not used for some time or if they are idle, they will be unloaded & reloaded in Ghost form. This will ensure resources (such as memory) are utilized to the best by unloading the applications that are not used very often.
To find out about how the above implementation performs, the following tests were carried out. This test focus on how the lazy loading for webapp behaves in a multi-tenant environment.
1. Without GD, we deployed a sample webapp on a tenant and let the tenant to idle.
2. When the tenant became idle, sent a request to the webapp (GET) and measured the response time. (This will include the total time of tenant becoming active and )
3. Repeated this by gradually increasing the number of webapps.
4. With GD enabled, carried out the same test as above, but made sure that those webapps are loaded in ghost form, when the tenant becomes active.
We can clearly observe from the graph that, when the number of applications, that has to be deployed on initial tenant loading, increases, the response time is steadily increasing and eventually stating to time-out. But with GD in effect, the initial response is at a constant level.
With Ghost Deployment available for both Services and Applications, in multi-tenant environment, like WSO2 StratosLive, the optimal resources utilization can be achieved giving a better performance.