openfeign 转发header 实现全链路灰度发布

openfeign 转发header 实现全链路灰度发布

  • 引言
  • 实现
    • 在服务中修改Predicate
    • 加一个Interceptor
    • 配置ribbon规则,使用我们自己的规则

引言

网关层看这里
之前写了网关层实现灰度发布,但是这个只能被路由一次
像是这样:
客户端->网关->根据版本号路由到应用
之后应用再调用其他服务,调用链的路由就没办法了,它只会被路由一次。

实现

在服务中加入在网关层写好的rulepredicatepredicate需要改一下,因为web中没有zuul的RequestContext,改为使用ServletRequestAttributes
具体代码去看网关层文章,我这里不重写了。

在服务中修改Predicate


import com.google.common.base.Optional;
import com.netflix.loadbalancer.AbstractServerPredicate;
import com.netflix.loadbalancer.PredicateKey;
import com.netflix.loadbalancer.Server;
import com.netflix.niws.loadbalancer.DiscoveryEnabledServer;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.List;

public class MyPredicate extends AbstractServerPredicate {

    @Override
    public boolean apply(@NullableDecl PredicateKey predicateKey) {
        Server server = predicateKey.getServer();
        //Object loadBalancerKey = predicateKey.getLoadBalancerKey();

        //仅仅允许元数据中有"version"的服务
        if (server instanceof DiscoveryEnabledServer){
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

            //从http头获取version
            final String contextVersion = attributes.getRequest().getHeader("version");

            final String metaVersion = ((DiscoveryEnabledServer) server).getInstanceInfo().getMetadata().get("version");
            return StringUtils.isEmpty(contextVersion) || StringUtils.isEmpty(metaVersion) || metaVersion.equals(contextVersion);
        }

        return true;
    }

    @Override
    public Optional<Server> chooseRoundRobinAfterFiltering(List<Server> servers, Object loadBalancerKey) {
        return super.chooseRoundRobinAfterFiltering(servers, loadBalancerKey);
    }
}

加一个Interceptor

利用FeignReqeustTemplate实现全链路Header转发,因为无论是gateway还是zuul,它们虽然自带了header转发,但是Feign默认是没有header转发的,所以我们在服务中需要统一加入一个Interceptor来转发header.

import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;

@Component
public class AddHeaderInterceptor implements RequestInterceptor {
    @Autowired
    HttpServletRequest request;

    @Override
    public void apply(RequestTemplate template) {
        Enumeration<String> headerNames = request.getHeaderNames();
        String hdrName = null;

        while(headerNames.hasMoreElements()){
            hdrName = headerNames.nextElement();
            template.header(hdrName,request.getHeader(hdrName));
        }
    }
}

配置ribbon规则,使用我们自己的规则

  1. 指定服务才具有灰度发布全链路转发
@RibbonClient(name="服务名",configuration = MyPredicateRule.class)

如果想使全局都直接支持,可以不用上面的方法,直接全局即可。

  1. 全局都支持
 import com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

@Configuration
@AutoConfigureBefore(RibbonClientConfiguration.class)
@ConditionalOnProperty(value = "ribbon.filter.metadata.enabled", matchIfMissing = true)
public class RuleConfiguration {
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnClass(DiscoveryEnabledNIWSServerList.class)
    @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
    public MyPredicateRule metadataAwareRule() {
        return new MyPredicateRule();
    }

}

热门文章

暂无图片
编程学习 ·

MySQL 简洁速查手册

MySQL 速查手册 文章目录MySQL 速查手册0. 前言1. 开启/关闭数据库2. 数据库操作3. 数据表操作4. 字段操作5. 数据操作6. 运算符7. 高级查询(group by、having、order by、limit)8. 高级插入9. 高级删除10. 高级更新11. 联合查询12. 连接查询12.1 左外连接12.2 右外连接13. 子查…
暂无图片
编程学习 ·

element dom 事件注册 on off once

/* istanbul ignore next */ // 匿名函数自执行,兼容IE-attachEvent,chrome-addEventListener export const on = (function() {if (!isServer && document.addEventListener) {return function(element, event, handler) {if (element && event && h…
暂无图片
编程学习 ·

vue中的keep-alive使用总结

在平常开发中,有些组件只需要加载一次,后面的数据将不存在变化,亦或者是组件需要缓存状态,滚动条位置等,这个时候,keep-alive的用处就立刻凸显出来了。1.App.vue中使用keep-alive,include表示需要缓存的页面,exclude表示不需要缓存的页面,你可以只设置其中一个即可,但…
暂无图片
编程学习 ·

面试官:小伙子,你给我说一下线程池的线程复用原理吧

前言 前两天和粉丝聊天的时候,粉丝问了我一个挺有意思的问题,说他之前在面试的时候被问到线程池的线程复用原理,当时我跟他简单的说了一下,没想到过了几天又来问我这个问题了,说他最近又被问到了这个问题…想了想,干脆写篇文章把这个东西讲清楚吧,满满的干货都放在下面了…
暂无图片
编程学习 ·

小程序学习之路五:scroll-view实现多列布局

上面讲解了一些部分简单功能,接下来讲讲scroll-view的进阶,实现多列布局,先上效果:首先来看看布局文件<scroll-view class="scroll"><view class="item" wx:for={{datas}} wx:key=index wx:for-item="item" data-item="{{item…
暂无图片
编程学习 ·

考研初试备考,感谢曾经努力的自己

人生的第一篇博客,说晚不晚,以后我会好好学习IT技术,并腾出时间写写东西,想写这篇文章有很长时间了,当初写好了也没有发布,现在作为一个过来人润色一番,着手发布。找不到合适的平台、合适的时间、合适的场地、合适的心情以及合适的内容,现在才开始在CSDN动手写东西,然…
暂无图片
编程学习 ·

Chen08

[Calendar] 实例化Calendar Calendar c = Calendar.getInstance(); 月份是从0开始计数的(0-11) c.set();//日历设置到某一天 c.get();//日历翻到的那一天BigInteger 表示整数、 BigDecimal表示浮点数 对于输出浮点数保留几位小数的问题,可以使用DecimalFormat类, DecimalForm…
暂无图片
编程学习 ·

海思NNIE开发系列文章--转载

https://blog.csdn.net/zh8706/article/details/94554337海思NNIE开发系列文章:海思NNIE开发(一):海思Hi3559AV100/Hi3519AV100 NNIE深度学习模块开发与调试记录海思NNIE开发(二):FasterRCNN在海思NNIE平台上的执行流程(一)海思NNIE开发(三):FasterRCNN在海思NNIE平…
暂无图片
编程学习 ·

个人认为制作系统盘(U盘启动盘)最干净的方式?

前言 只要你一搜索百度如何制作系统盘? 那必定是诸如大白菜,什么桃啦,什么大师啦之流!如下:广告在最前面也是某度的一贯作风! 我也曾试过这个推荐,但是往往需要在电脑上按照他们的软件等等,这个软件等你制作完系统盘之后,往往就是废物一个,占用电脑空间! 还有可恨之…
暂无图片
编程学习 ·

limit和rownum的区别,做兼容

两个数据库分页还是分批查sql肯定是不兼容的 然后limit的第二个参数是偏移量,不是between xx and yy 其次是limit后面不支持运算符 有种方式是 set @sql = concat(‘select* from user where id= 123456 andcode= 111 and create_date >= 20190101 and create_date <= 2…
暂无图片
编程学习 ·

【小甲鱼python】Tkinter学习笔记1-4

1.1 import tkinter as tkapp=tk.Tk() #生成了顶层窗口的实例 root窗口,T大写k小写 app.title("Fishc Demo")#设置标题栏#Label是一个组件,组件实例化后成为一个对象。 #该组件放在app这个窗口上 #该组件是最常见的组件之一,主要用于显示文本和图标 theLabel=tk.L…
暂无图片
编程学习 ·

CV之Haar特征描述算子-人脸检测

3.1简介 Haar-like特征最早是由Papageorgiou等应用于人脸表示,在2001年,Viola和Jones两位大牛发表了经典的《Rapid Object Detection using a Boosted Cascade of Simple Features》和《Robust Real-Time Face Detection》,在AdaBoost算法的基础上,使用Haar-like小波特征和…
暂无图片
编程学习 ·

操作系统——进程调度算法 python实现

文章目录一、实验内容(1)优先权法、轮转法(2) 算法描述二、流程图(1)优先权法——动态优先级(2)轮转法(RR法)三、实验分析四、完整代码及输出(1)代码(2)输出 一、实验内容 (1)优先权法、轮转法 简化假设 1) 进程为计算型的(无I/O) 2) 进程状态:ready、runni…
暂无图片
编程学习 ·

正则表达式知识点

目录笔记复习用的网站 笔记 * 任意次 ? 0或1次 + 1或更多 {n} 重复n次 {n,} n或更多 {n,m} n到m次 | 分支条件 ^$ 字符串开头结尾 (\n字符串\n) ^.*$ . 任意一个数字字母下划线 \s 空格回车 \d 数字 \b 该位置是空格 但不会显示空格,除非\b.\b \d+ 一串数字 …
暂无图片
编程学习 ·

jxl.jar下载

jxl.jar给java提供了简单操作Excel的方法:链接:https://pan.baidu.com/s/17HXj_w8E2nM8iIssf2Bmhg 提取码:l6t5
暂无图片
编程学习 ·

pytorch神经网络学习笔记(3)

分类import torch from torch.autograd import Variable import torch.nn.functional as F import matplotlib.pyplot as plt#生成数据 n_data=torch.ones(100,2) #类别1的数据 x0 = torch.normal(2*n_data,1) #类别1的标签 y0 = torch.zeros(100) #类别2的数据 x1 = torch.nor…
暂无图片
编程学习 ·

电子工程师不可常犯的错误小结

电子工程师指从事各类电子设备和信息系统研究、教学、产品设计、科技开发、生产和管理等工作的高级工程技术人才。一般分为硬件工程师和软件工程师。 硬件工程师:主要负责电路分析、设计;并以电脑软件为工具进行PCB设计,待工厂PCB制作完毕并且焊接好电子元件之后进行测试、调…