SpringCloud Alibaba

微服务概念

why

因为现在是互联网项目,超高并发的访问,传统的方式无法解决问题。

单体

Tomcat和Mysql等软件部署在一台服务器上面,比如项目一和项目二。

    只能用于小项目中,访问量小的项目中,如果访问量大了,所有的请求到在一个服务器就绷不住了。

分布式

分布式(部署角度):项目中包含Tomcat和Mysql等软件分别部署在不同的服务器中,比如Tocat放在一个服务器,Mysql放在一个服务器。但是假如Tomcat的服务器崩了,整个系统也崩了。

    能够解决单体的问题,但是高并发上来了,有一个服务器绷不住了,这个项目也崩了

集群

集群:通过了负载均衡器搭配分布式项目,通过负载均衡器来解决高并发对单个服务器的压力过大的问题,分担服务器的一个压力。但是对于项目来说还是没有分离,仅仅是多个服务器部署一个项目。

    能够解决高并发的问题,负载均衡器能够承受超强的高并发问题。


面试问题

1、分布式架构或者微服务架构相当于单体架构有什么好处

2、你的项目用户量比较少,为什么使用微服务架构

3、你在微服务架构当中遇到最大的难题是什么?

4、你们项目的服务划分原则是怎么进行划分的

    在前公司没有接触到,但是会根据以下原则考虑。
    先是根据业务来分,按照职责的范围来区分,

5、你们项目一个服务多少个人负责,或则你负责的这个服务一共多少个人

    理想情况,一个服务三个人负责
    真实情况,一个人负责一个或者多个服务


系统架构演变

1、单体应用架构

就是想我们学习开发,所有的软件启动部署都在自己的服务器中。
优点:开发简单,容易上手,容易维护,成本低
缺点:扩展性差,项目模块之间耦合度高

2、垂直应用架构

将一个项目拆分成几个系统(比如电商系统、后台系统、CMS系统)。一个系统可以部署在多个服务器上,需求大的可以安排几个服务器,需求小的可以安排少量服务器即可。
优点:能够解决高并发问题、系统分离、一个系统倒了不会影响其他系统,只会影响部分项目功能。
缺点:存在代码重复,毕竟还是一个服务器部署一个小系统。各个系统之间不能交互

3、分布式架构(部署角度)

将一个项目拆成几个系统(比如电商系统、后台系统、CMS系统),再将一个系统中的模块分别放在不同的服务器的Tomcat内。
优点:减少了代码重复问题,提高代码复用性
缺点:耦合度很高,调用复杂,难以维护

4、微服务架构(业务拆分角度)

一个项目中有很多个功能模块,根据功能模块来进行划分,可以根据功能模块的访问量来进行动态扩展,可以针对访问量大的和访问量小的功能来设计集群的大小等等。
优点:独立性强,扩展性强,每个服务之间清晰的任务划分
缺点:一个服务一个服务器,一个数据库一个服务器,成本高。


分布式架构和微服务的区别:

1、微服务的服务器是一个服务器对应一个数据库
2、微服务是按照业务拆分代码,而分布式会有重复的代码,只是将服务独立放在服务器中。
3、拆分的角度不同,微服务是根据业务需求来拆分,一个业务服务就是一个项目,一个服务器,专用一个数据库服务器

Nacos Discovery服务治理

WHY

微服务中,每个服务器之间的沟通是一个问题。比如需要调用服的时候,需要通过接口路径传送参数获取数据,但是在多个服务器的时候,我们无法准备获取某个服务器的路径。但是路径又不能够写死,写死就不能够换服务器分担了。

HOW

1、服务在启动的时候,会把信息注册到到注册中心,并且会拉取一份注册中心服务列表信息

2、每个一段时间就给注册中心发送一个心跳包,确保服务器还活着,并且会拉取一份最新的服务列表信息

3、如果连续几次没有给注册中心发送心跳包,以为服务已经挂了,注册中心就会把节点信息删除

实战入门

环境

1、安装Nacos

下载地址: https://github.com/alibaba/nacos/releases 
下载zip格式的安装包,然后进行解压缩操作,上课使用的Nacos Server版本是1.3.2

2、启动Nacos

#切换目录 (或者在目录中代开cmd)
cd nacos/bin 
#命令启动 
startup.cmd -m standalone

3、访问Nacos

​ 打开浏览器输入http://localhost:8848/nacos,即可访问服务, 默认密码是nacos/nacos

将服务注册到Nacos中

1、在pom.xml中添加Nacos的依赖



    com.alibaba.cloud
    spring-cloud-starter-alibaba-nacos-discovery

2、在主类上(SpringBootApplication类)添加@EnableDiscoveryClient注解

    让配置中心发现

3、在配置文件中添加 Nacos服务的地址

spring:
  cloud: 
    nacos: 
      discovery: 
        server-addr: localhost:8848

4、启动服务、观察Nacos的控制面板中是否有注册上来的微服务

5、实现微服务调用

        //从nacos中获取服务地址
        ServiceInstance instance = discoveryClient.
                getInstances("product-service").get(0);
        String url = instance.getHost()+":"+instance.getPort();
        //远程调用商品微服务,查询商品信息
        Product product = restTemplate.getForObject(
                "http://"+url+"/product/"+productId,Product.class);
        log.info("查询到{}号商品的信息,内容是:{}", productId, JSON.toJSONString(product));

WHAT

服务治理是微服务架构中最核心最基本的模块。用于实现各个微服务的自动化注册与发现

自动化注册:在每个微服务中,会将信息发送到注册中心,进行自动化注册。相当于形成一张动态的服务器状态登记表,每隔一段时间会记录服务器的情况。也可以说是实时监控微服务的服务器们。


Ribbon 远程调用负载均衡

WHY

微服务架构,服务器特别多,但是对于服务器的调用也是问题。如果通自己写逻辑去对请求进行分流也很麻烦。所以使用 Ribbon 组件来解决请求分配到服务器的问题。

WHAT

将请求通过策略,将服务器的使用最大化

HOW

1、通过反射接收到传递的 url 参数,将url的信息提出切割处理

2、上本地中去找product-service 对应服务信息, localhost:8081 localhost:8082

3、然后根据你配置的负载均衡策略,选择下一个节点 localhost:8081,吧 url中服务名字替换 ip:port

4、使用 RestTemplate 对象去发送请求

配置策略需要加载到服务调用方!

自定义负载均衡

1、通过idea启动多个微服务(两种方式,不懂百度)

2、通过Nacos查看微服务的启动情况

3、通过负载均来实现

    @Autowired
    private DiscoveryClient discoveryClient;


    List instances = discoveryCient.
                getInstances("product-service");
        int index = new Random().nextInt(instances.size());
        ServiceInstance instance = instances.get(index);
        String url = instance.getHost()+":"+instance.getPort();
        log.info(">>从nacos中获取到的微服务地址为:" + url);
        //远程调用商品微服务,查询商品信息
        Product product = restTemplate.getForObject(
                "http://"+url+"/product/"+productId,Product.class);
        log.info("查询到{}号商品的信息,内容是:{}", productId, JSON.toJSONString(product));

4、测试有没有调用两个服务器来处理请求

基于Ribbon实现负载均衡

1、在RestTemplate 的生成方法上添加@LoadBalanced注解

@Bean
@LoadBalanced    //开启负载均衡的功能
public RestTemplate restTemplate(){
    return new RestTemplate();
}

2、修改OrderServiceImpl服务调用的方法

 Product product = restTemplate.getForObject(
                "http://product-service/product?productId="+productId,Product.class);
        log.info("查询到{}号商品的信息,内容是:{}", productId, JSON.toJSONString(product));

3、被调用的微服务(Controller中)查看

获取被调用服务器的端口
    @Value("${server.port}")
    private String port;

修改均衡策略

Ribbon内置了多种负载均衡策略,内部负载均衡的顶级接口为

com.netflix.loadbalancer.IRule , 具体的负载策略如下图所示:

策略名 策略描述 实现说明
BestAvailableRule 选择一个最小的并发请求的server 逐个考察Server,如果Server被tripped了,则忽略,在选择其中ActiveRequestsCount最小的server
AvailabilityFilteringRule 先过滤掉故障实例,再选择并发较小的实例; 使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就就是检查status里记录的各个server的运行状态
WeightedResponseTimeRule 根据相应时间分配一个weight,相应时间越长,weight越小,被选中的可能性越低。 一个后台线程定期的从status里面读取评价响应时间,为每个server计算一个weight。Weight的计算也比较简单responsetime 减去每个server自己平均的responsetime是server的权
RetryRule 对选定的负载均衡策略机上重试机制。 在一个配置时间段内当选择server不成功,则一直尝试使用subRule的方式选择一个可用的server
RoundRobinRule 轮询方式轮询选择server 轮询index,选择index对应位置的server
RandomRule 随机选择一个server 在index上随机,选择index对应位置的server
ZoneAvoidanceRule(默认) 复合判断server所在区域的性能和server的可用性选择server 使用ZoneAvoidancePredicate和AvailabilityPredicate来判断是否选择某个server,前一个判断判定一个zone的运行性能是否可用,剔除不可用的zone(的所有server),AvailabilityPredicate用于过滤掉连接数过多的Server。
product-service: # 调用的提供者的名称
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

Feign 远程调用

WHY

在微服务中调用其他的服务还是麻烦,只需要创建一个接口和一个注解即可

HOW

1、通过反射拿到代理类实现接口

2、拿到接口上的注解 @FeignClient() ,并且拿到注解的值, product-server

3、拿到接口中方法,取方法上的 @RequestMapping注解,并且拿到注解中的 / Xxx 方法

4、拿到接中方法,去方法参数中注解@RequestParam(), 并且拿到注解中 id=xx

5、拼接路径, http://product-server/Xxx?id=xx

6、根据服务名字去本地区找 product-server 节点信息: localhost:8081, localhost:8082

7、根据 Ribbon 负载均衡策略选择一个节点 : localhost:8081

8、把服务名去替换成真实的 ip和端口 , http://localhost:8081/Xxx?id=xx

9、使用 RestTemplate 对象去发送 Http 请求

WHAT

声明式的伪Http客户端,它使得调用远程服务就像调用本地服务一样简单。
Nacos兼容了Feigh,Feign默认集成了Ribbin,可以在配置:超时配置和重试次数配置

Feign入门

1、在shop-order-server项目的pom文件加入Fegin的依赖



    org.springframework.cloud
    spring-cloud-starter-openfeign

2、在调用服务类启动类上添加Fegin的扫描注解,注意扫描路径(默认扫描当前包及其子包)

@SpringBootApplication    
@EnableDiscoveryClient    // 开启治理中心管理    
@EnableFeignClients
public class OrderServer {
    public static void main(String[] args) {
        SpringApplication.run(OrderServer.class,args);
    }
}

3、在调用服务的项目中新增接口 被调用类FeignApi

//name的名称一定要和订单服务的服务名保持一致
@FeignClient(name = "product-service")
public interface ProductFeignApi {

    // 这里直接复制被调用接口的代码
    
    @RequestMapping("/product")
    public Product findByPid(@RequestParam("pid") Long pid);
}

4、修改 远程调用方法(通过创建的 XxxFeignApi )

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderDao orderDao;
    @Autowired
    private ProductFeignApi productFeignApi;
    @Override
    public Order createOrder(Long productId,Long userId) {
        log.info("接收到{}号商品的下单请求,接下来调用商品微服务查询此商品信息", productId);
        //远程调用商品微服务,查询商品信息
        Product product = productFeignApi.findByPid(productId);
        log.info("查询到{}号商品的信息,内容是:{}", productId, JSON.toJSONString(product));
        //创建订单并保存
        Order order = new Order();
        order.setUid(userId);
        order.setUsername("叩丁狼教育");
        order.setPid(productId);
        order.setPname(product.getPname());
        order.setPprice(product.getPprice());
        order.setNumber(1);
        orderDao.save(order);
        log.info("创建订单成功,订单信息为{}", JSON.toJSONString(order));
        return order;
    }
}

超时配置

默认配置是1秒,重试次数1次

在服务调用方

feign:
  client:
    config:
      default:
        connectTimeout: 5000    # 连接等待时间
        readTimeout: 5000        # 连接通话时间

重试次数配置

要考虑你的业务情况,如果是插入数据的请求,重试会造成数据库的多次操作

https://github.com/Netflix/ri...

product-service: # 调用的提供者的名称
  ribbon:
    MaxAutoRetries: 0            # 最大重试次数
    MaxAutoRetriesNextServer: 0    # 最大重试节点个数

Sentinel(分布式系统的流量防卫兵)服务熔断降级

WHY

服务器雪崩效应

​ 在分布式的系统中,由于网络等等原因,造成某个服务阻塞.由于微服务是相互调用的关系(相互依赖),所以当一个服务受到影响,调用这个服务的服务器也会受到影响,从而影响整个系统.

解决思路

隔离机制(资源隔离)、超时机制(超时就脱离)、限流机制、熔断机制、降级机制(弄个备选方案)

HOW

通过网络来监控每个微服务的情况,再根据所设置的方案来进行调控。

WHAT

​ Sentinel (分布式系统的流量防卫兵) 是阿里开源的一套用于服务容错的综合性解决方案。它以流量

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

Sentinel 具有以下特征:

  • 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景, 例如秒杀(即

突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用

应用等。

  • 完备的实时监控:Sentinel 提供了实时的监控功能。通过控制台可以看到接入应用的单台机器秒

级数据, 甚至 500 台以下规模的集群的汇总运行情况。

  • 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块, 例如与 Spring

Cloud、Dubbo、gRPC 的整合。只需要引入相应的依赖并进行简单的配置即可快速地接入

Sentinel。

Sentinel入门

1、导入依赖



    com.alibaba.cloud
    spring-cloud-starter-alibaba-sentinel

2、安装Sentinel 控制台

  1. 下载jar包 https://github.com/alibaba/Se...
  2. 启动控制台

    # 直接使用jar命令启动项目(控制台本身是一个SpringBoot项目) 
    java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar
  3. 修改shop-order-server项目中的配置文件application.yml,新增如下配置:

    spring:
      cloud:
        sentinel: 
          transport: 
            port: 9999 #跟控制台交流的端口,随意指定一个未使用的端口即可 
            dashboard: localhost:8080 # 指定控制台服务的地址
  4. 通过浏览器访问localhost:8080 进入控制台 ( 默认用户名密码是 sentinel/sentinel )

    注意: 默认是没显示order-service的,需要访问几次接口,然后再刷新sentinel管控台才可以看到.

Sentinel规则

流控

​ 监控流量的QPS或者并发线程数等指标,达到阔值进行限流,避免冲破服务器
​ PS:峰值QPS,同一个时刻的并发量,一秒内能够处理的请求

资源名:唯一名称,默认是请求路径,可自定义

针对来源:指定对哪个微服务进行限流,默认指default,意思是不区分来源,全部限制

阈值类型/单机阈值

  • QPS(每秒请求数量): 当调用该接口的QPS达到阈值的时候,进行限流
  • 线程数:当调用该接口的线程数达到阈值的时候,进行限流

是否集群:暂不需要集群

高级选项:

sentinel共有三种流控模式,分别是:

  • 直接(默认):接口达到限流条件时,开启限流
  • 关联:当关联的资源达到限流条件时,开启限流 [适合做应用让步]
  • 链路:当从某个接口过来的资源达到限流条件时,开启限流

降级

降级规则就是设置当满足什么条件的时候,对服务进行降级。Sentinel提供了三个衡量条件:

  • 慢调用比例: 选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
  • 异常比例: 当单位统计时长内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
  • 异常数:当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

热点(细化的流控)

1、添加注解@SentinelResource

    需要在请求方法上天注解,否则热点规则无效

2、控制台新增热点

授权

很多时候,我们需要根据调用来源来判断该次请求是否允许放行,这时候可以使用 Sentinel 的来源访问控制(黑白名单控制)的功能。来源访问控制根据资源的请求来源(origin)限制资源是否通过,若配置白名单则只有请求来源位于白名单内时才可通过;若配置黑名单则请求来源位于黑名单时不通过,其余的请求通过。

Sentinel自定义异常返回

当前面设定的规则没有满足是,我们可以自定义异常返回.

  • FlowException 限流异常
  • DegradeException 降级异常
  • ParamFlowException 参数限流异常
  • AuthorityException 授权异常
  • SystemBlockException 系统负载异常

在shop-order-server项目中定义异常返回处理类

@Component
public class ExceptionHandlerPage implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
        response.setContentType("application/json;charset=utf-8");
        ResultData data = null;
        if (e instanceof FlowException) {
            data = new ResultData(-1, "接口被限流了");
        } else if (e instanceof DegradeException) {
            data = new ResultData(-2, "接口被降级了");
        }else if (e instanceof ParamFlowException) {
            data = new ResultData(-3, "参数限流异常");
        }else if (e instanceof AuthorityException) {
            data = new ResultData(-4, "授权异常");
        }else if (e instanceof SystemBlockException) {
            data = new ResultData(-5, "接口被降级了...");
        }
        response.getWriter().write(JSON.toJSONString(data));
    }
}
@Data
@AllArgsConstructor//全参构造
@NoArgsConstructor//无参构造
class ResultData {
    private int code;
    private String message;
}

Feign 整合 Sentinel

  1. 在shop-order-server项目的配置文件中开启feign对Sentinel的支持

    feign:
      sentinel:
        enabled: true
  2. 创建容错类

    @Component
    public class ProductFeignFallBack implements ProductFeignApi {
        @Override
        public Product findByPid(Long pid) {
            Product product = new Product();
            product.setPid(-1L);
            product.setPname("兜底数据");
            product.setPprice(0.0);
            return product;
        }
    }
  3. 在feign接口中定义容错类

    @FeignClient(name = "product-service",fallback = ProductFeignFallBack.class)
    public interface ProductFeignApi {
        @RequestMapping("/product")
        public Product findByPid(@RequestParam("pid") Long pid);
    }
  4. 停止所有 商品服务,重启 shop-order 服务,访问请求,观察容错效果

Gateway 服务网关

WHY

在微服务的项目中,往往是多个服务器,也就意味着有多个微服务地址,那我们需要通过微服务地址去寻找调用。但是地址很多,没有统一化管理, 逻辑比较复杂。而且如果添加了鉴权需求,需要去较多的代码去实现。

HOW

image-20201030161652819

1、当请求到网关,会有请求处理器会接受请求。然后转发处理器映射器,返回执行链

2、交给 Gateway web 处理器进行处理,根据发来的 url 跟本地配置进行匹配,如果匹配到了对应服务信息, product-service 服务器名对应 id 信息,比如 localhost:8081, localhost:8082

3、根据你配置 ribbon 的负载均衡策略选择一个节点 localhost:8081

4、最终他会进行拼接路径和请求,然后通过 template 来发送 HTTP 请求

WHAT

1、网关的作用作为统一入口

2、一些通用的功能放到网关这里进行处理

3、网络隔离

相当于以前项目的拦截器

Gateway快速入门

1、创建一个 api-gateway 的模块,导入相关依赖



    
        shop-parent
        cn.wolfcode
        1.0.0
    
    4.0.0

    api-gateway
    
        
        
            org.springframework.cloud
            spring-cloud-starter-gateway
        
        
        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-nacos-discovery
        
        
            org.projectlombok
            lombok
        
    

2、编写启动类

​ 需要 @EnableDiscoveryClient,因为需要去注册中心拉取微服务的服务信息

@SpringBootApplication
@EnableDiscoveryClient
public class ApiGatewayServer {
    public static void main(String[] args) {
        SpringApplication.run(ApiGatewayServer.class,args);
    }
}

3、编写配置文件

server:
  port: 9000
spring:
  application:
    name: api-gateway
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
    gateway:
      discovery:
        locator:
          enabled: true # 让gateway可以发现nacos中的微服务

4、通过网关的端口去访问微服务

​ localhost:9000/服务名/接口?参数

自定义路由接口

1、在 application/yml 中添加新的路由规则

- **id**,路由标识符,区别于其他 Route。 
- **uri**,路由指向的目的地 uri,即客户端请求最终被转发到的微服务。
- **order**,用于多个 Route 之间的排序,数值越小排序越靠前,匹配优先级越高。
- **predicate**,断言的作用是进行条件判断,只有断言都返回真,才会真正的执行路由。
- **filter**,过滤器用于修改请求和响应信息。

spring:
  application:
    gateway:
      routes:
        - id: product_route
          uri: lb://product-service 
          predicates:
            - Path=/product-serv/**
          filters:
            - StripPrefix=1
        - id: order_route
          uri: lb://order-service 
          predicates:
            - Path=/order-serv/**
          filters:
            - StripPrefix=1

Filter 过滤器

过滤器就是在请求的传递过程中,对请求和响应做一些手脚.

在Gateway中, Filter的生命周期只有两个:“pre” 和 “post”。

  • PRE: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择

请求的微服务、记录调试信息等。

  • POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP

Header、收集统计信息和指标、将响应从微服务发送给客户端等。

在Gateway中,Filter的作用范围两种:

  • GatewayFilter:应用到单个路由或者一个分组的路由上。
  • GlobalFilter:应用到所有的路由上

局部过滤

1、编写Filter 类,注意名称是有固定格式 xxxGatewayFilterFactory (Xxx与添加的路由配置相同)

@Component
public class TimeGatewayFilterFactory extends AbstractGatewayFilterFactory {

    /**
     * Parts key.
     */
    public static final String PARTS_KEY = "parts";

    public TimeGatewayFilterFactory() {
        super(TimeGatewayFilterFactory.Config.class);
    }

    @Override
    public List shortcutFieldOrder() {
        return Arrays.asList(PARTS_KEY);
    }

    public GatewayFilter apply(TimeGatewayFilterFactory.Config config) {
        return new GatewayFilter() {
            @Override
            public Mono filter(ServerWebExchange exchange,
                                     GatewayFilterChain chain) {

//                System.out.println("前置逻辑");

                if(!config.isParts()){
                    return chain.filter(exchange);
                }
                /**
                 * 前置这里去记录一下时间
                 */
                exchange.getAttributes().put("beginTime",new Date().getTime());

                return chain.filter(exchange).then(Mono.fromRunnable(new Runnable() {
                    @Override
                    public void run() {
                        // 记录一下时间, 然后相减
                        System.out.println("后置逻辑");
                        long endTime = new Date().getTime();
                        long beginTime = (long) exchange.getAttributes().get("beginTime");
                        System.out.println("最终耗时"+(endTime-beginTime) +"ms");

                    }
                }));
            }
        };
    }

    @Getter@Setter
    public static class Config {
        private boolean parts;
    }
}

2、添加路由规则

      routes:
        - id: order_route
          uri: lb://order-service 
          predicates:
            - Path=/order-serv/**
          filters:
            - StripPrefix=1
            - Time=true                    #这里与创建的Filter类名前缀相同

全局过滤

全局过滤器作用于所有路由, 无需配置。通过全局过滤器可以实现对权限的统一校验,安全性验证等功

能。

需求: 实现统一鉴权的功能,我们需要在网关判断请求中是否包含token且,如果没有则不转发路由,有则执行正常逻辑。

1、编写全局过滤类

@Component
public class AuthGlobalFilter implements GlobalFilter {
    @Override
    public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        if (StringUtils.isBlank(token)) {
            System.out.println("鉴权失败");
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }
}

2、测试携带 Token 是否能够进入方法

Sleuth&Zipkin 链路追踪

WHY

在微服务框架中,每天产生的日志也会很多,而且每个服务器之间调用频繁,需要查看不同的服务器的日志,错误寻找困难。

HOW

Sleuth在日志中产生日志的唯一标记,能够通过标记来寻找某一次的请求所产生的日志,再通过 Zipkin 来创建可视化的链路追踪。

日志格式:
[order-server,c323c72e7009c077,fba72d9c65745e60,false] 
1、第一个值,spring.application.name的值
2、第二个值,c323c72e7009c077 ,sleuth生成的一个ID,叫Trace ID,用来标识一条请求链路,一条请求链路中包含一个Trace ID,多个Span ID
3、第三个值,fba72d9c65745e60、spanID 基本的工作单元,获取元数据,如发送一个http
4、第四个值:true,是否要将该信息输出到zipkin服务中来收集和展示。

WHAT

分布式链路追踪(Distributed Tracing),就是将一次分布式请求还原成调用链路,进行日志记录,性能监控并将一次分布式请求的调用情况集中展示。比如各个服务节点上的耗时、请求具体到达哪台机器上、每个服务节点的请求状态等等。

Zipkin + Sleuth 整合

1、下载 Zipkin 的jar包:官网:https://zipkin.io/

2、通过 java -jar 启动

3、通过 浏览器访问 http://localhost:9411访问

4、添加依赖(添加了此依赖,Sleuth的依赖可以删除,里面整合了)


    org.springframework.cloud
    spring-cloud-starter-zipkin

5、配置

spring:
  zipkin:
    base-url: http://127.0.0.1:9411/ #zipkin server的请求地址
    discoveryClientEnabled: false #让nacos把它当成一个URL,而不要当做服务名
  sleuth: 
    sampler: 
      probability: 1.0 #采样的百分比

6、重启服务的服务器

7、访问zipkin的UI界面,观察效果

Nacos Config 配置中心

WHY

1、配置重复问题。当我们在多个服务中,需要配置相同的信息,在多个服务中配置量相同的配置,比如多个服务使用 Redis ,那服务都需要进行Redis的配置。

2、配置没有历史版本,修改完之后没有记录,想恢复之前的版本就无法退回。

3、切换环境麻烦。开发中会有开发环境、有测试环境还有生成环境,每个配置都需要修改

4、配置没有办法动态刷新

HOW

​ 把项目的各种配置全部放到一个集合中的地方进行统一管理,并提供一套标准的接口

当哥哥服务需要获取配置的时候,就去配置中心拉取自己的配置

因为服务每次启动都会拉取,所以配置有更新的时候,服务这边也会同步更新

WHAT

使用nacos作为配置中心,其实就是将nacos当做一个服务端,将各个微服务看成是客户端,我们

将各个微服务的配置文件统一存放在nacos上,然后各个微服务从nacos上拉取配置即可。

Nacos Config入门

1、搭建好Nacos 的环境(Nacos Discovery服务治理中)

2、在商品微服务中引入 Nacos 配置的依赖


    com.alibaba.cloud
    spring-cloud-starter-alibaba-nacos-config 

3、在微服务中添加 Nacos config 的配置

配置文件优先级(由高到低):
bootstrap.properties -> bootstrap.yml -> application.properties -> application.yml
Boostrap.yml文件

spring:
  application:
    name: product-service
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848 #nacos中心地址
        file-extension: yaml # 配置文件格式
  profiles: 
      active: dev # 环境标识

4、在 Nacos 中添加配置,然后把商品微服务 application.yml 配置复制到配置内容中

5、注释本地的application.yaml中的内容,启动程序进行测试

配置动态刷新

  1. 在nacos中的product-service-dev.yaml配置项中添加下面配置:

    appConfig:
      name: product2020
  2. 在商品微服务中新增NacosConfigControlller.java

    @RestController
    @RefreshScope
    public class NacosConfigController {
        @Value("${appConfig.name}")
        private String appConfigName;
        @RequestMapping("/nacosConfig1")
        public String nacosConfig(){
            return "远程信息:"+appConfigName;
        }
    }

配置共享

同一个微服务的不同环境之间(开发、测试、部署等环境)共享配置

创建一个公共配置,名称不带环境,如 product-service.yaml

不同微服务中间共享配置

不同微服务之间实现配置共享的原理类似于文件引入,就是定义一个公共配置,然后在当前配置中引

入。

在nacos中定义一个Data ID为global-config.yaml的配置,用于所有微服务共享

globalConfig: global

你可能感兴趣的:(SpringCloud Alibaba)