本文分享自华为云社区《Sermant框架下的服务治理插件快速开发及使用指南》,作者: 华为云开源 。

Sermant是基于Java字节码增强技术的云原生无代理服务网格,它具有非侵入、插件化和高性能的特点。通过Sermant核心框架,可以很容易的开发用于各种服务治理用途的插件,包括负载均衡、流量控制、标签路由、标签透传等。在本文中,我们通过案例讲解,说明如何基于Sermant开发一个接口统计调用时长的插件,并用于生产环境的部署。

一、 插件开发

本章,我们将基于Sermant官方提供的插件开发模板,从零开始完整的展示使用Sermant框架开发服务治理插件的流程。

本模板插件需要实现的主要任务是拦截并增强宿主应用的controller接口方法,计算方法执行耗时。

接下来就让我们开始插件开发的代码之路吧!

Sermant官方提供了插件开发的模板代码,执行以下Maven指令拉取:

$ 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

具体的执行步骤和细节可以参考Sermant官网创建​​首个插件文档​​。该模板代码预先设计了插件开发的项目结构和pom文件配置,我们可以更好的专注于插件功能的实现。下面展示的代码在此模板的基础上进行开发。我们也在​​Sermant-example的first-plugin-demo​​中提供了我们开发后的示例代码。

1.1 插件主模块开发

插件主模块是插件的主要实现,开发者需要在该模块中声明该插件的增强逻辑。

插件主模块需要确定拦截宿主应用的哪些类。本篇文章,宿主应用被拦截的类如下所示:

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);

}

}

插件主模块需要完成计算sayHello方法执行耗时的增强逻辑,因此我们首先需要拦截Controller类的sayHello方法,然后在拦截器中对该方法进行前置和后置增强计算方法耗时。

在template-plugin模块创建com.huawei.sermant.template包,本节创建的类均位于此包。

1)创建TemplateDeclarer类,该类继承自com.huaweicloud.sermant.core.plugin.agent.declarer.AbstractPluginDeclarer类,需重写父类的getClassMatcher方法和getInterceptDeclarers方法。用于声明字节码增强拦截的类名和方法名,以及相应的拦截器。代码实现细节如下:

public class TemplateDeclarer extends AbstractPluginDeclarer {

@Override

public ClassMatcher getClassMatcher() {

// 匹配需要拦截的类,具有多种匹配方式,本处使用类的全限定名匹配

return ClassMatcher.nameEquals("com.huaweicloud.template.Controller" );

}

@Override

public InterceptDeclarer[] getInterceptDeclarers(ClassLoader classLoader) {

// 返回InterceptDeclarer数组,每个InterceptDeclarer确定自己需要拦截的方法和Interceptor

return new InterceptDeclarer[]{

// 匹配需要拦截的方法,具有多种匹配方式,本处使用方法名称进行匹配

InterceptDeclarer.build(MethodMatcher.nameEquals("sayHello"), new TemplateInterceptor())

};

}

}

ClassMatcher类和MethodMatcher类具有多种匹配方法,可以查阅Sermant官网​​字节码增强文档​​。

2)创建TemplateInterceptor类,该类需实现com.huaweicloud.sermant.core.plugin.agent.interceptor.Interceptor接口,重写接口的before、after和onThrow方法,以分别实现对拦截点的前置增强、后置增强和异常处理代码逻辑。代码实现细节如下:

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("已记录方法运行开始的时间");

return context;

}

@Override

public ExecuteContext after(ExecuteContext context) {

long endTime = System.currentTimeMillis();

long elapsedTime = endTime - (long) context.getLocalFieldValue(START_TIME);

System.out.println("方法耗时:" + elapsedTime + "毫秒");

return context;

}

@Override

public ExecuteContext onThrow(ExecuteContext context) {

return context;

}

}

我们在before方法记录被拦截方法执行开始的时间,在after方法计算被拦截方法执行耗时并打印到控制台。

3)添加增强声明的SPI配置,在工程中template/template-plugin下的资源目录resources中添加META-INF/services目录,并在其中创建名为com.huaweicloud.sermant.core.plugin.agent.declarer.PluginDeclarer的SPI文件,并向其中添加字节码增强声明类的类名:

com.huaweicloud.sermant.template.TemplateDeclarer

到此,插件主模块的代码逻辑开发完成,我们实现了对目标类的拦截,并对被拦截类的方法进行了增强。

1.2 插件打包构建

在该模板目录下执行maven命令对模板插件进行打包构建:

mvn clean package

构建完成后会生成agent/目录,具体文件结构如下所示:

.

├── common

├── config Sermant配置文件

├── core

├── god

├── implemant

├── Application.jar 宿主应用,可以替换为自己开发的应用

├── sermant-agent.jar Sermant Agent产品,用于宿主应用挂载使用

└── pluginPackage

└── template

├── config 插件配置文件

├── plugin 插件主模块

└── service 插件服务模块

现在我们已经完成了一个简单的插件,该插件可以计算被拦截方法的耗时,下面我们将开始展示该插件的效果。

二、 Sermant Agent 使用

2.1 启动Sermant Agent

Sermant默认开启动态配置服务,​​修改config目录下的config.properties文件关闭动态配置服务:​​

# 动态配置服务开关

agent.service.dynamic.config.enable=false

进入到第一章1.2节构建的产物目录agent/中,通过为宿主服务配置-javaagent指令来通过premain方式启动Sermant Agent:

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

控制台打印如下输出说明通过premain方式启动Sermant Agent成功。

[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还可以通过agentmain方式在宿主应用运行中执行挂载。关于Sermant Agent使用的更多细节请参考Sermant官网​​Sermant Agent使用手册文档​​。

2.2 验证

宿主应用已经成功挂载Sermant Agent,本节我们将验证插件增强逻辑是否生效。

执行以下命令发起对宿主应用接口服务的get请求:

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

宿主应用控制台打印的输出内容如下所示:

已记录方法运行开始的时间

hello lihua

方法耗时:20毫秒

ECHO: Best wish to you!

可以看到,Sermant Agent成功拦截到了宿主应用的类并执行了增强逻辑。

三、 Sermant 进阶功能

3.1 Sermant Backend

Sermant Backend包含Sermant数据处理后端模块和前端信息展示模块,旨在为Sermant提供运行时的可观测能力,当前主要包括Sermant Agent心跳信息、上报事件的接收和展示、webhook推送等功能。

Sermant Backend与Sermant Agent配合使用。Sermant Agent挂载在宿主应用中,其作为数据发送端可定时发送当前Sermant Agent的心跳数据(服务名、主机名、实例ID、版本号、IP、时间戳、插件挂载信息)和事件数据(Sermant Agent启停、核心服务启停、字节码增强、日志数据等)。

Backend为非必要组件,用户可按需部署,通过​​下载Sermant-1.2.0​​的release包获取Backend组件。解压该release包,进入sermant-agent/server/sermant目录执行以下命令启动Sermant Backend:

java -jar sermant-backend-1.2.0.jar

通过浏览器访问地址​​http://127.0.0.1:8900/​​,如果看到如下页面,则说明Sermant Backend启动成功;

Sermant Agent使用Backend需要对Agent的参数进行配置。修改agent(第一章构建的产物目录)/config目录下的config.properties文件。

配置项需修改为:

# 开启心跳服务开关

agent.service.heartbeat.enable=true

# 开启统一网关服务开关

agent.service.gateway.enable=true

参考2.1节启动Sermant Agent,在Backend前端页面可以看到启动的Sermant Agent和挂载的template插件信息:

关于Backend的更多细节请参考Sermant官网​​Sermant Backend使用手册文档​​。

3.2 日志功能

日志是在程序开发中不可或缺的能力,通过日志可以快速找出程序运行时的状态及遇到的问题。

JavaAgent产品在使用日志类时容易出现和宿主应用类冲突和日志配置冲突的问题,Sermant构建的日志系统解决了这一问题。Sermant日志系统基于JUL&logback构建,为插件开发提供了完整的、配置灵活的、避免类冲突的日志工具,并且Sermant提供的日志系统可以和宿主微服务做到从配置到执行上的完全隔离。除此之外,结合Sermant Backend组件,Sermant日志系统可以提供异常事件的统一采集和上报。

现在我们需要在日志中记录被拦截方法的执行时间,本节将演示如何使用Sermant提供的日志系统。

3.2.1 添加日志

我们在插件主模块的TemplateInterceptor类中定义一个私有静态常量LOGGER,用于该类下的日志构造。

// Sermant日志类

private static final Logger LOGGER = LoggerFactory.getLogger();

接下来我们在该类的after方法使用日志记录被拦截方法的运行时间,该条日志的级别为INFO。

LOGGER.info("方法耗时: " + elapsedTime);

Sermant日志系统可以记录各级别(TRACE、DEBUG、INFO、WARN、ERROR)日志来达到对程序运行不同程度的监控。

更多细节请参考Sermant官网​​日志功能文档​​。

3.2.2 日志演示

按照第二章的方式启动Sermant并调用宿主应用的接口:

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

前往logs/sermant/core/app/xxxx-xx-xx目录查看Sermant日志,“xxxx-xx-xx”为记录日志的时间。可以看到方法耗时成功记录在了日志文件中。

[INFO] [com.huaweicloud.sermant.template.TemplateInterceptor] [after:45] [http-nio-8080-exec-1] 方法耗时: 20

3.2.3 异常日志上报

Sermant日志系统统一采集到的warn和error级别的日志可上传至Sermant Backend进行观测。我们将人为打印异常日志,并通过Backend观测。

在插件主模块TemplateInterceptor类的before方法中打印一条warn级别的日志,在after方法中打印一条error级别的日志:

LOGGER.warning("warning message");

LOGGER.severe("error message");

修改config目录下的config.properties文件开启事件上报相关配置:

# 事件系统开关

event.enable=true

# Warn级别日志事件上报开关

event.offerWarnLog=true

# Error级别日志事件上报开关

event.offerErrorLog=true

按照第二章的方式启动Sermant并调用宿主应用的接口:

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

前往Sermant Backend前端页面可以看到上报的异常信息:

3.3 动态配置

3.3.1 添加动态配置

Sermant提供了动态配置功能,目前支持Zookeeper、Nacos和Kie作为配置中心。动态配置功能允许Sermant对动态配置中心下发的配置进行配置管理和监听等操作,以实现丰富多样的服务治理能力。本节以Zookeeper为例,演示如何使用Sermant的动态配置服务为此插件添加执行增强逻辑的开关。

首先在插件主模块TemplateInterceptor类中添加Map字段模拟开关状态,ENABLE_KEY为开关的名称,并设置开关默认状态为true:

private static final Map<String, Boolean> CONFIG_MAP = new HashMap<>();

private static final String ENABLE_KEY = "enable";

{

// 开关默认状态为true

CONFIG_MAP.put(ENABLE_KEY, true);

}

然后在before方法和after方法中添加开关:

if (!CONFIG_MAP.get(ENABLE_KEY)) {

System.out.println("不执行增强逻辑");

return context;

}

接下来,我们需要动态修改开关的状态,添加动态配置服务字段,获取动态配置服务类实例并注册监听器监听Zookeeper相应节点变化:

// 获取动态配置服务类实例

private final DynamicConfigService dynamicConfigService = ServiceManager.getService(DynamicConfigService.class);

// 获取Sermant框架提供的yaml解析器

private final YamlConverter converter = OperationManager.getOperation(YamlConverter.class);

{

dynamicConfigService.addConfigListener("template-config", "sermant/template-plugin",

new DynamicConfigListener() {

@Override

public void process(DynamicConfigEvent event) {

// 解析yaml文件为map

Optional<Map<String, Object>> convertOptional = converter.convert(event.getContent(), Map.class);

if (convertOptional.isPresent()) {

// 修改开关状态

CONFIG_MAP.put(ENABLE_KEY, (boolean) convertOptional.get().get(ENABLE_KEY));

}

System.out.println("插件配置项发生变化, 配置项值为: " + event.getContent());

}

});

}

使用动态配置需要打开动态配置服务开关,修改config目录下的config.properties文件:

# 动态配置服务开关

agent.service.dynamic.config.enable=true

3.3.2 动态配置演示

开启动态配置服务需在本地启动zookeeper。启动宿主应用并挂载Sermant Agent,对宿主应用接口服务发起调用:

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

此时开关默认开启,控制台输出如下:

已记录方法运行开始的时间

hello lihua

方法耗时:23毫秒

开始下发动态配置,创建/sermant/template-plugin/template-config节点,设置节点的value为“enable: false”:

create /sermant

create /sermant/template-plugin

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

宿主应用控制台打印如下输出:

插件配置项发生变化, 配置项值为: enable: false

再次对宿主应用接口服务发起调用:

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

可以看到控制台打印出了不执行增强逻辑的内容,说明动态配置下发成功:

不执行增强逻辑

hello lihua

不执行增强逻辑

动态配置的演示到此就结束了,更多动态配置的细节请参考Sermant官网​​动态配置功能文档​​。

四、本章总结

本篇文章介绍了如何基于Sermant框架快速开发服务治理插件的流程以及使用Sermant Agent产品的方式。可以发现,通过Sermant底层框架提供的能力,我们可以非常容易的开发符合自身需求的插件,同时结合Sermant的日志系统、动态配置和Backend组件,更精细灵活的增强服务治理插件的功能。Sermant是基于Java字节码增强技术的无代理服务网格,具有无侵入、插件化和高性能的特点,希望本篇文章能对有意愿使用Sermant产品的开发者们有所帮助!

Sermant作为专注于服务治理领域的字节码增强框架,致力于提供高性能、可扩展、易接入、功能丰富的服务治理体验,并会在每个版本中做好性能、功能、体验的看护,广泛欢迎大家的加入。

点击关注,第一时间了解华为云新鲜技术~

实例讲解基于Sermant快速开发服务治理插件的更多相关文章

  1. 实例讲解基于 React+Redux 的前端开发流程

    原文地址:https://segmentfault.com/a/1190000005356568 前言:在当下的前端界,react 和 redux 发展得如火如荼,react 在 github 的 s ...

  2. (转载)实例详解Android快速开发工具类总结

    实例详解Android快速开发工具类总结 作者:LiJinlun 字体:[增加 减小] 类型:转载 时间:2016-01-24我要评论 这篇文章主要介绍了实例详解Android快速开发工具类总结的相关 ...

  3. 基于django快速开发一个网站(一)

    基于django快速开发一个网站(一) *  创建虚拟环境.基于虚拟环境创建django==2.0.0和图片加载库和mysql数据库驱动 1. 创建目录并创建虚拟环境 ╰$ mkdir Cornuco ...

  4. Sublime插件库新成员基于APICloud快速开发跨平台App

    互联网时代强调用户体验,那什么是HTML5跨平台App开发者的编程体验?“不剥夺.不替换开发者喜欢的开发工具,就是人性化的用户体验”,APICloud给出了这样的答案! 重磅发布“多开发工具支持策略” ...

  5. 审核流(3)低调奢华,简单不凡,实例演示-SNF.WorkFlow--SNF快速开发平台3.1

    下面我们就从什么都没有,结合审核流进行演示实例.从无到有如何快速完美的实现,然而如此简单.低调而奢华,简单而不凡. 从只有数据表通过SNF.CodeGenerator代码生成器快速生成单据并与审核流进 ...

  6. 基于flink快速开发实时TopN程序

    TopN 是统计报表和大屏非常常见的功能,主要用来实时计算排行榜.流式的TopN可以使业务方在内存中按照某个统计指标(如出现次数)计算排名并快速出发出更新后的排行榜. 我们以统计词频为例展示一下如何快 ...

  7. 如何基于 PHP-X 快速开发一个 PHP 扩展

    0x01 起步 PHP-X本身基于C++11开发,使用cmake进行编译配置.首先,你需要确定所有依赖项已安装好.包括: gcc-4.8 或更高版本 PHP7.0 或更高版本,需要php7-dev 开 ...

  8. STM32F767ZI NUCLEO144 基于CubeIDE快速开发入门指南

    刚入手的NUCLEO-F767ZI:整合官网资源,理清思路,便于快速进行快发: 文章目录 1 NUCLEO 系列 2 NUCLEO-F767ZI 3 环境搭建 3.1 Keil/IAR安装 3.2 C ...

  9. 教程:基于Spring快速开发电子邮件发送功能

    在Spring框架的spring-context-support.jar中有对电子邮件发送功能的封装: 基于Spring开发简单省事,而且更稳定.需要mail.jar包支持 @Component pu ...

  10. 基于Cordova5.0开发自己定义插件(android)

    1.开发插件java部分 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvenhmMjE2MjE2/font/5a6L5L2T/fontsize/400/fi ...

随机推荐

  1. CF755C

    题目简化和分析: 这题不用说怎么分析了吧,这一看就是个并查集求连通分量个数的经典模板. 我们需要将 \(i\) 和 \(p_i\) 进行合并. 遍历每个 \(i\) 与 \(i+1\) 是否属于同一个 ...

  2. 21.4 Python 使用GeoIP2地图定位

    GeoIP2是一种IP地址定位库,它允许开发人员根据IP地址查找有关位置和地理位置的信息.它使用MaxMind公司的IP地址数据库,并提供一个方便的Python API.GeoIP2可以用于许多不同的 ...

  3. @ApiImplicitParam dataType属性失效

    最近在弄swagger,老是碰到注解属性失效问题.百度看了一大推,都是说什么版本问题.但是都不是我遇到的情况,下面直接上我遇到的问题及答案   可以看到,我直接用Integer,或者int,去到swa ...

  4. go语言reflection反射

    一.反射 1.1简介 Reflection(反射)在计算机中就是表示程序在运行期间能够探知自身结构的能力类型(类型信息.内存结构.更新变量.以及调用方法) 1.2使用场景 函数的参数类型是interf ...

  5. tcpdump必知必会

    tcpdump原理 & 在tcp协议栈的位置 tcpdump用法 基于协议.主机.端口过滤 使用and or逻辑运算符做复杂的过滤操作 tcpdump flags 1. tcpdump原理 l ...

  6. HDL刷题:Edgedetect

    原题链接 一道想了好久的题目,在这种并行执行的程序里怎么才能保存前一个状态,看了题解后才发觉,非阻塞赋值啊,代码如下: module top_module ( input clk, input [7: ...

  7. AtCoder Beginner Contest 240 F - Sum Sum Max

    原题链接F - Sum Sum Max 首先令\(z_i = \sum\limits_{k = 1}^i y_k\),\(z_0 = 0\),\(z_i\)就是第\(i\)段相同的个数的前缀和. 对于 ...

  8. 发现AI自我意识:进入混合增强只能的纪元

    执行性思维:人工智能的现实优势 如何解构人类的思维模型是一个跨多学科的综合性问题.本文仅针对AI领域发展方向预测以及理解,提出一个简化的模型.我认为人类的思维基于思考的目的性可以分为:执行性思维和创造 ...

  9. 【开源项目推荐】-支持GPT的智能数据库客户端与报表工具——Chat2DB

    2023年是人工智能爆火的一年,ChatGPT为首的一系列的大模型的出现,让生成式人工智能彻底火了一把.但有人会说,GPT对于我们数据开发来说并没有什么作用啊? 今天为大家推荐的开源项目,就是GPT在 ...

  10. RV1126 快速启动

    一.硬件信息 RV1126/RV1109 系列芯⽚内置硬件解压缩模块 -- decom,可以极⼤得提升系统启动速度 RV1126/RV1109 内置⼀个 MCU,MCU 在 SoC 上电后就会快速启动 ...