通过本篇博客,你将能够掌握常见的网关配置方式,提升对系统架构的理解与运维能力。
目录
前言
在现代微服务架构中,网关是连接各个服务的重要组件,承担着流量控制、路由转发、负载均衡等重要功能。作为架构中的入口点,网关的配置与管理对于系统的稳定性与性能至关重要。本篇博客将带你快速了解网关的基本概念与使用方法,重点介绍如何通过设置路由属性来灵活控制请求的转发和处理。通过本篇博客,你将能够掌握常见的网关配置方式,提升对系统架构的理解与运维能力。
支付服务
创建新模块pay-service
pom.xml文件内容如下:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>hmall</artifactId>
<groupId>com.heima</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>pay-service</artifactId>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<!--common-->
<dependency>
<groupId>com.heima</groupId>
<artifactId>hm-common</artifactId>
<version>1.0.0</version>
</dependency>
<!--api-->
<dependency>
<groupId>com.heima</groupId>
<artifactId>hm-api</artifactId>
<version>1.0.0</version>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--数据库-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--mybatis-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!--nacos 服务注册发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
编写启动类PayApplication
package com.hmall.pay;
import com.hmall.api.config.DefaultFeignConfig;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableFeignClients(basePackages = "com.hmall.api.client", defaultConfiguration = DefaultFeignConfig.class)
@MapperScan("com.hmall.pay.mapper")
@SpringBootApplication
public class PayApplication {
public static void main(String[] args) {
SpringApplication.run(PayApplication.class, args);
}
}
配置文件application.yaml内容如下:
server:
port: 8086
spring:
application:
name: pay-service
profiles:
active: dev
datasource:
url: jdbc:mysql://${hm.db.host}:3306/hm-pay?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: ${hm.db.pw}
cloud:
nacos:
server-addr: 192.168.244.132:8848
mybatis-plus:
configuration:
default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
global-config:
db-config:
update-strategy: not_null
id-type: auto
logging:
level:
com.hmall: debug
pattern:
dateformat: HH:mm:ss:SSS
file:
path: "logs/${spring.application.name}"
knife4j:
enable: true
openapi:
title: 支付服务接口文档
description: "支付服务接口文档"
email: zhanghuyi@itcast.cn
concat: 虎哥
url: https://www.itcast.cn
version: v1.0.0
group:
default:
group-name: default
api-rule: package
api-rule-resources:
- com.hmall.pay.controller
支付服务模块如下:
在支付服务中,当用户使用余额支付时,系统需要执行以下步骤:
- 扣减用户的账户余额。
- 更新订单状态为“已支付”。
在此流程中,用户余额扣减的功能存在于 user-service服务
中,而 订单状态更新 则由 trade-service
服务提供。因此,trade-service
服务需要通过 OpenFeign 来远程调用这两个服务。为此,我们可以将这些操作封装为一个 Feign 客户端。
通过 Feign 客户端,trade-service
服务可以高效地与 user-service
和 trade-service
进行交互,以便在支付过程中进行相应的调用。这样,我们将用户余额扣减和订单状态更新的功能模块化,并保证服务间的解耦与高效通信。
扣减用户余额,抽取到hm-api的UserClient接口中,代码如下:
package com.hmall.api.client;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient("user-service")
public interface UserClient {
@PutMapping("/users/money/deduct")
void deductMoney(@RequestParam("pw") String pw, @RequestParam("amount") Integer amount);
}
修改pay-service服务中的PayOrderServiceImpl
@Service
@RequiredArgsConstructor
public class PayOrderServiceImpl extends ServiceImpl<PayOrderMapper, PayOrder> implements IPayOrderService {
private final UserContext userContext;
private final TradeClient tradeClient;
private final UserClient userClient;
@Override
@Transactional
public void tryPayOrderByBalance(PayOrderFormDTO payOrderFormDTO) {
// 1.查询支付单
PayOrder po = getById(payOrderFormDTO.getId());
// 2.判断状态
if(!PayStatus.WAIT_BUYER_PAY.equalsValue(po.getStatus())){
// 订单不是未支付,状态异常
throw new BizIllegalException("交易已支付或关闭!");
}
// 3.尝试扣减余额
userClient.deductMoney(payOrderFormDTO.getPw(), po.getAmount());
// 4.修改支付单状态
boolean success = markPayOrderSuccess(payOrderFormDTO.getId(), LocalDateTime.now());
if (!success) {
throw new BizIllegalException("交易已支付或关闭!");
}
// 5.修改订单状态
tradeClient.markOrderPaySuccess(po.getBizOrderNo());
}
...
}
网关
网关:就是网络的关口,负责请求的路由、转发、身份校验。
在SpringCloud中网关的实现包括两种:
Spring clowd Gateway
- Spring官方出品
- 基于WebFlux响应式编程
- 无需调优即可获得优异性能
Netfilx Zuul
- Netflix出品
- 基于Servlet的阻塞式编程。
- 需要调优才能获得与SpringCloudGateway类似的性能
快速入门
网关其实就是一个独立的服务。具体步骤如下:
- 创建新模块
- 引入网关依赖
- 编写启动类
- 配置路由规则
spring:
cloud :
gateway:
routes:
- id:item # 路由规则id,自定义,唯一
uri:lb://item-service # 路由目标微服务,lb代表负载均衡
predicates:#路由断言,判断请求是否符合规则,符合则路由到目标
- Path=/items/**# 以请求路径做判断,以/items开头则符合
- id: xX
uri:lb://xx-service
predicates:
- Path=/xx/**
(1)创建模块hm-gateway
(2)pom.xml文件如下:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.heima</groupId>
<artifactId>hmall</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>hm-gateway</artifactId>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!--common-->
<dependency>
<groupId>com.heima</groupId>
<artifactId>hm-common</artifactId>
<version>1.0.0</version>
</dependency>
<!--网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos discovery-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--负载均衡-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
(3)创建启动类GatewayApplication类
package com.hmall.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
(4)application.yaml文件内容如下:
server:
port: 8080
spring:
application:
name: gateway
cloud:
nacos:
server-addr: 192.168.244.132:8848
gateway:
routes:
- id: item-service
uri: lb://item-service
predicates:
- Path=/items/**,/search/**
- id: user-service
uri: lb://user-service
predicates:
- Path=/addresses/**,/users/**
- id: cart-service
uri: lb://cart-service
predicates:
- Path=/carts/**
- id: trade-service
uri: lb://trade-service
predicates:
- Path=/orders/**
- id: pay-service
uri: lb://pay-service
predicates:
- Path=/pay-orders/**
访问网关服务8080端口,成功访问商品服务8081端口的功能。
路由属性
网关路由对应的Java类型是RouteDefinition,其中常见的属性有:
- id:路由唯一标示
- uri:路由目标地址
- predicates:路由断言,判断请求是否符合当前路由。
- filters:路由过滤器,对请求或响应做特殊处理
Spring提供了12种基本的RoutePredicateFactory实现:
名称 | 说明 | 示例 |
---|---|---|
After | 是某个时间点后的请求 | - After=2037-01-20T17:42:47.789-07:00[America/Denver] |
Before | 是某个时间点之前的请求 | - Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai] |
Between | 是某两个时间点之前的请求 | - Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver] |
Cookie | 请求必须包含某些cookie | - Cookie=chocolate, ch.p |
Header | 请求必须包含某些header | - Header=X-Request-Id, \d+ |
Host | 请求必须是访问某个host(域名) | - Host=**.somehost.org,**.anotherhost.org |
Method | 请求方式必须是指定方式 | - Method=GET,POST |
Path | 请求路径必须符合指定规则 | - Path=/red/{segment},/blue/** |
Query | 请求参数必须包含指定参数 | - Query=name, Jack或者- Query=name |
RemoteAddr | 请求者的ip必须是指定范围 | - RemoteAddr=192.168.1.1/24 |
weight | 权重处理 | -Weight=group1,2 |
XForwarded Remote Addr | 基于请求的来源IP做判断 | XForwardedRemoteAddr=192.168.1.1/24 |
网关中提供了33种路由过滤器,每种过滤器都有独特的作用.
总结
在本文中,我们从网关的基本概念开始,详细介绍了如何快速入门并配置网关。在讨论了路由属性后,我们深入探讨了其在流量控制、负载均衡以及请求转发中的应用。正确配置路由属性能够帮助开发者更好地优化系统架构,提高服务的可用性与灵活性。希望通过这篇博客,你能够更好地理解和应用网关的路由功能,为你的微服务架构带来更加稳定和高效的支持。如果你有任何问题,欢迎留言讨论,我们一同探索更多的技术细节。