浅谈Spring Cloud Netflix-Ribbon灰度方案之Zuul网关灰度
eureka默认集成了ribbon,所以ribbon的灰度实现原理就是借助服务注册到eureka中的eureka.instance.metadata-map的内容来进行匹配的。
zuul网关的灰度实现也是借助了一个ribbon的插件来实现,相对比较简单。
项目环境说明:有两个eureka的服务端(eureka-server),有两个相同的后端服务(service-sms),有一个网关服务(cloud-zuul)。
1、网关的依赖:
<?xml version="1.0" encoding="utf-8"?> <project xmlns="http://maven.apache.org/pom/4.0.0" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://maven.apache.org/pom/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelversion>4.0.0</modelversion> <parent> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-parent</artifactid> <version>2.3.9.release</version> <relativepath/> <!-- lookup parent from repository --> </parent> <groupid>com.kevin</groupid> <artifactid>cloud-zuul</artifactid> <version>0.0.1-snapshot</version> <name>cloud-zuul</name> <description>demo project for spring boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>hoxton.sr10</spring-cloud.version> </properties> <dependencies> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency> <dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-starter-netflix-eureka-client</artifactid> </dependency> <dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-starter-netflix-zuul</artifactid> <version>2.2.7.release</version> </dependency> <dependency> <groupid>io.jmnarloch</groupid> <artifactid>ribbon-discovery-filter-spring-cloud-starter</artifactid> <version>2.1.0</version> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-data-redis</artifactid> <version>2.2.7.release</version> </dependency> <dependency> <groupid>org.projectlombok</groupid> <artifactid>lombok</artifactid> <optional>true</optional> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-test</artifactid> <scope>test</scope> <exclusions> <exclusion> <groupid>org.junit.vintage</groupid> <artifactid>junit-vintage-engine</artifactid> </exclusion> </exclusions> </dependency> <dependency> <groupid>org.mybatis.spring.boot</groupid> <artifactid>mybatis-spring-boot-starter</artifactid> <version>2.1.2</version> </dependency> <dependency> <groupid>com.alibaba</groupid> <artifactid>druid</artifactid> <version>1.1.21</version> </dependency> <dependency> <groupid>mysql</groupid> <artifactid>mysql-connector-java</artifactid> <version>5.1.48</version> </dependency> </dependencies> <dependencymanagement> <dependencies> <dependency> <groupid>org.springframework.cloud</groupid> <artifactid>spring-cloud-dependencies</artifactid> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencymanagement> <build> <plugins> <plugin> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-maven-plugin</artifactid> <configuration> <excludes> <exclude> <groupid>org.projectlombok</groupid> <artifactid>lombok</artifactid> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
这里我们用到的就是io.jmnarloch.ribbon-discovery-filter-spring-cloud-starter 这个插件包。需要注意的是,这个包引入之后,eureka-client自身带的ribbon很多功能就被覆盖了,而且不能再自定义irule规则。因为这个包里面会生成一个metadataawarerule的irule,因为spring默认是单例,所以如果再自定义irule会出现冲突运行时报错。
2、配置application.yaml
server: port: 9100 spring: application: name: cloud-zuul datasource: type: com.alibaba.druid.pool.druiddatasource driver-class-name: com.mysql.jdbc.driver url: jdbc:mysql://localhost:3306/test?characterencoding=utf-8&servertimezone=asia/shanghai username: root password: root dbcp2: initial-size: 5 min-idle: 5 max-total: 10 max-wait-millis: 1000 validation-query: select 1 test-while-idle: true test-on-borrow: false test-on-return: false eureka: client: service-url: defaultzone: http://eureka-7900:7900/eureka/ mybatis: mapper-locations: classpath:mapper/*.xml
说明: 我的eureka服务端是部署在域名eureka-7900端口7900。
3、springboot启动类中添加@enablezuulproxy
@springbootapplication @enablezuulproxy public class cloudzuulapplication { public static void main(string[] args) { springapplication.run(cloudzuulapplication.class, args); } }
4、添加灰度过滤器
import com.kevin.dao.commongrayruledao; import com.kevin.entity.commongrayrule; import com.netflix.zuul.zuulfilter; import com.netflix.zuul.context.requestcontext; import com.netflix.zuul.exception.zuulexception; import io.jmnarloch.spring.cloud.ribbon.support.ribbonfiltercontextholder; import org.springframework.beans.factory.annotation.autowired; import org.springframework.cloud.netflix.zuul.filters.support.filterconstants; import org.springframework.stereotype.component; import javax.servlet.http.httpservletrequest; //加入spring的管理 @component public class grayfilter extends zuulfilter { @override public string filtertype() { return filterconstants.route_type; } @override public int filterorder() { return 0; } @override public boolean shouldfilter() { //必须返回true,否则过滤器不起作用 return true; } @suppresswarnings("springjavainjectionpointsautowiringinspection") @autowired private commongrayruledao commongrayruledao; @override public object run() throws zuulexception { //模拟从数据库中获取灰度规则配置,此处根据id获取的,实际项目中可以从数据库查处所有放到缓存 commongrayrule commongrayrule = commongrayruledao.selectbyprimarykey(1); requestcontext currentcontext = requestcontext.getcurrentcontext(); httpservletrequest request = currentcontext.getrequest(); int userid = integer.parseint(request.getheader("userid")); //从head中拿出userid,根据数据库中规则进行匹配,如果灰度规则中有这个用户就走灰度v1版本,此处模拟的是根据 //某一个具体的id获取的值,实际根据情况来定,实际情况中灰度规则也不一定是根据用户来 if(commongrayrule.getid() == userid){ //核心代码就这么一行,实现了灰度,这里的version与要访问的服务的metadata-map中的key和value进行对应 ribbonfiltercontextholder.getcurrentcontext().add("version","v1"); } return null; } }
至此通过网关访问service-sms服务就可以了。如果head中添加version就可以指定到具体服务上。
事前说明:两个service-sms服务的application.yaml文件如下:
spring: profiles: sms1 application: name: service-sms server: port: 8001 eureka: client: service-url: defaultzone: http://eureka-7900:7900/eureka/ instance: metadata-map: version: v1 --- spring: profiles: sms2 application: name: service-sms server: port: 8002 eureka: client: service-url: defaultzone: http://eureka-7900:7900/eureka/ instance: metadata-map: version: v2
因为本机测试,所以使用的是profiles进行区分。
可以看到一个metadata-map设置的是version: v1 ,另一个是version: v2。
当我们数据库添加一条用户id是1的数据时,我们通过网关访问服务的时候,head里面添加userid为1的内容,那么这个用户为1的请求就会一直走sms1这个服务,否则会在sms1和sms2中轮询切换。
以上就是浅谈spring cloud netflix-ribbon灰度方案之zuul网关灰度的详细内容,更多关于ribbon灰度方案之zuul网关灰度的资料请关注其它相关文章!