利用go-kit组件进行服务注册与发现和健康检查的操作
来源:脚本之家
时间:2023-01-07 12:16:22 489浏览 收藏
本篇文章给大家分享《利用go-kit组件进行服务注册与发现和健康检查的操作》,覆盖了Golang的常见基础知识,其实一个语言的全部知识点一篇文章是不可能说完的,但希望通过这些问题,让读者对自己的掌握程度有一定的认识(B 数),从而弥补自己的不足,更好的掌握它。
在go的微服务架构中
使用go-kit组件进行开发微服务
type Reg struct { Host string Port int Client consul.Client } func MakeReg (host string , port int) (*Reg , error) { reg := api.DefaultConfig() reg.Address = host + ":" + strconv.Itoa(port) apiclient , err = api.NewClient(reg) if err != nil { return nil , err } client := consul.NewClient(apiclient) return &Reg{Host : host , Port : port ,Client : client} , nil } func (r Reg) Resiter (servicename , tag , host , seviceid ,checkinter ,healthcheckhttp ,deregisterafter string , port int) bool { congig := api.AgentServiceRegistration{ Port : port , Address : host , Name := servicename, ID := serviceid, Ckeck : &api.AgentServiceCheck{ Interval : checkinter, HTTP : "http://" + host + ":" + healthcheckhttp , DeregisterCriticalServiceAfter : deregisterafter, } } if err := r.Client.Register(&config) ; err != nil { fmt.Println(err) return false } return true } func (r Reg) Deregister (serviceid string) bool { dreg := api.AgentServiceRegistration{ID : serviceid} if err != r.Client.Deregister(&config) ; err != nil { fmt.Println(err) return false } return true } func (r Reg) discover (servicename , tag string ,passingonly bool) ( []*api.ServiceEntry ,error ) { if entries ,_ ,err := r.Client.Service(servicename , tag , passingonly , nil) ;err != nil { return nil ,err }else{ return entries , nil } }
补充:go-kit 与 grpc 结合实现注册发现与负载均衡
介绍
grpc提供了简单的负载均衡,需要自己实现服务发现resolve。我们既然要使用go-kit来治理微服务,那么我们就使用go-kit的注册发现、负载均衡机制。
go-kit官方【stringsvc3】例子中使用的负载均衡方案是通过服务端转发进行,翻找下源码go-kit的服务注册发现、负载均衡在【sd】包中。下面我们介绍怎么通过go-kit进行客户端负载均衡。
go-kit提供的注册中心
1、 etcd
2、 consul
3、 eureka
4、 zookeeper
go-kit提供的负载均衡
1、 random[随机]
2、 roundRobin[轮询]
只需实现Balancer接口,我们可以很容易的增加其它负载均衡机制
type Balancer interface { Endpoint() (endpoint.Endpoint, error) }
etcd注册发现
etcd和zookeeper类似是一个高可用、强一致性的存储仓库,拥有服务发现功能。 我们就通过go-kit提供的etcd包来实现服务注册发现
服务端代码
服务注册
1、连接注册中心
2、注册当前服务
var ( //etcd服务地址 etcdServer = "127.0.0.1:2379" //服务的信息目录 prefix = "/services/book/" //当前启动服务实例的地址 instance = "127.0.0.1:50052" //服务实例注册的路径 key = prefix + instance //服务实例注册的val value = instance ctx = context.Background() //服务监听地址 serviceAddress = ":50052" ) //etcd的连接参数 options := etcdv3.ClientOptions{ DialTimeout: time.Second * 3, DialKeepAlive: time.Second * 3, } //创建etcd连接 client, err := etcdv3.NewClient(ctx, []string{etcdServer}, options) if err != nil { panic(err) } // 创建注册器 registrar := etcdv3.NewRegistrar(client, etcdv3.Service{ Key: key, Value: value, }, log.NewNopLogger()) // 注册器启动注册 registrar.Register()
完整代码
package main import ( "grpc-test/pb" "context" grpc_transport "github.com/go-kit/kit/transport/grpc" "github.com/go-kit/kit/endpoint" "google.golang.org/grpc" "net" "github.com/go-kit/kit/sd/etcdv3" "github.com/go-kit/kit/log" "time" ) type BookServer struct { bookListHandler grpc_transport.Handler bookInfoHandler grpc_transport.Handler } //通过grpc调用GetBookInfo时,GetBookInfo只做数据透传, 调用BookServer中对应Handler.ServeGRPC转交给go-kit处理 func (s *BookServer) GetBookInfo(ctx context.Context, in *book.BookInfoParams) (*book.BookInfo, error) { _, rsp, err := s.bookInfoHandler.ServeGRPC(ctx, in) if err != nil { return nil, err } return rsp.(*book.BookInfo),err } //通过grpc调用GetBookList时,GetBookList只做数据透传, 调用BookServer中对应Handler.ServeGRPC转交给go-kit处理 func (s *BookServer) GetBookList(ctx context.Context, in *book.BookListParams) (*book.BookList, error) { _, rsp, err := s.bookListHandler.ServeGRPC(ctx, in) if err != nil { return nil, err } return rsp.(*book.BookList),err } //创建bookList的EndPoint func makeGetBookListEndpoint() endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { //请求列表时返回 书籍列表 bl := new(book.BookList) bl.BookList = append(bl.BookList, &book.BookInfo{BookId:1,BookName:"21天精通php"}) bl.BookList = append(bl.BookList, &book.BookInfo{BookId:2,BookName:"21天精通java"}) return bl,nil } } //创建bookInfo的EndPoint func makeGetBookInfoEndpoint() endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { //请求详情时返回 书籍信息 req := request.(*book.BookInfoParams) b := new(book.BookInfo) b.BookId = req.BookId b.BookName = "21天精通php" return b,nil } } func decodeRequest(_ context.Context, req interface{}) (interface{}, error) { return req, nil } func encodeResponse(_ context.Context, rsp interface{}) (interface{}, error) { return rsp, nil } func main() { var ( //etcd服务地址 etcdServer = "127.0.0.1:2379" //服务的信息目录 prefix = "/services/book/" //当前启动服务实例的地址 instance = "127.0.0.1:50052" //服务实例注册的路径 key = prefix + instance //服务实例注册的val value = instance ctx = context.Background() //服务监听地址 serviceAddress = ":50052" ) //etcd的连接参数 options := etcdv3.ClientOptions{ DialTimeout: time.Second * 3, DialKeepAlive: time.Second * 3, } //创建etcd连接 client, err := etcdv3.NewClient(ctx, []string{etcdServer}, options) if err != nil { panic(err) } // 创建注册器 registrar := etcdv3.NewRegistrar(client, etcdv3.Service{ Key: key, Value: value, }, log.NewNopLogger()) // 注册器启动注册 registrar.Register() bookServer := new(BookServer) bookListHandler := grpc_transport.NewServer( makeGetBookListEndpoint(), decodeRequest, encodeResponse, ) bookServer.bookListHandler = bookListHandler bookInfoHandler := grpc_transport.NewServer( makeGetBookInfoEndpoint(), decodeRequest, encodeResponse, ) bookServer.bookInfoHandler = bookInfoHandler ls, _ := net.Listen("tcp", serviceAddress) gs := grpc.NewServer(grpc.UnaryInterceptor(grpc_transport.Interceptor)) book.RegisterBookServiceServer(gs, bookServer) gs.Serve(ls) }
客户端代码
客户端流程
1、 连接注册中心
2、 获取提供的服务
3、 监听服务目录变化,目录变化更新本地缓存
4、 创建负载均衡器
5、 获取请求的 endPoint
完整代码
package main import ( "context" "github.com/go-kit/kit/sd/etcdv3" "time" "github.com/go-kit/kit/sd" "github.com/go-kit/kit/log" "github.com/go-kit/kit/endpoint" "io" "github.com/go-kit/kit/sd/lb" "grpc-test/pb" "fmt" "google.golang.org/grpc" ) func main() { var ( //注册中心地址 etcdServer = "127.0.0.1:2379" //监听的服务前缀 prefix = "/services/book/" ctx = context.Background() ) options := etcdv3.ClientOptions{ DialTimeout: time.Second * 3, DialKeepAlive: time.Second * 3, } //连接注册中心 client, err := etcdv3.NewClient(ctx, []string{etcdServer}, options) if err != nil { panic(err) } logger := log.NewNopLogger() //创建实例管理器, 此管理器会Watch监听etc中prefix的目录变化更新缓存的服务实例数据 instancer, err := etcdv3.NewInstancer(client, prefix, logger) if err != nil { panic(err) } //创建端点管理器, 此管理器根据Factory和监听的到实例创建endPoint并订阅instancer的变化动态更新Factory创建的endPoint endpointer := sd.NewEndpointer(instancer, reqFactory, logger) //创建负载均衡器 balancer := lb.NewRoundRobin(endpointer) /** 我们可以通过负载均衡器直接获取请求的endPoint,发起请求 reqEndPoint,_ := balancer.Endpoint() */ /** 也可以通过retry定义尝试次数进行请求 */ reqEndPoint := lb.Retry(3, 3*time.Second, balancer) //现在我们可以通过 endPoint 发起请求了 req := struct{}{} if _, err = reqEndPoint(ctx, req); err != nil { panic(err) } } //通过传入的 实例地址 创建对应的请求endPoint func reqFactory(instanceAddr string) (endpoint.Endpoint, io.Closer, error) { return func(ctx context.Context, request interface{}) (interface{}, error) { fmt.Println("请求服务: ", instanceAddr) conn, err := grpc.Dial(instanceAddr, grpc.WithInsecure()) if err != nil { fmt.Println(err) panic("connect error") } defer conn.Close() bookClient := book.NewBookServiceClient(conn) bi,_:=bookClient.GetBookInfo(context.Background(),&book.BookInfoParams{BookId:1}) fmt.Println("获取书籍详情") fmt.Println("bookId: 1", " => ", "bookName:", bi.BookName) bl,_ := bookClient.GetBookList(context.Background(), &book.BookListParams{Page:1, Limit:10}) fmt.Println("获取书籍列表") for _,b := range bl.BookList { fmt.Println("bookId:", b.BookId, " => ", "bookName:", b.BookName) } return nil,nil },nil,nil }
测试
请求测试
请求服务: 127.0.0.1:50052 获取书籍详情 bookId: 1 => bookName: 21天精通php 获取书籍列表 bookId: 1 => bookName: 21天精通php bookId: 2 => bookName: 21天精通java
负载均衡测试
1、 修改server的注册监听端口,启动多个server
instance = "127.0.0.1:50052" serviceAddress = ":50052"
2、client发起多次请求
req := struct{}{} for i := 1; i通过返回结果中记录的请求地址,我们可以看到已经按照轮询的方式请求不同的微服务实例。
请求服务: 127.0.0.1:50051 获取书籍详情 bookId: 1 => bookName: 21天精通php 获取书籍列表 bookId: 1 => bookName: 21天精通php bookId: 2 => bookName: 21天精通java 请求服务: 127.0.0.1:50052 获取书籍详情 bookId: 1 => bookName: 21天精通php 获取书籍列表 bookId: 1 => bookName: 21天精通php bookId: 2 => bookName: 21天精通java 请求服务: 127.0.0.1:50051 获取书籍详情 bookId: 1 => bookName: 21天精通php 获取书籍列表 bookId: 1 => bookName: 21天精通php bookId: 2 => bookName: 21天精通java 请求服务: 127.0.0.1:50052 获取书籍详情 bookId: 1 => bookName: 21天精通php 获取书籍列表 bookId: 1 => bookName: 21天精通php bookId: 2 => bookName: 21天精通java 请求服务: 127.0.0.1:50051 获取书籍详情 bookId: 1 => bookName: 21天精通php 获取书籍列表 bookId: 1 => bookName: 21天精通php bookId: 2 => bookName: 21天精通java 请求服务: 127.0.0.1:50052 获取书籍详情 bookId: 1 => bookName: 21天精通php 获取书籍列表 bookId: 1 => bookName: 21天精通php bookId: 2 => bookName: 21天精通java 请求服务: 127.0.0.1:50051 获取书籍详情 bookId: 1 => bookName: 21天精通php 获取书籍列表 bookId: 1 => bookName: 21天精通php bookId: 2 => bookName: 21天精通java 请求服务: 127.0.0.1:50052 获取书籍详情 bookId: 1 => bookName: 21天精通php 获取书籍列表 bookId: 1 => bookName: 21天精通php bookId: 2 => bookName: 21天精通java Process finished with exit code 0以上为个人经验,希望能给大家一个参考,也希望大家多多支持golang学习网。如有错误或未考虑完全的地方,望不吝赐教。
好了,本文到此结束,带大家了解了《利用go-kit组件进行服务注册与发现和健康检查的操作》,希望本文对你有所帮助!关注golang学习网公众号,给大家分享更多Golang知识!
-
482 收藏
-
230 收藏
-
367 收藏
-
128 收藏
-
236 收藏
-
340 收藏
-
298 收藏
-
249 收藏
-
460 收藏
-
495 收藏
-
365 收藏
-
369 收藏
-
194 收藏
-
213 收藏
-
382 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 508次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习
-
- 英勇的玉米
- 这篇文章内容真及时,太全面了,太给力了,码住,关注大佬了!希望大佬能多写Golang相关的文章。
- 2023-02-17 01:39:04
-
- 魔幻的大象
- 太细致了,已加入收藏夹了,感谢老哥的这篇文章,我会继续支持!
- 2023-02-06 03:57:41
-
- 踏实的长颈鹿
- 这篇技术贴太及时了,细节满满,感谢大佬分享,收藏了,关注大佬了!希望大佬能多写Golang相关的文章。
- 2023-02-02 09:46:59
-
- 曾经的项链
- 这篇博文出现的刚刚好,细节满满,写的不错,码住,关注师傅了!希望师傅能多写Golang相关的文章。
- 2023-01-17 08:56:44
-
- 单身的音响
- 赞 👍👍,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,帮助很大,总算是懂了,感谢博主分享文章内容!
- 2023-01-16 16:54:44
-
- 冷傲的诺言
- 受益颇多,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢大佬分享技术贴!
- 2023-01-08 04:40:56