JMX+Prometheus监控Grafana展示

news2024/7/4 5:08:30

文章目录

    • 概述
    • Java代码使用PrometheusApi统计监控指标
    • Prometheus
    • Grafana展示

概述

最近在阅读InLong的源码,发现它采用通过JMX+Prometheus进行指标监控。

这里做了下延伸将介绍使用JMX+Prometheus+Grafana进行监控指标展示,这里单独将Metric部分代码抽离出来做介绍。

Java代码使用PrometheusApi统计监控指标

完整代码地址:https://download.csdn.net/download/zhangshenghang/88030454

主要类(使用Prometheus HTTPServer):

public class AgentPrometheusMetricListener extends Collector implements MetricListener {

    public static final String DEFAULT_DIMENSION_LABEL = "dimension";
    public static final String HYPHEN_SYMBOL = "-";
    private static final Logger LOGGER = LoggerFactory.getLogger(AgentPrometheusMetricListener.class);
    protected HTTPServer httpServer;
    private AgentMetricItem metricItem;
    private Map<String, AtomicLong> metricValueMap = new ConcurrentHashMap<>();
    private Map<String, MetricItemValue> dimensionMetricValueMap = new ConcurrentHashMap<>();
    private List<String> dimensionKeys = new ArrayList<>();//维度key组成的字段列表,即所有监控实体标记@Dimension的字段

    public AgentPrometheusMetricListener() {
        this.metricItem = new AgentMetricItem();
        final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        StringBuilder beanName = new StringBuilder();
        beanName.append(JMX_DOMAIN).append(DOMAIN_SEPARATOR).append("type=AgentPrometheus");
        String strBeanName = beanName.toString();
        try {
            ObjectName objName = new ObjectName(strBeanName);
            mbs.registerMBean(metricItem, objName);
        } catch (Exception ex) {
            LOGGER.error("exception while register mbean:{},error:{}", strBeanName, ex);
        }
        // prepare metric value map
        metricValueMap.put(M_JOB_RUNNING_COUNT, metricItem.jobRunningCount);
        metricValueMap.put(M_JOB_FATAL_COUNT, metricItem.jobFatalCount);

        metricValueMap.put(M_TASK_RUNNING_COUNT, metricItem.taskRunningCount);
        metricValueMap.put(M_TASK_RETRYING_COUNT, metricItem.taskRetryingCount);
        metricValueMap.put(M_TASK_FATAL_COUNT, metricItem.taskFatalCount);

        metricValueMap.put(M_SINK_SUCCESS_COUNT, metricItem.sinkSuccessCount);
        metricValueMap.put(M_SINK_FAIL_COUNT, metricItem.sinkFailCount);

        metricValueMap.put(M_SOURCE_SUCCESS_COUNT, metricItem.sourceSuccessCount);
        metricValueMap.put(M_SOURCE_FAIL_COUNT, metricItem.sourceFailCount);

        metricValueMap.put(M_PLUGIN_READ_COUNT, metricItem.pluginReadCount);
        metricValueMap.put(M_PLUGIN_SEND_COUNT, metricItem.pluginSendCount);
        metricValueMap.put(M_PLUGIN_READ_FAIL_COUNT, metricItem.pluginReadFailCount);
        metricValueMap.put(M_PLUGIN_SEND_FAIL_COUNT, metricItem.pluginSendFailCount);
        metricValueMap.put(M_PLUGIN_READ_SUCCESS_COUNT, metricItem.pluginReadSuccessCount);
        metricValueMap.put(M_PLUGIN_SEND_SUCCESS_COUNT, metricItem.pluginSendSuccessCount);

        int metricsServerPort = 19090;
        try {
            this.httpServer = new HTTPServer(metricsServerPort);
            this.register();
            LOGGER.info("Starting prometheus metrics server on port {}", metricsServerPort);
        } catch (IOException e) {
            LOGGER.error("exception while register agent prometheus http server,error:{}", e.getMessage());
        }
    }


    @Override
    public List<MetricFamilySamples> collect() {
        DefaultExports.initialize();   
        // 在prometheus中命名为agent_total,(_total是CounterMetricFamily自动添加)
        CounterMetricFamily totalCounter = new CounterMetricFamily("agent", "metrics_of_agent_node_total",
                Arrays.asList(DEFAULT_DIMENSION_LABEL));
        totalCounter.addMetric(Arrays.asList(M_JOB_RUNNING_COUNT), metricItem.jobRunningCount.get());
        totalCounter.addMetric(Arrays.asList(M_JOB_FATAL_COUNT), metricItem.jobFatalCount.get());
        totalCounter.addMetric(Arrays.asList(M_TASK_RUNNING_COUNT), metricItem.taskRunningCount.get());
        totalCounter.addMetric(Arrays.asList(M_TASK_RETRYING_COUNT), metricItem.taskRetryingCount.get());
        totalCounter.addMetric(Arrays.asList(M_TASK_FATAL_COUNT), metricItem.taskFatalCount.get());
        totalCounter.addMetric(Arrays.asList(M_SINK_SUCCESS_COUNT), metricItem.sinkSuccessCount.get());
        totalCounter.addMetric(Arrays.asList(M_SINK_FAIL_COUNT), metricItem.sinkFailCount.get());
        totalCounter.addMetric(Arrays.asList(M_SOURCE_SUCCESS_COUNT), metricItem.sourceSuccessCount.get());
        totalCounter.addMetric(Arrays.asList(M_SOURCE_FAIL_COUNT), metricItem.sourceFailCount.get());
        totalCounter.addMetric(Arrays.asList(M_PLUGIN_READ_COUNT), metricItem.pluginReadCount.get());
        totalCounter.addMetric(Arrays.asList(M_PLUGIN_SEND_COUNT), metricItem.pluginSendCount.get());
        totalCounter.addMetric(Arrays.asList(M_PLUGIN_READ_FAIL_COUNT), metricItem.pluginReadFailCount.get());
        totalCounter.addMetric(Arrays.asList(M_PLUGIN_SEND_FAIL_COUNT), metricItem.pluginSendFailCount.get());
        totalCounter.addMetric(Arrays.asList(M_PLUGIN_READ_SUCCESS_COUNT), metricItem.pluginReadSuccessCount.get());
        totalCounter.addMetric(Arrays.asList(M_PLUGIN_SEND_SUCCESS_COUNT), metricItem.pluginSendSuccessCount.get());
        List<MetricFamilySamples> mfs = new ArrayList<>();
        mfs.add(totalCounter);

        // 返回每个维度的统计
        for (Entry<String, MetricItemValue> entry : this.dimensionMetricValueMap.entrySet()) {
            MetricItemValue itemValue = entry.getValue();
            Map<String, String> dimensionMap = itemValue.getDimensions();
            // 取配置文件任务中ID
            String pluginId = dimensionMap.getOrDefault(KEY_PLUGIN_ID, HYPHEN_SYMBOL);
            String componentName = dimensionMap.getOrDefault(KEY_COMPONENT_NAME, HYPHEN_SYMBOL);
            // 统计名称
            String counterName = pluginId.equals(HYPHEN_SYMBOL) ? componentName : pluginId;
            List<String> dimensionIdKeys = new ArrayList<>();
            dimensionIdKeys.add(DEFAULT_DIMENSION_LABEL);
            dimensionIdKeys.addAll(dimensionMap.keySet());
            // 第一个参数统计名称,第二个参数帮助说明,第三个参数维度确认字段
            CounterMetricFamily idCounter = new CounterMetricFamily(counterName,
                    "metrics_of_agent_dimensions_" + counterName, dimensionIdKeys);

            addCounterMetricFamily(M_JOB_RUNNING_COUNT, itemValue, idCounter);
            addCounterMetricFamily(M_JOB_FATAL_COUNT, itemValue, idCounter);

            addCounterMetricFamily(M_TASK_RUNNING_COUNT, itemValue, idCounter);
            addCounterMetricFamily(M_TASK_RETRYING_COUNT, itemValue, idCounter);
            addCounterMetricFamily(M_TASK_FATAL_COUNT, itemValue, idCounter);

            addCounterMetricFamily(M_SINK_SUCCESS_COUNT, itemValue, idCounter);
            addCounterMetricFamily(M_SINK_FAIL_COUNT, itemValue, idCounter);

            addCounterMetricFamily(M_SOURCE_SUCCESS_COUNT, itemValue, idCounter);
            addCounterMetricFamily(M_SOURCE_FAIL_COUNT, itemValue, idCounter);

            addCounterMetricFamily(M_PLUGIN_READ_COUNT, itemValue, idCounter);
            addCounterMetricFamily(M_PLUGIN_SEND_COUNT, itemValue, idCounter);
            addCounterMetricFamily(M_PLUGIN_READ_FAIL_COUNT, itemValue, idCounter);
            addCounterMetricFamily(M_PLUGIN_SEND_FAIL_COUNT, itemValue, idCounter);
            addCounterMetricFamily(M_PLUGIN_READ_SUCCESS_COUNT, itemValue, idCounter);
            addCounterMetricFamily(M_PLUGIN_SEND_SUCCESS_COUNT, itemValue, idCounter);
            mfs.add(idCounter);
        }
        return mfs;
    }

    @Override
    public void snapshot(String domain, List<MetricItemValue> itemValues) {
        System.out.println("domain:" + domain + "metricItem1 = " + JSONUtil.toJsonStr(metricItem));

        for (MetricItemValue itemValue : itemValues) {
            // 不同dimension的指标,统计求和
            for (Entry<String, MetricValue> entry : itemValue.getMetrics().entrySet()) {
                String fieldName = entry.getValue().name;
                AtomicLong metricValue = this.metricValueMap.get(fieldName);
                if (metricValue != null) {
                    long fieldValue = entry.getValue().value;
                    metricValue.addAndGet(fieldValue);
                }
            }
            // 获取统计维度唯一标识
            String dimensionKey = itemValue.getKey();
            //dimensionMetricValue统计维度数量总和
            MetricItemValue dimensionMetricValue = this.dimensionMetricValueMap.get(dimensionKey);
            if (dimensionMetricValue == null) {//首次进来
                dimensionMetricValue = new MetricItemValue(dimensionKey, new ConcurrentHashMap<>(),
                        new ConcurrentHashMap<>());
                this.dimensionMetricValueMap.putIfAbsent(dimensionKey, dimensionMetricValue);
                dimensionMetricValue = this.dimensionMetricValueMap.get(dimensionKey);
                dimensionMetricValue.getDimensions().putAll(itemValue.getDimensions());
                // add prometheus label name
                for (Entry<String, String> entry : itemValue.getDimensions().entrySet()) {
                    if (!this.dimensionKeys.contains(entry.getKey())) {
                        this.dimensionKeys.add(entry.getKey());
                    }
                }
            }
            // 遍历具体统计的指标
            for (Entry<String, MetricValue> entry : itemValue.getMetrics().entrySet()) {
                String fieldName = entry.getValue().name;//统计指标名称
                MetricValue metricValue = dimensionMetricValue.getMetrics().get(fieldName);//获取历史统计的数量
                if (metricValue == null) {
                    //首次统计添加
                    metricValue = MetricValue.of(fieldName, entry.getValue().value);
                    dimensionMetricValue.getMetrics().put(metricValue.name, metricValue);
                    continue;
                }
                //累加本次统计的数量
                metricValue.value += entry.getValue().value;
            }
        }

        System.out.println("metricItem2 = " +  JSONUtil.toJsonStr(metricItem));
    }

    private void addCounterMetricFamily(String defaultDimension, MetricItemValue itemValue,
                                        CounterMetricFamily idCounter) {
        Map<String, String> dimensionMap = itemValue.getDimensions();
        List<String> labelValues = new ArrayList<>(dimensionMap.size() + 1);
        labelValues.add(defaultDimension);//首先添加统计维度字段,如:jobRunningCount
        for (String key : dimensionMap.keySet()) {
            String labelValue = dimensionMap.getOrDefault(key, HYPHEN_SYMBOL);
            labelValues.add(labelValue);
        }
        long value = 0L;
        Map<String, MetricValue> metricValueMap = itemValue.getMetrics();
        MetricValue metricValue = metricValueMap.get(defaultDimension);
        if (metricValue != null) {
            value = metricValue.value;
        }
        idCounter.addMetric(labelValues, value);
    }
}

启动后访问绑定端口http://ip:19090/获取监控内容如下,包括了我们程序中自己监控的信息

# HELP process_cpu_seconds_total Total user and system CPU time spent in seconds.
# TYPE process_cpu_seconds_total counter
process_cpu_seconds_total 12.819136
# HELP process_start_time_seconds Start time of the process since unix epoch in seconds.
# TYPE process_start_time_seconds gauge
process_start_time_seconds 1.688973202094E9
# HELP process_open_fds Number of open file descriptors.
# TYPE process_open_fds gauge
process_open_fds 57.0
# HELP process_max_fds Maximum number of open file descriptors.
# TYPE process_max_fds gauge
process_max_fds 10240.0
# HELP agent_total metrics_of_agent_node_total
# TYPE agent_total counter
agent_total{dimension="jobRunningCount",} 3370.0
agent_total{dimension="jobFatalCount",} 0.0
agent_total{dimension="taskRunningCount",} -90.0
agent_total{dimension="taskRetryingCount",} 0.0
agent_total{dimension="taskFatalCount",} 0.0
agent_total{dimension="sinkSuccessCount",} 0.0
agent_total{dimension="sinkFailCount",} 0.0
agent_total{dimension="sourceSuccessCount",} 0.0
agent_total{dimension="sourceFailCount",} 0.0
agent_total{dimension="pluginReadCount",} 0.0
agent_total{dimension="pluginSendCount",} 6740.0
agent_total{dimension="pluginReadFailCount",} 0.0
agent_total{dimension="pluginSendFailCount",} 0.0
agent_total{dimension="pluginReadSuccessCount",} 0.0
agent_total{dimension="pluginSendSuccessCount",} 0.0
# HELP AServer_total metrics_of_agent_dimensions_AServer
# TYPE AServer_total counter
AServer_total{dimension="jobRunningCount",streamId="streamId",pluginId="AServer",groupId="groupId1",} 1685.0
AServer_total{dimension="jobFatalCount",streamId="streamId",pluginId="AServer",groupId="groupId1",} 0.0
AServer_total{dimension="taskRunningCount",streamId="streamId",pluginId="AServer",groupId="groupId1",} -19.0
AServer_total{dimension="taskRetryingCount",streamId="streamId",pluginId="AServer",groupId="groupId1",} 0.0
AServer_total{dimension="taskFatalCount",streamId="streamId",pluginId="AServer",groupId="groupId1",} 0.0
AServer_total{dimension="sinkSuccessCount",streamId="streamId",pluginId="AServer",groupId="groupId1",} 0.0
AServer_total{dimension="sinkFailCount",streamId="streamId",pluginId="AServer",groupId="groupId1",} 0.0
AServer_total{dimension="sourceSuccessCount",streamId="streamId",pluginId="AServer",groupId="groupId1",} 0.0
AServer_total{dimension="sourceFailCount",streamId="streamId",pluginId="AServer",groupId="groupId1",} 0.0
AServer_total{dimension="pluginReadCount",streamId="streamId",pluginId="AServer",groupId="groupId1",} 0.0
AServer_total{dimension="pluginSendCount",streamId="streamId",pluginId="AServer",groupId="groupId1",} 3370.0
AServer_total{dimension="pluginReadFailCount",streamId="streamId",pluginId="AServer",groupId="groupId1",} 0.0
AServer_total{dimension="pluginSendFailCount",streamId="streamId",pluginId="AServer",groupId="groupId1",} 0.0
AServer_total{dimension="pluginReadSuccessCount",streamId="streamId",pluginId="AServer",groupId="groupId1",} 0.0
AServer_total{dimension="pluginSendSuccessCount",streamId="streamId",pluginId="AServer",groupId="groupId1",} 0.0
# HELP AServer_total metrics_of_agent_dimensions_AServer
# TYPE AServer_total counter
AServer_total{dimension="jobRunningCount",streamId="streamId",pluginId="AServer",groupId="groupId2",} 1685.0
AServer_total{dimension="jobFatalCount",streamId="streamId",pluginId="AServer",groupId="groupId2",} 0.0
AServer_total{dimension="taskRunningCount",streamId="streamId",pluginId="AServer",groupId="groupId2",} -71.0
AServer_total{dimension="taskRetryingCount",streamId="streamId",pluginId="AServer",groupId="groupId2",} 0.0
AServer_total{dimension="taskFatalCount",streamId="streamId",pluginId="AServer",groupId="groupId2",} 0.0
AServer_total{dimension="sinkSuccessCount",streamId="streamId",pluginId="AServer",groupId="groupId2",} 0.0
AServer_total{dimension="sinkFailCount",streamId="streamId",pluginId="AServer",groupId="groupId2",} 0.0
AServer_total{dimension="sourceSuccessCount",streamId="streamId",pluginId="AServer",groupId="groupId2",} 0.0
AServer_total{dimension="sourceFailCount",streamId="streamId",pluginId="AServer",groupId="groupId2",} 0.0
AServer_total{dimension="pluginReadCount",streamId="streamId",pluginId="AServer",groupId="groupId2",} 0.0
AServer_total{dimension="pluginSendCount",streamId="streamId",pluginId="AServer",groupId="groupId2",} 3370.0
AServer_total{dimension="pluginReadFailCount",streamId="streamId",pluginId="AServer",groupId="groupId2",} 0.0
AServer_total{dimension="pluginSendFailCount",streamId="streamId",pluginId="AServer",groupId="groupId2",} 0.0
AServer_total{dimension="pluginReadSuccessCount",streamId="streamId",pluginId="AServer",groupId="groupId2",} 0.0
AServer_total{dimension="pluginSendSuccessCount",streamId="streamId",pluginId="AServer",groupId="groupId2",} 0.0
....

Prometheus

上面通过代码获取到了Prometheus的监控信息,下面我们通过配置Prometheus,在Prometheus中获取到监控指标。

修改Prometheus配置文件/etc/prometheus/prometheus.yml将我们程序中开启的端口,添加到配置文件

# my global config
global:
  scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).

# Alertmanager configuration
alerting:
  alertmanagers:
    - static_configs:
        - targets:
          # - alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  # - "first_rules.yml"
  # - "second_rules.yml"

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: "prometheus"

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    static_configs:
      - targets: ["localhost:9090"]
  # 程序中开启的端口
  - job_name: "Jast Monitor"
    static_configs:
      - targets: ['192.168.1.41:19090']

重启Prometheus服务

访问Prometheus进入status->Targets页面

在这里插入图片描述

可以看到我们配置的监控

在这里插入图片描述

至此Prometheus已经将我们程序的监控信息捕获到。

Grafana展示

Grafana安装不在这里介绍,自行安装

登录Grafana,添加数据源Data Sources

在这里插入图片描述

点击Add data source

在这里插入图片描述

选择Prometheus

在这里插入图片描述

配置Prometheus地址

在这里插入图片描述

拖到最底下,点击Savae & test,成功会提示Data source is working

在这里插入图片描述

创建仪表盘,配置监控

在这里插入图片描述

在这里插入图片描述

点击Metrics browser展开

在这里插入图片描述

选择展示的监控指标(这里AServer_total和agent_total是我们自己代码中配置的监控信息)

在这里插入图片描述

在这里插入图片描述

点击Use query

在这里插入图片描述

查询出数据展示效果

在这里插入图片描述

点击保存可以在Dashboard中查看我们监控指标

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/741102.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络配置管理器中的系统日志配置

包含许多设备的大型网络基础设施将在其清单中具有某些重要和关键设备&#xff0c;例如核心路由器或防火墙。这些设备必须始终受到有关任何配置更改的持续监视。 在如此庞大的网络中&#xff0c;手动跟踪所有这些重要设备并在每次进行新更改时触发备份几乎是不可能的。如果管理…

windows环境部署seata注意事项

1.将seata放置微服务项目中&#xff1a; 1.服务端下载地址&#xff1a;https://github.com/seata/seata/releases/download/v1.4.2/seata-server-1.4.2.zip 2.源码下载地址: https://github.com/seata/seata &#xff08;将script目录以及里面文件放至seata-server中&#xff…

力扣挑战:中枢整数的定义与寻找方法

本篇博客讲解力扣“2485. 找出中枢整数”的解题思路&#xff0c;这是题目链接。 给定一个正整数n&#xff0c;如果它存在一个中枢整数x&#xff0c;那么满足以下等式&#xff1a; 123…x x(x1)(x2)…n 利用等差数列求和公式&#xff1a;(首项末项)项数2&#xff0c;以及项数…

优思学院|TQM与六西格玛完美契合:质量和利润的共赢之道

TQM的本质乃无止境地追求质量&#xff0c;然而在解决各个问题点时&#xff0c;直到目的逹成之前必须不断地转动PDCA或者六西格玛方法中的DMAIC这些个活动&#xff0c;究竟与经营有什么关连呢&#xff1f; 我们都知道企业的目的是生产好的产品、提供好的服务&#xff0c;并以合…

火热的低代码和无代码赛道

一、背景 星霜荏苒&#xff0c;居诸不息。互联网技术飞速发展&#xff0c;软件的设计、开发、应用也是风发泉涌&#xff0c;无论是开发工具还是应用程序&#xff0c;都在不断追求降本增效&#xff0c;极大地推动了软件研发的长足进步。但然而&#xff0c;长期以来&#xff0c;我…

elementui-drawer模板

1、效果图 2、上代码 <template><div><el-drawersize"100%":visible.sync"drawer"style"position: absolute;"class"details":modal-append-to-body"false":modal "false":before-close"ha…

Linux环境基础开发工具使用(yum软件安装工具的使用、vim编辑器使用及握gcc/g++编译器的使用等)

Linux环境基础开发工具使用 1.Linux 软件包管理器 yum1.1 什么是软件包1.2 yum常用命令1.3 好玩的yum包 2.Linux开发工具2.1 vim工具的由来2.2 vim模式①基本模式②派生模式 2.3 vim的基本操作2.4 vim正常模式命令集2.5 vim末行模式命令集2.6 简单vim配置 3.Linux编译器 - gcc/…

并发容器(三)BlockigQueue

阻塞队列 看几个常用的实现&#xff1a; 1.ArrayBlockingQueue是最简单的一种阻塞队列&#xff0c;底层是由数组实现 2.LinkedBlockingQueue 底层是由链表实现的&#xff0c;锁的粒度更细&#xff0c;但是占用的内存更大 当移除元素的时候takeLock和putLock一起加 3.Synchrono…

HCIP第七天

题目 拓扑图 1.所有路由器各自创建一个环回接口&#xff0c;合理规划IP地址 测试 2. R1-R2-R3-R4-R6之间使用OSPF协议&#xff0c;R4-R5-R6之间使用RIP协议 3. R1环回重发布方式引入OSPF网络 4. R4/R6上进行双点双向重发布 将OSPF中的环回接口改成broadcast 因为华为默认环回接…

用ChatGPT解析Wireshark抓取的数据包样例

用Wireshark抓取的数据包&#xff0c;常用于网络故障排查、分析和应用程序通信协议开发。其抓取的分组数据结果为底层数据&#xff0c;看起来比较困难&#xff0c;现在通过chatGPT大模型&#xff0c;可以将原始抓包信息数据提交给AI进行解析&#xff0c;本文即是进行尝试的样例…

4.4Java EE——多对多查询

订单和商品多对多关系图 在实际项目开发中&#xff0c;多对多的关联关系非常常见。以订单和商品为例&#xff0c;一个订单可以包含多种商品&#xff0c;而一种商品又可以属于多个订单&#xff0c;订单和商品属于多对多关联关系&#xff0c;订单和商品之间的关联关系如图。 在数…

springboot家政服务管理平台

本系统为了数据库结构的灵活性所以打算采用MySQL来设计数据库&#xff0c;而java技术&#xff0c;B/S架构则保证了较高的平台适应性。本文主要介绍了本系统的开发背景&#xff0c;所要完成的功能和开发的过程&#xff0c;主要说明了系统设计的重点、设计思想。 本系统主要是设…

通信算法之177: 基于Matlab的OFDM通信系统关键基带算法设计7-流程

一. 接收算法流程 1.1 粗同步&#xff08;分组检测&#xff09; 1.2 载波同步&#xff08;精细频偏估计&#xff09; 多普勒频偏和晶振。频率偏差&#xff0c;会破坏子载波间的正交性&#xff0c;且这种频差对相位的影响还具有累加性。 1.3 精同步&#xff08;OFDM起始&…

软件工程——第10章面向对象分析知识点整理

本专栏是博主个人笔记&#xff0c;主要目的是利用碎片化的时间来记忆软工知识点&#xff0c;特此声明&#xff01; 文章目录 1.分析工作主要包括哪三项内容&#xff1f; 2.面向对象分析是一个怎样的过程&#xff1f; 3.需求陈述是一成不变的吗&#xff1f; 4.复杂问题的对象…

web信息收集----网站指纹识别

文章目录 一、网站指纹&#xff08;web指纹&#xff09;二、CMS简介三、指纹识别方法3.1 在线网站识别3.2 工具识别3.3 手动识别3.4 Wappalyzer插件识别 一、网站指纹&#xff08;web指纹&#xff09; Web指纹定义&#xff1a;Web指纹是一种对目标网站的识别技术&#xff0c;通…

敞篷超跑造型,还支持4KHz回报,雷柏VT960 Pro游戏鼠标体验

想要在游戏中获得精准、迅速的操作反馈&#xff0c;鼠标的配置很重要&#xff0c;之前雷柏推出的支持4KHz的高回报率鼠标&#xff0c;很适合高刷显示器使用&#xff0c;最近我也上手了一款雷柏VT960 Pro。这只无线游戏鼠标采用了一种镂空“超跑”的外观设计&#xff0c;还带有个…

【C语言基础】内存布局和作用域

(꒪ꇴ꒪(꒪ꇴ꒪ ),hello我是祐言博客主页&#xff1a;C语言基础,Linux基础,软件配置领域博主&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff01;送给读者的一句鸡汤&#x1f914;&#xff1a;集中起来的意志可以击穿顽石!作者水平很有限&#xff0c;如果发现错误…

UnityVR--机械臂场景10-简单流水线应用2

目录 一. 前言 二. 事件中心修改 三. 机械臂加入DoTween的运动 四. 机械臂关节的控制 一. 前言 上一篇已经完成了流水线的搭建&#xff0c;本篇要完成的是&#xff1a;1. 事件中心的修改&#xff1b;2. 机械臂的DoTween运动改造&#xff1b; 本篇是在事件中心2和机械臂场景…

macOS Ventura 13.5beta5(22G5072a)发布

系统介绍 黑果魏叔 7 月 11 日消息&#xff0c;苹果今日向 Mac 电脑用户推送了 macOS 13.5 开发者预览版 Beta 5 更新&#xff08;内部版本号&#xff1a;22G5072a&#xff09;&#xff0c;本次更新距离上次发布隔了 12 天。 macOS Ventura 带来了台前调度、连续互通相机、Fa…

Python自动化办公:提升效率,释放潜力(借助AI实现)

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术。搜…