之前网络上的教程中,spring cloud微服务大部分以eureka作为服务与注册中心,zull作为api网关,但是spring官方已经不推荐试用这两者,逐步使用Consul及Spring Cloud Gateway进行取代,本文进行尝试,其中spring cloud版本为Finchley.SR3,spring boot版本为2.0.4.
一、consul
consul最新版本为1.6.1,下载地址如下:,我使用windows版本方便调试,命令都一样。
下载后解压,工作目录下cmd运行: .\consul.exe agent -dev -ui -node=my-test-consul (-dev表示调试模式,-node是节点名称),浏览器访问http://127.0.0.1:8500, 若出现ui界面代表安装成功。
二、微服务工程ScHelloWorldSvr
该微服务功能很简单,就是echo信息,该微服务将注册到consul。只需要使用@EnableDiscoveryClient注解,表示将注册到服务发现中心。
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
1)application.properties文件配置
这个文件配置应用名(在consul中将以这个名字注册)、启动端口、与consul连接的配置等。
spring.application.name=HelloWorldService
server.port=9999
#localhost是默认
spring.cloud.consul.host=localhost
#8500端口也是默认
spring.cloud.consul.port=8500
#健康检查路径也是默认
spring.cloud.consul.discovery.health-check-path=/actuator/health
#健康检查间隔也是默认
spring.cloud.consul.discovery.health-check-timeout=10s
2)访问
@RestController
public class CustomerSvr {
@Value("${server.port}")
private String port;
@Autowired
private HttpServletRequest request;
@RequestMapping("/echo/{message}")
public String echoMsg(@PathVariable String message){
String param = request.getHeader("x-foo");
return String.format("welcome, my port is %s, your enter message is %s, and the added header is [x-foo=%s]", port, message, param);
}
}
很简单,就是访问/echo/**时,控制器回送端口、请求参数、请求header等信息。至于要打印出header信息,是因为后面api gateway会插入新的header。
我们可以启动两个ScHelloWorldSvr工程,一个为9999端口,一个为8888端口,由于spring.application.name=HelloWorldService都一样,所以他们都将注册到consul的同一个服务HelloWorldService,后面api gateway就是根据服务名下有的服务进行负载均衡调用的。idea intelj启动两个同名工程自己搜索一下百度哈~
访问consul的ui,这就是注册上去的服务了~~
三、spring cloud gateway
下面介绍api网关。api网关提供一个统一的调用入口,起到路由、鉴权、预处理等功能,说大白话,就是gateway是个看门狗,它有去各个注册的微服务的路径,知道转发规则,同时,它又能做一些预处理,如权限鉴别,改变请求参数,改变响应参数等等。学习gateway主要是学习Route Predicate(路由转发规则)和GatewayFilter(按照filter进行处理,有pre和post两种),官网写的太详细了,也不难。https://cloud.spring.io/spring-cloud-gateway/single/spring-cloud-gateway.html
prefilter主要用于修改请求内容,postfilter用于修改响应内容
1、api网关注册到consul
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ApiGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApplication.class, args);
}
}
api网关注册到consul后,网关可以知道consul上面的微服务信息,很方便进行负载均衡调用。
api网关使用5000端口,应用名称为MyApiGateWay,注册到consul的配置不用写默认去找127.0.0.1:8500
server.port=5000
spring.application.name=MyApiGateWay
2、route和filter
可以使用配置,也可以使用代码实现,推荐是使用配置,可以和spring cloud config结合,我这里使用可代码实现,因为习惯了。
@Configuration
public class GatewayConfig {
@Value("${spring.application.name}")
private String appName;
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route(p -> p
.path("/echo/**")
.filters(f->f.addRequestParameter("param",appName))
.uri("lb://HelloWorldService/echo/"))
.build();
}
}
这个代码实现了下面功能:
访问api网关 /echo/的请求,请求参数添加param=appName,之后转发到 HelloWorldService/echo/?param=appName
lb://HelloWorldService/echo/ 这个是啥意思呢?lb就loadbalance的意思,带上lb网关就会去服务注册中心解析HelloWorldService对应的真实服务,之后负载均衡调用~~~~
3、额外问题:如何对api gateway的负载均衡策略Irule进行修改?
1)全局配置
可以起全局配置,但是起全局配置后单个服务的配置就无效了,呜呜呜。。。
如:全局负载均衡策略为随机
@Configuration
public class DefaultRibbonConfig {
// 全局Ribbon负载均衡算法为Random
// 但是只要起了全局设置,单个的设置就会失效
@Bean
public IRule defaultRandomRule(){
return new RandomRule();
}
}
看到网上说可以在application.properties中配置:
ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
实际测试发现是不可以的!!!
default.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule 也是不行的。。。还有这个default是我自己想的,觉得可以这样。。
对于全局配置,看官网ribbon的文档也没有发现可以通过文档配置的,所以全局只能代码配置。
2)单个服务进行配置
官网文档推荐使用配置:
HelloWorldService.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RoundRobinRule
HelloWorldService就是我的服务名拉~~你要替换为自己的
(注:其实RoundRobinRule是默认负载均衡策略)
没发现使用代码怎么配置啊。。。