基于Docker + Locust的数据持久化性能测试系统

在这里插入图片描述

前几天给大家分享了如何使用Locust进行性能测试,但是在实际使用中会发现存在压测的结果无法保存的问题,比如在分布式部署情况下进行压测,每轮压测完成需要释放资源删除容器重新部署后,这段时间的压测结果就都丢失了,如果想要对比多次压测的结果,就需要在每轮压测完成后手动记录,非常不方便,而且Locust在压测过程中对于一些指标的展示也过于简单,不利于我们对测试结果的分析,接下来跟大家分享使用Locust + Prometheus实现数据持久化,并且用Grafana创建性能测试仪表,希望能给大家的测试工作带来帮助。

关于Docker,在本文中就不做介绍了,之前给大家分享过一篇关于Docker介绍与安装的文章:
Docker在Windows与CentOS上的安装

Prometheus用途:

Prometheus是一个开源的监控和警报工具,用于收集、存储和查询各种类型的时间序列数据。它可以监控服务器、应用程序和网络服务的性能指标,以便管理员能够及时发现问题并采取相应的措施。Prometheus系统还可以通过配置警报规则来实时监测系统的状态,并在发现异常情况时发送警报通知。这使得管理员能够快速响应并解决问题,确保系统的稳定性和可靠性。

Grafana用途:

Grafana的主要用途是数据可视化和监控。它可以帮助用户通过创建各种图表和仪表板来可视化数据,从而更容易地理解数据、发现趋势和问题,并做出更明智的决策。Grafana还可以与各种数据源集成,包括数据库、云服务和监控系统,帮助用户监控系统的健康状况、性能和运行情况。总的来说,Grafana是一个功能强大的工具,可以帮助用户更好地理解和管理他们的数据和系统。

一、准备Docker环境

操作系统:CentOS 7
Python版本:3.8
Locust版本:2.1

通过yum安装docker

yum install -y docker

安装完成后,查看docker版本

docker -v

创建docker虚拟网络,docker虚拟网络可以让不同的docker容器在各自独立的网络环境中运行,相互之间不会干扰;还能方便容器之间进行通信,就像一个内部的“网络小世界”;并且能让容器与外部网络进行连接,实现数据的传输和交互。

docker network create locust_network

通过以下命令查看创建的网络

docker network ls

二、部署locust的Master节点

我们需要采用Locust的分布式部署,那么Master节点的主要作用是收集数据。那么就需要在Master节点服务器上启动Locust的master与prometheus。

非常感谢大佬开源了一个集成了集成了prometheus的locust的master节点代码,可以通过下面链接下载:

https://github.com/myzhan/boomer/blob/master/prometheus_exporter.py

如果下载遇到问题,也可以直接使用下面代码:

# -*- coding: utf-8 -*-
import six
from itertools import chain
from flask import request, Response
from locust import stats as locust_stats, runners as locust_runners
from locust import User, task, events
from prometheus_client import Metric, REGISTRY, exposition


class LocustCollector(object):
    """
    用于收集Locust的指标数据,并且以Prometheus格式导出
    """
    registry = REGISTRY

    def __init__(self, environment, runner):
        self.environment = environment
        self.runner = runner

    def collect(self):
        '''
        该方法用于收集指标数据,并生成相应的Prometheus指标,只在locust状态为spawning或者running时收集指标。
        '''
        runner = self.runner
        if runner and runner.state in (locust_runners.STATE_SPAWNING, locust_runners.STATE_RUNNING):
            stats = []
            for s in chain(locust_stats.sort_stats(runner.stats.entries), [runner.stats.total]):
                stats.append({
                    'method': s.method,
                    'name': s.name,
                    'num_requests': s.num_requests,
                    'num_failures': s.num_failures,
                    'avg_response_time': s.avg_response_time,
                    'min_response_time': s.min_response_time or 0,
                    'max_response_time': s.max_response_time,
                    'current_rps': s.current_rps,
                    'median_response_time': s.median_response_time,
                    'ninetieth_response_time': s.get_response_time_percentile(0.9),
                    # 只有总统计数据可以使用current_response_time
                    # 'current_response_time_percentile_95': s.get_current_response_time_percentile(0.95),
                    'avg_content_length': s.avg_content_length,
                    'current_fail_per_sec': s.current_fail_per_sec
                })
            # 只在worker节点中起作用
            errors = [e.to_dict() for e in six.itervalues(runner.stats.errors)]
            metric = Metric('locust_user_count', 'Swarmed users', 'gauge')
            metric.add_sample('locust_user_count', value=runner.user_count, labels={})
            yield metric
            metric = Metric('locust_errors', 'Locust requests errors', 'gauge')
            for err in errors:
                metric.add_sample('locust_errors', value=err['occurrences'], labels={'path': err['name'], 'method': err['method'], 'error': err['error']})
            yield metric
            is_distributed = isinstance(runner, locust_runners.MasterRunner)
            if is_distributed:
                metric = Metric('locust_slave_count', 'Locust number of slaves', 'gauge')
                metric.add_sample('locust_slave_count', value=len(runner.clients.values()), labels={})
                yield metric

            metric = Metric('locust_fail_ratio', 'Locust failure ratio', 'gauge')
            metric.add_sample('locust_fail_ratio', value=runner.stats.total.fail_ratio, labels={})
            yield metric

            metric = Metric('locust_state', 'State of the locust swarm', 'gauge')
            metric.add_sample('locust_state', value=1, labels={'state': runner.state})
            yield metric
            stats_metrics = ['avg_content_length', 'avg_response_time', 'current_rps', 'current_fail_per_sec','max_response_time',
                             'ninetieth_response_time', 'median_response_time','min_response_time', 'num_failures', 'num_requests']
            for mtr in stats_metrics:
                mtype = 'gauge'
                if mtr in ['num_requests', 'num_failures']:
                    mtype = 'counter'
                metric = Metric('locust_stats_' + mtr, 'Locust stats ' + mtr, mtype)
                for stat in stats:
                    # aggregstat的方法标签是None,所以将它命名为aggregstat
                    if 'Aggregated' != stat['name']:
                        metric.add_sample('locust_stats_' + mtr, value=stat[mtr], labels={'path': stat['name'], 'method': stat['method']})
                    else:
                        metric.add_sample('locust_stats_' + mtr, value=stat[mtr], labels={'path': stat['name'], 'method': 'Aggregated'})
                yield metric

@events.init.add_listener
def locust_init(environment, runner, **kwargs):
    if environment.web_ui and runner:
        @environment.web_ui.app.route('/export/prometheus')
        def prometheus_exporter():
            registry = REGISTRY
            encoder, content_type = exposition.choose_encoder(request.headers.get('Accept'))
            if 'name[]' in request.args:
                registry = REGISTRY.restricted_registry(request.args.get('name[]'))
            body = encoder(registry)
            return Response(body, content_type=content_type)
        REGISTRY.register(LocustCollector(environment, runner))

class Dummy(User):
    @task(20)
    def hello(self):
        pass

1、下载完成后,将prometheus_exporter.py上传至当做master节点的服务器
2、启动Locust的Master节点

启动命令如下:

docker run -p 8089:8089 -p 5557:5557 -v $PWD/prometheus_exporter.py:/mnt/locust/locustfile.py --name=locust_master --network=locust_network --network-alias=locust_master locustio/locust -f /mnt/locust/locustfile.py --master

执行命令时,会自动下载镜像,可以不用执行docker pull。

对于这条命令的解释:

docker run:运行一个 Docker 容器。

-p 8089:8089 -p 5557:5557:将主机的 8089 端口和 5557 端口分别映射到容器的 8089 端口和 5557 端口。

-v $PWD/prometheus_exporter.py:/mnt/locust/locustfile.py:将当前工作目录下的prometheus_exporter.py文件挂载到容器的/mnt/locust/locustfile.py位置。

--name=locust_master:为容器命名为locust_master。

--network=locust_network:指定容器使用的网络为locust_network。

--network-alias=locust_master:为容器在网络中设置别名locust_master。

locustio/locust -f /mnt/locust/locustfile.py --master:指定使用locustio/locust镜像,并指定要运行的文件为/mnt/locust/locustfile.py,以主节点模式运行。

如果执行上面命令在启动容器时出现报错
在这里插入图片描述

说明容器里面没有安装prometheus_client库,需要进行手动安装。手动安装完成后可以重新打一个镜像,避免后续报错,此处先描述一下如何进行手动安装,首先我们要现将容器启动起来,然后进入容器内部进行包的安装。

编辑prometheus_exporter.py文件

vim prometheus_exporter.py

在文件的第二行添加两行代码,然后保存文件。

关于vim编辑器的使用可以参考之前给大家分享的linux常用命令:
作为测试人员的Linux常用命令

import os
os.system("tail -f /dev/null")

在这里插入图片描述

这两行代码的意思是使用os.system方法执行命令tail -f /dev/null,会持续追踪/dev/null文件的内容(实际上/dev/null是一个空设备,不会有实际内容)。一般用于在后台保持进程运行,这样容器就可以正常启动。

重启docker的master节点容器

docker restart locust_master

查看容器运行状态,locust_master容器启动成功。

docker ps -a

进入到locust_master容器中。

docker exec -it locust_master /bin/bash

进入容器后,使用pip安装prometheus_client包。

pip install prometheus_client

安装成功后,通过exit退出容器回到服务器上,再次使用vim编辑prometheus_exporter.py文件,删除刚刚添加的两行代码,保存文件。

还原prometheus_exporter.py文件后,再次重启master节点容器

docker restart locust_master
3、验证Locust的Master节点

重启完成后,打开浏览器,在浏览器输入http://master-ip:8089可以访问到locust的原生web页面。
在这里插入图片描述

然后在浏览器输入http://master-ip:8089/export/prometheus
如果出现如下图的prometheus数据,表示master节点启动正确。
在这里插入图片描述

4、启动Prometheus

在master节点服务器上创建prometheus.yml配置文件,并且写入以下内容:

global:
  scrape_interval:     10s
  evaluation_interval: 10s
 
scrape_configs:
  - job_name: prometheus
    static_configs:
      - targets: ['localhost:9090']
        labels:
          instance: prometheus
          
  - job_name: locust
    
    metrics_path: '/export/prometheus'
    static_configs:
      - targets: ['locust_master:8089']  # 这里是locust的master节点启动命令中的network-alias后面的参数 + 内部端口,不要写外部映射的端口号
        labels:
          instance: locust

运行下面命令创建prometheus容器

docker run -d -p 9090:9090 -v $PWD/prometheus.yml:/etc/prometheus/prometheus.yml --name=prometheus --network=locust_network --network-alias=prometheus prom/prometheus

对于这条命令的解释:

docker run:运行一个 Docker 容器。

-d:以守护进程模式运行容器。

-p 9090:9090:将主机的 9090 端口映射到容器的 9090 端口。

-v $PWD/prometheus.yml:/etc/prometheus/prometheus.yml:将当前工作目录下的prometheus.yml文件挂载到容器的/etc/prometheus/prometheus.yml位置。

--name=prometheus:给容器命名为“prometheus”。

--network=locust_network:指定容器使用的网络为“locust_network”。

--network-alias=prometheus:为容器在网络中设置别名“prometheus”。

prom/prometheus:指定要使用的镜像为“prom/prometheus”

查看容器运行状态

docker ps -a

启动容器成功后进行验证
浏览器输入http://master-ip:9090/targets,出现如下页面,则代表服务运行正常。
在这里插入图片描述

5、启动Grafana

使用以下命令启动grafana容器

docker run -d -p 3000:3000 --name grafana --network=locust_network grafana/grafana

对于这条命令的解释:

docker run:启动一个 Docker 容器。

-d:表示在后台以守护进程的方式运行。

-p 3000:3000:将主机的 3000 端口映射到容器的 3000 端口。

--name grafana:给容器命名为“grafana”。

--network=locust_network:指定容器使用“locust_network”网络。

grafana/grafana:使用“grafana/grafana”镜像来创建容器。

浏览器输入http://master_ip:3000
在这里插入图片描述

首次登录用户名和密码都是admin,进去了之后需要修改密码,登录后进入Configuration

在这里插入图片描述

添加一个数据源。
在这里插入图片描述

选择数据源为prometheus。
在这里插入图片描述

配置数据源的url,url处输入创建prometheus容器时的–network-alias的别名:9090,所以此处需要填写http://prometheus:9090。
在这里插入图片描述

导入仪表盘模版。
在这里插入图片描述

输入id为12081,点击load,来加载locust性能测试的仪表盘模版。
在这里插入图片描述

选择完仪表盘模版后选择数据源,选择prometheus,点击import。
在这里插入图片描述

导入成功后,出现如下页面,此时通过locust执行测试的数据将会展示在仪表盘中。
在这里插入图片描述

关于启动用户数的图表配置:

id为12081的这个模版中缺少Locust的用户数量指标,需要额外进行创建。

点击仪表盘上方添加图表按钮
在这里插入图片描述

在这里插入图片描述

数据源选择prometheus,然后下方的Metrics browser处填写locust_user_count,最后点击右上角的Apply,此时仪表盘中会显示启动用户数据。
在这里插入图片描述

三、部署Locust的Worker节点

关于Locust压测脚本编写有很多种方式,需要具备一定的python编程基础,可以参照:
使用Python3 + Locust进行性能测试
worker节点启动的py文件是压测需要的业务代码。
以下是一个单接口压测的例子:

# -*- coding:utf-8 -*-
from locust import User, task, events
import requests
import time
import json

__doc__ = '埋点接口压测脚本'


class Dummy(User):

    @task
    def send_lingge_burying_point(self):
        """
        发送埋点接口
        """
        api_url = 'https://app.xxxxxxxxx.cn/app_v1/advert/dataBack'
        headers = {'Content-Type': 'application/x-www-form-urlencoded'}
        request_data = {'androidid': '0', 'appType': 'ios-app-user', 'appVersion': '1.61.0', 'channel': 'ios-official',
                        'deviceBrand': 'iPhone', 'deviceModel': 'iPhone XS',
                        'equipmentId': '09bf8295234a91723908172394635c98f', 'eventName': 'obtainLocationInformation',
                        'eventParam': json.dumps({"cityCode": "110000"}), 'idfa': '00000000-0000-0000-0000-000000000000',
                        'interfaceType': 'event', 'mac': '0', 'oaid': '0', 'osType': 'iOS', 'platform': 'ios',
                        'systemVersion': '15.5'}
        start_time = time.time()
        try:
            response = requests.post(url=api_url, params=request_data, headers=headers)
            response_text = json.loads(response.text)
            total_time = int((time.time() - start_time) * 1000)
            if response_text['success'] is True:
                events.request_success.fire(request_type="HTTPS", name="埋点接口-成功", response_time=total_time, response_length=len(response_text))
            else:
                events.request_failure.fire(request_type="HTTPS", name="埋点接口-失败", response_time=total_time, response_length=len(response_text))
        except Exception as e:
            total_time = int((time.time() - start_time) * 1000)
            events.request_failure.fire(request_type="HTTPS", name="埋点接口-错误", response_time=total_time, exception=f'埋点接口错误:{e}', response_length=0)

文件名称为locust_burial_point.py

将locust_burial_point.py上传到服务器,然后执行下面命令,来启动worker节点。

docker run -d -v $PWD/locust_worker.py:/mnt/locust/locustfile.py --name=locust_worker --network=locust_network locustio/locust -f /mnt/locust/locustfile.py --worker --master-host locust_master --master-port 5557

对于这条命令的解释:

docker run:运行 Docker 容器。

-d:以守护进程模式运行。

-v $PWD/locust_worker.py:/mnt/locust/locustfile.py:将当前工作目录下的locust_worker.py文件挂载到容器内的/mnt/locust/locustfile.py位置。

--name=locust_worker:给容器命名为“locust_worker”。

--network=locust_network:指定容器使用“locust_network”网络。

locustio/locust:使用“locustio/locust”镜像。

-f /mnt/locust/locustfile.py:指定要运行的文件为/mnt/locust/locustfile.py。

--worker:以工作节点模式运行。

--master-host locust_master:指定主节点的主机名。

--master-port 5557:指定主节点的端口号。

启动成功后,查看容器运行状态。

docker ps -a

此时Master和Worker节点都已经正确启动,进入master节点的Locust web页面,可以看到worker数变为了1。
在这里插入图片描述

到此,大功告成,可以输入总用户数和每秒启动数来进行压测了,压测过程中,可以通过grafana的仪表盘分析测试过程与结果。

在此处贴一张我前段时间压测过程中的图:
在这里插入图片描述

四、搭建docker私有仓库(扩展)

1、修改/etc/docker/daemon.json文件,添加信任。
将以下内容添加到文件中

"insecure-registries":["http://master-ip:8080"]

2、重新加载并且重启docker

# 重加载
systemctl daemon-reload
# 重启docker
systemctl restart docker

3、部署带有图象界面的DockerRegistry容器,用来管理镜像。

创建registry-ui目录,并且进入到目录中。

mkdir registry-ui && cd registry-ui

创建docker-compose.yml文件。

touch docker-compose.yml

将以下内容写入docker-compose.yml,REGISTRY_URL需要修改为服务器的ip地址,然后保存文件。

version: '3.0'
services:
  registry:
    image: registry 
    volumes:
      - ./registry-data:/var/lib/registry
  ui:
    image: joxit/docker-registry-ui:static
    ports:
      - 8080:80
    environment:
      - REGISTRY_TITLE=这是一个性能测试镜像仓库
      - REGISTRY_URL=http://master_ip:5000
    depends_on:
      - registry

在registry-ui目录中启动。

docker-compose up -d

启动成功后访问http://master_ip:8080,出现下图则代表启动成功。
在这里插入图片描述

最后,关于如何创建镜像、上传下载镜像等,以及docker的常用命令,大家可以阅读:Docker常用命令

希望本文能给大家的测试工作带来一定的帮助,谢谢~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一文讲解Android车载系统camera架构 - EVS

Android的camera开发中,使用最多的是camera2 以及现在Google主推的cameraX 架构,而这两个架构主要针对的是手机移动端上camera的流程。 而今天介绍的EVS(Exterior View System)架构是不同于camera2上的手机架构,针对Automotive的版本&#x…

【源码阅读】 Golang中的database/sql库源码探究

Note:文章待完结 文章目录 前言一、整体目录结构二、driver包1、驱动相关driver.Driver2、驱动连接:driver.Conn3、预处理结构:Stmt4、执行结果 driver.Result5、查询结果:driver.Rows6、driver.RowsAffected7、driver.Value8、Va…

vue-quill-editor富文本插件控制字数显示

最终效果 富文本编辑框&#xff0c;只统计内容&#xff0c;不包含标签以及样式&#xff0c;超出最大字数限制提示。 具体代码 html <div class"relative"><quillEditorv-model"form.nutriSuggestion"ref"myQuillEditor7":options&quo…

03-JAVA设计模式-策略模式

策略模式 什么是策略模式 策略模式&#xff08;Strategy Pattern&#xff09;是行为设计模式之一&#xff0c;它使你能在运行时改变对象的行为。在策略模式中&#xff0c;一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为模式。 在策略模式中&#xff0c;…

uniapp微信小程序开发踩坑日记:由于图表数据渲染不出来,我第一次在项目中用watch函数监听数据变化

一、发现问题 在我们团队自己开发的微信小程序中&#xff0c;引入了Echarts图表库 然后突然有一天&#xff0c;后端队友反应图表渲染有问题。后面我去试了一下&#xff0c;确实20次里面必有一次数据渲染不出来 断定代码没问题&#xff0c;于是我们将其鉴定为玄学 二、问题原因…

【GitHub】主页简历优化

【github主页】优化简历 写在最前面一、新建秘密仓库二、插件卡片配置1、仓库状态统计2、Most used languages&#xff08;GitHub 常用语言统计&#xff09;使用细则 3、Visitor Badge&#xff08;GitHub 访客徽章&#xff09;4、社交统计5、打字特效6、省略展示小猫 &#x1f…

UDP和TCP(传输层)

这里写目录标题 UDPUDP的基本特点UDP协议报文格式 TCPTCP协议报文格式TCP特点可靠传输实现机制确认应答超时重传数据丢了应答报文丢了 小结 UDP UDP的基本特点 无连接不可靠传输面向数据报全双工 UDP协议报文格式 2个字节有效范围(无符号): 0 ~ 65535(2^16 - 1). 2个字节有效范…

用数据检验函数正确性,matlab2C

数据存取格式 filename1 g.txt; fid1 fopen(filename1,w); for i 1 : length(g)for j1:size(g,2)if(j1)fprintf(fid1,{%.16f,,g(i,j)); elseif(j>1&&j<151)fprintf(fid1,%.16f,,g(i,j)); elsefprintf(fid1,%.16f},\n,g(i,j));endend%fprintf(fid1,\n…

如何用Python语言实现远程控制4路控制器/断路器

如何用Python语言实现远程控制4路控制器/断路器呢&#xff1f; 本文描述了使用Python语言调用HTTP接口&#xff0c;实现控制4路控制器/断路器&#xff0c;支持4路输出&#xff0c;均可独立控制&#xff0c;可接入各种电器。 可选用产品&#xff1a;可根据实际场景需求&#xf…

Spring Web MVC入门(3)——响应

目录 一、返回静态页面 RestController 和 Controller之间的关联和区别 二、返回数据ResponseBody ResponseBody作用在类和方法的情况 三、返回HTML代码片段 响应中的Content-Type常见的取值&#xff1a; 四、返回JSON 五、设置状态码 六、设置Header 1、设置Content…

2024李卜常识开天斧

2024年&#xff0c;李卜常识开天斧课程以其独特的魅力吸引了众多学子。这门课程如同开天辟地的神斧&#xff0c;帮助我们打开常识知识的大门&#xff0c;引领我们走进一个全新的学习世界。在李卜老师的悉心指导下&#xff0c;我们逐渐掌握了各种常识知识&#xff0c;拓宽了视野…

leaftjs+turfjs+idw纯前端实现等值面绘图+九段线

最近有个绘制等值面图的需求。我们一般的实现路径是&#xff1a; 1.后台绘图&#xff0c;用surfer绘制好&#xff0c;给前端调用叠加到地图。 2.后台用python绘图&#xff0c;绘制好给前端调用&#xff0c;叠加到地图。 3.后台进行插值计算、地图裁剪、最终生成geojson文件或…

VS2019配合QT5.9开发IRayAT430相机SDK

环境配置 VS2019 QT5.9 编译器版本 MSVC2017_64添加系统环境变量&#xff08;完毕后重启电脑&#xff09; 从VS2019中下载Qt插件 从VS2019中添加单个编译组件 上述操作完成后用VS打开工程文件&#xff0c;工程文件地址 &#xff1a; C:\Users\86173\Desktop\IRCNETSDK_W…

初识 Linux

一、基础命令 0、 ls cd cat pwd 当前工作目录 find -name 测试.py 查找文件 grep "学院" 测试.py 查找字符串 "学院" 在文件 测试.py 中位置&#xff0c;输出所在的 行 1、重定向器 echo "Hello Kali Linux!" > Hello 创建 文件 Hel…

openssl3.2 - exp - 使用默认的函数宏,在release版中也会引入__FILE__

文章目录 openssl3.2 - exp - 使用默认的函数宏&#xff0c;在release版中也会引入__FILE__概述笔记验证是否__FILE__在release版下也能用&#xff1f;将openssl编译成release版的&#xff0c;看看CRYPTO_free()是否只需要一个参数就行&#xff1f;将工程中的openssl相关的库换…

stream中的foreach,allMatch,noneMatch,anyMatch的基本使用

1.1foreach遍历集合元素 1.2anyMatch()的使用 结论:上边使用foreach循环遍历和使用anyMatch()的作用相同 2.allMatch() 2.1初级使用 2.2进级使用 3.noneMatch()使用

Python 实现视频去抖动技术

&#x1f47d;发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。【点击进入巨牛的人工智能学习网站】。 视频去抖动是视频处理中的一项重要技术&#xff0c;它可以有效地减少视频中由于相机震动或手…

华为matebook 14安装ubuntu双系统

一、准备u盘 首先格式化u盘(选择FAT32) 二、确认电脑类型 键盘按下win+r(win:开始键/也就是Windows的标志那个键),在输入框内输入msinfo32后,回车确认 确定自己电脑 硬盘 的类型: 在显示屏下方的搜索框内搜索“计算机管理” 点击进入后,再点击左边列表内的“磁…

拉普拉斯IPO:荣获国家级专精特新和国家级制造业单项冠军殊荣

近期&#xff0c;拉普拉斯荣获国家级专精特新和国家级制造业单项冠军的殊荣&#xff0c;这无疑是对其在技术和发展方面的肯定。这些荣誉证明了拉普拉斯在光伏行业的卓越表现和持续创新&#xff0c;以及其在国内制造业中的领先地位&#xff0c;进一步彰显了拉普拉斯在技术研发和…

智慧浪潮下的产业园区:洞察智慧化转型如何打造高效、绿色、安全的新园区

目录 一、引言 二、智慧化转型的内涵与价值 三、打造高效园区的智慧化策略 1、建设智能化基础设施 2、推广智能化应用 3、构建智慧化服务平台 四、实现绿色园区的智慧化途径 1、推动绿色能源应用 2、实施绿色建筑设计 3、加强环境监测与治理 五、保障园区安全的智慧…
最新文章