目录
服务发现
每个服务端把自己的ip和端口号注册到服务发现模块
客户端访问服务的时候去服务发现模块查找IP:PORT,然后访问相应的服务
[服务发现,也可以看做一个服务,是为服务提供服务的]
图片来源:
https://www.bilibili.com/video/BV1po4y1X7hH?p=85
健康检查:
服务发现模块定期查看服务端能不能访问
client、server工作流程:
- 每个server启动时,都将自己的IP、port 和 服务名 注册给 ”服务发现“
- 当 client 向服务发现发起服务请求时, “服务发现” 会自动找一个可用的 服务,将其 IP/port/服务名返回给 client
- client 再借助服务发现,访问 server。
服务发现的种类:
- consul: 常应用于 go-micro 中。
- mdns:go-micro中默认自带的服务发现。
- etcd:k8s 内嵌的服务发现
- zookeeper:java中较常用。
consul
Consul是HashiCorp公司推出的开源工具,用于实现分布式系统的服务发现与配置。
特性:
- 服务发现: consul 提供服务, 服务端 主动向 consul 发起注册。
- 健康检查: 定时发送消息,类似于 “心跳包”,保证 客户端获得到的 一定是 健康的服务。
- 键值存储: consul 提供,但是我们使用 redis
- 多数据中心:可以轻松搭建集群。
安装 consul 源码包:
$ go get -u -v github.com/hashicorp/consul
启动命令
consul agent -dev
consul和grpc
使用整体流程
-
创建 proto文件 , 指定 rpc 服务
-
启动 consul 服务发现 consul agent -dev
-
启动server
-
获取consul 对象。
-
使用 consul对象,将 server 信息,注册给 consul
-
启动服务
-
-
启动client
-
获取consul 对象。
-
使用consul对象,从consul 上获取健康的 服务。
-
再访问服务 (grpc远程调用)
-
目录结构
person.proto
syntax = "proto3";
package pb;
option go_package ="../pb";// 避免错误 unable to determine Go import path for "myproto.proto"
message Person{
string name = 1;
int32 age = 2;
}
// 添加rpc服务
service hello{
rpc sayHello (Person) returns (Person);
}
编译命令
protoc --go_out=plugins=grpc:./ *.proto
consul_server.go
package main
import (
"awesomeProject1/Microservices/consul/pb"
"context"
"fmt"
"github.com/hashicorp/consul/api"
"google.golang.org/grpc"
"net"
)
// 定义类
type Children struct {
}
// 绑定类方法, 实现接口
func (this *Children) SayHello(ctx context.Context, p *pb.Person) (*pb.Person, error) {
p.Name = "你好" + p.Name
return p, nil
}
func main() {
// 把 grpc服务注册到consul上
// 1. 初始化consul配置
consulConfig := api.DefaultConfig()
// 2. 创建consul对象
consulClient, err := api.NewClient(consulConfig)
if err != nil {
fmt.Println("api.NewClient err:", err)
return
}
// 3. 告诉consul即将注册的服务配置信息
registerService := api.AgentServiceRegistration{
ID: "id_1",
Tags: []string{"grpc", "consul"}, // 服务别名
Name: "grpc and consul", // 当前服务名字
Address: "127.0.0.1",
Port: 8800,
Check: &api.AgentServiceCheck{
CheckID:"consul grpc test",
TCP: "127.0.0.1:8800",
Timeout:"1s",
Interval: "5s",
},
}
// 4. 注册服务到consul上
consulClient.Agent().ServiceRegister(®isterService)
// grpc 远程调用
// 1. 初始化 grpc 对象,
grpcServer := grpc.NewServer()
// 2.注册服务
pb.RegisterHelloServer(grpcServer, new(Children))
// 3.设置监听, 指定IP/port
listener, err := net.Listen("tcp", "127.0.0.1:8800")
if err != nil {
fmt.Println("Listen err:", err)
}
defer listener.Close()
// 4.启动服务
fmt.Println("服务启动...")
grpcServer.Serve(listener)
}
consul_client.go
package main
import (
"awesomeProject1/Microservices/consul/pb"
"context"
"fmt"
"github.com/hashicorp/consul/api"
"google.golang.org/grpc"
"strconv"
)
func main(){
// 1. 初始化 consul 配置
consulConfig := api.DefaultConfig()
// 2. 创建 consul对象 --(可以重新指定consul属性,ip,port,...,也可以使用默认)
consulClient, err := api.NewClient(consulConfig)
// 3. 服务发现, 从consul上获取健康的服务
services, _, err := consulClient.Health().Service("grpc and consul", "grpc", true, nil )
// 这里可以添加简单的负载均衡,访问压力均摊给集群中的每个服务
addr := services[0].Service.Address + ":" + strconv.Itoa(services[0].Service.Port)
// grpc 远程调用
// 1. 连接服务
// 原始的方式
// grpcConn, _ := grpc.Dial("127.0.0.1:8800", grpc.WithInsecure())
// 使用服务发现consul上的 ip和port 来与服务建立连接
grpcConn, _ := grpc.Dial(addr, grpc.WithInsecure())
// 2. 初始化一个grpc客户端
grpcClient := pb.NewHelloClient(grpcConn)
var person pb.Person
person.Name = "张三"
person.Age = 18
// 3. 调用远程函数
p, err := grpcClient.SayHello(context.TODO(), &person)
fmt.Println(p, err)
}
结果
服务注销
consul_deregister.go
package main
import "github.com/hashicorp/consul/api"
func main(){
// 1. 初始化一个consul配置
consulConfig := api.DefaultConfig()
// 2. 创建consul对象
consulClient, _ := api.NewClient(consulConfig)
// 3. 注销服务
consulClient.Agent().ServiceDeregister("id_1")
}