微服务 - Consul集群化 · 服务注册 · 健康检测 · 服务发现 · 负载均衡

news2024/11/16 7:46:53

一、Consul 概括

Consul 是由N多个节点(台机/虚机/容器)组成,每个节点中都有 Agent 运行着,各节点间用RPC通信,所有节点内相同的 Datacenter 名称为一个数据中心,节点又分三种角色 Client/Server/Leader:

  • Agent:Consul 各成员节点的运行载体
  • Client:不是必须存在的角色,数量也无上限,少量的资源开销,建议更多的 Client 角色存在。
  • Server:必须的Server角色,每个Server下可多个Client,可以代替Client,对接收到的信息持久化;资源开销大,官方建议3/5台。
  • Leader:一个数据中心内的 Server 选举产生一个 Leader 角色,将信息下发广播给所有 Server

默认端口

  • 8500:Consul 对外提供注册查询UI等的专用端口
  • 830x:Consul 内各节点间TCP/RPC等通信的专用端口
  • 8600:Consul DNS 使用
  • 21xxx:Consul 自动分配代理使用

整体架构示意图

Consul 架构运行示意图

图解:任意的 应用服务 Join 到任意的 Consul Node;任意的 Client Join 到任意的 Server;Node之间数据共享。

Consul 中的服务 与 注册的应用服务

Consul Node Server:是组成 Consul 整体运行的不可缺少的一种节点角色,注册于 Consul Catalog 中,不如后续叫<节点服务>
Agent Register Service:是被 Consul 管理、发现、健康检测的目标业务应用,注册于 Consul Agent 中,不如后续叫<应用服务>

二、Consul 功能

服务注册

所有的应用服务,都向 Consul 报告自己的存在及具体的信息;

新应用服务的加入,通过Client/Server上报给上级,直至Leader;Leader再向所有Server广播新服务的存在及具体信息,Consul 中所有节点共享新加入服务的信息;其中包括应用服务本身的连接及健康检测信息。

任何注销的应用服务,Consul 也会同步到各节点,关联的健康检测一并注销。

健康检测

Consul向各应用服务发起的连接过程,为了提供所有健康可用的应用服务,按提供的检测方式、检测地址、检测频率等,发起通信检测,识别服务状态,踢除异常及不可用的实例,保留健康可用的实例,并把结果上报给 Consul-Server/Leader。

检测方式分为:script / http / tcp / udp / ttl / rpc 等

比如:脚本在各服务上的运行反馈

比如:各服务提供HTTP请求的API

比如:各服务提供TCP连接的端口

服务发现

在集群内外,任何想要连接集群内应用服务的信息,先通过 Consul-Server 拉取到健康可用的应用服务信息,才能连接到指定的应用服务;

新应用服务不断的注册/宕机/注销等,每个时间段所提供的各应用服务信息都可能是变化的;

这种 Consul-Server 时时检测网络上的服务, 并提供健康可用的应用服务列表的过程,就叫做服务发现。

比如:Nginx需要时时知道[订单服务]的访问IP端口信息,才好转发请求

比如:[订单服务]需要请求[产品服务]API,Consul提供了所有健康的[产品服务]访问IP端口信息,[订单服务]才能请求到[产品服务]API

按[订单]服务查询出健康可用的应用服务列表,屏蔽了异常状况的应用服务,达到了 故障转移 的效果。

K/V存储

动态的、可维护的、持久化的、键值对的存储方式;比较独立的一项Consul功能,我们可以把需要动态的内容放入KV中存储,它就像库一样,随时可变更查询。

key 唯一键;value 对应值;flags 64位整数可选值

GET 查询/列表

# 命令行 查询全部
consul kv get -recurse
# 命令行 查询单个[列表]
consul kv get [-detailed] {key}
# API 查询全部
curl http://{host}:8500/v1/kv/?recurse
# API 查询单个
curl http://{host}:8500/v1/kv/{key}

PUT 新增/修改

# 命令行 新增/修改
consul kv put [-flags=13] {key} {value}
# API 新增/修改
curl -X PUT -d '{value}' http://{host}:8500/v1/kv/{key}[?flag=13]

DELETE 删除/全部

# 命令行 删除一个
consul kv delete {key}
# 命令行 删除列表(全部)
consul kv delete -recurse [key/prefix]
# API 删除列表(全部)
curl -X DELETE http://{host}:8500/v1/kv/{key/prefix}[?recurse]

更多相关API参考:KV Store - HTTP API | Consul | HashiCorp Developer

Datacenter

数据中心算是一个概念吧。。。

以上几点内容大致体现了 Consul 的运作方式,综合起来也就是一个范围集群的说法,其中会按 Datacenter 名称的不同,区分为多个数据中心。比如在不同的地域提供不同的数据中心,或者相同的数据中心互通,以做候选备用等。

三、集群相关

负载均衡

在集群中,每种应用服务都可能不止一个运行实例,订单服务A调用产品服务B,通过ConsulAPI给出的产品服务B可用地址会是多个,同样都是产品服务,有的资源已用90%,有的资源才用10%,为了避免这种资源利用不均匀,如何做到负载均衡呢?

常用方式:随机、轮询、最小连接、权重 等。

  • 随机方式:实现起来比较简单,在拉取到的应用服务数据列表中,随意挑一个使用就好
  • 轮询方式:需要有个全局变量,记录当前已用到哪个地址了,下标+1的方式取列表中下个健康的地址
  • 最小连接:记录每个应用服务实例当前已产生多少连接,每次使用最小已连接的实例做为本次的连接
  • 权重方式:配置应用服务实例在整体服务中所占的使用比例上限,每次连接后计算更新已连接的占比

当然,Consul未提供此功能,或用第三方或自己编写实现;

比如:写一个负载均衡的类库,每个服务已连接次数记录在 Consul 的 KV 中,调用方给出要调用的服务组名,使用类库得出本次要请求的具体服务地址等。

熔断降级

Consul 并没有提供这样的功能,作为集群中不可忽视的点,这里只有粗略叙述,以作了解。

熔断:存在于请求方与应用服务之间,当应用服务异常次数达到指定值,下次请求就在熔断处直接返回,不用再连接到异常应用服务上。

降级:也就是备用方案的启用;比如:DB异常时,用缓存的数据;缓存异常时,或保留请求信息做延迟处理;或默认数据的返回等。

Snapshot

对于集群的灾难与备份,上述有提到多数据中心同步可达到备份的效果,Consul 的快照方式也是一个可选项:

# 命令行 生成快照
consul snapshot save {backup-name}.snap
# API 生成快照
curl http://{host}:8500/v1/snapshot?dc={dc-name} --output {backup-name}.snap
# 命令行 恢复快照
consul snapshot restore {backup-name}.snap
# API 恢复快照
curl -X PUT --data-binary @{backup-name}.snap http://{host}:8500/v1/snapshot
# 命令行 快照详细
consul snapshot inspect {backup-name}.snap

定期生成快照consul snapshot agent仅企业版可用

四、Consul 部署

以下用 docker 部署,docker 拉取镜像:docker pull consul

不管是 Client / Server / Leader 哪种角色,都是 Agent 运行起来的 Node;以下通过两种方式来创建维护 Consul Node:

CLI 方式管理节点

CLI 命令行创建节点的格式如下:

docker run -d --name={容器名称} -p 8500:8500 {image} agent -server -ui -node={节点名称} -bootstrap-expect=3

下表列出了常用各参数的作用说明:

agent必须;Consul 的应用,于每个节点中
-server必须,服务角色;无:被视为Client角色
-node必须;本节点名称
-bootstrap-expect必须;定义Server角色的数量,必须够数,才能成为一个集群,否则集群不会运行
-datacenter数据中心名称(群名称),默认 dc1
-join加入的节点IP地址(Client/Server)
-retry-join尝试重新加入时的节点IP(Client/Server)
-data-dir指定运行时的数据存放目录
-config-file使用指定的配置文件启动运行(文件内容与此表参数项作用相似)
-ui带管理Web页面;访问服务器IP http://{ip}:8500 进入页面管理方式
-client连接限制,开放连接的客户端;浏览器连接打开UI、Client连接Server等

下面来部署一个 Consul Datacenter,计划有3个 Server 节点,3个 Client 节点。

创建3个 Server 节点

节点名称分别定为:ser-a / ser-b / ser-c;由于 Datacenter 的默认值都是 dc1,所以就形成了一个名为 dc1 的数据中心。

# 第一个 Server Node,所以 Consul 会默认为 Leader 角色
docker run -d --name=cons-ser-a -p 8501:8500 consul agent -server -ui -node=ser-a -bootstrap-expect=3 -client=0.0.0.0
# 以下的 Server Node 都 Join 到 Leader Node 上
docker run -d --name=cons-ser-b -p 8502:8500 consul agent -server -node=ser-b -ui -client=0.0.0.0 -retry-join=172.17.0.2
docker run -d --name=cons-ser-c -p 8503:8500 consul agent -server -node=ser-c -ui -client=0.0.0.0 -retry-join=172.17.0.2

起初创建 Leader Node 时bootstrap-expect=3,现在已经运行了3个 Server Node;
所以 Consul 已经启动完成并运转;可以打开UI界面:http://{宿主机IP}:8501/

 

再创建3个 Client 节点,并加入到不同的 Server Node

docker run -d --name=cons-cli-a -p 8511:8500 consul agent -node=cli-a -client=0.0.0.0 -retry-join=172.17.0.2
docker run -d --name=cons-cli-b -p 8512:8500 consul agent -node=cli-b -client=0.0.0.0 -retry-join=172.17.0.3
docker run -d --name=cons-cli-c -p 8513:8500 consul agent -node=cli-c -client=0.0.0.0 -retry-join=172.17.0.4

以上节点的创建过程,是用宿主机的不同端口映射到各自容器节点的8500端口,所以用支持UI的对应宿主机端口都可以打开UI界面

计划的所有 Consul 节点创建完成,Consul 就是用这些节点来管理应用服务集群的,应用服务等后续再加入;以下先阐述节点的维护

查看 Datacenter 成员

# 命令行 列出所属 Datacenter 中的全部成员 [详细]
docker exec -t {容器名称} consul members [-detailed]
# 命令行 列出所属 Datacenter 中的 Server 角色成员
docker exec -t {容器名称} consul operator raft list-peers

Server 加入到 Leader 下

# 如果要加 -datacenter 的话,必须与 join 参数目标的dc名称一致
docker run -d --name={容器名称} {image} agent -server -node={node-name} -join={leader-ip}

Client 加入到 Server 下

# 创建时加入
docker run -d --name={容器名称} {image} agent -datacenter={有要一致} -node={name} -join {server-ip}
# 创建后加入
docker exec -t {容器名称} consul join {server-ip}

下线指定节点

# 命令行 移除所处节点
consul leave
# 命令行 强制移除指定节点 [清楚未运行的节点]
consul force-leave {node-name} [-prune]

不止命令行方式,Consul 也提供了 API 方式来管理节点。

API 方式管理节点

# API 列出所有成员
curl http://{host}:8500/v1/catalog/nodes
# API 加入新节点
# 参数文件 json 指明了节点名称/地址/端口等必要项
curl -X PUT -d @cli-d.json http://{host}:8500/v1/catalog/register
# API 注销节点
curl -X PUT -d '{"Datacenter":"dc1","Node":"cli-d"}' http://{host}:8500/v1//catalog/deregister

有没有麻烦了点。。。 这种方式应该用的不多吧。。。

Consul 6个节点已部署完成,接下来该在 Consul Node 上部署微服务了。

五、应用服务部署

Consul Node 部署完成以后呢,剩下的就是告知 Consul 有哪些应用服务需要你管理,这告知 Consul 的方式有以下几种:

命令行方式注册服务

假设应用服务已经运行起来,然后按 Consul 定义的应用服务配置格式,编写配置文件,放到 Consul 任意节点的配置目录下,文件名称自定义,每次 Consul 启动的时候,都会读取配置目录下的所有文件。

配置内容也就是告诉 Consul 我是谁、我在哪、怎么与我联系、我的检测方式等;

1、配置示例格式如下:

{
  "service": [
    {
      // 服务身份定义
      "id": "AppService-Redis-aaaaa-bbbb-cccc-dddd-eeeee",
      "name": "AppService-Redis",
      "port": 80,
      // 健康检测定义
      "check": {
        "id": "AppService-Redis-Check-TCP",
        "name": "Redis Check TCP on port 80",
        "tcp": "172.17.0.10:80",
        "interval": "10s",
        "timeout": "3s"
      }
    }
  ]
}

2、重载此节点配置:docker exec -t cons-ser-a consul reload

至此完成应用服务注册;如下效果图:

 

以上配置文件:有 Service 项 就是 服务注册,有 Check 项 就是 健康检测注册。

那。。。注销健康检测呢?注销服务呢?

删除 Check 项 就是注销健康检测;删除文件 就是 注销服务;记得重新加载配置consul reload

API 方式注册服务

几乎命令行能做的事情,Consul 提供的 API 方式也可以做到。

假设应用服务已经运行起来了,同样是编写配置文件,以传参的方式请求注册的 API,完成 服务注册、健康注册、服务注销、健康注销等。

以下案例准备了服务注册所需的参数文件:AppService-kafka.json

{
  "service": [
    {
      // 服务身份定义
      "id": "AppService-Kafka-xxxxx-yyyy-zzzz-wwww-vvvvv",
      "name": "AppService-Kafka",
      "port": 80
    }
  ]
}

带文件参数请求注册服务的API接口:

curl -X PUT -d @AppService-kafka.json http://{host}:8500/v1/agent/service/register

当然,也可以单独请求注册健康检测的API接口:

curl -X PUT -d @AppService-health.json http://{host}:8500/v1/agent/check/register

同样的,API注销接口:

curl -X PUT http://{host}:8500/v1/agent/service/deregister/{app-service-id}

curl -X PUT http://{host}:8500/v1/agent/check/deregister/{app-check-id}

更所相关API接口参考官网:Consul HTTP API Overview | Consul | HashiCorp Developer

引用类库方式注册服务

1、创建 .NET 项目,并启用 Docker 方式,假设叫[订单服务],Nuget 安装 Consul

[订单服务]中必须要完成开发的事情:服务注册动作,健康检测定义,服务注销动作。

其实就是把 Consul 类库相关的参数赋值,由 Consul 类库自动完成注册/检测/注销。

2、appsettings 相关配置

"Consul": {
    "Service-Name": "AppService-Order",
    "Service-Port": 80,
    "Service-Health": "/Health",
    // 应用服务 Join to Node Address
    // 未来 Join 的 Node 不固定;所以 创建容器时 再传参
    "Register-Address": null
}

3、扩展 IApplicationBuilder 实现 注册/检测/注销 并启用

以下扩展方法创建后,并在管道中启用:app.UseConsul(app.Configuration, app.Lifetime);

public static IApplicationBuilder UseConsul(this IApplicationBuilder app, IConfiguration conf, IHostApplicationLifetime lifetime)
{
    // 取本机IP(告诉 Consul 健康检测的地址)
    string? _local_ip = NetworkInterface.GetAllNetworkInterfaces()
        .Select(p => p.GetIPProperties())
        .SelectMany(p => p.UnicastAddresses)
        .FirstOrDefault(p =>
            p.Address.AddressFamily == AddressFamily.InterNetwork && !IPAddress.IsLoopback(p.Address)
        )?.Address.ToString();


    // 指明注册到的 Consul Node
    var client = new ConsulClient(options =>
    {
        options.Address = new Uri(conf["Consul:Register-Address"]);
    });
    
    
    // 应用服务的 服务信息 / 健康检测
    var registration = new AgentServiceRegistration
    {
        Name = conf["Consul:Service-Name"],
        ID = $"Order-{Guid.NewGuid().ToString()}",
        Address = _local_ip,
        Port = Convert.ToInt32(conf["Consul:Service-Port"]),
        Check = new AgentServiceCheck
        {
            Timeout = TimeSpan.FromSeconds(5),
            Interval = TimeSpan.FromSeconds(10),
            DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),
            HTTP = $"http://{_local_ip}:{conf["Consul:Service-Port"]}{conf["Consul:Service-Health"]}"
        }
    };
    
    
    // 应用服务启动时 - 注册
    lifetime.ApplicationStarted.Register(() =>
    {
        client.Agent.ServiceRegister(registration).Wait();
    });
    // 应用服务停止时 - 注销
    lifetime.ApplicationStopping.Register(() =>
    {
        client.Agent.ServiceDeregister(registration.ID).Wait();
    });

    return app;
}

4、编写健康检测 API

这里健康检测选用 HTTP API 方式;为此,需要编写 WebApi。

# 服务中追加健康检测接口,供 Consul 调用
# 与 appsettings 配置保持一致的控制器
# 比较简单,达到通信正常,就被视为服务运行正常
public class HealthController : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        return Ok();
    }
}

5、生成 Docker 镜像并运行

每个应用服务都会运行多个实例,把已开发的[订单服务]用Docker运行多个实例,模仿集群环境:

# 项目根目录 生成 docker 镜像
docker build -t order.serv.cons:dev -f ./Order-Web/Dockerfile .
# docker 运行 [订单服务],这里运行2个吧(多实例)
# 还记得 appsettings 中的注册节点地址么...这里传参指明注册的节点
docker run -d --name=order-serv-cons.a -p 5001:80 order.serv.cons:dev --Consul:Register-Address='http://172.17.0.6:8500'
docker run -d --name=order-serv-cons.b -p 5002:80 order.serv.cons:dev --Consul:Register-Address='http://172.17.0.7:8500'

测试验证效果

运行2个 [订单服务] 后的 Consul-UI 图示:

新的服务 AppService-Order 下有两个运行健康的实例,注册与检测都是类库帮助实现的,并显示出IP及注册节点。

相同的服务,有多个运行实例;不同的服务,组成完整的微服务集群;被 Consul 的6个 Node 时时管理着。

测试服务发现

1、Consul API 方式 指定服务的健康实例查询:http://{host}:8501/v1/health/service/{service-name}?passing

2、Consul 类库方式 拉取指定服务的健康实例地址:

// 指明一个节点地址
var _consul_node = new ConsulClient(options =>{ options.Address = new Uri(_conf["Consul:Node-Address"]); });
// 向 Consul 拉取 指定服务 健康实例的列表
var _order_result = await _consul_node.Health.Service("AppService-Order", null, true, _query_options);
var _order_instance_list = _order_result.Response.Select(i => $"http://{i.Service.Address}:{i.Service.Port}");

以上两种方式都发现了两个健康运行的应用服务;测试通过。

服务异常测试

docker 停止一个容器后,只剩一个运行实例:

 

以上停掉一个应用服务后,剩下一个健康运行的应用服务;测试通过。当然,docker 容器再启动后,实例还会再回来。

服务间的相互调用,X服务 -> 订单服务,通过以上方式得出多个可用的实例地址,假如用轮询方式实现了负载均衡;
后续也可以把各应用服务的可用列表,时时的提供给网关(如Nginx),实现网关中的负载均衡。

Consul:Service Mesh & Gateways

consul connect proxy:集群代理,通过调用代理者的端口,实现与被代理者的连接(像是两台机的端口映射似的,被代理者端口不被暴露)  

Consul Service Mesh:在多个集群和环境间建立连接,创建全球化的跨平台服务网络;下有多个Mesh Gateway,每个Mesh Gateway 下是 Datacenter。 

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

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

相关文章

Python算法笔记(3)-树、二叉树、二叉堆、二叉搜索树

树和二叉树 什么是树 树是一种非线性的数据结构&#xff0c;由n个节点构成的有限集合&#xff0c;节点数0的树叫空树&#xff0c;在任意一棵树中&#xff0c;有且仅有一个特点的称为根节点&#xff0c;当N>1时&#xff0c;其余节点可分m为互不相交的有限集。 例如如下&…

子序列,回文串相关题目

class Solution { public:int dp[2510];int lengthOfLIS(vector<int>& nums) {//dp[i]表示以nums[i]为结尾的最长子序列的长度int nnums.size();for(int i0;i<n;i){dp[i]1;}for(int i1;i<n;i){for(int j0;j<i;j){if(nums[i]>nums[j]){dp[i]max(dp[i],dp[…

因子分解机介绍和PyTorch代码实现

因子分解机&#xff08;Factorization Machines&#xff0c;简称FM&#xff09;是一种用于解决推荐系统、回归和分类等机器学习任务的模型。它由Steffen Rendle于2010年提出&#xff0c;是一种基于线性模型的扩展方法&#xff0c;能够有效地处理高维稀疏数据&#xff0c;并且在…

用Blender做一个足球烯C60

文章目录 作图思路先做一个足球球棍模型平滑 Blender初学者入门&#xff1a;做一个魔方 作图思路 C 60 C_{60} C60​是由60个碳原子构成&#xff0c;形似足球&#xff0c;又名足球烯。而足球的顶点&#xff0c;可以通过正二十面体削去顶点得到&#xff0c;原理可参照这篇&…

基于数据驱动的多尺度表示的信号去噪统计方法研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

React组件进阶之children属性,props校验与默认值以及静态属性static

React组件进阶之children属性,props校验与默认值以及静态属性static 一、children属性二、props校验2.1 props说明2.2 prop-types的安装2.3 props校验规则2.4 props默认值 三、静态属性static 一、children属性 children 属性&#xff1a;表示该组件的子节点&#xff0c;只要组…

网站创建004:跟用户交互的标签

input 系列&#xff1a; <body><input type"text" /> <!--文本输入框--><input type"password" /> <!--密码输入框--><input type"checkbox" /> <!--复选框--><input type"checkbox"…

【MySQL】使用C语言连接

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《零基础入门MySQL》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录 &#x1f449;my…

用CSS和HTML写一个水果库存静态页面

HTML代码&#xff1a; <!DOCTYPE html> <html> <head><link rel"stylesheet" type"text/css" href"styles.css"> </head> <body><header><h1>水果库存</h1></header><table>…

函数指针及其使用

类比 数组的地址 函数的地址 数组指针 函数的指针 函数指针的运用 有趣的代码1

从0到1构建基于自身业务的前端工具库

前言 在实际项目开发中无论 M 端、PC 端&#xff0c;或多或少都有一个 utils 文件目录去管理项目中用到的一些常用的工具方法&#xff0c;比如&#xff1a;时间处理、价格处理、解析url参数、加载脚本等&#xff0c;其中很多是重复、基础、或基于某种业务场景的工具&#xff0…

链表(一) 单链表操作详解

文章目录 一、什么是链表二、链表的分类1、单向或者双向2、带头或不带头3、循环或不循环 三、无头单向不循环链表的实现SList.hSList.c动态申请一个节点单链表打印单链表尾插单链表头插单链表的尾删单链表头删单链表查找在pos位置前插入单链表在pos位置之后插入x删除pos位置单链…

自动驾驶下半场的“入场券”

交流群 | 进“传感器群/滑板底盘群/汽车基础软件群/域控制器群”请扫描文末二维码&#xff0c;添加九章小助手&#xff0c;务必备注交流群名称 真实姓名 公司 职位&#xff08;不备注无法通过好友验证&#xff09; 作者 | 张萌宇 自动驾驶战争的上半场拼的是硬件和算法&…

DTC介绍

DTC 一般由3个字节组成&#xff1a; 字节1&#xff1a;High Byte bit 7-6: 对应DTC属于哪一个系统&#xff0c;P: 00动力系统、C: 01底盘、B: 10车身和U: 11通信系统bit 5-4: 用来区分DTC是标准组织所定义还是制造商自定义 00: ISO/SAE01: 制造商10: ISO/SAE11: ISO/SAE bit 3…

【Rust教程 | 基础系列2 | Cargo工具】Cargo介绍及使用

文章目录 前言一&#xff0c;Cargo介绍1&#xff0c;Cargo安装2&#xff0c;创建Rust项目2&#xff0c;编译项目&#xff1a;3&#xff0c;运行项目&#xff1a;4&#xff0c;测试项目&#xff1a;5&#xff0c;更新项目的依赖&#xff1a;6&#xff0c;生成项目的文档&#xf…

python皮卡丘字符打印代码,用python皮卡丘的代码

大家好&#xff0c;本文将围绕python皮卡丘字符打印代码展开说明&#xff0c;python皮卡丘编程代码教程是一个很多人都想弄明白的事情&#xff0c;想搞清楚python皮卡丘编程代码需要先了解以下几个事情。 1、我用python画皮卡丘&#xff0c;没有错误出现&#xff0c;我也打开才…

内网横向移动—NTLM-Relay重放Responder中继攻击LdapEws

内网横向移动—NTLM-Relay重放&Responder中继攻击&Ldap&Ews 1. 前置了解1.1. MSF与CS切换权限1.1.1. CS会话中切换权限1.1.1.1. 查看进程1.1.1.2. 权限权限 1.1.2. MSF会话中切换权限 2. NTLM中继攻击—Relay重放—SMB上线2.1. 案例测试2.1.1. 同账户密码测试2.1.2…

如何使用CRM系统进行客户关系维护管理?

企业要想持续的发展&#xff0c;就必须管理和维护与客户的关系。但如今客户需求更加复杂和多样化&#xff0c;维护客户关系的难度越来越大。许多企业使用CRM系统来帮助自己管理客户关系。通过本文&#xff0c;让您客户关系维护管理全知道。 1、客户画像 CRM系统可以帮助企业建…

【【萌新的stm32学习-1】】

萌新的stm32学习 冯诺依曼结构 采用了分时复用的结构 优点&#xff1a;总线资源占用少 缺点&#xff1a;执行效率低 哈佛结构 执行效率高 总线资源占用多 RISC 这是精简指令集的意思 arm公司 ARMv9是2021年发布的最新 Cortex-A 最好高性能 Cortex-R 中 Cortex-M 低 何为STM…

VScode的简单使用

一、VScode的安装 Visual Studio Code简称VS Code&#xff0c;是一款跨平台的、免费且开源的现代轻量级代码编辑器&#xff0c;支持几乎主流开发语言的语法高亮、智能代码补全、自定义快捷键、括号匹配和颜色区分、代码片段提示、代码对比等特性&#xff0c;也拥有对git的开箱…