ElasticSearch Windows服务化并使用指定的Java版本

公司使用Elasticsearch做全文搜索, 我在测试期间, 使用Linux的Es, 但是试生产环境下, 公司突然给我一个Windows的机器…让我在上面部署Es. 随后我发现Es windows版本是支持以服务方式运行的(如果能用服务运行我却用了前台运行, 九成要被领导说一顿), 服务器环境比较恶心, 上面装了jdk1.7(还不能随便改), 然后我需要让es指定使用某个版本的jdk8, 虽然通过在elasticsearch-service.bat中添加了set JAVA_HOME, 服务能创建成功, 但是启动时一直报 windows 不能在本地启动Elasticsearch 6.6.0(elasticsearch-service-x64)…并参考特定服务错误代码 4.

(English version translate by GPT-3.5)

环境

以下操作均虚拟机操作, 写本文的这一刻, 官网最新版本是7.0.0

附ElasticSearch 6.6.0 官方下载 Elasticsearch 6.6.0 - elastic.co

常规做法

  1. 常规的按照官方的文档创建一个服务.
  2. 然后分分钟报出如下错误
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>

报错易懂, 版本不够, 可是线上环境又不是想升就能升的, 所以只能想个法子指定给它一个jdk8来运行

慢慢找

  1. 基本思路, 按照tomcat那样, 在bat中配置 set JAVA_HOME 应该就可以实现了.
  2. 如图设置了环境变量, 在文件上追加了这么一行, 如果真那么简单解决就好了.

后来我看到elasticsearch-services.bat中调用了elasticsearch-env.bat, 所以我之后将set放在这里了

add-enviroment

  1. 然后运行elasticsearch-service.bat install, 显示成功安装
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. 然后去服务那边启动它, 分分钟报出了错误
    error-on-service-startup

  2. 我去/logs/elasticsearch-service-x64-stderr.yyyy-mm-dd.log看了下失败日志

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"

Unsupported major.minor version 52.0这个错误, 第一反应是java版本对不上, 52这个对应的是java8, 搜到了一篇StackOverflow的文章, 理出一个列表, 见底部.

解决

  1. 既然它启动的时候我写的那个set没生效, 那表示肯定读到了系统变量%JAVA_HOME%, 即那个set没有在启动服务时生效

  2. 为了确认这点, 我在虚拟机上改了下系统的%JAVA_HOME%
    change-evironment

  3. 服务立马开心的起来了…
    changed-startup-success

  4. 所以我觉得启动时可能设置了获取JAVA_HOME这个环境变量, 但是如果是exe级别的环境变量获取, 那我就爱莫能助了, 我总不可能去逆向人家的exe吧, 但是还是先细看elasticsearch-service.bat脚本

  5. 在doInstall中找到这么一行
    find-line

  6. 我尝试在前面加上echo, 得到如下命令, 我看到好像这里面有没被替换, 获取了系统变量%JAVA_HOME%, 我看到了这个脚本格式是%%JAVA_HOME%%, 就猜: %JAVA_HOME%会被转成实际路径, 但是%%JAVA_HOME%%应该起到转义效果, 即保留完整的%JAVA_HOME%.
    find-unreplaced-javahome

  7. 我去掉这两边的%符号, 然后再次打印, 果然刚才的遍历被转成绝对路径了
    find-absoluted

  8. 速度去掉echo, 然后移除服务再重新创建, 服务运行成功!

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

但是这样做的问题

这样做其实有个问题, 虽然服务能运行, 但是这样相当于写死了java path, 如果这个java path被移动或更改, 那这个服务也无法启动了, 如果改了javapath, 就会出现如下提示:

if-java-path-changed

附: Java版本列表

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