当前位置:网站首页>甲方不让用开源【监控软件】?大不了我自己写一个
甲方不让用开源【监控软件】?大不了我自己写一个
2022-08-03 15:53:00 【YYniannian】

相信在公司的小伙伴,有很多都经历过这样一种情况:公司对于某些开源软件禁止使用,或者说需要修改源码,去掉其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还是一个襁褓里的孩子。但是意义在于给大家提供一个监控的最简单思路,让你能够快速的打造完全属于公司自己的监控体系。
边栏推荐
- 出海季,互联网出海锦囊之本地化
- [Code Hoof Set Novice Village 600 Questions] Define a function as a macro
- 攻防世界----bug
- DataGrip:非常好用的数据库工具,安装与使用教程,亮点介绍
- 如何将二维空间先验注入到ViT中? UMA&港理工&阿里提出SP-ViT,为视觉Transformer学习2D空间先验知识!...
- 高压直流输电(HVDC)的最优潮流(OPF)(Matlab代码实现)
- 2021年数据泄露成本报告解读
- 兔起鹘落全端涵盖,Go lang1.18入门精炼教程,由白丁入鸿儒,全平台(Sublime 4)Go lang开发环境搭建EP00
- 一个文件管理系统的软硬件配置清单
- Common distributed theories (CAP, BASE) and consensus protocols (Gosssip, Raft)
猜你喜欢

Introduction to the advantages of the new generation mesh network protocol T-Mesh wireless communication technology

一文看懂推荐系统:召回03:基于用户的协同过滤(UserCF),要计算用户之间的相似度

【数据库数据恢复】SqlServer数据库无法读取的数据恢复案例

Interpretation of the 2021 Cost of Data Breach Report

证实了,百度没有快照了

为什么我强烈推荐使用智能化async?

并发编程的核心问题

出海季,互联网出海锦囊之本地化

AWS中国区SDN Connector

49 万奖金等你来拿!第四届实时计算 Flink 挑战赛启动,Beyond Stream Processing!
随机推荐
分享一款免费OPC UA服务器
JS handwritten call apply bind (detailed) (interview)
一通骚操作,我把SQL执行效率提高了10000000倍!
posgresql 到 es 报这个错误 ,啥意思
Introduction to the advantages of the new generation mesh network protocol T-Mesh wireless communication technology
mysql delete execution error: You can't specify target table 'doctor_info' for update in FROM clause
[QT] Qt project demo: data is displayed on the ui interface, double-click the mouse to display specific information in a pop-up window
How Navicat connects to MySQL on a remote server
Common distributed theories (CAP, BASE) and consensus protocols (Gosssip, Raft)
身为售后工程师的我还是觉得软件测试香,转行成功定薪11.5K,特来分享下经验。
AWS China SDN Connector
一文看懂推荐系统:召回03:基于用户的协同过滤(UserCF),要计算用户之间的相似度
您的移动端app安全吗
[Code Hoof Set Novice Village 600 Questions] Define a function as a macro
请问下阿里云全托管flink能执行两条flink sql命令么?
opencv 读取和写入路径有汉字的处理方法
5 v 8.4 v1A charging current charging management IC
ruoyi若依框架@DataScope注解使用以及碰到的一些问题
No inner demons, to dry!SQL optimization and diagnosis
ffplay视频播放原理分析



