关于后台管理系统的一些系统监控案例

2024-04-25 21:52

本文主要是介绍关于后台管理系统的一些系统监控案例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

关于后台管理系统的一些系统监控案例

在阅读开源的项目的时候,发现了一个很神奇的功能。

https://github.com/valarchie/AgileBoot-Back-End

我这个是本地去运行的,发现他可以检测到这么多的数据

image-20240425125100735

下面我们就来看他是如何进行的这样一个检测

我们首先来看他后端返回的一个结果:

{"code": 0,"msg": "操作成功","data": {"cpuInfo": {"cpuNum": 16,"total": 1625000.0,"sys": 5.86,"used": 18.84,"wait": 0.0,"free": 74.82},"memoryInfo": {"total": 15.8,"used": 9.77,"free": 6.02,"usage": 61.86},"jvmInfo": {"total": 210.0,"max": 4046.0,"free": 72.05,"version": "17.0.5","home": "C:\\Program Files\\Java\\jdk-17.0.5","name": "Java HotSpot(TM) 64-Bit Server VM","startTime": "2024-04-25 12:47:59","usage": 65.69,"used": 137.95,"runTime": "3分54秒728毫秒","inputArgs": "[-XX:TieredStopAtLevel=1, -Dspring.output.ansi.enabled=always, -Dcom.sun.management.jmxremote, -Dspring.jmx.enabled=true, -Dspring.liveBeansView.mbeanDomain, -Dspring.application.admin.enabled=true, -Dmanagement.endpoints.jmx.exposure.include=*, -javaagent:E:\\ideasss\\IntelliJ IDEA 2022.3.1\\lib\\idea_rt.jar=13917:E:\\ideasss\\IntelliJ IDEA 2022.3.1\\bin, -Dfile.encoding=UTF-8]"},"systemInfo": {"computerName": "LAPTOP-5M8H38DP","computerIp": "26.175.19.186","userDir": "D:\\onenodes\\githubprojectstart\\AgileBoot-Back-End","osName": "Windows 11","osArch": "amd64"},"diskInfos": [{"dirName": "C:\\","sysTypeName": "NTFS","typeName": "本地固定磁盘 (C:)","total": "200.0 GB","free": "34.6 GB","used": "165.4 GB","usage": 82.7096},{"dirName": "D:\\","sysTypeName": "NTFS","typeName": "本地固定磁盘 (D:)","total": "137.0 GB","free": "9.0 GB","used": "128.0 GB","usage": 93.4018},{"dirName": "E:\\","sysTypeName": "NTFS","typeName": "本地固定磁盘 (E:)","total": "137.7 GB","free": "52.7 GB","used": "85.0 GB","usage": 61.7589}]}
}

可以看到是如此之多。首先我们来看后台他是如何进行一个获取的。

我们从上往下慢慢的去看

服务器数据检测

/*** CPU相关信息*/
private CpuInfo cpuInfo = new CpuInfo();

他这里定义了cpu有这些字段

/*** 核心数*/
private int cpuNum;/*** CPU总的使用率*/
private double total;/*** CPU系统使用率*/
private double sys;/*** CPU用户使用率*/
private double used;/*** CPU当前等待率*/
private double wait;/*** CPU当前空闲率*/
private double free;

之后来看是如何获取的:

/*** 设置CPU信息*/
private void fillCpuInfo(CentralProcessor processor) {// CPU信息long[] prevTicks = processor.getSystemCpuLoadTicks();Util.sleep(OSHI_WAIT_SECOND);long[] ticks = processor.getSystemCpuLoadTicks();long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()];long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()];long softIrq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()];long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()];long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()];long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()];long ioWait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()];long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()];long totalCpu = user + nice + cSys + idle + ioWait + irq + softIrq + steal;cpuInfo.setCpuNum(processor.getLogicalProcessorCount());cpuInfo.setTotal(totalCpu);cpuInfo.setSys(cSys);cpuInfo.setUsed(user);cpuInfo.setWait(ioWait);cpuInfo.setFree(idle);
}

这里用到了
CentralProcessor这个接口

这个是github的一个项目。oshi/oshi: Native Operating System and Hardware Information (github.com)

oshi。

通过他就可以获得一些系统的参数。

同时也可以获取到内存。

/*** 设置内存信息*/
private void fillMemoryInfo(GlobalMemory memory) {memoryInfo.setTotal(memory.getTotal());memoryInfo.setUsed(memory.getTotal() - memory.getAvailable());memoryInfo.setFree(memory.getAvailable());
}

以及磁盘:

/*** 设置磁盘信息*/
private void fillDiskInfos(OperatingSystem os) {FileSystem fileSystem = os.getFileSystem();List<OSFileStore> fsArray = fileSystem.getFileStores();for (OSFileStore fs : fsArray) {long free = fs.getUsableSpace();long total = fs.getTotalSpace();long used = total - free;DiskInfo diskInfo = new DiskInfo();diskInfo.setDirName(fs.getMount());diskInfo.setSysTypeName(fs.getType());diskInfo.setTypeName(fs.getName());diskInfo.setTotal(convertFileSize(total));diskInfo.setFree(convertFileSize(free));diskInfo.setUsed(convertFileSize(used));if (total != 0){diskInfo.setUsage(NumberUtil.div(used * 100, total, 4));} else {//Windows下如果有光驱(可能是虚拟光驱),total为0,不能做除数diskInfo.setUsage(0);}diskInfos.add(diskInfo);}

之后的服务器信息,如果本地运行也就是本地的信息

image-20240425130530644

/*** 设置服务器信息*/
private void fillSystemInfo() {Properties props = System.getProperties();systemInfo.setComputerName(NetUtil.getLocalHostName());systemInfo.setComputerIp(NetUtil.getLocalhost().getHostAddress());systemInfo.setOsName(props.getProperty("os.name"));systemInfo.setOsArch(props.getProperty("os.arch"));systemInfo.setUserDir(props.getProperty("user.dir"));
}

是这样进行的一个获取。

NetUtil就是Hutool里面的东西。

剩下的东西就是从java的自带类System.getProperties里面获取到的。

下面是他可以获得的常见属性:

  • java.version: Java运行时环境版本
  • java.vendor: Java运行时环境的供应商
  • java.vendor.url: Java供应商的URL
  • java.home: Java运行时环境的安装目录
  • user.dir: 用户的当前工作目录
  • java.class.version: Java类文件的版本号
  • os.name: 操作系统的名称
  • os.arch: 操作系统的架构
  • os.version: 操作系统的版本
  • file.separator: 文件路径分隔符(例如,在Windows上是\,在Unix上是/
  • path.separator: 路径的分隔符(例如,在Windows上是;,在Unix上是:
  • line.separator: 行分隔符(例如,\n在Unix上,\r\n在Windows上)
  • java.specification.version: Java平台的规范版本
  • java.specification.vendor: Java平台规范的供应商
  • java.specification.name: Java平台规范的名称
  • java.vm.specification.version: Java虚拟机规范的版本
  • java.vm.specification.vendor: Java虚拟机规范的供应商
  • java.vm.specification.name: Java虚拟机规范的名称
  • java.vm.version: Java虚拟机实现的版本
  • java.vm.vendor: Java虚拟机实现的供应商
  • java.vm.name: Java虚拟机实现的名称
  • java.runtime.version: Java运行时环境的版本
  • java.runtime.name: Java运行时环境的名称
  • java.ext.dirs: 系统扩展目录的路径
  • java.endorsed.dirs: 被认可的库的目录
  • java.library.path: 系统库的路径
  • java.io.tmpdir: 临时文件目录的路径
  • java.compiler: 要使用的JIT编译器的名称
  • java.class.path: 类路径,用于搜索类文件和库
  • user.name: 用户的账号名称
  • user.home: 用户的主目录
  • user.timezone: 用户的时区

这里需要注意的是,我们在用osi的时候

public static ServerInfo fillInfo() {ServerInfo serverInfo = new ServerInfo();oshi.SystemInfo si = new oshi.SystemInfo();HardwareAbstractionLayer hal = si.getHardware();serverInfo.fillCpuInfo(hal.getProcessor());serverInfo.fillMemoryInfo(hal.getMemory());serverInfo.fillSystemInfo();serverInfo.fillJvmInfo();serverInfo.fillDiskInfos(si.getOperatingSystem());return serverInfo;
}

要给他传递参数,才能正确的获取到这个。

缓存监控

image-20240425131155982

之后来看他是如何获得redis的信息的。

下面是响应的数据:

{"code": 0,"msg": "操作成功","data": {"info": {"uptime_in_seconds": "1902","maxmemory_human": "0B","aof_last_cow_size": "0","master_replid2": "0000000000000000000000000000000000000000","mem_replication_backlog": "0","aof_rewrite_scheduled": "0","total_net_input_bytes": "4834","rss_overhead_ratio": "0.00","hz": "10","redis_build_id": "5627b8177c9289c","aof_last_bgrewrite_status": "ok","multiplexing_api": "WinSock_IOCP","client_recent_max_output_buffer": "0","allocator_resident": "587202560","mem_fragmentation_bytes": "0","repl_backlog_first_byte_offset": "0","redis_mode": "standalone","redis_git_dirty": "0","allocator_rss_bytes": "8388608","repl_backlog_histlen": "0","rss_overhead_bytes": "-586477112","total_system_memory": "0","loading": "0","evicted_keys": "0","cluster_enabled": "0","redis_version": "5.0.14.1","repl_backlog_active": "0","mem_aof_buffer": "0","allocator_frag_bytes": "539235920","instantaneous_ops_per_sec": "0","used_memory_human": "749.34K","role": "master","maxmemory": "0","used_memory_lua": "37888","rdb_current_bgsave_time_sec": "-1","used_memory_startup": "661224","lazyfree_pending_objects": "0","used_memory_dataset_perc": "51.43%","allocator_frag_ratio": "14.62","arch_bits": "64","mem_clients_normal": "49950","expired_time_cap_reached_count": "0","mem_fragmentation_ratio": "1.00","aof_last_rewrite_time_sec": "-1","master_replid": "d9ae6531155b1ebd86e9dfe419a6bf0504a02e8a","aof_rewrite_in_progress": "0","config_file": "","lru_clock": "2745918","maxmemory_policy": "noeviction","run_id": "50a68c2d09ac5826c61be90414ee99e82a71a4ce","latest_fork_usec": "0","total_commands_processed": "37","expired_keys": "0","used_memory": "767320","mem_clients_slaves": "0","keyspace_misses": "6","executable": "e:\redis\redis-server.exe","db1": "keys=5,expires=0,avg_ttl=0","db0": "keys=10,expires=7,avg_ttl=2093322","db2": "keys=3,expires=0,avg_ttl=0","used_memory_peak_human": "749.34K","db4": "keys=6,expires=0,avg_ttl=0","keyspace_hits": "8","rdb_last_cow_size": "0","used_memory_overhead": "712750","active_defrag_hits": "0","tcp_port": "6379","uptime_in_days": "0","used_memory_peak_perc": "100.00%","blocked_clients": "0","sync_partial_err": "0","used_memory_scripts_human": "0B","aof_current_rewrite_time_sec": "-1","aof_enabled": "0","master_repl_offset": "0","used_memory_dataset": "54570","used_cpu_user": "0.296875","rdb_last_bgsave_status": "ok","atomicvar_api": "pthread-mutex","allocator_rss_ratio": "1.01","client_recent_max_input_buffer": "2","aof_last_write_status": "ok","mem_allocator": "jemalloc-5.2.1-redis","used_memory_scripts": "0","used_memory_peak": "767320","process_id": "1480","used_cpu_sys": "0.109375","repl_backlog_size": "1048576","connected_slaves": "0","total_system_memory_human": "0B","sync_full": "0","connected_clients": "1","allocator_active": "578813952","total_net_output_bytes": "18441","pubsub_channels": "0","active_defrag_key_hits": "0","rdb_changes_since_last_save": "8","instantaneous_input_kbps": "0.00","configured_hz": "10","used_memory_rss_human": "708.45K","expired_stale_perc": "0.00","active_defrag_misses": "0","used_cpu_sys_children": "0.000000","number_of_cached_scripts": "0","sync_partial_ok": "0","used_memory_lua_human": "37.00K","rdb_last_save_time": "1714020048","pubsub_patterns": "0","slave_expires_tracked_keys": "0","redis_git_sha1": "ec77f72d","used_memory_rss": "725448","rdb_last_bgsave_time_sec": "-1","os": "Windows  ","mem_not_counted_for_evict": "0","active_defrag_running": "0","rejected_connections": "0","active_defrag_key_misses": "0","allocator_allocated": "39578032","instantaneous_output_kbps": "0.00","second_repl_offset": "-1","rdb_bgsave_in_progress": "0","used_cpu_user_children": "0.000000","total_connections_received": "1","migrate_cached_sockets": "0"},"dbSize": 10,"commandStats": [{"name": "keys","value": "2"},{"name": "ping","value": "1"},{"name": "get","value": "14"},{"name": "info","value": "9"},{"name": "dbsize","value": "4"},{"name": "setex","value": "8"}]}
}

之后我们先来看他的代码实现:

public RedisCacheInfoDTO getRedisCacheInfo() {Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) RedisServerCommands::info);Properties commandStats = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info("commandstats"));Long dbSize = redisTemplate.execute(RedisServerCommands::dbSize);if (commandStats == null || info == null) {throw new ApiException(Internal.INTERNAL_ERROR, "获取Redis监控信息失败。");}RedisCacheInfoDTO cacheInfo = new RedisCacheInfoDTO();cacheInfo.setInfo(info);cacheInfo.setDbSize(dbSize);cacheInfo.setCommandStats(new ArrayList<>());commandStats.stringPropertyNames().forEach(key -> {String property = commandStats.getProperty(key);CommandStatusDTO commonStatus = new CommandStatusDTO();commonStatus.setName(StrUtil.removePrefix(key, "cmdstat_"));commonStatus.setValue(StrUtil.subBetween(property, "calls=", ",usec"));cacheInfo.getCommandStats().add(commonStatus);});return cacheInfo;
}

这个我们分三步来进行解析。

也就是他set的三个对象。Info dbSize和commandStats

首先是info

Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) RedisServerCommands::info);

execute 方法的作用是执行一个 Redis 命令,并返回执行结果。它的参数类型是 RedisCallback,它是一个函数式接口,用于表示一个可以执行 Redis 命令的回调函数。

他这个就相当于执行了redis的一个

info server的指令

可以获得下面的信息

image-20240425132013980

之后的dbsize也是同理

image-20240425132323951

之后来看

commandStats.stringPropertyNames().forEach(key -> {String property = commandStats.getProperty(key);CommandStatusDTO commonStatus = new CommandStatusDTO();commonStatus.setName(StrUtil.removePrefix(key, "cmdstat_"));commonStatus.setValue(StrUtil.subBetween(property, "calls=", ",usec"));cacheInfo.getCommandStats().add(commonStatus);
});

这个是从Redis 服务器返回的命令统计信息。

这里的关键是

commonStatus.setValue(StrUtil.subBetween(property, "calls=", ",usec"));:从属性值中提取命令调用次数,并设置到 commonStatus 对象中,使用 StrUtil.subBetween 方法提取。这里假设属性值的格式为 "calls=xxx,usec=xxx",通过 subBetween 方法提取出调用次数。

至此,缓存监控结束。

在线用户

最后是一个在线用户功能。

这个实现起来比较简单

public List<OnlineUserDTO> getOnlineUserList(String username, String ipAddress) {Collection<String> keys = redisTemplate.keys(CacheKeyEnum.LOGIN_USER_KEY.key() + "*");Stream<OnlineUserDTO> onlineUserStream = keys.stream().map(o ->CacheCenter.loginUserCache.getObjectOnlyInCacheByKey(o)).filter(Objects::nonNull).map(OnlineUserDTO::new);List<OnlineUserDTO> filteredOnlineUsers = onlineUserStream.filter(o ->StrUtil.isEmpty(username) || username.equals(o.getUsername())).filter( o ->StrUtil.isEmpty(ipAddress) || ipAddress.equals(o.getIpAddress())).collect(Collectors.toList());Collections.reverse(filteredOnlineUsers);return filteredOnlineUsers;
}

这段代码的核心功能是从 Redis 缓存中获取所有在线用户的信息,并根据给定的用户名和 IP 地址过滤出符合条件的在线用户列表。

那么这个ip是如何获取的呢?

其实我们可以发现在登陆的时候就已经获取到了。

他在redis里面是这样进行的一个存储

image-20240425133356577

这里就不讲如何获取ip了。相信这个操作对大家来说是很简单的。

之后是他这个数据监控。我就不多说了

用的是druid的

image-20240425133738515

这篇关于关于后台管理系统的一些系统监控案例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/935897

相关文章

SpringBoot实现动态插拔的AOP的完整案例

《SpringBoot实现动态插拔的AOP的完整案例》在现代软件开发中,面向切面编程(AOP)是一种非常重要的技术,能够有效实现日志记录、安全控制、性能监控等横切关注点的分离,在传统的AOP实现中,切... 目录引言一、AOP 概述1.1 什么是 AOP1.2 AOP 的典型应用场景1.3 为什么需要动态插

Golang操作DuckDB实战案例分享

《Golang操作DuckDB实战案例分享》DuckDB是一个嵌入式SQL数据库引擎,它与众所周知的SQLite非常相似,但它是为olap风格的工作负载设计的,DuckDB支持各种数据类型和SQL特性... 目录DuckDB的主要优点环境准备初始化表和数据查询单行或多行错误处理和事务完整代码最后总结Duck

MySQL不使用子查询的原因及优化案例

《MySQL不使用子查询的原因及优化案例》对于mysql,不推荐使用子查询,效率太差,执行子查询时,MYSQL需要创建临时表,查询完毕后再删除这些临时表,所以,子查询的速度会受到一定的影响,本文给大家... 目录不推荐使用子查询和JOIN的原因解决方案优化案例案例1:查询所有有库存的商品信息案例2:使用EX

Linux使用nohup命令在后台运行脚本

《Linux使用nohup命令在后台运行脚本》在Linux或类Unix系统中,后台运行脚本是一项非常实用的技能,尤其适用于需要长时间运行的任务或服务,本文我们来看看如何使用nohup命令在后台... 目录nohup 命令简介基本用法输出重定向& 符号的作用后台进程的特点注意事项实际应用场景长时间运行的任务服

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

深入探索协同过滤:从原理到推荐模块案例

文章目录 前言一、协同过滤1. 基于用户的协同过滤(UserCF)2. 基于物品的协同过滤(ItemCF)3. 相似度计算方法 二、相似度计算方法1. 欧氏距离2. 皮尔逊相关系数3. 杰卡德相似系数4. 余弦相似度 三、推荐模块案例1.基于文章的协同过滤推荐功能2.基于用户的协同过滤推荐功能 前言     在信息过载的时代,推荐系统成为连接用户与内容的桥梁。本文聚焦于

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、

客户案例:安全海外中继助力知名家电企业化解海外通邮困境

1、客户背景 广东格兰仕集团有限公司(以下简称“格兰仕”),成立于1978年,是中国家电行业的领军企业之一。作为全球最大的微波炉生产基地,格兰仕拥有多项国际领先的家电制造技术,连续多年位列中国家电出口前列。格兰仕不仅注重业务的全球拓展,更重视业务流程的高效与顺畅,以确保在国际舞台上的竞争力。 2、需求痛点 随着格兰仕全球化战略的深入实施,其海外业务快速增长,电子邮件成为了关键的沟通工具。

【区块链 + 人才服务】区块链集成开发平台 | FISCO BCOS应用案例

随着区块链技术的快速发展,越来越多的企业开始将其应用于实际业务中。然而,区块链技术的专业性使得其集成开发成为一项挑战。针对此,广东中创智慧科技有限公司基于国产开源联盟链 FISCO BCOS 推出了区块链集成开发平台。该平台基于区块链技术,提供一套全面的区块链开发工具和开发环境,支持开发者快速开发和部署区块链应用。此外,该平台还可以提供一套全面的区块链开发教程和文档,帮助开发者快速上手区块链开发。