一. 架构设计
微服务架构图
架构原理
1. 微服务系统在启动时将自己注册到服务注册中心,同时对外发布 Http 接口供其它系统调用(一般都是基于Spring MVC)
2、服务消费者基于 Feign 调用服务提供者对外发布的接口,先对调用的本地接口加上注解@FeignClient,Feign会针对 加了该注解的接口生成动态代理,服务消费者会针对 Feign 生成的动态代理去调用方法时,在底层会生成Http协议格式的请求,类似 /stock/deduct?productId=100
3、Feign 最终会调用Ribbon从本地的Nacos注册表的缓存里根据服务名取出服务提供在机器的列表,然后进行负载均衡 并选择一台机器出来,对选出来的机器IP和端口拼接之前生成的url请求,生成类似调用http接口地址 http://192.168.0.60:9000/stock/deduct?productId=100,最后基于HTTPClient调用请求
基于微服务架构的原理,来设计灰度方案
概要流程:
1. 全局配置灰度是否启用--在nacos中配置, 动态更新
2. 配置灰度规则, version=2.0, class="1234567" maxClassId="010-1234567"
3. 设置灰度服务器, 哪些服务器是灰度服务器。 为其打标签
4. 启动所有服务, 服务在nacos上进行注册
5. 客户端发起请求, 带着header参数
6. zuul进行过滤,判断是否符合灰度条件, 如果符合,打上灰度标签
7. 通过feign将灰度标签进行透传
8. 通过ribbon选择跳转的服务器, 可以指定负载均衡策略
9. 下一个服务器继续跳转,带上feign的灰度标签,继续请求。
以上是这个灰度方案实现的整体逻辑和思路
二. 具体操作及规划
2.1 灰度的目标
不同的流量过来, 根据元数据匹配, 走不同的微服务
当流量请求过来以后, 根据其匹配的灰度规则的不同, 走的服务有所不同, 可以将其分为三种类型.
1. 不匹配任何灰度规则, 则走无灰度服务
2. 匹配灰度规则, 则走对应的灰度服务
3. 同时匹配多个灰度规则, 选择灰度服务
2.2 设置灰度规则
1. 全局灰度标签设置在nacos中, nacos配置的灰度标签的开闭, 可实时自动更新同步.
2. 灰度管理后台, 管理后台主要有两大块内容.
1) 配置灰度规则
1. 根据需要设置灰度规则, 比如: 城市, 大班, 小班, 版本号, 学科等,
2) 设置灰度服务器
1. 调用nacos接口, 获取所有微服务ip+port
2. 为灰度服务器打灰度标签
3. 做同步策略, 当灰度服务标签内容有变化, 通知网关, 做相应更新
2.3. 网关设置--拦截请求, 为其打灰度标签
网关其实就是各种各样的过滤器, 常用的过滤器类型有:pre:前置过滤器, routing: 路由过滤器, post过滤器, error过滤器
这里我们定义一个前置过滤器, 过滤所有 过来的请求, 判断其是否匹配灰度规则
执行步骤:
1. 初始化灰度规则, 我们首先判断nacos中灰度规则是否启用, 启用则去灰度管理服务器获取有效的灰度规则
2. 判断请求头是否和某一灰度规则匹配, 如果匹配, 则将请求header添加到请求上下文, 后续feign进行透传. 同时添加到ribbon请求上下文, 做服务选择.
2.4. ribbon设置 -- 根据灰度规则, 选择灰度服务器
ribbon是客户端负载均衡, 通过对ribbon上下文中的灰度标签和微服务列表中灰度标签的比较, 来选择一台服务器, 作为目标跳转服务器
2.5. 自定义Feign拦截器, 实现参数(灰度标签)的透传
feign的实质是拦截器, feign将拦截所有的请求跳转, 主要作用是用来做header参数透传, 保证服务间的调用也可以正确选择灰度服务器.
三. 各组件功能原理
3.1 zuul网关
1. 标准的过滤器类型
pre:前置过滤器
在请求被路由到原服务器之前, 要执行的过滤器
认证 : 认证安全, 是否符合条件, 认证为安全的才能放过
选路由: 当前这个请求来了, 应该调用后面的哪个微服务呢? A还是B
请求日志: 请求日志, 日志来了, 写日志, 对其进行监控
routing: 路由过滤器
处理将请求发送到源服务器的过滤器
post过滤器
在响应从源服务器返回时要被执行的过滤器
对响应增加http请求头: 要增加调试的header日志
收集统计和度量: 这次请求, 它的性能如何, 有没有出错? 可以搜集一些信息
将响应以流的方式返回客户端
error过滤器
2. 请求处理的生命周期
1) 请求过来了, 首先会进入一系列的前置过滤器pre filter.
2)前置过滤器处理完了, 进入routing filter路由过滤器, routing filter路由过滤器是真正的向后台服务发起请求, 接收响应的过滤器
3) 经过routing filter路由过滤器, 最后会传递过post filter 后置过滤器,进行一些后续的处理, 这时候已经拿到响应了, 然后在返回给客户端.
4) 在这三个过滤器过滤的过程中,任何一个环节发生错误, 都会进入error filter. 有error filter进行统一的错误处理. error filter错误过滤器会发送给post filter, 也是以响应的方式发回给客户端.
这是一个请求, 在网关处理的生命周期.
3. 自定义路由拦截器
这个过滤器extends ZuulFilter
package com.lxl.www.gateway.filter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
@Component
public class TokenFilter extends ZuulFilter {
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 1;
}
@Override
public boolean shouldFilter() {
return true;
}
/**
* 实现token 拦截验证
* @return
* @throws ZuulException
*/
@Override
public Object run() throws ZuulException {
return null;
}
}
这个过滤器extends自ZuulFilter, 后面的案例多了, 我们就发现, 其实zuul网关的本质就是拦截器, zuul的各种功能,也是通过拦截器来实现的
filterType() : 拦截器的类型是前置拦截器.
filterOrder(): 执行顺序是第一个执行.
shouldFilter(): 过滤器执行的条件, 这里是所有的连接都需要过这个拦截器, 所以直接设置为true
run(): 拦截器的核心逻辑.
4. spring-cloud-zuul已经实现的过滤器
pre过滤器:
PreDecorationFilter
ServletDetectionFilter
FormBodyWrapperFilter
DebugFilter
Servlet30WrapperFilter
routing 过滤器
RibbonRoutingFilter
SimpleHostRoutingFilter
post过滤器
SendResponseFilter
SendForwardFilter
error过滤器
SendErrorFilter
3.2 ribbon
1. ribbon是一个客户端负载均衡
ribbon的实现原理 原来我们的http请求是 http://ip:port/**** 使用ribbon: 需要使用项目名/ 那么也就是根据项目名 寻找一台服务 然后将项目名定位到一台服务的过程
2、 重新定义ribbon负载均衡策略
public class TheSameClusterPriorityRule extends AbstractLoadBalancerRule {
@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {
}
/**
* 主要实现choose方法
*
*/
@Override
public Server choose(Object o) {
}
}
1、 feign也是客户端负载均衡
Ribbon VS Feign
feign和ribbon是Spring Cloud的Netflix中提供的两个实现软负载均衡的组件,Ribbon和Feign都是用于 调用其他服务的,方式不同。Feign则是在Ribbon的基础上进行了一次改进,采用接口的方式。 将需要调用的其他服务的方法定义成抽象方法即可,不需要自己构建 http 请求