golang go语言 组建微服务架构详解 - 代码基于开源框架grpc+nacos服务管理配置平台
整体介绍:
本文主要介绍如何用go语言 来组建微服务的框架,grpc+服务管理
示例框架 代码由grpc+nacos go sdk 组成。 grpc负责将调用序列化并传递到远端,nacos负责服务发现和服务管理。
grpc和nacos都是开源产品。代码复制下来就能跑。
微服务解决了什么问题?
微服务架构通过将应用拆分为一系列小而自治的服务,解决了单体应用在扩展性和维护性上的问题。它主要提升了系统的可用性和稳定性,同时促进了开发团队间的高效协作。
例如,在一个快速成长的项目中,随着业务增长,订单处理、商品展示等功能模块逐渐庞大复杂。采用微服务后,可以将这些功能独立部署为单独的服务,每个服务由专门的小团队负责。
这样不仅加快了新功能的迭代速度,也使得故障隔离变得更容易,从而提高了整体系统的健壮性。
当团队规模扩大时,这种模式有助于明确职责划分,减少沟通成本,进而加速产品开发周期。
微服务实战中的应用拆分
在对一个典型的交易网站进行微服务切分时,可以采用领域驱动设计(DDD)的思想。
首先,识别出业务中的核心领域,比如用户管理、商品展示与管理、交易处理以及评价系统等。每个领域对应着一个或多个关键实体。以淘宝为例,它可以被拆分为“用户”、“商品”、“交易”和“评价”四大主要领域,领域主要和团队的角色分工相关。
然后 规划和构建领域内的核心方法,“用户”领域负责账号注册、登录验证和个人信息管理;“商品”领域则专注于商品的发布、搜索与分类;“交易”领域涵盖下单、支付及订单状态跟踪等功能;而“评价”领域则处理买家对卖家或商品的反馈。
最后,用微服务框架来实现,本例假设前两步已经做好,那么就可以用grpc+nacos来实现服务调用和服务管理。
这种按照业务领域来划分的方式,不仅使得每个服务都能由专门的团队独立开发维护,而且还能提高系统的可扩展性和灵活性,便于后续的技术迭代升级。
Nacos Go SDK 概述
Nacos 是一个动态服务发现、配置管理和服务管理平台,旨在帮助开发者更容易地构建、维护和管理微服务架构。
它提供了包括服务注册与发现、动态配置、DNS 服务等多种功能,并支持多种主流的编程语言。这个产品最新推出了Nacos go sdk,开源免费,可以作为Go语言微服务的最佳拍档。
服务注册与发现流程解析
在Nacos中,服务注册和服务发现是两个核心的功能,这两个功能共同保证了微服务架构下的服务能够被有效管理和访问。以下将基于提供的知识内容,对服务注册和服务发现的主要流程进行介绍,并提及如何使用gRPC和Nacos Go SDK来实现这些过程。
服务注册
- 启动服务实例:首先,开发者需要启动一个或多个服务实例。每个实例拥有自己独立的网络地址(IP:Port)。
- 配置Nacos客户端:接下来,在服务实例内部配置Nacos客户端的相关参数,包括Nacos服务器的地址等信息。如果使用的是Nacos Go SDK,则需按照其文档指南初始化客户端。
- 注册服务至Nacos:通过调用Nacos客户端提供的API(对于Go语言环境而言就是通过Nacos Go SDK),将当前服务实例的信息提交给Nacos服务端。这里提交的信息可能包括但不限于服务名、IP地址、端口号以及元数据(如版本号)。对于支持gRPC协议的服务来说,还需要额外指定服务所使用的协议类型为gRPC。
- 健康检查设置:配置好自动健康检查机制。一旦服务成功注册到Nacos之后,Nacos会定期对该服务执行健康状态检测以确保其实例处于可用状态。这一步骤对于保持整个服务体系稳定运行非常重要。
服务发现
- 客户端初始化:与服务注册类似,任何希望查找特定服务位置的应用程序都需要先完成Nacos客户端的初始化工作。
- 请求获取服务列表:应用程序通过Nacos客户端向Nacos服务器发起查询请求,询问指定名称的服务有哪些正在运行中的实例。这里同样可以利用Nacos Go SDK简化开发流程。
- 解析服务信息:从Nacos返回的结果中解析出所需的服务实例详情,比如它们的具体IP地址及端口等信息。如果目标服务支持gRPC通信方式的话,还需注意选择合适的服务实例来进行后续交互。
- 建立连接并调用服务:根据获取到的服务实例信息,客户端可以直接与其建立TCP连接(对于gRPC服务则是gRPC连接),然后开始发送请求并接收响应。
综上所述,借助于Nacos强大的服务注册与发现能力,结合gRPC高效的数据传输效率以及Nacos Go SDK提供的便捷接口支持,可以轻松构建起一套灵活可靠的服务管理体系。在整个过程中,重要的是正确配置各项参数,并合理设计系统的健壮性和容错性,以应对可能出现的各种异常情况。
基于gRPC和Nacos的服务发现与注册构建过程
实际的构建过程,基于grpc 和 nacos 的服务发现和服务注册
1. GRPC Prerequisites
在开始之前,请确保已安装protoc
及其Go插件,以生成gRPC服务所需的Go代码。这可以通过执行以下命令完成:
$ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
$ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
之后,更新您的环境变量PATH
来包含这些工具:
$ export PATH="$PATH:$(go env GOPATH)/bin"
2. Nacos-sdk-go 安装
接着,通过运行下面的命令安装Nacos Go SDK:
$ go get -u github.com/nacos-group/nacos-sdk-go/v2
3. Grpc proto文件准备 & 代码生成
创建一个简单的gRPC服务定义(这里假设为helloworld.proto
),然后使用protoc
工具生成对应的Go语言实现:
// helloworld.proto
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
rpc SayHelloAgain (HelloRequest) returns (HelloReply) {}
}
message HelloRequest { string name = 1; }
message HelloReply { string message = 1; }
运行如下命令来从.proto
文件生成Go代码:
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
helloworld/helloworld.proto
4. Go Grpc Server与Nacos集成
现在我们有了基本的服务接口和数据结构定义,接下来是服务器端的实现,并将其与Nacos结合用于服务注册。这部分代码展示了如何初始化gRPC服务并将其注册到Nacos:
import (
"context"
"flag"
"fmt"
"log"
"net"
"os"
"os/signal"
"syscall"
pb "your_project_path/helloworld" // 导入自动生成的pb包
grpc "google.golang.org/grpc"
"github.com/nacos-group/nacos-sdk-go/v2/clients"
constant "github.com/nacos-group/nacos-sdk-go/v2/common/constant"
vo "github.com/nacos-group/nacos-sdk-go/v2/vo"
)
var port = flag.Uint64("port", 50051, "The server port")
type server struct{ pb.UnimplementedGreeterServer }
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("Received: %v", in.GetName())
return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}
func main() {
flag.Parse()
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
clientConfig := constant.ClientConfig{
NamespaceId: "public",
TimeoutMs: 5000,
NotLoadCacheAtStart: true,
LogDir: "/tmp/nacos/log",
CacheDir: "/tmp/nacos/cache",
LogLevel: "info",
}
serverConfigs := []constant.ServerConfig{{IpAddr: "mse-51d24ce0-p.nacos-ans.mse.aliyuncs.com", Port: 8848}}
namingClient, _ := clients.CreateNamingClient(map[string]interface{}{
"serverConfigs": serverConfigs,
"clientConfig": clientConfig,
})
serviceName, groupName, clusterName := "example.grpc.server", "DEFAULT_GROUP", "cluster-a"
_, err = namingClient.RegisterInstance(vo.RegisterInstanceParam{
Ip: "127.0.0.1",
Port: *port,
ServiceName: serviceName,
Weight: 10,
Enable: true,
Healthy: true,
Ephemeral: true,
Metadata: map[string]string{"idc": "shanghai"},
ClusterName: clusterName,
GroupName: groupName,
})
if err != nil {
log.Fatalf("Error registering service: %v", err)
}
go func() {
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}()
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
<-sigCh
fmt.Println("Shutting down...")
_, err = namingClient.DeregisterInstance(vo.DeregisterInstanceParam{
Ip: "127.0.0.1",
Port: *port,
ServiceName: serviceName,
Ephemeral: true,
Cluster: clusterName,
GroupName: groupName,
})
if err != nil {
log.Printf("Error deregister service: %v", err)
}
s.GracefulStop()
fmt.Println("grpc server is stopped")
}
5. Go Grpc Client与Nacos集成
最后一步是客户端代码,它通过Nacos发现服务实例并调用远程方法。
const defaultName = "world"
var name = flag.String("name", defaultName, "Name to greet")
func main() {
flag.Parse()
clientConfig := constant.ClientConfig{
NamespaceId: "public",
TimeoutMs: 5000,
NotLoadCacheAtStart: true,
LogDir: "/tmp/nacos/log",
CacheDir: "/tmp/nacos/cache",
LogLevel: "info",
}
serverConfigs := []constant.ServerConfig{{IpAddr: "mse-51d24ce0-p.nacos-ans.mse.aliyuncs.com", Port: 8848}}
namingClient, _ := clients.CreateNamingClient(map[string]interface{}{
"serverConfigs": serverConfigs,
"clientConfig": clientConfig,
})
instance, err := namingClient.SelectOneHealthyInstance(vo.SelectOneHealthInstanceParam{
ServiceName: "example.grpc.server",
GroupName: "DEFAULT_GROUP",
Clusters: []string{"cluster-a"},
})
if err != nil {
log.Fatalf("failed to select instances: %v", err)
}
addr := fmt.Sprintf("%s:%d", instance.Ip, instance.Port)
conn, err := grpc.Dial(addr, grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.SayHello(ctx, &pb.HelloRequest{Name: *name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.GetMessage())
}
解释
以上步骤描述了从设置环境直到创建gRPC服务并通过Nacos进行服务发现的完整流程。首先,您需要准备好必要的开发工具如protoc
;其次,通过编写.proto
文件定义服务接口;然后,分别实现服务端和客户端程序,并将它们与Nacos服务发现机制集成起来。这样做的好处在于能够动态地发现可用的服务实例,并支持负载均衡等功能。