当前位置: 首页 > news >正文

SpringClound——网关、服务保护和分布式事务

一、网关

网络的关口,负责请求的路由、转发、身份验证

server:port: 8080
spring:cloud:nacos:discovery:server-addr: 192.168.96.129:8848gateway:routes:- id: item-serviceuri: lb://item-servicepredicates:- Path=/items/**,/search/**- id: user-serviceuri: lb://user-servicepredicates:- Path=/addresses/**,/users/**- id: cart-serviceuri: lb://cart-servicepredicates:- Path=/carts/**- id: trade-serviceuri: lb://trade-servicepredicates:- Path=/orders/**application:name: hm-gateway

二、网关登录校验

自定义过滤器:

package com.hmall.gateway.filters;import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;@Component
public class MyGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();System.out.println("GlobalFilter pre阶段 执行了");return chain.filter(exchange);}@Overridepublic int getOrder() {return 0;}
}

微服务项目网关:

package com.hmall.gateway.filters;import com.hmall.common.exception.UnauthorizedException;
import com.hmall.gateway.config.AuthProperties;
import com.hmall.gateway.utils.JwtTool;
import lombok.RequiredArgsConstructor;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import java.util.List;@Component
@RequiredArgsConstructor
public class AuthGlobalFilter implements GlobalFilter, Ordered {//不需要处理的请求路径public final AuthProperties authProperties;public final JwtTool jwtTool;private final AntPathMatcher antPathMatcher = new AntPathMatcher();@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//获得请求头ServerHttpRequest request = exchange.getRequest();//放行不需要拦截的请求//路径合法,需要放行if (isUnique(request.getPath().toString())){//合法,放行return chain.filter(exchange);}//判断令牌是否合法String token=null;Long userId=null;List<String> authorization = request.getHeaders().get("authorization");if (authorization != null && authorization.size() > 0) {token = authorization.get(0);}try {userId = jwtTool.parseToken(token);}catch (UnauthorizedException e) {//401 未登录、未授权ServerHttpResponse response = exchange.getResponse();response.setStatusCode(HttpStatus.UNAUTHORIZED);return response.setComplete();}//TODO 保存用户id到请求头,实现多个微服务间用户id的共享String userInfo = userId.toString();ServerWebExchange swe=exchange.mutate().request(builder -> builder.header("user-info", userInfo)).build();//System.out.println(userId);//放行return chain.filter(swe);}@Overridepublic int getOrder() {return 0;}private boolean isUnique(String path) {for (String excludePath : authProperties.getExcludePaths()) {if (antPathMatcher.match(excludePath, path)) {return true;}}return false;}
}

server:port: 8080
spring:application:name: hm-gatewaycloud:nacos:discovery:server-addr: 192.168.96.129:8848gateway:routes:- id: item-serviceuri: lb://item-servicepredicates:- Path=/items/**,/search/**- id: user-serviceuri: lb://user-servicepredicates:- Path=/addresses/**,/users/**- id: cart-serviceuri: lb://cart-servicepredicates:- Path=/carts/**- id: trade-serviceuri: lb://trade-servicepredicates:- Path=/orders/**- id: pay-serviceuri: lb://pay-servicepredicates:- Path=/pay-orders/**
hm:jwt:location: classpath:hmall.jksalias: hmallpassword: hmall123tokenTTL: 30mauth:excludePaths:- /search/**- /users/login- /items/**- /hi

网关传递用户:将用户的id保存在请求头当中,通过统一拦截处理,获取用户的id,放入ThreadLocal当中;请求完成,清理ThreadLocal,实现用户id从网关到各个项目模块的传递

OpenFeign传递用户:OpenFeign中提供了一个拦截器接口,所有由OpenFeign发起的请求都会先调用拦截器处理请求,在拦截处理过程中,我们将ThreadLocal中的用户id放入OpenFeign的请求头当中,其他微服务拦截处理的过程中获得用户id并放入线程当中

三、配置管理

1.拉取共享配置

2.加入相关依赖

        <!--nacos配置管理--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><!--读取bootstrap文件--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId></dependency>

3.配置热更新

(1)nacos中要有一个与微服务名有关的配置文件

(2)微服务中要以特定方式读取需要热更新的配置属性

package com.hmall.cart.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@Data
@ConfigurationProperties(prefix = "hm.cart")
public class MaxCommodityConfig {private Integer maxCommodity;
}

4.动态路由

package com.hmall.gateway.routes;
import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.RequiredArgsConstructor;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.Executor;@Component
@RequiredArgsConstructor
public class DynamicRounterLoader {private final NacosConfigManager nacosConfigManager;private final RouteDefinitionWriter writer;private final String dataId="gateway-routes.json";private final String group="DEFAULT_GROUP";//记录路由的idprivate HashSet<String> set=new HashSet<String>();//在Bean初始化之后执行@PostConstructpublic void initRoutesConfigListener() throws NacosException {//拉取配置并更新配置String configInfo = nacosConfigManager.getConfigService().getConfigAndSignListener(dataId, group, 5000, new Listener() {@Overridepublic Executor getExecutor() {return null;}@Overridepublic void receiveConfigInfo(String configInfo) {//路由表更新,更新监听器System.out.println(configInfo+"监听器更新执行了");updateRouters(configInfo);}});System.out.println(configInfo+"监听器更新了");//第一次启动,更新监听器updateRouters(configInfo);}private void updateRouters(String configInfo) {//将json数据转换为实体类List<RouteDefinition> routeDefinitionList = JSONUtil.toList(configInfo, RouteDefinition.class);//删除原来的路由表for (String id : set) {writer.delete(Mono.just(id)).subscribe();}set.clear();//添加新的路由表并记录idfor (RouteDefinition routeDefinition : routeDefinitionList) {writer.save(Mono.just(routeDefinition)).subscribe();set.add(routeDefinition.getId());}}}

将yaml配置转换为json配置:

[{"id": "item","predicates": [{"name": "Path","args": {"_genkey_0":"/items/**", "_genkey_1":"/search/**"}}],"filters": [],"uri": "lb://item-service"},{"id": "cart","predicates": [{"name": "Path","args": {"_genkey_0":"/carts/**"}}],"filters": [],"uri": "lb://cart-service"},{"id": "user","predicates": [{"name": "Path","args": {"_genkey_0":"/users/**", "_genkey_1":"/addresses/**"}}],"filters": [],"uri": "lb://user-service"},{"id": "trade","predicates": [{"name": "Path","args": {"_genkey_0":"/orders/**"}}],"filters": [],"uri": "lb://trade-service"},{"id": "pay","predicates": [{"name": "Path","args": {"_genkey_0":"/pay-orders/**"}}],"filters": [],"uri": "lb://pay-service"}
]

三、服务保护和分布式事务

1.雪崩问题

微服务调用链路中的某个服务故障,引起整个链路中的所有微服务都不可用

解决方案:保证代码的健壮性、保证网络的畅通、能应对高并发请求

2.服务保护

请求限流:限制访问服务器的并发量,避免服务因流量激增出现故障

线程隔离:模拟船舱隔板的防水原理。通过限定每个业务能使用的线程数量而将故障业务隔离,避免故障扩散

服务熔断:由断路器统计请求的异常比例或慢调用比例,如果超出阈值则会熔断业务,则拦截该接口请求

3.分布式事务

事务协调者(TC):维护全局和分支事务的状态,协调全局事务提交和回滚

事务管理器(TM):定义全局事务范围、开始全局事务、提交或回滚全局事务

资源管理器(RM):管理分支事务,与TC交谈以注册分支事务和报告分支事务状态

XA模式:

优点:事务的强一致性,满足ACID原则​,常用数据库都支持,实现简单,并且没有代码侵入

缺点:因为一阶段需要锁定数据库资源,等待二阶段结束才释放,性能较差​,依赖关系型数据库实现事务​

AT模式:

优点:满足ACID原则​,常用数据库都支持,实现简单,并且没有代码侵入,单个RM完成之后进行事务的提交,不占用资源,提高了性能

缺点:难以实现复的事务控制,如特定隔离级别;当事务的隔离级别过低时会出现脏读、不可重复读、幻读问题


http://www.dtcms.com/a/339061.html

相关文章:

  • Redis-缓存-击穿-分布式锁
  • 使用ros2跑mid360的fastlio2算法详细教程
  • 【数据结构】用堆解决TOPK问题
  • 算法训练营day56 图论⑥ 108. 109.冗余连接系列
  • C++---为什么迭代器常用auto类型?
  • 强、软、弱、虚引用
  • 在 Qt C++ 中利用 OpenCV 实现视频处理技术详解
  • 尝试Claude Code的安装
  • 学习笔记分享——基于STM32的平衡车项目
  • Mac调试ios的safari浏览器打开的页面
  • 电子电气架构 --- 软件项目成本估算
  • 技术攻坚全链铸盾 锁定12月济南第26届食品农产品安全高峰论坛
  • 任务十二 我的页面及添加歌曲功能开发
  • Typescript入门-对象讲解
  • Python量化交易:结合爬虫与TA-Lib技术指标分析
  • Matplotlib数据可视化实战:Matplotlib子图布局与管理入门
  • Ansible 角色管理指南
  • Pandas数据处理与分析实战:Pandas数据处理与Matplotlib可视化入门
  • 0819 使用IP多路复用实现TCP并发服务器
  • Tomcat 的核心脚本catalina.sh 和 startup.sh的关系
  • 陪诊小程序系统开发:开启智慧就医新时代
  • CNN 在故障诊断中的应用:原理、案例与优势
  • BEV:隐式相机视角转换-----BEVFormer
  • 简单实现监听redis的Key过期事件
  • Shopee本土店账号安全运营:规避封禁风险的多维策略
  • 微服务-08.微服务拆分-拆分商品服务
  • 什么是强化学习
  • JMeter高级性能测试训练营 – 从入门到企业级实战
  • pytest高级用法之插件开发
  • Quartus Prime 18.1网盘资源下载与安装指南