ElasticSearch Windows Service and Specifying Java Version

Our company uses ElasticSearch for full-text search. During testing, I used the Linux version of ElasticSearch. However, when it came time for production, the company suddenly gave me a Windows machine and asked me to deploy ElasticSearch on it. I discovered that the Windows version of ElasticSearch supports running as a service (even though I used foreground running during testing - which would probably get me scolded by my leader). The server environment was quite complicated as it had JDK 1.7 installed and I needed to make ElasticSearch use a specific version of JDK 8. Although I added the set JAVA_HOME command in the elasticsearch-service.bat file and the service was successfully created, I consistently received an error message when trying to start it: “Windows could not start Elasticsearch 6.6.0 (elasticsearch-service-x64)…refer to specific service error code 4.”(English version Translated by GPT-3.5, 返回中文)

Environment

All of the following operations were conducted in a virtual machine. At the time of writing this article, the latest version available on the official website was 7.0.0.

ElasticSearch 6.6.0 Download Elasticsearch 6.6.0 - elastic.co

Common Practice

  1. Follow the official documentation to create a service as usual. Official documentation
  2. Encounter an error within minutes:
1
2
3
4
C:\Users\ruter\Desktop\elasticsearch-6.6.0\bin>elasticsearch-service.bat  install
the minimum required Java version is 8; your Java version from [C:\Program Files\Java\jdk1.7.0_80\jre] does not meet this requirement

C:\Users\ruter\Desktop\elasticsearch-6.6.0\bin>

The error message is clear: “Version not sufficient.” However, upgrading the production environment is not always possible. So, I needed to find a way to specify that ElasticSearch should run with JDK 8.

Searching for a Solution

  1. The basic idea was to configure the set JAVA_HOME command in the bat file, similar to how it is done with Tomcat.
  2. I set the environment variable and added the line to the file as shown in the image below, hoping it would solve the problem.

Later, I noticed that elasticsearch-services.bat calls elasticsearch-env.bat. So, I moved the set command to that file.

add-environment

  1. Then, I ran the command “elasticsearch-service.bat install” and it showed successful installation.
1
2
3
4
5
6
C:\Users\ruter\Desktop\elasticsearch-6.6.0\bin>elasticsearch-service.bat  install
Installing service : "elasticsearch-service-x64"
Using JAVA_HOME (64-bit): "C:\Program Files\Java\jdk1.8.0_192" -Xms1g;-Xmx1g;-XX:+UseConcMarkSweepGC;- XX:CMSInitiatingOccupancyFraction=75;-XX: +UseCMSInitiatingOccupancyOnly;-Des.networkaddress.cache.ttl=60;-Des.networkaddress.cache.negative.ttl=10;-XX:+AlwaysPreTouch;-Xss1m;-Djava.awt.headless=true;-Dfile.encoding=UTF-8;-Djna.nosys=true;-XX:-OmitStackTraceInFastThrow;-Dio.netty.noUnsafe=true;-Dio.netty.noKeySetOptimization=true;-Dio.netty.recycler.maxCapacityPerThread=0;-Dlog4j.shutdownHookEnabled=false;-Dlog4j2.disable.jmx=true;-Djava.io.tmpdir=C:\Users\ruter\AppData\Local\Temp\elasticsearch;-XX:+HeapDumpOnOutOfMemoryError;-XX:HeapDumpPath=data;-XX:ErrorFile=logs/hs_err_pid%p.log;-XX:+PrintGCDetails;-XX:+PrintGCDateStamps;-XX:+PrintTenuringDistribution;-XX:+PrintGCApplicationStoppedTime;-Xloggc:logs/gc.log;-XX:+UseGCLogFileRotation;-XX:NumberOfGCLogFiles=32;-XX:GCLogFileSize=64m
The service 'elasticsearch-service-x64' has been installed.

C:\Users\ruter\Desktop\elasticsearch-6.6.0\bin>
  1. However, when I tried to start the service, I encountered an error immediately.
    error-on-service-startup

  2. I went to the /logs/elasticsearch-service-x64-stderr.yyyy-mm-dd.log file to check the failure logs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2019-04-23 20:27:46 Commons Daemon procrun stderr initialized
java.lang.UnsupportedClassVersionError: org/elasticsearch/bootstrap/Elasticsearch : Unsupported major.minor version 52.0
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
Exception in thread "main"

The error “Unsupported major.minor version 52.0” indicated that the Java version did not match. “52” corresponds to Java 8. I found an article on StackOverflow that listed the major version numbers for Java class file format. Please refer to the list at the bottom of this article.

Resolution

  1. Since the set command I wrote was not taking effect at startup, it meant that the service was reading the system variable %JAVA_HOME%, and the set command was not executed when starting the service.

  2. To confirm this, I changed %JAVA_HOME% in the system on the virtual machine as shown in the image below.
    change-environment

  3. The service started successfully immediately.
    changed-startup-success

  4. So, I think that during startup, the service sets and retrieves the JAVA_HOME environment variable. But if it is an exe-level environment variable, there is nothing more I can do since I cannot reverse engineer their exe file. However, I still examined the elasticsearch-service.bat script in detail.

  5. In the doInstall section, I found the following line.
    find-line

  6. I tried adding the echo command in front and obtained the following command. It seems that something was not being replaced. The script format used %%JAVA_HOME%%, so I guessed that %JAVA_HOME% would be converted to the actual path while the %%JAVA_HOME%% format would be treated as an escaped value, keeping the %JAVA_HOME% intact.
    find-unreplaced-javahome

  7. I removed the % symbols on both sides and printed again, and the previous iteration was replaced with an absolute path.
    find-absolute

  8. I removed the echo command, removed the service, and reinstalled it. The service ran successfully!

1
2
3
4
5
6
7
8
C:\Users\ruter\Desktop\elasticsearch-6.6.0\bin>elasticsearch-service.bat remove
The service 'elasticsearch-service-x64' has been removed

C:\Users\ruter\Desktop\elasticsearch-6.6.0\bin>elasticsearch-service.bat install

Installing service : "elasticsearch-service-x64"
Using JAVA_HOME (64-bit): "C:\Users\ruter\Desktop\jdk1.8.0_192"-Xms1g;-Xmx1g;-XX:+UseConcMarkSweepGC;-XX:CMSInitiatingOccupancyFraction=75;-XX:+UseCMSInitiatingOccupancyOnly;-Des.networkaddress.cache.ttl=60;-Des.networkaddress.cache.negative.ttl=10;-XX:+AlwaysPreTouch;-Xss1m;-Djava.awt.headless=true;-Dfile.encoding=UTF-8;-Djna.nosys=true;-XX:-OmitStackTraceInFastThrow;-Dio.netty.noUnsafe=true;-Dio.netty.noKeySetOptimization=true;-Dio.netty.recycler.maxCapacityPerThread=0;-Dlog4j.shutdownHookEnabled=false;-Dlog4j2.disable.jmx=true;-Djava.io.tmpdir=C:\Users\ruter\AppData\Local\Temp\elasticsearch;-XX:+HeapDumpOnOutOfMemoryError;-XX:HeapDumpPath=data;-XX:ErrorFile=logs/hs_err_pid%p.log;-XX:+PrintGCDetails;-XX:+PrintGCDateStamps;-XX:+PrintTenuringDistribution;-XX:+PrintGCApplicationStoppedTime;-Xloggc:logs/gc.log;-XX:+UseGCLogFileRotation;-XX:NumberOfGCLogFiles=32;-XX:GCLogFileSize=64m
The service 'elasticsearch-service-x64' has been installed.

img
success-http

The Problem with This Approach

Although this approach allows the service to run, there is still a problem. By specifying the Java path in this way, it is hard-coded. If the Java path is relocated or changed, the service will no longer be able to start. If the javapath is changed, the following prompt will be displayed:

if-java-path-changed

Attached: Java Version List

Java Version major
Java 1.2 46
Java 1.3 47
Java 1.4 48
Java 5 49
Java 6 50
Java 7 51
Java 8 52
Java 9 53
Java 10 54
Java 11 55
Java 12 56
Java 13 57
“””