# Sermant Agent使用手册
Sermant Agent是提供字节码增强基础能力及各类服务治理能力的核心组件。Sermant使用介绍中描述的产品目录sermant-agent-x.x.x/agent
目录下内容即为Sermant Agent组件的各模块。Sermant Agent的主体为Sermant提供了字节码增强基础能力及开发框架,同时支持心跳功能、动态配置功能、日志功能、事件上报等公共基础能力,当前已支持premain
和agentmain
两种方式启动。
Sermant Agent插件目录中则由各插件提供了标签路由、限流降级、双注册等服务治理能力,当前已支持在宿主服务运行时动态安装和卸载服务治理插件(需要插件支持动态安装和卸载)。
# 支持版本
Sermant Agent支持Linux、Windows,基于JDK 1.8开发,建议使用JDK 1.8版本及以上版本。
- HuaweiJDK 1.8 (opens new window) / OpenJDK 1.8 (opens new window) / OracleJDK 1.8 (opens new window)
# Agent启动
# premain方式
通过为宿主服务配置-javaagent
指令来利用premain
方式启动Sermant Agent ,基于快速开始所构建环境,执行以下命令启动Sermant Agent:
# linux mac
java -javaagent:${path}/sermant-agent-x.x.x/agent/sermant-agent.jar -jar spring-provider.jar
# windows
java -javaagent:${path}\sermant-agent-x.x.x\agent\sermant-agent.jar -jar spring-provider.jar
查看spring-provider.jar
的日志开头是否包含以下内容:
[xxxx-xx-xxTxx:xx:xx.xxx] [INFO] Loading god library into BootstrapClassLoader.
[xxxx-xx-xxTxx:xx:xx.xxx] [INFO] Building argument map by agent arguments.
[xxxx-xx-xxTxx:xx:xx.xxx] [INFO] Loading core library into SermantClassLoader.
[xxxx-xx-xxTxx:xx:xx.xxx] [INFO] Loading sermant agent, artifact is: default
[xxxx-xx-xxTxx:xx:xx.xxx] [INFO] Load sermant done, artifact is: default
若日志如上正常输出,则说明Sermant Agent启动成功,打开浏览器并导航到http://localhost:8900
,可以看到已经有Sermant Agent实例,如下图所示效果:
# agentmain方式
- 基于快速开始所构建环境,首先启动宿主服务
spring-provider.jar
java -jar spring-provider.jar
- 通过
agentmain
方式启动,需要借助Attach API
来完成,首先通过附件 AgentLoader.java创建一个Java文件,通过javac编译:
# Linux、MacOS
javac -cp ./:$JAVA_HOME/lib/tools.jar AgentLoader.java
# Windows 已正确配置JAVA所需环境变量
javac AgentLoader.java -encoding utf-8
- 编译完成后,将在目录下生成
AgentLoader.class
文件,使用如下指令运行AgentLoader
# Linux、MacOS
java -cp ./:$JAVA_HOME/lib/tools.jar AgentLoader
# Windows 已正确配置JAVA所需环境变量
java AgentLoader
# 运行指令根据所使用操作系统进行选择,此处以Linux、MacOS指令编写
$ java -cp ./:$JAVA_HOME/lib/tools.jar AgentLoader
请选择需要使用Sermant Agent的Java进程:
0: xxxxx AgentLoader # xxxxx为进程号,此处模糊
1: xxxxx spring-provider.jar # xxxxx为进程号,此处模糊
2: xxxxx sermant-backend-1.0.0.jar # xxxxx为进程号,此处模糊
请输入需要使用Sermant Agent的Java进程序号:1 # 选择spring-provider的进程序号
您选择的进程 ID 是:xxxxx # xxxxx为进程号,此处模糊
请输入Sermant Agent所在目录(默认采用该目录下sermant-agent.jar为入口):${path}/sermant-agent-x.x.x/agent # 填充Sermant Agent所在目录
请输入向Sermant Agent传入的参数(可为空,默认配置参数agentPath): # 配置Sermant Agent参数,此处可为空
按照指引填充完成后在spring-provider.jar
日志中可以看到以下内容:
[xxxx-xx-xxTxx:xx:xx.xxx] [INFO] Loading god library into BootstrapClassLoader.
[xxxx-xx-xxTxx:xx:xx.xxx] [INFO] Building argument map by agent arguments.
[xxxx-xx-xxTxx:xx:xx.xxx] [INFO] Loading core library into SermantClassLoader.
[xxxx-xx-xxTxx:xx:xx.xxx] [INFO] Loading sermant agent, artifact is: default
[xxxx-xx-xxTxx:xx:xx.xxx] [INFO] Load sermant done, artifact is: default
若日志如上正常输出,则说明Sermant Agent读取启动指令成功并开始执行安装,打开浏览器并导航到http://localhost:8900
,可以看到已经有Sermant Agent实例,如下图所示效果:
# Agent卸载
注:为避免部分基于premain启动方式开发的服务治理能力在卸载时引发不可预知的异常,Sermant Agent对卸载进行限制,通过agentmain方式启动的Sermant Agent才支持卸载,通过premain方式启动的Sermant Agent不支持。
在通过agentmain方式启动后,可以对Sermant Agent进行卸载,再次运行AgentLoader
,并通过传入参数下发卸载Sermant Agent的指令command=UNINSTALL-AGENT
:
# 运行指令根据所使用操作系统进行选择,此处以Linux、MacOS指令编写
$ java -cp ./:$JAVA_HOME/lib/tools.jar AgentLoader
请选择需要使用Sermant Agent的Java进程:
0: xxxxx AgentLoader # xxxxx为进程号,此处模糊
1: xxxxx spring-provider.jar # xxxxx为进程号,此处模糊
2: xxxxx sermant-backend-1.0.0.jar # xxxxx为进程号,此处模糊
请输入需要使用Sermant Agent的Java进程序号:1 # 选择spring-provider的进程序号
您选择的进程 ID 是:xxxxx # xxxxx为进程号,此处模糊
请输入Sermant Agent所在目录(默认采用该目录下sermant-agent.jar为入口):${path}/sermant-agent-x.x.x/agent # 填充Sermant Agent所在目录
请输入向Sermant Agent传入的参数(可为空,默认配置参数agentPath):command=UNINSTALL-AGENT # 此处通过传入参数下发卸载指令
按照指引填充完成后在spring-provider.jar
日志中可以看到以下内容:
[xxxx-xx-xxTxx:xx:xx.xxx] [INFO] Building argument map by agent arguments.
[xxxx-xx-xxTxx:xx:xx.xxx] [INFO] Sermant for artifact is running, artifact is: default
[xxxx-xx-xxTxx:xx:xx.xxx] [INFO] Execute command: UNINSTALL-AGENT
若日志如上正常输出,打开浏览器并导航到http://localhost:8900
,可以看到已经有Sermant Agent实例已经下线(状态为灰色),则说明Sermant Agent卸载成功,如下图所示效果:
注:该能力可以在开发态通过调用sermant-agentcore-core所提供 AgentCoreEntrance (opens new window)::uninstall()接口来实现
# 动态安装插件
在通过agentmain方式启动后,可以动态的安装服务治理插件(需要插件支持动态安装和卸载),再次运行AgentLoader
,并通过传入参数下发动态安装插件的指令command=INSTALL-PLUGINS:pluginA/pluginB
:
注:可以一次安装多个插件,插件名通过 '/' 进行分隔,pluginA、pluginB为插件名,需要按照实际实际填写,本示例使用monitor插件
# 运行指令根据所使用操作系统进行选择,此处以Linux、MacOS指令编写
$ java -cp ./:$JAVA_HOME/lib/tools.jar AgentLoader
请选择需要使用Sermant Agent的Java进程:
0: xxxxx AgentLoader # xxxxx为进程号,此处模糊
1: xxxxx spring-provider.jar # xxxxx为进程号,此处模糊
2: xxxxx sermant-backend-1.0.0.jar # xxxxx为进程号,此处模糊
请输入需要使用Sermant Agent的Java进程序号:1 # 选择spring-provider的进程序号
您选择的进程 ID 是:xxxxx # xxxxx为进程号,此处模糊
请输入Sermant Agent所在目录(默认采用该目录下sermant-agent.jar为入口):${path}/sermant-agent-x.x.x/agent # 填充Sermant Agent所在目录
请输入向Sermant Agent传入的参数(可为空,默认配置参数agentPath):command=INSTALL-PLUGINS:monitor # 此处通过传入参数下发安装插件指令 本示例以monitor进行演示
按照指引填充完成后在spring-provider.jar
日志中可以看到以下内容:
[xxxx-xx-xxTxx:xx:xx.xxx] [INFO] Building argument map by agent arguments.
[xxxx-xx-xxTxx:xx:xx.xxx] [INFO] Sermant for artifact is running, artifact is: default
[xxxx-xx-xxTxx:xx:xx.xxx] [INFO] Execute command: INSTALL-PLUGINS:monitor # 本示例以monitor进行演示
若日志如上正常输出,则说明插件安装成功,打开浏览器并导航到http://localhost:8900
,可以看到插件已被成功安装,插件列可以看到当前安装的插件,如下图所示效果:
动态安装插件前
动态安装插件后
注:该能力可以在开发态通过调用sermant-agentcore-core所提供PluginManager (opens new window)::install(Set pluginNames)方法来实现
# 动态卸载插件
在通过agentmain方式启动并动态安装插件后,可以动态的卸载服务治理插件(需要插件支持动态安装和卸载),再次运行AgentLoader
,并通过传入参数下发动态卸载插件的指令command=UNINSTALL-PLUGINS:pluginA/pluginB
:
注:可以一次卸载多个插件,插件名通过 '/' 进行分隔,pluginA、pluginB为插件名,需要按照实际实际填写,本示例使用monitor插件
# 运行指令根据所使用操作系统进行选择,此处以Linux、MacOS指令编写
$ java -cp ./:$JAVA_HOME/lib/tools.jar AgentLoader
请选择需要使用Sermant Agent的Java进程:
0: xxxxx AgentLoader # xxxxx为进程号,此处模糊
1: xxxxx spring-provider.jar # xxxxx为进程号,此处模糊
2: xxxxx sermant-backend-1.0.0.jar # xxxxx为进程号,此处模糊
请输入需要使用Sermant Agent的Java进程序号:1 # 选择spring-provider的进程序号
您选择的进程 ID 是:xxxxx # xxxxx为进程号,此处模糊
请输入Sermant Agent所在目录(默认采用该目录下sermant-agent.jar为入口):${path}/sermant-agent-x.x.x/agent # 填充Sermant Agent所在目录
请输入向Sermant Agent传入的参数(可为空,默认配置参数agentPath):command=UNINSTALL-PLUGINS:monitor # 此处通过传入参数下发安装插件指令
按照指引填充完成后在spring-provider.jar
日志中可以看到以下内容:
[2023-09-27T17:42:50.500] [INFO] Building argument map by agent arguments.
[2023-09-27T17:42:50.504] [INFO] Sermant for artifact is running, artifact is: default
[2023-09-27T17:42:50.504] [INFO] Execute command: UNINSTALL-PLUGINS:monitor #本示例以monitor进行演示
# 该日志会展示本次卸载中恢复了多少被字节码增强过的类
[Byte Buddy] REDEFINE BATCH #0 [1 of 1 type(s)]
[Byte Buddy] REDEFINE COMPLETE 1 batch(es) containing 1 types [0 failed batch(es)]
[Byte Buddy] REDEFINE COMPLETE 1 batch(es) containing 0 types [0 failed batch(es)]
若日志如上正常输出,打开浏览器并导航到http://localhost:8900
,可以看到插件已被成功卸载,插件列可以看到当前安装的插件,如下图所示效果:
动态卸载插件前
动态卸载插件后
注:该能力可以在开发态通过调用sermant-agentcore-core所提供PluginManager (opens new window)::uninstall(Set pluginNames)方法来实现
# 配置规范
Sermant项目properties配置文件和各插件的中yaml配置文件都支持下列几种参数配置方式,以配置文件中的gateway.nettyIp=127.0.0.1
为例:
- 直接修改配置文件,即在配置文件中修改
gateway.nettyIp=127.0.0.1
- 通过应用启动时的-D参数配置,即
-Dgateway.nettyIp=127.0.0.1
- 通过环境变量配置,即在环境变量中新增
gateway.nettyIp=127.0.0.1
- 通过Sermant Agent启动参数配置,即
-javaagent:sermant-agent.jar=gateway.nettyIp=127.0.0.1
以上四种方式,配置生效的优先级从高到低排列为:4 > 3 > 2 > 1。
其中,后三种参数配置值的获取方式支持多种格式,以配置文件中的gateway.nettyIp=127.0.0.1
为例,下列配置格式都可识别:
gateway.nettyIp=127.0.0.1
gateway_nettyIp=127.0.0.1
gateway-nettyIp=127.0.0.1
GATEWAY.NETTYIP=127.0.0.1
GATEWAY_NETTYIP=127.0.0.1
GATEWAY-NETTYIP=127.0.0.1
gateway.nettyip=127.0.0.1
gateway_nettyip=127.0.0.1
gateway-nettyip=127.0.0.1
gateway.netty.ip=127.0.0.1
gateway_netty_ip=127.0.0.1
gateway-netty-ip=127.0.0.1
GATEWAY.NETTY.IP=127.0.0.1
GATEWAY_NETTY_IP=127.0.0.1
GATEWAY-NETTY-IP=127.0.0.1
Sermant Agent将从上至下依次检索各项配置值是否通过启动参数、环境变量、-D参数来配置。
注意: 通过容器场景的env修改配置,请将点(.)可用下划线(_)替代!!!
原因:因为一些OS镜像无法识别带 . 的env
举个例子:如需想通过pod的env修改配置文件中的gateway.nettyIp=127.0.0.1
则
env:
- name: "gateway_nettyIp"
value: "127.0.0.2"
# 附件
# AgentLoader.java
import com.sun.tools.attach.AgentInitializationException;
import com.sun.tools.attach.AgentLoadException;
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
public class AgentLoader {
private AgentLoader() {
}
/**
* AgentLoader 的main方法
*/
public static void main(String[] args)
throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException {
List<VirtualMachineDescriptor> vmDescriptors = VirtualMachine.list();
if (vmDescriptors.isEmpty()) {
System.out.println("没有找到 Java 进程");
return;
}
System.out.println("请选择需要使用Sermant Agent的Java进程:");
for (int i = 0; i < vmDescriptors.size(); i++) {
VirtualMachineDescriptor descriptor = vmDescriptors.get(i);
System.out.println(i + ": " + descriptor.id() + " " + descriptor.displayName());
}
// 读取用户输入的序号
BufferedReader userInputReader = new BufferedReader(new InputStreamReader(System.in));
System.out.print("请输入需要使用Sermant Agent的Java进程序号:");
int selectedProcessIndex = Integer.parseInt(userInputReader.readLine());
if (selectedProcessIndex < 0 || selectedProcessIndex >= vmDescriptors.size()) {
System.out.println("无效的进程序号");
return;
}
// 连接到选定的虚拟机
VirtualMachineDescriptor selectedDescriptor = vmDescriptors.get(selectedProcessIndex);
System.out.println("您选择的进程 ID 是:" + selectedDescriptor.id());
VirtualMachine vm = VirtualMachine.attach(selectedDescriptor);
// 获取Sermant Agent目录
System.out.print("请输入Sermant Agent所在目录(默认采用该目录下sermant-agent.jar为入口):");
String agentPath = userInputReader.readLine();
// 获取传入Sermant Agent的参数
System.out.print("请输入向Sermant Agent传入的参数(可为空,默认配置参数agentPath):");
String agentArgs = "agentPath=" + agentPath + "," + userInputReader.readLine();
// 关闭资源
userInputReader.close();
// 启动Sermant Agent
vm.loadAgent(agentPath + "/sermant-agent.jar", agentArgs);
vm.detach();
}
}