服务发现和注册
我们有了两个服务。服务A的IP地址是192.168.0.1,端口9001,服务B的IP地址192.168.0.2,端口9002。我们的客户端需要调用服务A和服务B,我们只需要在配置文件中写上服务A和服务B的IP地址即可。
此时,服务A的服务器负载有点高,我们需要临时增加服务A的实例,IP192.168.0.3,端口9001。但是我们的客户端要怎么才能调用新的实例?
常规来说,我们可以有以下几种方法:
网络代理方式
如果是http方式通信的服务,可以增加一个nginx做反向代理,转发到两个服务A的实例上。
如果是RPC服务则可以增加一个LVS或HAProxy或者ESB之类的网络代理,客户端配置网络代理地址。
服务B我们再来一套一样的配置,这时候又来了服务C、服务D、服务E...,好吧我们好还要再多维护同样多的网络代理。此外,所有的服务调用服务调用都必须经过网络代理,我们还必须保证代理的高可用。最后,陷入运维灾难。DNS方式
给服务A配置一个域名,然后通过配置两个A记录分别指向两个服务A的实例,客户端只要配置服务A的域名即可。
这种方式也存在问题,首先DNS没有办法管理端口,我们的端口还是只能写在每个客户端的配置文件中。此外DNS轮询负载均衡能力太弱,可能会导致客户端负载的不均衡。
现在有了服务发现和注册机制,我们可以更合理的解决这个问题。
服务发现和注册,参考字面意思很容易理解,其核心部分可以理解为一个服务注册表。服务启动时,将自己的信息注册到注册表中。注册表需要每一定时间访问下已经注册的服务,将没有响应的服务从注册表中删除。最终让客户端拿到正常运行的服务地址。
此时,我们的服务注册表必须具备分布式、高可用、强一致性等特点。
目前,业界开源的服务发现和注册产品有很多,比较流行的主要有:ZooKeeper,Etcd,Consul,Eureka等。
下面介绍下今天的主角,Consul。
Consul
Consul是一个服务发现和注册的工具,其具有分布式、高扩展性能特点。
Consul主要包含如下功能:
- 服务发现: 支持 http 和 dns 两种协议的服务注册和发现方式。
- 监控检查: 支持多种方式的健康检查。
- Key/Value存储: 支持通过HTTP API实现分布式KV数据存储。
- 多数据中心支持:支持任意数量数据中心。
上图是官网提供的一个事例系统图,图中的Server是consul服务端高可用集群,Client是consul客户端。consul客户端不保存数据,客户端将接收到的请求转发给响应的Server端。Server之间通过局域网或广域网通信实现数据一致性。每个Server或Client都是一个consul agent。Consul集群间使用了GOSSIP协议通信和raft一致性算法。
使用Consul也非常简单,基本可以做到开箱即用。
下载应用后可以通过简单的脚本启动服务端和客户端:
$ consul
usage: consul [--version] [--help] <command> [<args>]Available commands are:
agent Runs a Consul agent
configtest Validate config file
event Fire a new event
exec Executes a command on Consul nodes
force-leave Forces a member of the cluster to enter the "left" state
info Provides debugging information for operators
join Tell Consul agent to join cluster
keygen Generates a new encryption key
keyring Manages gossip layer encryption keys
kv Interact with the key-value store
leave Gracefully leaves the Consul cluster and shuts down
lock Execute a command holding a lock
maint Controls node or service maintenance mode
members Lists the members of a Consul cluster
monitor Stream logs from a Consul agent
operator Provides cluster-level tools for Consul operators
reload Triggers the agent to reload configuration files
rtt Estimates network round trip time between nodes
version Prints the Consul version
watch Watch for changes in Consul
运行consul agent
加上相关的参数,就可以启动一个consul server 或者 client。
接着,我们可以通过http api注册服务,向/v1/catalog/register发送PUT动作的JSON报文:
{"Datacenter": "dc1", "Node": "foobar", "Address": "192.168.10.10", "Service": { //注册的服务信息"ID": "redis1","Service": "redis","Tags": ["primary","v1"],"Address": "127.0.0.1","Port": 8000},"Check": { //注册健康检查"Node": "foobar","CheckID": "service:redis1","Name": "Redis health check","Notes": "Script based health check","Status": "passing","ServiceID": "redis1"}
}
注册后,我们可以在consul自带的WEB UI中看到刚刚注册的服务:
与Spring Cloud集成
如果你的服务正好使用spring boot构建,不妨试试Spring Cloud Consul。
Spring Cloud Consul通过几个简单的注解,就可以集成诸多consul功能,让你更方便的治理你的服务。
@SpringBootApplication
@EnableDiscoveryClient //只要添加这个注解即可向配置号的consul注册服务
@RestController
public class Application { @RequestMapping("/")public String home() {return "Hello world";}public static void main(String[] args) {new SpringApplicationBuilder(Application.class).web(true).run(args);}
}
同时我们可以配合spring boot actuator来注册监控检查:
spring:cloud:consul:discovery:healthCheckPath: ${management.contextPath}/healthhealthCheckInterval: 15s
Spring Cloud支持 Feign 或者 Spring RestTemplate 通过服务发现来调用服务,也可以使用org.springframework.cloud.client.discovery.DiscoveryClient:
@Autowired //注入一个DiscoveryClient
private DiscoveryClient discoveryClient;public String serviceUrl() {List<ServiceInstance> list = discoveryClient.getInstances("STORES");if (list != null && list.size() > 0 ) {return list.get(0).getUri();}return null;
}
consul除了可以用作服务治理的工具,还可以利用其KV存储能力,实现分布式服务配置或分布式锁等功能。各位感兴趣的童鞋可以去consul官网,学习更多的内容。
最后,都看到这了,就顺手点个赞吧~~~
参考资料:
https://www.nginx.com/blog/service-discovery-in-a-microservices-architecture/
https://highops.com/insights/service-discovery-6-questions-to-4-experts/
https://www.consul.io/
http://cloud.spring.io/spring-cloud-consul/