Build your first Go Micro service

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

Part Two: Go microservices-building our first service

The second part contains:

    • Set up our Go workspace.
    • Build our first micro-service.
    • Use Gorilla WEB Toolkit to provide some JSON services over HTTP.

Introduced

While providing JSON services over HTTP is not the only option for internal and external services, this article focuses on HTTP and JSON. It is also interesting to use RPC mechanisms and binary message formats (such as Protocol Buffer) for internal communications or for external communication, especially when external consumers belong to another system. The go language has built-in RPC support, and GRPC is definitely worth looking at. However, we are now focusing only on HTTP provided by HTTP packets and Gorilla WEB Toolkit.

Another aspect to consider is a lot of useful frameworks (security, tracking, and so on) that rely on HTTP headers to transmit the status of requests being made by participants. The example we will see in this article is how we pass the correlation ID and OAuth ticket in the header. While other protocols certainly support similar mechanisms, many frameworks are built with HTTP, and I prefer to keep our integrations as straightforward as possible.

Set up Go workspace

If you are an experienced go developer, you can skip this section at will. In my humble opinion, the work space structure of Go language takes some time to adapt. In general, I am accustomed to using the project root as the root of the workspace, the Go language conventions how to properly construct the workspace, so the go compiler can find source code and dependencies, a bit unorthodox, Put the source code in a subdirectory under the source control path in the directory named SRC. I highly recommend reading the official guide and this article before you start. I wish I was like this.

Installing the SDK

Before we start writing our first line of code (or before check out the full code), we need to install the Go Language SDK. It is advisable to follow the official instructions and the direct operation is sufficient.

Setting up the development environment

In these blog series, we will use the built-in Go SDK tools we have installed to build and run our code, and to set the work space of go in the usual way.

1. Create a workspace root directory

All commands are based on the OS X or Linux development environment. If you are running Windows, take the necessary instructions.

mkdir ~/goworkspacecd goworkspaceexport GOPATH=`pwd`

Here we create a root directory and then assign the GOPATH environment variable to that directory. This is the root of our workspace, and all of the Go language codes and third-party class libraries We write are underneath it. I recommend adding this gopath to a. bash_profile file or a similar configuration file, so that you do not have to reset it every time for each console window.

2. Create a folder and file for our first project

Since we have already specified the same directory in the root directory of the workspace (for example, and in the GOPATH environment variable), execute the following statement:

mkdir -p src/github.com/callistaenterprise

If you want to follow your own code, you can execute the following command:

cd src/github.com/callistaenterprisemkdir -p goblog/accountservicecd goblog/accountservicetouch main.gomkdir service

Or you can clone this Git repository, contain the same code, and switch to the P2 branch. From the Src/github.com/callistaenterprise/goblog.git directory you created above, execute the following command.

git clone https://github.com/callistaenterprise/goblog.gitcd gobloggit checkout P2

Remember: $GOPATH/src/github.com/callistaenterprise/goblog is the root of our project and is actually stored on GitHub.

Then we have enough structure to start easily. Open the Main.go file with your favorite IDE.

Create service-Main.go

The main function in the go language is where you do things-the entry point for the Go language application. Let's take a look at its specific code:

package mainimport (    "fmt")var appName = "accountservice"func main() {    fmt.Printf("Starting %v\n", appName)}

Then run the program:

> go run path/to/main.goStarting accountservice

That's it, the program only prints a string and then exits. It's time to add the first HTTP endpoint.

Building an HTTP Web server

Note: The basics of these HTTP examples are derived from a good blog post, see the reference link.

To keep the code clean, we put all the HTTP service-related files under the service directory.

Start the HTTP server

Create the Webservice.go file in the service directory.

package serviceimport (    "log"    "net/http")func StartWebServer(port string) {    log.Println("Starting HTTP service at " + port)    err := http.ListenAndServe(":"+port, nil) // Goroutine will block here    if err != nil {        log.Println("An error occured starting HTTP listener at port " + port)        log.Println("Error: " + err.Error())    }}

Above we use the built-in Net/http package to execute the Listenandserve, starting an HTTP server at the specified port number.

Then we update the following MAIN.GO code:

package mainimport (    "fmt"    "github.com/callistaenterprise/goblog/accountservice/service" // 新增代码)var appName = "accountservice"func main() {    fmt.Printf("Starting %v\n", appName)    service.StartWebServer("6767") // 新增代码}

Then run this program again to get the following output:

> go run *.goStarting accountservice2017/01/30 19:36:00 Starting HTTP service at 6767

So now we have an HTTP server that listens on the 6767 port of localhost. Then curl it:

> curl http://localhost:6767404 page not found

Getting 404 is completely predictable, because we haven't added any routes yet.

CTRL + C stops this Web server.

Add a first route

It's time for our servers to provide some real service. We first declare our first route with the go language structure, and we will use it to populate the gorilla router. In the service directory, create a routes.go file.

package serviceimport (    "net/http")// Define a single route, e.g. a human readable name, HTTP method and the pattern the function that will execute when the route is called.type Route struct {    Name        string    Method      string    Pattern     string    HandlerFunc http.HandlerFunc}// Defines the type Routes which is just an array (slice) of Route structs.type Routes []Routevar routes = Routes{    Route{        "GetAccount", // Name        "GET",        // HTTP method        "/accounts/{accountId}", // Route pattern        func(w http.ResponseWriter, r *http.Request) {            w.Header().Set("Content-Type", "application/json; charset=UTF-8")            w.Write([]byte("{\"result\":\"OK\"}"))        },    },}

In the code snippet above, we declare a path/accounts/{accountid}, and we will use curl to access it later. Gorilla also supports complex routing using regular pattern matching, schemes, methods, queries, headers values, and so on. Therefore, path and path parameters are not limited.

In response, we hardcoded a small JSON message:

{    "result": "OK"}

We also need some modular code snippets to hook up our declared routes to the actual gorilla router. In the service directory, we create the Router.go file:

package serviceimport (    "github.com/gorilla/mux")// Function that returns a pointer to a mux.Router we can use as a handler.func NewRouter() *mux.Router {    // Create an instance of the Gorilla router    router := mux.NewRouter().StrictSlash(true)    // Iterator over the routes we declared in routes.go and attach them to the router instance    for _, route := range routes {        // Attach each route, uses a Builder-like pattern to set each route up.        router.Methods(route.Method).            Path(route.Pattern).            Name(route.Name).            Handler(route.HandlerFunc)    }    return router}

Importing dependent Packages

In the import area of Router.go, we declare a dependency Github.com/gorilla/mux package. We can get the source code of the dependent package through go get.

Wrapping up

We can go back to the Webserver.go file and add the following two lines of code at the beginning of the function Startwebserver.

func StartWebServer(port string) {    r := NewRouter()    http.Handle("/", r)}

This binds the router we just created to the processing of the Http.handle pair/path. Then recompile and run the modified code:

> go run *.goStarting accountservice2017/01/31 15:15:57 Starting HTTP service at 6767

Then open another window, curl as follows:

> curl http://localhost:6767/accounts/10000{"result":"OK"}

Well, we now have our first HTTP service.

Information and performance (footprint and performance)

Given that we're exploring go-based microservices, because of the amazing memory footprint and good performance, we'd better be able to benchmark quickly to see how they perform.
I have developed a simple Gatling test that can be used to thrash/accounts/{accountid} with a GET request. If before you were directly from Https://github.com/callistaen ..., then your source code would contain the load test codes goblog/loadtest. Or you can view Https://github.com/callistaen directly ....

You run the load test yourself.

If you need to run the load test tool yourself, make sure that the Accountservice service is up and running on port 6767 on localhost. And you have checkout the code of our P2 branch. You also need the Java Runtime environment and the need to install Apache Maven.

To change the directory to the Goblog/loadtest directory, execute the following command at the command line.

mvn gatling:execute -Dusers=1000 -Dduration=30 -DbaseUrl=http://localhost:6767

This will start and run the test. The parameters are as follows:

    • Users: Number of concurrent users for simulated tests.
    • Duration: Test the number of seconds to run.
    • BASEURL: The underlying path to the service we are testing. When we migrated it to Docker Swarm, BaseURL modified the public IP that was modified to swarm. Introduced in the 5th chapter.

For the first run, MVN will automatically install a lot of stuff. After the test is finished, it writes the results to the console window and produces a report to the HTML in Target/gatling/results.

Results

Note: Later, when our services are running into Docker swarm mode Docker containers, we will do all the benchmarking and capture metrics there.

Before starting the load test, our go-based accountservice memory consumption can be seen from the task manager of the MacBook, presumably as follows:

1.8MB, not particularly bad. Let's use the Gatling test to run 1000 requests per second. One thing to keep in mind is that we used a very naïve implementation, and we just responded with a hard-coded JSON response.

The service is 1000 requests per second, and the memory consumed is only increased to 28MB. The spring boot application still uses 1/10 of the memory when it starts. When we add some real features to it, it's more interesting to see how these numbers change.

Performance and CPU Usage

Provide 1000 requests per second, approximately 8% per core.

Note how latency is Gatling for a round of microseconds, but the average latency report value is 0ms per request and takes a huge 11 milliseconds. At this point, our Accountservice performs well, serving 745 requests per second in the sub-millisecond range.

Next Chapter

In the next section, we will really let accountservice do something meaningful. We will add a simple embedded database to the account object and then provide the HTTP service. We'll also look at JSON serialization and check the impact of these additions on footprints and performance.

Reference links

    • http://callistaenterprise.se/...
    • Http://thenewstack.io/make-a-...
    • https://github.com/gorilla/
    • Topic Home
    • Next section
Related Article

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.