JVM Tuning

From AlfrescoWiki

Jump to: navigation, search

Back to Server Configuration

Contents

[edit] Introduction

The Alfresco Repository and web-client hardware requirements are variable and depend significantly on the number of concurrent users that will be accessing the system. You should tune the memory and garbage collection parameters for the JVM as appropriate for your use-case. The metrics and estimates below are only a suggestion and your system may vary .

[edit] Disk Space Usage

The size of your Alfresco repository defines how much disk space you will need and is a very simple calculation. Content in Alfresco is by default stored directly on the disk, therefore to hold 1000 documents of 1MB in size will require 1000MB of disk space. You should also make sure there is sufficient space overhead for temporary files.

It is highly recommended that a server class machine with SCSI Raid disk array is used. The performance of reading/writing content is almost solely dependent on the speed of your network and the speed of your disk array. The overhead of the Alfresco server itself for reading content is very low as content is streamed directly from the disks to the output stream. The overhead of writing content is also low but depending on the indexing options (e.g. atomic or background indexing) there may be some additional overhead as the content is indexed or meta-data extracted from the file information.

[edit] JVM Memory and CPU Hardware for multiple users

The Repository L2 Cache plus initial VM overhead plus basic Alfresco system memory is setup with a default installation to require a maximum of approximately 512MB. This means you can run the Alfresco repository and web-client with many users accessing the system with a basic single CPU server and only 512MB of memory assigned to the Alfresco JVM. However - you will need to add additional memory as your user base grows. You will need to add CPUs depending on the complexity of the tasks you expect your users to perform and how many concurrent users are accessing the client.

Note that for these metrics, N concurrent users is considered equivalent to 10xN casual users that the server could support.

Suggested memory+CPU settings per server:

  • For 50 concurrent or up to 500 casual users:
1GB JVM RAM
2x server CPU (or 1xDual-core)
  • For 100 concurrent users or up to 1000 casual users:
1GB JVM RAM
4x server CPU (or 2xDual-core)
  • For 200 concurrent users or up to 2000 casual users:
2GB JVM RAM
8x server CPU (or 4xDual-core)

For the tests providing these metrics, a Dell Poweredge Server 2600 dual Xeon CPU 32bit machine was used:

2x Intel Xeon 2.8GHz (533Mhz FSB, single-core)
3GB RAM
3x 36GB Ultra320 SCSI Raid 0

Alfresco Enterprise 2.1 and MySQL 5 on Windows 2000 with Tomcat was deployed onto the server. Approximately 100,000 documents and 1000 user instances were imported into the system (Note that over 5 million documents have been successfully loaded into a similarly configured Alfresco repository).

Similar tests were performed on an equivalently configured Linux box running Fedora core 4 (also Suse and Ubuntu have been tested).

Recently tests have been run using Alfresco Enterprise 1.3 and MySQL 5 on Windows Server 2003 with TomCat on a dual CPU, Opteron Server machine:

2x AMD Operaton 285 2.6GHz (dual-core)
4GB RAM
3x 36GB Ultra320 SCSI Raid 0

Concurrent users are considered to be users constantly accessing the system through the Alfresco web-client with only a small pause between requests (3-10 seconds maximum) - with continuous access 24/7. Casual users are considered to be users occasionally accessing the system through the Alfresco web-client or webdav/CIFS interfaces with a large gap between requests (e.g. occasional document access during the working day).

[edit] Thread Stack Size

The default thread stack size on Windows32bit/Linux32bit is 256K - which is quite large (e.g. for 500 users, 128MB will be used just for native thread stacks). This can be safely reduced on a Windows machine TomCat based deployment using Java cmd arguments to a more sensible number e.g. -Xss64k is a good starting point. Note that we do not recommend changing this value on Linux.

This forum article has some information on Thread stack size: http://forum.java.sun.com/thread.jspa?threadID=645335&tstart=20

[edit] Permanent Generation (PermGen) Size

The default PermGen size in Sun JVMs is 64M, which is very close to the total size of permanent objects (Spring beans, caches, etc.) that Alfresco creates. For this reason it's quite easy to overflow the PermGen via configuration changes or with the addition of custom extensions, and so it's recommended to increase the PermGen to avoid OutOfMemory errors eg. -XX:MaxPermSize=128M is a good starting point. Note that as of Alfresco v3.0, we've increased the size of the PermGen in the alfresco startup scripts, so provided you're using those scripts no changes should be necessary.

[edit] Maximum JVM Heap Size 32/64bit

An important calculation to keep in mind is:

(Managed Heap + native heap + (thread stack size * number of threads)) cannot exceed 2GB on 32bit x86 Windows or Linux systems.

This is a limitation of the Sun Java VM. It means that even if you install 4GB of RAM into your server, a single instance of the Java Virtual Machine cannot grow beyond 2GB on a 32bit server machine.

Note that a 64 bit OS/JVM has much bigger values! It is recommended that a 64bit OS with large memory hardware (>2GB assigned to the JVM) is used for deployments of >250 concurrent or >2500 casual users.

You can also setup you machine to cluster if you would prefer to solve multi-user access performance issues with additional machines rather than a single powerful server.

[edit] JVM Settings

Alfresco generates a high proportion of temporary objects, both in client threads as well as in the background processes. In order to reduce the spillover of temporary objects into the OldGen portion of the heap, the NewSize should be as large as possible.

The following settings tamed the garbage collections and revealed (with GC printing and JMX tracing) that the OldGen was not growing noticeably over and above the permanent space allocated for caches. Cache sizes are still estimated top out around 520M. The StackSize should also be generously set to 1M. So, for a typical 32 bit installation:

JAVA_OPTS= 
-server 
-Xcomp 
-Xbatch 
-Xss1024K 
-Xms1G 
-Xmx2G 
-XX:+UseConcMarkSweepGC 
-XX:+CMSIncrementalMode 
-XX:NewSize=512m 
-XX:MaxPermSize=128M 
-XX:CMSInitiatingOccupancyFraction=80 

Given that the OldGen is composed primarily of cache data of up to about 520M, at least 1GB should be reserved for OldGen. Once -Xmx increases, the OldGen can be increased to 2G. 512M should be left as a buffer to account for miscellaneous (PermGen, etc). So the following variations might be applied:

-Xmx2G -Xms1G -XX:NewSIze=512M (OldGen at least 1G) 
-Xmx3G -Xms1G -XX:NewSize=512M (OldGen at least 2G) 
-Xmx4G -Xms2G -XX:NewSize=1G (OldGen at least 2.5G) 
-Xmx6G -Xms3G -XX:NewSize=2G (OldGen at least 3.5G) 
-Xmx8G -Xms4G -XX:NewSize=3G (OldGen at least 4.5G) 

If you're needing these kinds of figures, you'll be needing to run JConsole (and Java 6) to observe the rate of spillover from Eden to Survivor to OldGen. If, after the system has been running for a while, the OldGen size stabilizes, then the NewSize can be increased appropriately. The following diagram (using VisualGC) shows how varying the NewSize value affects overall garbage collection activity.:

Image:EffectsOfNewSize.jpg#file

The Effects of Enough NewSize (30M, 256M, 512M)