微服务生态 -- dubbo -- dubbo3应用级别服务发现(阅读官方文档)

news2024/11/18 14:25:16

服务发现概述

从 Internet 刚开始兴起,如何动态感知后端服务的地址变化就是一个必须要面对的问题,为此人们定义了 DNS 协议,基于此协议,调用方只需要记住由固定字符串组成的域名,就能轻松完成对后端服务的访问,而不用担心流量最终会访问到哪些机器 IP,因为有代理组件会基于 DNS 地址解析后的地址列表,将流量透明的、均匀的分发到不同的后端机器上。

在使用微服务构建复杂的分布式系统时,如何感知 backend 服务实例的动态上下线,也是微服务框架最需要关心并解决的问题之一。业界将这个问题称之为 - 微服务的地址发现(Service Discovery),业界比较有代表性的微服务框架如 SpringCloud、Dubbo 等都抽象了强大的动态地址发现能力,并且为了满足微服务业务场景的需求,绝大多数框架的地址发现都是基于自己设计的一套机制来实现,因此在能力、灵活性上都要比传统 DNS 丰富得多。如 SpringCloud 中常用的 Eureka, Dubbo 中常用的 Zookeeper、Nacos 等,这些注册中心实现不止能够传递地址(IP + Port),还包括一些微服务的 Metadata 信息,如实例序列化类型、实例方法列表、各个方法级的定制化配置等。

下图是微服务中 Service Discovery 的基本工作原理图,微服务体系中的实例大概可分为三种角色:服务提供者(Provider)、服务消费者(Consumer)和注册中心(Registry)。而不同框架实现间最主要的区别就体现在注册中心数据的组织:地址如何组织、以什么粒度组织、除地址外还同步哪些数据?

img1

dubbo地址发现机制解析

我们先以一个 DEMO 应用为例,来快速的看一下 Dubbo “接口粒度”服务发现与“应用粒度”服务发现体现出来的区别。这里我们重点关注 Provider 实例是如何向注册中心注册的,并且,为了体现注册中心数据量变化,我们观察的是两个 Provider 实例的场景。

应用 DEMO 提供的服务列表如下:

<dubbo:service interface="org.apache.dubbo.samples.basic.api.DemoService" ref="demoService"/>
<dubbo:service interface="org.apache.dubbo.samples.basic.api.GreetingService" ref="greetingService"/>

我们示例注册中心实现采用的是 Zookeeper ,启动 192.168.0.103 和 192.168.0.104 两个实例后,以下是两种模式下注册中心的实际数据

接口粒度服务发现

192.168.0.103 实例注册的数据

dubbo://192.168.0.103:20880/org.apache.dubbo.samples.basic.api.DemoService?anyhost=true&application=demo-provider&default=true&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.samples.basic.api.DemoService&methods=testVoid,sayHello&pid=995&release=2.7.7&side=provider&timestamp=1596988171266

dubbo://192.168.0.103:20880/org.apache.dubbo.samples.basic.api.GreetingService?anyhost=true&application=demo-provider&default=true&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.samples.basic.api.GreetingService&methods=greeting&pid=995&release=2.7.7&side=provider&timestamp=1596988170816

192.168.0.104 实例注册的数据

dubbo://192.168.0.104:20880/org.apache.dubbo.samples.basic.api.DemoService?anyhost=true&application=demo-provider&default=true&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.samples.basic.api.DemoService&methods=testVoid,sayHello&pid=995&release=2.7.7&side=provider&timestamp=1596988171266

dubbo://192.168.0.104:20880/org.apache.dubbo.samples.basic.api.GreetingService?anyhost=true&application=demo-provider&default=true&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.samples.basic.api.GreetingService&methods=greeting&pid=995&release=2.7.7&side=provider&timestamp=1596988170816

应用粒度服务发现

192.168.0.103 与 192.168.0.104 两个实例共享一份注册中心数据,如下:

{
	"name": "demo-provider",
	"id": "192.168.0.103:20880",
	"address": "192.168.0.103",
	"port": 20880,
  "metadata": {
    "dubbo.endpoints": "[{\"port\":20880,\"protocol\":\"dubbo\"}]",
    "dubbo.metadata.storage-type": "local",
    "dubbo.revision": "6785535733750099598"
  },
	"time": 1583461240877
}
{
	"name": "demo-provider",
	"id": "192.168.0.104:20880",
	"address": "192.168.0.104",
	"port": 20880,
  "metadata": {
    "dubbo.endpoints": "[{\"port\":20880,\"protocol\":\"dubbo\"}]",
    "dubbo.metadata.storage-type": "local",
    "dubbo.revision": "7829635812370099387"
  },
	"time": 1583461240877
}

对比以上两种不同粒度的服务发现模式,从 “接口粒度” 升级到 “应用粒度” 后我们可以总结出最大的区别是:注册中心数据量不再与接口数成正比,不论应用提供有多少接口,注册中心只有一条实例数据。

那么接下来我们详细看下这个变化给 Dubbo 带来了哪些好处。

dubbo应用级服务发现的意义

  1. 与业界主流微服务框架对齐,比如SpringCloud,Kubernetes Native Service等
  2. 提升性能与可伸缩性。注册中心数据的重新组织(减少),能最大幅度的减轻注册中心的存储、推送压力,进而减少 Dubbo Consumer 侧的地址计算压力;集群规模也开始变得可预测、可评估(与 RPC 接口数量无关,只与实例部署规模相关)。

对齐主流微服务模型

自动、透明的实例地址发现(负载均衡)是所有微服务框架需要解决的事情,这能让后端的部署结构对上游微服务透明,上游服务只需要从收到的地址列表中选取一个,发起调用就可以了。要实现以上目标,涉及两个关键点的自动同步:

  • 实例地址,服务消费方需要知道地址以建立连接
  • RPC 方法定义,服务消费方需要知道 RPC 服务的具体定义,不论服务类型是 rest 或 rmi 等。

概念介绍,dubbo中应用,服务和实例的概念区分:

应用是一个独立的逻辑单元,一个应用可以包含多个服务,每个服务可以包含多个实例。而实例是一个具体的服务实例,一个实例可以运行在一个独立的进程中,也可以运行在多个进程中。

应用和实例在Dubbo中有以下关系:

  1. 应用在Dubbo中是一个逻辑单元,可以包含多个服务。
  2. 每个服务可以有多个实例,每个实例都是一个具体的服务提供者或消费者。
  3. 在Dubbo的注册中心中,应用和实例都是一个注册节点,应用节点下面包含多个服务节点,服务节点下面包含多个实例节点。
  4. 应用和实例都可以配置相应的元数据信息,用于描述应用或实例的基本信息和特性,例如应用名称、实例IP地址、服务端口等。
  5. 在Dubbo的路由和负载均衡等功能中,应用和实例都可以作为选择的对象,根据实际情况进行选择和调度。

rest通信和rmi通信

两种通信协议的区别:

  1. 通信协议不同:REST通信基于HTTP协议,而RMI通信基于Java的RMI协议。
  2. 通信方式不同:REST通信是基于请求和响应的方式,客户端发送HTTP请求到服务器,服务器返回HTTP响应;而RMI通信是基于对象的方式,客户端通过RMI协议调用服务器上的Java对象。
  3. 应用场景不同:REST通信适用于Web应用程序的开发和通信,而RMI通信适用于Java平台上的分布式应用程序的开发和通信。
  4. 跨语言支持不同:REST通信支持多种语言,可以与其他语言的Web应用程序进行通信;而RMI通信只支持Java语言。

Spring Cloud

Spring Cloud 通过注册中心只同步了应用与实例地址,消费方可以基于实例地址与服务提供方建立连接,但是消费方对于如何发起 http 调用(SpringCloud 基于 rest 通信)一无所知,比如对方有哪些 http endpoint,需要传入哪些参数等。

RPC 服务这部分信息目前都是通过线下约定或离线的管理系统来协商的。这种架构的优缺点总结如下。 优势:部署结构清晰、地址推送量小; 缺点:地址订阅需要指定应用名, provider 应用变更(拆分)需消费端感知;RPC 调用无法全自动同步。

img3

dubbo

Dubbo 通过注册中心同时同步了实例地址和 RPC 方法,因此其能实现 RPC 过程的自动同步,面向 RPC 编程、面向 RPC 治理,对后端应用的拆分消费端无感知,其缺点则是地址推送数量变大,和 RPC 方法成正比。

img4

dubbo+Kubernetes

Dubbo 要支持 Kubernetes native service,相比之前自建注册中心的服务发现体系来说,在工作机制上主要有两点变化:

  • 服务注册由平台接管,provider不再需要关心服务注册
  • consumer端服务发现将是dubbo关注的重点,通过对接平台层的API-Server,DNS等,Dubbo client可以通过一个Service Name(通常对应到Application Name)查询到一组Endpoints(一组运行provider的pod),通过将Endpoints映射到Dubbo内部地址列表,以驱动Dubbo内置的负载均衡机制工作。

Kubernetes Service 作为一个抽象概念,怎么映射到 Dubbo 是一个值得讨论的点

  • Service Name - > Application Name,Dubbo 应用和 Kubernetes 服务一一对应,对于微服务运维和建设环节透明,与开发阶段解耦。
apiVersion: v1
kind: Service
metadata:
  name: provider-app-name
spec:
  selector:
    app: provider-app-name
  ports:
    - protocol: TCP
      port: 
      targetPort: 9376
  • Service Name - > Dubbo RPC Service,Kubernetes 要维护调度的服务与应用内建 RPC 服务绑定,维护的服务数量变多。
---
apiVersion: v1
kind: Service
metadata:
  name: rpc-service-1
spec:
  selector:
    app: provider-app-name
  ports: ##
...
---
apiVersion: v1
kind: Service
metadata:
  name: rpc-service-2
spec:
  selector:
    app: provider-app-name
  ports: ##
...
---
apiVersion: v1
kind: Service
metadata:
  name: rpc-service-N
spec:
  selector:
    app: provider-app-name
  ports: ##
...

img5

更大规模的微服务集群 - 解决性能瓶颈

这部分涉及到和注册中心、配置中心的交互,关于不同模型下注册中心数据的变化,之前原理部分我们简单分析过。为更直观的对比服务模型变更带来的推送效率提升,我们来通过一个示例看一下不同模型注册中心的对比:

img6

图中左边是微服务框架的一个典型工作流程,Provider 和 Consumer 通过注册中心实现自动化的地址通知。其中,Provider 实例的信息如图中表格所示: 应用 DEMO 包含三个接口 DemoService 1 2 3,当前实例的 ip 地址为 10.210.134.30。

  • 对于 Spring Cloud 和 Kubernetes 模型,注册中心只会存储一条 DEMO - 10.210.134.30+metadata 的数据;
  • 对于老的 Dubbo 模型,注册中心存储了三条接口粒度的数据,分别对应三个接口 DemoService 1 2 3,并且很多的址数据都是重复的;

可以总结出,基于应用粒度的模型所存储和推送的数据量是和应用、实例数成正比的,只有当我们的应用数增多或应用的实例数增长时,地址推送压力才会上涨。 而对于基于接口粒度的模型,数据量是和接口数量正相关的,鉴于一个应用通常发布多个接口的现状,这个数量级本身比应用粒度是要乘以倍数的;另外一个关键点在于,接口粒度导致的集群规模评估的不透明,相对于实例、应用增长都通常是在运维侧的规划之中,接口的定义更多的是业务侧的内部行为,往往可以绕过评估给集群带来压力。

以 Consumer 端服务订阅举例,根据我对社区部分 Dubbo 中大规模头部用户的粗略统计,根据受统计公司的实际场景,一个 Consumer 应用要消费(订阅)的 Provier 应用数量往往要超过 10 个,而具体到其要消费(订阅)的的接口数量则通常要达到 30 个,平均情况下 Consumer 订阅的 3 个接口来自同一个 Provider 应用,如此计算下来,如果以应用粒度为地址通知和选址基本单位,则平均地址推送和计算量将下降 60% 还要多, 而在极端情况下,也就是当 Consumer 端消费的接口更多的来自同一个应用时,这个地址推送与内存消耗的占用将会进一步得到降低,甚至可以超过 80% 以上。

一个典型的极端场景即是 Dubbo 体系中的网关型应用,有些网关应用消费(订阅)达 100+ 应用,而消费(订阅)的服务有 1000+ ,平均有 10 个接口来自同一个应用,如果我们把地址推送和计算的粒度改为应用,则地址推送量从原来的 n * 1000 变为 n * 100,地址数量降低可达近 90%。

应用级服务发现工作原理

设计原则

上面一节我们从服务模型支撑大规模集群的角度分别给出了 Dubbo 往应用级服务发现靠拢的好处和原因,但这么做的同时接口粒度的服务治理能力还是要继续保留,这是 Dubbo 框架编程模型易用性、服务治理能力优势的基础。 以下是我认为我们做服务模型迁移仍要坚持的设计原则

  • 新的服务发现模型要实现对原有 Dubbo 消费端开发者的无感知迁移,即 Dubbo 继续面向 RPC 服务编程、面向 RPC 服务治理,做到对用户侧完全无感知。

基本原理详解

应用级服务发现作为一种新的服务发现机制,和以前 Dubbo 基于 RPC 服务粒度的服务发现在核心流程上基本上是一致的:即服务提供者往注册中心注册地址信息,服务消费者从注册中心拉取&订阅地址信息。

这里主要的不同有以下两点:

注册中心数据以“应用 - 实例列表”格式组织,不再包含RPC服务信息

img7

以下是每个 Instance metadata 的示例数据,总的原则是 metadata 只包含当前 instance 节点相关的信息,不涉及 RPC 服务粒度的信息。

总体信息概括如下:实例地址、实例各种环境标、metadata service 元数据、其他少量必要属性。

{
	"name": "provider-app-name",
	"id": "192.168.0.102:20880",
	"address": "192.168.0.102",
	"port": 20880,
	"sslPort": null,
	"payload": {
		"id": null,
		"name": "provider-app-name",
		"metadata": {
			"metadataService": "{\"dubbo\":{\"version\":\"1.0.0\",\"dubbo\":\"2.0.2\",\"release\":\"2.7.5\",\"port\":\"20881\"}}",
			"endpoints": "[{\"port\":20880,\"protocol\":\"dubbo\"}]",
			"storage-type": "local",
			"revision": "6785535733750099598",
		}
	},
	"registrationTimeUTC": 1583461240877,
	"serviceType": "DYNAMIC",
	"uriSpec": null
}

Client-Server自行协商PRC方法信息

在注册中心不再同步 RPC 服务信息后,服务自省在服务消费端和提供端之间建立了一条内置的 RPC 服务信息协商机制,这也是“服务自省”这个名字的由来。服务端实例会暴露一个预定义的 MetadataService RPC 服务,消费端通过调用 MetadataService 获取每个实例 RPC 方法相关的配置信息。

img8

当前 MetadataService 返回的数据格式如下,

[
  "dubbo://192.168.0.102:20880/org.apache.dubbo.demo.DemoService?anyhost=true&application=demo-provider&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=9585&release=2.7.5&side=provider&timestamp=1583469714314", 
 "dubbo://192.168.0.102:20880/org.apache.dubbo.demo.HelloService?anyhost=true&application=demo-provider&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=9585&release=2.7.5&side=provider&timestamp=1583469714314",
  "dubbo://192.168.0.102:20880/org.apache.dubbo.demo.WorldService?anyhost=true&application=demo-provider&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=9585&release=2.7.5&side=provider&timestamp=1583469714314"
]

熟悉 Dubbo 基于 RPC 服务粒度的服务发现模型的开发者应该能看出来,服务自省机制机制将以前注册中心传递的 URL 一拆为二:

  • 一部分和实例相关的数据继续保留在注册中心,如 ip、port、机器标识等。
  • 另一部分和 RPC 方法相关的数据从注册中心移除,转而通过 MetadataService 暴露给消费端。

以下是服务自省的一个完整工作流程图,详细描述了服务注册、服务发现、MetadataService、RPC 调用间的协作流程。

img9

  • 服务提供者启动,首先解析应用定义的普通服务并依次注册为RPC服务,紧接着注册内建的MetadataService服务,最后打开TCP监听端口。
  • 启动完成后,将实例信息注册到注册中心(仅限ip,port等实例相关数据),提供者启动完成。
  • 服务消费者启动,首先依据其要的消费的provider应用名到注册中心查询地址列表,并完成订阅(以实现后续地址变更自动通知)。
  • 消费端拿到地址列表后,紧接着对 MetadataService 发起调用,返回结果中包含了所有应用定义的“普通服务”及其相关配置信息。
  • 至此,消费者可以接收外部流量,并对提供者发起 Dubbo RPC 调用

服务自省中的关键机制

元数据同步机制

Client 与 Server 间在收到地址推送后的配置同步是服务自省的关键环节,目前针对元数据同步有两种具体的可选方案,分别是:

  • 内建 MetadataService。
  • 独立的元数据中心,通过中心化的元数据集群协调数据。
  1. 内建 MetadataService MetadataService 通过标准的 Dubbo 协议暴露,根据查询条件,会将内存中符合条件的“普通服务”配置返回给消费者。这一步发生在消费端选址和调用前。
  2. 元数据中心 复用 2.7 版本中引入的元数据中心,provider 实例启动后,会尝试将内部的 RPC 服务组织成元数据的格式同步到元数据中心,而 consumer 则在每次收到注册中心推送更新后,主动查询元数据中心。

img10

RPC服务 <-> 应用映射关系

我们以往基于RPC服务来检索地址,现在consumer需要通过指定provider应用名才能实现地址查询或者订阅。

老的 Consumer 开发与配置示例:

<!-- 框架直接通过 RPC Service 1/2/N 去注册中心查询或订阅地址列表 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<dubbo:reference interface="RPC Service 1" />
<dubbo:reference interface="RPC Service 2" />
<dubbo:reference interface="RPC Service N" />

新的 Consumer 开发与配置示例:

<!-- 框架需要通过额外的 provided-by="provider-app-x" 才能在注册中心查询或订阅到地址列表 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181?registry-type=service"/>
<dubbo:reference interface="RPC Service 1" provided-by="provider-app-x"/>
<dubbo:reference interface="RPC Service 2" provided-by="provider-app-x" />
<dubbo:reference interface="RPC Service N" provided-by="provider-app-y" />

以上指定 provider 应用名的方式是 Spring Cloud 当前的做法,需要 consumer 端的开发者显示指定其要消费的 provider 应用。

以上问题的根源在于注册中心不知道任何 RPC 服务相关的信息,因此只能通过应用名来查询。

为了使整个开发流程对老的 Dubbo 用户更透明,同时避免指定 provider 对可扩展性带来的影响(参见下方说明),我们设计了一套 RPC 服务到应用名的映射关系,以尝试在 consumer 端自动完成 RPC 服务到 provider 应用名的转换。

img11

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

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

相关文章

236. 二叉树的最近公共祖先【190】

难度等级&#xff1a;中等 上一篇算法&#xff1a; 103. 二叉树的锯齿形层序遍历【191】 力扣此题地址&#xff1a; 236. 二叉树的最近公共祖先 - 力扣&#xff08;Leetcode&#xff09; 1.题目&#xff1a;236. 二叉树的最近公共祖先 给定一个二叉树, 找到该树中两个指定节点…

【MySQL】数据表的增删查改

1、CRUD的解释 C&#xff1a;Create增加 R&#xff1a;Retrieve查询 U&#xff1a;Update更新 D&#xff1a;Deleta删除 2、添加数据 2.1 添加一条记录 添加数据是对表进行添加数据的&#xff0c;表在数据库中&#xff0c;所以还是得先选中数据库&#xff0c;选中数据库还在进行…

STM32F429移植microPython笔记

目录 一、microPython下载。二、安装开发环境。三、编译开发板源码。四、下载验证。 一、microPython下载。 https://micropython.org/download/官网 下载后放在linux中。 解压命令&#xff1a; tar -xvf micropython-1.19.1.tar.xz 二、安装开发环境。 sudo apt-get inst…

MUSIC算法仿真

DOA波达方向估计 DOA&#xff08;Direction Of Arrival&#xff09;波达方向是指通过阵列信号处理来估计来波的方向&#xff0c;这里的信源可能是多个&#xff0c;角度也有多个。DOA技术主要有ARMA谱分析、最大似然法、熵谱分析法和特征分解法&#xff0c;特征分解法主要有MUS…

HTML+CSS+JS 学习笔记(四)———jQuery

&#x1f331;博客主页&#xff1a;大寄一场. &#x1f331;系列专栏&#xff1a;前端 &#x1f331;往期回顾&#xff1a; &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注​​ 目录 jQuery 基础 jQuery 概述 下载与配置jQuery 2. 配置jQuery jQuery 选…

数据库管理-第七十期 自己?自己(20230425)

数据库管理 2023-04-25 第七十期 自己&#xff1f;自己1 自己吓自己2 自己坑自己3 自己挺自己4 自己懵自己总结 第七十期 自己&#xff1f;自己 来到70了&#xff0c;最近有点卷&#xff0c;写的稍微多了些。 吐槽一下五一调休&#xff0c;周末砍一天&#xff0c;连6天&#x…

重学Java第一篇——数组

本片博客主要讲述了以下内容&#xff1a; 1、 一维数组和二维数组的创建和初始化方式&#xff1b; 2、数组的遍历和赋值 3、java.util.Arrays的常用方法 4、数组在内存中的分布&#xff08;图示&#xff09; 创建数组和初始化 type[] arr_name;//方式一 type arr_name[];//方式…

一家传统制造企业的上云之旅,怎样成为了数字化转型典范?

众所周知&#xff0c;中国是一个制造业大国。在想要上云以及正在上云的企业当中&#xff0c;传统制造企业也占据了相当大的比例。 那么这类企业在实施数字化转型的时候&#xff0c;应该如何着手&#xff1f;我们不妨来看看一家传统制造企业的现身说法。 国茂股份的数字化转型诉…

云原生-如何部署k8s集群与部署sms集群

阿里云开通三台云服务器实例&#xff0c;&#xff08;同一个vpc下&#xff09;&#xff0c;配置安全组入规则&#xff0c;加入80端口 ssh登录三台云服务器 在三台云服务器上部署容器环境&#xff08;安装docker&#xff09;&#xff08;https://www.yuque.com/leifengyang/oncl…

Springboot Mybatis使用pageHelper实现分页查询

以下介绍实战中数据库框架使用的是mybatis&#xff0c;对整合mybatis此处不做介绍。 使用pageHelper实现分页查询其实非常简单&#xff0c;共两步&#xff1a; 一、导入依赖&#xff1b; 二、添加配置&#xff1b; 那么开始&#xff0c; 第一步&#xff1a; pom.xml添加依…

工具链和其他-超级好用的web调试工具whistle

目录 whistle介绍 整体结构 能力 规则 6个使用场景示例 1.修改Host 2.代理 3.替换文件&#xff08;线上报错时&#xff09; 4.替换UA 5.远程调试 6.JS注入 互动 whistle介绍 整体结构 安装&#xff1a; npm install whistle -g cli&#xff1a;whistle help 启动…

前端系列第10集-实战篇

用户体验&#xff1a;性能&#xff0c;交互方式&#xff0c;骨架屏&#xff0c;反馈&#xff0c;需求分析等 组件库&#xff1a;通用表单&#xff0c;表格&#xff0c;弹窗&#xff0c;组件库设计&#xff0c;表单等 项目质量&#xff1a;单元测试&#xff0c;规范&#xff0c;…

mac十大必备软件排行榜 mac垃圾清理软件哪个好

刚拿到全新的mac电脑却不知道该怎么使用&#xff1f;首先应该装什么软件呢&#xff1f;如果你有同样的疑惑&#xff0c;今天这篇文章一定不要错过。接下来小编为大家介绍mac十大必备软件排行榜&#xff0c;以及mac垃圾清理软件哪个好。 一、mac十大必备软件排行榜 1.CleanMyM…

权限提升:AT || SC || PS 提权.(本地权限提升)

权限提升&#xff1a;AT || SC || PS 提权 权限提升简称提权&#xff0c;由于操作系统都是多用户操作系统&#xff0c;用户之间都有权限控制&#xff0c;比如通过 Web 漏洞拿到的是 Web 进程的权限&#xff0c;往往 Web 服务都是以一个权限很低的账号启动的&#xff0c;因此通…

电能计量管理系统在煤矿上的应用

摘要&#xff1a;随着煤矿供电系统管、控一体化的发展需要&#xff0c;本文提出了一种基于矿井光纤网络构成的煤矿电参数计量系统&#xff0c;该系统具有实现变电所各类开关、动力设备的用电高精度计量&#xff1b;远程实时监测各路电参数&#xff1b;远程抄表&#xff1b;远程…

Aspose.Pdf使用教程:在PDF文件中添加水印

Aspose.PDF 是一款高级PDF处理API&#xff0c;可以在跨平台应用程序中轻松生成&#xff0c;修改&#xff0c;转换&#xff0c;呈现&#xff0c;保护和打印文档。无需使用Adobe Acrobat。此外&#xff0c;API提供压缩选项&#xff0c;表创建和处理&#xff0c;图形和图像功能&am…

Windows环境下实现设计模式——模板方法模式(JAVA版)

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天总结一下Windows环境下如何编程实现模板方法模式&#xff08;设计模式&#xff09;。 不知道大家有没有这样的感觉&#xff0c;看了一大堆编程和设计模式的书&#xff0c;却还是很难理解设计模式&#x…

STM32驱动SG90舵机

STM32驱动SG90舵机 关于SG90舵机SG90转动角度与占空比的关系驱动SG90舵机代码①确定控制引脚②写代码 SG90舵机正常驱动现象总结 关于SG90舵机 SG90是一种小型伺服电机&#xff0c;通常用于模型制作和小型机械应用中: 问题答案SG90的工作电压是多少SG90的工作电压通常为3V至7.…

QT笔记——QtPropertyBrowser的使用

上一节&#xff0c;我们将了如何去配置QtPropertyBrowser 本节&#xff0c;我们将说明 如何 去 使用QtPropertyBrowser 这个属性类的一些基本知识 简单的几种用法&#xff1a; 首先&#xff1a; 我们需要创建一个Widget 提升一个类 为 QtTreePropertyBrowser .h文件 QtVariant…

git -团队开发 版本控制

文章目录 Git的概念Git的安装过程Git结构交互方式初始化本地仓库Git常用命令add和commit命令status命令log命令log命令2reset命令hard参数/mixed参数/soft参数 删除文件找回本地库删除的文件找回暂存区删除的文件 diff命令 分支操作分支冲突问题&#xff0c;如何解决冲突题 Git…