ClassLoader Isolation
To be Reviewed By: 13 Mar 2020
Authors: Udo Kohlmeyer
Status: Draft Draft | Discussion | Active | Dropped | Superseded
Superseded by: N/A
...
Apache Geode uses many libraries and frameworks to complete features. These libraries will be on the classpath for global access within the JVM using a global Java ClassLoader (default behavior). Apache Geode has the ability to run custom code deployed onto the server-side. This means that logic that requires data can be run where the data is located, which results into in potentially faster response times, as there are less fewer network hop hops and serialization steps required to complete a single operation. Writing custom code allows users to tailor-make their logic to solve their problemproblems. This code can use either the libraries that Apache Geode has available on its classpath OR deploy the libraries that the code requires to complete the functionality. In the latter scenario, it is possible that the custom deployed code requires/uses libraries that are conflicting in version or implementation with the libraries that Apache Geode uses. A prime example of this is Apache Geode Management's use of the Spring Framework.
In order older versions of Apache Geode, the bundled Spring Framework version was on v4.3.x. Which meant that any user that wanted to use Spring in their custom code would be restricted to using that version. Manually upgrading the a Spring Framework version higher, like v5.x, could result in version conflicts in either the custom deployed code, Apache Geode, or in both. In all cases, this is undesirable behavior that is unwarranted.
Without a solution that does not restrict users on framework and versions, it will be impossible for users to most effectively use Apache Geode to their advantage. It also adds an extra burden on the Apache Geode system to always be up-to-date with all the latest versions of libraries, but also have tested with many different combinations of library versions. This of course is an impossible feat, which would result in always being on the wrong version than compared to what the custom code required. i.e Apache Geode has upgraded to the latest version of libraryA (v2.0) but the custom deployed code is reliant on (v1.0) OR vice versa. One cannot keep everybody happy!!!
What is required is the ability to deploy custom code, that functions as expected (and tested externally) and that does not affect the Apache Geode core system or breaks break in an unexpected manner due to version conflicts. The ability to deploy custom code with the freedom to use whatever libraries/frameworks and versions of those without any restriction. The expected behavior should be similar to a Web Container or Application Container. Where , where the web/application does not affect the container system that and is runs or is not affected by the libraries that the container system uses.
...
This proposal is aimed at ONLY solving/resolving problems that one is faced with when deploying custom code, into Apache Geode, and use using any library/framework or version that one chooses without affecting the core Apache Geode system or without being affected by the libraries/framework that Apache Geode uses.
This proposal is not there to help define how to modularize one's code (as per the related reading) or any other approaches (like API/SPI) to simplifying simplify code and implementation.
Solution
...
In order to have Apache Geode bootstrap correctly, Apache Geode's current bootstrapping cycle needs to be altered to accommodate for this modular loading system. In order to bootstrap the "JBoss Modules" modular environment correctly, the initiating class needs to change from org.apache.geode.distributed.ServerLauncher or org.apache.geode.distributed.LocatorLauncher to using org.jboss.modules.Main. The ServerLauncher or LocatorLauncher will still be invoked, as the JBoss Modules Main is a passthrough for the command. e.g The new bootstrapping mechanism will bootstrap Apache Geode components using a ModularServiceJBoss Modules modular system, which will load the Apache Geode system into its own ClassLoader. Determining what strategy is used, will be determined by the implementation of the ModuleService. Initially the JBossModuleService will be opt-in only. This way users can migrate their implementation to match the requirements of the new ModuleService.
draw.io Diagram | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
The initial bootstrapping implementation is "simple". The implementation will bootstrap the Apache Geode system using the current bootstrapping mechanism of `LocatorLauncher` or `ServerLauncher`.
There will be two bootstrapping options:
- Using the current class loading mechanism
- Using the new JBoss module loading system to achieve class loading isolationachieve ClassLoader isolation
The determination of the bootstrapping type will be done in GFSH using an "--enable-classloader-isolation" flag. This flag will instruct GFSH to either use the current class loading mechanism or use the class loader isolated mechanismThe Bootstrap module will use the ModuleService to load modules/components or load service implementations using the standard ServiceLoader functionality. Other than the bootstrapping change the "normal" behavior of the system should not change.
The biggest change that will be visible will be when opting into using the JBoss Modules class loading. The initial targeted implementation would be the `gfsh deploy jar' .
...
draw.io Diagram | |||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
The deploy jar function initiated by running `deploy jar` --jar` from gfsh will trigger the Geode-Management JarDeploymentService to register the module with the ModuleService using the uploaded JAR-fileDeploymentService using the uploaded JAR file. This is done by the JAR file being placed in a known location on disk.
The ModuleService registration service will create a DeploymentService will create a JBoss Module module construct, with the jar as a resource and a dependency on the the Apache Geode system. The DeploymentService will then interact with the GeodeModuleLoader to load the jar into its own module and Classloader.
The The deployment of custom code, like gfsh deploy jar, will be handled by the ModuleService. The ModuleService will load the deployed jar into its own ClassLoader with a dependency on the Apache Geode system. That way the deployed custom code will still have access to the Apache Geode's public API'sAPIs, but without being exposed to not its libraries.
Changes and Additions to Public Interfaces
Gliffy Diagram macroId 47113394-4357-4196-b05e-18686ebe5381 displayName ClassDiagram - ModuleService name ClassDiagram - ModuleService pagePin 2
registerModule(moduleMeta:ModuleMeta):boolean – Registers a module given the ModuleMeta data object.
loadService(clazz: Class<T>): T – Load all services of type Class<T> . This functionality is equivalent to the ServiceLoader semantics currently present in Java
unloadModule(moduleName:String): boolean – Unloads the registered module
8
Performance Impact
No anticipated performance impact.
...
No backward compatibility impact.
No public API's APIs being changed
Deploying of jars might have a small change in behavior. The initial implementation might require the user to deploy a fully build built jar, not part-jars where the sum of the jars make up a whole. Upgrading of libraries will result in the old jar being undeployed and the new one deployed in its place.
...
An alternative to this solution is to either leave the ClassLoader model as it is currently working in Geode. Whilst the current approach has a notion of ClassLoader isolation, but the user will still be limited to the versions of the libraries that Apache Geode chooses to use.
...