本文主要内容:
- 服务注册与发现的作用
- 准备工作
- 服务注册
- 服务发现
- 客户端发现服务
- 服务注册与发现工作原理
- 附源码
服务注册与发现作用
服务注册:服务进程在注册中心注册自己的位置。它通常注册自己的主机和端口号,有时还有身份验证信息,协议,版本号,以及运行环境的详细资料。
服务发现:客户端应用进程向注册中心发起查询,来获取服务的位置。服务发现的一个重要作用就是提供一个可用的服务列表
准备工作
- 下载 Consul 镜像
docker pull consul:0.9.2
- 安装 consul-template
brew install consul-template
- 安装 nginx
brew install nginx
- 启动 nginx
brew services restart nginx
- 启动 Consul
docker run -d -p 8500:8500 -p 8300:8300 -p 8301:8301 -p 8302:8302 -p 8600:8600 consul:0.9.2 agent -dev -bind=0.0.0.0 -client=0.0.0.0
- 点击此处查看 Consul 服务
服务注册
- 在 build.gradle 中加入依赖
ext {
springCloudVersion = 'Dalston.SR4'
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-starter-parent:${springCl
oudVersion}"
}
}
dependencies {
...
compile('org.springframework.boot:spring-boot-starter-actuator')
compile('org.springframework.cloud:spring-cloud-starter-consul-discovery')
...
}
- bootstrap.yml 中加入配置
spring:
cloud:
consul:
enabled: true
hostname: localhost
port: 8500
ribbon:
enabled: true
discovery:
enabled: true
register: true
- 在项目的入口加入注解
@SpringBootApplication
@EnableDiscoveryClient //加入此注解
public class MstUserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(MstUserServiceApplication.class, args);
}
}
到此,我们的服务已经注册成功,点击此处查看服务注册,结果如下图:
红色选中区域就是我们注册的服务 mst-user-service
,此时我们注册的服务是失败的,由于健康检查没过
- 健康检查
在WebSecurityConfig.java
中加入:
http.authorizeRequests()
.antMatchers(HttpMethod.GET, "/health").permitAll()
.anyRequest().authenticated();
重启 mst-user-service
服务,再次点击此处查看服务注册,结果如下图:
至此,我们 mst-user-service
服务已经注册成功。接下来,服务发现。
服务发现
按照上述服务注册的方式,将该服务先用 consul 注册
- 在发现方 build.gradle 中加入依赖
dependencies {
...
compile('org.springframework.cloud:spring-cloud-starter-feign')
...
}
- 在发现方入口加入注解
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients // 加入此注解
public class MstOrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(MstOrderServiceApplication.class, args);
}
}
- 创建 UserClient 接口,并在发现方写一个跨服务调用的接口
@FeignClient("mst-user-service") // 此处名字应与我们在 Consul 中注册的名字一致
public interface UserClient {
@GetMapping("/api/users/names")
List<String> getUserNames();
}
- 重启发现方服务,发送请求。
客户端发现服务——Consul Template + Nginx
设置 Consul Template
mkdir consule-template && cd consule-template
生成 Consul Template Config 文件
cat >> ./config.json << EOF
{
"consul": {
"address": "http://127.0.0.1:8500"
},
"template": {
"source": "./config.ctmpl",
"destination": "/usr/local/etc/nginx/servers/ms-nginx.conf",
"command": "brew services reload nginx"
}
}
EOF
- 生成 Nginx 模板
{{range services}} {{$name := .Name}} {{$service := service .Name}}
upstream {{$name}} {
#zone upstream-{{$name}} 64k;
{{range $service}}server {{.Address}}:{{.Port}} max_fails=3 fail_timeout=60 weight=1;
{{else}}server 127.0.0.1:65535; # force a 502{{end}}
} {{end}}
server {
listen 8999 default_server;
{{range services}} {{$name := .Name}}
location ~* {{ $name }} {
proxy_pass http://{{$name}};
}
{{end}}
location / {
root /usr/share/nginx/html/;
index index.html;
} }
EOF
启动 Consul Template
consul-template -config ./config.json
查看生成好的 nginx 模板
vim /usr/local/etc/nginx/servers/ms-nginx.conf
Consul 中添加 Key/Value
matchers/mst-users-service -> /api/(users)
matchers/mst-order-service -> /api/(goods)
点此查看 Consule Key/Value修改 config.ctmpl
使用下面的代码,替换 config.ctmpl 中同位置的代码
...
{{range services}} {{$name := .Name}}
{{if (printf "matchers/%s" $name | keyExists)}}
location ~* {{ printf "matchers/%s" $name | key }} {
proxy_pass http://{{$name}};
}
{{end}}
{{end}}
...
重启 Consul Template
查看生成好的 nginx 模板
此时,我们可以发请求到 Nginx 对应的 Port 来完成我们的跨服务调用。
服务注册与发现工作原理
- 当 Service A 启动的时候,会向 Consul 发送一个 POST 请求,告诉 Consul 自己的 IP 和 Port。
- Consul 接收到 Service A 的注册后,每隔 10s(默认)会向 Service A 发送一个健康检查的请求,检验 Service A 是否健康
- 当 Service B 发送 GET 方式请求 /api/getA 到 Service A 时,会先从 Consul 中拿到一个存储服务 IP 和 Port 的临时表,从表中拿到 Service A 的 IP 和 Port 后再发送 GET 方式请求 /api/getA
- 该临时表每隔 10s 会更新,只含有通过健康检查的 Service