甲方不让用开源监控软件?大不了我自己写一个
Posted YYniannian
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了甲方不让用开源监控软件?大不了我自己写一个相关的知识,希望对你有一定的参考价值。
相信在公司的小伙伴,有很多都经历过这样一种情况:公司对于某些开源软件禁止使用,或者说需要修改源码,去掉其logo或者身份信息,各种监控软件就是其受害者。对于较大的系统,或者组件较多的系统,拥有一个可靠的监控系统将是非常有必要的。
warriors体验地址:http://122.112.181.245/
背景
之前我曾就职于一家面向三大运营商的传统行业公司,所有的系统都是内网部署,且对于第三方的开源软件并不完全提倡使用。
比如springboot自带的监组件springboot-admin
,在使用的时候,我还专门去修改器源码,将logo替换为自己公司的logo,重新打包部署,说实话,挺痛苦的。而对于我一直比较推崇的skywalking
和prometheus
,根本就不给你部署的机会。
但是一个好的指标监控系统,对于项目的平稳运行还是能起到很关键的作用的。所以虽然不在之前的公司了,但是我始终有一个搭建自己的监控体系的想法,可以按照公司的需要自行接入,而与原本的系统做到毫无违和。
简介
鉴于前面提到的背景,我在休息的时间,缓慢的开始了我自己的监控系统的建设,因为我是库里的球迷,所以暂时将此监控系统命名为勇士监控系统,即warriors,系统的色调,也采用了勇士蓝黄组合。
勇士监控系统提供各种常用组件的接入,因为业余时间较少,目前仅仅接入了redis,作为给大家的演示。提供组件的各种常用指标,以报表的形式给用户提供直观的展示。
界面介绍
目前主要提供两个界面,首页简介,以及具体的监控页面。
-
首页
首页主要简单的为大家介绍勇士监控系统:
此界面可以手动原则将要查看的组件性能信息:
-
监控界面
选择"redis"后,即进入redis监控页面,页面将会对具体的指标信息进行展示,包含但不限于以下的指标,可以随时添加新的指标。
架构介绍
勇士监控系统以简单为主,只有一个服务,组件的监控代码通过stater的形式进行引入,整体架构如下所示:
如上图所示,整个监控系统由四部分组成,由上至下分别是:
- ui界面:采用vue3实现
- 服务端:采用springboot实现
- 组件依赖:通过stater定义不同组件的不同监控指标
- 基础依赖:提供各组件需要的基础类
实现
后台实现
基于简单的架构,组件的实现也非常的简单。代码结构如下所示:
上图当中还包含了代码生成器的部分,方便我们快速开发。
对于常见的一些组件,比如redis,我们可以通过它自带的api去完成对其性能的监控,我这里使用的是RedisTemplate,一起简单看下其实现:
-
首选,看下公共依赖都包含什么?
如上图所示,从上至下分别是:
- 常量:公共常量
- 枚举:返回枚举
- 工具类:bean copye工具类,分页对象,返回结果
需要特别关注的spring.factories,它是stater能够实现的核心配置,后面单独讲解。
-
引入redis依赖
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- redis 连接池 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> <!-- 基础依赖 --> <dependency> <groupId>com.wjbgn.warriors</groupId> <artifactId>warriors-base-starter</artifactId> </dependency> 复制代码
-
看看redis-stater包含什么?
如上图所示,从上直线分别是:
-
redis配置文件:用来方便redis操作实例化对象:
/** * description: 默认情况下RedisTemplate模板只能支持字符串,我们自定义一个RedisTemplate, * 设置序列化器,这样我们可以很方便的操作实例对象。 * * @return: * @author: weirx * @time: 2021/3/26 13:58 */ @Configuration public class RedisConfig @Bean public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory connectionFactory) RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>(); redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); redisTemplate.setConnectionFactory(connectionFactory); return redisTemplate; 复制代码
-
实体类:用来封装监控指标的属性,比如服务信息如下所示:
package com.wjbgn.warriors.redis.entity; import lombok.Data; /** * @description: 服务信息 * @author:weirx * @date:2022/6/23 17:41 * @version:3.0 */ @Data public class ServerInfo /** * 版本 */ private String version; /** * 模式:单例,集群 */ private String mode; /** * 操作系统 */ private String os; private String port; /** * 运行时间 */ private String updateInDays; /** * 配置文件路径 */ private String config_path; 复制代码
-
工具类:redis各类指标采集的工具类,以服务信息的代码为例:
```java package com.wjbgn.warriors.redis.util; import cn.hutool.core.util.ObjectUtil; import com.wjbgn.warriors.base.util.Result; import com.wjbgn.warriors.redis.entity.ServerInfo; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import static com.wjbgn.warriors.base.constants.CommonConstants.FLAG; /** * @description: redis服务信息 * @author:weirx * @date:2022/6/23 17:19 * @version:3.0 */ @Slf4j @Component public class RedisServerInfoUtil extends AbstractRedisInfoUtil /** * description: 获取服务信息 * @return: com.wjbgn.warriors.base.util.Result * @author: weirx * @time: 2022/6/24 10:21 */ public Result serverInfo() Object serverInfo = getInfo("server"); if (ObjectUtil.isNotEmpty(serverInfo)) String s = serverInfo.toString().replaceAll("[\\t\\n\\r]", FLAG); ServerInfo parse = this.parse(s); return Result.success(parse); return Result.failed(); /** * description: 解析服务信息 * @param s * @return: com.wjbgn.warriors.redis.entity.ServerInfo * @author: weirx * @time: 2022/6/24 10:21 */ public ServerInfo parse(String s) String[] split = s.split(FLAG + FLAG); List<String> list = Arrays.asList(split); ServerInfo serverInfo = new ServerInfo(); Map<String, String> map = new HashMap<>(); list.stream().forEach(str -> String[] strings = str.split(":"); if (strings.length > 1) map.put(strings[0], strings[1]); ); map.forEach((k, v) -> if (k.equals("redis_version")) serverInfo.setVersion(v); else if (k.equals("redis_mode")) serverInfo.setMode(v); else if (k.equals("os")) serverInfo.setOs(v); else if (k.equals("tcp_port")) serverInfo.setPort(v); else if (k.equals("uptime_in_days")) serverInfo.setUpdateInDays(v); else if (k.equals("config_file")) serverInfo.setConfig_path(v); ); return serverInfo; ``` 复制代码
-
仍然是很重要的spring.factories。
-
前台实现
前台代码的实现非常简单,采用vue3 + element-plus为基础进行开发,标准的vue3结构,如下所示:
组件实际只引用了:
- element-plus
- router
- echarts
- axios
具体监控界面,采用elment-plus的布局:
<el-card>
<el-row>
<el-col :span="4">
Redis版本: redisServerInfo.redisVersion
</el-col>
<el-col :span="4">
模式: redisServerInfo.redisMode
</el-col>
<el-col :span="4">
端口: redisServerInfo.redisPort
</el-col>
<el-col :span="4">
运行时间: redisServerInfo.redisUpdateInDays 天
</el-col>
<el-col :span="4">
总内存: parseFloat((redisMemoryInfo.totalSystemMemory - redisMemoryInfo.usedMemory)/(1024*1024*1024)).toFixed(2) G
</el-col>
<el-col :span="4">
客户端: redisClientsInfo.connectionClientsNum
</el-col>
</el-row>
</el-card>
复制代码
使用echarts实现报表的展示:
function drawHistogram()
// 基于准备好的dom,初始化echarts实例
let myChart = echarts.init(document.getElementById('histogram'));
// 绘制图表
myChart.setOption(
title:
text: '客户端信息'
,
tooltip: ,
xAxis:
data: ['连接数','集群数','阻塞数','超时数']
,
yAxis: ,
series: [
name: '',
type: 'bar',
data: [
redisClientsInfo.connectionClientsNum,
redisClientsInfo.clusterConnections,
redisClientsInfo.blockedClients,
redisClientsInfo.clientsInTimeoutTable
]
]
);
复制代码
spring.factories是什么?
前面提到的spring.factories,单独拿出一部分来讲解。其内部的构成如下所示:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\
com.wjbgn.warriors.redis.util.RedisSlowLogUtil,\\
com.wjbgn.warriors.redis.util.RedisServerInfoUtil,\\
com.wjbgn.warriors.redis.util.RedisClientsInfoUtil,\\
com.wjbgn.warriors.redis.util.RedisMemoryInfoUtil,\\
com.wjbgn.warriors.redis.util.RedisPersistenceInfoUtil,\\
com.wjbgn.warriors.redis.util.RedisStatsInfoUtil
复制代码
如上所示,在第一行的类:EnableAutoConfiguration,相信熟悉springboot的小伙伴都很熟悉,它是sopringboot自动装载配置的注解。所以我们能够知道,这个文件就是配合自动装配进行使用的。
在向下,则是配置文件,和我们定义的一系列的redis指标获取工具类。我们可以根据自己的项目需要进行配置制定的util。
不配置spring.factories行吗?
答案是**可以配置,可以不配置*。
但是需要分为两种情况:
- 不需要配置:工具类和依赖它的服务在同一个包名下。
- 需要配置:工具类和依赖它的服务不在同一个包名下。
造成这种问题的本质原因是什么呢?
比如warriors这个系统,我完全可以不进行配置,因为我的包路径,全部都是com.wjbgn.warriors
。
我们需要知道的是,springboot的启动类,在启动的时候,会默认扫描和其同一级包名,和其包名下的类,这些类需要带有指定的注解,比如:@Service
,@Component
等等。所以即使不指定spring.factories,也可以扫描到我们定义的配置文件和工具类,冰江他们注入到的spring容器当中,供我们直接使用。
但是当我们的redis-starter是在其他的服务当中被依赖了呢?
他们想要使用此starter去做一些定制化的开发,那么就必须要配置spring.factories
。
spring.factories
和EnableAutoConfiguration
相互配合,从而将其需要的bean进行自动配置。
上面提到的这种方式,我们可以称之为SPI,(Service Provider Interface)。
总结
到此为止,warriors监控就介绍完成了,无论是使用的技术,还是实现方案,都是我们经常使用,并且很实用的方式,能够尽量简单的完成自定义监控系统的研发。也非常适合初学者小伙伴上手去学习java相关的知识,同时能够使你更加清晰的认识各种组件的性能指标。
目前还处于开发阶段,进度取决于我的空闲时间,但是后续的规划还是有的:
- 接入邮件等告警模块。
- 实现页面的动态配置方式。
- 完善更多的组件监控。
相比于市面大多数的监控软件,warriors还是一个襁褓里的孩子。但是意义在于给大家提供一个监控的最简单思路,让你能够快速的打造完全属于公司自己的监控体系。
以上是关于甲方不让用开源监控软件?大不了我自己写一个的主要内容,如果未能解决你的问题,请参考以下文章