SpringCloud高级应用和原理

  • Post author:
  • Post category:其他



目录


一.微服务技术栈


二.微服务部分技术栈现状


1.Eureka闭源


2.Hystrix停止更新


3.Zuul过时


4.SpringCloud Config实用性差


5.SpringCloud Bus实用性差


三.微服务注册中心之Consul


1.Consul简介


2.consul官网连接


3.consul角色


4.consul安装(Windows下安装步骤)


四.微服务网关SpringCloud Gateway


1.概述


2.实现微服务网关的技术


3.Gateway路由配置


4.Gateway-Predicate配置详解


5.Gateway过滤器


6.Gateway跨域配置


7.限流


五.Spring Cloud OpenFeign


1.Feign


2.OpenFeign


3.OpenFeign应用


六.Spring Cloud 拦截器


1.拦截器的作用


2.拦截器的应用


一.微服务技术栈

1.SpringCloud Config 配置中心

集中管理配置文件(Git)

结合SpringCloud Bus动态刷新配置

2.安全控制

SpringCloud SpringSecurity/OAuth2

单点登录、统一认证、资源授权

JWT

同行令牌、身份信息载体

3.限流、降级

Hystrix

SpringCloud Alibaba Sentinel

4.Spring Cloud Alibaba阿里系技术栈集成

SpringCloud Alibaba RocketMQ

SpringCloud Alibaba Seata

SpringCloud Alibaba Nacos

SpringCloud Alibaba Sentinel

SpringCloud Alibaba Dubbo

SpringCloud Alibaba Sidecar

5.链路追踪

Sleuth+Zipkin

skywalking

6.消息组件

SpringCloud Stream

发布与订阅

消息分片

分组消费

集成MQ

SpringCloud Bus数据总线

基于SpringCloud Stream

多服务事件通信

7.微服务网关

Zuul

SpringCloud Gateway

8.服务调用

OpenFeign

服务间调用(Http协议)

支持数据压缩

RestTemplate

Http请求工具

Rest API风格操作

Ribbon

客户端负载均衡

9.注册中心与配置中心

SpringCloud Eureka

SpringCloud Alibaba Nacos

Spring Cloud Consul

Spring Cloud Zookeeper

二.微服务部分技术栈现状

1.Eureka闭源

Eureka 2.0 的开源工作已经停止,依赖于开源库里面的 Eureka 2.x 分支构建的项目或者相关代码,风险自负。

Eureka在微服务项目中主要承担服务注册与发现工作,可以替代的技术方案比较多,而且很多方案都比Eureka优秀,比如Consul、Nacos等。

2.Hystrix停止更新

官方宣布将不在开发,我们更推荐使用功能更加强悍的 SpringCloud Alibaba Sentinel 。

3.Zuul过时

Zuul 是一个微服务网关技术,但 Zuul1.x 使用的是阻塞式的API,不支持长连接,没有提供异步,高并发场景下性能低。 SpringCloud 官网推出了全新的微服务网关技术 SpringCloud Gateway ,比 Zuul 性能更强悍、功能更丰富、且支持异步等多种特性。

4.SpringCloud Config实用性差

SpringCloud Config 主要用于管理项目的配置文件,每次要使用 SpringCloud Config 的时候,总得经过一波操作和配置的折腾,才可以使用 SpringCloud Config 实现配置管理,而且单独使用无法支持配置实时刷新,在项目中用起来,真比较头疼的。

当前有很多技术可以取代 SpringCloud Config ,比如携程的 Apollo 、 SpringCloud Alibaba Nacos ,功能都比 SpringCloud Config 强,并且支持实时刷新配置。

5.SpringCloud Bus实用性差

SpringCloud Bus是服务消息总线,主要实现通知多个服务执行某个任务,一般和SpringCloud Config一起使用。这个功能其实不太使用,因为很多任务组件基本都具备消息通知功能,比如Nacos、Apollo都能实现所有服务订阅执行相关操作。

三.微服务注册中心之Consul

1.Consul简介

Consul 用于实现分布式系统的服务发现与配置。与其它分布式服务注册与发现的方案相比,Consul 的方案更“一站式”,内置了服务注册与发现框架、分布一致性协议实现、健康检查、Key/Value 存储、多数据中心方案,不再需要依赖其它工具(比如 ZooKeeper 等)。使用起来也较 为简单。Consul 使用 Go 语言编写,因此具有天然可移植性(支持 Linux、windows和Mac OS X);安装包仅包含一个可执行文件,方便部署,与 Docker 等轻量级容器可无缝配合。

2.consul官网连接


Consul by HashiCorp

3.consul角色

client: 客户端, 无状态, 将 HTTP 和 DNS 接口请求转发给局域网内的服务端集群。

server: 服务端, 保存配置信息, 高可用集群, 在局域网内与本地客户端通讯, 通过广域网与其它数据中心通讯。 每个数据中心的 server 数量推荐为 3 个或是 5 个。

4.consul安装(Windows下安装步骤)

(1)下载地址:

Downloads | Consul by HashiCorp

(2)配置环境变量:将解压后consul.exe所在的目录添加到环境变量Path中

(3)启动consul:cmd运行 consul agent -dev

(4)访问:http://localhost:8500

(5)启动优化:按照上面的命令启动,有个问题就是每次consul启动,之前的配置就不存在了,这里可以用新的启动方法代替

consul agent -server -bootstrap-expect=1 -ui -bind=127.0.0.1 -client=0.0.0.0 -data-dir=D:/develop/consul/data -config-dir=D:/develop/consul

这样每次重启consul,配置信息依然存在。

(6)启动脚本编写

为了方便后续启动,可以编写启动脚本start.bat,脚本内容如下

@echo off 
color 09
consul agent -server -bootstrap-expect=1 -ui -bind=127.0.0.1 -client=0.0.0.0 -data-dir=D:/develop/consul/data -config-dir=D:/develop/consul

(7)项目中配置consul

四.微服务网关SpringCloud Gateway

1.概述

微服务网关就是一个系统,通过暴露该微服务网关系统,方便我们进行相关的鉴权,安全控制,日志统一处理,易于监控,限流等相关功能。

2.实现微服务网关的技术

Nginx,zuul,SpringCloud Gateway

3.Gateway路由配置

基于配置路由设置如下

4.Gateway-Predicate配置详解

在 Spring Cloud Gateway 中 Spring 利用 Predicate 的特性实现了各种路由匹配规则,通过 Header、请求参数等不同的条件来作为条件匹配到对应的路由。

(1) Cookie配置:

Gateway的Cookie匹配接收两个参数:一个是 Cookie name ,一个是正则表达式。路由规则就是通过获取对应的 Cookie name 值和正则表达式去匹配,如果匹配上就会执行路由,如果没有匹配上则不执行。如下配置,要求请求携带cookie为username的数据,并且值为itheima,就允许通过。

gateway:
    routes:
    - id: hailtaxi-driver
      uri: lb://hailtaxi-driver
      predicates:
      - Path=/driver/**
      - Cookie=username,itheima

(2)Header 匹配:

Header 匹配 和 Cookie 匹配 一样,也是接收两个参数,一个 header 中属性名称和一个正则表达式,这个属性值和正则表达式匹配则执行。配置如下,就是要求请求头要有token属性,并且值必须为数字和字母组 合的正则表达式,例如携带token= 19and30 就可以通过访问。

gateway:
    routes:
    - id: hailtaxi-driver
      uri: lb://hailtaxi-driver
      predicates:
      - Path=/driver/**
      - Header=token,^(?!\d+$)[\da-zA-Z]+$

(3)Method请求方式匹配:

通过请求的方式是 POST、GET、PUT、DELETE 等进行路由。配置如下:

gateway:
    routes:
    - id: hailtaxi-driver
      uri: lb://hailtaxi-driver
      predicates:
      - Path=/driver/**
      - Method=GET,POST

5.Gateway过滤器

(1)Spring Cloud Gateway根据作用范围划分为GatewayFilter和 GlobalFilter。

过滤器作为Gateway的重要功能。常用于请求

鉴权



服务调用时长统计



修改请求或响应header



限流



去除路径

等等。

(2)

GatewayFilter

配置方式1:通过spring.cloud.routes.filters 配置在具体路由下,只作用在当前路由上

配置方式2:通过spring.cloud.default-filters配置在全局,作用在所有路由上。

(3)

GlobalFilter

无需配置:全局过滤器,不需要在配置文件中配置,作用在所有的路由上,最终通过GatewayFilterAdapter包装成GatewayFilterChain可识别的过滤器,它为请求业务以及路由的URI转换为真实业务服务的请求地址的核心过滤器,不需要配置,系统初始化时加载,并作用在每个路由上。

(4)过滤器分类:

默认过滤器:出厂自带,实现好了拿来就用,不需要实现
全局默认过滤器
局部默认过滤器
自定义过滤器:根据需求自己实现,实现后需配置,然后才能用哦。
全局过滤器:作用在所有路由上。
局部过滤器:配置在具体路由下,只作用在当前路由上。

过滤器有很多,常见的过滤器有如下几个

(5)默认过滤器的使用(系统自带的过滤器)

<1> 添加响应头

spring:
    cloud:
        gateway:
        # 配置全局默认过滤器 作用在所有路由上,也可单独为某个路由配置
            default-filters:
                # 往响应过滤器中加入信息
                - AddResponseHeader=X-Response-Default-MyName,itheima

接口的响应头中就上了如上配置的信息

<2>前缀处理

gateway:
    routes:
    - id: hailtaxi-driver
      uri: lb://hailtaxi-driver
      predicates:
      - Path=/api/driver/**
      filters:
          - StripPrefix=1

此处 – StripPrefix=1 表示真实请求地址是当前用户请求以 /api 开始的 uri中去除第1个路径 /api

StripPrefix=1 
路由地址:http://localhost:8001/api/driver/info/2
访问地址:http://localhost:8001/driver/info/2

StripPrefix=2
路由地址:http://localhost:8001/api/test/driver/info/2
访问地址:http://localhost:8001/driver/info/2

有时候为了简化用户请求地址,比如用户请求

http://localhost:8001/info/1

我们想统一路由到

http://localhost:18081/driver/info/1

可以使用 – PrefixPath = /driver 过滤器增加前缀。

6.Gateway跨域配置

(1)跨域概念

同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。

所谓同源就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)。

(2)Spring Cloud Gateway中配置跨域是非常简单的,如下面 application.yml 所示

gateway:
    globalcors:
        corsConfigurations:
            '[/**]':
              allowedOrigins: "*"
              allowedMethods:
                - GET
                - POST
                - PUT

7.限流

(1)令牌桶算法

令牌桶算法是常见的限流算法之一,下面是令牌桶算法的处理步骤

1)所有的请求在处理之前都需要拿到一个可用的令牌才会被处理;
2)根据限流大小,设置按照一定的速率往桶里添加令牌;
3)桶设置最大的放置令牌限制,当桶满时、新添加的令牌就被丢弃或者拒
绝;
4)请求达到后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务
逻辑,处理完业务逻辑之后,将令牌直接删除;
5)令牌桶有最低限额,当桶中的令牌达到最低限额的时候,请求处理完之后
将不会删除令牌,以此保证足够的限流

(2)gateway限流案例

首先引入redis依赖

<!--redis-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redisreactive</artifactId>
    <version>2.2.1.RELEASE</version>
</dependency>

配置redis

redis:
    host: 127.0.0.1
    port: 6379

在Application引导类中定义KeyResolver

    /**
     * IP限流
     * @return
     */
    @Bean(name = "ipKeyResolver")
    public KeyResolver userKeyResolver(){
       return new KeyResolver() {
           @Override
           public Mono<String> resolve(ServerWebExchange exchange) {
               //获取远程客户端IP
               String hostName = exchange
                        .getRequest()
                        .getRemoteAddress()
                        .getAddress()
                        .getHostAddress();
               System.out.println("hostName:"+hostName);
               return Mono.just(hostName);
           }
       };
    }

在配置文件中添加限流配置

filters:
    #请求数限流 名字不能随便写 ,使用默认的facatory
    - name: RequestRateLimiter
        args:
            #用于通过SPEL表达式来指定使用哪一个KeyResolver.
            key-resolver: "#{@ipKeyResolver}"
            #表示1秒内,允许1个请求通过,令牌桶的填充速率也是1秒钟添加1个令牌。
            redis-rate-limiter.replenishRate: 1
            #最大突发状况 也只允许1秒内有1次请求,可以根据业务来调整 。
            redis-rate-limiter.burstCapacity: 1

五.Spring Cloud OpenFeign

1.Feign

Feign是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端,内置了Ribbon,用来做客户端负载均衡,Feign本身不支持Spring MVC的注解,它有一套自己的注解。

2.OpenFeign

OpenFeign是Spring Cloud 在Feign的基础上支持了Spring MVC的注解,如@RequesMapping等。

3.OpenFeign应用

使用OpenFeign实现服务之间调用,可以按照如下步骤实现:

1:导入openfeign依赖
2:编写openfeign客户端接口-将请求地址写到该接口上
3:消费者启动引导类开启openfeign功能注解
4:访问接口测试

需求分析:

下单时,需要更新订单状态,此时order服务需要调用driver服务的更新状态的方法。

<1> 将需要远程调用的接口单独抽取成一个工程模块,并导入OpenFeign依赖

<!--配置feign-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>2.2.1.RELEASE</version>
</dependency>

<2> 创建Feign客户端接口

@FeignClient(value = "hailtaxi-driver")//value = "hailtaxidriver"指定服务的名字
public interface DriverFeign {
    /****
    * 更新司机信息,该方法和hailtaxi-driver服务中的方法保持一致
    * Feign会通过动态代理,帮我们生成实现类。
    * 注解@FeignClient声明Feign的客户端,注解value指明服务名称
    * 接口定义的方法,采用SpringMVC的注解。Feign会根据注解帮我们生成URL地址
    * 注解@RequestMapping中的/driver,不要忘记。因为Feign需要拼接可访问地址
    */
    @PutMapping(value = "/driver/status/{id}/{status}")
    Driver status(@PathVariable(value = "id")String id,@PathVariable(value = "status")Integer status);
}

hailtaxi-driver中controller代码如下

@RestController
@RequestMapping(value = "/driver")
@Slf4j
public class DriverController {

    @Autowired
    private DriverService driverService;
    @Value("${server.port}")
    private int port;

    /****
     * 更新司机信息
     */
    @PutMapping(value = "/status/{id}/{status}")
    public Driver status(@PathVariable(value = "id")String id,@PathVariable(value = "status")Integer status){
        log.info("当前服务占用的端口为:{}",port);
        //修改状态
        driverService.update(id,status);
        //修改状态后的司机信息
        return driverService.findById(id);
    }
}

<3> hailtaix-order服务调用feign

    @Autowired
    private DriverFeign driverFeign;

    /***
     * 下单
     */
    @PostMapping
    public OrderInfo add(){

        //更新司机状态
        driverFeign.status("1",2);

        //创建订单
        OrderInfo orderInfo = new OrderInfo("No"+((int)(Math.random()*10000)), (int)(Math.random()*100), new Date(), "深圳北站", "罗湖港", null);
        orderInfoService.add(orderInfo);
        return orderInfo;
    }

<4>hailtaix-order消费者服务启动引导类加上注解

@EnableFeignClients(basePackages = “com.itheima.driver.feign”)

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.itheima.driver.feign")
public class OrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class,args);
    }

}

<5>OpenFeign远程调用测试

六.Spring Cloud 拦截器

1.拦截器的作用

用 Feign 来调用远程服务,比如远程服务的权限验证,需要在 header 中传递 token 之类的。在方法中显示传递又过于麻烦了,这时候就可以考虑使用 Feign 提供的 RequestInterceptor 接口,只要实现了该接口,那么 Feign 每次做远程调用之前都可以被它拦截下来在进行包装

2.拦截器的应用

<1> 在OpenFeign的公共接口调用模块中添加拦截器

/**
* 1、直接实现接口
* 2、继承 BaseRequestInterceptor
*/
@Slf4j
public class MyRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        String url = template.url();
        Map<String, Collection<String>> headers =template.headers();
        String method = template.method();
        Map<String, Collection<String>> queries =template.queries();
        Request.Body body = template.requestBody();
        log.info("url={},headers={},method={},queries={},body={}",url,headers,method,queries,body);
        //添加头信息
        template.header("GlobalId",UUID.randomUUID().toString());
    }
}

<2>在需要调用远程服务的客户端加入容器即可

@Configuration
public class InterceptorConfiguration {
    @Bean
    public RequestInterceptor interceptor() {
        return new MyRequestInterceptor();
    }
}



版权声明:本文为qq_45443475原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。