分布式之日志系统平台ELK

ELK解决了什么问题

我们开发完成后发布到线上的项目出现问题时(中小型公司),我们可能需要获取服务器中的日志文件进行定位分析问题。但在规模较大或者更加复杂的分布式场景下就显得力不从心。因此急需通过集中化的日志管理,将所有服务器上的日志进行收集汇总。所以ELK应运而生,它通过一系列开源框架提供了一整套解决方案,将所有节点上的日志统一收集、存储、分析、可视化等。

  • 注意:ELK不仅仅适用于日志分析,它还可以支持其它任何数据分析(比如我们之前项目开发中通过ES实现了用户在不同周期内访问系统的活跃度)和收集的场景,日志分析和收集只是更具有代表性而并非唯一性

概念

ELK是Elasticsearch(存储、检索数据)、Logstash(收集、转换、筛选数据)、Kibana(可视化数据) 三大开源框架的首字母大写简称,目前通常也被称为Elastic Stack(在 ELK的基础上增加了 Beats)

单机版的日志系统架构

Elasticsearch(ES,Port:9200)

  • 开源分布式搜索引擎,提供搜集、分析、存储数据功能
  • ES是面向文档document存储,它可以存储整个对象或文档(document)。同时也可以对文档进行索引、搜索、排序、过滤。这种理解数据的方式与传统的关系型数据库完全不同,因此这也是ES能够执行复杂的全文搜索的原因之一,document可以类比为RDMS中的行
  • ES使用JSON作为文档序列化格式,统一将document数据转换为json格式进行存储,JSON已经成为NoSQL领域的标准格式
  • ES是基于Lucene实现的全文检索,底层是基于倒排的索引方法,用来存储在全文检索下某个单词在一个/组文档中的存储位置[倒排索引是ES具有高检索性能的本质原因]
  • ES-head插件(Port:9100)

    • 查看我们导入的数据是否正常生成索引
    • 数据删除操作

    • 数据浏览

  • Index: Index是文档的容器,在ES的早期版本中的index(类似于RDMS中的库)中还包含有type(类似于RDMS中的表)的概念。但在后续版本中,type被逐渐取消而index同时具有数据库和表的概念

  • 查询DSL: 使用JSON格式并基于RESTful API进行通信,提供了全文搜索、范围查询、布尔查询、聚合查询等不同的搜索需求

Logstash(Port:5044)

  • ELK的数据流引擎,从不同目标(文件/数据存储/MQ)收集的不同格式数据,经过滤后输出到ES
  • Filebeat是一个轻量级的日志收集处理工具(Agent),占用资源少,可在各服务器上搜集信息后传输给Logastash(官方推荐)

Kibana(Port:5601)

  • 分析和可视化数据:利用工具分析 es中的数据,编制图表仪表板,利用仪表、地图和其他可视化显示发现的内容
  • 搜索、观察和保护数据:向应用和网站添加搜索框,分析日志和指标,并发现安全漏洞
  • 管理、监控和保护 Elastic Stack:监控和管理 es集群、kibana等 elastic stack的运行状况,并控制用户访问特征和数据
  • 常用核心功能
    • Discover: 浏览ES索引中的数据,还可以添加筛选条件进而查看感兴趣的数据
Discover
    • Dev_Tool: 用ES支持的语法编写查询条件查询,也可用于测试代码中的查询条件
用于运维/开发查询
    • 管理:索引管理和索引模式
      •  索引管理:查看索引的运行状况、状态、主分片和副本分片等信息
      • 索引模式:用于匹配命名符合一定规律的单个或多个索引,便于在 discover界面查看和分析目标索引的数据
    • Monitoring: 查看ES集群版本、运行时间、节点状态情况和索引情况
实际项目开发中单节点部署的ES/Kibana信息
    • 可视化: 根据需求可创建条形图、饼图、云图(词云图)进行个性化定制

项目实战

在公司项目实际开发中我们基于logback -> rabbitmq -> elk 工作模式进行日志收集,实现了日志的集中管理。在此基础上通过ES搜索建立系统可视化看板来显示用户在不同周期内访问系统的活跃度

注意:logback是日志框架(log4j也是一种日志框架),而slf4j是日志门面接口

具体相关核心实现流程

  1. Maven导入Logback、ElasticSearch依赖
    <dependency>
    	<groupId>net.logstash.logback</groupId>
    	<artifactId>logstash-logback-encoder</artifactId>
    	<version>5.1</version>
    </dependency>
    <dependency>
    	<groupId>net.logstash.log4j</groupId>
    	<artifactId>jsonevent-layout</artifactId>
    	<version>1.7</version>
    </dependency>
    
    <dependency>
    	<groupId>org.elasticsearch</groupId>
    	<artifactId>elasticsearch</artifactId>
    	<version>6.3.1</version>
    </dependency>
    <dependency>
    	<groupId>org.elasticsearch.client</groupId>
    	<artifactId>transport</artifactId>
    	<version>6.3.1</version>
    </dependency>
    <dependency>
    	<groupId>org.elasticsearch.plugin</groupId>
    	<artifactId>transport-netty4-client</artifactId>
    	<version>6.3.1</version>
    </dependency>
  2. 定义logback-prod.xml配置文件
    # 首先需要在application.yml文件配置log日志相关属性配置
    logging:
      config: classpath:logback-prod.xml #配置logback文件,本地开发不需要配置
      file: logs/${logback.log.file} #存储日志的文件
    
    #我们logback采用Rabbitmq方式收集日志时消息服务配置信息
    logback:
      log:
        path: "./logs/"
        file: logback_amqp.log
      amqp:
        host: 10.225.225.225
        port: 5672
        username: admin
        password: admin
    <?xml version="1.0" encoding="UTF-8"?>
    <configuration  scan="true" scanPeriod="60 seconds" debug="false">
    	<include resource="org/springframework/boot/logging/logback/base.xml" />
    	<contextName>logback</contextName>
    	<!-- 日志输出路径: source对应的值取自application.yml文件-->
    	<springProperty scope="context"  name="log.path" source="logback.log.path" />
    	<springProperty scope="context"  name="log.file" source="logback.log.file" />
    	<springProperty scope="context" name="logback.amqp.host" source="logback.amqp.host"/>
    	<springProperty scope="context" name="logback.amqp.port" source="logback.amqp.port"/>
    	<springProperty scope="context" name="logback.amqp.username" source="logback.amqp.username"/>
    	<springProperty scope="context" name="logback.amqp.password" source="logback.amqp.password"/>
    	
    	<!-- 输出到logstash的appender-->
    	<appender name="stash-amqp" class="org.springframework.amqp.rabbit.logback.AmqpAppender"> 
    		<!--日志收集模式:logback -> rabbitmq -> elk 工作模式,因此我们需要使用net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder实现-->
    		<encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
    			<providers>
    		    	<pattern>
    		    		<!-- 其中"application": "application"中的值必须为小写,否则elk创建index报错(elk创建index基本规则为:字母必须都为小写) -->
    			 		<pattern>
    			        {
    						"time": "%date{ISO8601}", 
    						"thread": "%thread", 
    						"level": "%level", 
    						"class": "%logger{60}", 
    						"message": "%message", 
    						"application": "application" 
    					}
    			      	</pattern>
    		    	</pattern>
    		  	</providers>
    		</encoder>
    		<host>${logback.amqp.host}</host> 
    		<port>${logback.amqp.port}</port> 
    		<username>${logback.amqp.username}</username> 
    		<password>${logback.amqp.password}</password>
    		<declareExchange>true</declareExchange> 
    		<exchangeType>fanout</exchangeType> 
    		<exchangeName>ex_common_application_Log</exchangeName> <!-- 需在rabbitmq页面手动配置交换机与队列-->
    		<generateId>true</generateId> 
    		<charset>UTF-8</charset> 
    		<durable>true</durable> 
    		<deliveryMode>PERSISTENT</deliveryMode> 
    	</appender> 
    	<!--输出到控制台-->
    	<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
    	    <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
    	    	<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
    	        <pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
    	    </encoder>
        </appender>
        <!--输出到文件-->
        <!-- 按照每天生成日志文件 -->
        <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
       		<file>${log.path}/${log.file}</file>
       		<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
       			<!--日志文件输出的文件名,如果文件名为.zip结尾,则归档时支持自动压缩-->
       			<fileNamePattern>${log.path}/%d{yyyy/MM}/${log.file}.%i.zip</fileNamePattern>
       			<!--日志文件保留天数-->
       			<MaxHistory>30</MaxHistory>
       			<!-- 最多存储5GB日志 -->
       			<totalSizeCap>5GB</totalSizeCap>
       			<!-- 每个文件最大500MB -->
       			<maxFileSize>300MB</maxFileSize>
       		</rollingPolicy>
       		<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
       			<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
       			<pattern>%d{HH:mm:ss.SSS} %contextName [%thread] %-5level %logger{36} - %msg%n</pattern>
       		</encoder>
       	</appender>
       	<!-- 总开关 -->
       	<!-- 日志输出级别 -->
        <root level="info">
            <!-- <appender-ref ref="console" /> -->
            <appender-ref ref="file" />
            <appender-ref ref="stash-amqp" />
        </root>
    </configuration>
  3. SpringBoot集成Elasticsearch
    # 所属应用的yml文件配置elasticsearch信息
    elasticsearch:
      protocol: http
      hostList: 10.225.225.225:9200 # elasticsearch集群-单节点
      connectTimeout: 5000
      socketTimeout: 5000
      connectionRequestTimeout: 5000
      maxConnectNum: 10
      maxConnectPerRoute: 10
      username:    # 帐号为空
      password:    # 密码为空

    Elasticsearch配置类

    package com.bierce;
    
    import java.io.IOException;
    import java.util.concurrent.TimeUnit;
    import org.apache.commons.lang3.StringUtils;
    import org.apache.http.HttpHost;
    import org.apache.http.auth.AuthScope;
    import org.apache.http.auth.UsernamePasswordCredentials;
    import org.apache.http.client.CredentialsProvider;
    import org.apache.http.client.config.RequestConfig.Builder;
    import org.apache.http.impl.client.BasicCredentialsProvider;
    import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
    import org.elasticsearch.client.RestClient;
    import org.elasticsearch.client.RestClientBuilder;
    import org.elasticsearch.client.RestClientBuilder.HttpClientConfigCallback;
    import org.elasticsearch.client.RestHighLevelClient;
    import org.elasticsearch.client.sniff.ElasticsearchHostsSniffer;
    import org.elasticsearch.client.sniff.HostsSniffer;
    import org.elasticsearch.client.sniff.SniffOnFailureListener;
    import org.elasticsearch.client.sniff.Sniffer;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    /**
     * 
     * @ClassName: ElasticSearchConfiguration
     * @Description: ES配置类
     */
    @Configuration
    public class ElasticSearchConfiguration {
    
        @Value("${elasticsearch.protocol}") // 基于Http协议
        private String protocol;
        @Value("${elasticsearch.hostlist}") // 集群地址,如果有多个用“,”隔开
        private String hostList;
        @Value("${elasticsearch.connectTimeout}") // 连接超时时间
        private int connectTimeout;
        @Value("${elasticsearch.socketTimeout}") // Socket 连接超时时间
        private int socketTimeout;
        @Value("${elasticsearch.connectionRequestTimeout}") // 获取请求连接的超时时间
        private int connectionRequestTimeout;
        @Value("${elasticsearch.maxConnectNum}") // 最大连接数
        private int maxConnectNum;
        @Value("${elasticsearch.maxConnectPerRoute}") // 最大路由连接数
        private int maxConnectPerRoute;
        @Value("${elasticsearch.username:}")
        private String username;
         @Value("${elasticsearch.password:}")
        private String password;
        
    	// 配置restHighLevelClient,
    	// 当Spring容器关闭时,应该调用RestHighLevelClient类的close方法来执行清理工作
        @Bean(destroyMethod="close")
    	public RestHighLevelClient restHighLevelClient() { 
        	
        	String[] split = hostList.split(",");
    		HttpHost[] httphostArray = new HttpHost[split.length];
    		SniffOnFailureListener sniffOnFailureListener = new SniffOnFailureListener();
    		
    		//获取集群地址进行ip和端口后放入数组
    		for(int i=0; i<split.length; i++) {
    			String hostName = split[i];
    			httphostArray[i] = new HttpHost(hostName.split(":")[0], Integer.parseInt(hostName.split(":")[1]), protocol);
    		}
    		
    		// 构建连接对象
    		// 为RestClient 实例设置故障监听器
            RestClientBuilder builder = RestClient.builder(httphostArray).setFailureListener(sniffOnFailureListener);
    		// 异步连接延时配置
            builder.setRequestConfigCallback(new RestClientBuilder.RequestConfigCallback() {
            	@Override
    			public Builder customizeRequestConfig(Builder requestConfigBuilder) {
    				requestConfigBuilder.setConnectTimeout(connectTimeout);
    	        	requestConfigBuilder.setSocketTimeout(socketTimeout);
    	        	requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeout);
    	        	return requestConfigBuilder;
    			}
            });
            // 连接认证
            CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
            if( StringUtils.isNotBlank( username ) && StringUtils.isNotBlank(password )) {
            	credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(username, password));
            }
            // 异步连接数配置
            builder.setHttpClientConfigCallback(new HttpClientConfigCallback() {
    			@Override
    			public HttpAsyncClientBuilder customizeHttpClient(HttpAsyncClientBuilder httpClientBuilder) {
    				httpClientBuilder.setMaxConnTotal(maxConnectNum);
    				httpClientBuilder.setMaxConnPerRoute(maxConnectPerRoute);
    				// 设置帐号密码
    				if(credentialsProvider != null 
    						&& StringUtils.isNotBlank( username ) && StringUtils.isNotBlank(password )) {
    					httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
    				}
    				return httpClientBuilder;
    			}
            });
            
            
            RestHighLevelClient restHighLevelClient = new RestHighLevelClient(builder);
            RestClient restClient = restHighLevelClient.getLowLevelClient();
            
            HostsSniffer hostsSniffer = new ElasticsearchHostsSniffer(restClient,
                    ElasticsearchHostsSniffer.DEFAULT_SNIFF_REQUEST_TIMEOUT,
                    ElasticsearchHostsSniffer.Scheme.HTTP);
            try {
            	/* 故障后嗅探,不仅意味着每次故障后会更新节点,也会添加普通计划外的嗅探行为,
                 * 默认情况是故障之后1分钟后,假设节点将恢复正常,那么我们希望尽可能快的获知。
                 * 如上所述,周期可以通过 `setSniffAfterFailureDelayMillis` 
                 * 方法在创建 Sniffer 实例时进行自定义设置。需要注意的是,当没有启用故障监听时,
                 * 这最后一个配置参数不会生效 
                 */
                Sniffer sniffer = Sniffer.builder(restClient)
                		.setSniffAfterFailureDelayMillis(30000)
                		.setHostsSniffer(hostsSniffer)
                		.build();
                // 将嗅探器关联到嗅探故障监听器上
                sniffOnFailureListener.setSniffer(sniffer); 
    			sniffer.close();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
            return restHighLevelClient;
        } 
    }
    
  4. 通过ES提供的API搜索相关数据
    package com.bierce;
    
    /**
     * 
     * @ClassName: UserVisitInfo
     * @Description: 用戶访问系统相关信息类
     *
     */
    public class UserVisitInfo {
    	private String dayOfWeek; // 星期几
    	private Long docCount; //访问次数
    
    	public UserVisitInfo() {
    	}
    	public UserVisitInfo(String dayOfWeek, Long docCount) {
    		super();
    		this.dayOfWeek = dayOfWeek;
    		this.docCount = docCount;
    	}
    	public String getDayOfWeek() {
    		return dayOfWeek;
    	}
    	public void setDayOfWeek(String dayOfWeek) {
    		this.dayOfWeek = dayOfWeek;
    	}
    	public Long getDocCount() {
    		return docCount;
    	}
    	public void setDocCount(Long docCount) {
    		this.docCount = docCount;
    	}
    	@Override
    	public String toString() {
    		return "UserVisitInfo [dayOfWeek=" + dayOfWeek + ", docCount=" + docCount + "]";
    	}
    }
    package com.bierce;
    
    import java.util.ArrayList;
    import java.util.List;
    import com.bierce.UserVisitInfo;
    import org.elasticsearch.action.search.SearchResponse;
    import org.elasticsearch.client.RestHighLevelClient;
    import org.elasticsearch.index.query.QueryBuilder;
    import org.elasticsearch.index.query.QueryBuilders;
    import org.elasticsearch.script.Script;
    import org.elasticsearch.search.aggregations.AggregationBuilders;
    import org.elasticsearch.search.aggregations.Aggregations;
    import org.elasticsearch.search.aggregations.bucket.histogram.Histogram;
    import org.elasticsearch.search.aggregations.bucket.histogram.HistogramAggregationBuilder;
    import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
    import org.elasticsearch.search.builder.SearchSourceBuilder;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    /**
     * 
     * @ClassName: VisitUserCountSearchTemplate
     * @Description: 获取用户不同周期内活跃度
     *
     */
    @Service
    public class VisitUserCountSearchTemplate {
    
    	private static final String INDEX_PREFIX = "user-visit-";
    	
    	@Autowired
    	private RestHighLevelClient restHighLevelClient;
    	
    	/**
    	 * 
    	 * @Title: getUserActivityInfo
    	 * @Description: 获取用户访问系统活跃度
    	 * @param startDate
    	 * @param endDate
    	 * @return
    	 */
    	public List<UserVisitInfo> getUserActivityInfo(String startDate, String endDate) {
    		
    		SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
    		searchSourceBuilder.size(0);
    		searchSourceBuilder.query(QueryBuilders.matchAllQuery());
    		
    		// 设置聚合查询相关參數
    		String aggregationName = "timeslice";
    		String rangeField = "@timestamp";
    		String termField = "keyword";
    		Script script = new Script("doc['@timestamp'].value.dayOfWeek");
    		String[] igonredAppCode = {"AMQP", "Test"}; 
    		
    		QueryBuilder timeQueryBuilder = QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery(rangeField).gte(startDate).lte(endDate))
    																.mustNot(QueryBuilders.termsQuery(termField, igonredAppCode))
    																.filter(QueryBuilders.existsQuery(termField));
    		
    		// 按照星期几搜索对应数据
    		HistogramAggregationBuilder dayOfWeekAggregationBuilder = AggregationBuilders.histogram(aggregationName).script(script).interval(1).extendedBounds(1, 7);
    		
    		searchSourceBuilder.query(timeQueryBuilder);
    		searchSourceBuilder.aggregation(dayOfWeekAggregationBuilder);		
    																					
    		SearchResponse searchResponse = ElasticsearchUtils.buildSearchSource(INDEX_PREFIX + "*", searchSourceBuilder, client);																		
    																					
    		List<UserVisitInfo> userActivityInfoList = new ArrayList<>();
    		Aggregations aggregations = searchResponse.getAggregations();
    		Histogram dayOfWeekHistogram = aggregations.get(aggregationName);
    		List<? extends Histogram.Bucket> buckets = dayOfWeekHistogram.getBuckets();
    		
    		for(Histogram.Bucket bucket: buckets) {
    			String dayOfWeek = bucket.getKeyAsString();
    			long docCount = bucket.getDocCount();
    			UserVisitInfo item = new UserVisitInfo(dayOfWeek, docCount);
    			userActivityInfoList.add(item);
    		}
    		
    		return userActivityInfoList;
    	}
    }
    
  5. 将数据返回给前台进行页面渲染,最终实现的效果
可按条件筛选显示用户在不同周期内访问系统的活跃度

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

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

相关文章

【C/C++】【学生成绩管理系统】深度剖析

可接各类C/C管理系统课设 目录 实现功能 部分1&#xff1a;系统设置和主菜单 1. 引入头文件 2. 定义结构体 3. 函数声明 4. 主函数 部分2&#xff1a;添加学生信息 部分3&#xff1a;删除学生信息 部分4&#xff1a;修改学生信息 部分5&#xff1a;查询学生信息 部分…

MySQL实现排名

数据准备 Create table If Not Exists Scores (id int, score DECIMAL(3,2)) Truncate table Scores insert into Scores (id, score) values (1, 3) insert into Scores (id, score) values (2, 3) insert into Scores (id, score) values (3, 4.0) insert into Scores (id, …

虾皮平台API:获取商品买家评论数据

一、接口核心功能 在电商领域&#xff0c;买家评论对于商品的销售和商家的口碑至关重要。虾皮作为东南亚地区知名的电商平台&#xff0c;为商家提供了丰富的商品买家评论数据。为了方便商家获取这些数据&#xff0c;我们的API接口服务其核心功能就是获取商品买家评论数据信息。…

使用pip2pi和nginx搭建私有pip镜像源方法

在内网环境下部署python开发环境&#xff0c;安装python第三方库比较麻烦&#xff0c;特别是安装需要多个依赖的库。一种比较好的解决方案是搭建一个本地的私有pip镜像源&#xff0c;有多个方案可以选择&#xff0c;比如pypiserver、pip2pi等&#xff0c;本文介绍使用python的p…

vue3轮播图怎么做

先看效果 实现代码 <n-carouseleffect"card"dot-type"line"draggable:autoplay"!isHovered":current-index"currentIndex"prev-slide-style"transform: translateX(-150%) translateZ(-450px);opacity:1"next-slide-st…

第零篇——数学到底应该怎么学?

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 宏观讲解数学定位&#xff0c;数学学习方式方法&#xff0c;再次详细学习…

Spring学习笔记(九)简单的SSM框架整合

实验目的 掌握SSM框架整合。 实验环境 硬件&#xff1a;PC机 操作系统&#xff1a;Windows 开发工具&#xff1a;idea 实验内容 整合SSM框架。 实验步骤 搭建SSM环境&#xff1a;构建web项目&#xff0c;导入需要的jar包&#xff0c;通过单元测试测试各层框架搭建的正确…

Rewrite the Stars

文章目录 摘要1、引言2、相关工作3、重写星操作3.1、单层中的星操作3.2、扩展到多层3.3、特殊情况3.4、实证研究3.4.1、星操作的实证优越性3.4.2、决策边界对比3.4.3、扩展到无激活函数的网络 3.5、开放讨论与更广泛的影响 4、概念验证&#xff1a;StarNet4.1、StarNet架构4.2、…

用于云医疗图像的缩略图保持加密方案

论文标题&#xff1a;《Data hiding with thumbnail-preserving encryption for cloud medical images》&#xff0c;作者提出了一种用于云医疗图像的可逆数据隐藏方案&#xff0c;同时保留了缩略图。下面是论文的创新点和算法过程的总结。 一、缩略图保持加密与传统图像加密 …

PCL 计算点云的形心

目录 一、形心二、代码实现三、结果展示本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、形心 面的形心就是截面图形的几何中心,质心是针对实物体而言的,而形心是针对抽象几何体而言的,对于密度均匀的实物体,…

Axios基础用法

目录 Axios简介&#xff1f; json-server 下载json-server 创建模拟数据json文件 运行json-server ​编辑​编辑 安装Axios Axios基础用法 创建Vue项目 get请求 post请求 put请求 delete请求 并发请求 总结 Axios简介&#xff1f; Axios是一个基于Promise的HTTP库&#xf…

存储器的性能指标以及层次化存储器

存储器的性能指标 存储器有三个性能指标&#xff1a;速度、容量和位价&#xff08;每位价格&#xff09; 1.存储速度 &#xff08;1&#xff09;存取时间 想衡量存储速度&#xff0c;最直观的指标就是完成一次存储器读写操作所需要的时间&#xff0c;这叫做存取时间&#x…

nginx+tomcat+nfs →web集群部署

nginxtomcatnfs →web集群部署 一.安装前介绍 NGINX是一个高性能的Web服务器和反向代理服务器。它能够处理静态内容&#xff0c;缓存请求结果&#xff0c;以及将请求转发给后端服务器。通过反向代理&#xff0c;NGINX能够实现请求的负载均衡、安全性增强、SSL加密等功能。此外…

RabbitMQ实践——利用随机交换器做负载均衡

大纲 启用Random Exchange创建Exchange绑定队列测试 在《RabbitMQ实践——利用一致性Hash交换器做负载均衡》中&#xff0c;我们使用了Consistent Hash Exchange实践了消息路由的负载均衡。本文我们将使用一种更简单的交换器来实现该功能&#xff0c;这就是“随机交换器”&…

Linux初识地址空间

前言 上一期我们对进程优先级、命令行参数以及环境和变量做了介绍&#xff01;以前我们就提到过一个问题有了运行队列为什么还要有优先级&#xff1f;本期将带你揭晓&#xff01; 本期内容介绍 虚拟地址空间的引入 虚拟地址空间的介绍 如何理解地址空间 为什么要有地址空间 如…

3DMAX卷曲修改器Roller插件使用方法详解

3DMAX卷曲修改器Roller插件使用教程 3DMAX卷曲修改器Roller&#xff0c;用于创建卷曲形状建模&#xff0c;并可生成卷曲和展开动画。使创建诸如卷起和打开毯子、旗帜这样的动画变得非常简单。 【适用版本】 适用于3ds Max 2012及更高版本 【安装方法】 3DMAX卷曲修改器Roller…

QT

#include "widget.h" #include "ui_widget.h" Widget::Widget(QWidget *parent) : QWidget(parent) , ui(new Ui::Widget) ,Gcancle(new QPushButton("取消",this)) ,EmmEdit(new QLineEdit(this)) { ui->setupUi(this);…

UDS——诊断三要素

文章目录 诊断三要素一、请求1.1 带子功能的服务1.2 不带子功能的服务二、正响应(肯定响应)2.1 带子功能诊断请求的肯定响应格式2.2 不带子功能诊断请求的肯定响应格式三、负响应(否定响应)否定响应码诊断三要素 诊断主要包含请求、肯定响应和否定响应三个要素 “请求”由…

浙大版PTA Python程序设计 题目与知识点整理(综合版)

目录 第一章 一、高级语言程序的执行方式 二、变量赋值与内存地址 三、字符编码 3.1 Unicode 3.2 ASCII&#xff08;American Standard Code for Information Interchange&#xff09; 四、编程语言分类按照编程范式分类 4.1 面向过程语言 4.2 面向对象语言 五、原码…

【LeetCode最详尽解答】42-接雨水 Trapping-Rain-Water

欢迎收藏Star我的Machine Learning Blog:https://github.com/purepisces/Wenqing-Machine_Learning_Blog。如果收藏star, 有问题可以随时与我交流, 谢谢大家&#xff01; 链接: 42-接雨水 直觉 通过可视化图形来解决这个问题会更容易理解和解决。 给定输入: height [0,1,…