单体应用架构--->垂直应用架构--->分布式架构--->SOA架构--->微服务架构
在一台tomcat服务器上部署一个web项目
就是将原来的一个应用拆成互不相干的几个应用,以提升效率
它将把工程拆分成表现层和服务层两个部分,服务层中包含业务逻辑,表现层只需要处理和页面的交互
一个调度中心对集群进行实时管理,解决在分布式架构下服务越来越多的问题
在SOA基础上继续发展,分而治之
微服务架构, 简单的说就是将单体应用进一步拆分,拆分成更小的服务,每个服务都是一个可以独立运行的项目
进行服务的自动化管理,其核心是服务的自动注册与发现。
服务实例将自身服务信息注册到注册中心。
服务实例通过注册中心获取到注册到其中的服务实例的信息
服务注册中心将出问题的服务自动剔除到可用列表之外,使其不会被调用到。
多个服务之间的远程调用的需求。目前主流的远程调用技术有基于HTTP的RESTful接口以及基于TCP的RPC协议。
REST(Representational State Transfer):
这是一种HTTP调用的格式,更标准,更通用,无论哪种语言都支持http协议
RPC(Remote Promote Call):
一种进程间通信方式。允许像调用本地服务一样调用远程服务。
将所有API调用统一接入到API网关层,由网关层统一接入和输出
将出问题的服务自动剔除到可用列表之外
对一次请求涉及的多个服务链路进行日志记录,性能监控即链路追踪
spring cloud是指通过spring boot整合其他工具快速构建微服务的一套规范,如解决服务治理、负载均衡、熔断器、全局锁等等问题,cloud netflix、cloud alibaba是规范的实现
Dubbo+Nacos+Sentinel+RocketMQ+Seata+OSS+SchedulerX
把对象的生命周期交给Spring容器管理
依赖注入
@Component("componentBean")
public class ComponentBean {
}
@Configuration
public class BeanConfig {
@Bean
public ConfigBean configBean() {
return new ConfigBean();
}
}
首先各个服务之间要可以互相的访问
即远程过程调用,通过访问 JAR 包的方式
直接使用HTTP做应用层协议
通过注册中心管理各个微服务,服务注册与监控是RPC架构的两个基本功能
服务越多,本地配置的url维护成本越高,需要动态维护
监控每个服务的调用量和使用时间
保存所有服务的名字,服务提供者的IP列表,服务消费者的IP列表
提供跨进程服务
寻找服务并消费。
基本功能RPC通信
可以集成其他主流框架
a、支持多种协议的服务发布,默认dubbo://,还支持rest://、webservice://等
b、支持不同的注册中心,如zookeeper、Nacos、Redis
服务治理
dubbo虽然作为一个rpc框架负责通信,但仍然具备其他注册中心基本的功能
当服务消费方调用服务提供方的服务出现错误时候,缺省模式为failover,也就是失败重试
为了避免大量请求一直落到一个或几个服务提供方机器上,缺省为random,也就是每次随机调用一台服务提供者的机器。
动态维护越来越多服务的url地址
服务的调用量即响应时间
服务感知
某个节点异常时需要选取新节点继续工作
分布式协调中间件,主要解决分布式环境中各个服务进程访问控制,避免同一时刻有多个进程访问某一资源
注意:
a、基于本身的特性可以用作注册中心
b、由于apache官方推荐的关系,最早dubbo用zookeeper实现服务注册
a、conf目录下配置样例zoo_sample.cfg
b、修改为zoo.cfg,默认端口2181
c、zkCli.sh启动
Zookeeper维护一个类似文件系统的数据结构:
a、每个子目录项如 NameService 都被称作为 znode(目录节点)
b、和文件系统一样,我们能够自由的增加、删除znode
c、唯一的不同在于znode是可以存储数据的,维护了一个start状态信息,包含数据化的时间和版本等
PERSISTENT-持久节点
保存到磁盘,客户端与zookeeper断开连接后,该节点依旧存在
SEQUENTIAL-有序节点
递增序列,可以将持久节点、临时节点设为有序
EPHEMERAL-临时节点
客户端与zookeeper断开连接后,该节点被删除
当目录节点发生变化(数据改变、被删除、子目录节点增加删除)时,zookeeper会通知客户端。
获得节点信息
获取所有子节点
判断节点是否存在
解决多个进程需要访问统一服务时的问题
每个客户端可以去ZooKeeper服务器上的/Exclusice_Locks节点下创建一个临时节点/lock,每次只能有一个客户端创建成功
客户端断开连接后自动删除
集群中某一节点(master)出现故障后选举其他节点作为master继续工作
a、多个客户端在zookeeper创建命名一致的临时节点,因为节点的唯一性,所以只会有一个创建成功,若该节点删除了再重新创建
b、所有客户端在zookeeper共同创建链式临时有序节点,后节点监听前节点的删除事件
当bubbo服务启动时会在zookeeper服务器下建立URL
服务接口全路径名称
表示提供者,dubbo://表示该服务发布的协议类型和访问地址(涉及集群、负载均衡、watcher监听)
消费者写入自己的URL
pom.xml 配置
application.properties 配置
## Dubbo 服务提供者配置
#应用名称
spring.dubbo.application.name=provider
#注册中心
spring.dubbo.registry.address=zookeeper://127.0.0.1:2181
#协议名称
spring.dubbo.protocol.name=dubbo
#协议端口
spring.dubbo.protocol.port=20880
#服务类包
spring.dubbo.scan=org.spring.springboot.dubbo
CityDubboServiceImpl.java
@Service 注解标识为 Dubbo 服务
// 注册为 Dubbo 服务
@Service(version = "1.0.0")
public class CityDubboServiceImpl implements CityDubboService {
public City findCityByName(String cityName) {
return new City(1L,2L,"温岭","是我的故乡");
}
}
City.java 城市实体类
实体类通过 Dubbo 服务之间 RPC 调用,则需要实现序列化接口
pom.xml 、 CityDubboService.java、City.java 没有改动
application.properties 配置
## 避免和 server 工程端口冲突
server.port=8081
## Dubbo 服务消费者配置
spring.dubbo.application.name=consumer
spring.dubbo.registry.address=zookeeper://127.0.0.1:2181
spring.dubbo.scan=org.spring.springboot.dubbo
CityDubboConsumerService.java
@Reference(version = “1.0.0”) 通过该注解,订阅该接口版本为 1.0.0 的 Dubbo 服务
@Component
public class CityDubboConsumerService {
@Reference(version = "1.0.0")
CityDubboService cityDubboService;
public void printCity() {
String cityName="温岭";
City city = cityDubboService.findCityByName(cityName);
System.out.println(city.toString());
}
}
ClientApplication.java 客户端启动类
@SpringBootApplication
public class ClientApplication {
public static void main(String[] args) {
// 程序启动入口
// 启动嵌入式的 Tomcat 并初始化 Spring 环境及其各 Spring 组件
ConfigurableApplicationContext run = SpringApplication.run(ClientApplication.class, args);
CityDubboConsumerService cityService = run.getBean(CityDubboConsumerService.class);
cityService.printCity();
}
}
动态管理配置文件、自动注册服务、动态感知异常节点
a、 下载地址
github地址: https://github.com/alibaba/nacos/releases
b、启动Nacos服务
启动命令(standalone代表着单机模式运行,非集群模式)
启动命令:sh startup.sh -m standalone
启动命令:cmd startup.cmd 或者双击startup.cmd运行文件。
访问:http://localhost:8848/nacos
用户名密码:nacos/nacos
dubbo-nacos-demo
com.zmq
1.0-SNAPSHOT
4.0.0
com.zmq
dubbo-provide
1.8
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-logging
org.springframework.boot
spring-boot-starter-log4j2
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
org.apache.dubbo
dubbo-spring-boot-starter
org.apache.dubbo
dubbo
org.apache.dubbo
dubbo-registry-nacos
2.7.3
com.alibaba.nacos
nacos-client
apache.snapshots.https
Apache Development Snapshot Repository
https://repository.apache.org/content/repositories/snapshots
false
true
org.springframework.boot
spring-boot-maven-plugin
dubbo-nacos-demo
com.zmq
1.0-SNAPSHOT
4.0.0
com.zmq
dubbo-provide
1.8
org.springframework.boot
spring-boot-starter
org.springframework.boot
spring-boot-starter-logging
org.springframework.boot
spring-boot-starter-log4j2
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
org.apache.dubbo
dubbo-spring-boot-starter
org.apache.dubbo
dubbo
org.apache.dubbo
dubbo-registry-nacos
2.7.3
com.alibaba.nacos
nacos-client
apache.snapshots.https
Apache Development Snapshot Repository
https://repository.apache.org/content/repositories/snapshots
false
true
org.springframework.boot
spring-boot-maven-plugin
application.yml
nacos注册中心nacos.config.servier-addr
dubbo名称dubbo.application.name
dubbo注册中心dubbo.registry.address
dubbo路径dubbo.scan.base-packages
nacos:
config:
server-addr: localhost:8848
spring:
application:
name: dubbo-provide
dubbo:
application:
name: ${spring.application.name}
registry:
address: nacos://${nacos.config.server-addr}
scan:
base-packages: com.zmq.service
protocol:
name: dubbo
port: 20881
启动类
@SpringBootApplication
@EnableDubbo
public class DubboProvideApplication {
public static void main(String[] args) {
SpringApplication.run(DubboProvideApplication.class);
}
}
service接口
public interface ProvideService {
String sayHello(String word);
}
service接口实现类
@service注册dubbo服务
@Service
public class ProvideImpl implements ProvideService {
public String sayHello(String word) {
return word;
}
}
dubbo-nacos-demo
com.zmq
1.0-SNAPSHOT
4.0.0
com.zmq
dubbo-consumer
1.8
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-logging
org.springframework.boot
spring-boot-starter-log4j2
org.projectlombok
lombok
true
org.springframework.boot
spring-boot-starter-test
test
org.apache.dubbo
dubbo-spring-boot-starter
org.apache.dubbo
dubbo
org.apache.dubbo
dubbo-registry-nacos
2.7.3
com.alibaba.nacos
nacos-spring-context
0.3.1
com.alibaba.nacos
nacos-client
com.zmq
dubbo-provide
1.0-SNAPSHOT
compile
apache.snapshots.https
Apache Development Snapshot Repository
https://repository.apache.org/content/repositories/snapshots
false
true
org.springframework.boot
spring-boot-maven-plugin
application.yml
server:
address:
port: 8081
spring:
application:
name: dubbo-consumer
nacos:
config:
server-addr: localhost:8848
dubbo:
registry:
address: nacos://${nacos.config.server-addr}
application:
name: ${spring.application.name}
启动类
@SpringBootApplication
public class dubboConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(dubboConsumerApplication.class);
}
}
controller调用服务
@RestController
public class ConsumerController {
@Reference
ProvideService provideService;
@RequestMapping("sayHello")
public String sayHello(){
return provideService.sayHello("我爱你");
}
}
浏览器
启动nacos后可在服务列表看到注册的服务
a、用Nginx 来负载多个 Nacos 节点 IP
b、外部客户端直接通过域名访问就可
nacos的conf目录下有配置文件cluster.conf
application.properties
nacos/conf/application
在没有参数模式,是集群模式sh startup.sh,打开任何一个Nacos控制台都能看到节点列表
a、server_name 直接改成域名就行。
b、Nginx -s reload 重新加载配置后即可
a、acos官方Spring Cloud Nacos Example的示例打开
b、Provider和Consumer两个项目中的application.properties
c、nacos server地址改成 Nginx中配置的server_name。
启动项目,就可以在nacos集群的任何一个节点的服务管理列表中看到里面已经有服务注册成功了
动态维护application配置文件
node08-nacos-server
node08-nacos-clien
配置内容如下:
DataID、文件格式、文件内容的配置。这里还配置了一个MySQL数据源。
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
2.1.1.RELEASE
spring:
application:
name: node08-nacos-server
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
这里的name
配置和上面DataID
一致,就可以读取上述配置内容。
@RestController
public class ServerWeb {
private static Logger logger = LoggerFactory.getLogger(ServerWeb.class) ;
@RequestMapping(value = "/web/getMsg",method = RequestMethod.GET)
public String getMsg (@RequestParam("name") String name){
logger.info("8001 服务被调用...");
return "Hello:" + name ;
}
}
@SpringBootApplication
// SpringCloud原生注解@EnableDiscoveryClient开启服务注册发现功能
@EnableDiscoveryClient
public class ApplicationServer {
public static void main(String[] args) {
SpringApplication.run(ApplicationServer.class,args) ;
}
}
加入基于Feign模式,访问上述服务端提供的接口服务 。
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
2.1.1.RELEASE
org.springframework.cloud
spring-cloud-starter-openfeign
2.1.3.RELEASE
@Configuration
public class RestConfig {
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
@RestController
public class ClientWeb {
@Resource
private RestTemplate restTemplate ;
@RequestMapping(value = "/web/getMsgV1/{name}",method = RequestMethod.GET)
public String getMsgV1 (@PathVariable String name){
String reqUrl = "http://node08-nacos-server:8001/web/getMsg/"+name ;
return restTemplate.getForObject(reqUrl,String.class) ;
}
}
Feign接口配置
@FeignClient("node08-nacos-server")
public interface MsgFeign {
@GetMapping("/web/getMsg")
String getMsg (@RequestParam(name = "name") String name);
}
请求方法
@RestController
public class ClientWeb {
@Resource
private MsgFeign msgFeign ;
@RequestMapping(value = "/web/getMsgV2/{name}",method = RequestMethod.GET)
public String getMsgV2 (@PathVariable String name){
return msgFeign.getMsg(name) ;
}
}
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages={"cloud.nacos.client.feign"})
public class ApplicationClient {
public static void main(String[] args) {
SpringApplication.run(ApplicationClient.class,args) ;
}
}
控制台Dashboard:基于springBoot开发,不需要额外的tomcat等应用容器
限制并发量或请求量
多个微服务调用会形成链式,当某个服务延迟或超时导致阻塞,为避免雪崩效应,将其隔离,直到恢复
出于整体系统负荷考虑暂时隔离
引入Sentinel的核心库
com.alibaba.csp
sentinel-core
1.7.2
业务类方法
@SentinelResource配置保护资源,blockHandler 的值在触发限流之后调用
private static void doSomething() {
try (Entry entry = SphU.entry("doSomething")){
//业务逻辑处理
System.out.println("hello world"+System.currentTimeMillis());
} catch (BlockException ex){
//被流控处理的逻辑
}
}
//注释实现
@SentinelResource(value = "resourceName" ,blockHandler = "blockHandlerForString")
public String getName(String id){
//业务逻辑
return " ";
}
public String blockHandlerForString(String id,BlockException e){
//被限流后的处理方法
return " ";
}
定义限流规则
private static void initFlowRules(){
ArrayList rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setResource("doSomething");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(20);
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
测试
public static void main(String[] args) {
initFlowRules();
while (true) {
doSomething();
}
}
我们需要去到日志文件观看(这个图显示了日志在什么位置):
private void initFlowQpsRule() {
ArrayList rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setCount(20);
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setLimitApp("default");
rule.setStrategy(RuleConstant.STRATEGY_CHAIN);
rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_DEFAULT);
rule.setClusterMode(false);
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
超过线程或qps的阀值触发限流
QPS模式:一台服务器每秒能够响应的查询次数
并发线程数模式:服务不稳定或响应延迟造成阻塞
默认是default即不区分调用来源。
默认当超出阀值抛出FlowException
三种策略:响应时间/异常比例/异常数量
private static void initDegradeRule() {
ArrayList rules = new ArrayList<>();
DegradeRule degradeRule = new DegradeRule();
degradeRule.setResource("key");
degradeRule.setCount(10);
degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
degradeRule.setTimeWindow(10);
degradeRule.setMinRequestAmount(5);
degradeRule.setRtSlowRequestAmount(5);
rules.add(degradeRule);
DegradeRuleManager.loadRules(rules);
}
a、创建一个基于Spring Boot的项目,并集成Greenwich.SR2版本的Spring Cloud依赖。
b、添加Sentinel依赖包
com.alibaba.cloud
spring-cloud-starter-alibaba-sentinel
2.1.1.RELEASE
c、创建一个REST接口,并通过@SentinelResource配置限流保护资源
@RestController
public class SentinelDemoController {
@SentinelResource(value = "hello", blockHandler = "blockHandlerHello")
@GetMapping("/hello")
public String hello() {
return "Hello Sentinel";
}
public String blockHandlerHello(BlockException e) {
return "限流了";
}
}
d、实现InitFunc接口,并在init方法中编写规则
public class FlowRuleInitFunc implements InitFunc {
@Override
public void init() throws Exception {
List rules = new ArrayList<>();
FlowRule rule = new FlowRule();
rule.setCount(1);
rule.setResource("hello");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setLimitApp("default");
rules.add(rule);
FlowRuleManager.loadRules(rules);
}
}
e、在resource目录下创建META-INF/services/com.alibaba.csp.sentinel.init.InitFunc文件,文件内容就是自定义扩展点的全路径
com.sentinel.springcloud.demo.FlowRuleInitFunc
f、启动服务后,访问http://localhost:8080/hello方法,当访问频率超过设定阈值的时候,就会触发限流。
a、启动Sentinel Dashboard
b、在application.yaml中增加如下配置:
spring.cloud.sentinel.transport.dashboard指向的是Sentinel Dashboard的服务器地址
spring:
application:
name: sentinel-spring-cloud-demo
cloud:
sentinel:
transport:
dashboard: localhost:7777
e、提供一个REST接口
@RestController
public class SentinelDashboardController {
@GetMapping("/dash")
public String dashboard() {
return "Hello Sentinel Dashboard";
}
}
f、启动服务后,此时访问http://localhost:8080/dash,不存在任何限流行为。
g、至此,Spring Cloud集成Sentinel的配置就完成了,接下来就可以进入Sentinel Dashboard去实现限流规则的配置。
h、针对/dash这个资源,点击最右边的操作栏中的“流控”按钮设置流控规则,如下图所示:
i、新增完成后,再次访问localhost:8080/dash,当超过设置的阈值的时候,就可以看到限流的效果,并获得如下输出:
自定义URL限流异常
a、在默认情况下,URL触发限流后会直接返回Blocked by Sentinel (flow limiting)
b、在实际应用中,大都采用JSON格式的数据,可以通过自定义限流异常来处理,实现UrlBlockHandler并重写blocked方法:
@Service
public class CustomUrlBlockHandler implements UrlBlockHandler {
@Override
public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws IOException {
httpServletResponse.setHeader("Content-Type", "application/json;charset=UTF-8");
String message = "{\"code\":999,\"msg\":\"访问人数过多\"}";
httpServletResponse.getWriter().write(message);
}
}
c、当触发限流之后,我们希望直接跳转到一个降级页面,可以通过下面这个配置来实现:
spring.cloud.sentinel.servlet.block-page={url}
URL资源清洗
a、把每个不同的URL统一归类,通过UrlCleaner接口来实现资源清洗
b、例如对/clean/{id}这个URL,我们可以统一归集到/clean/*资源下
@Service
public class CustomUrlCleaner implements UrlCleaner {
@Override
public String clean(String s) {
if (StringUtils.isEmpty(s)) {
return s;
}
if (s.startsWith("/clean/")) {
return "/clean/*";
}
return s;
}
}
a、Sentinel的理念是只需要开发者设置流控规则,它默认会对资源进行流控
b、Sentinel Dashboard所配置的流控规则,都是保存在内存中的,一旦应用重启,这些规则都会被清除,并没有实现动态维护。
c、Sentinel支持Consul、Zookeeper、Redis、Nacos、Apollo、etcd等数据源的扩展
a、添加Nacos数据源的依赖包
com.alibaba.csp
sentinel-datasource-nacos
1.7.0
b、创建一个REST接口,用于测试
@RestController
public class DynamicController {
@GetMapping("/dynamic")
public String dynamic() {
return "Hello Dynamic Rules";
}
}
c、在application.yml文件中添加数据源配置
spring:
application:
name: sentinel-spring-cloud-demo
cloud:
sentinel:
transport:
dashboard: 192.168.56.1:7777
datasource:
- nacos:
server-addr: 192.168.56.1:8848
data-id: ${spring.application.name}-sentinel
group-id: DEFAULT_GROUP
data-type: json
rule-type: flow
d、登陆Nacos控制台,创建流控配置规则:
e、登陆Sentinel Dashboard,找到执行项目名称菜单下的“流控规则”,就可以看到在Nacos上所配置的流控规则已经被加载了。
注意:
如果在Sentinel Dashboard上修改流控规则,无法同步到Nacos上
a、源码改动忽略,只看应用程序的改动
b、data-id的命名要以-sentinel-flow结尾即可(看源码具体实现用的什么后缀)
c、这样就解决了以上不同步的问题
spring:
application:
name: spring-cloud-sentinel-dynamic
cloud:
sentinel:
transport:
dashboard: 192.168.56.1:7777
datasource:
- nacos:
server-addr: 192.168.56.1:8848
data-id: ${spring.application.name}-sentinel-flow
group-id: DEFAULT_GROUP
data-type: json
rule-type: flow
a、Sentinel提供了与Dubbo整合的模块Sentinel Apache Dubbo Adapter
com.alibaba.csp
sentinel-apache-dubbo-adapter
1.7.1
b、关闭消费端的过滤器。
@Bean
public ConsumerConfig consumerConfig() {
ConsumerConfig consumerConfig = new ConsumerConfig();
consumerConfig.setFilter("-sentinel.dubbo.filter");
return consumerConfig;
}
a、spring-cloud-starter-alibaba-sentinel目前无法支持Dubbo服务的限流,
b、所以针对Dubbo服务的限流只能使用sentinel-apache-dubbo-adapter。
c、这个适配组件并没有自动接入sentinel dashboard,要引入sentinel-transport-simple-http依赖
com.alibaba.csp
sentinel-transport-simple-http
1.7.1
a、添加启动参数
-Djava.net.perferIPv4Stack=true -Dcsp.sentinel.api.port=8720 -Dcsp.sentinel.dashboard.server=localhost:7777 -Dproject.name=spring-cloud-sentinel-dubbo-provider
b、登陆Sentinel Dashboard之后,进入"簇点链路",就可以看到资源信息
a、添加sentinel-datasource-nacos的依赖
com.alibaba.csp
sentinel-datasource-nacos
1.7.1
b、通过Sentinel提供的InitFunc扩展点,实现Nacos数据源的配置
public class NacosDataSourceInitFunc implements InitFunc{
private String serverAddr="localhost:8848";
private String groupId="DEFAULT_GROUP";
private String dataId="spring-cloud.sentinel-dubbo.provider-sentinel-flow";
@Override
public void init() throws Exception {
loadNacosData();
}
private void loadNacosData(){
ReadableDataSource> flowRuleDataSource=
new NacosDataSource<>(serverAddr, groupId, dataId, source -> JSON.parseObject(source, new TypeReference>() {
}));
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
}
}
c、需要在resource目录下的META-INF/services中创建一个名称为com.alibaba.csp.sentinel.init.InitFunc的文件,内容为路径
d、访问Sentinel Dashboard,在针对资源创建流控规则的时候,这个规则会同步保存到Nacos配置中心。
e、而当Nacos配置中心发生变化的时候,也会触发事件机制通知Dubbo应用重新加载流控规则。
提供了AT、TCC、Sata、XA事务模式,AT模式是Seata主推的分布式事务解决方案
AT模式
维护全局事务和分支事务的状态
定义全局事务的范围:开始全局事务,提交或回滚全局事务。
管理正在处理的分支事务的资源,与TC对话以注册分支事务并报告分支事务的状态
a、TM(协调)——>要求TC(全局)开始一项新的全局事务,生成全局事务的XID。
b、RM(局部)本地事务——>在TC(全局)注册为全局事务XID的分支
c、TM(协调)——>要求TC(全局)提交XID相应全局事务下的所有分支
a、registry配置注册中心动态维护
b、file用数据库维护全局事务会话信息
file.conf
修改registry.conf文件
在类或者方法上@GlobalTransactional
@GlobalTransactional
public void purchase(String userId, String commodityCode, int orderCount) {
}
XID 的传递
全局事务ID的跨服务传递,需要我们自己实现,这里通过拦截器的方式。每个服务都需要添加下面两个类。
@Component
public class SeataFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
String xid = req.getHeader(RootContext.KEY_XID.toLowerCase());
boolean isBind = false;
if (StringUtils.isNotBlank(xid)) {
RootContext.bind(xid);
isBind = true;
}
try {
filterChain.doFilter(servletRequest, servletResponse);
} finally {
if (isBind) {
RootContext.unbind();
}
}
}
@Override
public void destroy() {
}
}
@Configuration
public class SeataRestTemplateAutoConfiguration {
@Autowired(
required = false
)
private Collection restTemplates;
@Autowired
private SeataRestTemplateInterceptor seataRestTemplateInterceptor;
public SeataRestTemplateAutoConfiguration() {
}
@Bean
public SeataRestTemplateInterceptor seataRestTemplateInterceptor() {
return new SeataRestTemplateInterceptor();
}
@PostConstruct
public void init() {
if (this.restTemplates != null) {
Iterator var1 = this.restTemplates.iterator();
while (var1.hasNext()) {
RestTemplate restTemplate = (RestTemplate) var1.next();
List interceptors = new ArrayList(restTemplate.getInterceptors());
interceptors.add(this.seataRestTemplateInterceptor);
restTemplate.setInterceptors(interceptors);
}
}
}
}
a、整合多个服务完成数据的获取
b、适配不同的协议
c、请求转发实现内外网隔离
d、统一错误码处理
e、在网关层统一进行权限控制
f、灰度发布
Route(路由):
这是网关的基本构建块。它由一个 ID,一个目标 URI,一组断言和一组过滤器定义。如果断言为真,则路由匹配。
Predicate(断言):
这是一个 Java 8 的 Predicate。输入类型是一个 ServerWebExchange。我们可以使用它来匹配来自 HTTP 请求的任何内容
Filter(过滤器):
这是org.springframework.cloud.gateway.filter.GatewayFilter的实例,我们可以使用它修改请求和响应。
a、客户端向 Spring Cloud Gateway 发出请求。
b、匹配路由
c、过滤器将请求发送到我们实际的服务执行业务逻辑
配置文件
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: gateway-service
uri: https://blog.csdn.net
predicates:
- Path=/meteor_93
a、Predicate 来源于 Java 8,是 Java 8 中引入的一个函数,Predicate 接受一个输入参数,返回一个布尔值结果
b、Predicate 就是为了实现一组匹配规则,方便让请求过来找到对应的 Route 进行处理
表示在这个时间段可以进行路由,否则访问地址http://localhost:8080,页面会报 404 没有找到地址。
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: gateway-service
uri: https://www.baidu.com
order: 0
predicates:
- Between=2019-01-01T00:00:00+08:00[Asia/Shanghai], 2019-07-01T00:00:00+08:00[Asia/Shanghai]
可以通过是 POST、GET、PUT、DELETE 等不同的请求方式来进行路由。
Path Route Predicate 接收一个匹配路径的参数来判断是否走路由