0

I am running ActiveMQ Artemis (2.18.0) on CentOS

OS: CentOS Linux release 7.9.2009 (Core) Kernel: Linux 3.10.0-1160.31.1.el7.x86_64

Since I am running a kernel version newer than 2.6 on an x86_64 architecture then based on the documentation I only need to ensure that libaio is installed:

yum install libaio
Loaded plugins: fastestmirror
Loading mirror speeds from cached hostfile
 * base: mirror.1000mbps.com
 * centos-sclo-rh: mirror.seedvps.com
 * centos-sclo-sclo: mirror.seedvps.com
 * extras: mirror.seedvps.com
 * updates: mirror.seedvps.com
Package libaio-0.3.109-13.el7.x86_64 already installed and latest version

In the broker.xml I set the journal type to AIO:

<journal-type>ASYNCIO</journal-type>

I start the broker programmatically:

broker = new EmbeddedActiveMQ(); 
broker.setConfigResourcePath(fileConfig);
broker.start();

However, I get the following warning:

org.apache.activemq.artemis.core.server : AMQ222018: AIO was not located on this platform, it will fall back to using pure Java NIO. If your platform is Linux, install LibAIO to enable the AIO journal

What could be the case?

Justin Bertram
  • 29,372
  • 4
  • 21
  • 43
user2209562
  • 244
  • 2
  • 16
  • Removed it from the question. May ask the mailing list on this separate question. The reason I added it, because I not only want to know why it doesn't work, but also why it's needed (or what the consequences are to ignore the warning). – user2209562 Sep 21 '21 at 17:26
  • FWIW, I don't think anybody on the ActiveMQ mailing lists will be able to give you an approximate performance difference either. Again, every use-case is different. – Justin Bertram Sep 21 '21 at 17:27
  • I start it programmatically: broker = new EmbeddedActiveMQ(); broker.setConfigResourcePath(fileConfig); broker.start(); – user2209562 Sep 21 '21 at 17:31
  • I am still thinking about the right approach. I'm distributing my program as a single executable jar. Users can use it on Windows/Linux/Unix. I don't want to let users use separate files and command line parameters. I'm thinking about embedding the library and check for the OS/architecture, but unsure if it can be set in runtime. – user2209562 Sep 21 '21 at 19:50
  • I mean the "java.library.path" property, because of [is-djava-library-path-equivalent-to-system-setpropertyjava-library-path](https://stackoverflow.com/questions/5419039/is-djava-library-path-equivalent-to-system-setpropertyjava-library-path) – user2209562 Sep 22 '21 at 06:59

2 Answers2

0

By starting the broker yourself programmatically you miss an important configuration detail performed by the artemis run command which sets the java.library.path system property to include the proper JNI library for AIO integration. Therefore you'll need to do this manually when you start your own Java application which starts the embedded instance of ActiveMQ Artemis. The library you need is in $ARTEMIS_HOME/bin/lib/linux-x86_64.

The documentation you cited references this fact saying:

These are the native libraries distributed by Apache ActiveMQ Artemis:

  • libartemis-native-64.so - x86 64 bits
  • We distributed a 32-bit version until early 2017. While it's not available on the distribution any longer it should still be possible to compile to a 32-bit environment if needed.

When using libaio, Apache ActiveMQ Artemis will always try loading these files as long as they are on the library path

If you then follow the library path link you'll see this:

If you're using the Asynchronous IO Journal on Linux, you need to specify java.library.path as a property on your Java options. This is done automatically in the scripts.

If you don't specify java.library.path at your Java options then the JVM will use the environment variable LD_LIBRARY_PATH.

Justin Bertram
  • 29,372
  • 4
  • 21
  • 43
0

The warning occurs because in order to integrate properly with AIO three conditions must be met:

  1. Run on Linux.
  2. LibAIO must be installed.
  3. The java.library.path Java system property must be set to the directory with the proper shared object (e.g. libartemis-native-64.so).

In this case the third condition isn't met. Normally java.library.path is set on startup by the bin/artemis script, but this isn't done when embedding ActiveMQ Artemis into a Java application.

If using EmbeddedActiveMQ you can add AIO support in one of the following ways:

Manually

  1. Download the Artemis version (i.e. the same version as your ActiveMQ Artemis Maven dependency).
  2. Unzip the downloaded version (e.g. apache-artemis-2.18.0-bin.zip).
  3. Copy the library proper library for your platform architecture (e.g. from apache-artemis-2.18.0/bin/lib/linux-x86_64).
  4. Put the library on every Linux server where the broker is running.
  5. Start your application with the following command:
    -Djava.library.path="/path/to/linux-x86_64/"
    

Docker Container

Add the library to the container and startup java with the -Djava.library.path parameter.

Programmatically

If you feel comfortably (this works for me) you can load the library in runtime:

    File aioFile = new File("./linux-x86_64/libartemis-native-64.so");

        if(OSUtil.getOS().equals(OSUtil.OS.LINUX)){

            if(!aioFile.exists()) {

                //Create an empty file
                FileUtils.touch(aioFile);

                //Copy file from resources into empty file
                ClassLoader classloader = Thread.currentThread().getContextClassLoader();
                InputStream is = classloader.getResourceAsStream("libartemis-native-64.so");
                Files.copy(is, aioFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
                is.close();

                logger.info("AIO Directory is set to " + aioFile.getParent());

            }

            addDir(aioFile.getParent());

        }

    public static void addDir(String s) throws IOException {
        try {
            // This enables the java.library.path to be modified at runtime
            // From a Sun engineer at http://forums.sun.com/thread.jspa?threadID=707176
            //
            Field field = ClassLoader.class.getDeclaredField("usr_paths");
            field.setAccessible(true);
            String[] paths = (String[])field.get(null);
            for (int i = 0; i < paths.length; i++) {
                if (s.equals(paths[i])) {
                    return;
                }
            }
            String[] tmp = new String[paths.length+1];
            System.arraycopy(paths,0,tmp,0,paths.length);
            tmp[paths.length] = s;
            field.set(null,tmp);
            System.setProperty("java.library.path", System.getProperty("java.library.path") + File.pathSeparator + s);
        } catch (IllegalAccessException e) {
            throw new IOException("Failed to get permissions to set library path");
        } catch (NoSuchFieldException e) {
            throw new IOException("Failed to get field handle to set library path");
        }
    }

For more info on loading java.library.path at runtime see this SO article.

Justin Bertram
  • 29,372
  • 4
  • 21
  • 43
user2209562
  • 244
  • 2
  • 16
  • For what it's worth, this technically doesn't answer the question that was asked. The question was about why the message "AIO was not located on this platform" was being logged. It didn't ask for a tutorial about how to set `java.library.path`. While the answer is useful (given that `java.library.path` isn't actually being set properly) it's not clear *why* it's useful. – Justin Bertram Sep 22 '21 at 15:26
  • I have explained it additionally. I think the warning would be clearer if the term ASYNCIO was used (so it can be linked to the journal type in the broker.xml) and that for every condition that isn't met there is a separate specific warning message. Of course, these kinds of problems arise when making platform specific code, which is uncommon on the JVM. – user2209562 Sep 22 '21 at 16:57
  • Those are fair points about the user experience with the current warning message, although the documentation is pretty clear about what is required for AIO integration. Such platform-specific integration is relatively uncommon for Java applications, but in this case the JNI library is pretty concise and the potential performance benefit is significant. – Justin Bertram Sep 22 '21 at 17:26
  • @JustinBertram This is the best answer there is. It is rather strange that Artemis cannot do this itself. It is fully possible to include the so-file in a jar, and let this resolution happen in Java, without having to resort to shell files. Plenty other projects do this. So since you don't, hacking it is clearly an option. Here's a random google: https://stackoverflow.com/a/6511351/39334 – stolsvik Jan 17 '23 at 22:29
  • I'm not sure what you mean by, "Artemis cannot do this itself." The broker ships with the AIO integration library and the broker's start script sets the `java.library.path` appropriately so everything works out of the box for the standalone use-case (which is most important for performance considerations). Anybody embedding the broker on their own can set the `java.library.path` themselves as needed just like all Java applications do when they need to load native libraries (i.e. no "hacking" required). That said, it would certainly be made easier by packaging the SO in a jar. – Justin Bertram Jan 18 '23 at 04:06
  • It's worth noting that most Java-based server software uses shell scripts for start-up. This is standard practice, not something that one must "resort to". At this point, folks embedding the broker can use a shell script to set the `java.library.path` as needed or they can do it programmatically. – Justin Bertram Jan 18 '23 at 04:09
  • Packaging the SO in a jar would really be great. – user2209562 Jan 19 '23 at 08:37