服务注册与发现:ETCD
1直接调包
kitex-contrib: 上面有实现的案例,直接cv。下面是具体的理解
2 相关概念
-
EtcdResolver: etcd resolver是一种DNS解析器,用于将域名转换为etcd集群中的具体地址,以便应用程序可以与etcd集群进行通信。etcd是一个分布式键值存储系统,常用于服务发现、配置共享和分布式锁等应用场景。通过使用etcd resolver,应用程序可以更方便地与etcd集群交互
-
endpoints 用于指定集群的地址列表.例如:etcd1.example.com:2379, etcd2.example.com:2379。应用程序将通过这些地址与etcd集群的各个节点进行通信,以读取和更新数据。
3 IP设置为 0.0.0.0
-
为什么Etcd的endpoints中的ip需要设置为:0.0.0.0而不是本机ip?
- 原因:当你的服务器将 IP 地址设置为 0.0.0.0,并使用一个特定的端口号时,它可以通过监听所有网络接口包括本地计算机上的所有网络接口和外部计算机的公共 IP 地址来接受连接。这意味着来自互联网上其他计算机的请求可以通过公共 IP 地址和指定的端口号访问你的服务器。
- 而当你的服务器将 IP 地址设置为 127.0.0.1 或 localhost 时,它只会接受来自本地计算机的连接请求,不会监听其他计算机发起的连接请求。这意味着其他计算机或设备无法通过公共 IP 地址或局域网中的内部 IP 地址来访问你的服务器。
-
举例
假设你的服务器在一个局域网中,拥有一个内部 IP 地址(例如 192.168.1.100),同时连接到了互联网并获得了一个公共 IP 地址(例如 203.0.113.10)。当你将服务器的 IP 地址设置为 0.0.0.0,并指定端口号为9000 时,其他计算机可以通过访问 “http://203.0.113.10:9000” 来连接到你的服务器。
这时候自己服务器上的9000端口上的程序(如minio),就能被任何外网设备访问到了。而如果IP设置为192.168.1.100,外网访问"http://192.168.1.100:9000" 肯定是访问不到的。
还有一个解决方案就是设置为公网的ip,如:#MinioEndpoint = "h2eonr2x.shenzhuo.vip:38854"
这里直接设置了当前主机当前端口的ip+port,外网设备能够直接访问自己服务器上minio的9000端口的minio服务。 -
外网能访问的解决方案
除了将 IP 地址设置为 0.0.0.0,也可以将服务器的 IP 地址设置为本机对应的公共 IP 地址,以便外部网络也能够访问你的服务器。都是0.0.0.0方便,设置为公网的唯一IP还会依赖于服务商,可能还会发生变动。
4 案例
直接看例子就能大致明白;参考github网页:
client:文章来源:https://www.toymoban.com/news/detail-665402.html
func main() {
r, err := etcd.NewEtcdResolver([]string{"127.0.0.1:2379"})
if err != nil {
log.Fatal(err)
}
client := hello.MustNewClient("Hello", client.WithResolver(r))
for {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
resp, err := client.Echo(ctx, &api.Request{Message: "Hello"})
cancel()
if err != nil {
log.Fatal(err)
}
log.Println(resp)
time.Sleep(time.Second)
}
}
server:文章来源地址https://www.toymoban.com/news/detail-665402.html
type HelloImpl struct{}
func (h *HelloImpl) Echo(ctx context.Context, req *api.Request) (resp *api.Response, err error) {
resp = &api.Response{
Message: req.Message,
}
return
}
func main() {
r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"})
if err != nil {
log.Fatal(err)
}
server := hello.NewServer(new(HelloImpl), server.WithRegistry(r), server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{
ServiceName: "Hello",
}))
err = server.Run()
if err != nil {
log.Fatal(err)
}
}
5 实际项目实现
5.1 client
- handler层接受到app发来的参数如:token、latest_time,根据文档规范封装为一个向后端发起的请求:FeedRequest.
- rpc远程调用server的Feed接口,返回目标结果
- rpc调用的Feed实际上先调用了kitex自动生成的client,通过client与server通信,实现调用server的接口。
- kitex自动生成的client需要在使用前初始化,比如进行服务与发现
具体来说:client又需要注册中心的resolver,拿到resolver的办法就etcd.NewEtcdResolver([]string{etcdAddr})
,传入endpoint就可以直接拿到reslover
下面是初始化client的例子
// InitVideo
// 在构建client和server通信之前,先关注连通性
func InitVideo(viperConfig *viper.ConfigViper) {
etcdAddr := fmt.Sprintf("%s:%d", viperConfig.Viper.GetString("etcd.host"), viperConfig.Viper.GetString("etcd.port"))
resolver, err2 := etcd.NewEtcdResolver([]string{etcdAddr})
if err2 != nil {
log.Fatal(err2)
}
serverName := viperConfig.Viper.GetString("server.name") //指定客户端所连接的服务的名称
newClient, err := videoservice.NewClient(
serverName,
//client.WithMiddleware(middleware.CommonMiddleware),
//client.WithInstanceMW(middleware.ClientMiddleware), //实例级别的中间件。这个中间件可能会对客户端的每个请求进行预处理或后处理
client.WithMuxConnection(1), // mux
client.WithRPCTimeout(300*time.Second), // rpc timeout
client.WithConnectTimeout(300000*time.Millisecond), // conn timeout
client.WithFailureRetry(retry.NewFailurePolicy()), // retry
client.WithSuite(tracing.NewClientSuite()), // tracer 添加了一个追踪器,用于跟踪客户端的请求和响应
client.WithResolver(resolver), // resolver
// Please keep the same as provider.WithServiceName
client.WithClientBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: serverName}),
)
if err != nil {
// TODO 思考应该直接panic吗
log.Fatal(err)
}
videoClient = newClient
}
5.2 server
- 在一个server运行的时候,main是入口,所以需要在main中将自己的服务注册到etcd中
先通过viper的init方法搜索到对于的配置文件,加载到对象config中:
var (
config = viper.Init("video")
serviceName = config.Viper.GetString("server.name")
serviceAddr = fmt.Sprintf("%s:%d", config.Viper.GetString("server.host"), config.Viper.GetInt("server.port"))
etcdAddr = fmt.Sprintf("%s:%d", config.Viper.GetString("etcd.host"), config.Viper.GetInt("etcd.port"))
signingKey = config.Viper.GetString("JWT.signingKey")
logger = zap.InitLogger()
)
- 服务注册
之前服务发现是NewEtcdResolver,现在注册是:r, err := etcd.NewEtcdRegistry([]string{etcdAddr})
,将得到一个Registry类型的对象
- 调kitex自动生成的service的NewServer方法,注意使用上面拿到的Registry对象
- 上面的启动main方法已经将VideoServiceImpl注册好了,现在可以在脚手架中写具体的各个Impl的接口实现。
到了这里,关于golang云原生项目之:etcd服务注册与发现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!