The things that grpc-streaming

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

GRPC is a high-performance, general-purpose, open-source RPC framework developed by Google primarily for mobile applications and based on the HTTP/2 protocol standards, developed based on the PROTOBUF (Protocol buffers) serialization protocol, and supports many development languages. GRPC provides an easy way to precisely define services and automatically generate a highly reliable client function library for iOS, Android, and background support services. Clients take advantage of advanced streaming and linking capabilities to help conserve bandwidth, reduce the number of TCP links, conserve CPU usage, and battery life.

GRPC has the following important characteristics:
Powerful IDL features RPC uses PROTOBUF to define services, and PROTOBUF is a data serialization protocol developed by Google that excels in performance and has been widely used.
Support for multiple languages support C + +, Java, Go, Python, Ruby, C #, node. js, Android Java, Objective-c, PHP and other programming languages. 3. Based on HTTP/2 standard design

GRPC has been applied to Google's cloud services and externally available APIs.

Grpc is very simple to develop, you can read a HelloWorld example to understand its basic development process (this series of articles takes the development of go language as an example).

The most basic development step is to define the proto file, define the format of the request and response Response, and then define a service provider that can contain multiple methods.

Basic GRPC Development Many articles have been introduced, the official also has the relevant documents, this series of articles do not introduce these basic development, but want to through the code demonstration grpc more in-depth development. As the first article in this series, I would like to share with you the knowledge of GRPC stream development.

GRPC streams can be divided into three categories, client streaming, server streaming, and client/server simultaneous streaming, i.e. one-way and two-way flows. The following are examples of these three cases, respectively.

Server-streaming response

By using the stream (streaming), you can send bulk data to the server or client, and the server and client can receive this data without having to wait for all messages to start responding, but to receive the first message in a timely response, which is obviously more than the previous class HTTP 1.1 of the way to provide faster response, which improves performance.

For example, there is a batch of records of personal income data, the client streamed to the server, the server calculates the individual income tax for each person, the results streamed to the client. This allows the client to send a parallel line of computation to the server side, thereby reducing the delay in service. This is just a simple example where you can use the flow to implement asynchronous execution of RPC calls, and handle client calls and server side execution in parallel,

The current GRPC through the HTTP2 protocol transmission, can be conveniently implemented streaming function. If you are interested in how GRPC transfers through HTTP2, you can read this article Grpc over HTTP2, which describes the GRPC transmission by HTTP2 in the low-level format. The format of Request and Response is as follows:

    • Request→request-headers *length-prefixed-message EOS
    • response→ (response-headers *length-prefixed-message trailers)/trailers-only

To implement a streaming response for a server, simply precede proto the response with a tag in the method definition in, stream as in the SayHello1 method, preceded by an HelloReply stream identity.

123456789101112131415161718192021
Syntax = "Proto3";p ackage pb;import "Github.com/gogo/protobuf/gogoproto/gogo.proto";//The Greeting service Definition.service Greeter {  //sends a greeting  RPC SayHello1 (hellorequest) returns (Stream helloreply) {}}//Th E request message containing the user ' s name.message hellorequest {  string name = 1;} The response message containing the Greetingsmessage helloreply {  string message = 1;}

In this example, I use Gogo to generate more efficient PROTOBUF code, and of course you can use the native tool to generate it.

12
gogo_root=${gopath}/src/github.com/gogo/protobufprotoc-i.:${gopath}/src  --gogofaster_out =PLUGINS=GRPC:. Helloworld.proto

The generated code already contains the processing of the stream, so the difference from the normal GRPC code is not very large, just note that the implementation of the server-side code to send the response through the stream.

12345678
func (S *server) SayHello1 (in *PB. Hellorequest, GS PB. Greeter_sayhello1server) Error {Name: = in. Name for i: = 0; I < "Hello" + name + StrConv. Itoa (i)})}returnnil}

What's the difference between a grpc and a normal one?

The normal grpc is to return an HelloReply object directly, whereas a streaming response you can Send return multiple objects through a method HelloReply , and the object stream is serialized and then streamed back.

Looking at its lower level implementations is actually ServerStream.SendMsg implemented using.

123456789
type Interface {Send (*helloreply) errorgrpc. Serverstream}func (x *greetersayhello1server) Send (M *helloreply) error {return x. Serverstream.sendmsg (M)}

For the client, we need to focus on two aspects of whether there is a change, one is to send a request, one is to read the response. Here is the code for the client:

 123456789101112131415161718192021222324 
 conn, err: = Grpc. Dial (*address, Grpc. Withinsecure ()) if  err! = nil  {log. Fatalf ( "faild to connect:%v" , Err)} defer  conn. Close () c: = PB. Newgreeterclient (conn) stream, Err: = C.sayhello1 (context. Background (), &PB. Hellorequest{name: *name}) if  err! = nil  {log. Fatalf ( "could not greet:%v" , err)}for  {reply, err: = stream. RECV () if  err = = Io. EOF {break }if  err! = nil  { Log. Printf ( "failed to recv:%v" , err)}log. Printf ( "greeting:%s" , reply. Message)} 

The send request does not look much different, just the return result is no longer a single HelloReply object, but one Stream . This corresponds to the server-side code, which stream.Recv() returns each object through a call HelloReply until an error occurs or the end of the stream (IO. EOF).

As you can see, the generated code provides the ability to send/read objects easily to/from the stream, and all of this GRPC help you build.

Client-side Streaming

Clients can also stream objects, and of course these objects are the same type of object as above.

The first thing to do is to define it in a proto file, similar to the definition above, with an identity in front of the request stream .

12345678910111213141516171819202122
Syntax = "Proto3";p ackage pb;import "Github.com/gogo/protobuf/gogoproto/gogo.proto"; option (Gogoproto.unmarshaler_ All) = true;//The greeting service definition.service Greeter {  rpc SayHello2 (stream hellorequest) returns (Hellorep LY) {}}//The request message containing the user ' s name.message hellorequest {  string name = 1;} The response message containing the Greetingsmessage helloreply {  string message = 1;}

Notice here that we only marked the flow of the request, the response or the previous look.

After generating the relevant code, the client's code is:

 12345678910111213141516171819 
td>
 func  SayHello2 (c pb). greeterclient) {var  err Errorstream, err: = C.sayhello2 (context. Background ()) for  i: = 0 ; I < []; i++ {if  err! = nil  {log. Printf ( "failed to call:%v" , err) break }stream. Send (&PB. Hellorequest{name: *name + StrConv. Itoa (i)})}reply, err: = stream. CLOSEANDRECV () if  err! = nil  {fmt. Printf ( "failed to recv:%v" , err)}log. Printf ( "greeting:%s" , reply. Message)} 

The call here c.SayHello2 does not go directly into the request parameter, but instead returns a stream send through which stream Send we can stream an object. In this example we have sent 100 requests.

The client reads the method by stream.CloseAndRecv() which the stream is closed, and the method returns the final result. Note The client is only responsible for closing the send of the stream.

The server-side code is as follows:

 123456789101112131415161718 
 func  (S *server) SayHello2 (GS PB. Greeter_sayhello2server) Error {var  names []string  for  {in, err: = Gs. RECV () if  err = = Io. EOF {GS. Sendandclose (&PB. Helloreply{message:  "Hello"  + strings. Join (names, )}) return  nil }if  err! = nil  {log. Printf ( "failed to recv:%v" , err) return  err}names = append  (names, in. Name)}return  nil } 

Each message received by the server is processed, and the processing is simplified to add to a slice. Once it detects that the client has turned off the stream, it sends the final result to the client by closing the stream. The closing of a stream is io.EOF distinguished by this error.

Bidirectional flow

Integrating the above two examples is an example of a two-way flow. Client streaming, server-side streaming response, all send and read are streamed.

protois defined in the following, both the request and the response are preceded by an stream identity:

123456789101112131415161718192021
Syntax = "Proto3";p ackage pb;import "Github.com/gogo/protobuf/gogoproto/gogo.proto";//The Greeting service  Definition.service Greeter {  rpc SayHello3 (stream hellorequest) returns (Stream helloreply) {}}//the request message Containing the user ' s name.message hellorequest {  string name = 1;} The response message containing the Greetingsmessage helloreply {  string message = 1;}

The client's code:

 12345678910111213141516171819202122232425 
 func  SayHello3 (c pb). greeterclient) {var  err Errorstream, err: = C.sayhello3 (context. Background ()) if  err! = nil  {log. Printf ( "failed to call:%v" , err) return } var  i int64  for  {stream. Send (&PB. Hellorequest{name: *name + StrConv. Formatint (I, )}) if  err! = nil  {log. Printf ( "failed to send:%v" , err) break }reply, err: = stream. RECV () if  err! = nil  {log. Printf ( "failed to recv:%v" , err) break }log. Printf ( "greeting:%s" , reply. Message) i++}} 

By stream.Send sending a request by stream.Recv reading the response. The client can CloseSend close the send stream by method.

The server-side code also Send responds by sending a response Recv :

12345678910111213141516
func (S *server) SayHello3 (GS PB. Greeter_sayhello3server) Error { for {in, err: = Gs. RECV ()if err = = Io. EOF {returnnil}ifnil {log. Printf ("failed to recv:%v", err)return"Hello" + in. Name})}returnnil}

This basically "degenerates" into a TCP client and server architecture.

In a real-world application, you can use one-way or two-way flow depending on your scenario.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.