【Consul】基于Golang实现Consul服务的注册、注销、修改、监控注册的服务变化、实时同步服务信息机制

【Consul】基于Go实现Consul服务的注册、注销、修改、监控注册的服务变化、实时同步服务信息机制


大家好 我是寸铁👊
总结了一篇【Consul】基于Go实现Consul服务的注册、注销、修改、监控注册的服务变化、实时同步服务信息机制✨
这应该是目前全网最全的使用golang手搓Consul服务信息机制✨
喜欢的小伙伴可以点点关注 💝


前言

consul常常被用来作服务注册与服务发现,而它的watch机制则可被用来监控一些数据的更新,包括:nodes, KV pairs, health checks等。另外,在监控到数据变化后,还可以调用外部处理程序,此处理程序可以是任何可执行文件或HTTP调用,具体说明可见官网。


介绍

consul中的watch可以监听servicek-vcheckevent等事件的变化,实时获取最新的数据。
consul支持以下watch类型:

key 监听一个consul kv中的key
keyprefix 监听consul kv中的key的前缀
services 监听有效服务的变化
nodes 监听节点的变化
service 监听服务的变化
checks 监听check的变化
event 监听自定义事件的变化

从以上可以看出consul提供非常丰富的监听类型,通过这些类型我们可以实时观测到consul整个集群中的变化,从而实现一些特别的需求,比如:服务告警,配置实时更新等功能。


启动与后台展示

Windows启动命令如下:

consul agent -dev

在这里插入图片描述


后台运行结果展示如下:

在这里插入图片描述


UI界面展示

在这里插入图片描述

在这里插入图片描述

Consul服务

AgentService结构体字段具体信息

1.Kind:服务类型,是一个自定义类型 ServiceKind。
2.ID:服务的唯一标识符。(一个ID只能对应一个服务)
3.Service:服务的名称(一个服务可以创建多个ID)
4.Tags:服务的标签,以字符串数组形式存储。
5.Meta:服务的元数据,以键值对的形式存储。
6.Port:服务的端口号。
7.Address:服务的地址。
8.SocketPath:服务的套接字路径,可选的,以字符串形式存储。
9.TaggedAddresses:带标签的地址,以键值对的形式存储,键是标签,值是 ServiceAddress 类型。
10.Weights:服务的权重,类型为 AgentWeights。
11.EnableTagOverride:是否启用标签覆盖。
12.CreateIndex:创建索引,无符号整数类型,用于 JSON 序列化时忽略。
13.ModifyIndex:修改索引,无符号整数类型,用于 JSON 序列化时忽略。
14.ContentHash:内容哈希,字符串类型,用于 JSON 序列化时忽略。
15.Proxy:代理配置,类型为 AgentServiceConnectProxyConfig,可选的。
16.Connect:连接信息,类型为 AgentServiceConnect,可选的。
17.PeerName:对等名称,字符串类型,可选的。
18.Namespace:命名空间,字符串类型,用于 JSON 序列化时忽略。
19.Partition:分区,字符串类型,用于 JSON 序列化时忽略。
20.Datacenter:数据中心,字符串类型,用于 JSON 序列化时忽略。
21.Locality:地点信息,类型为 Locality,用于 JSON 序列化时忽略。    

打印的结果如下:

服务的类型Kind:
服务的ID:  him-service-1
服务的名字Service:  him-service
服务的标签Tags:  [tag1 tag2]
服务的元数据Meta:  map[]
服务的端口Port:  8082
服务的地址Address:  127.0.0.4
服务的套接字路径SocketPath:
服务的带标签的地址TaggedAddresses:  map[lan_ipv4:{127.0.0.4 8082} wan_ipv4:{127.0.0.4 8082}]
服务的权重Weights:  {1 1}
服务是否启用标签覆盖EnableTagOverride:  false
服务创建的索引CreateIndex:  5235
服务修改的索引ModifyIndex:  5235
服务内容哈希ContentHash:
服务代理配置Proxy:  &{[]    0   <nil> map[] [] {} {false []} <nil>}
服务连接信息Connect:  &{false <nil>}
服务对等名称PeerName:
服务的命名空间Namespace:
服务的数据中心Datacenter:
服务的分区Partition:
服务的地点信息Locality:  <nil>

同下:

在这里插入图片描述


注册Consul服务

package mainimport ("fmt""github.com/hashicorp/consul/api"
)func main() {//写api的配置信息config := api.DefaultConfig()//注册到consul上的地址config.Address = "127.0.0.1:8500" // Consul 服务器地址//将config注册到客户端,由客户端实现client, err := api.NewClient(config)if err != nil {panic(err)}// 创建一个新的服务条目registration := new(api.AgentServiceRegistration)registration.ID = "my-service-3"registration.Name = "my-service"registration.Port = 8083registration.Address = "127.0.0.1"registration.Tags = []string{"tag1", "tag2"}reg := &api.AgentServiceRegistration{Name:    registration.Name,    // 服务名称ID:      registration.ID,      // 服务 ID,必须唯一Address: registration.Address, //服务的地址Port:    registration.Port,    // 服务端口 服务所在的监听端口Tags:    registration.Tags,    // 可选:服务标签}// 将服务注册到 Consulerr = client.Agent().ServiceRegister(reg)if err != nil {panic(err)}fmt.Println("Service registered successfully")}

注销Consul服务

package mainimport ("fmt""log""github.com/hashicorp/consul/api"
)func main() {// 创建Consul客户端config := api.DefaultConfig()client, err := api.NewClient(config)if err != nil {log.Fatal(err)}// 创建注销的服务IDserviceID := "my-service-2"// 注销服务agent := client.Agent()if err := agent.ServiceDeregister(serviceID); err != nil {log.Fatal(err)}fmt.Println("Service deregistered successfully")
}

实时同步更新Consul服务的信息

package mainimport ("fmt""github.com/hashicorp/consul/api""time"
)type Service struct {Name    stringID      stringAddress stringPort    intTags    []string
}var serviceMap = map[string][]map[string]Service{}func main() {serviceMap = make(map[string][]map[string]Service)// 创建Consul客户端config := api.DefaultConfig()client, err := api.NewClient(config)if err != nil {panic(err)}for {// 查询Consul客户端的服务目录,得到所有的服务名称。catalog := client.Catalog()//得到consul上的所有服务servicesallServices, _, err := catalog.Services(nil)if err != nil {panic(err)}fmt.Println("所有服务services的名称:", allServices)//创建当前的ServiceMap记录当前的Service 出现则标记为truevar currentServiceMap map[string]boolcurrentServiceMap = make(map[string]bool, 0)//遍历所有的Consul服务,将所有的Consul服务的信息存入map中。//如服务: my-service first-servicefor serviceName, _ := range allServices {currentServiceMap[serviceName] = true// 通过服务名称查询服务实例 如my-service下有两个服务实例: my-service1 my-service2// services是每个服务下的服务实例集合services, _, err := client.Health().Service(serviceName, "", true, nil)if err != nil {panic(err)}var servcieSlice []map[string]ServiceservcieSlice = make([]map[string]Service, 0)// 遍历服务实例集合for _, service := range services {fmt.Printf("Service %s:%d\n", service.Service.Service, service.Service.Port)//map先定义var instanceMap map[string]Service//定义后用make进行创建instanceMap = make(map[string]Service)//每一个服务的实例ID对应该服务的信息instanceMap[service.Service.ID] = Service{Name:    service.Service.Service,ID:      service.Service.ID,Address: service.Service.Address,Port:    service.Service.Port,Tags:    service.Service.Tags,}fmt.Println(instanceMap)servcieSlice = append(servcieSlice, instanceMap)将serviceMap全局map之前出现过的service.Service.Service不存在则赋值为nil//if _, ok := serviceMap[service.Service.Service]; !ok {//	serviceMap[service.Service.Service] = nil//}//service.Service.Service作为serviceMap的键,map[string]Service{}作为值存储入map中。//这里最后一个值会覆盖掉同一个键前面多个值,采用一个值对应一个map的数组serviceMap[service.Service.Service] = servcieSlice}fmt.Println(serviceMap)}//serviceMap为全局的Map,最后遍历一遍serviceMap,看一下里面的serviceName在当前的currentServiceMap中能否找到。//如果说找不到,则把serviceMap中这个serviceName服务给删除掉。for serviceName := range serviceMap {//遍历一遍全局的serviceMap,把不存在的服务删除掉。//如果说currentServiceMap不存在serviceName,则把serviceName从serviceMap中移除。if _, ok := currentServiceMap[serviceName]; !ok {delete(serviceMap, serviceName)}}time.Sleep(10 * time.Second)}
}

长轮询方式监控服务

package mainimport ("fmt""github.com/hashicorp/consul/api"
)func main() {// 创建Consul客户端配置config := api.DefaultConfig()client, err := api.NewClient(config)if err != nil {panic(err)}// 创建WatchParamsparams := &api.QueryOptions{WaitIndex: 0,    // 初始的索引,设置为0表示从最新的变更开始监听WaitTime:  1000, // 设置长轮询的等待时间,单位为秒}// 循环监听服务变化for {// 查询Consul客户端的服务目录,得到所有的服务名称catalog := client.Catalog()allServices, _, err := catalog.Services(params)if err != nil {panic(err)}fmt.Println("所有服务的名称:", allServices)// 查询服务健康状态//for serviceName := range allServices {services, _, err := client.Health().Service("my-service", "", true, params)if err != nil {panic(err)}for _, service := range services {fmt.Printf("服务: %s, 端口号: %v\n", service.Service.Service, service.Service.Port)}//}// 更新WaitIndex,以便下次长轮询从更新后的索引开始params.WaitIndex = 0 // 使用长轮询时,将WaitIndex设置为0,以获取最新的变更}
}

Watch机制监控注册的服务变化

consul官方提供了Golang版的watch包。其实际上也是对watch机制进行了一层封装,最终代码实现的还是对consul HTTP API 的 endpoints的使用。 文章开始说过,“在监控到数据变化后,还可以调用外部处理程序”。是了,数据变化后调用外部处理程序才是有意义的,Golang的watch包中对应的外部处理程序是一个函数handler。因为业务的关系,这里只实现了watch对service的变化的监控,其主要创建了一个plan 来对整个服务的变化做一个监控,以及再为每个服务创建一个 plan,对单个服务变化作监控。话不多说,上代码:

//Watch机制同步
package mainimport ("fmt""github.com/hashicorp/consul/api""github.com/hashicorp/consul/api/watch""log"
)var serviceMap map[string][]map[string]Servicetype Service struct {Name    stringID      stringAddress stringPort    intTags    []string
}func main() {serviceMap = make(map[string][]map[string]Service)// 创建Consul客户端config := api.DefaultConfig()client, err := api.NewClient(config)if err != nil {panic(err)}// 初始化监视器计划params := map[string]interface{}{"type": "services"}plan, err := watch.Parse(params)if err != nil {log.Fatal(err)}// 设置监视器的处理函数plan.Handler = func(idx uint64, data interface{}) {services, ok := data.(map[string][]string)if !ok {log.Println("Error: Data format unexpected")return}// 重置服务映射serviceMap = make(map[string][]map[string]Service)// 在这里阻塞住了// 遍历服务列表for serviceName := range services {// 查询服务实例instances, _, err := client.Health().Service(serviceName, "", true, nil)if err != nil {log.Printf("Error retrieving instances for service %s: %v\n", serviceName, err)continue}// 创建服务实例切片var serviceInstances []map[string]Service// 遍历服务实例for _, instance := range instances {service := Service{Name:    instance.Service.Service,ID:      instance.Service.ID,Address: instance.Service.Address,Port:    instance.Service.Port,Tags:    instance.Service.Tags,}instanceMap := map[string]Service{instance.Service.ID: service}serviceInstances = append(serviceInstances, instanceMap)}// 更新服务映射serviceMap[serviceName] = serviceInstances}// 输出服务映射fmt.Println("Updated Service Map:")for serviceName, instances := range serviceMap {fmt.Println("Service:", serviceName)for _, instance := range instances {for id, service := range instance {fmt.Printf("Instance ID: %s, Address: %s, Port: %d, Tags: %v\n", id, service.Address, service.Port, service.Tags)}}}}// 启动监视器plan.Run("http://localhost:8500")// 保持程序运行,直到手动中断select {}
}

长时间没有响应,则进程结束。
在这里插入图片描述


采用goroutinr消息型监控服务


package mainimport ("context""fmt""github.com/hashicorp/consul/api"
)// 定义服务信息
type Service struct {Name    stringID      stringAddress stringPort    intTags    []string
}// 全部服务信息的字典
var servicesMap = map[string]map[string]Service{}// 记录本次目录存在的服务的字典,布尔型,用于和lastServiceMap进行判断
var currentServicesMap = map[string]bool{}// 记录上次目录存在的服务的字典,布尔型,用于和currentServicesMap进行判断
var lastServiceMap = map[string]bool{}// 取消服务的协程的字典,存的是服务名和上下文cancel方法的映射,用于删除指定的goroutine
var withCancelMap = map[string]context.CancelFunc{}func main() {//初始化mapcurrentServicesMap = make(map[string]bool)lastServiceMap = make(map[string]bool)servicesMap = make(map[string]map[string]Service)withCancelMap = make(map[string]context.CancelFunc)// 创建Consul客户端config := api.DefaultConfig()client, err := api.NewClient(config)if err != nil {panic(err)}// 创建WatchParams//params := &api.QueryOptions{//	WaitIndex: 0, // 初始的索引,设置为0表示从最新的变更开始监听//}//配置参数放在外面,则达到获取目录信息阻塞的效果queryOptions := &api.QueryOptions{WaitIndex: 0, // 初始索引}for {catalog := client.Catalog()// 查询Consul客户端的服务目录,得到所有的服务名称。//得到consul上的所有服务services//目录发生变化再更新,不发生变化则不更新,需要在这里阻塞。allServices, meta, err := catalog.Services(queryOptions)fmt.Println(err)if err != nil {panic(err)}//currentServicesMap记录allServices出现过的服务for name := range allServices {currentServicesMap[name] = true}//遍历一遍上次服务的哈希表lastServiceMapfor lastServiceName := range lastServiceMap {//如果说上次服务的哈希表中存在这个服务,现在遍历目录没有这个服务if allServices[lastServiceName] == nil {//将lastServiceName从当前的currentServicesMap移除delete(currentServicesMap, lastServiceName)}}//如果没有一个检查机制的话,这里相当于一直去读取目录,读完目录后再不断启协程//这里就会造成不断的for死循环,所以需要一个检查机制,控制目录的更新。//当目录没发生更新的时候则阻塞,目录发生更新了则进行检查。//这样就确保了你目录没更新时,我启动的go func就一直在监听服务的变化即可fmt.Println("所有服务services的名称:", allServices)//如果说协程中不启动go routine则相当于每次遍历服务时都去创建go routine 导致启动的go routine数量比较多//每次目录发生变化后,这里就会创建新的协程,就会导致多了几个协程。//正确的话,这里应该是先阻塞,然后如果说哪个协程监听到变化,则这个协程发消息即可//其他的协程不用动,需要编写一个服务的检查机制,让之前启动的goroutine去监控对应的服务即可,其他不变化的go routine不用动。fmt.Println("lastServiceMap:", lastServiceMap)fmt.Println("currentServicesMap:", currentServicesMap)for serviceName := range allServices {if currentServicesMap[serviceName] && lastServiceMap[serviceName] {//如果说上次和这次都存在该服务,说明之前已经创建过了,则跳过fmt.Println("跳过……", serviceName)continue} else if currentServicesMap[serviceName] && !lastServiceMap[serviceName] {//如果说上次不存在,这次存在则说明要进行创建//如果说目录多增加了一个服务,则启动多一个服务。fmt.Println("启动协程……", serviceName)//使用上下文进行协程的注销ctx, cancel := context.WithCancel(context.Background())//存储一个serviceName为键、cancel()方法为值的withCancelMapwithCancelMap[serviceName] = cancelgo syncInfo(ctx, serviceName, client, queryOptions)//range上次的lastServiceMap}}//比较上次目录的服务信息和这次目录的服务信息//执行删除指定go routine的操作for lastName := range lastServiceMap {if !currentServicesMap[lastName] && lastServiceMap[lastName] {//如果说上次该服务存在,这次该服务不存在则说明要进行销毁fmt.Println("进入删除协程函数……", lastName)//当走到这里时,执行serviceName对应的cancel方法cacnelService := withCancelMap[lastName]cacnelService() //取消掉该服务的协程fmt.Println("删除协程……", lastName)//由于该服务lastName已经取消了,则从serviceMap中移除掉delete(servicesMap, lastName)//由于该服务lastName已经取消了,则从lastServiceMap中移除掉delete(lastServiceMap, lastName)//由于该服务lastName已经取消了,则从withCancelMap中移除掉delete(withCancelMap, lastName)}}// 赋值 currentServicesMap 的值给 lastServiceMap,用于下一次的目录信息检查。for key, value := range currentServicesMap {lastServiceMap[key] = value}//fmt.Println(serviceMap)// 更新长轮询参数中的索引queryOptions.WaitIndex = meta.LastIndex}
}/*
将服务的各个实例的信息同步更新到全部服务信息的字典中,对开启服务的协程持续监控服务的信息变化。
当服务不存在时,执行取消服务所在的协程的操作。
*/
func syncInfo(ctx context.Context, serviceName string, client *api.Client, params *api.QueryOptions) {for {select {//执行ctx绑定cancel//执行cancel时,绑定对应的ctx执行Done()方法,取消掉协程。case <-ctx.Done(): //会有一点延迟fmt.Println("协程取消了……")returndefault://params要作为参数传入函数,这样params := &api.QueryOptions{WaitIndex: 0, // 初始的索引,设置为0表示从最新的变更开始监听}fmt.Println("1111111111", serviceName)services, meta, err := client.Health().Service(serviceName, "", true, params)fmt.Println("2222222222", serviceName)if err != nil {panic(err)}//var servcieSlice []map[string]Service//servcieSlice = make([]map[string]Service, 0)// 遍历服务实例集合//map先定义var instanceMap map[string]Service//定义后用make进行创建instanceMap = make(map[string]Service)for _, service := range services {//fmt.Printf("Service %s:%d\n", service.Service.Service, service.Service.Port)//每一个服务的实例ID对应该服务的信息instanceMap[service.Service.ID] = Service{Name:    service.Service.Service,ID:      service.Service.ID,Address: service.Service.Address,Port:    service.Service.Port,Tags:    service.Service.Tags,}//fmt.Println(instanceMap)打印出服务中每个实例的信息servicesMap[service.Service.Service] = instanceMap}fmt.Println(instanceMap)params.WaitIndex = meta.LastIndex // 更新版本,根据和上次的不同进行变化。}}
}

参考网址

https://vearne.cc/archives/13983
https://juejin.cn/post/6984378158347157512
https://juejin.cn/post/6883095345623597064
https://zhuanlan.zhihu.com/p/111673886
https://developer.hashicorp.com/consul/api-docs/catalog


看到这里的小伙伴,恭喜你又掌握了一个技能👊
希望大家能取得胜利,坚持就是胜利💪
我是寸铁!我们下期再见💕


往期好文💕

保姆级教程

【保姆级教程】Windows11下go-zero的etcd安装与初步使用

【保姆级教程】Windows11安装go-zero代码生成工具goctl、protoc、go-zero

【Go-Zero】手把手带你在goland中创建api文件并设置高亮


报错解决

【Go-Zero】Error: user.api 27:9 syntax error: expected ‘:‘ | ‘IDENT‘ | ‘INT‘, got ‘(‘ 报错解决方案及api路由注意事项

【Go-Zero】Error: only one service expected goctl一键转换生成rpc服务错误解决方案

【Go-Zero】【error】 failed to initialize database, got error Error 1045 (28000):报错解决方案

【Go-Zero】Error 1045 (28000): Access denied for user ‘root‘@‘localhost‘ (using password: YES)报错解决方案

【Go-Zero】type mismatch for field “Auth.AccessSecret“, expect “string“, actual “number“报错解决方案

【Go-Zero】Error: user.api 30:2 syntax error: expected ‘)‘ | ‘KEY‘, got ‘IDENT‘报错解决方案

【Go-Zero】Windows启动rpc服务报错panic:context deadline exceeded解决方案


Go面试向

【Go面试向】defer与time.sleep初探

【Go面试向】defer与return的执行顺序初探

【Go面试向】Go程序的执行顺序

【Go面试向】rune和byte类型的认识与使用

【Go面试向】实现map稳定的有序遍历的方式

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Git命令(1)[删除,恢复与移动]

文章目录 1.删除文件1.1命令----rm <filename>1.2命令----git rm <filename>1.1命令----git rm <filename> -f 2.恢复文件2.1命令----git restore <filename>2.1命令----git restore --staged <filename> 3.重命名文件3.1命令----mv 旧文件 新文…

Node.js------Express

◆ 能够使用 express.static( ) 快速托管静态资源◆ 能够使用 express 路由精简项目结构◆ 能够使用常见的 express 中间件◆ 能够使用 express 创建API接口◆ 能够在 express 中启用cors跨域资源共享 一.初识Express 1.Express 简介 官方给出的概念&#xff1a;Express 是基…

CSS - 你实现过0.5px的线吗

难度级别:中级及以上 提问概率:75% 我们知道在网页显示或是网页打印中,像素已经是最小单位了,但在很多时候,即便是最小的1像素,精度却不足以呈现所需的线条精度和细节。因此,为了在网页显示和网页打印中呈现更加细致的线条,为了在视觉…

带你了解自动驾驶中的功能安全

谈一谈自动驾驶中的功能安全 附赠自动驾驶学习资料和量产经验&#xff1a;链接 一 概述 汽车涉及到人的生命财产安全&#xff0c;谈汽车首先要谈的就是安全。目前自动驾驶的安全主要分为三大块&#xff1a;功能安全&#xff0c;网络&#xff08;信息&#xff09;安全&#xf…

【LeetCode】--- 动态规划 集训(二)

目录 一、63. 不同路径 II1.1 题目解析1.2 状态转移方程1.3 解题代码 二、931. 下降路径最小和2.1 题目解析2.2 状态转移方程2.3 解题代码三、174. 地下城游戏3.1 题目解析3.2 状态转移方程3.3 解题代码 一、63. 不同路径 II 题目地址&#xff1a; 不同路径 II 一个机器人位于…

腾讯云(CVM)托管进行权限维持

前言 刚好看到一个师傅分享了一个阿里云ECS实战攻防&#xff0c;然后想到了同样利用腾讯云CVM的托管亦可实现在实战攻防中的权限维持。 简介 腾讯云自动化助手&#xff08;TencentCloud Automation Tools&#xff0c;TAT&#xff09;是一个原生运维部署工具&#xff0c;它可…

“Linux 三剑客”,通常指的是三个经典的命令行工具:grep、sed 和 awk

1、grep&#xff1a; 简介&#xff1a;grep 是一个强大的文本搜索工具&#xff0c;可以用于在文件中查找匹配特定模式的行。示例&#xff1a; 搜索包含特定关键词的行&#xff1a; grep "keyword" filename 递归搜索目录下所有文件&#xff1a; grep -r define zj…

java面试题(Redis)

事情干的差不多了&#xff0c;开刷面试题和算法&#xff0c;争取在短时间内快速成长&#xff0c;理解java面试的常见题型 一、redis使用场景&#xff1a; 缓存&#xff1a;穿透、击穿、雪崩 双写一致、持久化 数据过期、淘汰策略 分布式锁&#xff1a;setnx、redisson 计数…

Flutter Boost 3

社区的 issue 没有收敛的趋势。 设计过于复杂&#xff0c;概念太多。这让一个新手看 FlutterBoost 的代码很吃力。 这些问题促使我们重新梳理设计&#xff0c;为了彻底解决这些顽固的问题&#xff0c;我们做一次大升级&#xff0c;我们把这次升级命名为 FlutterBoost 3.0&am…

Redis -- 缓存穿透问题解决思路

缓存穿透 &#xff1a;缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在&#xff0c;这样缓存永远不会生效&#xff0c;这些请求都会打到数据库。 常见的解决方案有两种&#xff1a; 缓存空对象 优点&#xff1a;实现简单&#xff0c;维护方便 缺点&#xff1a; 额外…

讲讲你对数据结构-线性表了解多少?

线性表 - 数组和矩阵 当谈到线性表时&#xff0c;数组和矩阵是两种常见的数据结构。 数组&#xff08;Array&#xff09;&#xff1a; 数组是有序的元素集合&#xff0c;可以通过索引来访问和操作其中的元素。它是最简单、最基本的数据结构之一。数组的特点包括&#xff1a; …

paddlepaddle模型转换onnx指导文档

一、检查本机cuda版本 1、右键找到invdia控制面板 2、找到系统信息 3、点开“组件”选项卡&#xff0c; 可以看到cuda版本&#xff0c;我们这里是cuda11.7 cuda驱动版本为516.94 二、安装paddlepaddle环境 1、获取pip安装命令 &#xff0c;我们到paddlepaddle官网&#xff…

2012年认证杯SPSSPRO杯数学建模C题(第二阶段)碎片化趋势下的奥运会商业模式全过程文档及程序

2012年认证杯SPSSPRO杯数学建模 C题 碎片化趋势下的奥运会商业模式 原题再现&#xff1a; 从 1984 年的美国洛杉矶奥运会开始&#xff0c;奥运会就不在成为一个“非卖品”&#xff0c;它在向观众诠释更高更快更强的体育精神的同时&#xff0c;也在攫取着巨大的商业价值&#…

idea2023.2.1 java项目-web项目创建-servlet类得创建

如何创建Java项目 1.1 方式1&#xff1a; 1.2 方式&#xff1a; 1.3 方式 如何创建web项目 方式 ----- 推荐 如何创建servlet类 复制6 中得代码 给servlet 配置一个路径 启动tomcat 成功了

【星海随笔】Ubuntu22.04忘记密码

服务器篇&#xff1a; 有问题可留言。 第一步 远程console界面进入该设备 并重启该设备 如果看到这个界面情况 则点击右上角按钮 【发送 CtrlAltDelete】 调出grub启动菜单 NOTE&#xff1a;启动的后半段去点击这个按钮&#xff0c;前半段一直点会一直重启 如果是直连服务器&a…

Linux-4 gcc和makefile

Linux编译器-gcc/g使用 1.设计样例 c语言&#xff1a;linux中用的stdc99版本--可能会出现其他问题 c&#xff1a;Linux中用的stdc11--使用c11版本 Linux没有文件格式的区分&#xff0c;但是编译器区分 gcc编译器的文件格式是filename.c g编译器的文件格式是filename.cc或者fil…

docker的安装及入门指令

目录 一、将docker安装到云服务器步骤 1.更新系统yum版本 2.安装所需依赖 3.添加docker仓库设置(使用的是阿里云) 4.安装docker引擎 5.启动docker并开启自动启动 6. 检查是否安装成功&#xff0c;成功会显示相应版本&#xff0c;否则安装失败 二、docker常用命令 1.从…

Javascript/Node.JS中如何用多种方式避免属性为空(cannot read property of undefined ERROR)

>>>>>>问题 "cannot read property of undefined" 是一个常见的 JavaScript 错误&#xff0c;包含我在内很多人都会遇到&#xff0c;表示你试图访问一个未定义&#xff08;undefined&#xff09;对象的属性。这通常是因为你在访问一个不存在的对象…

【第十六篇】使用BurpSuite实现匹配替换(实战案例)

在Burp中可配置匹配和替换规则,当我们使用浏览器请求程序时,这些规则会自动修改我们的请求和响应。 在某些环境下,我们可以修改 IP 地址,让服务器相信我们属于其本地网络,从而实现与原本无法访问的内部基础设施进行通信。下面将以IP欺骗为例进行操作讲解。 如图,admin目…

2024.4.2-[作业记录]-day07-CSS 盒子模型(显示模式、盒子模型)

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; 文章目录 作业 2024.4.2 学习笔记CSS标签元素显示模式1 块元素2 行内元素3 行内块元素4…