Quick development and usage guide for service governance plug-ins under the Sermant framework

Summary

Sermant is a cloud-native agentless service mesh based on Java bytecode enhancement technology. It is non-intrusive, plug-inable and high-performance. Through the Sermant core framework, plug-ins for various service management purposes can be easily developed, including load balancing, flow control, label routing, label transparent transmission, etc. In this article, we use a case to explain how to develop a plug-in that counts the call duration based on Sermant and use it for deployment in the production environment.
In the first chapter, we explain how to quickly develop a plug-in and demonstrate the complete code development process. We will focus on 1) how to develop a main module to enhance the code for the application; 2) how to package and build plug-ins.
In Chapter 2, we will explain how to perform service governance through the Sermant package developed in Chapter 1. We will demonstrate that the host application mounts the Sermant Agent through the premain method and verifies the enhancement effect.
In Chapter 3, we will introduce the high-level functions provided by Sermant. Key points include: 1) Monitoring Sermant Agent through Sermant Backend; 2) How to use the Sermant log function for log printing to avoid class conflicts in the log function while taking into account the observability of the abnormal status of the sidecar; 3) How to use dynamic configuration functions Adjust Agent runtime behavior in real time.

1. Plug-in Development

In this chapter, we will completely demonstrate the process of developing service governance plug-ins using the Sermant framework from scratch based on the plug-in development template officially provided by Sermant.

The main task that this template plug-in needs to implement is to intercept and enhance the controller interface method of the host application and calculate the method execution time.

Next, let’s start the code path of plug-in development!

Sermant officially provides template code for plug-in development. Execute the following Maven instructions to pull:

$ mvn archetype:generate -DarchetypeGroupId=com.huaweicloud.sermant -DarchetypeArtifactId=sermant-template-archetype -DarchetypeVersion=1.2.0 -DgroupId=com.huaweicloud.sermant -Dversion=1.2.0 -Dpackage=com.huaweicloud -DartifactId=first-plugin 

For specific implementation steps and details, please refer to the Sermant official website to create the first plug-in document. The template code pre-designs the project structure and pom file configuration for plug-in development, so we can better focus on the implementation of plug-in functions. The code shown below was developed based on this template. We also provide our developed sample code in the first-plugin-demo of Sermant-example.

1.1 Plug-in main module development

The plug-in main module is the main implementation of the plug-in, and developers need to declare the plug-in’s enhancement logic in this module.

The plug-in main module needs to determine which classes of the host application to intercept. In this article, the intercepted classes of the host application are as follows:

package com.huaweicloud.template;
  
@RestController
public class Controller {
    @RequestMapping("sayHello")
    public void sayHello(String name) throws InterruptedException {
        System.out.println("hello " + name);
        Thread.sleep(5);
    }
}

The main module of the plug-in needs to complete the enhancement logic that calculates the time-consuming execution of the sayHello method, so we first need to intercept the sayHello method of the Controller class, and then perform pre- and post-enhancement calculations on the method in the interceptor.

Create the com.huawei.sermant.template package in the template-plugin module. The classes created in this section are all located in this package.

1) Create the TemplateDeclarer class, which inherits from the com.huaweicloud.sermant.core.plugin.agent.declarer.AbstractPluginDeclarer class. You need to override the getClassMatcher method and getInterceptDeclarers method of the parent class. The class name and method name used to declare bytecode enhanced interception, and the corresponding interceptor. The code implementation details are as follows:

public class TemplateDeclarer extends AbstractPluginDeclarer {
    @Override
    public ClassMatcher getClassMatcher() {
        // Match the classes that need to be intercepted. There are multiple matching methods. Here we use the fully qualified name of the class to match.
        return ClassMatcher.nameEquals("com.huaweicloud.template.Controller" );
    }
  
    @Override
    public InterceptDeclarer[] getInterceptDeclarers(ClassLoader classLoader) {
        // Return the InterceptDeclarer array. Each InterceptDeclarer determines the method and Interceptor it needs to intercept.
        return new InterceptDeclarer[]{
                // Match the methods that need to be intercepted. There are multiple matching methods. Here, the method name is used for matching.
                InterceptDeclarer.build(MethodMatcher.nameEquals("sayHello"), new TemplateInterceptor())
        };
    }
} 

The ClassMatcher class and the MethodMatcher class have multiple matching methods. You can check the bytecode enhancement documentation on the Sermant official website.

2) Create the TemplateInterceptor class, which needs to implement the com.huaweicloud.sermant.core.plugin.agent.interceptor.Interceptor interface, and rewrite the before, after, and onThrow methods of the interface to achieve pre-enhancement and post-interception points respectively. Set enhancement and exception handling code logic. The code implementation details are as follows:

public class TemplateInterceptor implements Interceptor {
   
    private static final String START_TIME = "startTime";
  
    @Override
    public ExecuteContext before(ExecuteContext context) {
        context.setLocalFieldValue(START_TIME, System.currentTimeMillis());
        System.out.println("The time when the recorded method started running");
        return context;
    }
  
    @Override
    public ExecuteContext after(ExecuteContext context) {
        long endTime = System.currentTimeMillis();
        long elapsedTime = endTime - (long) context.getLocalFieldValue(START_TIME);
        System.out.println("Method takes time:" + elapsedTime + "milliseconds");
        return context;
    }
  
    @Override
    public ExecuteContext onThrow(ExecuteContext context) {
        return context;
    }
}

We record the start time of the intercepted method execution in the before method, calculate the execution time of the intercepted method in the after method and print it to the console.

3) Add the SPI configuration of the enhanced declaration, add the META-INF/services directory to the resources directory under template/template-plugin in the project, and create a directory named com.huaweicloud.sermant.core.plugin.agent.declarer in it. .PluginDeclarer’s SPI file and add the class name of the bytecode enhanced declaration class to it:

com.huaweicloud.sermant.template.TemplateDeclarer

At this point, the code logic development of the main module of the plug-in is completed. We have implemented the interception of the target class and enhanced the methods of the intercepted class.

1.2 Plug-in packaging and building

Execute the maven command in the template directory to package and build the template plug-in:

mvn clean package

After the build is completed, the agent/ directory will be generated. The specific file structure is as follows:

.
├── common
├── config Sermant configuration file
├──core
├── god
├── implemant
├──Application.jar host application, which can be replaced by your own developed application
├── sermant-agent.jar Sermant Agent product, used for mounting and use by host applications
└── pluginPackage
    └── template
        ├── config plug-in configuration file
        ├── plugin plug-in main module
        └── service plug-in service module

Now that we have completed a simple plug-in that can calculate the time taken by intercepted methods, we will start to show the effect of the plug-in.

2. Sermant Agent Use

2.1 Start Sermant Agent

Sermant enables the dynamic configuration service by default. Modify the config.properties file in the config directory to turn off the dynamic configuration service:

# Dynamically configure service switches
agent.service.dynamic.config.enable=false 

Enter the product directory agent/ built in Chapter 1.2, and start the Sermant Agent in premain mode by configuring the -javaagent directive for the host service:

java -javaagent:sermant-agent.jar -jar Application.jar

The console prints the following output, indicating that the Sermant Agent is successfully started in premain mode.

[2023-1024T17:26:49.049] [INFO] Loading god library into BootstrapClassLoader.
[2023-10-24T17:26:49.153] [INFO] Building argument map by agent arguments.
[2023-10-24T17:26:49.161] [INFO] Loading core library into SermantClassLoader.
[2023-10-24T17:26:49.162] [INFO] Loading sermant agent, artifact is: default
[2023-10-24T17:26:49.740] [INFO] Load sermant done, artifact is: default

Sermant Agent can also perform mounting while the host application is running through the agentmain method. For more details about the use of Sermant Agent, please refer to the Sermant Agent User Manual document on the Sermant official website.

2.2 Verification

The host application has successfully mounted the Sermant Agent. In this section we will verify whether the plug-in enhancement logic takes effect.

Execute the following command to initiate a get request for the host application interface service:

curl http://127.0.0.1:8080/sayHello?name=lihua

The output printed by the host application console is as follows:

The time when the method execution started has been recorded
hello lihua
Method takes: 20 milliseconds
ECHO: Best wish to you!

It can be seen that the Sermant Agent successfully intercepted the classes of the host application and executed the enhanced logic.

3. Sermant Advanced functions

3.1 Sermant Backend

Sermant Backend includes Sermant data processing back-end module and front-end information display module, aiming to provide runtime observability capabilities for Sermant. Currently, it mainly includes functions such as Sermant Agent heartbeat information, reception and display of reported events, and webhook push.

Sermant Backend works with Sermant Agent. The Sermant Agent is mounted in the host application. As a data sender, it can regularly send the current Sermant Agent’s heartbeat data (service name, host name, instance ID, version number, IP, timestamp, plug-in mounting information) and event data ( Sermant Agent start and stop, core service start and stop, bytecode enhancement, log data, etc.)

Backend is a non-essential component. Users can deploy it on demand and obtain the Backend component by downloading the release package of Sermant-1.2.0. Unzip the release package, enter the sermant-agent/server/sermant directory and execute the following command to start Sermant Backend:

java -jar sermant-backend-1.2.0.jar

Access the address http://127.0.0.1:8900/ through the browser. If you see the following page, it means that Sermant Backend is started successfully;

Sermant Agent needs to configure the parameters of the Agent when using Backend. Modify the config.properties file in the agent (product directory built in Chapter 1)/config directory.

The configuration items need to be modified as:

# Enable heartbeat service switch
agent.service.heartbeat.enable=true
# Turn on the unified gateway service switch
agent.service.gateway.enable=true

Refer to Section 2.1 to start the Sermant Agent. You can see the started Sermant Agent and mounted template plug-in information on the Backend front-end page:

For more details about Backend, please refer to the Sermant Backend User Manual document on the official Sermant website.

3.2 Log function

Logs are an indispensable capability in program development. Through logs, you can quickly find out the status of the program when it is running and the problems encountered.

JavaAgent products are prone to conflicts with host application classes and log configuration conflicts when using log classes. The log system built by Sermant solves this problem. The Sermant log system is built on JUL & logback, providing a complete, flexible configuration, and class conflict-avoiding log tool for plug-in development. The log system provided by Sermant can be fully integrated with the host microservice from configuration to execution. isolation. In addition, combined with the Sermant Backend component, the Sermant log system can provide unified collection and reporting of abnormal events.

Now we need to record the execution time of the intercepted method in the log. This section will demonstrate how to use the logging system provided by Sermant.

3.2.1 Add log

We define a private static constant LOGGER in the TemplateInterceptor class of the main module of the plug-in, which is used for log construction under this class.

// Sermant log class
private static final Logger LOGGER = LoggerFactory.getLogger(); 

Next, we use logging in the after method of this class to record the running time of the intercepted method. The level of this log is INFO.

LOGGER.info("Method time-consuming: " + elapsedTime);

The Sermant log system can record logs of various levels (TRACE, DEBUG, INFO, WARN, ERROR) to achieve different levels of monitoring of program operation.

For more details, please refer to the Sermant official website log function documentation.

3.2.2 Log demo

Start Sermant and call the interface of the host application according to the method in Chapter 2:

curl http://127.0.0.1:8080/sayHello?name=lihua

Go to the logs/sermant/core/app/xxxx-xx-xx directory to view the Sermant log. “xxxx-xx-xx” is the time when the log was recorded. You can see that the method’s time consumption is successfully recorded in the log file.

[INFO] [com.huaweicloud.sermant.template.TemplateInterceptor] [after:45] [http-nio-8080-exec-1] Method takes: 20 

3.2.3 Exception log reporting

Warn and error level logs collected uniformly by the Sermant log system can be uploaded to Sermant Backend for observation. We will manually print the exception log and observe it through Backend.

Print a warn-level log in the before method of the TemplateInterceptor class of the plug-in’s main module, and print an error-level log in the after method:

LOGGER.warning("warning message");
LOGGER.severe("error message");

Modify the config.properties file in the config directory to enable event reporting related configurations:

# Event system switch
event.enable=true
# Warn level log event reporting switch
event.offerWarnLog=true
# Error level log event reporting switch
event.offerErrorLog=true

Start Sermant and call the interface of the host application according to the method in Chapter 2:

curl http://127.0.0.1:8080/sayHello?name=lihua

Go to the Sermant Backend front-end page to see the reported exception information:

3.3 Dynamic configuration

3.3.1 Add dynamic configuration

Sermant provides dynamic configuration functions and currently supports Zookeeper, Nacos and Kie as configuration centers. The dynamic configuration function allows Sermant to perform configuration management and monitoring operations on the configurations issued by the dynamic configuration center to achieve rich and diverse service governance capabilities. This section takes Zookeeper as an example to demonstrate how to use Sermant’s dynamic configuration service to add a switch for executing enhanced logic to this plug-in.

First, add a Map field to the TemplateInterceptor class in the main module of the plug-in to simulate the switch state. ENABLE_KEY is the name of the switch, and set the default state of the switch to true:

private static final Map<String, Boolean> CONFIG_MAP = new HashMap<>();
  
private static final String ENABLE_KEY = "enable";
{
    //The default state of the switch is true
    CONFIG_MAP.put(ENABLE_KEY, true);
}

Then add switches in the before method and after method:

if (!CONFIG_MAP.get(ENABLE_KEY)) {
    System.out.println("Do not execute enhanced logic");
    return context;
}

Next, we need to dynamically modify the status of the switch, add the dynamic configuration service field, obtain the dynamic configuration service class instance and register a listener to monitor the corresponding node changes in Zookeeper:

//Get dynamic configuration service class instance
    private final DynamicConfigService dynamicConfigService = ServiceManager.getService(DynamicConfigService.class);
  
// Get the yaml parser provided by the Sermant framework
    private final YamlConverter converter = OperationManager.getOperation(YamlConverter.class);
  
    {
       dynamicConfigService.addConfigListener("template-config", "sermant/template-plugin",
            new DynamicConfigListener() {
                @Override
                public void process(DynamicConfigEvent event) {
                    // Parse yaml file into map
                    Optional<Map<String, Object>> convertOptional = converter.convert(event.getContent(), Map.class);
                    if (convertOptional.isPresent()) {
                        //Modify switch status
                        CONFIG_MAP.put(ENABLE_KEY, (boolean) convertOptional.get().get(ENABLE_KEY));
                    }
                    System.out.println("The plug-in configuration item has changed, the configuration item value is: " + event.getContent());
                }
            });
    } 

To use dynamic configuration, you need to turn on the dynamic configuration service switch and modify the config.properties file in the config directory:

# Dynamically configure service switches

agent.service.dynamic.config.enable=true

3.3.2 Dynamic Configuration Demonstration

To enable the dynamic configuration service, you need to start zookeeper locally. Start the host application and mount the Sermant Agent, and initiate a call to the host application interface service:

curl http://127.0.0.1:8080/sayHello?name=lihua

At this time, the switch is turned on by default, and the console output is as follows:

The time when the method execution started has been recorded
hello lihua
Method takes: 23 milliseconds 

Start delivering dynamic configuration, create the /sermant/template-plugin/template-config node, and set the value of the node to “enable: false”:

create /sermant
create /sermant/template-plugin
create /sermant/template-plugin/template-config enable: false

The host application console prints the following output:

The plug-in configuration item has changed, the configuration item value is: enable: false

Make another call to the host application interface service:

curl http://127.0.0.1:8080/sayHello?name=lihua

You can see that the console prints out the content that the enhanced logic is not executed, indicating that the dynamic configuration is successfully delivered:

Do not execute enhancement logic
hello lihua
Enhancement logic is not executed

The demonstration of dynamic configuration ends here. For more details of dynamic configuration, please refer to the dynamic configuration function document of Sermant official website.

IV. Summary of this chapter

This article introduces the process of quickly developing service governance plug-ins based on the Sermant framework and how to use the Sermant Agent product. It can be found that through the capabilities provided by the Sermant underlying framework, we can easily develop plug-ins that meet our own needs. At the same time, combined with Sermant’s logging system, dynamic configuration and Backend components, we can enhance the functions of the service management plug-in in a more refined and flexible manner. Sermant is an agentless service grid based on Java bytecode enhancement technology. It is non-intrusive, plug-inable and high-performance. I hope this article will be helpful to developers who are willing to use Sermant products!

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.

  • Sermant Official website: https://sermant.io
  • GitHub Warehouse address: https://github.com/huaweicloud/Sermant
  • Scan the QR code to join the Sermant community communication group

The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge. Cloud native entry-level skills treeHomepageOverview 17033 people are learning the system