- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章利用go-kit组件进行服务注册与发现和健康检查的操作由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
在go的微服务架构中 。
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
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接口,我们可以很容易的增加其它负载均衡机制 。
1
2
3
|
type Balancer interface {
Endpoint() (endpoint.Endpoint, error)
}
|
etcd注册发现 。
etcd和zookeeper类似是一个高可用、强一致性的存储仓库,拥有服务发现功能。 我们就通过go-kit提供的etcd包来实现服务注册发现 。
。
服务注册 。
1、连接注册中心 。
2、注册当前服务 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
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()
|
完整代码 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
|
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 。
完整代码 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
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
}
|
。
请求测试 。
1
2
3
4
5
6
|
请求服务: 127.0.0.1:50052
获取书籍详情
bookId: 1 => bookName: 21天精通php
获取书籍列表
bookId: 1 => bookName: 21天精通php
bookId: 2 => bookName: 21天精通java
|
负载均衡测试 。
1、 修改server的注册监听端口,启动多个server 。
1
2
|
instance = "127.0.0.1:50052"
serviceAddress = ":50052"
|
2、client发起多次请求 。
1
2
3
4
5
6
|
req := struct{}{}
for i := 1; i <= 8; i++ {
if _, err = reqEndPoint(ctx, req); err != nil {
panic(err)
}
}
|
通过返回结果中记录的请求地址,我们可以看到已经按照轮询的方式请求不同的微服务实例.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
请求服务: 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
|
以上为个人经验,希望能给大家一个参考,也希望大家多多支持我。如有错误或未考虑完全的地方,望不吝赐教.
原文链接:https://blog.csdn.net/Xiang_lhh/article/details/115249056 。
最后此篇关于利用go-kit组件进行服务注册与发现和健康检查的操作的文章就讲到这里了,如果你想了解更多关于利用go-kit组件进行服务注册与发现和健康检查的操作的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我没有使用 Sprite Kit 的经验。我想知道是否有类似 Cocos2D 的东西 调度程序在 SpriteKit 中?如果不是,应该用什么 NSTimer 是唯一的选择吗?我想如果唯一的选择是使用
在我的 Sprite Kit 应用程序中,我想要一个粘性物理体:任何与该物体接触的动态物体都不会反弹,而是与其保持连接。 是否有任何属性可以执行这种粘性行为?如果不能,如何实现? 最佳答案 SKNod
在我的 Sprite Kit 应用程序中,我想要一个粘性物理体:任何与该物体接触的动态物体都不会反弹,而是与其保持连接。 是否有任何属性可以执行这种粘性行为?如果不能,如何实现? 最佳答案 SKNod
我正在构建一个 flappy bird 游戏,其中一半关卡在水上,另一半关卡在水下。 如果您的小鸟在空中,则存在规律的重力,当您轻敲时,会施加一个直线向上的冲量。 如果你的鸟在水中,重力应该在负方向(
我正在使用 Sprite 套件制作游戏,现在我想知道让对象“跳跃”的最佳方法是什么。所以它将以几个像素垂直启动。 这是我要跳转的对象的代码: SKSpriteNode *sprite = [SKSpr
我很好奇如何为我的游戏显示像素艺术。现在我只是将 SKScene 的大小调整为 sceneWithSize:CGSizeMake(256, 192) 这是正确的方法还是有更好的方法来进行这种排序任务?
我不知道如何阻止节点旋转。 为什么允许旋转没有禁用它? 这是我描述我的节点的方式: SKSpriteNode *badguy = [SKSpriteNode spriteNodeWithTexture
我在 Xcode 中使用 Sprite Kit,我想知道如何更改重力方向。默认重力方向为“X”,您可以在轴下方的图形上想象。如果我想更改为“Y”怎么办。 我的目标是给予物体坠落效果。它就像从高处坠落并
我想知道如何在屏幕外删除我的 SKNode 以帮助我的游戏运行更流畅。 如何在 Sprite Kit 上做到这一点 非常感谢 最佳答案 https://stackoverflow.com/a/2419
我有一个关于“WEBKIT”的问题。什么是 WebKit?什么是 Android WebKit 以及它与 IOS WEbKit 有何不同?如何使用 WebKit?想要完美清晰的答案。有人有什么想法吗?
在我的 Sprite 套件游戏中,当两个 Sprite 发生碰撞时,我使用 SKAction 播放 mp3 文件。虽然游戏运行良好,但我在第一次播放声音时注意到游戏中有一个小的“hickup”。整个游
我正在创建一个游戏,对于我的角色,他的腿和躯干有单独的动画,因此它们是具有单独物理体的单独节点。我在将躯干和腿连接在一起时遇到了很多麻烦,但是,将它们连接起来不是问题,让它们保持连接才是问题。在四处走
Sprite Kit 是否具有相当于 9 切片缩放的 Sprite ? 我试过谷歌搜索,但没有找到任何东西,但是......它通常是一个在不同框架中有不同名称的功能。所以我可能会错过它。 最佳答案 S
我正在 Sprite Kit 中制作“Achtung die kurve”克隆。对于不断移动的队伍/球员,我使用 CGMutablePathRef 和 SKShapeNode。在更新方法中我正在这样做
我正在尝试开发一个building information model iPad 的查看器,我面临着当前的挑战。我应该使用 SpriteKit 还是 SceneKit?我知道 SceneKit 是用来
在 iPhone ios10 上安装后,我的 ready to ship appstore 应用程序不再播放声音!帮助!使用 ios9,一切都完美运行 SKAction.playSoundFileNa
如何将 CIPixellate 核心图像过滤器添加到 Sprite Kit 场景中? 我有一个 SpriteKit 场景,它是 SKScene 或其子类。 我想在场景中添加一个核心图像过滤器。特别是
这似乎不是一个明智的问题,但我心中有一些困惑,我想澄清。在Apple的2d游戏框架Sprite kit中,通常建议将节点相关的数据存储在Plist中,然后在代码中需要时检索。我不明白的是,在使用 .s
这似乎不是一个明智的问题,但我心中有一些困惑,我想澄清。在Apple的2d游戏框架Sprite kit中,通常建议将节点相关的数据存储在Plist中,然后在代码中需要时检索。我不明白的是,在使用 .s
我试图让用户能够将 skspritenode 拖到 UIImageView 和 UIButton 上,但每当我创建场景时,它都会出现在 UI 元素后面。我该如何解决这个问题? 最佳答案 恐怕这是不可能
我是一名优秀的程序员,十分优秀!