SpringCloud微服务

微服务架构演变过程

微服务架构如何演变的?

传统架构—》分布式架构—》SOA面向服务架构—》微服务架构

从传统到微服务架构过程

传统架构
也就是为单点应用,也就是大家在早期所学习的JavaEE知识SSH或者SSM架构模式,会采用分层架构模式:数据库访问层、业务逻辑层、控制层,从前端到后台所有的代码都是一个开发者去完成。

  • 优点:开发简单、运维简单。
  • 缺点:该架构模式没有对我们业务逻辑实现拆分,所有的代码都要写入到同一个项目中,只适合小公司开发团队或者个人开发。不适合团队模式协作开发。如果该系统一个模块出现不可用、会导致整个系统无法使用。

分布式架构
分布式架构模式是基于传统的架构模式演变过来,将传统的单点项目根据业务模块实现拆分、会拆分为会员系统、订单系统、支付系统、秒杀系统等。 从而降低我们项目的耦合度,这种架构模式开始慢慢的适合于互联网公司开发团队。

SOA面向服务架构
SOA架构模式也称作为:面向服务架构模式、俗称面向与接口开发,将共同存在的业务逻辑抽取成一个共同的服务,提供给其他的服务接口实现调用、服务与服务之间通讯采用rpc远程调用技术。
特点:

  • SOA架构通讯中,采用XML方式实现通讯、在高并发下通讯过程中协议存在非常大冗余性,所以在最后微服务架构模式中使用JSON格式替代了XML。
  • SOA架构模式实现方案为WebService或者是ESB企业服务总线 底层通讯协议SOAP协议(Http+XML)实现传输。

缺点:

  1. 采用SOAP协议实现通讯,xml传输非常重,效率比较低。
  2. 服务化管理和治理不够完善。
  3. 依赖与中心服务发现机制。
  4. 不适合于前后端分离的架构模式。
    SpringCloud微服务_第1张图片

ESB企业服务总线:解决多系统之间跨语言通讯,数据协议的转换,提供可靠消息传输。

微服务架构
微服务架构模式是从SOA架构模式演变过来, 比SOA架构模式粒度更加精细,让专业的人去做专业的事情(专注),目的是提高效率,每个服务与服务之间互不影响,微服务架构中每个服务必须独立部署、互不影响,微服务架构模式体现轻巧、轻量级、适合于互联网公司开发模式。

微服务架构倡导应用程序设计程多个独立、可配置、可运行和可微服务的子服务。
服务与服务通讯协议采用Http协议,使用restful风格API形式来进行通讯,数据交换格式轻量级json 格式通讯,整个传输过程中,采用二进制,所以http协议可以跨语言平台,并且可以和其他不同的语言 进行相互的通讯,所以很多开放平台都采用http协议接口。

产生的原因:因为SOA架构(webService)有如下问题

  1. 依赖中心化服务发现机制
  2. 使用Soap通讯协议,通常使用XML格式来序列化通讯数据,xml格式非常喜欢重,比较占宽带传输。
  3. 服务化管理和治理设施不完善
  4. 不适合前后端分离
    SpringCloud微服务_第2张图片

微服务架构与SOA架构的区别?

  1. 微服务架构基于 SOA架构演变过来,继承 SOA架构的优点,在微服务架构中去除 SOA 架构中的 ESB 企业服务总线,采用 http+json(restful)进行传输。
  2. 微服务架构比 SOA 架构粒度会更加精细,让专业的人去做专业的事情(专注),目的提高效率,每个服务于服务之间互不影响,微服务架构中,每个服务必须独立部署,微服务架构更加轻巧,轻量级。
  3. SOA 架构中可能数据库存储会发生共享,微服务强调独每个服务都是单独数据库,保证每个服务于服务之间互不影响。
  4. 项目体现特征微服务架构比 SOA 架构更加适合与互联网公司敏捷开发、快速迭代版本,因为粒度非常精细。

微服务架构架构模式的优缺点?

优点:

  1. 每个微服务都很小,这样能聚焦一个指定的业务功能或业务需求。
  2. 微服务能够被小团队单独开发,这个小团队是2到5人的开发人员组成。
  3. 微服务是松耦合的,是有功能意义的服务,无论是在开发阶段或部署阶段都是独立的。
  4. 微服务能使用不同的语言开发。
  5. 微服务易于被一个开发人员理解,修改和维护,这样小团队能够更关注自己的工作成果。无需通过合作才能体现价值。
  6. 微服务允许你利用融合最新技术。
  7. 微服务只是业务逻辑的代码,不会和HTML,CSS 或其他界面组件混合。

缺点:

  1. 微服务架构可能带来过多的操作。
  2. 需要DevOps技巧 (http://en.wikipedia.org/wiki/DevOps)。
  3. 可能双倍的努力。
  4. 分布式系统可能复杂难以管理。
  5. 因为分布部署跟踪问题难。
  6. 当服务数量增加,管理复杂性增加。

SpringCloud第一代与二代的区别?

SpringCloud第一代:
SpringCloud Config 分布式配置中心
SpringCloud Netflix 核心组件
Eureka:服务治理
Hystrix:服务保护框架
Ribbon:客户端负载均衡器
Feign:基于ribbon和hystrix的声明式服务调用组件(rpc远程服务调用)
Zuul: 网关组件,提供智能路由、访问过滤等功能。

SpringCloud第二代(自己研发)和优秀的组件组合:
Spring Cloud Gateway 网关
Spring Cloud Loadbalancer 客户端负载均衡器
Spring Cloud r4j(Resilience4J) 服务保护
Spring Cloud Alibaba Nacos 服务注册
Spring Cloud Alibaba Nacos 分布式配置中心
Spring Cloud Alibaba Sentinel服务保护
SpringCloud Alibaba Seata分布式事务解决框架
Alibaba Cloud OSS 阿里云存储
Alibaba Cloud SchedulerX 分布式任务调度平台
Alibaba Cloud SMS 分布式短信系统

SpringCloud微服务_第3张图片

Nacos实现服务注册与发现

微服务架构中服务治理核心概念

在RPC远程调用过程中,服务与服务之间依赖关系非常大,服务Url地址管理非常复杂,所以这时候需要对我们服务的url实现治理,通过服务治理可以实现服务注册与发现、负载均衡、容错等。

分布式注册中心设计原理

每次调用该服务如果地址直接写死的话,一旦接口发生变化的情况下,这时候需要重新发布版本才可以该接口调用地址,所以需要一个注册中心统一管理我们的服务注册与发现。

  • 注册中心:我们的服务注册到我们注册中心,key为服务名称、value为该服务调用地址,该类型为集合类型。Eureka、consul、zookeeper、nacos等。
  • 服务注册:我们生产者项目启动的时候,会将当前服务自己的信息地址注册到注册中心。
  • 服务发现: 消费者从我们的注册中心上获取生产者调用的地址(集合),在使用负载均衡的策略获取集群中某个地址实现本地rpc远程调用。

Nacos与Eureka、Zookeeper的区别?

相同点: 都可以实现分布式注册中心框架

不同点:

  • Zookeeper采用CP保证数据的一致性的问题,原理采用(ZAP原子广播协议),当我们ZK领导者因为某种情况下部分节点出现了故障,会自动重新实现选举新的领导角色,整个选举的过程中为了保证数据一致性的问题,客户端暂时无法使用我们的Zookeeper,那么这会以为整个微服务无法实现通讯。最大缺点:剩余节点数没有满足过半原则的话,整个集群不可用。

  • Eureka采用AP设计思想实现分布式注册中心,完全去中心化、每个节点都是相等,采用你中有我、我中有你相互注册设计思想, 只要最后有一台Eureka节点存在整个微服务就可以实现通讯。

  • Nacos从1.0版本选择Ap和CP混合形式实现注册中心,默认情况下采用Ap,CP则采用Raft协议实现保持数据的一致性。 如果选择为Ap模式,注册服务的实例仅支持临时模式,在网络分区的的情况允许注册服务实例,选择CP模式可以支持注册服务的实例为持久模式,在网络分区的产生了抖动情况下不允许注册服务实例。

discoveryClient的作用有哪些?

能够让注册中心能够发现,扫描到该服务。DiscoveryClient 通过@EnableDiscoveryClient的方式进行启用。
根据服务名获取到该服务的所有url。

本地负载均衡的实现原理

消费者从我们的注册中心获取到集群地址列表,缓存到本地,然后本地采用负载均衡策略(轮训、随机、权重、hash一致性等),获取接口列表地址,采用算法获取选择一个接口地址实现本地的rpc远程的。

本地负载均衡器Ribbon与接口调用工具

本地负载均衡与Nginx 的区别

应用场景:Nginx属于服务器负载均衡,应用于Tomcat/Jetty服务器等,而我们的本地负载均衡器,属于客户端负载均衡,应用于在微服务架构中rpc框架中,rest、openfeign、dubbo。

  • 本地负载均衡器:我们的消费者服务从我们的注册中心获取到集群地址列表,缓存到本地,让后本地采用负载均衡策略(轮训、随机、权重、hash一致性等),获取接口列表地址,采用算法获取选择一个接口地址实现本地的rpc远程的。
    在SpringCloud第一代中使用Ribbon、SpringCloud第二代中直接采用自研发loadbalancer即可,默认使用的Ribbon。底层默认原理是调用ribbon的实现客户端负载均衡器。
  • Nginx:是客户端所有的请求统一都交给我们的Nginx处理,让后在由Nginx实现负载均衡转发,属于服务器端负载均衡器。

Ribbon实现负载均衡的原理

ribbon实现的关键点是为ribbon定制的RestTemplate,ribbon利用 了RestTemplate的拦截器机制,在拦截器中实现ribbon的负载均衡。负载均衡的基本实现就是利用applicationName从服务注册中心获取可用的服务地址列表,然后通过一定算法负载,决定使用哪一个服务地址来进行http调用。

LoadBalancedClient的作用

通过服务名进行服务的查找。获取这个服务名所有的服务接口路径。

openfeign客户端与feign客户端区别

两者都是是一个Web声明式的Http客户端调用工具,提供接口和注解形式调用。
SpringCloud微服务_第4张图片

Feign
Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。feign的使用方式是:使用Feign注解定义一个接口,调用这个接口,就可以调用服务注册中心的服务。

SpringCloud微服务_第5张图片

OpenFeign
OpenFeign是springcloud在feign的基础上支持了springmvc注解,如@RequestMapping等等(推荐使用@postMapping和@getMapping注解)。openFeign的@FeignClient注解可以解析springmvc的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。
SpringCloud微服务_第6张图片
代码中:注解@FeignClient 的name属性值为服务方的名称,也就是application service全局配置文件中的spring.application.name属性值。

使用openfeign为何要继承接口

Feign客户端实际上就是一个接口,但是这个接口继承了服务提供者的接口,通过@FeignClient注解声明需要调用的服务别名,由于是继承了提供者的接口,这里就不需要将getMember重新定义,减少了重复代码。

RestTemplate 的使用方式?

在 springcloud 中我们如果想要使用客户端负载均衡,方法很简单,开启@LoadBalanced注解即可,现在使用springcloud-order服务调用springcloud-emp服务,再 order 启动类里面注入 RestTemplate,并添加@LoadBalanced注解。
SpringCloud微服务_第7张图片

使用 RestTemplate 调用服务接口
SpringCloud微服务_第8张图片

Ribbon+RestTemplate和Feign的区别

  1. 实际开发中,对服务依赖的调用可能不止一处,往往一个接口会被多处调用,如果使用Ribbon+RestTemplate,就需要在每一个模块都要创建一个配置类,而且,各社区中javaweb也倾向于面向接口编程
  2. 通常针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用,所以,Feign在此基础上做了进一步封装,在Feign的实现下,我们只需要创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可),完成对服务提供方的接口绑定
  3. 使用Feign是通过接口的方法调用Rest服务,该请求发送给Eureka服务器,通过Feign直接找到服务接口。Feign融合了Ribbon技术(可以在yml中配置负载均衡的策略),所以也支持负载均衡。

配置调用接口的超时时间、重试次数?

一般情况下 都是 ribbon 的超时时间(<)hystrix的超时时间(因为涉及到ribbon的重试机制)
超时时间:谁设置的时间短以谁的为准。
SpringCloud微服务_第9张图片

配置重试次数:
因为ribbon的重试机制和Feign的重试机制有冲突,所以源码中默认关闭Feign的重试机制
如果在重试期间,时间超过了hystrix的超时时间,便会立即执行熔断,fallback。所以hystrix的超时时间应该根据重试次数进行配置(也不是绝对的,根据情况具体配置)。
当ribbon超时后且hystrix没有超时,便会采取重试机制。
如果不配置ribbon的重试次数,默认会重试一次 。
SpringCloud微服务_第10张图片

调用接口的负载均衡配置?

在RestTemplate上面加入@LoadBalanced注解,这样子就已经有了负载均衡

@Bean
@LoadBalanced
public RestTemplate restTemplate(){
  RestTemplate restTemplate = new RestTemplate();
  return restTemplate;
}

总共提供了其中负载均衡的方式,见下图:
也可以自定义负载均衡的方式,主要继承AbstractLoadBalancerRule 类,然后把自己写的Rule交给Spring就好了。
SpringCloud微服务_第11张图片


SpringCloud微服务_第12张图片

在项目中的使用方式是?

第一种 RestTemplate使用方式配置(全局范围的负载均衡策略
1、在注入RestTemplate上增加注解启用负载均衡

// 在RestTemplate上增加注解启用负载均衡
@LoadBalanced
@Bean
public RestTemplate restTemplate(){...}

2、以负载均衡方式调用服务

// 使用服务ID调用服务
restTemplate.getForObject("http://serviceId/api");

3.1、Java配置负载均衡规则(全局配置)

@Bean
public IRule myIRule(){
    return  new RandomRule();
}

SpringCloud微服务_第13张图片
3.2、配置文件中,指定某个服务的负载均衡策略

#不同于RibbonConfiguration进行的全局负载均衡策略
#这里的是针对某一个服务进行负载均衡配置。
#eureka-client 为指定的服务名称
eureka-client:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

3.3、配置类注解的方式指定服务的负载均衡策略

@Configuration
//对某个服务指定负载均衡策略时,可使用这个注解,并指定服务名称和负载均衡策略
@RibbonClient(name = "eureka-client", configuration = com.netflix.loadbalancer.RandomRule.class)
public class RibbonConfiguration {

    //fixme 两种指定服务负载均衡的配置方式哪种优先级更高
    //@RibbonClient的优先级高于在配置文件中配置


}

第二种 RestTemplate使用方式配置
OpenFeign集成了Ribbon,利用Ribbon维护了服务方列表消息,并且通过轮询的方式 实现了客户端的负载。而与Ribbon不同的是,通过Feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务的调用;

1、编写主启动类,加上 @EnableFeignClients注解,表明开启Feign注解

2、业务逻辑接口,注意这里的接口中定义的方法需要和服务提供类中的方法一致;

@Component
@FeignClient("CLOUD-PAYMENT-SERVICE")//集成了Ribbon,默认轮询方式
public interface PaymentFeignService {

    @GetMapping(value = "/payment/get/{id}")
    public CommonResult<Payment> getPaymetById(@PathVariable Long id);

    }

3、接口调用超时配置

#设置feign客户算超时时间(opneFeign默认支持ribbon)
ribbon:
#指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
ReadTimeout: 5000
#  指的是建立连接后从服务器读取到可用资源所用的时间
  ConnectTimeiout: 5000

4、负载均衡策略的配置和RestTemplate配置方式一样

总结: 如果需要根据每个服务的每个接口配置负载均衡策略的话,自定义负载均衡策略,具体接口具体配置。

配置中心

分布式配置中心产生的背景

分布式与微服务的应用深入,配置项的繁琐引出分布式配置中心技术。分布式配置中心可以实现不需要重启我们的服务器,动态的修改我们的配置文件内容,常见的配置中心有携程的阿波罗(属于比较重的分布式配置)、SpringCloud Config、Nacos轻量级的配置中心、disconfig等。

分布式配置中心架构设计的原理

  1. 本地应用读取我们云端分布式配置中心文件(第一次建立长连接)
  2. 本地应用读取到配置文件之后,本地jvm和硬盘中都会缓存一份
  3. 本地应用与分布式配置中心服务端一直保持长连接
  4. 当我们的配置文件发生变化(MD5|版本号)实现区分,将变化结果通知给我们的本地应用及时的刷新我们的配置文件。
    完全百分之百动态化修改我们的配置文件。

如何判断配置文件是否发生改变:采用版本、MD5

Apollo是什么?

Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景。

Nacos如何实现服务器集群

首先需要Java程序运行环境(也就是安装jdk1.8+),在nacos安装目录下的conf目录下创建cluster.conf文件。文件的配置文件如下:
192.168.xx.xx:8848
192.168.xx.xx:8848
192.168.xx.xx:8848
持久化配置,配置mysql数据库的信息,每一台服务器都要配置。

启动:首先进入到nacos安装的bin目录下
Windows系统:默认是单机版启动,所以需要执行集群启动命令:startup.cmd -m cluster
Linux系统:默认是集群版启动,直接执行命令:sh startup.sh

注册中心设计Ap与CP区别

这个定理的内容是指的是在一个分布式系统中、Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。
一致性©:在分布式系统中,如果服务器集群,每个节点在同时刻访问必须要保持数据的一致性。
可用性(A):集群节点中,部分节点出现故障后任然可以使用 (高可用)
分区容错性§:在分布式系统中网络会存在脑裂的问题,部分Server与整个集群失去节点联系,无法组成一个群体。
CP:保证注册中心中数据一致性
AP:保证注册中心的可用性,只要有一个节点可以使用整个集群节点既可以使用。
只有在CP和AP选择一个平衡点

Eureka与Zookeeper的区别

Zookeeper:Zookeeper采用CP保证数据的一致性的问题, 原理采用(ZAP原子广播协议),当我们ZK领导者因为某种情况下部分节点出现了故障,会自动重新实现选举新的领导角色,整个选举的过程中为了保证数据一致性的问题,客户端暂时无法使用我们的Zookeeper,那么这意味着整个微服务无法实现通讯(本地有缓存除外)。
注意:可运行的节点必须满足过半机制,整个zk采用使用,自己选举 leader 和 处理follower

Eureka:基于AP模式实现注册中心,去中心化的思想、每个节点都是对等的,采用你中有我,我中有你的形式实现注册中心。

Nacos与Eureka的区别?

Eureka:采用AP设计思想实现分布式注册中心, 完全去中心化、每个节点都是相等, 采用你中有我、 我中有你相互注册设计思想,只要最后有一台Eureka节点存在整个微服务就可以实现通讯。

Nacos:默认采用AP模式,在1.0 版本之后采用 AP+CP 模式混合实现注册中心。CP则采用Raft协议实 现保持数据的一致性。如果选择为AP模式,注册服务的实例仅支持临时模式,在网络分区的的情况允 许注册服务实例,选择CP模式可以支持注册服务的实例为持久模式,在网络分区的产生了抖动情 下不允许注册服务实例。

分布式一致性算法有哪些?

  1. ZAP协议(底层就是基于Paxos实现),核心底层基于2PC两阶段提交协议实现。
  2. Nacos中集群保证一致性算法采ratf协议模式,采用心跳机制实现选举的。

Nacos集群模式底层原理

Nacos集群采用 raft 算法来实现,它是相对zookeeper的选举算法较为简单的一种。选举算法的核心在 RaftCore 中,包括数据的处理和数据同步。

raft协议底层实现原理

Raft协议中有三种状态:跟随者、竞选者、领导者。
默认情况下选举的过程:

  • 默认的情况下每个节点都是为跟随者角色
  • 每个节点随机生成一个选举的超时时间 大概分为100-300ms,在这个超时时间内必须要等待。
  • 超时时间过后,当前节点的状态由跟随者变为竞选者角色,会给其他的节点发出选举的投票的通知,只要该竞选者有超过半数以上即可选为领导角色。核心的设计原理其实就是靠的谁超时时间最短谁就有非常大的概率为领导角色。

故障的重新实现选举:
如果我们跟随者节点不能够及时的收到领导角色消息,那么这时候跟随者就会将当前自己的状态由跟随者变为竞选者角色,会给其他的节点发出选举的投票的通知,只要该竞选者有超过半数以上即可选为领导角色。

是否可能会产生两个同时的竞选者呢,同时实现拉票呢?
注意当我们的集群节点总数,如果是奇数情况下 就算遇到了该问题也不用担心。
当我们的节点是为偶数的情况下,可能会存在该问题,如果两个竞选者获取的票数相等的情况下,开始重置竞选的超时时间,一直到谁的票数最多谁就为领导。

新一代服务网关Gateway

为什么要使用服务网关

微服务网关是整个微服务API请求的入口,可以实现日志拦截、权限控制、解决跨域问题、限流、熔断、负载均衡、黑名单与白名单拦截、授权等。

过滤器与微服务网关的区别

过滤器用于拦截单个服务,网关拦截整个的微服务。

Zuul网关与Gateway之间的区别

Zuul网关属于netfix公司开源的产品属于第一代微服务网关
Gateway属于SpringCloud自研发的第二代微服务网关

相比来说SpringCloudGateway性能比Zuul性能要好:
注意:Zuul基于Servlet实现的,阻塞式的Api, 不支持长连接。
SpringCloudGateway基于Spring5构建,能够实现响应式非阻塞式的Api,支持长连接,能够更好的整合Spring体系的产品。

Nginx与网关存在哪些区别

相同点: 都是可以实现对api接口的拦截,负载均衡、反向代理、请求过滤等,可以实现和网关一样的效果。
不同点:
Nginx采用C语言编写的
微服务都是自己语言编写的,比如Gateway就是java写的。

毕竟Gateway属于Java语言编写的,能够更好对微服务实现扩展功能,相比Nginx如果想实现扩展功能需要结合Nginx+Lua语言等。

Nginx实现负载均衡的原理:属于服务器端负载均衡器。
Gateway实现负载均衡原理:采用本地负载均衡器的形式。

如何保证微服务接口的安全?

接口分为内网和外网接口

外网接口:基于OATUH2.0构建开放平台 比如appid、appsocet获取accesstoken调用接口。
内网接口:都是当前内网中实现通讯,相对于来说比较安全的。

  • 需要保证接口幂等性问题(基于Token)
  • 接口采用安全加密传输 https协议
  • 防止数据被篡改 md5验证签名
  • 使用微服务网关实现Api授权认证等、黑名单白名单。
  • 对我们的接口实现服务的保护 隔离、熔断、降级等等。

最后使用apiswagger管理我们的微服务接口。

网关部署实现集群设计思路

使用Nginx或者lvs虚拟vip访问增加系统的高可用,利用nginx做网关的负载均衡。
SpringCloud微服务_第14张图片

如何实现GateWay动态网关

方案:

  1. 基于数据库形式实现
  2. 基于配置中心实现

注意:配置中心实现维护性比较差,建议采用数据库形式设计。

GateWay词汇表格有哪些?

  • 路由:是网关基本的模块,分别为id、目标uri、一组谓词+过滤器一起组合而成,如果谓词匹配成功, 则路由匹配成功。
  • 谓词: 匹配Http请求参数。
  • 过滤器:对下游的服务器之前和之后实现处理。

GateWay网关谓词用法

答:
1.匹配时间之后

- id: mayikt
  uri: http://www.mayikt.com/
  ###匹配规则
  predicates:
    - After=2017-01-20T17:42:47.789-07:00[America/Denver]

此路由与 2017 年 1 月 20 日 17:42 MountainTime(Denver)之后的所有请求相匹配。

2.匹配对应的host

- id: meite
  uri: http://www.mayikt.com/
  ###匹配规则
  predicates:
    - Host=meite.mayikt.com

访问 mete.mayikt.com 转发到http://www.mayikt.com/

3.权重谓词

- id: weight_high
  uri: http://www.mayikt.com/yushengjun
  predicates:
    - Weight=group1, 2
- id: weight_low
  uri: http://www.mayikt.com
  predicates:
    - Weight=group1, 1

根据权重比例实现转发

- id: weight_order
  uri: lb://meitemayikt-order
  predicates:
    - Weight=group1,2
- id: weight_member
  uri: lb://mayikt-member
  predicates:
    - Weight=group1,1

详细参考:
https://cloud.spring.io/spring-cloud-gateway/reference/html/#gatewayfilter-factories

GateWay如何解决网关跨域的问题?

微服务中跨域的问题 不属于前端解决 jsonp 只能支持get请求。

解决跨域的核心点就是在我们后端。
解决跨域的问题

  • HttpClient转发
  • 使用过滤器允许接口可以跨域 响应头设置
  • Jsonp 不支持我们的post 属于前端解决
  • Nginx解决跨域的问题保持我们域名和端口一致性
  • Nginx也是通过配置文件解决跨域的问题
  • 基于微服务网关解决跨域问题,需要保持域名和端口一致性
  • 使用网关代码允许所有的服务可以跨域的问题
  • 使用SpringBoot注解形式@CrossOrigin

服务保护框架

服务保护、服务限流、服务降级的概念

服务限流/熔断
服务限流目的是为了更好的保护我们的服务,在高并发的情况下,如果客户端请求的数量达到一定极限(后台可以配置阈值),请求的数量超出了设置的阈值,开启自我的保护,直接调用我们的服务降级的方法,不会执行业务逻辑操作,直接走本地falback的方法,返回一个友好的提示。

服务降级
在高并发的情况下, 防止用户一直等待,采用限流/熔断方法,使用服务降级的方式返回一个友好的提示给客户端,不会执行业务逻辑请求,直接走本地的falback的方法。
提示语:当前排队人数过多,稍后重试~

服务雪崩效应产生的背景

默认的情况下,Tomcat或者是Jetty服务器只有一个线程池去处理客户端的请求,这样的话就是在高并发的情况下,如果客户端所有的请求都堆积到同一个服务接口上,那么就会产生tomcat服务器所有的线程都在处理该接口,可能会导致其他的接口无法访问。
假设我们的tomcat线程最大的线程数量是为20,这时候客户端如果同时发送100个请求会导致有80个请求暂时无法访问,就会转圈。

服务隔离机制信号量与线程池隔离

服务的隔离机制分为信号量和线程池隔离模式
服务的线程池隔离机制:每个服务接口都有自己独立的线程池,互不影响,缺点就是占用cpu资源非常大。
服务的信号量隔离机制:最多只有一定的阈值线程数处理我们的请求,超过该阈值会拒绝请求。

sentinel与hystrix的区别

前哨以流量为切入点,从流量控制,熔断降级,系统负载保护等多个维度保护服务的稳定性。

前哨具有以下特征:

  1. 丰富的应用场景:前哨兵承接了阿里巴巴近10年的双十一大促流的核心场景,例如秒杀(即突然流量控制在系统容量可以承受的范围),消息削峰填谷,传递流量控制,实时熔断下游不可用应用等。
  2. 完备的实时监控:Sentinel同时提供实时的监控功能。您可以在控制台中看到接收应用的单台机器秒级数据,甚至500台以下规模的整合的汇总运行情况。
    广泛的开源生态:Sentinel提供开箱即用的与其他开源框架/库的集成模块,例如与Spring Cloud,Dubbo,gRPC的整合。您只需要另外的依赖并进行简单的配置即可快速地接入Sentinel。
  3. 完善的SPI扩展点:Sentinel提供简单易用,完善的SPI扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理,适应动态数据源等。
    SpringCloud微服务_第15张图片

sentinel如何实现对服务限流

手动配置管理Api限流接口

private static final String GETORDER_KEY = "getOrder";

@RequestMapping("/initFlowQpsRule")
public String initFlowQpsRule() {
    List<FlowRule> rules = new ArrayList<FlowRule>();
    FlowRule rule1 = new FlowRule();
    rule1.setResource(GETORDER_KEY);
    // QPS控制在2以内
    rule1.setCount(1);
    // QPS限流
    rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
    rule1.setLimitApp("default");
    rules.add(rule1);
    FlowRuleManager.loadRules(rules);
    return "....限流配置初始化成功..";
}


@RequestMapping("/getOrder")
public String getOrders() {
    Entry entry = null;
    try {
        entry = SphU.entry(GETORDER_KEY);
        // 执行我们服务需要保护的业务逻辑
        return "getOrder接口";
    } catch (Exception e) {
        e.printStackTrace();
        return "该服务接口已经达到上线!";
    } finally {
        // SphU.entry(xxx) 需要与 entry.exit() 成对出现,否则会导致调用链记录异常
        if (entry != null) {
            entry.exit();
        }
    }

}

手动放入到项目启动自动加载

@Component
@Slf4j
public class SentinelApplicationRunner implements ApplicationRunner {
    private static final String GETORDER_KEY = "getOrder";

    @Override
    public void run(ApplicationArguments args) throws Exception {
        List<FlowRule> rules = new ArrayList<FlowRule>();
        FlowRule rule1 = new FlowRule();
        rule1.setResource(GETORDER_KEY);
        // QPS控制在2以内
        rule1.setCount(1);
        // QPS限流
        rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule1.setLimitApp("default");
        rules.add(rule1);
        FlowRuleManager.loadRules(rules);
        log.info(">>>限流服务接口配置加载成功>>>");
    }
}

注解形式配置管理Api限流
@SentinelResource value参数:流量规则资源名称、
blockHandler 限流/熔断出现异常执行的方法
Fallback 服务的降级执行的方法

@SentinelResource(value = GETORDER_KEY, blockHandler = "getOrderQpsException")
@RequestMapping("/getOrderAnnotation")
public String getOrderAnnotation() {
    return "getOrder接口";
}
/**
 * 被限流后返回的提示
 *
 * @param e
 * @return
 */
public String getOrderQpsException(BlockException e) {
    e.printStackTrace();
    return "该接口已经被限流啦!";
}

控制台形式管理限流接口
Sentinel dashboard 控制台选择创建流量规则,设置资源名称(服务接口地址)、设置QPS 为1 表示每s最多能够访问1次接口。
SpringCloud微服务_第16张图片

项目需要整合Sentinel仪表盘

sentinel:
  transport:
    dashboard: 127.0.0.1:8718
  eager: true

接口上没有加注解的话,资源名称默认为@RequestMapping注解的value的值
线程数就是信号隔离
QPS表示一秒多少个处理多少个请求

sentinel实现限流的模式有那些

  • 手动配置管理Api限流接口
  • 手动放入到项目启动自动加载
  • 注解形式配置管理Api限流
  • 控制台形式管理限流接口

Sentinel如何保证规则的持久化

默认的情况下Sentinel的规则是存放在内存中,如果Sentinel客户端重启后,Sentinel数据规则可能会丢失。
Sentinel持久化机制支持四种持久化的机制。

  1. 本地文件
  2. 携程阿波罗
  3. Nacos
  4. Zookeeper

qps限流与并发限流之间的区别

qps限流:在1s内处理多少个请求,超过的请求都不做处理,返回友好提示。
并发限流:并发数控制在10个,其他超过并发数的请求全部拒绝,返回友好提示。

Feign整合Sentinel怎么使用?

1、开启支持配置

feign:
  sentinel:
    enabled: true # 开启feign对sentinel的支持

2、编写失败降级逻辑
业务失败后,不能直接报错,而应该返回用户一个友好提示或者默认结果,这个就是失败降级逻辑。给FeignClient编写失败后的降级逻辑
①方式一:FallbackClass,无法对远程调用的异常做处理
②方式二:FallbackFactory,可以对远程调用的异常做处理

/**
 * 自定义失败降级处理
 */
@Slf4j
@Component
public class UserClientFallbackFactory implements FallbackFactory<UserClient> {

    /**
     * 业务处理
     * @param throwable
     * @return
     */
    @Override
    public UserClient create(Throwable throwable) {
        return new UserClient() {
            @Override
            public User one(Long id) {
                log.error("查询用户异常", throwable);
                User user = new User();
                user.setAddress("xx");
                user.setUsername("yu");
                return user;
            }
        };
    }
}

在feing-api项目中的UserClient接口中使用UserClientFallbackFactory:

**
 *String url = "http://itheima-user/user/"+orderInfo.getUserId();
 * 替换成当前接口
 * 1.通过@FeignClient("被调用的服务名称")
 * 2.定义方法 需要跟 被调用的微服务要一样
 *  2.1.路径必须是被调用微服务的完整路径
 *  2.2.参数一定要加别名
 */
@FeignClient(value = "itheima-user",fallbackFactory = UserClientFallbackFactory.class)
public interface UserClient {

    /***
     * 根据id查询用户详情
     */
    @GetMapping(value = "/user/{id}")
    public User one(@PathVariable(value = "id") Long id);
}

Hystrix的使用

参考博客:https://blog.csdn.net/zhaoqingquanajax/article/details/115019260

网关整合服务保护使用

分布式事务

传统项目分布式事务产生的背景

在单体的项目中,有多个不同的数据源,每个数据源中都有自己独立的事务管理器,互不影响,那么这时候也会存在多数据源事务管理:解决方案jta+ Atomikos

RPC通讯的分布式事务产生的背景

答:在分布式/微服务架构中,每个服务都有自己的本地的事务,每个服务本地事务互不影响,那么这时候也会存在分布式事务的问题。调用方调用完服务方的接口的时候突然发生异常。

CAP与Base的基本设施理论

CAP这个定理的内容是指的是在一个分布式系统中、Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。

  • 一致性C:在分布式系统中,同一时刻所有的节点的数据都是相同的;
  • 可用性A: 集群中部分节点出现了故障,集群的整体也能够给响应;
  • 分区容错性P:分区容错性是指系统能够容忍节点之间的网络通信的故障,意味着发生了分区的情况,必须就当前操作在C和A之间做出选择;

BASE是Basically Available(基本可用)、Soft state(软状态)和 Eventually consistent(最终一致性)三个短语的缩写

分布式事务最终一致性的概念

在我们的分布式系统中,因为数据之间同步通过网络实现通讯,短暂的数据延迟是允许的,但是最终数据必须要一致性。

你熟悉那些分布式事务的解决框架

  1. 单体项目多数据源 可以jta+ Atomikos
  2. 基于rabbitmq的形式解决 最终一致性的思想
  3. 基于rocketmq解决分布式事务 采用事务消息
  4. LCN采用lcn模式 假关闭连接 (目前已经被淘汰)
  5. Alibaba的Seata 未来可能是主流 背景非常强大

LCN模式解决分布式事务实现的原理

  1. 发起方与参与方都与我们的LCN管理器一直保持长连接;
  2. 发起方在调用接口之前,先向LCN管理器申请一个全局的事务分组id;
  3. 发起方调用接口的时候在请求头中传递事务分组id;
  4. 参与方获取到请求头中有事务分组的id的,则当前业务逻辑执行完实现假关闭,不会提交或者回滚当前的事务。
  5. 发起方调用完接口后,如果出现异常的情况下,在通知给事务协调者回滚事务,这时候事务协调则告诉给参与方回滚当前的事务。

Lcn如何判断自己是发起方还是参与方?

根据当前的线程threadlocal中获取事务分组id,如果能够成功获取到则是为参与方,没有能够获取到就是为发起方。

Lcn的用法?

参与方与发起方都要加上该注解
@LcnTransaction
@Transactional

Seata解决分布式事务基本的介绍

Seata:Simple Extensible Autonomous Transaction Architecture,简易可扩展的自治式分布式事务管理框架,其前身是fescar。是一种简单分布式事务的解决方案。
Seata给用户提供了AT、TCC、SAGA和XA事务模式,AT模式是阿里云中推出的商业版本GTS全局事务服务。

Seata有3个基本组成部分:
1.事务协调器(TC):维护全局事务和分支事务的状态,驱动全局提交或回滚,相当于是协调者。
2.事务管理器TM:定义全局事务的范围:开始全局事务,提交或回滚全局事务,相当于LCN中发起方。
3.资源管理器(RM):管理分支事务正在处理的资源,与TC进行对话以注册分支事务并报告分支事务的状态,并驱动分支事务的提交或回滚,相当于是LCN中的参与方

Lcn与Seata的基本区别

  • tx-lcn是本地事务协调,本身并不会产生事务
  • seata 是两阶段提交事务,第一阶段解析业务sql并生成对应快照,第二阶段是提交/回滚,并删除快照

Seata解决分布式事务的原理

Seata实现原理

  1. TM(发起方)连接到我们的TC事务协调者,创建一个全局的事务的xid,保存到ThreadLoacl中;
  2. TM(发起方)和RM(参与方)都被Seata的数据数据源实现代理,在原生的sql之前和之后保存原来和 修改后日志到undo_log中,方便后期实现回滚。
  3. TM(发起方)使feign客户端调用接口时候,在ThreadLoacl中获取xid,设置到请求头中;
  4. RM(参与方)从请求中获取到该xid,设置到ThreadLoacl中,同时也会向seataserver注册该分支事 务。
  5. TM(发起方)将当前本地事务的结果,告诉给协调者TC,协调者TC在通知所有的分支是否回滚。
  6. TM(发起方)如果调用接口成功之后抛出异常的情况下,告诉给协调者TC,协调者TC在通知所有的分 支根据根据全局的xid和分支事务的id 查询分支数据源的undo_log日志表逆向生成sql语句实现回滚, 同时删除对应的undo_log日志
  7. TM(发起方)如果调用接口成功之后没有抛出任何的异常,告诉给协调者TC,协调者TC在通知所有的 分支根据根据全局的xid和分支事务的id 查询分支数据源的 删除对应的undo_log日志表

微服务安全

如何设计项目的接口

考虑:接口权限(开放接口 | 内部接口)幂等性的问题、安全性(Https)、防止串改数据(验证签名)使用网关拦截接口实现黑名单和白名单、接口使用http协议+json格式restful目的为了夸平台。

考虑高并发场景:对接口实现服务保护、服务降级、熔断、隔离之类,最后使用统一AP|管理平台api swagger。

接口分类:
1、开放接口
其他机构合作伙伴进行调用(必须在外网访问)蚂蚁开放平台、 微信公众号开发,需要通过appid + appsocet生成accessToken进行通讯。对接支付开发、微信开发。目的可以授权一些接口权限OAuth20协议方式第三方联合登陆。
2、内部接口
一般只能在局域网中进行访问,服务与服务调用之间关系都在同一个微服务系统中。目的是为了保证安全问题。

网关整合认证服务器

SpringCloud微服务_第17张图片

组件源码

Rabbon

你可能感兴趣的:(面试题,微服务,spring,cloud,java)