Go实战--golang中使用gRPC和Protobuf实现高性能api(golang/proto
生命不止,继续 go go go !!! 号外号外,插播一条广告,通过博客的uv可以看到周五,程序员是不怎么干活的: 本篇博客,使用gRPC和Protobuf,实现所谓的高性能api。 protobufgolang中的protobuf大家应该不会很陌生,之前也有博客介绍过: Protocol Buffers (a.k.a.,protobuf) are Google’s language-neutral,platform-neutral,extensible mechanism for serializing structured data. You can find protobuf’s documentation on the Google Developers site. 获取: go get -u github.com/golang/protobuf/proto
go get -u github.com/golang/protobuf/protoc-gen-go
Protobuf语法 Message定义 Syntax = "proto3";
package tutorial;
首行声明使用的protobuf版本为proto3 message Person {
string name = 1;
int32 id = 2; // Unique ID number for this person.
string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
string number = 1;
PhoneType type = 2;
}
repeated PhoneNumber phones = 4;
}
// Our address book file is just one of these.
message AddressBook {
repeated Person people = 1;
}
生成 protoc -I=$SRC_DIR --go_out=$DST_DIR $SRC_DIR/addressbook.proto
写消息 book := &pb.AddressBook{}
// ...
// Write the new address book back to disk.
out,err := proto.Marshal(book)
if err != nil {
log.Fatalln("Failed to encode address book:",err)
}
if err := IoUtil.WriteFile(fname,out,0644); err != nil {
log.Fatalln("Failed to write address book:",err)
}
读消息 // Read the existing address book.
in,err := IoUtil.ReadFile(fname)
if err != nil {
log.Fatalln("Error reading file:",err)
}
book := &pb.AddressBook{}
if err := proto.Unmarshal(in,book); err != nil {
log.Fatalln("Failed to parse address book:",err)
}
grpcgolang中的rpc大家也不会陌生,之前也有介绍过奥: 什么是rpc RPC是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。如果涉及的软件采用面向对象编程,那么远程过程调用亦可称作远程调用或远程方法调用,信息数据。通过它可以使函数调用模式网络化。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。 net/rpc 什么是grpc 在gRPC客户端可以直接调用不同服务器上的远程程序,使用姿势看起来就像调用本地程序一样,很容易去构建分布式应用和服务。和很多RPC系统一样,服务端负责实现定义好的接口并处理客户端的请求,客户端根据接口描述直接调用需要的服务。客户端和服务端可以分别使用gRPC支持的不同语言实现。 grpc-go Star: 4402 文档地址: 获取: 应用文件结构 proto文件 Syntax = "proto3";
package customer;
// The Customer service definition.
service Customer {
// Get all Customers with filter - A server-to-client streaming RPC.
rpc GetCustomers(CustomerFilter) returns (stream CustomerRequest) {}
// Create a new Customer - A simple RPC
rpc CreateCustomer (CustomerRequest) returns (CustomerResponse) {}
}
// Request message for creating a new customer
message CustomerRequest {
int32 id = 1; // Unique ID number for a Customer.
string name = 2;
string email = 3;
string phone= 4;
message Address {
string street = 1;
string city = 2;
string state = 3;
string zip = 4;
bool isShippingAddress = 5;
}
repeated Address addresses = 5;
}
message CustomerResponse {
int32 id = 1;
bool success = 2;
}
message CustomerFilter {
string keyword = 1;
}
生成customer.pb.go protoc --go_out=plugins=grpc:. customer.proto
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: customer.proto
/* Package customer is a generated protocol buffer package. It is generated from these files: customer.proto It has these top-level messages: CustomerRequest CustomerResponse CustomerFilter */
package customer
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
// Request message for creating a new customer
type CustomerRequest struct {
Id int32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"`
Name string `protobuf:"bytes,2,name=name" json:"name,omitempty"`
Email string `protobuf:"bytes,3,name=email" json:"email,omitempty"`
Phone string `protobuf:"bytes,4,name=phone" json:"phone,omitempty"`
Addresses []*CustomerRequest_Address `protobuf:"bytes,5,rep,name=addresses" json:"addresses,omitempty"`
}
func (m *CustomerRequest) Reset() { *m = CustomerRequest{} }
func (m *CustomerRequest) String() string { return proto.CompactTextString(m) }
func (*CustomerRequest) ProtoMessage() {}
func (*CustomerRequest) Descriptor() ([]byte,[]int) { return fileDescriptor0,[]int{0} }
func (m *CustomerRequest) GetId() int32 {
if m != nil {
return m.Id
}
return 0
}
func (m *CustomerRequest) GetName() string {
if m != nil {
return m.Name
}
return ""
}
func (m *CustomerRequest) GetEmail() string {
if m != nil {
return m.Email
}
return ""
}
func (m *CustomerRequest) GetPhone() string {
if m != nil {
return m.Phone
}
return ""
}
func (m *CustomerRequest) GetAddresses() []*CustomerRequest_Address {
if m != nil {
return m.Addresses
}
return nil
}
type CustomerRequest_Address struct {
Street string `protobuf:"bytes,name=street" json:"street,omitempty"`
City string `protobuf:"bytes,name=city" json:"city,omitempty"`
State string `protobuf:"bytes,name=state" json:"state,omitempty"`
Zip string `protobuf:"bytes,name=zip" json:"zip,omitempty"`
IsShippingAddress bool `protobuf:"varint,name=isShippingAddress" json:"isShippingAddress,omitempty"`
}
func (m *CustomerRequest_Address) Reset() { *m = CustomerRequest_Address{} }
func (m *CustomerRequest_Address) String() string { return proto.CompactTextString(m) }
func (*CustomerRequest_Address) ProtoMessage() {}
func (*CustomerRequest_Address) Descriptor() ([]byte,[]int{0, 0} }
func (m *CustomerRequest_Address) GetStreet() string {
if m != nil {
return m.Street
}
return ""
}
func (m *CustomerRequest_Address) GetCity() string {
if m != nil {
return m.City
}
return ""
}
func (m *CustomerRequest_Address) GetState() string {
if m != nil {
return m.State
}
return ""
}
func (m *CustomerRequest_Address) GetZip() string {
if m != nil {
return m.Zip
}
return ""
}
func (m *CustomerRequest_Address) GetIsShippingAddress() bool {
if m != nil {
return m.IsShippingAddress
}
return false
}
type CustomerResponse struct {
Id int32 `protobuf:"varint,omitempty"`
Success bool `protobuf:"varint,name=success" json:"success,omitempty"`
}
func (m *CustomerResponse) Reset() { *m = CustomerResponse{} }
func (m *CustomerResponse) String() string { return proto.CompactTextString(m) }
func (*CustomerResponse) ProtoMessage() {}
func (*CustomerResponse) Descriptor() ([]byte,[]int{1} }
func (m *CustomerResponse) GetId() int32 {
if m != nil {
return m.Id
}
return 0
}
func (m *CustomerResponse) GetSuccess() bool {
if m != nil {
return m.Success
}
return false
}
type CustomerFilter struct {
Keyword string `protobuf:"bytes,name=keyword" json:"keyword,omitempty"`
}
func (m *CustomerFilter) Reset() { *m = CustomerFilter{} }
func (m *CustomerFilter) String() string { return proto.CompactTextString(m) }
func (*CustomerFilter) ProtoMessage() {}
func (*CustomerFilter) Descriptor() ([]byte,[]int{2} }
func (m *CustomerFilter) GetKeyword() string {
if m != nil {
return m.Keyword
}
return ""
}
func init() {
proto.RegisterType((*CustomerRequest)(nil),"customer.CustomerRequest")
proto.RegisterType((*CustomerRequest_Address)(nil),"customer.CustomerRequest.Address")
proto.RegisterType((*CustomerResponse)(nil),"customer.CustomerResponse")
proto.RegisterType((*CustomerFilter)(nil),"customer.CustomerFilter")
}
// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConn
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion4
// Client API for Customer service
type CustomerClient interface {
// Get all Customers with filter - A server-to-client streaming RPC.
GetCustomers(ctx context.Context,in *CustomerFilter,opts ...grpc.CallOption) (Customer_GetCustomersClient,error)
// Create a new Customer - A simple RPC
CreateCustomer(ctx context.Context,in *CustomerRequest,opts ...grpc.CallOption) (*CustomerResponse,error)
}
type customerClient struct {
cc *grpc.ClientConn
}
func NewCustomerClient(cc *grpc.ClientConn) CustomerClient {
return &customerClient{cc}
}
func (c *customerClient) GetCustomers(ctx context.Context,error) {
stream,err := grpc.NewClientStream(ctx,&_Customer_serviceDesc.Streams[0],c.cc,"/customer.Customer/GetCustomers",opts...)
if err != nil {
return nil,err
}
x := &customerGetCustomersClient{stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil,err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil,err
}
return x,nil
}
type Customer_GetCustomersClient interface {
Recv() (*CustomerRequest,error)
grpc.ClientStream
}
type customerGetCustomersClient struct {
grpc.ClientStream
}
func (x *customerGetCustomersClient) Recv() (*CustomerRequest,error) {
m := new(CustomerRequest)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil,err
}
return m,nil
}
func (c *customerClient) CreateCustomer(ctx context.Context,error) {
out := new(CustomerResponse)
err := grpc.Invoke(ctx,"/customer.Customer/CreateCustomer",in,err
}
return out,nil
}
// Server API for Customer service
type CustomerServer interface {
// Get all Customers with filter - A server-to-client streaming RPC.
GetCustomers(*CustomerFilter,Customer_GetCustomeRSServer) error
// Create a new Customer - A simple RPC
CreateCustomer(context.Context,*CustomerRequest) (*CustomerResponse,error)
}
func RegisterCustomerServer(s *grpc.Server,srv CustomerServer) {
s.RegisterService(&_Customer_serviceDesc,srv)
}
func _Customer_GetCustomers_Handler(srv interface{},stream grpc.ServerStream) error {
m := new(CustomerFilter)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(CustomerServer).GetCustomers(m,&customerGetCustomeRSServer{stream})
}
type Customer_GetCustomeRSServer interface {
Send(*CustomerRequest) error
grpc.ServerStream
}
type customerGetCustomeRSServer struct {
grpc.ServerStream
}
func (x *customerGetCustomeRSServer) Send(m *CustomerRequest) error {
return x.ServerStream.SendMsg(m)
}
func _Customer_CreateCustomer_Handler(srv interface{},ctx context.Context,dec func(interface{}) error,interceptor grpc.UnaryServerInterceptor) (interface{},error) {
in := new(CustomerRequest)
if err := dec(in); err != nil {
return nil,err
}
if interceptor == nil {
return srv.(CustomerServer).CreateCustomer(ctx,in)
}
info := &grpc.UnaryServerInfo{
Server: srv,FullMethod: "/customer.Customer/CreateCustomer",}
handler := func(ctx context.Context,req interface{}) (interface{},error) {
return srv.(CustomerServer).CreateCustomer(ctx,req.(*CustomerRequest))
}
return interceptor(ctx,info,handler)
}
var _Customer_serviceDesc = grpc.ServiceDesc{
ServiceName: "customer.Customer",HandlerType: (*CustomerServer)(nil),Methods: []grpc.MethodDesc{
{
MethodName: "CreateCustomer",Handler: _Customer_CreateCustomer_Handler,},Streams: []grpc.StreamDesc{
{
StreamName: "GetCustomers",Handler: _Customer_GetCustomers_Handler,ServerStreams: true,Metadata: "customer.proto",}
func init() { proto.RegisterFile("customer.proto",fileDescriptor0) }
var fileDescriptor0 = []byte{
// 326 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x02, 0xff, 0x74, 0x92, 0xef, 0x4a, 0xc3, 0x30, 0x10, 0xc0, 0x97, 0x6e, 0xdd, 0x9f, 0x53, 0xea, 0x0c, 0x22, 0xb1, 0x6a, 0x3f, 0x15, 0x91, 0x21, 0xf3, 0xab, 0x20, 0x32, 0x70, 0xf8, 0xb5, 0x3e, 0x41, 0x6d, 0x0f, 0x17, 0xdc, 0xda, 0x9a, 0xcb, 0x90, 0xf9, 0x0a, 0xbe, 0x83, 0xcf, 0xe0, 0x23, 0xd2, 0x66, 0x03, 0xe7, 0x72, 0x77, 0xe5, 0x04, 0x42, 0x35, 0xa9, 0x55, 0xa5, 0x2b, 0x1c, 0x78, 0x6b, 0xc5, 0xf7, 0xe6, 0x01, 0xb2, 0x2c, 0x62, 0x89, 0x7a, 0x65, 0xb6, 0xe1, 0x45, 0x19, 0x36, 0x67, 0xe3, 0x2a, 0x93, 0x4b, 0xd1, 0xc9, 0x06, 0x4c, 0x5e, 0x54, 0x25, 0x8a, 0x61, 0x94, 0x85, 0x24, 0x47, 0xe4, 0x68, 0x39, 0xd9, 0x1a, 0xfd, 0xb9, 0x7d, 0xf2, 0xd0, 0xa6, 0xbb, 0x9e, 0xf0, 0xc1, 0xa0, 0x4d, 0x73, 0xe8, 0x56, 0x88, 0x8e, 0x96, 0x8c, 0x64, 0x2e, 0xf5, 0xc6, 0x49, 0xd8, 0xce, 0x34, 0x3a, 0x0b, 0x7c, 0x4f, 0x59, 0xb7, 0x26, 0xd7, 0xe9, 0x79, 0xeb, 0x5a, 0xaf, 0xed, 0xc2, 0x8f, 0x58, 0xe2, 0x3b, 0x18, 0x9c, 0xae, 0xbd, 0x95, 0x09, 0xcd, 0x71, 0x5f, 0xba, 0x1f, 0x52, 0xa3, 0x6f, 0xb8, 0xa8, 0xf4, 0x9b, 0x51, 0xf6, 0x57, 0x2f, 0x0e, 0x37, 0xee, 0xfe, 0xfa, 0x43, 0xd4, 0x3c, 0xbc, 0x0d, 0xde, 0xd3, 0x60,}
server/main.go package main
import (
"log"
"net"
"strings"
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "go_grpc_protobuf/customer"
)
const (
port = ":50051"
)
// server is used to implement customer.CustomerServer.
type server struct {
savedCustomers []*pb.CustomerRequest
}
// CreateCustomer creates a new Customer
func (s *server) CreateCustomer(ctx context.Context,in *pb.CustomerRequest) (*pb.CustomerResponse,error) {
s.savedCustomers = append(s.savedCustomers,in)
return &pb.CustomerResponse{Id: in.Id,Success: true},nil
}
// GetCustomers returns all customers by given filter
func (s *server) GetCustomers(filter *pb.CustomerFilter,stream pb.Customer_GetCustomeRSServer) error {
for _,customer := range s.savedCustomers {
if filter.Keyword != "" {
if !strings.Contains(customer.Name,filter.Keyword) {
continue
}
}
if err := stream.Send(customer); err != nil {
return err
}
}
return nil
}
func main() {
lis,err := net.Listen("tcp",port)
if err != nil {
log.Fatalf("Failed to listen: %v",err)
}
// Creates a new gRPC server
s := grpc.NewServer()
pb.RegisterCustomerServer(s,&server{})
s.Serve(lis)
}
client/main.go package main
import (
"io"
"log"
"golang.org/x/net/context"
"google.golang.org/grpc"
pb "go_grpc_protobuf/customer"
)
const (
address = "localhost:50051"
)
// createCustomer calls the RPC method CreateCustomer of CustomerServer
func createCustomer(client pb.CustomerClient,customer *pb.CustomerRequest) {
resp,err := client.CreateCustomer(context.Background(),customer)
if err != nil {
log.Fatalf("Could not create Customer: %v",err)
}
if resp.Success {
log.Printf("A new Customer has been added with id: %d",resp.Id)
}
}
// getCustomers calls the RPC method GetCustomers of CustomerServer
func getCustomers(client pb.CustomerClient,filter *pb.CustomerFilter) {
// calling the streaming API
stream,err := client.GetCustomers(context.Background(),filter)
if err != nil {
log.Fatalf("Error on get customers: %v",err)
}
for {
customer,err := stream.Recv()
if err == io.EOF {
break
}
if err != nil {
log.Fatalf("%v.GetCustomers(_) = _,%v",client,err)
}
log.Printf("Customer: %v",customer)
}
}
func main() {
// Set up a connection to the gRPC server.
conn,err := grpc.Dial(address,grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v",err)
}
defer conn.Close()
// Creates a new CustomerClient
client := pb.NewCustomerClient(conn)
customer := &pb.CustomerRequest{
Id: 101,Name: "Shiju Varghese",Email: "shiju@xyz.com",Phone: "732-757-2923",Addresses: []*pb.CustomerRequest_Address{
&pb.CustomerRequest_Address{
Street: "1 Mission Street",City: "San Francisco",State: "CA",Zip: "94105",IsShippingAddress: false,&pb.CustomerRequest_Address{
Street: "Greenfield",City: "Kochi",State: "KL",Zip: "68356",IsShippingAddress: true,}
// Create a new customer
createCustomer(client,customer)
customer = &pb.CustomerRequest{
Id: 102,Name: "Irene Rose",Email: "irene@xyz.com",Phone: "732-757-2924",customer)
// Filter with an empty Keyword
filter := &pb.CustomerFilter{Keyword: ""}
getCustomers(client,filter)
}
运行server,运行client,输出: 2017/12/07 11:55:59 A new Customer has been added with id: 101
2017/12/07 11:55:59 A new Customer has been added with id: 102
2017/12/07 11:55:59 Customer: id:101 name:"Shiju Varghese" email:"shiju@xyz.com" phone:"732-757-2923" addresses:<street:"1 Mission Street" city:"San Francisco" state:"CA" zip:"94105" > addresses:<street:"Greenfield" city:"Kochi" state:"KL" zip:"68356" isShippingAddress:true >
2017/12/07 11:55:59 Customer: id:102 name:"Irene Rose" email:"irene@xyz.com" phone:"732-757-2924" addresses:<street:"1 Mission Street" city:"San Francisco" state:"CA" zip:"94105" isShippingAddress:true > (编辑:北几岛) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- 【图像处理】使用OpenCV+Python进行图像处理入门
- C#数据结构-线索化二叉树
- 3.3 Spring5源码---循环依赖过程中spring读取不完
- ASP.NET Core 3.x启动时运行异步任务(一)
- 【Java并发编程】面试常考的ThreadLocal,超详细
- 如何使用php检索utf-8数据并在excelsheet数据库转
- 翻译:《实用的Python编程》02_05_Collections
- php – 如何根据’title’和’description’列在
- SpringCloud学习笔记【八】:Ribbon负载均衡服务
- [备忘]LINQ to Entities在Trust Level = Medium中