由于官方文档对es原理方面的讲解非常少,所以如果时间允许可以自己下载源码在本地调试。
首先在github
上可以下载到各个版本的源码,写作本文时最新的是6.4.2
版本:https://github.com/elastic/elasticsearch/tree/v6.4.2
下载的源码是gradle
项目,所以需要安装gradle
,对版本有要求,我用的是4.10.2
版本。
对java
的版本也有要求,我用的是jdk11
,jdk9
以上应该就可以了。
用idea
打开需要在源码根目录下执行gradle idea
命令。
然后尝试运行server
模块下org.elasticsearch.bootstrap.Elasticsearch
主类,可能会遇到下列问题:
1. 配置文件路径设置问题
ERROR: the system property [es.path.conf] must be set
解决方法:新建任意目录,idea
在vm option
中添加设置,如-Des.path.conf=F:\middleware\elasticsearch-data\config
。
这是放配置文件的地方,如果路径下没有配置文件,将使用默认配置,可将elasticsearch.yml
文件放在此路径下。
2. home路径设置问题
Exception in thread "main" java.lang.IllegalStateException: path.home is not configured
解决方法:添加es.path.home
的路径设置,可随意设置,如-Des.path.home=F:\middleware\elasticsearch-data
。
这是es运行的home
路径。plugins
,modules
,lib
等都会在此路径下相应的子路径加载。如果不指定,默认的data
,log
,config
路径也会创建在此home
路径下。但其实因为代码的问题config
路径必须指定,否则会报错。
3. java security权限设置问题
ERROR Could not register mbeans java.security.AccessControlException: access denied ("javax.management.MBeanTrustPermission" "register")
解决方法:添加设置,-Dlog4j2.disable.jmx=true
。
由于本人对java security
了解甚少,此处存疑,这是网上找到的办法,不知道是真正解决了问题,还是仅仅抑制了报错。
经试验也可以在server
模块找到src\main\resources\org\elasticsearch\bootstrap\security.policy
文件,在grant{}
中添加上相应的permission
,比如这里可以加上
permission javax.management.MBeanTrustPermission "register";
后面遇到其它类似的问题,加上相应的permission
即可。
4. 日志配置问题
ERROR: no log4j2.properties found; tried [F:\middleware\elasticsearch-data\config] and its subdirectories
解决方法:在上面配置的es.path.conf
路径下添加log4j2.properties
文件,此文件可以在distribution
模块的src\config\
路径下找到,建议下载一个相同版本的es发行版(因为后面也要用到),用发行版里面的配置文件。
5. modules加载问题
org.elasticsearch.bootstrap.StartupException: java.lang.IllegalStateException: modules directory [F:\middleware\elasticsearch-data\modules] not found
解决方法:下载一个相同版本的es发行版,将里面的modules
文件夹复制到上面配置的es.path.home
路径下。
6. libs模块的类加载问题
java.lang.NoClassDefFoundError: org/elasticsearch/plugins/ExtendedPluginsClassLoader
解决方法:这个类在libs
模块,server
模块中原来的gradle
配置是
compileOnly project(':libs:plugin-classloader')
compileOnly
改为compile
即可。
至此,应该已经能够正常运行es源码了。
7. transport通信断点调试
es集群节点间通信都是通过transport
模块来进行的,想要调试节点间的transport请求,在TransportRequestHandler
接口的默认方法messageReceived
方法处打个断点,节点间交互时都会进来。
public interface TransportRequestHandler<T extends TransportRequest> {
/**
* Override this method if access to the Task parameter is needed
*/
default void messageReceived(final T request, final TransportChannel channel, Task task) throws Exception {
messageReceived(request, channel);
}
void messageReceived(T request, TransportChannel channel) throws Exception;
}
8. http通信断点调试
集群外部访问集群,比如search
、index
等操作通常是http
方式的,调试这种可以在RestController
类的dispatchRequest
方法处打个断点,这样对该节点的http
请求都会进到这里来。
@Override
public void dispatchRequest(RestRequest request, RestChannel channel, ThreadContext threadContext) {
if (request.rawPath().equals("/favicon.ico")) {
handleFavicon(request, channel);
return;
}
try {
tryAllHandlers(request, channel, threadContext);
} catch (Exception e) {
try {
channel.sendResponse(new BytesRestResponse(channel, e));
} catch (Exception inner) {
inner.addSuppressed(e);
logger.error(() ->
new ParameterizedMessage("failed to send failure response for uri [{}]", request.uri()), inner);
}
}
}