Detailed explanation of Python using consumer for service discovery example

Time:2021-10-19

preface

The previous chapter talked about some advantages and disadvantages of microservices, and how to do it

1、 Target

2、 Use steps

1. Install consumer

We can directly use the binaries provided by the official for installation and deployment. The official website address is https://www.consul.io/downloads

Detailed explanation of Python using consumer for service discovery example

After downloading, it is an executable file, which can be used directly during our development and experimentconsul agent -devCommand to start a single node consumer

You can see it in the print log of startupagent: Started HTTP server on 127.0.0.1:8500 (tcp), we can access it directly in the browser127.0.0.1:8500You can see the following

Detailed explanation of Python using consumer for service discovery example

Here, our consumer starts successfully

2. Service registration

In network programming, the IP, port and protocol of the project are generally provided. In service governance, we also need to know the corresponding service name, instance name and some user-defined extension information

Use hereServiceInstanceInterface to specify some information necessary to register a service

class ServiceInstance:

 def __init__(self, service_id: str, host: str, port: int, secure: bool = False, metadata: dict = None,
   instance_id: str = None):
 self.service_id = service_id
 self.host = host
 self.port = port
 self.secure = secure
 self.metadata = metadata
 self.instance_id = instance_id

 def get_instance_id(self):
 return

Define base class

The necessary information of the services to be registered is specified above. The methods of service registration and elimination are defined below to facilitate the implementation of Eureka and redis in the future

import abc


class ServiceRegistry(abc.ABC):

 @abc.abstractmethod
 def register(self, service_instance: ServiceInstance):
 pass

 @abc.abstractmethod
 def deregister(self):
 pass

Concrete implementation

Because the consumer provides an HTTP interface to operate the consumer, we can also use the HTTP request method to register and reject. See the HTTP interface document for detailshttps://www.consul.io/api-docs, consumer does not provide an implementation of Python language, so it is used herepython-consulTo access the consumer

import consul


class ConsulServiceRegistry(ServiceRegistry):
 _consul = None
 _instance_id = None

 def __init__(self, host: str, port: int, token: str = None):
 self.host = host
 self.port = port
 self.token = token
 self._consul = consul.Consul(host, port, token=token)

 def register(self, service_instance: ServiceInstance):
 schema = "http"
 if service_instance.secure:
  schema = "https"
 check = consul.Check.http(f'{schema}:{service_instance.host}:{service_instance.port}/actuator/health', "1s",
     "3s", "10s")
 self._consul.agent.service.register(service_instance.service_id,
      service_id=service_instance.instance_id,
      address=service_instance.host,
      port=service_instance.port,
      check=check)
 self._instance_id = service_instance.instance_id

 def deregister(self):
 if self._instance_id:
  self._consul.agent.service.deregister(service_id=self._instance_id)
  self._instance_id = None

3. Service discovery

In service discovery, two methods are generally required

  • Get a list of all services
  • Gets all instance information of the specified service

Base class definition

import abc


class DiscoveryClient(abc.ABC):

 @abc.abstractmethod
 def get_services(self) -> list:
 pass

 @abc.abstractmethod
 def get_instances(self, service_id: str) -> list:
 pass

Concrete implementation

Let’s do it

This is a simplified version, so some parameters are written directly. If necessary, they can be modified appropriately

import consul


class ConsulServiceDiscovery(DiscoveryClient):

 _consul = None

 def __init__(self, host: str, port: int, token: str = None):
 self.host = host
 self.port = port
 self.token = token
 self._consul = consul.Consul(host, port, token=token)

 def get_services(self) -> list:
 return self._consul.catalog.services()[1].keys()

 def get_instances(self, service_id: str) -> list:
 origin_instances = self._consul.catalog.service(service_id)[1]
 result = []
 for oi in origin_instances:
  result.append(ServiceInstance(
  oi.get('ServiceName'),
  oi.get('ServiceAddress'),
  oi.get('ServicePort'),
  oi.get('ServiceTags'),
  oi.get('ServiceMeta'),
  oi.get('ServiceID'),
  ))
 return result

4. Test cases

import unittest
from random import random

class MyTestCase(unittest.TestCase):
 def test_consul_register(self):
 instance = ServiceInstance("abc", "127.0.0.1", 8000, instance_id=f'abc_{random()}')

 registry = ConsulServiceRegistry("127.0.0.1", 8500)
 discovery = ConsulServiceDiscovery("127.0.0.1", 8500)
 registry.register(instance)
 print(discovery.get_services())
 print(discovery.get_instances("abc"))
 self.assertEqual(True, True)
if __name__ == '__main__':
 unittest.main()

summary

By using the consumption API, we can simply realize the service discovery based on consumption. We can simply realize the service call by combining HTTP RPC. In the following chapter, we will briefly talk about how go initiates HTTP requests to pave the way for us to do RPC

See for specific code https://github.com/zhangyunan1994/gimini

reference resources

https://www.consul.io/api-docs

https://github.com/hashicorp/consul/tree/master/api

This is the end of this article on Python’s use of consumer for service discovery. For more information about Python’s use of consumer services, please search for previous articles on developepper or continue to browse the relevant articles below. I hope you will support developepper in the future!