灰度发布
中游服务部分:
ribbon:
自定义部分:
1,从nacos配置中获取配置
2,根据请求获取请求的实例名---对应成相应的ip(对应的配置列表中,配置的都是灰度机map)
3,把对应的ip和ribbon中服务列表匹配有放行,需要下的灰度注掉这个实例对应的ip
应用部分:
4,将自定义的rule纳入spring
5,业务的请求换成走ribbon的服务名形式,让ribbon转发即可负载----可用拦截器做(改造没有用注册中心的项目,或者没有经过zuul的项目)(zuul有一次负载,ribbon有一次负载)
这样一来只要
开启了灰度测试开关,
配置ip列表中有灰度机器就,
灰度机器注册到nacos(配置的ip在nacos可以对应到)
用的是测试账号---测试账号ip的map的key会加:,所以解析的时候要根据:能解析出需要的是测试账号
就一直走的是灰度,之前的正式的就不会走,否则就走以前正式的服务
注入自定义的规则:
@Bean
public IRule ribbonRule() {
CustomPredicateRule rule = new CustomPredicateRule(canaryServerManager);
return rule;
}
获取nacos的配置:
package com.houbank.xloan.core.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
/**
* @author wangdong
* @Description: TODO
* @date 2019/5/22 11:56
*/
@Component
@RefreshScope
public class CanaryConfig {
@Value("${canary.open}")
private Boolean open;
@Value("${canary.telesaleBackAddr}")
private String telesaleBackAddr;
@Value("${canary.telsaleSeatAddr}")
private String telesaleSeatAddr;
@Value("${canary.telesaleWeixinAddr}")
private String telesaleWeixinAddr;
@Value("${canary.telesaleKuaiyipaiAddr}")
private String telesaleKuaiyipaiAddr;
@Value("${canary.telesaleProduct}")
private String telesaleProduct;
@Value("${canary.sessionIds}")
private String sessionIds;
public void setOpen(Boolean open) {
this.open = open;
}
public boolean isOpen() {
return open;
}
public String getSessionIds() {
return sessionIds;
}
public String getServerHost(String key){
switch (key){
case "telesale-back":return telesaleBackAddr;
case "telsale-seat":return telesaleSeatAddr;
case "telesale-seat":return telesaleSeatAddr;
case "v1":return telesaleWeixinAddr;
case "kuaiyipai-api":return telesaleKuaiyipaiAddr;
case "telesale-product":return telesaleProduct;
default:return null;
}
}
}
选择服务的工具类:
CanaryServerManager
请求的服务实例名在配置的服务列表中就返回这,否则返回空
请求loadBalancerKey在ribbon的注册中就返回该服务转发------下架灰度机的时候就loadBalancerKey找到的主机地址和ribbon中注册的不一致即可
基于配置选择服务:
CustomPredicateRule
下架灰度机的时候就loadBalancerKey找到的主机地址和ribbon中注册的不一致即可
业务中:
将请求转化成zuul请求的url:
//建议将这块代码提出封装下
loadBalancerKey 请求的实例名,根据这个获取配置文件中的主机地址 case "telesale-back":return telesaleBackAddr;
private String buildBackHost(String serviceName){
checkCanaryRequest(serviceName);
ServiceInstance serviceInstance = loadBalancerClient.choose(serviceName);
String url = String.format("http://%s:%s/",serviceInstance.getHost(),serviceInstance.getPort());
return url;
}
//判断是否开启金丝雀测试,如果开启则构造loadbalanceKey 构成为 应用名:filter
private void checkCanaryRequest(String serviceName) {
if (!canaryServerManager.isOpen())
return;
ServletRequestAttributes requestAttributes= (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
if (requestAttributes==null)
return;
HttpServletRequest httpServletRequest = requestAttributes.getRequest();
String sessionId=httpServletRequest.getRequestedSessionId();
StringBuilder loadBalancerKey=new StringBuilder();
loadBalancerKey.append(serviceName).append(":");
if (StringUtils.isNotBlank(sessionId)&&canaryServerManager.isSpecialAcct(sessionId)) { //filter表示是否是测试账号访问
loadBalancerKey.append("filter");
}
canaryServerManager.setLoadBalancerKey(loadBalancerKey.toString());
}
中游服务部分:
feign 参照ribbon
自定义部分:
1,从nacos配置中获取配置
2,根据请求获取请求的实例名---对应成相应的ip
3,把对应的ip和ribbon中服务列表匹配有放行,需要下的灰度注掉这个实例对应的ip
应用部分:
4,将自定义的rule纳入spring
5,业务的请求换成走ribbon的服务名形式,让ribbon转发即可负载----这里用拦截器做
注意:自定义hystrix的并发策略,解决hystrix线程模式下RequestContextHolder丢失问题 (信号量模式不会),自定义的策略需要在init中注册-----用于降级使用
思路:将父的上下文属性传给子复制
引入hystrix为了实现熔断降级:
自定义策略就是为了实现包装callable,
包装的目的就是为了能调用前cpoy threadlocal变量,子线程被调用设置的就在子线程中
所以一个策略可以包装多个callable,在spring容器中,一次设置都有效---类似初始化思想
效果就是只要用了这个策略,里面的callable都是有自定义用自定义的,没有用默认的(总和就是自定义+默认的)
注册策略类的本质就是注册其中的callable:
HystrixConcurrencyStrategy target = new HystrixConcurrencyStrategyCustomize(canaryServerManager);
HystrixPlugins.getInstance().registerConcurrencyStrategy(target);
1,定义策略类:
RequestContextHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy
引用定义的callable类
2,定义策略类中包装的callable类
static class RequestAttributeAwareCallable<T> implements Callable<T>
基于接口?????????
@Component
@Slf4j
public class HystrixConfig {
@PostConstruct
public void init() {
HystrixPlugins.getInstance().registerConcurrencyStrategy(new RequestContextHystrixConcurrencyStrategy());
}
}
ThreadLocal:线程之间不共享
普通的RequestContextHolder就是threadlocal
在多线程的世界,多半是父子线程,并行的线程少数
inheritableThreadLocal:子线程继续传播父线程的上下文
ribbon上下文就是inheritableThreadLocal
RibbonFilterContextHolder.getCurrentContext().get("TAG")
//父线程传入当前的ReuestContextHolder
@Slf4j
public class HystrixConcurrencyStrategyCustomize extends HystrixConcurrencyStrategy {
private CanaryServerManager canaryServerManager;
public HystrixConcurrencyStrategyCustomize(CanaryServerManager canaryServerManager) {
this.canaryServerManager = canaryServerManager;
}
public <T> Callable<T> wrapCallable(Callable<T> callable) {
HystrixCustomizeCallable hystrixCustomizeCallable = new HystrixCustomizeCallable( (ServletRequestAttributes)RequestContextHolder.getRequestAttributes(),callable);
return hystrixCustomizeCallable;
}
}
class HystrixCustomizeCallable<T> implements Callable<T>{
private Callable<T> callable;
private ServletRequestAttributes attributes;
public HystrixCustomizeCallable(ServletRequestAttributes attributes, Callable<T> callable){=========父线程值传进来
this.attributes = attributes;
this.callable = callable;
}
public HystrixCustomizeCallable(Callable<T> callable) {
this.callable = callable;
}
//子线程复制父线程中的attribute
@Override
public T call() throws Exception {============子线程才执行这个方法============
try{
//这里是为了feign拿到源请求的头信息
if(null != this.attributes){
RequestContextHolder.setRequestAttributes(this.attributes);
}
return this.callable.call();
}finally {
RequestContextHolder.resetRequestAttributes();
//结束时清除loadbalancerkey的缓存
CanaryServerManager.resetLoadBalancerKey();
}
}
}
hystrix两种模式---线程,信号量
https://blog.csdn.net/songhaifengshuaige/article/details/80345012
api部分:
zuul
参考上一篇zuul自定义负载原理
相关推荐
同时,插件化还允许进行灰度发布,即在部分用户群体中测试新功能,确保稳定后再全面推广,降低了因更新导致的问题风险。 在JavaScript开发中,Chimee的API设计友好且易于理解,使得前端开发者可以轻松上手并进行...
而如果你写了一篇文档:为了便于说明,作者准备了两个示例文档:一篇思路笔记,和一篇完整的产品文档——这样可以完整介绍产品文档的撰写流程。 思路笔记示例是根据你已知的信息和想要解答的问题所梳理成的列表。这...
- **灰度发布**:在大规模部署前,可以先对一部分用户进行新版本的测试,验证无误后再全面推广。 - **日志分析**:升级前后,系统日志的分析对于发现潜在问题至关重要。 本示例代码可能涵盖了上述部分流程的实现,...
6. **治理中心**:提供统一的数据库治理平台,监控、管理分布式数据库集群,支持灰度发布、故障切换等高级功能。 7. **插件化架构**:ShardingSphere采用插件化设计,用户可以自定义扩展功能,如新的分片策略、加密...
OpenMV源码的发布,为开发者提供了深入学习和研究机器视觉算法、嵌入式系统设计以及C语言编程的宝贵资源。本文将对OpenMV源码进行详细介绍,帮助你理解其核心概念和实现机制。 1. **OpenMV项目介绍** OpenMV项目的...
17.4.6 灰度发布/流量切换 356 17.4.7 监控服务质量 356 17.4.8 限流 356 17.5 前端业务逻辑后置 356 17.6 前端接口服务端聚合 357 17.7 服务隔离 359 18 使用OpenResty开发高性能Web应用 360 18.1 OpenResty简介 ...
然而,在某些应用场景下,我们可能需要将PDF文档转换为图像格式,例如为了方便在线共享、社交媒体发布或者进行进一步的图像处理。这时,一款高效的PDF转图像工具就显得尤为重要。SautinSoft.PdfFocus.dll正是这样一...
- **开源化**:2000年发布为开源项目。 - **社区贡献**:2006年起,由全球开发者社区持续贡献代码和功能。 - **OpenCV主要特点:** - **跨平台性**:支持Windows、Linux、Mac OS等多种操作系统。 - **丰富的...
发布后,微信会自动进行灰度测试和版本更新,确保用户能够获得最新的小程序体验。 11. **社区资源**: "Awesome mini program" 可能包含了各种社区讨论、最佳实践、工具库和模板,这些都是开发者提升技能、解决...
- **灰度发布**:可以对部分用户先推送新版本,观察反馈后再全面发布,降低风险。 5. 学习资源与社区: - **官方文档**:微信小程序提供了详尽的开发文档,包括教程、API参考、示例代码等,是学习的重要参考资料...
此外,它还可以实现灰度发布和A/B测试,通过控制不同版本服务的流量比例,帮助开发者进行新功能的验证和优化。 4. 监控与日志:Galeb提供了丰富的监控和日志记录功能,以便于开发者分析系统性能、排查问题和优化...