随着公司的业务发展,有幸经历了从单体应用迁移到分布式应用,又从分布式应用开始准备搭建 微服务 应用,以下是公司从零开始搭建微服务的过程,记录并分享出来,希望对大家有所帮助,我们先使用Spring Cloud GateWay作为网关,由于目前还没有服务发现组件,例如eurka,所以需要通过配置文件的方式配置Ribbon作负载均衡。所以以下重点讲解 Spring Cloud GateWay 和 Ribbon 的搭配使用。
网关的由来
微服务提出后,单体应用被拆分成多个服务,为了对外提供统一入口,解耦客户端与内部服务。
网关的作用
网关能做统一的路由转发、熔断、限流、安全认证、日志监控等。
网关zuul与Spring Cloud Gateway对比
Spring Cloud Gateway核心概念
1. 路由(route) 路由是网关最基础的部分,路由信息由一个ID、一个目的URL、一组断言工厂和一组 filter 组成。如果断言为真,则说明请求URL和配置的路由匹配。
2. 断言(predicates) Java8中的断言函数,Spring Cloud Gateway中的断言函数输入类型是Spring5.0框架中的ServerWebExchange。Spring Cloud Gateway中的断言函数允许开发者去定义匹配来自Http Request中的任何信息,比如请求头和参数等。
3. 过滤器(filter) 一个标准的Spring webFilter,Spring Cloud Gateway中的Filter分为两种类型,分别是Gateway Filter和Global Filter。过滤器Filter可以对请求和相应进行处理。
Spring Cloud Gateway工作原理
Spring Cloud Gateway核心处理流程如上图所示,Gateway的客户端向Spring Cloud Gateway发送请求,请求首先被HttpWebHandlerAdapter进行提取组装成网关上下文,然后网关的上下文会传递到DispatcherHandler。DispatcherHandler是所有请求的分发处理器,DispatcherHandler主要负责分发请求对应的处理器。比如请求分发到对应的RoutePredicateHandlerMapping(路由断言处理映射器)。路由断言处理映射器主要作用用于路由查找,以及找到路由后返回对应的FilterWebHandler。FilterWebHandler主要负责组装Filter链并调用Filter执行一系列的Filter处理,然后再把请求转到后端对应的代理服务处理,处理完毕之后将Response返回到Gateway客户端。
路由断言Factories整理
- After 路由断言 Factory :在该日期时间之后发生的请求都将被匹配。
- Before 路由断言 Factory:在该日期时间之前发生的请求都将被匹配。
- Between 路由断言 Factory:在datetime1和datetime2之间的请求将被匹配。
- Cookie 路由断言 Factory:Cookie 路由断言 Factory有两个参数,cookie名称和正则表达式。请求包含以cookie名称且正则表达式为真的将会被匹配。
- Header 路由断言 Factory:Header 路由断言 Factory有两个参数,header名称和正则表达式。请求包含以header名称且正则表达式为真的将会被匹配。
- Host 路由断言 Factory:Host 路由断言 Factory包括一个参数:host name列表。使用Ant路径匹配规则,.作为分隔符。
- Method 路由断言 Factory:Method 路由断言 Factory只包含一个参数: 需要匹配的HTTP请求方式。
- Path 路由断言 Factory:Path 路由断言 Factory 有2个参数: 一个Spring PathMatcher表达式列表和可选。
- Query 路由断言 Factory:Query 路由断言 Factory 有2个参数: 必选项 param 和可选项 regexp。
- RemoteAddr 路由断言 Factory:RemoteAddr 路由断言 Factory的参数为 一个CIDR符号(IPv4或IPv6)字符串的列表,最小值为1,例如192.168.0.1/16(其中192.168.0.1是IP地址并且16是子网掩码)。
GatewayFilter Factories整理
- AddRequestHeader GatewayFilter Factory:对于所有匹配的请求,这将向下游请求的头中添加header。
- AddRequestParameter GatewayFilter Factory:对于所有匹配的请求,这将向下游请求添加查询字符串。
- AddResponseHeader GatewayFilter Factory:对于所有匹配的请求,这会将头添加到下游响应的header中。
- Hystrix GatewayFilter Factory:Hystrix 是Netflix开源的断路器组件。Hystrix GatewayFilter允许你向网关路由引入断路器,保护你的服务不受级联故障的影响。
- FallbackHeaders GatewayFilter Factory:FallbackHeaders允许在转发到外部应用程序中的FallbackUri的请求的header中添加Hystrix异常详细信息。
- PrefixPath GatewayFilter Factory:这将给所有匹配请求的路径加前缀。
- PreserveHostHeader GatewayFilter Factory:该filter没有参数。设置了该Filter后,GatewayFilter将不使用由HTTP客户端确定的host header ,而是发送原始host header 。
- RequestRateLimiter GatewayFilter Factory:RequestRateLimiter使用RateLimiter实现是否允许继续执行当前请求。如果不允许继续执行,则返回HTTP 429 – Too Many Requests (默认情况下)。
- Redis RateLimiter:令牌桶的填充速率。
- RedirectTo GatewayFilter Factory:该过滤器有一个 status 和一个 url参数。status是300类重定向HTTP代码,如301。该URL应为有效的URL,这将是 Location header的值。
- RemoveRequestHeader GatewayFilter Factory:有一个name参数. 这是要删除的header的名称。
- RemoveResponseHeader GatewayFilter Factory:有一个name参数. 这是要删除的header的名称。
- RewritePath GatewayFilter Factory:包含一个 regexp正则表达式参数和一个 replacement 参数. 通过使用 Java 正则表达式灵活地重写请求路径。
- RewriteResponseHeader GatewayFilter Factory:包含 name, regexp和 replacement 参数.。通过使用Java正则表达式灵活地重写响应头的值。
- SetPath GatewayFilter Factory:它提供了一种通过允许路径的模板化segments来操作请求路径的简单方法。使用Spring Framework中的URI模板,允许多个匹配segments。
- SetStatus GatewayFilter Factory:SetStatus GatewayFilter Factory 包括唯一的 status参数.必须是一个可用的Spring HttpStatus。
- StripPrefix GatewayFilter Factory:parts参数指示在将请求发送到下游之前,要从请求中去除的路径中的节数。
- Retry GatewayFilter Factory:Retry GatewayFilter Factory包括 retries, statuses, methods和 series 参数。
- RequestSize GatewayFilter Factory:当请求大小大于允许的限制时,RequestSize GatewayFilter Factory可以限制请求不到达下游服务。过滤器以RequestSize作为参数,这是定义请求的允许大小限制(以字节为单位)。
Ribbon的LoadBalancer的主要组件
IRule
IPing
检查实例是否存活。如何ping。实现类:
ServerList
获取服务器列表。
ServerListFilter
在获取的服务器列表中进行获取。
CommonClientConfigKey#EnableZoneExclusivity=true。开启后,同一个区域之外的服务器将被过滤。默认情况下,区域亲和力和排他性是关闭的,并且
不会过滤任何内容。
ServerListUpdater
更新服务器列表。
IClientConfig
- IClientConfig的实现类为DefaultClientConfigImpl。DefaultClientConfigImpl是默认的客户端配置,可以从Archaius ConfigurationManager加载属性。
ILoadBalancer
LoadBalancer的组成:
- 一个基于特定条件可能进行存储的服务器列表。
- 一个类:通过IRule实现并定义LoadBalancing策略。
- 该类定义并实现一种机制,用户确定列表中节点/服务器的实用性/可用性。
LoadBalancer的实现类:
则该区域将从活动服务器列表中删除。如果多个区域已达到阈值,则将删除每台服务器上最活跃请求的区域。一旦删除了最坏的区域,
将在其余区域中选择一个区域,其概率与其实例数成正比。服务器将从具有指定规则的选定区域返回。每个区域相关的负载平衡决策都是在最新统计信息的帮助下实时做出的。
代码实践
pom .xml增加SpringCloud Gateway和Ribbon依赖
<parent>
<groupId> org .springframework. boot </groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
</dependencies>
代码方式配置网关
@SpringBootApplication
@RestController
public class DemoGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(DemoGatewayApplication.class, args);
}
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route(r -> r
.path("/refund/**")
.filters(f -> f.addRequestHeader("Hello", "World"))
.uri("#34;)
).build();
}
}
yml方式配置网关
spring:
application:
name: gateway-service
cloud:
gateway:
routes:
- id: merchant
uri: lb://merchant-load-balanced-service
predicates:
- Path=/merchant/**
- Method=POST
- id: split
uri: lb://split-load-balanced-service
predicates:
- Path=/split/**
filters:
- RewritePath=/split, /ledger-split #重写url
- id: cashier
uri: lb://cashier-load-balanced-service
predicates:
- Path=/cashier/**
filters:
- StripPrefix=1 #将cashier过滤掉
#ribbon全局配置
ribbon:
ConnectTimeout: 1000 #服务请求连接超时时间(毫秒)
ReadTimeout: 3000 #服务请求处理超时时间(毫秒)
OkToRetryOnAllOperations: true #对超时请求启用重试机制
MaxAutoRetriesNextServer: 1 #切换重试实例的最大个数
MaxAutoRetries: 1 # 切换实例后重试最大次数
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RoundRobinRule #负载均衡算法
NFLoadBalancerPingClassName: com.talpay.gateway.config.HealthCheck #健康检查
NFLoadBalancerPingInterval: 20 #设置健康检查间隔,单位秒,默认30秒
merchant-load-balanced-service:
ribbon:
listOfServers: 192.168.xxx.xxx:8080
split-load-balanced-service:
ribbon:
listOfServers: 192.168.xxx.xxx:8081
cashier-load-balanced-service:
ribbon:
listOfServers: 192.168.xxx.xxx:8080
Ribbon服务健康检查
@Slf4j
@Component
public class HealthCheck implements IPing{
@Autowired
private RestTemplate restTemplate;
@Value("${dingtalk.url}")
private String dingtalkURL; //钉钉报警url
@Override
public boolean isAlive(Server server) {
String url = "#34;+ server.getId()+ "/actuator/health";
try {
ResponseEntity<String> heath = restTemplate.getForEntity(url, String.class);
if (heath.getStatusCode() == HttpStatus.OK) {
log.info("ping " + url + " success ");
return true;
}
log.info("ping " + url + " error and response is " + heath.getBody());
return false;
} catch (Exception e) {
log.error("ping " + url + " failed");
DingRebotSendUtil.send(dingtalkURL,new TextMessage("网关|ping:" + url + " failed"));
return false;
}
}
}
自定义GlobalFilter
@Component
public class LogGlobalFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest serverHttpRequest= exchange.getRequest();
String url = serverHttpRequest.getURI().toString();
System.out.println("url ------>: " + url);//打印每次请求的url
return chain.filter(exchange);
}
}
测试结果:
以上为真实测试数据,第一次触发链接到生产环境,第二次触发链接到仿真环境。
不断分享开发过程用到的技术和面试经常被问到的问题,如果您也对IT技术比较感兴趣可以「关注」我
Hi there Dear, are you genuinely visiting this website regularly, if so
after that you will without doubt take fastidious know-how.