首先我需要去了解一些概念,根據百度百科了解到:
l 微服務架構:微服務架構是一項在雲中部署應用和服務的新技術。微服務可以在“自己的程序”中運行,並通過“輕量級設備與HTTP型API進行溝通”。
l gPRC:gRPC 是一款高性能、開源的 RPC 框架,產自 Google,基於 ProtoBuf 序列化協議進行開發,支持多種語言。
我們過去根據 MVC 划分目錄結構,由Controller 層處理業務邏輯,Model 層作為對象實體類,對數據庫進行 CURD操作,View 視圖層處理數據渲染和頁面交互。以及 MVP、MVVM 都是將整個項目的代碼是集中在一個代碼庫中,進行業務處理。這種單一聚合代碼的方式在前期實現業務的速度很快,但在后期會暴露很多問題:
1. 開發與維護困難:隨着業務復雜度的增加,代碼的耦合度往往會變高,多個模塊相互耦合后不易橫向擴展
2. 效率和可靠性低:過大的代碼量將降低響應速度,應用潛在的安全問題也會累積
微服務將一個大且聚合的業務項目拆解為多個小且獨立的業務模塊,每一模塊即服務,各服務間使用高效的協議(protobuf、JSON 等)相互調用即是 RPC。這種拆分代碼庫的方式有以下特點:
每個服務應作為小規模的、獨立的業務模塊在運行,類似 Unix 的 Do one thing and do it well
每個服務應在進行自動化測試和(分布式)部署時,不影響其他服務
每個服務內部進行細致的錯誤檢查和處理,提高了健壯性
本質上,二者只是聚合與拆分代碼的方式不同。
安裝gRPC與protoc編譯器:
go get -u google.golang.org/grpc
go get -u github.com/golang/protobuf/protoc-gen-go
定義微服務的user.protoc文件
syntax = "proto3"; // 指定語法格式,注意 proto3 不再支持 proto2 的 required 和 optional
package proto; // 指定生成的 user.pb.go 的包名,防止命名沖突
// service 定義開放調用的服務,即 UserInfoService 微服務
service UserInfoService {
// rpc 定義服務內的 GetUserInfo 遠程調用
rpc GetUserInfo (UserRequest) returns (UserResponse) {
}
}
// message 對應生成代碼的 struct
// 定義客戶端請求的數據格式
message UserRequest {
// [修飾符] 類型 字段名 = 標識符;
string name = 1;
}
// 定義服務端響應的數據格式
message UserResponse {
int32 id = 1;
string name = 2;
int32 age = 3;
repeated string title = 4; // repeated 修飾符表示字段是可變數組,即 slice 類型
生成 user.pb.go
package proto
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
// 請求結構
type UserRequest struct {
Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
}
// 為字段自動生成的 Getter
func (m *UserRequest) GetName() string {
if m != nil {
return m.Name
}
return ""
}
// 響應結構
type UserResponse struct {
Id int32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"`
Age int32 `protobuf:"varint,3,opt,name=age" json:"age,omitempty"`
Title []string `protobuf:"bytes,4,rep,name=title" json:"title,omitempty"`
}
// ...
// 客戶端需實現的接口
type UserInfoServiceClient interface {
GetUserInfo(ctx context.Context, in *UserRequest, opts ...grpc.CallOption) (*UserResponse, error)
}
// 服務端需實現的接口
type UserInfoServiceServer interface {
GetUserInfo(context.Context, *UserRequest) (*UserResponse, error)
}
// 將微服務注冊到 grpc
func RegisterUserInfoServiceServer(s *grpc.Server, srv UserInfoServiceServer) {
s.RegisterService(&_UserInfoService_serviceDesc, srv)
}
// 處理請求
func _UserInfoService_GetUserInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {...}