Sermant class isolation architecture: practice in resolving JavaAgent scene class conflicts

This article is shared from Huawei Cloud Community " Analysis of Sermant Class Isolation Architecture - Practice of Resolving JavaAgent Scenario Class Conflicts ", author: Huawei Cloud Open Source.

Sermant is an agentless service mesh based on Java bytecode enhancement technology, which uses Java bytecode enhancement technology to provide service management functions for host applications. Knowing the impact of class conflicts in JavaAgent scenarios, Sermant planned a comprehensive class isolation architecture from the beginning of the design. After many iterations, Sermant's class isolation architecture can now easily cope with various complex class loading environments.

1. Why should we pay attention to class conflicts in JavaAgent scenarios?

The class conflict problem does not only exist in the JavaAgent scenario, but has always existed in the Java scenario. This problem usually causes exceptions such as NoClassDefFoundError, ClassNotFoundException, and NoSuchMethodError to be triggered at runtime.

From the perspective of usage scenarios, tools implemented based on JavaAgent technology are often used in monitoring, governance and other scenarios, and are not core business programs of the enterprise. If class conflicts are introduced during use, it may cause the core business program to malfunction, and the gain outweighs the losses. Therefore, avoiding the introduction of class conflicts into the core business program is a basic requirement of a JavaAgent tool.

Another important reason is that in Java applications, this problem can be solved in the development state by means of upgrading and downgrading dependencies and unified dependency architecture management. However, tools implemented based on JavaAgent technology act in the running state and cannot perform unified dependency management with Java applications that need to be enhanced in the development state, so the possibility of introducing class conflicts is greater.

2. How to solve this problem in JavaAgent scenario?

Whether in Java applications or in JavaAgent scenarios, the logic for repairing class conflicts is the same, which is to avoid introducing conflicting classes. The difference is that various tools implemented based on JavaAgent technology are often business-independent and are not customized for specific Java application types at the beginning of design and implementation. For JavaAgent programs, applications that need to be enhanced by bytecode are black boxes, so they cannot sort out the dependency structure, exclude and upgrade dependencies, and uniformly manage dependency architecture like Java applications. And JavaAgent is often used at runtime, so conflicts can only be avoided by ensuring absolute isolation of dependencies.

Why class conflicts occur is not the focus of this article. Simply put, it is because we repeatedly introduce transitive dependencies and cannot control the loading order of classes in Java, which leads to the introduction of the same class loader and fully qualified class name (Fully Qualified). Class Name) but behave differently [class logic is inconsistent due to different class versions]. Therefore, in order to avoid conflicts, we need to avoid introducing the same class at runtime. How to make the classes introduced by JavaAgent completely different from the host is based on fully qualified class names and class loaders:

  • Class isolation based on maven shade plugin

This plug-in is a plug-in provided by Maven for building and packaging. It uses the 'Relocating Classes' capability of maven-shade-plugin to modify the fully qualified class names of certain classes.

cke_151.png

The principle of this method is to change the fully qualified class name so that the classes introduced by JavaAgent and the classes of the Java program are completely impossible to have the same situation, fundamentally avoiding class conflicts. But when we use a framework or a product, convention is often better than configuration. Changing the fully qualified class name through configuration based on maven-shade-plugin is not a simple method. When using it, you need to target JavaAgent. The dependencies involved are sorted out, configured in the maven-shade-plugin, and need to be re-screened after each dependency change. Very unfriendly to continuous iteration.

Using the above method also hinders debugging. The breakpoints of the redirected classes during the debugging process will be unreachable, seriously reducing debugging efficiency.

  • Class isolation based on class loading mechanism

Modifying the fully qualified class name based on maven-shade-plugin is often used to solve single-point class conflict problems. Although it can also completely isolate the classes introduced by JavaAgent, it is not a good solution.

Based on the principle of class conflict, we can also restrict the loaders of two classes with the same fully qualified class name to make them different. Like Tomcat, a custom class loader destroys Java's parental delegation principle to isolate the classes introduced by JavaAgent. . This avoids heavy configuration and the impact of dependency changes. But it also has its drawbacks. In JavaAgent scenarios, Java application classes are often used. Therefore, the isolation mechanism based on class loaders often allows developers to complete such logic only through operations such as reflection, which will affect performance and development. adversely affect efficiency.

3. How does Sermant do it?

Sermant is an agentless service grid based on Java bytecode enhancement technology. It is not only an out-of-the-box service governance tool, but also an easy-to-use service governance capability development framework.

"Leave the simplicity to others and the trouble to yourself!"

Sermant has followed the above important principles from the beginning of its design, and has planned a comprehensive class isolation architecture. It uses Java's class loading mechanism to fully isolate each module of its own modules, so that users and developers do not need to consider the consequences of using JavaAgent. It solves class conflict problems and is optimized for developers' usage scenarios. It can seamlessly use enhanced Java program classes during development to avoid adverse effects caused by reflection and other behaviors. How is Sermant implemented? The following will provide a detailed analysis of the Sermant class isolation architecture.

1) Analysis of Sermant’s class isolation architecture

As mentioned above, Sermant is not only an out-of-the-box service grid, but also an easy-to-use service governance capability development framework. Service governance capabilities are diverse, including but not limited to traffic governance, availability governance, security governance, etc. Therefore, Sermant adopts a plug-in architecture to allow users to more flexibly access and develop service governance capabilities.

cke_152.png

Under Sermant's overall architecture, we not only need to ensure that class conflicts are not introduced into the host service to avoid negative impacts on the host service when used out of the box, but we also need to ensure that classes are not introduced between the framework and plug-ins, and between plug-ins. Conflict issues prevent plug-in developers from being distressed by class conflicts with other service management plug-ins, so Sermant designed the following class isolation structure:

cke_153.png

  • SermantClassLoader destroys parental delegation , is used to load the core logic of the Sermant framework, and isolates Sermant's class loading model under the AppClassLoader. Avoid being affected by the complex class loading structure of the host service itself and reduce the adaptation requirements for services with different class loading structures.
  • FrameworkClassLoader destroys parent delegation . Its main function is to isolate the three-party dependencies introduced by Sermant's core capabilities and avoid introducing class conflicts to host services and service management plug-ins. The current main scenarios are ① used to isolate the log system of Sermant to avoid impact on the log system of the host service ② to isolate the three-party dependencies required by the core services of the Sermant framework (heartbeat, dynamic configuration, unified messaging gateway).
  • PluginClassLoader, which follows parent delegation , is mainly used to isolate Sermant service management plug-ins and avoid class conflicts between different service management plug-ins.
  • ServiceClassLoader destroys parental delegation and is mainly used to isolate dependencies in plug-ins. The related libs of the plug-in service are loaded through this class loader (the plug-in service will be initialized by Sermant when the plug-in is loaded). Developers can introduce third-party dependencies at will without worrying about the dependencies. Influence of the main logic of the plugin.

The PluginClassloader and ServiceClassloader not only play a vital role in class isolation, but also a long-term consideration. Designing an independent class loader for each plug-in allows Sermant to smoothly dynamically install & uninstall plug-ins and plug-ins. Hot update.

2) Special features of plug-in isolation

cke_154.png

In the class isolation architecture mentioned above, you can see a special logic (red box), which is also the special feature of PluginClassLoader (plug-in class loader) in Sermant. In actual use, each plug-in class The loader maintains a local class loader (localLoader) for each thread.

PluginClassLoader follows parent delegation. During the class loading process, it first delegates SermantClassLoader to load Sermant's core class, and then loads the plug-in class by itself. When it needs to use the class of the host service, it delegates the local class loader (its Parent can be any class loader). device, not limited to those indicated in the figure) for loading. The aspect logic (Sermant interceptor) used to enhance the bytecode can obtain the classes used by the host service, which is beneficial to service management scenarios. The logic is shown in the following figure:

cke_155.png

By rewriting the loadClass logic of the class loader, when executing the Sermant interceptor, a local class loading environment is configured, so that the logic in the Sermant interceptor can smoothly use the classes loaded by the host service, so that reflection is not required when developing service management plug-ins . Obtain the class of the host service , thereby improving the development efficiency of service governance capabilities and the final runtime performance, while also avoiding class conflicts between the host service and the service governance plug-in.

(The code implementation can be viewed in the open source warehouse:)

3) What is the actual combat effect?

Dependency conflicts and class conflicts caused by access to JavaAgent are common problems in the industry. However, with the support of Sermant's class loading mechanism, this problem can be avoided from the root and will no longer affect the majority of JavaAgent users and developers. Harmful!

The case described in "Please, don't rely on fastjson in the agent" is a typical scenario of dependency conflict problems caused by JavaAgent. Its application is loaded into the fastjson class FastJsonHttpMessageConverter in the Agent through AppClassLoader, which depends on spring-web.jar. The class GenericHttpMessageConverter, but because spring-web.jar is not in the search path of AppClassLoader (fastjson is introduced through the provide method), the class ultimately fails to be loaded.

However, if you develop based on Sermant, this problem will not occur. The class isolation architecture when developing JavaAgent and Spring applications based on Sermant is as follows:

cke_156.png

There are two key differences under the structure of this class of loaders:

  1. Since Sermant changed the class loading structure, fastjson introduced through Agent is no longer in the search path of AppClassLoader. Therefore, the FastJsonHttpMessageConverter class in Agent will no longer be loaded by Spring application through AppClassLoader, which avoids the class conflict problem triggered in this article from the root. .
  2. When the Agent needs to use the spring-web class GenericHttpMessageConverter at runtime, it can successfully obtain it from the Spring application through the LaunchedUrlClassloader through the local class loading environment provided by Sermant.

It is precisely because of these two differences that capabilities developed based on Sermant can isolate classes from applications to avoid class conflicts introduced through JavaAgent. At the same time, classes introduced by applications can be used at runtime.

4. Summary

Sermant is an agentless service mesh based on Java bytecode enhancement technology, which uses Java bytecode enhancement technology to provide service management functions for host applications. Knowing the impact of class conflicts in JavaAgent scenarios, Sermant planned a comprehensive class isolation architecture from the beginning of the design. After many iterations, Sermant's class isolation architecture can now easily cope with various complex class loading environments.

In addition to ensuring class isolation, Sermant, as a service grid, needs to focus on the performance impact of its own service governance capabilities on host services, so it also uses unique design to avoid performance losses caused by excessive isolation. At the same time, Sermant is also building an open service governance plug-in development ecosystem and providing an efficient service governance capability development framework. Issues such as ease of use and improvement in development efficiency were also taken into consideration when designing class isolation. The existence of the class isolation mechanism does not reduce the efficiency of development and increase the steepness of the learning curve.

As a bytecode enhancement framework focusing on the field of service governance, Sermant is committed to providing a high-performance, scalable, easy-to-access, and feature-rich service governance experience, and will take care of performance, functionality, and experience in each version. , everyone is widely welcome to join.

Extra!

cke_18489.jpeg

Huawei will hold the 8th Huawei Connectivity Conference (HUAWEICONNECT 2023) at the Shanghai World Expo Exhibition and Convention Center and Shanghai World Expo Center from September 20-22, 2023. With the theme of "Accelerating Industry Intelligence", this conference invites thought leaders, business elites, technical experts, partners, developers and other industry colleagues to discuss how to accelerate industry intelligence from the aspects of business, industry, ecology and other aspects.

We sincerely invite you to come to the site, share the opportunities and challenges of intelligentization, discuss the key measures of intelligentization, and experience the innovation and application of intelligent technology. you can:

  • In 100+ keynote speeches, summits, and forums, collide with the viewpoint of accelerating industry intelligence
  • Visit the 17,000-square-meter exhibition area to experience the innovation and application of intelligent technology in the industry at close range
  • Meet face-to-face with technical experts to learn about the latest solutions, development tools, and hands-on
  • Seek business opportunities with customers and partners

Thank you for your continued support and trust, and we look forward to meeting you in Shanghai.

Official website of the conference: Huawei Connect Conference 2023 | HUAWEI CONNECT 2023

Welcome to follow the "Huawei Cloud Developer Alliance" public account to get the conference agenda, exciting activities and cutting-edge information.

Click to follow and learn about Huawei Cloud's fresh technologies for the first time~

Guess you like

Origin blog.csdn.net/devcloud/article/details/132760524