以前使用APISIX实现过灰度发布《jenkins与apisix整合,实现自动化部署与负载均衡、灰度发布(蓝绿发布)》
同样可以使用Spring Gateway实现类似灰度功能。本文使用前文的示例代码《Spring Cloud 2022.x版本使用gateway和nacos实现动态路由和负载均衡》来演示效果
app1和app2两个工程都增加一个version接口
示例代码如下:
// app1工程,版本1.0
private static int count = 0;
@GetMapping("/version")
public Map<String, Object> version(){
Map<String, Object> data = new HashMap<>();
data.put("visit_count", ++count);
data.put("version", "1.0");
data.put("service", "app1");
return data;
}
// app2工程,版本1.0
private static int count = 0;
@GetMapping("/version")
public Map<String, Object> version(){
Map<String, Object> data = new HashMap<>();
data.put("visit_count", ++count);
data.put("version", "1.0");
data.put("service", "app2");
return data;
}
正常负载均衡时nacos里gatewayapp.yml路由配置
- id: app
uri: lb://app-service
predicates:
- Path=/app/**
filters:
- StripPrefix=1
app2发布新版本,此时接口代码的版本号修改为1.1。
对访问的用户,随机分配流量,新版本流量占20%,旧版本流量占80%,使用Gateway的Weight路由判断器来实现。Nacos的路由配置修改为:
- id: app_gray
uri: http://localhost:9092
predicates:
- Path=/app/**
- Weight=group1, 20
filters:
- StripPrefix=1
- id: app
uri: http://localhost:9091
predicates:
- Path=/app/**
- Weight=group1, 80
filters:
- StripPrefix=1
按用户id、用户ip等方式实现的灰度,一般用户属性信息可以放在Header、Cookie、请求参数。可以通过路由判断器Cookie、Header、Query、RemoteAddr、XForwardedRemoteAddr判断属性值是否进入灰度环境
用户id<100访问,进入灰度新版本,其他用户进入旧版本,Nacos的路由配置修改为:
spring:
cloud:
gateway:
routes:
- id: app_gray
uri: http://localhost:9092
predicates:
- Header=userid, ^([1-9][0-9]?)$
- Path=/app/**
filters:
- StripPrefix=1
- id: app
uri: http://localhost:9091
predicates:
- Path=/app/**
filters:
- StripPrefix=1
用户id<100访问,进入灰度新版本,其他用户进入旧版本,Nacos的路由配置修改为:
spring:
cloud:
gateway:
routes:
- id: app_gray
uri: http://localhost:9092
predicates:
- Query=userid, ^([1-9][0-9]?)$
- Path=/app/**
filters:
- StripPrefix=1
- id: app
uri: http://localhost:9091
predicates:
- Path=/app/**
filters:
- StripPrefix=1
只允许ip=192.168.76.128的访问,进入灰度新版本,其他用户进入旧版本,Nacos的路由配置修改为:
spring:
cloud:
gateway:
routes:
- id: app_gray
uri: http://localhost:9092
predicates:
- RemoteAddr=192.168.76.128/24
- Path=/app/**
filters:
- StripPrefix=1
- id: app
uri: http://localhost:9091
predicates:
- Path=/app/**
filters:
- StripPrefix=1
Spring Cloud Gateway包括许多内置的路由判断器,官方介绍https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#gateway-request-predicates-factories
这些路由判断器匹配HTTP请求的不同属性。可以将多个路由判断器与逻辑和语句组合在一起。
名称 | 说明 |
---|---|
After | After路由接受一个日期参数,匹配在指定日期时间之后发生的请求。 |
Before | Before路由接受一个日期参数,匹配在指定日期时间之前发生的请求。 |
Between | Between路由接受两个参数datetime1和datetime2,匹配在datetime1之后和datetime2之前发生的请求。 |
Cookie | Cookie路由接受两个参数,Cookie名称和regexp(一个Java正则表达式),匹配具有给定名称且其值与正则表达式匹配的cookie。 |
Header | Header路由接受两个参数:Header名称和regexp(一个Java正则表达式),匹配与具有给定名称且其值与正则表达式匹配的hearder。 |
Host | Host路由接受一个参数:域名列表,匹配列表中的域名地址。 |
Method | Method路由接受一个Http方法(GET、POST…)参数,该参数是一个或多个HTTP方法。 |
Path | Path路由判断器接受两个参数:Spring PathMatcher模式列表和一个名为matchTrailingSlash的可选标志(默认为true)。 |
Query | Query路由器接受两个参数:一个必需的参数和一个可选的regexp(它是一个Java正则表达式)。 |
RemoteAddr | RemoteAddr路由器接受一个来源列表(至少1个),这些来源地址是IPv4或IPv6字符串,例如192.168.0.1/16(其中192.168.0.1是IP地址,16是子网掩码)。 |
Weight | Weight路由器接受两个参数:group和Weight (int型),权重按组计算。 |
XForwarded Remote Addr | XForwarded Remote Addr路由判断器接受一个来源列表(至少1个),这些来源地址IPv4或IPv6字符串,例如192.168.0.1/16(其中192.168.0.1是IP地址,16是子网掩码)。 此路由器基于HTTP头X-Forwarded-For过滤请求。 可以与反向代理一起使用,例如负载平衡器或web应用程序防火墙,其中只有当请求来自这些反向代理使用的受信任IP地址列表时才允许请求。 |
After路由判断器接受一个日期参数,匹配在指定日期时间之后发生的请求。
spring:
cloud:
gateway:
routes:
- id: after_route
uri: https://example.org
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
This route matches any request made after Jan 20, 2017 17:42 Mountain Time (Denver).
Before路由判断器接受一个日期参数,匹配在指定日期时间之前发生的请求。
spring:
cloud:
gateway:
routes:
- id: before_route
uri: https://example.org
predicates:
- Before=2017-01-20T17:42:47.789-07:00[America/Denver]
Between路由判断器接受两个参数datetime1和datetime2,匹配在datetime1之后和datetime2之前发生的请求。
spring:
cloud:
gateway:
routes:
- id: between_route
uri: https://example.org
predicates:
- Between=2017-01-20T17:42:47.789-07:00[America/Denver], 2017-01-21T17:42:47.789-07:00[America/Denver]
Cookie路由判断器接受两个参数,Cookie名称和regexp(一个Java正则表达式),匹配具有给定名称且其值与正则表达式匹配的cookie。
spring:
cloud:
gateway:
routes:
- id: cookie_route
uri: https://example.org
predicates:
- Cookie=chocolate, ch.p
Header路由判断器接受两个参数:Header名称和regexp(一个Java正则表达式),匹配与具有给定名称且其值与正则表达式匹配的hearder。
spring:
cloud:
gateway:
routes:
- id: header_route
uri: https://example.org
predicates:
- Header=X-Request-Id, \d+
Host路由判断器接受一个参数:域名列表,匹配列表中的域名地址。
spring:
cloud:
gateway:
routes:
- id: host_route
uri: https://example.org
predicates:
- Host=**.somehost.org,**.anotherhost.org
Method路由判断器接受一个Http方法(GET、POST…)参数,该参数是一个或多个HTTP方法。
spring:
cloud:
gateway:
routes:
- id: method_route
uri: https://example.org
predicates:
- Method=GET,POST
Path路由判断器接受两个参数:Spring PathMatcher模式列表和一个名为matchTrailingSlash的可选标志(默认为true)。
spring:
cloud:
gateway:
routes:
- id: path_route
uri: https://example.org
predicates:
- Path=/red/{segment},/blue/{segment}
此路由将匹配路径/red/1、/red/1/、/red/blue、/blue/green。
如果matchTrailingSlash设置为false,那么请求路径/red/1/将不匹配。
Query路由判断器接受两个参数:一个必需的参数和一个可选的regexp(它是一个Java正则表达式)。
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://example.org
predicates:
- Query=green
如果请求中包含绿色查询参数,则匹配上述路由。
此路由匹配包含参数名为green的请求,比如https://www.test.com?green=1
spring:
cloud:
gateway:
routes:
- id: query_route
uri: https://example.org
predicates:
- Query=red, gree.
此路由匹配参数名为red,值为gree.(正则匹配,比如green、greet都会匹配),
RemoteAddr路由器接受一个来源列表(至少1个),这些来源地址是IPv4或IPv6字符串,例如192.168.0.1/16(其中192.168.0.1是IP地址,16是子网掩码)。
spring:
cloud:
gateway:
routes:
- id: remoteaddr_route
uri: https://example.org
predicates:
- RemoteAddr=192.168.1.1/24
如果请求的客户端地址为192.168.1.10,则符合路由匹配。
注意:如果Spring Cloud Gateway位于代理层后面,可能无法获取真实的客户端IP地址。可以通过设置一个自定义的RemoteAddressResolver来自定义远程地址解析的方式。Spring Cloud Gateway提供了一个非默认的远程地址解析器,它基于X-Forwarded-For报头,即XForwardedRemoteAddressResolver。
RemoteAddressResolver resolver = XForwardedRemoteAddressResolver
.maxTrustedIndex(1);
...
.route("direct-route",
r -> r.remoteAddr("10.1.1.1", "10.10.1.1/24")
.uri("https://downstream1")
.route("proxied-route",
r -> r.remoteAddr(resolver, "10.10.1.1", "10.10.1.1/24")
.uri("https://downstream2")
)
Weight路由器接受两个参数:group和Weight (int型),权重按组计算。
spring:
cloud:
gateway:
routes:
- id: weight_high
uri: https://weighthigh.org
predicates:
- Weight=group1, 8
- id: weight_low
uri: https://weightlow.org
predicates:
- Weight=group1, 2
这条路由将把80%的流量转发给weighthigh.org, 20%的流量转发给weighlow.org
XForwarded Remote Addr路由判断器接受一个来源列表(至少1个),这些来源地址IPv4或IPv6字符串,例如192.168.0.1/16(其中192.168.0.1是IP地址,16是子网掩码)。
此路由器基于HTTP头X-Forwarded-For过滤请求。
可以与反向代理一起使用,例如负载平衡器或web应用程序防火墙,其中只有当请求来自这些反向代理使用的受信任IP地址列表时才允许请求。
spring:
cloud:
gateway:
routes:
- id: xforwarded_remoteaddr_route
uri: https://example.org
predicates:
- XForwardedRemoteAddr=192.168.1.1/24
如果X-Forwarded-For报头包含192.168.1.10,则匹配些路由。