什么是服务注册与发现
在微服务架构中,整个系统会按职责能力划分为多个服务,通过服务之间协作来实现业务目标。
这样在我们的代码中免不了要进行服务间的远程调用,服务的消费方要调用服务的生产方,为了完成一次请求,消费方需要知道服务生产方的网络位置(IP地址和端口号)。
我们的代码可以通过读取配置文件的方式读取服务生产方网络位置,如下:
我们通过Spring boot技术很容易实现:
Service B(服务生产者)
Service B是服务的生产方,暴露/service服务地址,实现代码如下:
@SpringBootApplication
@RestController
public class SpringRestProviderBootstrap {
public static void main(String[] args) {
SpringApplication.run(SpringRestProviderBootstrap.class, args);
}
@GetMapping(value = "/service") //暴露服务
public String service(){
return "provider invoke";
}
}
配置文件:
server.port = 56010
Service A(服务消费者)
实现代码:
@SpringBootApplication
@RestController
public class SpringRestConsumerBootstrap {
public static void main(String[] args) {
SpringApplication.run(SpringRestConsumerBootstrap.class, args);
}
@Value("${provider.address}")
private String providerAddress;
@GetMapping(value = "/service")
public String service(){
RestTemplate restTemplate = new RestTemplate();
//调用服务
String providerResult = restTemplate.getForObject("http://" + providerAddress + "/service",String.class);
return "consumer invoke | " + providerResult;
}
}
配置文件:
server.port = 56020
# 服务生产方地址
provider.address = 127.0.0.1:56010
访问http://127.0.0.1:56020/service,输出以下内容:
consumer invoke | provider invoke
看上去很完美,但是,仔细考虑以下,此方案对于微服务应用而言行不通。
首先,微服务可能是部署在云环境的,服务实例的网络位置或许是动态分配的。
另外,每一个服务一般会有多个实例来做负载均衡,由于宕机或升级,服务实例网络地址会经常动态改变。
再者,每一个服务也可能应对临时访问压力增加新的服务节点。正如下图所示:
基于以上的问题,服务之间如何相互感知?服务如何管理?这就是服务发现的问题了。如下图:
上图中服务实例本身并不记录服务生产方的网络地址,所有服务实例内部都会包含服务发现客户端。
(1)在每个服务启动时会向服务发现中心上报自己的网络位置。这样,在服务发现中心内部会形成一个服务注册表,服务注册表是服务发现的核心部分,是包含所有服务实例的网络地址的数据库。
(2)服务发现客户端会定期从服务发现中心同步服务注册表 ,并缓存在客户端。
(3)当需要对某服务进行请求时,服务实例通过该注册表,定位目标服务网络地址。若目标服务存在多个网络地址,则使用负载均衡算法从多个服务实例中选择出一个,然后发出请求。
总结一下,在微服务环境中,由于服务运行实例的网络地址是不断动态变化的,服务实例数量的动态变化 ,
因此无法使用固定的配置文件来记录服务提供方的网络地址,必须使用动态的服务发现机制用于实现微服务间的相互感知。
各服务实例会上报自己的网络地址,这样服务中心就形成了一个完整的服务注册表,各服务实例会通过服务发现中心来获取访问目标服务的网络地址,从而实现服务发现的机制。