当前位置: 首页 > news >正文

[golang 微服务] 5. 微服务服务发现介绍,安装以及consul的使用,Consul集群

一.服务发现介绍

  1. 引入

上一节讲解了使用 gRPC创建微服务,客户端的一个接口可能需要调用 N个服务,而不同服务可能存在 不同的服务器,这时,客户端就必须知道所有服务的 网络位置(ip+port),来进行连接服务器操作,如下图所示:

以往的做法是把服务的地址放在配置文件或者数据库中,这样就有以下几个问题:

  • 需要配置N个服务的网络位置,加大配置的复杂性

  • 服务的网络位置变化,需要改变每个调用者的配置

  • 集群的情况下,难以做负载(反向代理的方式除外)

总结起来一句话: 服务多了,配置很麻烦,问题一大堆

所以现在就选择服务发现来解决这些问题,具体设计如下:

与之前解决方法不同的是,加了个 服务发现模块,服务端把当前自己的网络位置 注册到服务发现模块(这里注册的意思就是告诉),服务发现就以 K-V的方式记录下,K一般是 服务名,V就是 IP:PORT,服务发现模块 定时的轮询查看这些服务能不能访问的了(这就是 健康检查),客户端在调用服务A-N的时候,就跑去服务发现模块问下它们的网络位置,然后再调用它们的服务,这样的方式就可以解决上面的问题了, 客户端完全不需要记录这些服务的网络位置, 客户端和服务端完全解耦

常见的服务发现框架有:Etcd、mdns、Consul、Zookeeper

  • consul 常应用于grpc 、 go-micro

  • mdns:以前mdns是go-micro中默认自带的服务发现go-micro的默认服务发现也是consul

  • etcd:k8s 内嵌的服务发现

  • zookeeper:java中较常用

这里选择服务发现框架consul来做一个详细介绍

  1. consul介绍

Consul是Go语言写的开源 的服务器发现软件,用于实现 分布式系统的服务发现与配置,包含 多个组件,作为一个整体,它为基础设施提供服务发现和服务配置的工具,提供以下关键特性:
  • 服务发现:consul通过DNS或者HTTP接口使服务注册服务发现变的很容易,一些外部服务,例如saas提供的也可以一样注册,consul采用Raft一致性协议算法来保证服务的高可用,使用GOSSIP协议管理成员广播消息

  • 健康检查:健康检测使consul可以快速的告警在集群中的操作,和服务发现的集成,可以防止服务转发到故障的服务上面(心跳机制)

  • 键/值存储:一个用来存储动态配置的系统,提供简单的HTTP接口,可以在任何地方操作

  • 多数据中心方案支持:无需复杂的配置,即可支持任意数量的区域

  • 简易安装:安装包仅包含一个二进制文件,支持跨平台,可与Docker等轻量级容器实现无缝对接

  • 提供Web管理界面:官方提供web管理界面

官方建议:最好是三台或者三台以上的consul在运行,同名服务最好是三台或三台以上,默认可
以搭建集群

官网:https://www.consul.io/

Git地址:https://github.com/hashicorp/consul

  1. consul安装

Consul用Golang实现,因此具有天然可移植性 (支持 Linux、windows和macOS),安装包仅包含一个可执行文件, Consul安装非常简单,只需要下载对应系统的软件包并解压后就可使用

(1). windows电脑安装consul

1).下载consul

下载地址: https://www.consul.io/downloads

2).解压consul到一个目录

把consul解压到E盘

3).配置consul到环境变量

a.电脑左下方设置选项
b.选择系统
c.关于->高级系统设置
d.选择'环境变量'
e.配置consul到环境变量

4).测试consul是否安装成功

重启计算机,命令行运行 consul -v, 出现如下代码,说明安装成功

(2).Mac电脑安装consul

方法一

运行以下命令即可
brew tap hashicorp/tap
brew install hashicorp/tap/consul

方法二

和windows类似
1).下载consul
2).减压consul到一个目录 配置consul到环境变量
或者下载解压后,将文件放置在 /usr/local/bin 目录下
3).查看安装情况
consul --version

(3).Linux电脑安装consul

方法一

Ubuntu安装步骤
curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com
$(lsb_release -cs) main"
sudo apt-get update && sudo apt-get install consul
CentOS安装步骤
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo
https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
sudo yum -y install consul

方法二

和windows/mac安装类似
1).下载consul
2).减压consul到一个目录 配置consul到环境变量
[root@localhost ~]# mkdir -p usr/local/consul
[root@localhost ~]# unzip consul_1.11.4_linux_arm64.zip -d /usr/local/consul/
[root@localhost ~]# cd /usr/local/consul/
[root@localhost ~]# ./consul -v
如果要全局使用请把consul加入到环境变量,或者下载解压后,将文件放置在 /usr/local/bin 目录下
3).安装验证
安装 Consul后,通过执行 consul命令,可以看到命令列表的输出
ok,consul在各个环境安装完成

二. consul的使用

  1. consul的角色

完成consul的安装后,必须运行 agent, agent可以运行为 server模式client模式或者 dev模式, 每个数据中心至少必须拥 有一台serve,建议在一个集群中有 3或者5个server,因为部署单一server,在出现失败时,也许会不可避免的出现数据丢失
  • client客户端角色: 将 HTTP 和 DNS 接口请求转发给局域网内的Server服务端集群

  • server服务端角色 :保存配置信息、实现高可用集群、在局域网内与本地客户端通讯、通过广域网与其他数据中心通讯等, 每个数据中心(集群)的 server 数量推荐为3个或是5个

  • 开发模式:主要用于开发阶段(dev模式也是server模式)

consul安装好之后,在使用之前,先了解一下consul都有哪些命令,使用命令 consul -h可以查看consul支持的所有参数,而且每个参数里面还支持其他参数
C:\Users\zhoupenghui>consul -h
Usage: consul [--version] [--help] <command> [<args>]Available commands are:acl             Interact with Consul's ACLsagent           Runs a Consul agentcatalog         Interact with the catalogconfig          Interact with Consul's Centralized Configurationsconnect         Interact with Consul Connectdebug           Records a debugging archive for operatorsevent           Fire a new eventexec            Executes a command on Consul nodesforce-leave     Forces a member of the cluster to enter the "left" stateinfo            Provides debugging information for operators.intention       Interact with Connect service intentionsjoin            Tell Consul agent to join clusterkeygen          Generates a new encryption keykeyring         Manages gossip layer encryption keyskv              Interact with the key-value storeleave           Gracefully leaves the Consul cluster and shuts downlock            Execute a command holding a locklogin           Login to Consul using an auth methodlogout          Destroy a Consul token created with loginmaint           Controls node or service maintenance modemembers         Lists the members of a Consul clustermonitor         Stream logs from a Consul agentoperator        Provides cluster-level tools for Consul operatorspeering         Create and manage peering connections between Consul clustersreload          Triggers the agent to reload configuration filesrtt             Estimates network round trip time between nodesservices        Interact with servicessnapshot        Saves, restores and inspects snapshots of Consul server statetls             Builtin helpers for creating CAs and certificatestroubleshoot    CLI tools for troubleshooting Consul service meshvalidate        Validate config files/directoriesversion         Prints the Consul versionwatch           Watch for changes in Consul
agent参数说明:指令是consul的核心,它运行agent来维护成员的重要信息、运行检查、服务宣布、查询处理等等
  1. consul agent -dev 开发者模式启动consul

开发阶段可以使用下面命令启动consul ,执行 consul agent -dev 启动了一个consul 服务端
consul agent -dev
访问 http://localhost:8500 可以打开Web管理界面,如下:
  1. consul和gRPC结合使用

(1).启动consul

代码中结合gRPC和consul使用时,需要先 启动consul ,开发阶段通过 consul agent -dev 启动consul,在操作consul时使用的是 github.com/hashicorp/consul 这个包,需要先下载,可以通过命令 go get -u -v github.com/hashicorp/consul,或者在import中引入 github.com/hashicorp/consul/api后,使用go mod tidy来加载

(2).注册一个服务到consul上

把上一节中的 hello grpc服务注册到consul上,找到server/hello/main.go,编辑,代码如下:
增加了 consul服务相关代码,其它地方保存不变
package mainimport ("context""fmt""net""google.golang.org/grpc""github.com/hashicorp/consul/api""serverHello/proto/helloService"
)//rpc远程调用的接口,需要实现hello.proto中定义的Hello服务接口,以及里面的方法
//1.定义远程调用的结构体和方法,这个结构体需要实现HelloServer的接口type Hello struct{}//SayHello方法参考hello.pb.go中的接口
/*
// HelloServer is the server API for Hello service.
type HelloServer interface {// 通过rpc来指定远程调用的方法:// SayHello方法, 这个方法里面实现对传入的参数HelloReq, 以及返回的参数HelloRes进行约束SayHello(context.Context, *HelloReq) (*HelloRes, error)
}*/
func (this Hello) SayHello(c context.Context, req *helloService.HelloReq) (*helloService.HelloRes, error) {fmt.Println(req)return &helloService.HelloRes{Message: "你好" + req.Name,}, nil
}func main() {//------------------------- consul服务相关----------------------//注册consul服务//1、初始化consul配置consulConfig := api.DefaultConfig()//设置consul服务器地址: 默认127.0.0.1:8500, 如果consul部署到其它服务器上,则填写其它服务器地址//consulConfig.Address = "127.0.0.1:8500"//2、获取consul操作对象consulClient, _ := api.NewClient(consulConfig)// 3、配置注册服务的参数agentService := api.AgentServiceRegistration{ID:      "1",  // 服务id,顺序填写即可Tags:    []string{"test"},  // tag标签Name:    "HelloService",  //服务名称, 注册到服务发现(consul)的KPort:    8080, // 端口号: 需要与下面的监听, 指定 IP、port一致Address: "127.0.0.1",  // 当前微服务部署地址: 结合Port在consul设置为V: 需要与下面的监听, 指定 IP、port一致Check: &api.AgentServiceCheck{  //健康检测TCP:      "127.0.0.1:8080",  //前微服务部署地址,端口 : 需要与下面的监听, 指定 IP、port一致Timeout:  "5s",  // 超时时间Interval: "30s",  // 循环检测间隔时间},}//4、注册服务到consul上consulClient.Agent().ServiceRegister(&agentService)//------------------------- grpc相关----------------------//1. 初始一个 grpc 对象grpcServer := grpc.NewServer()//2. 注册服务//helloService.RegisterHelloServer(grpcServer, &Hello{})// &Hello{}和 new(Hello)相同helloService.RegisterHelloServer(grpcServer, new(Hello))//3. 设置监听, 指定 IP、portlistener, err := net.Listen("tcp", "127.0.0.1:8080")if err != nil {fmt.Println(err)}// 4退出关闭监听defer listener.Close()//5、启动服务grpcServer.Serve(listener)
}

效果展示:

运行该main..go
consul界面展示效果如下:

说明HelloService微服务注册到了consul这个服务发现中了

(3).在客户端使用服务发现获取hello微服务相关

把上一节中的 hello grpc服务客户端代码修改一下,通过consul获取hello微服务相关,找到server/client/main.go,编辑,增加了 consul服务相关代码,在连接服务器的时候,使用consul返回的微服务地址, 其它地方保存不变,代码如下:
package mainimport ("client/proto/helloService""context""fmt""google.golang.org/grpc""github.com/hashicorp/consul/api""google.golang.org/grpc/credentials/insecure""strconv"
)func main() {//----------------------------consul相关---------------------------//初始化consul配置, 客户端服务器需要一致consulConfig := api.DefaultConfig()//设置consul服务器地址: 默认127.0.0.1:8500, 如果consul部署到其它服务器上,则填写其它服务器地址//consulConfig.Address = "127.0.0.1:8500"//2、获取consul操作对象consulClient, _ := api.NewClient(consulConfig)  //目前先屏蔽error,也可以获取error进行错误处理//3、获取consul服务发现地址,返回的ServiceEntry是一个结构体数组//参数说明:service:服务名称,服务端设置的那个Name, tag:标签,服务端设置的那个Tags,, passingOnly bool, q: 参数serviceEntry, _, _ := consulClient.Health().Service("HelloService", "test", false, nil)//打印地址fmt.Println(serviceEntry[0].Service.Address)fmt.Println(serviceEntry[0].Service.Port)//拼接地址//strconv.Itoa: int转string型address := serviceEntry[0].Service.Address + ":" + strconv.Itoa(serviceEntry[0].Service.Port)//----------------------------hello微服务相关------------------------------// 1、连接服务器/*credentials.NewClientTLSFromFile :从输入的证书文件中为客户端构造TLS凭证。grpc.WithTransportCredentials :配置连接级别的安全凭证(例如,TLS/SSL),返回一个DialOption,用于连接服务器。*///把上面拼接的地址放入下面grpcClient, err := grpc.Dial(address, grpc.WithTransportCredentials(insecure.NewCredentials()))if err != nil {fmt.Println(err)}//2、注册客户端client := helloService.NewHelloClient(grpcClient)//3、调用服务端函数, 实现HelloClient接口:SayHello()/*// HelloClient is the client API for Hello service.//// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.type HelloClient interface {// 通过rpc来指定远程调用的方法:// SayHello方法, 这个方法里面实现对传入的参数HelloReq, 以及返回的参数HelloRes进行约束SayHello(ctx context.Context, in *HelloReq, opts ...grpc.CallOption) (*HelloRes, error)}*/res, err1 := client.SayHello(context.Background(), &helloService.HelloReq{Name: "张三",})if err1 != nil {fmt.Printf("调用服务端代码失败: %s", err1)return}fmt.Printf("%#v\r\n", res)fmt.Printf("调用成功: %s", res.Message)
}

(4).校验客户端-服务发现-服务端功能是否成功

启动consul

见上面操作

启动服务端

见上面操作

启动客户端

校验成功

(5).测试不同服务端口下,客户端调用hello微服务操作

修改服务端hello微服务main.go中的端口号,改为8081,然后重新运行该微服务,再使用客户端请求服务发现,看看返回的hello微服务对应的端口号发生变化没有,如果发生变化了,说明操作成功,以此为案例,开发者可以把微服务服务端部署到不同服务器上,并指定对应的端口,从而实现微服务的负载均衡操作

F:\www\go-data\src\go_code\micro\grpc_demo\server\hello>go run .\main.go

name:"张三"

(6)实现goods微服务-服务发现-客户端操作

把上一节 goods微服务注册到consul上,找到server/goods/main.go,编辑,代码如下:
增加了 consul服务相关代码,其它地方保存不变
package mainimport ("context""fmt""github.com/hashicorp/consul/api""goods/proto/goodsService""net""google.golang.org/grpc""strconv"
)//rpc远程调用的接口,需要实现goods.proto中定义的Goods服务接口,以及里面的方法
//1.定义远程调用的结构体和方法,这个结构体需要实现GoodsServer的接口type Goods struct{}//GoodsServer方法参考goods.pb.go中的接口
/*
// GoodsServer is the server API for Goods service.
type GoodsServer interface {// 通过rpc来指定远程调用的方法:// AddGoods方法:增加商品, 这个方法里面实现对传入的参数AddGoodsReq, 以及返回的参数AddGoodsRes进行约束AddGoods(context.Context, *AddGoodsReq) (*AddGoodsRes, error)// 获取商品列表: GetGoodsReq 参数可为空, 返回参数GetGoodsRes是一个商品相关的切片GetGoods(context.Context, *GetGoodsReq) (*GetGoodsRes, error)
}
*/
//增加商品数据
func (this Goods) AddGoods(c context.Context, req *goodsService.AddGoodsReq) (*goodsService.AddGoodsRes, error) {fmt.Println(req)//模拟返回操作,正式项目在这里进行数据库的操作即可,根据操作结果,返回相关数据return &goodsService.AddGoodsRes{Message: "增加数据成功",Success: true,}, nil
}//获取商品列表
func (g Goods) GetGoods(c context.Context, req *goodsService.GetGoodsReq) (*goodsService.GetGoodsRes, error) {//  GoodsList []*GoodsModelvar tempList []*goodsService.GoodsModel  //定义返回的商品列表切片//模拟从数据库中获取商品的请求,循环结果,把商品相关数据放入tempList切片中for i := 0; i < 10; i++ {tempList = append(tempList, &goodsService.GoodsModel{Title:   "商品" + strconv.Itoa(i),  // strconv.Itoa(i): 整型转字符串类型Price:   float64(i),  //float64(i): 强制转换整型为浮点型Content: "测试商品内容" + strconv.Itoa(i),})}return &goodsService.GetGoodsRes{GoodsList: tempList,}, nil
}func main() {//------------------------- consul服务相关----------------------//注册consul服务//1、初始化consul配置consulConfig := api.DefaultConfig()//设置consul服务器地址: 默认127.0.0.1:8500, 如果consul部署到其它服务器上,则填写其它服务器地址//consulConfig.Address = "127.0.0.1:8500"//2、获取consul操作对象consulClient, _ := api.NewClient(consulConfig)// 3、配置注册服务的参数agentService := api.AgentServiceRegistration{ID:      "1",  // 服务id,顺序填写即可Tags:    []string{"test"},  // tag标签Name:    "GoodsService",  //服务名称, 注册到服务发现(consul)的KPort:    8080, // 端口号: 需要与下面的监听, 指定 IP、port一致Address: "127.0.0.1",  // 当前微服务部署地址: 结合Port在consul设置为V: 需要与下面的监听, 指定 IP、port一致Check: &api.AgentServiceCheck{  //健康检测TCP:      "127.0.0.1:8080",  //前微服务部署地址,端口 : 需要与下面的监听, 指定 IP、port一致Timeout:  "5s",  // 超时时间Interval: "30s",  // 循环检测间隔时间},}//4、注册服务到consul上consulClient.Agent().ServiceRegister(&agentService)//1. 初始一个 grpc 对象grpcServer := grpc.NewServer()//2. 注册服务//helloService.RegisterGoodsServer(grpcServer, &Goods{})// &Hello{}和 new(Hello)相同goodsService.RegisterGoodsServer(grpcServer, new(Goods))//3. 设置监听, 指定 IP、portlistener, err := net.Listen("tcp", "127.0.0.1:8080")if err != nil {fmt.Println(err)}// 4退出关闭监听defer listener.Close()//5、启动服务grpcServer.Serve(listener)
}

效果展示:

运行该main..go
consul界面展示效果如下:

说明GoodsService微服务注册到了consul这个服务发现中了

(7).在客户端使用服务发现获取goods微服务相关

把上一节中的 goods grpc服务注册客户端代码修改一下,通过consul获取goods微服务相关,找到server/goods/main.go,编辑,增加了 consul服务相关代码,在连接服务器的时候,使用consul返回的微服务地址, 其它地方保存不变,代码如下:
package mainimport ("client/proto/goodsService""context""fmt""github.com/hashicorp/consul/api""google.golang.org/grpc""google.golang.org/grpc/credentials/insecure""strconv"
)func main() {//----------------------------consul相关---------------------------//初始化consul配置, 客户端服务器需要一致consulConfig := api.DefaultConfig()//设置consul服务器地址: 默认127.0.0.1:8500, 如果consul部署到其它服务器上,则填写其它服务器地址//consulConfig.Address = "127.0.0.1:8500"//2、获取consul操作对象consulClient, _ := api.NewClient(consulConfig)  //目前先屏蔽error,也可以获取error进行错误处理//3、获取consul服务发现地址,返回的ServiceEntry是一个结构体数组//参数说明:service:服务名称,服务端设置的那个Name, tag:标签,服务端设置的那个Tags,, passingOnly bool, q: 参数//serviceEntry, _, _ := consulClient.Health().Service("HelloService", "test", false, nil)//打印地址//fmt.Println(serviceEntry[0].Service.Address)//fmt.Println(serviceEntry[0].Service.Port)//拼接地址//strconv.Itoa: int转string型//address := serviceEntry[0].Service.Address + ":" + strconv.Itoa(serviceEntry[0].Service.Port)//----------------------------hello微服务相关------------------------------// 1、连接服务器/*credentials.NewClientTLSFromFile :从输入的证书文件中为客户端构造TLS凭证。grpc.WithTransportCredentials :配置连接级别的安全凭证(例如,TLS/SSL),返回一个DialOption,用于连接服务器。*///把上面拼接的地址放入下面//grpcClient, err := grpc.Dial(address, grpc.WithTransportCredentials(insecure.NewCredentials()))//if err != nil {//    fmt.Println(err)//}//2、注册客户端//client := helloService.NewHelloClient(grpcClient)//3、调用服务端函数, 实现HelloClient接口:SayHello()/*// HelloClient is the client API for Hello service.//// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.type HelloClient interface {// 通过rpc来指定远程调用的方法:// SayHello方法, 这个方法里面实现对传入的参数HelloReq, 以及返回的参数HelloRes进行约束SayHello(ctx context.Context, in *HelloReq, opts ...grpc.CallOption) (*HelloRes, error)}*///res, err1 := client.SayHello(context.Background(), &helloService.HelloReq{//    Name: "张三",//})//if err1 != nil {//    fmt.Printf("调用服务端代码失败: %s", err1)//    return//}////fmt.Printf("%#v\r\n", res)//fmt.Printf("调用成功: %s", res.Message)----------------------------goods微服务相关--------------------------//3、获取consul服务发现地址,返回的ServiceEntry是一个结构体数组//参数说明:service:服务名称,服务端设置的那个Name, tag:标签,服务端设置的那个Tags,, passingOnly bool, q: 参数serviceGoodsEntry, _, _ := consulClient.Health().Service("GoodsService", "test", false, nil)//打印地址fmt.Println(serviceGoodsEntry[0].Service.Address)fmt.Println(serviceGoodsEntry[0].Service.Port)//拼接地址//strconv.Itoa: int转string型addressGoods := serviceGoodsEntry[0].Service.Address + ":" + strconv.Itoa(serviceGoodsEntry[0].Service.Port)// 1、连接服务器/*credentials.NewClientTLSFromFile :从输入的证书文件中为客户端构造TLS凭证。grpc.WithTransportCredentials :配置连接级别的安全凭证(例如,TLS/SSL),返回一个DialOption,用于连接服务器。*/grpcGoodsClient, err := grpc.Dial(addressGoods, grpc.WithTransportCredentials(insecure.NewCredentials()))if err != nil {fmt.Println(err)}//2、注册客户端clientGoods := goodsService.NewGoodsClient(grpcGoodsClient)//增加res1, _ := clientGoods.AddGoods(context.Background(), &goodsService.AddGoodsReq{Goods: &goodsService.GoodsModel{Title:   "测试商品",Price:   20,Content: "测试商品的内容",},})fmt.Println(res1.Message)fmt.Println(res1.Success)//获取商品数据res2, _ := clientGoods.GetGoods(context.Background(), &goodsService.GetGoodsReq{})fmt.Printf("%#v", res2.GoodsList)for i := 0; i < len(res2.GoodsList); i++ {fmt.Printf("%#v\r\n", res2.GoodsList[i])}
}

(8).校验客户端-服务发现-服务端功能是否成功

启动consul

见上面操作

启动服务端

见上面操作

启动客户端

校验成功

(9).注销服务

func main(){//初始化consul配置,客户端服务器需要一致consulConfig := api.DefaultConfig()//获取consul操作对象registerClient,_ := api.NewClient(consulConfig)//注销服务ServiceDeregister(ServerID),ServerID: 微服务服务端服务发现idregisterClient.Agent().ServiceDeregister("1")
}

.consul集群,监控检查,服务发现

通过上面例子已经可以实现 注册服务发现服务了,下面给大家详细的讲解一下consul中的 服务端以及 客户端
  1. 简介

Consul 是 HashiCorp 公司推出的开源工具,用于实现 分布式系统的服务发现与配置,Consul 是 分布式的高可用的可横向扩展的,完成consul的安装后,必须运行 agent代理, agent可以运行为 server模式client模式
  • 服务模式(server模式): 主要参与维护集群状态响应RPC查询,与其他数据中心交换WAN gossip ,以及向上级或远程数据中心转发查询,并且会将数据持久化,推荐使用3到5台机器

  • 客户模式(client模式):客户模式下ConsulAgent是一个非常轻量级的进程,它消耗最小的资源开销和少量的网络带宽,提供注册服务运行健康检查,并将查询转发给服务器,客户端是相对无状态的,客户端执行的唯一后台活动是LANgossip池,不负责数据的持久化,客户模式不能单独存在,必须要有一个服务模式的Consul

  • 数据中心:一个数据中心由多个ServerClient模式Consul组成,多个数据中心通过WAN通信,每个数据中心(数据中心是一个大型的计算机系统集群,通常由成千上万台计算机、存储设备、网络设备、电源设备、冷却设备等组成,以提供高效、可靠的计算和存储能力,主要功能是提供云计算、虚拟化、存储和数据处理等服务,以满足企业、政府机构和个人的计算和数据存储需求,是现代企业和政府机构不可或缺的基础设施之一)至少必须拥有一台server,建议在一个集群中有3或者5个server,部署单一server,在出现失败时,会不可避免的出现数据丢失

图片上 datacenter 分成上下两个部分, 但是这两个部分又不是完全隔离的,他们之间通过 WAN GOSSIP 进行报文交互,单个 datacenter 中,节点被划分成两种颜色, 红色的 server, 紫色的 client, 他们之间通过 GRPC 进行通信(业务数据), 除此之外, Client 和 Server 之间通过还有一条 LAN Gosssip 进行通信,比如,当 Server 节点增加,或者 down 机后,Client 可以获取对应的 Server列表,去除或者增加 Server 列表,同一个 Consul agent 程序,启动的时候,通过制定不同的参数来运行 Server 和 Client 模式,也就是说 client 和 server 本质上都是 Client Agent
一个client是一个非常 轻量级的进程,用于 注册服务,运行 健康检查转发对server的查询,每个数据中心 至少必须拥有一个server,agent必须在集群中的每个主机上运行,
注意:
server也可以用于注册服务,比如前面运行的 consul agent -dev ,但是正式上线后一般 通过client注册服务,使用保存配置信息、实现高可用集群、通过广域网与其他数据中心通讯等

Server功能

  • 参与共识仲裁(raft)

  • 存储机器状态(日志存储)

  • 处理查询

  • 维护周边(LAN/WAN) 节点之间的关系

Client功能

  • 负责通过该节点注册到 Consul 微服务的健康检查

  • 将客户端的注册请求和查询转换为 server 的 RPC 请求

  • 维护周边各节点(LAN/WAN) 的关系

  1. Client-Server 模式

Consul 的架构升级为 client-Server 模式,服务注册不再向 Consul-Server进行注册,而是向服务所在机器的 Consul-client 进行注册,通过 Consul-Client 将注册信息同步 Consul-Server 机器中

  1. 纯 Server 模式

Zookeeper 就是这种模,client server 本质上都是 consul 的 agent, 只是 角色不同,架构图如下:
  1. 架构的问题

纯 server 模式架构的问题

高可用服务实例注册时配置的 consul-host 是负载均衡地址,服务注册到集群后,由集群中的一个节点负责对该实例进行健康检查,假如有这样的情况:服务A,服务B,都注册到 Service1 ,也就是由 Service1 对 服务A,服务B 进行健康检查,当 Service1 宕机时,这样会导致 服务A,服务B 在注册列表中消失,导致无法无法访问到,但是其实服务本身没有问题。服务注销:当服务从注册中心注销时,由于是负载均衡的,可能会导致服务注销失败,因为要在Service1 上注销,有可能负载均衡到 Service2 上进行注销,导致注销失败,解决的办法:遍历集群中所有节点进行注销

Client-Server 架构的问题

高可用服务实例向本级别 consul-client 进行注册,如果 consul-client 不可用,只影响 consul-client 所在机器的服务实例,不影响另外一台机器上的实例服务注销服务注销值需要在 consul-client 上进行注销,不需要经过负载均衡

  1. 基于 Client-Server架构服务注册时序图

服务端口

  • 8300: 只存在于Server模式,选取Leader节点(Raft协议),为Leader节点和Client节点的提供RPC调用

  • 8301: LAN网中集群数据同步的通信端口(Gossip协议),也是加入集群的通信端口

  • 8302: 只存在于Server模式,WAN网中集群数据同步的通信端口(Gossip协议),也是加入集群的通信端口,主要支持数据中心与数据中心之间交互通过WLAN(8302端口)

  • 8500: 提供Http服务(或web界面)

  • 8600: 提供DNS服务端口

8301和8302接口作用类似,主要区分在于8301用于LAN网络,8302用于WAN网络,它们都可以用于加入consul集群(数据中心一致就是在一个集群),将各数据中心连接则使用8302端口

实现原理

核心原理在于亮点:
  • 集群信息之间的高效同步机制,保障拓扑变动与控制信号的及时同步

  • server 集群内日志存储强一致性

他们主要基于两个协议来实现:
  • Gossip 协议,在集群内消息传递

  • 使用 raft 协议保障日志的一致性

案例讲解

架构图

步骤

(1).部署集群
首先需要有一个正常的Consul集群,有Server,有 Leader(主服务领导),这里在服务器Server1、Server2、Server3上分别部署了Consul Server
(2).选举Leader节点
假设选举了Server2上的 Consul Server 节点为Leader,这些服务器上最好只部署Consul程序,以尽量维护Consul Server的稳定
(3).注册服务
然后在服务器Server5和Server7上通过Consul Client分别注册Service A、B、C,这里每个Service 分别部署在了 两个服务器上,这样可以避免Service的 单点问题,服务注册到Consul可以通过 HTTP API(8500 端口)的方式,也可以通过 Consul 配置文件的方式
(4).Consul Client转发注册消息
Consul Client 可以认为是无状态的,它将注册信息通过 RPC转发到Consul Server,服务信息保存在Server的各个节点中,并且通过 Raft实现了 强一致性
(5).服务发起通信请求
最后在服务器Server6中Service D需要访问Service B,这时候Service D首先访问本机Consul Client提供的HTTP API,本机Client会将请求转发到 Consul Server,Consul Server查询到Service B当前的信息返回,最终Service D拿到了Service B的所有部署的IP和端口,然后就可以选择Service B的其中一个部署并向其发起请求了
  1. 集群配置

准备四个虚拟机,安装好consul等相关软件(安装见上面讲解),三个虚拟机作为服务端(ip参考:192.168.1.129,192.168.1.130,192.168.1.131,),一个作为客户端(ip参考:192.168.1.132), 虚拟机查询consul如下:

其他虚拟机也是一致的,进行集群配置测试操作后

(1).启动服务端

启动服务端命令如下:

$ consul agent -server -bootstrap-expect 3 -node=server_01 -
bind=192.168.1.129 -ui -data-dir=/root/usr/local/consul/data -client 0.0.0.0$ consul agent -server -bootstrap-expect 3 -node=server_02 -
bind=192.168.1.130 -ui -data-dir=/root/usr/local/consul/data -client 0.0.0.0$ consul agent -server -bootstrap-expect 3 -node=server_03 -
bind=192.168.1.131 -ui -data-dir=/root/usr/local/consul/data -client 0.0.0.0#额外参数:
-advertise=106.52.1.126 -datacenter=myDataCenter-CentOS  -enable-script-checks=true -config-dir=/etc/consul.d/consul.d -server-port=8300 -serf-lan-port=8301 -serf-wan-port=8302 -http-port=8500 -dns-port=8600 
需要先在/etc/下面创建consul.d目录,上面参数说明:
-server : 定义agent运行在 server模式,表示以Server模式启动,没有设置-server表示Client方式启动
-bootstrap-expect :在一个 datacenter(数据中心)中期望提供的server节点数目,当该值提供的时候, consul一直等到达到指定sever数目的时候才会引导整个集群,该标记不能和bootstrap,通俗来讲,就是 构成集群的最小数量
共用(注意:bootstrap-expect值必须是server的数量)
-bind :集群通信的ip,该地址用来在集群内部的通讯,集群内的所有节点到地址都必须是可达的,默认是0.0.0.0 ,表示所有ip
-node :节点在集群中的名称,在一个集群中必须是唯一的,默认是该节点的主机名
-ui : 启动web界面 :8500,启动后台管理,默认 http://ip:8500访问
-rejoin :使consul启动的时候加入集群中。
-config-dir :配置文件目录,里面所有以.json结尾的文件都会被加载
-client :consul服务侦听地址,这个地址提供HTTP、DNS、RPC等服务,默认是127.0.0.1所以不对外提供服务,如果要对外提供服务改成0.0.0.0, ,表示所有ip
data-dir :提供一个目录用来存放agent的状态,所有的agent允许都需要该目录,该目录
必须是稳定的,系统重启后都继续存在,通俗来讲就是 数据存放目录

额外参数
enable-script-checks=true: 允许使用脚本进行监控检查
advertise=IP: 告诉集群其他节点你通过这个ip来和我通信,默认使用bind绑定的ip
datacenter=dataCenterName: 数据中心名称
server-port=8300:选取Leader节点(raft协议通信)和提供RPC调用的
serf-lan-port=8301: 集群通信端口,用在LAN网
serf-wan-port=8302: 数据中心通信端口,用在WAN网
http-port=8500: 提供Http服务的端口
dns-port=8600: 提供Dns服务的端口

(2).启动客户端

运行cosnul agent以client模式
$ consul agent -data-dir=/root/usr/local/consul/data -node=client-01 -
bind=192.168.1.132 -ui -client 0.0.0.0

(3).关联集群

以server-01为Leader,分别在server-02、server-03、client-01节点上面运行下面命令建立集群关系
consul join 192.168.1.129
注意:分别 关闭对应服务器的防火墙(systemctl stop firewalld),或者允许对应端口

(4).具体操作

启动服务端

把下面命令分别在对应虚拟机上运行

上面三条命令分别在对应虚拟机运行成功后,再启动客户端

启动客户端

把下面命令分别在对应虚拟机上运行

操作完后,三台服务端,一台客户端就启动完成了,

关联

以server-01(192.168.1.129)为Leader,分别在server-02、server-03、client-01节点上面运行下面命令建立集群关系, consul join 192.168.1.129
consul join 192.168.1.129

这样以server-01为Leader的集群就创建好了,浏览器打开web ui,可以看见:在server-01的服务器上,关联了三个服务(2个服务端,1个客户端),图示如下:

好了,集群就搭建好了

(5).查看consul成员和集群状态

consul members
节点 网络地址 状态 类型 版本 协议 数据中心 分管部分
Node Address Status Type Build Protocol DC Partition Segment

  1. Consul集群实现微服务

以上面代码为案例,先注册服务到sever里面,把Hello微服务注册到server-03这个consul中,代码只需修改consulConfig.Address=192.138.1.132,以及Hello微服务启动的地址,比如把127.0.0.1修改为本机地址192.168.1.111,这样才能让server-03和微服务服务器通讯,Goods微服务也类似操作

注意:需要配置consul集群地址,其中 consulConfig.Address = "192.168.234.132:8500" 为集群客户端地址 AgentServiceRegistration 中的地址需要和当前程序运行服务器的地址统一起来
package mainimport ("context""fmt""net""google.golang.org/grpc""github.com/hashicorp/consul/api""serverHello/proto/helloService"
)//rpc远程调用的接口,需要实现hello.proto中定义的Hello服务接口,以及里面的方法
//1.定义远程调用的结构体和方法,这个结构体需要实现HelloServer的接口type Hello struct{}//SayHello方法参考hello.pb.go中的接口
/*
// HelloServer is the server API for Hello service.
type HelloServer interface {// 通过rpc来指定远程调用的方法:// SayHello方法, 这个方法里面实现对传入的参数HelloReq, 以及返回的参数HelloRes进行约束SayHello(context.Context, *HelloReq) (*HelloRes, error)
}*/
func (this Hello) SayHello(c context.Context, req *helloService.HelloReq) (*helloService.HelloRes, error) {fmt.Println(req)return &helloService.HelloRes{Message: "你好" + req.Name,}, nil
}func main() {//------------------------- consul服务相关----------------------//注册consul服务//1、初始化consul配置consulConfig := api.DefaultConfig()//设置consul服务器地址: 默认127.0.0.1:8500, 如果consul部署到其它服务器上,则填写其它服务器地址 consulConfig.Address = "192.168.1.132:8500"//2、获取consul操作对象consulClient, _ := api.NewClient(consulConfig)// 3、配置注册服务的参数agentService := api.AgentServiceRegistration{ID:      "1",  // 服务id,顺序填写即可Tags:    []string{"test"},  // tag标签Name:    "HelloService",  //服务名称, 注册到服务发现(consul)的KPort:    8082, // 端口号: 需要与下面的监听, 指定 IP、port一致Address: "192.1678.1.111",  // 当前微服务部署地址: 结合Port在consul设置为V: 需要与下面的监听, 指定 IP、port一致Check: &api.AgentServiceCheck{  //健康检测TCP:      "192.1678.1.111:8082",  //前微服务部署地址,端口 : 需要与下面的监听, 指定 IP、port一致Timeout:  "5s",  // 超时时间Interval: "30s",  // 循环检测间隔时间},}//4、注册服务到consul上consulClient.Agent().ServiceRegister(&agentService)//------------------------- grpc相关----------------------//1. 初始一个 grpc 对象grpcServer := grpc.NewServer()//2. 注册服务//helloService.RegisterHelloServer(grpcServer, &Hello{})// &Hello{}和 new(Hello)相同helloService.RegisterHelloServer(grpcServer, new(Hello))//3. 设置监听, 指定 IP、portlistener, err := net.Listen("tcp", "192.1678.1.111:8082")if err != nil {fmt.Println(err)}// 4退出关闭监听defer listener.Close()//5、启动服务grpcServer.Serve(listener)
}

修改完后,和上面启动微服务操作一致,启动完后,查看,如下:Leader上已经注册好了相关微服务了

然后修改微服务客服端代码,让consulConfig.Address = "192.168.1.132:8500"(一般连接的是consul客户端),这样就访问到consul的客户端client-01了,从客户端就可以获取微服务对应数据了

  1. 退出集群

可以使用 Ctrl-C 优雅的关闭Agent,中断Agent之后可以看到服务离开了集群并关闭,在退出中,Consul提醒其他集群成员,这个节点离开了,如果强行杀掉进程,集群的其他成员应该能检测到这个节点失效了,当一个成员离开,他的服务和检测也会从目录中移除,当一个成员失效了,他的健康状况被简单的标记为危险,但是不会从目录中移除,Consul会 自动尝试对失效的节点进行重连,允许他从某些网络条件下恢复过来,离开的节点则不会再继续联系,此外,如果一个agent作为一个服务器,一个优雅的离开是很重要的,可以避免引起潜在的可用性故障影响达成一致性协议
停止server-01 测试程序是否正常,在对应consul服务优雅的退出运行命令 consul leave即可

然后使用命令consul members在其他三台consul服务器上查看server-01是否停止

server-01停止了,在浏览器上,consul web server-01查询,发现打不开了

而在其他server consul web ui 上可以打开,并且Leader已经发生变化(因为server-01停止了), 这样就实现了负载均衡操作,客户端访问微服务就不会挂掉

上面讲解的是一个客户端的案例,当然也可以一个微服务对应一个客户端,这样当一个服务器挂掉的话,就只会影响一个微服务,其他的微服务不会受到影响

[上一节][golang 微服务] 4. gRPC介绍,Protobuf结合gRPC 创建微服务

相关文章:

[golang 微服务] 5. 微服务服务发现介绍,安装以及consul的使用,Consul集群

一.服务发现介绍 引入 上一节讲解了使用 gRPC创建微服务,客户端的一个接口可能需要调用 N个服务,而不同服务可能存在 不同的服务器,这时&#xff0c;客户端就必须知道所有服务的 网络位置&#xff08;ipport&#xff09;&#xff0c;来进行连接服务器操作,如下图所示: 以往的做…...

【数据结构】哈希应用

目录 一、位图 1、位图概念 2、位图实现 2.1、位图结构 2.2、比特位置1 2.3、比特位置0 2.4、检测位图中比特位 3、位图例题 3.1、找到只出现一次的整数 3.2、找到两个文件交集 3.3、找到出现次数不超过2次的所有整数 二、布隆过滤器 1、布隆过滤器提出 2、布隆过…...

【 Python 全栈开发 - WEB开发篇 - 31 】where条件查询

文章目录 一、where条件查询1.关系运算符查询2.IN关键字查询3.BETWEEN AND关键字查询4.空值查询5.AND关键字查询6.OR关键字查询7.LIKE关键字查询普通字符串含有%通配的字符串含有_通配的字符串 一、where条件查询 MySQL 的 where 条件查询是指在查询数据时&#xff0c;通过 wh…...

Android系统的Ashmem匿名共享内存子系统分析(5)- 实现共享的原理

声明 其实对于Android系统的Ashmem匿名共享内存系统早就有分析的想法&#xff0c;记得2019年6、7月份Mr.Deng离职期间约定一起对其进行研究的&#xff0c;但因为我个人问题没能实施这个计划&#xff0c;留下些许遗憾…文中参考了很多书籍及博客内容&#xff0c;可能涉及的比较…...

谈一谈冷门的C语言爬虫

C语言可以用来编写爬虫程序&#xff0c;但是相对于其他编程语言&#xff0c;C语言的爬虫开发可能会更加复杂和繁琐。因为C语言本身并没有提供现成的爬虫框架和库&#xff0c;需要自己编写网络请求、HTML解析等功能。 不过&#xff0c;如果你对C语言比较熟悉&#xff0c;也可以…...

基于状态的维护(CBM)如何推动设备效率提高?

基于状态的维护&#xff08;Condition-Based Maintenance&#xff0c;CBM&#xff09;是一种先进的维护策略&#xff0c;通过实时监测和分析设备的状态数据&#xff0c;预测设备故障并采取相应的维护措施。CBM基于数据驱动的方法&#xff0c;能够提高设备的可用性、降低维修成本…...

DC LAB8SDC约束四种时序路径分析

DC LAB 1.启动DC2.读入设计3. 查看所有违例的约束报告3.1 report_constraint -all_violators (alias rc)3.2 view report_constraint -all_violators -verbose -significant_digits 4 (打印详细报告) 4.查看时序报告 report_timing -significant_digits 45. 约束组合逻辑(adr_i…...

学生考试作弊检测系统 yolov8

学生考试作弊检测系统采用yolov8网络模型人工智能技术&#xff0c;学生考试作弊检测系统过在考场中安装监控设备&#xff0c;对学生的作弊行为进行实时监测。当学生出现作弊行为时&#xff0c;学生考试作弊检测系统将自动识别并记录信息。YOLOv8 算法的核心特性和改动可以归结为…...

【基于容器的部署、扩展和管理】 3.2 基于容器的应用程序部署和升级

往期回顾&#xff1a; 第一章&#xff1a;【云原生概念和技术】 第二章&#xff1a;【容器化应用程序设计和开发】 第三章&#xff1a;【3.1 容器编排系统和Kubernetes集群的构建】 3.2 基于容器的应用程序部署和升级 3.2 基于容器的应用程序部署和升级 3.2 基于容器的应用程…...

Jmeter 实现 grpc服务 压测

一、Jmeter安装与配置 网上有很多安装与配置文章&#xff0c;在此不做赘述 二、Jmeter gRPC Request 插件安装 插件下载地址&#xff1a;JMeter Plugins :: JMeter-Plugins.org 将下载文件解压后放到Jmeter安装目录下 /lib/ext 然后在终端输入Jmeter即可打开 Jmeter GUI界面…...

深入源码分析RecyclerView缓存复用原理

文章目录 前言四级缓存 源码分析缓存一级缓存&#xff08;mChangedScrap和mChangedScrap&#xff09;二级缓存&#xff08;mCachedViews&#xff09;三级缓存&#xff08;ViewCacheExtension&#xff09;四级缓存&#xff08;mRecyclerPool&#xff09;缓存池mRecyclerPool结构…...

内网隧道代理技术(一)之内网隧道代理概述

内网隧道代理技术 内网转发 在渗透测试中&#xff0c;当我们获得了外网服务器&#xff08;如web服务器&#xff0c;ftp服务器&#xff0c;mali服务器等等&#xff09;的一定权限后发现这台服务器可以直接或者间接的访问内网。此时渗透测试进入后渗透阶段&#xff0c;一般情况…...

设计图形用户界面的原则

1) 一般性原则&#xff1a;界面要具有一致性、常用操作要有快捷方式、 提供简单的错误处理、对操作人员的重要操作要有信息反馈、操作可 逆、设计良好的联机帮助、合理划分并高效地使用显示屏、保证信息 显示方式与数据输入方式的协调一致 2) 颜色的使用&#xff1a;颜色…...

1:操作系统导论

1.1操作系统的定义 •Anoperatingsystemactsanintermediarybetweenuserofacomputerandthecomputer hardware. ◦ 操作系统充当计算机⽤⼾和计算机硬件之间的中介 •Thepurposeofanoperatingsystemistoprovideanenvironmentinwhichausercanexecute programsinaconvenientandeff…...

什么是微软的 Application Framework?

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天来看一下什么是微软的 Application Framework&#xff1f; 到底什么是 Application Framework&#xff1f; 还没有真正掌握任何一套Application Framework的使用之前&#xff0c;就来研究这个真的不是很…...

一个关于宏定义的问题,我和ChatGPT、NewBing、Google Bard、文心一言 居然全军覆没?

文章目录 一、问题重述二、AI 解题2.1 ChatGPT2.2 NewBing2.3 Google Bard2.4 文心一言2.5 小结 一、问题重述 今天在问答模块回答了一道问题&#xff0c;要睡觉的时候&#xff0c;又去看了一眼&#xff0c;发现回答错了。 问题描述&#xff1a;下面的z的值是多少。 #define…...

【服务器数据恢复】断电导致RAID无法找到存储设备的数据恢复案例

服务器数据恢复环境&#xff1a; HP EVA存储&#xff0c;6块SAS硬盘组建的raid5磁盘阵列。上层操作系统是WINDOWS SERVER。该存储为公司内部文件服务器使用。 服务器故障&分析&#xff1a; 在遭遇两次意外断电后&#xff0c;设备重启时raid提示“无法找到存储设备”。管理员…...

Windows上不可或缺的5款宝藏软件,工作效率拉满!

职场小白与大牛的区别&#xff1a;小白需要耗费大半天琢磨的事情&#xff0c;而大牛可以只花5分钟就能处理。 “牛人”&#xff0c;即拥有过人之处&#xff0c;专业、经验、技术等等&#xff0c;学会灵活运用高效率的工具也是关键的一点。工具找得好&#xff0c;运用得快&#…...

链表内指定区间反转

题目&#xff1a; 将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转&#xff0c;要求时间复杂度 O(n)&#xff0c;空间复杂度 O(1)。 例如&#xff1a; 给出的链表为 1→2→3→4→5→NULL&#xff0c;m2&#xff0c;n4 返回 1→4→3→2→5→NULL 数据范围&#xff…...

Vue中如何进行地图展示与交互(如百度地图、高德地图)?

Vue中如何进行地图展示与交互 随着移动互联网的普及&#xff0c;地图应用已经成为人们生活中不可或缺的一部分。在Vue.js中&#xff0c;我们可以使用第三方地图库&#xff08;如百度地图、高德地图&#xff09;来实现地图的展示和交互。本文将介绍如何在Vue.js中使用百度地图和…...

uni-app组件概述

1、组件 1.1、组件的含义 组件是视图层的基本组成单元。 组件是一个单独且可复用的功能模块的封装。 组件&#xff0c;包括&#xff1a;以组件名称为标记的开始标签和结束标签、组件内容、组件属性、组件属性值。 <component-name>是开始标签&#xff0c;</compon…...

什么是防火墙?它有什么作用?

作者&#xff1a;Insist-- 个人主页&#xff1a;insist--个人主页 作者会持续更新网络知识和python基础知识&#xff0c;期待你的关注 目录 一、什么是防火墙 二、防火墙的分类 1、软件防火墙 2、硬件防火墙 三、防火墙的作用 1、防止病毒 2、防止访问不安全内容 3、阻…...

基础工程(cubeide串口调试,printf实现,延时函数)

0.基础工程&#xff08;cubeide串口调试&#xff0c;printf实现&#xff0c;延时函数&#xff09; 文章目录 0.基础工程&#xff08;cubeide串口调试&#xff0c;printf实现&#xff0c;延时函数&#xff09;外部时钟源CLOCK(RCC)系统时钟SYS与DEBUG设置UART串口设置cubeide设置…...

大厂设计师都在用的9个灵感工具

每一件伟大的设计作品都离不开设计师灵感的爆发。设计师有很多灵感来源&#xff0c;比如精美的摄影图片、酷炫的网站设计、APP的特色功能、友好的用户体验动画&#xff0c;或者一篇文章。 设计师每天都需要收集灵感&#xff0c;把灵感收集当成日常生活。在这篇文章中&#xff…...

安全实现SpringBoot配置文件自动加解密

需求背景 应用程序开发的时候&#xff0c;往往会存在一些敏感的配置属性 数据库账号、密码第三方服务账号密码内置加密密码其他的敏感配置 对于安全性要求比较高的公司&#xff0c;往往不允许敏感配置以明文的方式出现。 通常做法是对这些敏感配置进行加密&#xff0c;然后在…...

数据结构--队列2--双端队列--java双端队列

介绍 双端队列&#xff0c;和前面学的队列和栈的区别在于双端队列2端都可以进行增删&#xff0c;其他2个都是只能一端可以增/删。 实现 链表 因为2端都需要可以操作所以我们使用双向链表 我们也需要一共头节点 所以节点设置 static class Node<E>{E value;Node<E…...

网络安全:信息收集专总结【社会工程学】

前言 俗话说“渗透的本质也就是信息收集”&#xff0c;信息收集的深度&#xff0c;直接关系到渗透测试的成败&#xff0c;打好信息收集这一基础可以让测试者选择合适和准确的渗透测试攻击方式&#xff0c;缩短渗透测试的时间。 一、思维导图 二、GoogleHacking 1、介绍 利用…...

Linux 命令总结

基本操作 Linux关机,重启 # 关机 shutdown -h now# 重启 shutdown -r now 查看系统,CPU信息 # 查看系统内核信息 uname -a# 查看系统内核版本 cat /proc/version# 查看当前用户环境变量 envcat /proc/cpuinfo# 查看有几个逻辑cpu, 包括cpu型号 cat /proc/cpuinfo | grep na…...

使用腾讯手游助手作为开发测试模拟器的方案---以及部分问题的解决方案

此文主要介绍使用第三方模拟器(这里使用腾讯手游助手)作为开发工具&#xff0c;此模拟器分为两个引擎&#xff0c;一个与其他模拟器一样基于virtualbox的标准引擎&#xff0c;不过优化不太好&#xff0c;一个是他们主推的aow引擎&#xff0c;此引擎。关于aow没有太多的技术资料…...

牛客网论坛最具争议的Linux内核成神笔记,GitHub已下载量已过百万

原文地址&#xff1a;牛客网论坛最具争议的Linux内核成神笔记&#xff0c;GitHub已下载量已过百万 1、前言 Linux内核是一个操作系统&#xff08;OS&#xff09;内核&#xff0c;本质上定义为类Unix。它用于不同的操作系统&#xff0c;主要是以不同的Linux发行版的形式。Linu…...

网站建设的工作总结/百度信息流广告

现有模型 在pytorch官网有很多模型 现有网络模型的使用 以vgg16为例 代码示例&#xff1a; import torchvision.datasets#因为数据集现在不能用这种方式下载了&#xff0c;只能手动下载 #train_data torchvision.datasets.ImageNet("../data_image", splittrain,…...

网页设计与网站建设指标点/镇江网站seo

我们很容易被漂亮的代码吸引&#xff0c;也不知不觉的在自己的代码库中加入这些。却没有冷静的想过它们的优劣。这不&#xff0c;我就收集了一系列形如 “是否为……&#xff1f;” 的判断的boolean函数。 isNull: function(a){return a null; }, isUndefined: function(a){re…...

合肥做机床的公司网站/重庆网站seo公司

我试图从WooCommerce中的特定产品类别获取购物车中的商品数量.我正在为酿酒厂做一个网站.它含有酒精和非酒精产品.所有的葡萄酒都属于’葡萄酒’或类别ID 34的主要类别,其下有许多子类别和产品.对于任何属于此类别的东西……我需要知道此类别下购物车中有多少件物品.如果有六瓶…...

安装wordpress导入工具/长沙关键词优化新报价

分享一个大牛的人工智能教程。零基础&#xff01;通俗易懂&#xff01;风趣幽默&#xff01;希望你也加入到人工智能的队伍中来&#xff01;请轻击http://www.captainbed.net package live.every.day.Programming.Array;/*** 题目&#xff1a;* 转圈打印矩阵。** 思路&#xf…...

网络营销的主要内容是什么/搜索关键词排名优化

为了让我们的信息能够有效地沟通&#xff0c;我们需要创建用户和我们的媒体之间的强有力的联系。今天我们就来探讨在网络上呈现故事的新方法&#xff0c;并为此创造了一个开源和免费使用的 JavaScript 库称为 space.js。该库是 HTML 驱动的&#xff0c;这意味着你不需要在网站上…...

长页在线制作网站/创建软件平台该怎么做

在写上篇文章《spring整合springmvc和hibernate》的时候&#xff0c;曾遇到一个问题 INFO: Server startup in 8102 ms Hibernate: insert into t_user (name, password) values (?, ?) Mar 31, 2018 5:47:19 PM org.apache.catalina.core.StandardWrapperValve invoke SEVER…...