实例讲解基于Sermant快速开发服务治理插件
本文分享自华为云社区《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 官网: https://sermant.io
- GitHub 仓库地址: https://github.com/huaweicloud/Sermant

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
如何最大化客户生命周期价值?APMDR 模型在袋鼠云的落地实践
相信大家都认可一个观点:不论是 To B 还是 To C,用户是企业的核心资源,是互联网产品中最重要的价值之一。因此,深入挖掘用户价值成为现在大部分企业运营的关键。 之前我们为大家介绍过如何利用 RFM 模型让企业聚焦于更有价值的用户,本文将为大家详细介绍用户生命周期模型 APMDR,以及「袋鼠云客户数据洞察平台」基于 APMDR 模型的落地实践。 APMDR 模型能够针对各类用户制定有效的运营策略提供科学依据,达到延长用户生命周期等目的,帮助企业进行业务生命周期的有效管理,真正实现数据赋能业务发展。 什么是 APMDR 模型? 用户的生命周期指的是用户从开始接触产品到离开产品的整个过程。用户的生命周期长短将直接影响产品与企业的营收,因此将用户生命周期科学地量化,在合适的时候做出合适的运营策略,从而延长用户的生命周期。 如上图所示,一般用户的生命周期主要分为5个阶段:获取期、提升期、成熟期、衰退期。对于不同时期的客户,客户为企业带来的利润不同,对应的运营策略也有所不同。 我们需要根据每个用户在不同阶段的特性进行用户的生命周期划分,再依据不同时期的用户定制不同的运营策略,这时候,就轮到 ...
- 下一篇
米哈游大数据云原生实践
近年来,容器、微服务、Kubernetes 等各项云原生技术的日渐成熟,越来越多的公司开始选择拥抱云原生,并开始将 AI、大数据等类型的企业应用部署运行在云原生之上。以 Spark 为例,在云上运行 Spark 可以充分享有公共云的弹性资源、运维管控和存储服务等,并且业界也涌现了不少 Spark on Kubernetes 的优秀实践。 在刚刚结束的 2023 云栖大会上,米哈游数据平台组大数据技术专家杜安明分享了米哈游大数据架构向云原生化升级过程中的目标、探索和实践,以及如何通过以阿里云容器服务 ACK 为底座的 Spark on K8s 架构,获得在弹性计算、成本节约以及存算分离方面的价值。 01 背景简介 随着米哈游业务的高速发展,大数据离线数据存储量和计算任务量增长迅速,早期的大数据离线架构已不再满足新场景和需求。 为了解决原有架构缺乏弹性、运维复杂、资源利用率低等问题,2022 年下半年,我们着手调研将大数据基础架构云原生化,并最终在阿里云上落地了Spark on K8s + OSS-HDFS 方案,目前在生产环境上已稳定运行了一年左右的时间,并获得了弹性计算、成本节约以及存...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- CentOS6,CentOS7官方镜像安装Oracle11G
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- CentOS7设置SWAP分区,小内存服务器的救世主
- CentOS8编译安装MySQL8.0.19
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16