This is a creation in Article, where the information may have evolved or changed. # # Introduction Golang in the total 10 parts of the micro-service series, is expected to be updated weekly. The solution in this series uses PROTOBUF and GRPC as the underlying transport protocol. Why use these two technologies? It took me quite a long time to figure out and decide to adopt this scheme. This program is very clear and concise for developers. I am also happy to share my experience in building, testing, and deploying end-to-end microservices to my friends who want to get in touch with this piece. In this tutorial, we will first touch on a few basic concepts and terminology, and then start building the first simple microservices model. In this series, we will create the following services:-Consignment-Inventory-users-certifications-roles-containers the entire technology stack can be divided from bottom to top: Golang, MongoDB, Grpc, Docker, Google Cloud, Kubernetes, NATS, Circleci, TerraForm and Go-micro. Next, you can step through the instructions in my [git repository] (https://github.com/EwanValentine/shippy) (each article has its own branch), but be careful to adjust the Gopath based on your development environment. At the same time you need to note that I developed on the Macbook, you may need to replace the makefiles in the ' $ (gopath) ' for ' $GOPATH '. The problem with operating system inconsistencies may be more than this one, but this is not listed here. # # Prerequisites-Mastering the Golang language and its development environment-install GRPC/PROTOBUF [view links] (https://grpc.io/docs/quickstart/go.html)-Install Golang [view links] (https:// Golang.org/doc/install)-Install Go's third-party library "Go get-u google.golang.org/grpc go get-u github.com/golang/protobuf/According to the following instructions Protoc-gen-go ' # # # What are we going to build? We will be building a very common micro-service-shipping container management platform. Of course, I can also use a micro-service to build a blog as an example, but it is simply too simple, I would like to be able to show the separation of complexity * * function. Finally I chose this management platform as an example, as a challenge! So, let's start with a few points of knowledge: # # What is MicroServices? In traditional monomer applications,All system features are written to a single application. Sometimes we use types to differentiate these features, such as controllers, unit modules, factories, and so on, and in other cases, for example, in larger applications, to differentiate application features with each other's relationships or their characteristics, so you might have an authorization package, a Friend relationship processing package, and an article Management Pack. These packages may have their own factories, services, databases, data models, and so on. Eventually, however, they were crammed into a code base. MicroServices are about making the second solution more thorough: separating the original relationships, and each package is saved in a separate, operational code base. # # Why do I use micro services? * * Complexity **--splits the program into multiple microservices according to features, helping to break chunks of code into smaller modules. As the old adage in Unix says, "Do one thing well" (doing, thing. In the system of monomer application, the modules tend to be closely combined and the relationship between the modules is very vague. This can cause system upgrades to be more dangerous and complex, with more potential bugs and more difficulty integrating. * * Extensibility **--in a single application system, the code for a particular module will be used more frequently than the rest of the module, and you can only expand the size of the entire library to address it. For example, your authentication module is called at high frequency, causing high load pressure on the system. So you expand the size of the library, and the reason is just a small authentication module. If you switch to MicroServices, you can expand any of the service modules independently, which means we can scale out more effectively. This separation is extremely helpful for multi-core, multi-region cloud computing. **nginx has an excellent micro-service series, which tells the various concepts, [please click on the link to access] (https://www.nginx.com/blog/introduction-to-microservices/). **## Why Choose Golang? Micro-services are supported in almost all languages. MicroServices are not a concrete framework or tool, but a concept. This means that in choosing a language to build microservices, there is always something more appropriate, or more supportive. Golang is one of the best. Golang is a lightweight, fast-running, high-concurrency-friendly language that supports multi-core, multi-device running scenarios. Golang also has a strong standard library on network services. Currently, there is a strong microservices framework--**go-micro**, which we will use in this series. # # PROTOBUF/GRPC Introduction microservices are split into multiple independent code repositories, which leads to an important issue-communication. In a single-application system, you can invoke the desired code anywhere in the code base, so there is no communication problem. Micro-services are distributed in differentCode base, you do not have the ability to call directly. So, you need to find a way to make data interactions between different services as low as possible. Here, we can adopt a traditional REST architecture, such as transmitting JSON or XML over HTTP. But this scenario poses a problem: service A encodes the raw data into the Json/xml format, sending a long string of characters to the service b,b to restore the original data by decoding it. However, when the amount of raw data is large, this can have a serious impact on communication. When we communicate with the Web browser, the format can be arbitrary as long as the communication between the services is agreed and the encoding and decoding methods are fixed. [GRPC] (https://grpc.io/) was born. GRPC is a Google-developed, RPC-based communication, lightweight binary transfer protocol. This definition is a little complicated, please let me have a word. The GRPC core data format is binary, and in the RESTful example above we use the JSON format, which is to send a string of strings over HTTP. The string includes its encoding format, length, and other bytes-consuming information, so the overall data volume is large. Based on the client-side string data, the server can notify the traditional browser and parse the expected data. But in the two microservices communication, we don't need all the data in the string, so we interact with hard-to-understand but lighter-weight binary data. GRPC uses the HTTP 2.0 specification that supports binary data, which also supports bidirectional traffic, which is pretty cool! HTTP 2 is the basis for GRPC work. If you want to learn more about HTTP 2, you can click on this [Google link] (https://developers.google.com/web/fundamentals/performance/http2/). The next question is what to do with binary data. Don't worry, GRPC has an internal digital analog language called PROTOBUF. PROTOBUF supports custom interface formats and is friendly to developers. Understanding Grpc and Protobuf, we're ready to start creating the first definition of a service. First, create the following file ' Consignment-service/proto/consignment/consignment.proto ' in the root directory of the codebase. For now, to make this tutorial easier to read, I'm using a single position, which is to store all of the services in a codebase. A lot of arguments and objections to the use of a single warehouse, I am not in-depth discussion here. Of course, you might want to store different services and components in separate code silos in your development, whichGenerally popular, but more complex. In the ' Consignment.proto ' file you just created, add the following: "' protobuf//consignment-service/proto/consignment/consignment.protosyntax = "Proto3";p ackage go.micro.srv.consignment; Service ShippingService {RPC createconsignment (consignment) returns (Response) {}}message Consignment {string id = 1; St Ring Description = 2; Int32 weight = 3; Repeated Container containers = 4; string vessel_id = 5;} Message Container {String id = 1; string customer_id = 2; string origin = 3; string user_id = 4;} Message Response {bool created = 1; Consignment consignment = 2;} "This is an example of a very basic definition, but there are a few things we need to master." First, you define the service content, which should include methods that you want to expose to other services. Next, you need to define the message types, which are very concise data structures. As in the above ' Container ' struct, protobuf is a static type that can be customized. Each message body is a type that they have customized. Two libraries are now in use: Messages are processed by PROTOBUF, and services are processed through GRPC's Protobuf plug-in and the messages are compiled into code for interaction, as in the ' Service ' section of the proto file. PROTOBUF defines a structure that can automatically generate binary data and functionality for the corresponding language through the client interface. Speaking of which, we'll come together. To create a Makefile for our service, the path is as follows ' $ touch consignment-service/makefile '. "' Makefilebuild:protoc-i--go_out=plugins=grpc:$ (gopath)/src/github.com/ewaNvalentine/shipper/consignment-service \ Proto/consignment/consignment.proto ' This Makefile will call the PROTOC library, will your PROTOBUF Compiled into the corresponding code. At the same time, we also specified the GRPC plug-in, the compile directory, and the output directory. After generating the Makefile file, go to the folder where the service is located, run the ' Make build ' command, and you will be able to see a new go file named ' Consignment.pb.go ' under ' proto/consignment/'. The GRPC/PROTOBUF library is used here to automatically convert the custom PROTOBUF structure into the code you want. Next, we will be able to formally build the service. Enter the project's root directory and create a file Main.go ' $ touch consignment-service/main.go '. "' go//consignment-service/main.gopackage mainimport (" Log "" NET "//import generated PROTOBUF code PB" Github.com/ewanvalentine/shi Pper/consignment-service/proto/consignment "" Golang.org/x/net/context "" Google.golang.org/grpc "" Google.golang.org/grpc/reflection ") const (port =": 50051 ") type IRepository interface {Create (*PB. Consignment) (*PB. Consignment, error)}//Repository-a virtual warehouse for simulating data storage, we will replace the real data warehouse type Repository struct {consignments []*PB] later. Consignment}func (Repo *repository) Create (consignment *PB. Consignment) (*PB. Consignment, error) {Updated: = append (repo.consignments, consignment) Repo.consiGnments = Updated return consignment, the nil}//service needs to implement all the methods defined in Protobuf. You can refer to the interface information in the go file generated by Protobuf. Type service struct {repo irepository}//createconsignment-only This method is currently created, including ' CTX ' (Environment information) and ' req ' (delegate request) two parameters, which are processed by the GRPC server Func (S *service) createconsignment (CTX context. Context, req *PB. Consignment) (*PB. Response, error) {//Save delegate Consignment, Err: = S.repo.create (req) If err! = Nil {return nil, err}//Return and Protobuf define matching ' Response ' message return &PB. Response{created:true, consignment:consignment}, Nil}func main () {repo: = &repository{}//Start GRPC server. Lis, Err: = Net. Listen ("TCP", port) if err! = Nil {log. Fatalf ("Failed to listen:%v", err)} s: = Grpc. NewServer ()///Register the service to the GRPC server and bind the defined protobuf with the automatically generated code interface. Pb. Registershippingserviceserver (S, &service{repo})//Register the Reflection service on the GRPC server. Reflection. Register (s) if err: = S.serve (LIS); Err! = Nil {log. Fatalf ("Failed to serve:%v", Err)}} "Please read the comments in the code carefully to help you understand the service." In short, the code implements the ability to create a GRPC server on port 50051,PROTOBUF generates a message format that implements the logic of GRPC interface interaction. In this way, you have completed a full-featured GRPC service! You can enter the command ' Go run main.go ' to run this program, however, currently, from the interface you also see nothing. How can you see this GRPC server working properly? Let's create a client to dock with it! Next, let's write a command-line interactive program that reads a JSON file containing the delegate information and interacts with the GRPC server we've created. Go to the root directory and enter the command line to create a new subfolder ' $ mkdir consignment-cli '. In the folder, create a new file ' Cli.go ', code as follows: ' ' go//consignment-cli/cli.gopackage mainimport ("Encoding/json" "Io/ioutil" "Log" "OS" PB "Github.com/ewanvalentine/shipper/consignment-service/proto/consignment" "Golang.org/x/net/context" " Google.golang.org/grpc ") const (address =" localhost:50051 "defaultfilename =" Consignment.json ") Func parsefile (file String) (*PB. Consignment, error) {var consignment *pb. Consignment data, err: = Ioutil. ReadFile (file) if err! = Nil {return nil, err} json. Unmarshal (data, &consignment) return consignment, Err}func main () {//Create and a connection to the server conn, err: = Grpc. Dial (address, grpc. Withinsecure ()) if err! = Nil {log. Fatalf ("Did not connect:%v", err)} defer conn. Close () Client: = PB. Newshippingserviceclient (Conn)//and server communication, and print out the return information file: = Defaultfilename if Len (OS. Args) > 1 {file = os. ARGS[1]} consignment, err: = Parsefile (file) if err! = Nil {log. Fatalf ("Could not parse File:%v", err)} r, Err: = client. Createconsignment (context. Background (), consignment) if err! = Nil {log. Fatalf ("Could not greet:%v", err)} log. Printf ("Created:%t", r.created)} "at the same time, create a delegate information file ' Consignment-cli/consignment.json '" "json{" description ":" This is a test consignment "," weight ": 550," containers ": [{" customer_id ":" cust001 "," user_id ":" user001 "," origin ":" Manche Ster, Kingdom "}]," vessel_id ":" vessel001 "}" "After completing the above steps, run ' Go run consignment-service ' under ' main.go ', then open a new terminal interface , run ' Go Run Cli.go ', and you'll see a message ' created:true '. However, how can we confirm that this delegate is actually generated? Let's continue to update our service, add a ' getconsignments ' method and be able to see all the created delegates. First we need to update our proto definition (I added a comment in the modification section) ' protobuf//Consignment-service/proto/consignment/consignment.protosyntax = ' Proto3 ";p ackage go.micro.srv.consignment;service shippingservice {RPC CreateconsignmeNT (Consignment) returns (Response) {}//Create a new method RPC Getconsignments (getrequest) returns (Response) {}}message consignmen t {string id = 1; string description = 2; Int32 weight = 3; repeated Container containers = 4; string vessel_id = 5;} Message Container {String id = 1; string customer_id = 2; string origin = 3; string user_id = 4;} Create a blank GET request message Getrequest {}message Response {bool created = 1; Consignment consignment = 2; Add an array to return the list of delegates repeated consignment consignments = 3;} "We have successfully created a new method called ' getconsignments ' and ' getrequest ' on the service, which does not currently contain any content. We also added the ' consignments ' parameter in the reply message. You may notice that the type of the parameter has a keyword: ' repeated '. As the name implies, this means that the parameter is saved as an array. Now, let's run the ' $ make build ' command again and start your service, and you'll see a similar ' *service does not implement Go_micro_srv_consignment. Shippingserviceserver (missing getconsignments method) ' error message. The interface generated by the PROTOBUF library must match exactly on both ends of the communication, which is the basis for implementing the GRPC. So, we need to make sure that the definition of proto is consistent. Let's update the next ' consignment-service/main.go ' file: ' Gopackage mainimport ("Log" "NET"//import generated PROTOBUF code PB "Github.com/ewanvaleNtine/shipper/consignment-service/proto/consignment "" Golang.org/x/net/context "" Google.golang.org/grpc "" Google.golang.org/grpc/reflection ") const (port =": 50051 ") type IRepository interface {Create (*PB. Consignment) (*PB. Consignment, error) GetAll () []*PB. consignment}//Repository-A virtual warehouse for analog data storage, we will replace the real data warehouse type Repository struct {consignments []*PB] in the future. Consignment}func (Repo *repository) Create (consignment *PB. Consignment) (*PB. Consignment, error) {Updated: = append (repo.consignments, consignment) Repo.consignments = updated return consignment, ni L}func (Repo *repository) GetAll () []*PB. Consignment {return repo.consignments}//service needs to implement all the methods defined in Protobuf. You can refer to the interface information in the go file generated by Protobuf. Type service struct {repo irepository}//createconsignment-only This method is currently created, including ' CTX ' (Environment information) and ' req ' (delegate request) two parameters, which are processed by the GRPC server Func (S *service) createconsignment (CTX context. Context, req *PB. Consignment) (*PB. Response, error) {//Save delegate Consignment, Err: = S.repo.create (req) If err! = Nil {return nil,ERR}//Return and Protobuf define a matching ' Response ' message in return &PB. Response{created:true, consignment:consignment}, Nil}func (S *service) getconsignments (CTX context. Context, req *PB. Getrequest) (*PB. Response, error) {consignments: = S.repo.getall () return &PB. Response{consignments:consignments}, Nil}func main () {repo: = &repository{}//Starts the GRPC server. Lis, Err: = Net. Listen ("TCP", port) if err! = Nil {log. Fatalf ("Failed to listen:%v", err)} s: = Grpc. NewServer ()///Register the service to the GRPC server and bind the defined protobuf with the automatically generated code interface. Pb. Registershippingserviceserver (S, &service{repo})//Register the Reflection service on the GRPC server. Reflection. Register (s) if err: = S.serve (LIS); Err! = Nil {log. Fatalf ("Failed to serve:%v", Err)}} "Now we have referenced the new ' Getconsignments ' method, updated the library and interface, and satisfied the proto definition on both sides. After running ' Go run Main.go ' again, the service will work properly. Back to our client tool, we list all the delegates by calling the ' Getconsignments ' method: ' Gofunc main () {...//... ' means consistent with the previous code, no longer repeating getAll, err: = client. Getconsignments (context. Background (), &PB. getrequest{}) If err! = Nil {log. Fatalf ("Could not list consignments:%v", Err)} for _, V: = range getall.consignments {log. Println (v)}} "" In the original main function, find the location where the ' created:success ' log is printed, add the above code after that, and then run ' Go run Cli.go '. The program creates a delegate, followed by the call ' getconsignments '. When you run more times, the list of delegates gets longer. * Note: In order to look concise, I sometimes use ' ... ' to indicate exactly the same as the previous code. After a few lines of new code, need to manually add to the original code * Here, we have completely created a microservices and a client that interacts with PROTOBUF and GRPC. The next section of this series will be expanded around integration [Go-micro] (Https://github.com/micro/go-micro). Go-micro is a microservices-based, powerful framework for creating GRPC. We will also create a second microservices-container service in the next chapter. The word "container" may confuse you, which refers specifically to the "container" concept in Docker. We'll explore the operation of microservices in Docker containers in the next chapter. If you have any bugs, errors or feedback on this article, please email [contact me] (ewan.valentine89@gmail.com). This tutorial contains the code base [link] (https://github.com/ewanvalentine/shippy), with the ' Git ' Tool Checkout Branch ' TUTORIAL-1 ' Chapter I. The second chapter will also be updated in the near future. Writing this article took me a long time and a lot of energy. If you think this series is helpful, please think about rewarding me (it depends entirely on your wishes). Thank you very much! [Https://monzo.me/ewanvalentine] (https://monzo.me/ewanvalentine) Acknowledgements: MicroServices Newsletter (22nd November 2017)
via:https://ewanvalentine.io/microservices-in-golang-part-1/
Author: Ewan Valentine Translator: Junedayday proofreading: Rxcai
This article by GCTT original compilation, go language Chinese network honor launches
This article was originally translated by GCTT and the Go Language Chinese network. Also want to join the ranks of translators, for open source to do some of their own contribution? Welcome to join Gctt!
Translation work and translations are published only for the purpose of learning and communication, translation work in accordance with the provisions of the CC-BY-NC-SA agreement, if our work has violated your interests, please contact us promptly.
Welcome to the CC-BY-NC-SA agreement, please mark and keep the original/translation link and author/translator information in the text.
The article only represents the author's knowledge and views, if there are different points of view, please line up downstairs to spit groove
4,627 reads ∙6 likes