WoodWing Help Center

Multi-volume storage in Elvis 5 Server

Multi-tiered storage in Elvis 5 Server

Info: This feature requires Elvis Server 5.4.2 or higher.

With the high number of assets that companies use nowadays, considerations need to be made about where all these assets should be stored. Assets that are used in production obviously need to be made available on fast disks while assets that are not used anymore can be moved to slower, less expensive disks to keep them available for reference and possible later use.

High-end storage solutions such as AWS Storage Gateway or ceph usually provide functionality to spread data over different disks transparently within the storage hardware.

Using such solutions is preferred because it allows Elvis Server to address its storage as a single volume. This means that Elvis can just move files around without having to copy actual data, an operation that is time consuming to perform. In these setups, the storage solution will move data between online storage and near-line storage in the background without affecting application performance.

Multiple volumes

If your storage hardware does not support the above, Elvis Server allows you to spread the "Elvis Data" over multiple volumes. This can be used in the following cases:

  • Store live production data on fast disks and store rarely accessed archive data on slower, less expensive disks (near-line storage), even if the storage hardware does not provide this by itself.
  • When limitations on volume sizes exist. These can either be related to the storage hardware, the operating system or a virtualization layer. By spreading the data over multiple smaller volumes you can still store all your data on one Elvis Server.

Before you start

Before implementing a multi-tier environment, please take note of the following:

  • When implementing a multi-tier environment in an existing Elvis 5 installation, be aware that existing assets will not be moved and might therefore become irretrievable. Ensure therefore that your new storage tiers do not match on existing folders, or alternatively move your existing assets / folders manually beforehand.
  • It is currently not supported to change the paths after they have been initially configured and files are stored in that location. Doing so results in bad behavior because the existing files will not have moved but are still placed in the previously defined location.
  • Elvis Server will try to move files where possible for optimal performance. Because files cannot be moved between volumes, a copy and delete action is used to spread data over multiple volumes. This dramatically impacts performance since a copy action is very slow compared to a move operation. Note that the tempFilestore (used for newly uploaded files) is always in the standard dataLocation, so make sure to keep critical production files on the default location for best import performance.

How it works

In the Elvis 5 multi-volume environment, assets are stored to a storage volume by a Storage Engine.

The multi-tier Storage Engine is configured as a top-level storage engine, with a default engine and typically one or more additional engines. It will delegate storage to its children, depending on defined patterns. This will be explained in more detail below.

The Storage Engine itself is of type 'multi-tier' while all following Storage Engines are of type 'shared-volume' or 's3'.

storage.engine {
  type = "multi-tier"
  default-engine {
    type = "shared-volume"
    ...
  }
  engines : [
    {
      name = "fast-storage"
      type = "shared-volume"
      ...
    }
    {
      name = "PDFs"
      type = "shared-volume"
      ...
    }
    {
      name = "archive"
      type = "s3"
      ...
    }
  ]
}

One of the main properties of each sub-engine (with the exception of the default engine) is the 'pattern' property. With it you can control which assets to store on the volume, for example all assets uploaded to a particular directory.

Note: This pattern matches your asset's folder path, not the file name or extension. Also, it must always end with one of the following:

  • '/*' to match the assets in the matched folder only
  • or '/**' to match the assets in the matched folder and in all its sub folders

Examples:

  • pattern = "/fast-storage/**" will store all assets that are uploaded to the 'fast-storage' folder.
  • pattern = "/**/pdf/**" will store assets that are uploaded to a subfolder named 'pdf'.

Patterns and order of definition

When folder paths are matched by multiple patterns, the order of storage engine definitions plays an important part. Precedence goes from top to bottom, with the default engine being an exception. In the following example for instance, the patterns will be matched in the following order.

  1. pattern = "/fast-storage/**"
  2. pattern = "/**/pdf/**"
  3. pattern = "/archive/**"

Example:

storage.engine {
  type = "multi-tier"
  default-engine {
    type = "shared-volume"
    ...
  }
  engines : [
    {
      name = "fast-storage"
      type = "shared-volume"
      pattern = "/fast-storage/**"
      ...
    }
    {
      name = "PDFs"
      type = "shared-volume"
      pattern = "/**/pdf/**"
      ...
    }
    {
      name = "archive"
      type = "s3"
      pattern = "/archive/**"
      ...
    }
  ]
}

This means that files uploaded to 'fast-storage/pdf' will be written to the location defined for 'fast-storage' because the 'fast-storage' pattern sits higher in the order than the 'PDFs' pattern. Similarly, files uploaded to 'archive/pdf' will be written to the storage location defined for 'PDFs' because the 'PDFs' pattern sits above the archive pattern in the order of definition.

Non-matching patterns

If none of the patterns can be matched, the assets are stored in the location that is defined for the default Storage Engine.

Multiple engine patterns

Info: This feature requires Elvis Server 5.11 or higher.

Multiple patterns can be defined for the same engine. Each pattern should be separated by a comma.

Example: In the following example, items are allowed to be stored in the /fast-storage root folder and any folder named 'pdf' on the same folder path:

    {
      name = "fast-storage"
      type = "shared-volume"
      pattern = "/fast-storage/**,**/pdf/**"
      ...
    }

Example

In the following example (taken from the example configuration file that is provided with Elvis 5), the following is defined:

  • All assets that do not match any of the patterns of the sub-engines are stored in a default shared volume (see lines 3 to 7)
  • All assets uploaded to the "/fast-storage/**" directory are stored on a fast storage shared volume (see lines 12 to 18). This includes files uploaded to a 'pdf' subdirectory.
  • All files in a 'pdf' subdirectory are uploaded to a separate shared volume (see lines 21 to 27) even when they are uploaded to, for example, 'archive/pdf', but not when they are uploaded to, for example, 'fast-storage/pdf'.
  • All assets uploaded to the "/archive/**" directory are stored on Amazon S3 (see lines 30 to 34), with the exception of files uploaded to 'pdf' sub directories, such as '/archive/pdf', which are always stored on the 'PDFs' volume.

Example:

storage.engine {
  type = "multi-tier"
  default-engine {
    type = "shared-volume"
    assetFilestore = "/Library/Elvis Server/fs/default/assets"
    renditionFilestore = "/Library/Elvis Server/fs/default/renditions"
    tempFilestore = "/Library/Elvis Server/fs/default/tmp"
    mounted = false
  }
  engines : [
    {
      name = "fast-storage"
      type = "shared-volume"
      pattern = "/fast-storage/**"
      assetFilestore = "/Library/Elvis Server/fs/SSD1/assets"
      renditionFilestore = "/Library/Elvis Server/fs/SSD1/renditions"
      tempFilestore = "/Library/Elvis Server/fs/SSD1/tempFilestore"
      mounted = true
    }
    {
      name = "PDFs"
      type = "shared-volume"
      pattern = "/**/pdf/**"
      assetFilestore = "/Library/Elvis Server/fs/PDF/assets"
      renditionFilestore = "/Library/Elvis Server/fs/PDF/renditions"
      tempFilestore = "/Library/Elvis Server/fs/PDF/tempFilestore"
      mounted = true
    }
    {
      name = "archive"
      type = "s3"
      pattern = "/archive/**"
      endpoint = "s3-eu-west-1.amazonaws.com"
      bucket = "elvis-archive"
    }
  ]
}

Configuration

Configuring multi-tiered storage is done in the storage-engine-config.conf file (located in the default Elvis Server/Config folder).

Define any of the engines and their patterns as described below and save the file.

Note: It is not allowed to point two engines to exactly the same folder path for the assetFilestore, renditionFilestore, or tempFilestore. Moves between these engines will fail.

It is possible though to point to different sub folders within the same shared folder.

If you need multiple patterns pointing to the same file store, use the comma-separated patterns.

Config syntax

The configuration of the file is specified in HOCON, a superset of JSON that is more human oriented and lenient. For more information about the syntax, see the HOCON specification.

Adding additional engines

Adding additional engines is a typical real-world scenario: you might start off with one or two main storage locations and decide to add an additional location at some later point — for example for archive purposes — and subsequently move files to that location.

To add an additional engine to your configuration, add another block ("{ }") to your list ("[ ]") of engines.

engines : [
    ...
    {
      ...
    }
    ...]

Note: The order in which engines are added matters to the outcome, see Patterns and order of definition.

Default Storage Engine

The default Storage Engine differs from the other Storage Engines in the following ways:

  • It is defined outside the list of sub-engines.
  • No name is needed.
  • No pattern is needed: it is the default engine when no match is found for all other engine patterns.
default-engine {
   type = "shared-volume"
   assetFilestore = "/Library/Elvis Server/fs/default/assets"
   renditionFilestore = "/Library/Elvis Server/fs/default/renditions"
   tempFilestore = "/Library/Elvis Server/fs/default/tmp"
   mounted = false
 }

Shared volume Storage Engine

Step 1. Add a descriptive name, define the type as "shared-volume" and set "mounted" to "true".

Setting "mounted = true" will cause Elvis Server to check whether the volume is actually mounted during startup and it will stop the Server if this check fails.

Note: For a local volume, set "mounted" to "false". Only do this for a standalone (single-node) installation, and only if there should really be no mounted volume in this location.

{
  name = "fast-storage"
  type = "shared-volume"
  ...
  mounted = true
}

Step 2. Define the locations on this mounted share where the assets (assetFilestore), their renditions (renditionFilestore) and the temporary files (tempFilestore) are stored.

{
  ...
  assetFilestore = "/Library/Elvis Server/fs/SSD1/assets"
  renditionFilestore = "/Library/Elvis Server/fs/SSD1/renditions"
  tempFilestore = "/Library/Elvis Server/fs/SSD1/tempFilestore"
  ...
}

Note: On Windows, use '/' or '\\' instead of '\'.

Tip: You can also use your Elvis 5 config properties here, such as sharedDataLocation.

{
  ...
  assetFilestore = "${sharedDataLocation}/assets"
  renditionFilestore = "${renditionFilestoreLocation}"
  tempFilestore = "${tempFilestoreLocation}"
  ...
}

Step 3. Provide a pattern to match the folderPath of your assets on. Only the matched assets will go to this storage engine.

The example below matches all your files that you store in sub directories called 'pdf' (for example: "/foo/bar/pdf").

{
  ...
  pattern = "/**/pdf/**"
  ...
}

S3 Storage Engine

Note: Although the use of S3 storage is fully supported, please be aware of possible performance issues such as long upload and download times.

Step 1. Provide a descriptive name and define the type as "s3" .

{
  name = "archive"
  type = "s3"
  ...
}

Step 2. Define the bucket name (bucket) and its endpoint where the assets and their renditions are stored.

{
  ...
  endpoint = "s3-eu-west-1.amazonaws.com"
  bucket = "elvis-archive"
  ...
}

Step 3. Provide a pattern to match the folderPath of your assets on. Only the matched assets will go to this storage engine.

The example below matches all files that you store in the "/archive" folder in Elvis.

{
  ...
  pattern = "/archive/**"
  ...
}

Step 4. (Optional) Add authentication specific to this bucket.

Note: The default AWS authentication settings will be used if you don't supply them here (therefore it is optional).

sigv4 {
enable = ${storage.engine.s3.sigv4.enable}
enforce = ${storage.engine.s3.sigv4.enforce}
}
accessKeyId = "${storage.engine.s3.accessKeyId}"
secretKey = "${storage.engine.s3.secretKey}"

Patterns

The patterns must be defined as "glob patterns" (see the Antglob Reference Guide). These will match on the assetPath of your asset, ignoring case.

Note: This pattern matches your asset's folder path, not the file name or extension. Also, it must always end with one of the following:

  • '/*' to match the assets in the matched folder only
  • or '/**' to match the assets in the matched folder and in all its sub folders

Example: To match on files in '/Users/admin', use a pattern such as '/users/admin/**'.

Allowed Not allowed
"/**/foo/*" "/**/foo.bar"
"/**/foo.bar/**" "/foo/bar.*"
"/foo*/bar/*" "/foo/foo*.bar*"
"/*/*foo*/*bar*/*" "/foo/bar/"
  "/foo*bar"

Fallback

During the installation of Elvis 5, the fileStoreType was defined as either 'local' or 'shared' in the node-config.properties.txt file.

These configuration values are used as fallback options in case no multi-tier storage is defined.

  • storage.engine.type will be set as the type of your default-engine.
  • fileStoreType will become the mounted property: 'shared' becomes 'true', 'local' becomes 'false'.
  • sharedDataLocation is by default the base of assetFilestoreLocation, renditionFilestoreLocation and tempFilestoreLocation. The default values of these properties will be used as your default-engine's assetFilestore, renditionFilestore and tempFilestore.

Note: You could set it directly to ${assetFilestoreLocation} and so on, if you changed those properties already.

  • For an S3 default-engine, your storage.engine.s3 properties will get used as default, as seen below.

Default configuration

The default configuration defines both the shared-volume and S3 configuration in the default-config block. This is fine, as only the properties for the defined type will be used.

For readability purposes it is however advised to only define the properties relevant to the type you configure.

storage.engine {
  type = "multi-tier"
  default-engine {
    type = "${storage.engine.type}"
 
    # the settings below are only used when type is 'shared-volume'
    sharedDataLocation = "${sharedDataLocation}"
    assetFilestore = "${assetFilestoreLocation}"
    renditionFilestore = "${renditionFilestoreLocation}"
    tempFilestore = "${tempFilestoreLocation}"
    mounted = ${mounted} # from the `filestoreType` legacy config option (`shared`=true,`local`=false)
 
    # the settings below are only used when type is 's3'
    endpoint = "${storage.engine.s3.endpoint}"
    bucket = "${storage.engine.s3.bucket}"
    sigv4 {
      enable = ${storage.engine.s3.sigv4.enable}
      enforce = ${storage.engine.s3.sigv4.enforce}
    }
    accessKeyId = "${storage.engine.s3.accessKeyId}"
    secretKey = "${storage.engine.s3.secretKey}"
  }
  engines : []
}

Full configuration

A full configuration is shown in the example below.

Note: You can use placeholders such as ${sharedDataLocation} to use values from your other Elvis configuration.

Notable properties:

  • The default-engine is configured just like s3 or a shared-volume (depending on its type), but the name and pattern are left out (they would have no added value).
  • Defining a multi-tier engine with only a default-engine and no sub-engines will work like configuring either of the other engines, with very little overhead.
  • Be careful when defining the mounted option. If this property is set to false, the storage engine will not perform a mount check on the location and happily create directories for it if it doesn't exist. In case of a shared-volume, this will lead to data being spread amongst nodes, which will yield unreadable files depending on the Elvis node that is being used to retrieve them.
  • Optional values are commented out in the example below:
  • sigv4.* enable/enforce SigV4, defaults to false and is usually not required.
  • accessKeyId / secretKey will be used as credentials when both are defined. Otherwise the default AWS credential provider will be used which will get this information from several other places in the system. See the Amazon documentation Class DefaultAWSCredentialsProviderChain.
  • tempDirLocation will be used to store your files when they get downloaded from S3 or before they get uploaded to S3. The default is to use the system's temporary directory (as defined in java.io.tmpdir).

Note: Make sure that this location is on a fast local disk.

Example:

storage.engine {
  type = "multi-tier"
  default-engine {
    type = "shared-volume"
    assetFilestore = "/Library/Elvis Server/fs/default/assets"
    renditionFilestore = "/Library/Elvis Server/fs/default/renditions"
    tempFilestore = "/Library/Elvis Server/fs/default/tmp"
    mounted = false
  }
  engines : [
    {
      name = "fast-storage"
      type = "shared-volume"
      pattern = "/fast-storage/**"
      assetFilestore = "/Library/Elvis Server/fs/SSD1/assets"
      renditionFilestore = "/Library/Elvis Server/fs/SSD1/renditions"
      tempFilestore = "/Library/Elvis Server/fs/SSD1/tempFilestore"
      mounted = true
    }
    {
      name = "PDF"
      type = "shared-volume"
      pattern = "/**/pdf/**"
      assetFilestore = "/Library/Elvis Server/fs/PDF/assets"
      renditionFilestore = "/Library/Elvis Server/fs/PDF/renditions"
      tempFilestore = "/Library/Elvis Server/fs/PDF/tempFilestore"
      mounted = true
    }
    {
      name = "archive"
      type = "s3"
      pattern = "/archive/**"
      endpoint = "s3-eu-west-1.amazonaws.com"
      bucket = "elvis-archive"
    }
  ]
}

Troubleshooting

The following error appears: ... has type STRING rather than BOOLEAN*

A placeholder was probably defined that resolves to some configuration property which is in fact a string instead of a boolean. ${mounted} is a special property, resolved to the legacy filestoreType configuration property, with 'shared' resolving to true and 'local' to false.

The following error appears: java.lang.IllegalArgumentException: 'pattern' property must end with '/*' or '/**': pattern '**/*png*.*' for engine 'PNG'

You have defined a pattern as shown in the error which would cause a match on file name or extension. Such a pattern is currently not supported.

All patterns must end with one of the following:

  • '/*' to match the assets in the matched folder only
  • or '/**' to match the assets in the matched folder and in all its sub folders
Was this article helpful?
0 out of 0 found this helpful / Created: / Updated:
Have more questions? Submit a request

2 Comments

  • 0
    Avatar
    Luis Mejia

    Hello Support,

    Regarding the note under the S3 section:

     

    Note: Although the use of S3 storage is fully supported, please be aware of possible performance issues such as long upload and download times.

     

    Is this stating that the use of a "cold"/slower S3 storage option could reduce performance, or that splitting up S3 into multi storage would have an impact on an overall solution?

    Thanks,
    Luis

  • 0
    Avatar
    Vincent Bergervoet

    Hello Luis,

    This note means S3 storage is slower then other storage from a locally hosted server. Using it for production data you may experience longer waiting times and a storage solution that is faster or closer to the server is advised. For archive purposes S3 is excellent.

    Regarding multi-tier storage, set it up in a way that files do not need to move between storage solutions too often, as moving and copying on the same storage solution will have better performance than when they need to move to a different storage.

    Regards,
    Vincent

Please sign in to leave a comment.