As we all know, the loading mechanism of JVM class adopts the parental delegation mechanism. However, in some frameworks, in order to provide some form of “isolation and sandbox”, a custom framework called
ChildFirstIn short, it destroys the parental delegation. The self-defined child class loader loads the class first instead of delegating it to the parent class loader. Because the same class can be loaded separately in different class loaders, using
ChildFirstClass loader can form a “sandbox” to run two same but different versions of classes in the program at the same time.
However, the author encountered a rare case of class loading conflict, root cause and
ChildFirstIt is related to the mechanism.
The program runs on the Flink platform and writes the data to es. after the security mechanism of a certain platform is turned on, the whole platform including es needs to be accessed based on Kerberos authentication. Based on a priori conclusion, we need to replace the magic
elasticsearch-rest-clientThe GSSAPI is used to log in to Kerberos, and based on sengpo protocol, the token class is sent through HTTP, and there is an independent thread to refresh the token. Because it is a private jar, it is very unfriendly to use in the project, so we consider using Maven shade plugin to exclude the previously dependent jars when packaging jobs
elasticsearch-rest-highlevel-clientAnd put the customized jar in the Flink / lib directory.
After submitting the job, task manager reports an error and exits as follows:
java.lang.LinkageError: loader constraint violation: when resolving method "org.elasticsearch.client.RestClient.builder([Lorg/apache/http/HttpHost;)Lorg/elasticsearch/client/RestClientBuilder;" the class loader (instance of org/apache/flink/util/ChildFirstClassLoader) of the current class, org/apache/flink/streaming/connectors/elasticsearch6/Elasticsearch6ApiCallBridge, and the class loader (instance of sun/misc/Launcher$AppClassLoader) for the method's defining class, org/elasticsearch/client/RestClient, have different Class objects for the type [Lorg/apache/http/HttpHost; used in the signature
The error description means:
org/apache/http/HttpHostAt the same time
AppClassLoaderLoad in the
org.elasticsearch.client.RestClient.builderWhen it comes in
org/apache/http/HttpHostInstance, the class in the method signature (formal parameter) is found
AppClassLoaderAnd the argument is
org/apache/http/HttpHostBut it belongs to me
ChildFirstClassLoaderAnd that caused the conflict.
The following two articles can be referred to:
Based on the following facts:
- The httphost class is typed in the job package.
- When the TM process of Flink starts, httpcore.x.x.jar under Hadoop will be added to classpath
- Appclassloader is responsible for loading the classes in the classpath parameter
- Childfirstclassloader is responsible for loading the classes in the job package
The argument httphosts is a list < httphost > serialized to TM and a private property of elasticsearch6apicallbridge (in the job package). This means that the classes of the argument httphosts are preferentially loaded by childfirstclassloader, and based on fact 1, childfirstclassloader can be loaded into httphost
The restclient class is located in elasticsearch rest client, that is, in the Flink / lib directory. Since elasticsearch rest client will not be typed in when we package, childfirstclassloader cannot be loaded into this class. It can only be loaded by appclassloader. Moreover, due to fact 2, appclassloader can also be loaded into httphost
In this way, the above error will appear
At first, we changed Flink to
parent-firstIt can be solved. After analysis: This is because
ParentFirstClassLoaderInstead of loading the httphost from the job package, the appclassloader loads the httphost, so there is no conflict.
From the above root cause analysis, another solution is to package elasticsearch rest client and other related jars into the job to ensure that they are all loaded by childfirstclassloader. However, the introduction of private jar in this way leads to the confusion of version management.
Flink support classloader.parent -first- patterns.additional Under the premise of child first, the parent first configuration for some classes is effective. However, due to the complex relationship of class loading, it can not be exhaustive.