1. Definition of microservices:

Can be understood as an application that a single programmer can design, implement, deploy, and maintain. In a holistic application, components call each other through language-level methods or functions. In contrast, microservices-based applications are distributed systems running on multiple machines, with each service instance being a different process. Therefore, these services need to interact using interprocess communication.

The simplest solution for communication between services is to use JSON format data to interact based on HTTP protocol, in addition, there are such as gRPC, PUB/SUB, etc.

Microservices also pose a number of challenges:

  • serialization
  • logging
  • fusing
  • Request tracking
  • Service discovery

2. go-kit

Go-kit is a go language related microservices toolkit that calls itself Toolkit, not a framework. Go-kit is a collection of services that provide an interface, giving developers the freedom to build their own microservices.

2.1 the go – kit components

2.1.1 Service

The specific business processing logic is placed here, and the service generally takes interface as the model, for example:

// StringService provides operations on strings.
type StringService interface {
    Uppercase(string) (string, error)
    Count(string) int
}
Copy the code

And then this interface needs a concrete implementation

type stringService struct{}
func (stringService) Uppercase(s string) (string, error) {
    if s == "" {
        return "", ErrEmpty
    }
    return strings.ToUpper(s), nil
}
func (stringService) Count(s string) int {
    return len(s)
}
// ErrEmpty is returned when input string is empty
var ErrEmpty = errors.New("Empty string")
Copy the code
2.1.2 the Endpoint

The endpoint, the most important layer of Go-Kit, is an abstract function type that receives requests and returns responses. In this defined type, the method on the service layer will be called, and the response will be assembled and returned. All middleware components in GoKit are injected through decorator design patterns. The endpoint also provides extended capabilities for logging, traffic limiting, fusing, link tracing, and service monitoring.

type Endpoint func(ctx context.Context, request interface{}) (response interface{}, err error) func makeUppercaseEndpoint(svc StringService) endpoint.Endpoint { return func(ctx context.Context, request interface{}) (interface{}, error) { req := request.(uppercaseRequest) v, err := svc.Uppercase(req.S) if err ! = nil { return uppercaseResponse{v, err.Error()}, nil } return uppercaseResponse{v, ""}, nil } }Copy the code
2.1.3 Transport

Transport is primarily about exposing services to the non-external world by some means of transport so that these services can be invoked. Go-kit supports multiple transmission modes out of the box, such as HTTP and RPC. HTTP JSON is used here.

import ( httptransport "github.com/go-kit/kit/transport/http" ) func main() { ctx := context.Background() svc := stringService{} uppercaseHandler := httptransport.NewServer( ctx, makeUppercaseEndpoint(svc), decodeUppercaseRequest, encodeResponse, ) countHandler := httptransport.NewServer( ctx, makeCountEndpoint(svc), decodeCountRequest, encodeResponse, ) http.Handle("/uppercase", uppercaseHandler) http.Handle("/count", countHandler) } func decodeUppercaseRequest(_ context.Context, r *http.Request) (interface{}, error) { var request uppercaseRequest if err := json.NewDecoder(r.Body).Decode(& request); err ! = nil { return nil, err } return request, nil } func decodeCountRequest(_ context.Context, r *http.Request) (interface{}, error) { var request countRequest if err := json.NewDecoder(r.Body).Decode(& request); err ! = nil { return nil, err } return request, nil } func encodeResponse(_ context.Context, w http.ResponseWriter, response interface{}) error { return json.NewEncoder(w).Encode(response) }Copy the code
2.1.4 Request Tracing Tracing

Reference: segmentfault.com/a/119000001…

Microservice is a distributed architecture, which is divided into units according to services. A distributed system often has many service units. Due to the large number of service units and the complexity of the business, it is difficult to locate errors and exceptions if they occur. This is mainly reflected in that a request may need to invoke many services, and the complexity of internal service invocation makes it difficult to locate problems. Therefore, in the microservice architecture, distributed link tracking must be implemented to follow up which services are involved in a request and the order of participation, so that the steps of each request can be clearly seen.

Go-kit offers two types of link tracing: OpenTracing and Zipkin

Here’s a quick introduction to Zipkin:

Zipkin can help collect time data, and also provides the collection and query function of distributed system time data. Zipkin architecture:

Zipkin consists of four components: Collector, Storage, API and UI. Reporter is provided and collected by the application system. Its working principle is as follows:

  • Embed a Tracer in the application, which uses a Span to record the timing and metadata information of application actions;
  • Reporter sends Span to Zipkin’s data Collector;
  • Collector Stores data to the database through the Storage component.
  • UI component queries and displays tracking data through API interface;

Zipkin traces a request through a trace structure. A request is processed by several services. Each service generates a SPAN. The main data model of SPAN is as follows:

2.1.5 API monitoring

In microservices, API is almost the only interaction channel between the service and the outside world, and the stability and reliability of API are becoming more and more important. We need to know the API health in real time (number of requests, latency, failures, etc.) and we need to analyze historical data to know which APIS have performance bottlenecks for later optimization. Therefore, in order to ensure that the system provides services well, most microservice frameworks also integrate API monitoring components. Prometheus is an open source system monitoring and alarm framework for metheus. As a new generation of monitoring framework, it has the following characteristics:

  • Provide powerful multidimensional data models such as Counter, Gauge, Histogram, Summary;
  • The powerful and flexible query statement can conveniently realize the query and aggregation operation of time series data;
  • Easy to manage and efficient;
  • Provide pull mode and push gateway to collect time series data.
  • Supports multiple visual graphical interfaces: Grafana, Web UI, API Clients;
  • Alarm rule management, alarm detection and alarm push function

Modify main.go to create counter collection objects, including request count collection objects and request delay collection objects.

count := kitprometheus.NewCounterFrom(stdprometheus.CounterOpts{
	Namespace: "51world",
	Subsystem: "stringService",
	Name:      "request_count",
	Help:      "Number of requests received.",
}, fieldKeys)
latency := kitprometheus.NewSummaryFrom(stdprometheus.SummaryOpts{
	Namespace: "51world",
	Subsystem: "stringService",
	Name:      "request_latency_seconds",
	Help:      "Total duration of requests in seconds.",
}, fieldKeys)
Copy the code