Through the service discovery and registry, it is easy to manage the dynamic service instance information in the system. At the same time, it may also become the bottleneck and failure point of the system. Because the information for invocations between services comes from the service registry and discovery center, invocations between services may not work properly when it is unavailable. Therefore, service discovery and registries tend to be multi-instance deployments, providing high availability and stability.

We will implement service registration and discovery for Golang Web based on Consul. We will first interact with Consul via HTTP in a native way. We will then interact with Consul through the Consul Client interface provided by the Go Kit framework and compare the differences between them.

In the previous article, we learned about the complete ConsulClient architecture of microservices, and we’ll start writing an implementation of the core ConsulClient interface to complete the simple process of registering and discovering services between Consul and microservices.

Service instance interacts with Consul

In this section, we will directly interact with Consul via HTTP to complete service registration and service discovery functions. We first define the service registration service instance structure of diy. InstanceInfo, source located at ch7 – discovery/diy/MyConsulClient. Go. The code looks like this:

// Service instance structure
type InstanceInfo struct {
	ID string `json:"ID"` // Service instance ID
	Name string `json:"Name"` / / service name
	Service string `json:"Service,omitempty"` // The name of the service returned when the service is discovered
	Tags []string `json:"Tags,omitempty"` // tag that can be used for service filtering
	Address string `json:"Address"` // Service instance HOST
	Port int `json:"Port"` // Service instance port
	Meta map[string]string `json:"Meta,omitempty"` / / metadata
	EnableTagOverride bool `json:"EnableTagOverride"` // Whether to allow label overwriting
	Check `json:"Check,omitempty"` // Health check configurations
	Weights `json:"Weights,omitempty"` / / weight
}

type Check struct {
	DeregisterCriticalServiceAfter string `json:"DeregisterCriticalServiceAfter"` // How long will it take to unregister the service
	Args []string `json:"Args,omitempty"` // Request parameters
	HTTP string `json:"HTTP"` // Health check address
	Interval string `json:"Interval,omitempty"` Consul took the initiative to conduct a health check
	TTL string `json:"TTL,omitempty"` // The service instance voluntarily submits a health check
}

type Weights struct {
	Passing int `json:"Passing"`
	Warning int `json:"Warning"`
}

Copy the code

The service instance information submitted to Consul includes:

  • Service instance ID, which uniquely identifies the service instance
  • The service name is the service cluster to which the service instance belongs
  • Address, Port, service Address and Port for initiating inter-service calls
  • Check: Health Check information, including the health Check address and interval.

Consul allows Consul to proactively invoke the health check interface provided by a service instance to maintain heartbeat communication, and a service instance to proactively submit health check data to Consul to maintain heartbeat communication. The Interval and TTL parameters in Check are used to set the Check Interval respectively. Only one of them can be set. Our microservice is proactive and provides a /health interface checked by Consul call.

. Then we define diy ConsulClint the creation of a structure and its function, which is located in ch7 – discovery/diy/MyConsulClient. Go, the code is as follows:

Type ConsulClient struct {Host Port int // Consul Port int // Consul Port} consulPort int) *ConsulClient { return &ConsulClient{ Host: consulHost, Port: consulPort, } }Copy the code

Consul to get a DIY.ConsulClient you need to pass Consul’s exact address, that is, Host and Port.

After we at ch7 – discovery/diy/MyConsulClient. Go down the implementation ch7 – discovery/ConsulClient interface, and the receiver at the specified method diy. ConsulClient, empty method code is as follows:

func (consulClient *ConsulClient) Register(serviceName, instanceId, healthCheckUrl string, instancePort int, meta map[string]string, logger *log.Logger) bool{
	return false
}

func (consulClient *ConsulClient) DeRegister(instanceId string, logger *log.Logger) bool {
	return false
}

func (consulClient *ConsulClient) DiscoverServices(serviceName string) []interface{} {return nil
}


Copy the code

Service registration and health check

We first implement the function of a service Register, which implements the Register interface and specifies the method receiver as D.I.Y. ConsulClient. Source is located at ch7 – discovery/diy/MyConsulClient. Go, the code is as follows:

func (consulClient *ConsulClient) Register(serviceName, instanceId, healthCheckUrl string, instancePort int, meta map[string]string, logger *log.Logger) bool{

	// Obtain the local IP address of the service
	instanceHost := ch7_discovery.GetLocalIpAddress()

	Encapsulate the metadata of the service instance
	instanceInfo := &InstanceInfo{
		ID:      instanceId,
		Name:    serviceName,
		Address: instanceHost,
		Port:    instancePort,
		Meta: meta,
		EnableTagOverride: false,
		Check: Check{
			DeregisterCriticalServiceAfter: "30s",
			HTTP:                           "http://" + instanceHost + ":" + strconv.Itoa(instancePort) + healthCheckUrl,
			Interval:						"15s",
		},
		Weights: Weights{
			Passing: 10,
			Warning: 1,
		},
	}

	byteData,_ := json.Marshal(instanceInfo)

	// 2. Send a service registration request to Consul
	req, err := http.NewRequest("PUT"."http://" + consulClient.Host + ":" + strconv.Itoa(consulClient.Port) + "/v1/agent/service/register",
		bytes.NewReader(byteData))

	if err == nil {
		req.Header.Set("Content-Type"."application/json; charset=UTF-8")
		client := http.Client{}
		resp, err := client.Do(req)
		// 3. Check the registration result
		iferr ! =nil {
			log.Println("Register Service Error!")}else {
			resp.Body.Close()
			if resp.StatusCode == 200 {
				log.Println("Register Service Success!")
				return true;
			} else {
				log.Println("Register Service Error!")}}}return false
}
Copy the code

The Register method performs the following operations:

  1. The service instance data is encapsulated as InstanceInfo, in which key data such as service instance ID, service name, service address, and service port are set. The health check address is /health and the check interval is 15 seconds. DeregisterCriticalServiceAfter parameter defines the health examination within 30 s failure, the service instance will be Consul active referrals.
  2. Through HTTP launched an registration request, the Consul will step on encapsulated InstanceInfo submitted to the registry, registered service address for/v1 / agent/service/register.

In the main function, we define that a service starts with a call to consult Client#Register. You can verify service registration and health check by starting the microservice in the CH7-discovery directory by running the following command:

 go run main/SayHelloService.go
Copy the code

You can see that the corresponding startup and health check logs are displayed on the command line:

2019/07/08 20:45:21 Register Service Success!
2019/07/08 20:45:22 Health check starts!
Copy the code

Visit http://localhost:8500 on Consul’s homepage and you can see that the SayHello service has been registered with Consul, as shown in the following figure:

Directly click the SayHello service in the page to enter the service cluster page and view the service instance information under the cluster, as shown in the figure:

The figure above shows the key information of the service instance ID, address and port that we registered.

summary

This paper mainly realizes the interaction process between Microservice instance and Consul, service registration and health check. So how to unregister a service once it is registered, and how to let other services find it?

The following articles continue to implement service logout and service discovery.

The full code, from my Github,Github.com/longjoy/mic…

Phase to recommend

  1. Do you know the game theory developed by Von Neumann, the “father of modern computing”?
  2. How to learn ETCD? | I’m book

3. Realize Go service registration and discovery by yourself (PART 1)

Read the latest article, pay attention to the public number: AOHO Qiusuo