上手【SpringCloud】这一篇就够了

1. 微服务介绍

微服务架构, 就是将应用拆分成非常小的服务,每个服务都是一个可以独立运行的项目。其主要特点如下:

  • 单一职责:每一个服务都对应唯一的业务能力,做到单一职责,避免重复业务开发
  • 面向服务:微服务对外暴露业务接口
  • 自治:团队独立、技术独立、数据独立、部署独立
  • 隔离性强:服务调用做好隔离、容错、降级,避免出现级联问题

在这里插入图片描述

一旦采用微服务系统架构,就势必会遇到这样几个问题:

  • 这么多小服务,如何管理他们? 服务治理(电话本)
  • 这么多小服务,他们之间如何通讯? http协议(打电话)
  • 这么多小服务,客户端怎么访问他们? 服务网关(保安)

对于上面的问题,是任何一个微服务设计者都不能绕过去的,因此大部分的微服务产品都针对每一个问题提供了相应的组件来解决它们。

SpringCloud

微服务这种方案需要技术框架来落地,全球的互联网公司都在积极尝试自己的微服务落地技术。

目前最知名的就是SpringCloudSpringCloud Alibaba

  • SpringCloud:Spring基于NetFlix微服务组件进行封装,提供微服务一站式解决方案
  • SpringCloud Alibaba:在SpringCloud NetFlix基础上封装了阿里巴巴的微服务解决方案

在这里插入图片描述

2. 服务治理 - Eureka

2-1. 服务治理

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

  • 服务注册: 在服务治理框架中,都会构建一个注册中心,每个服务单元向注册中心登记自己提供服务的详细信息。并在注册中心形成一张服务的清单,服务注册中心需要以心跳的方式去监测清单中的服务是否可用,如果不可用,需要在服务清单中剔除不可用的服务。
  • 服务发现: 服务调用方向服务注册中心咨询服务,并获取所有服务的实例清单,实现对具体服务实例的访问。

在这里插入图片描述

服务注册:每个服务实例会把自己的IP地址,服务名称等信息注册到注册中心。
服务发现:当服务实例需要进行服务间的调用时,会查询注册中心获取其它服务的网络位置,找到后就可以进行调用。
服务续约:服务实例在注册完毕后会定期向注册中心发送心跳消息,这个过程被称作服务续约。
服务剔除:注册中心在一定时间内没有收到服务实例的心跳消息,那么就会认为这个服务实例已经失效,进行服务剔除。

2-2. 负载均衡

负载均衡就是将负载(工作任务,访问请求)进行分摊到多个操作单元上进行执行。

根据负载均衡发生位置的不同,一般分为服务端负载均衡客户端负载均衡

服务端负载均衡指的是发生在服务提供者一方,比如常见的nginx负载均衡。

客户端负载均衡指的是发生在服务请求的一方,也就是在发送请求之前已经选好了由哪个实例处理请求。

在这里插入图片描述

我们在微服务调用关系中一般会选择客户端负载均衡,也就是在服务调用的一方来决定服务由哪个提供者执行。

开启负载均衡

在这里插入图片描述

负载均衡原理总结

  1. 在RestTemplate上添加了@LoadBalanced注解后,会使用LoadBalancerClient来配置RestTemplate
  2. Spring Cloud Ribbon 的自动配置类LoadBalancerAutoConfiguration中的@ConditionalOnBean(LoadBalancerClient.class)条件成立
  3. 自动配置中添加了LoadBalancerInterceptor,这个拦截器会拦截请求,通过服务ID获取服务的地址列表,然后通过负载均衡策略选出一个地址进行调用

在这里插入图片描述

负载均衡策略

负载均衡的规则都定义在IRule接口中,它有很多不同的实现类,分别代表不同规则

内置负载均衡规则类规则描述
RoundRobinRule简单轮询服务列表来选择服务器。第一次到8081,第二次就到8082,第三次又到8081,第四次又到8082…
AvailabilityFilteringRule可用过滤规则,其实它功能是先过滤掉不可用的Server实例,再选择并发连接最小的实例。
WeightedResponseTimeRule为每一个服务器计算一个权重范围区间,权重区间的宽度越大,而权重区间宽度越大被选中的概率就越大。
ZoneAvoidanceRule以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。而后再对Zone内的多个服务做轮询
BestAvailableRule忽略那些短路的服务器,并选择并发数较低的服务器。
RandomRule随机选择一个可用的服务器。
RetryRule轮询重试(重试采用的默认也是轮询)

SpringCloud允许通过定义IRule修改负载均衡规则,有两种方式:

  • 全局方式:向Spring容器中直接放入想要使用的策略对象
@Bean
public IRule randomRule(){
    return new RandomRule();
}
  • 局部方式:在配置文件中,针对指定的服务提供者配置策略。
user-service: # 给某个微服务配置负载均衡规则,这里是user-service服务  
	ribbon:    
		NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则 

注意: 负载均衡策略需要配置在服务消费者一方

饥饿加载

Ribbon默认是采用懒加载,即第一次访问时才会去创建LoadBalanceClient,请求时间会很长。

而饥饿加载则会在项目启动时创建,降低第一次访问的耗时,通过下面配置开启饥饿加载:

ribbon:  
	eager-load:    
		enabled: true # 开启饥饿加载    
		clients:       
		- user-service  # 指定饥饿加载的服务名称

3. 服务治理 - Nacos

Nacos是阿里巴巴的产品,也可以作为服务注册中心使用,相比Eureka功能更加丰富,在国内受欢迎程度较高。

3-1. 权重配置

nacos支持权重配置来控制不同实例的访问频率,权重越大则访问频率越高。0 <= 权重值 <= 1

在这里插入图片描述

3-2. 临时节点

Nacos的服务实例分为两种类型:

  • 临时实例:如果实例宕机超过一定时间,会从服务列表剔除,默认的类型。
  • 持久实例:如果实例宕机,不会从服务列表剔除,也可以叫永久实例。

配置一个服务实例为永久实例:

spring:   
	cloud:     
		nacos:       
			discovery:         
				ephemeral: false # 设置为非临时实例

临时和持久化的区别主要在健康检查失败后的表现,持久化实例健康检查失败后会被标记成不健康,而临时实例会直接从列表中被删除

3-3. Nacos和Eureka的区别

Nacos和Eureka整体结构类似,服务注册、服务拉取、心跳等待,但是也存在一些差异:

模块NacosEureka说明
注册中心服务治理基本功能,负责服务中心化注册
配置中心Eureka需要配合Config实现配置中心,且不提供管理界面
动态刷新Eureka需要配合MQ实现配置动态刷新,Nacos采用Netty保持TCP长连接实时推送
可用区AZ对服务集群划分不同区域,实现区域隔离,并提供容灾自动切换
分组Nacos可用根据业务和环境进行分组管理
元数据提供服务标签数据,例如环境或服务标识
权重Nacos默认提供权重设置功能,调整承载流量压力
健康检查Nacos支持由客户端或服务端发起的健康检查,Eureka是由客户端发起心跳
负载均衡均提供负责均衡策略
管理界面Nacos支持对服务在线管理,Eureka只是预览服务状态

4. 配置管理 - Nacos

Nacos除了可以做注册中心,同样可以做配置管理中心来使用。

3-1. 配置管理介绍

当微服务部署的实例越来越多,达到数十、数百时,逐个修改微服务配置就会让人抓狂,而且很容易出错。

在这里插入图片描述
我们需要一种统一配置管理方案,可以集中管理所有实例的配置。

Nacos一方面可以将配置集中管理,另一方可以在配置变更时,及时通知微服务,实现配置的热更新。

在这里插入图片描述

3-2. 统一配置管理

在nacos中添加配置

  1. 点击配置列表,添加新的配置信息

在这里插入图片描述

  1. 然后在弹出的表单中,填写配置信息

在这里插入图片描述
注意:项目的核心配置,需要热更新的配置才有放到nacos管理的必要。基本不会变更的一些配置还是保存在微服务本地比较好。

从微服务拉取配置

微服务要拉取nacos中管理的配置,并且与本地的application.yml配置合并,才能完成项目启动。

但如果尚未读取application.yml,又如何得知nacos地址呢?

因此springboot引入了一种新的配置文件:bootstrap.yml文件,它会在application.yml之前被读取,而且其内容优先级高于application.yml

在这里插入图片描述

  1. 引入nacos-config依赖

在user-service服务中,引入nacos-config的客户端依赖:

<!--nacos配置管理依赖-->
<dependency>
 	<groupId>com.alibaba.cloud</groupId>
 	<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
  1. 添加bootstrap.yml

在user-service中添加一个bootstrap.yml文件,内容如下:

spring:
  application:
    name: user-service
  cloud:
    nacos:
      config:
        server-addr: localhost:8848 # nacos 配置中心地址
        file-extension: yaml  # 文件扩展名

这里会根据spring.cloud.nacos.server-addr获取nacos地址,再根据
${spring.application.name}.${spring.cloud.nacos.config.file-extension}作为文件Data ID,来读取nacos的配置。
在这里插入图片描述

  1. 在代码中读取配置信息

在user-service中的UserController中添加业务逻辑,读取conf对象的相关配置

在这里插入图片描述

3-3. 配置热更新

我们最终的目的,是修改nacos中的配置后,微服务中无需重启即可让配置生效,也就是配置热更新

局部方式

使用@RefreshScope注解标注在使用配置信息的类上

在这里插入图片描述

全局方式

先使用@ConfigurationProperties注解将配置读取到一个对象上,然后在需要使用配置的类中注入配置对象

在这里插入图片描述

在这里插入图片描述

5. 远程调用 - Feign

5-1. Feign介绍

Feign是一个声明式的http客户端,它使得调用远程服务就像调用本地服务一样简单,只需要创建一个接口并添加一个注解即可。

其作用就是帮助我们优雅的实现http请求的发送,解决上面提到的问题。

而且Feign默认集成了Ribbon,所以使用Feign默认就实现了负载均衡的效果。

5-2. Feign使用

在这里插入图片描述

在这里插入图片描述

5-3. Feign优化

Feign底层发起http请求,依赖于其它的框架。其底层客户端实现包括:

  • URLConnection:默认实现,不支持连接池,每次请求都是新建连接

  • Apache HttpClient :支持连接池

  • OKHttp:支持连接池

因此提高Feign的性能主要手段就是使用连接池代替默认的URLConnection。

改用Apache的HttpClient

  1. 在order-service的pom文件中引入Apache的HttpClient依赖
<!--httpClient的依赖内置连接池 -->
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-httpclient</artifactId>
</dependency>
  1. 在order-service的application.yml中添加配置
feign:
  httpclient:
    enabled: true # 开启feign对HttpClient的支持
    max-connections: 200 # 设置最大的连接数
    max-connections-per-route: 50 # 并行接收一个服务的请求数量

6. 服务网关 - Gateway

在微服务架构中,一个系统会被拆分为很多个微服务。那么作为客户端要如何去调用这么多的微服务呢?

如果没有网关的存在,我们只能在客户端记录每个微服务的地址,然后分别去调用。

在这里插入图片描述

这样的架构,会存在着诸多的问题:

  • 客户端多次请求不同的微服务,增加客户端代码或配置编写的复杂性
  • 认证复杂,每个服务都需要独立认证。
  • 存在跨域请求,在一定场景下处理相对复杂。

上面的这些问题可以借助API网关来解决。所谓的API网关,就是指系统的统一入口。它封装了应用程序的内部结构,为客户端提供统一服务。

一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、路由转发等等。

添加上API网关之后,系统的架构图变成了如下所示:

在这里插入图片描述

在这里插入图片描述

配置文件

spring:
  cloud:
    gateway:
      routes: # 路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]
        - id: user-service-route # 当前路由的标识, 要求唯一
          uri: lb://user-service # 请求要转发到的地址
          predicates: # 断言(就是路由转发要满足的条件)
            - Path=/user/** # 当请求路径满足Path指定的规则时,才进行路由转发

6-1. 断言

断言用于进行条件判断(也就是在什么条件下才能进行路由转发),只有断言都返回真,才会真正的执行路由。

SpringCloud Gateway包括许多内置的断言工厂,所有这些断言都与HTTP请求的不同属性匹配。具体如下:

  • 基于Datetime类型的断言

    # AfterRoutePredicateFactory:   接收一个日期参数,判断请求日期是否晚于指定日期
    # BeforeRoutePredicateFactory:  接收一个日期参数,判断请求日期是否早于指定日期
    # BetweenRoutePredicateFactory: 接收两个日期参数,判断请求日期是否在指定时间段内
    - After=2019-12-31T23:59:59.789+08:00[Asia/Shanghai]
    
  • 基于远程地址的断言

    # RemoteAddrRoutePredicateFactory:接收一个IP地址段,判断请求主机地址是否在地址段中
    - RemoteAddr=192.168.1.1/24
    
  • 基于Cookie的断言

    # CookieRoutePredicateFactory:接收两个参数,cookie 名字和一个正则表达式。 判断请求cookie是否具有给定名称且值与正则表达式匹配。
    - Cookie=chocolate, ch. 
    
  • 基于Header的断言

    # HeaderRoutePredicateFactory:接收两个参数,标题名称和正则表达式。 判断请求Header是否具有给定名称且值与正则表达式匹配。
    - Header=X-Request-Id, \d+
    
  • 基于Host的断言

    # HostRoutePredicateFactory:接收一个参数,主机名模式。判断请求的Host是否满足匹配规则。
    - Host=**.testhost.org
    
  • 基于Method请求方法的断言

    # MethodRoutePredicateFactory:接收一个参数,判断请求类型是否跟指定的类型匹配。
    - Method=GET
    
  • 基于Path请求路径的断言

    # PathRoutePredicateFactory:接收一个参数,判断请求的URI部分是否满足路径规则。
    - Path=/foo/{segment}
    
  • 基于Query请求参数的断言

    # QueryRoutePredicateFactory :接收两个参数,请求param和正则表达式, 判断请求参数是否具有给定名称且值与正则表达式匹配。
    - Query=baz, ba.
    

内置断言的使用:

spring:
  cloud:
    gateway:
      routes: # 路由数组[路由 就是指定当请求满足什么条件的时候转到哪个微服务]
        - id: user-service-route # 当前路由的标识, 要求唯一
          uri: lb://user-service # 请求要转发到的地址
          predicates: # 断言(就是路由转发要满足的条件)
            - Path=/user/** # 当请求路径满足Path指定的规则时,才进行路由转发
            - Before=2019-11-28T00:00:00.000+08:00 # 限制请求时间在2019-11-28之前
            - Method=POST # 限制请求方式为POST

6-2. 过滤器

Gateway的过滤器会对请求或响应进行拦截,完成一些通用操作。在Gateway中, Filter的生效位置有两个:

  • PRE: 这种过滤器在请求被路由之前调用,可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等
  • POST:这种过滤器在路由到微服务以后执行,可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等

Gateway的Filter从作用范围可分为两种

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

自定义全局过滤器

//自定义SpringCloud gateway网关要求类必须实现两个接口
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    //处理拦截逻辑
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1. 获取token  (request.getParameter("token"))
        String token = exchange.getRequest().getQueryParams().getFirst("token");

        //状态码
        //200 成功
        //400 请求参数格式有误
        //401 未认证 
        //403 权限不足 
        //404 路径不存在
        //405 请求方式不匹配 
        //500 服务器错误
        
        //2. 校验token,如果失败,直返返回错误提示
        if (!"123".equals(token)) {
            //设置错误码 401
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); //resp.setStatus(401);
            //结束代码执行
            return exchange.getResponse().setComplete();
        } else {
            //3. 如果成功,放行
            return chain.filter(exchange);
        }
    }

    //这个方法的返回值用于过滤器排序, 返回的值越小, 优先越高, 越先执行
    @Override
    public int getOrder() {
        return 0;
    }
}

当过滤器的order值一样时,局部过滤器 优先级高于 全局过滤器

转载请标明出处: http://blog.csdn.net/forezp/article/details/70148833 本文出自方志朋的博客 错过了这一篇,你可能再也学不会 Spring Cloud 了!Spring Boot做为下一代 web 框架,Spring Cloud 作为最新最火的微服务的翘楚,你还有什么理由拒绝。赶快上船吧,老船长带你飞。终章不是最后一篇,它是一个汇总,未来还会写很多篇。 案例全部采用Spring Boot 1.5.x ,Spring Cloud版本为Dalston.RELEASE 我为什么这些文章?一是巩固自己的知识,二是希望有更加开放和与人分享的心态,三是接受各位大神的批评指教,有任何问题可以联系我: miles02@163.com . 码农下载:https://git.oschina.net/forezp/SpringCloudLearning github下载:https://github.com/forezp/SpringCloudLearning,记得star哦! 欢迎购买我的书《深入理解Spring Cloud与微服务构建》 1.jpg 京东购买 当当购买 亚马逊购买 CSDN专栏汇总:史上最简单的 SpringCloud 教程 《史上最简单的 SpringCloud 教程》系列: 史上最简单的 SpringCloud 教程 | 第一篇: 服务的注册与发现(Eureka) 史上最简单的SpringCloud教程 | 第二篇: 服务消费者(rest+ribbon) 史上最简单的SpringCloud教程 | 第三篇: 服务消费者(Feign) 史上最简单的SpringCloud教程 | 第四篇:断路器(Hystrix) 史上最简单的SpringCloud教程 | 第五篇: 路由网关(zuul) 史上最简单的SpringCloud教程 | 第六篇: 分布式配置中心(Spring Cloud Config) 史上最简单的SpringCloud教程 | 第七篇: 高可用的分布式配置中心(Spring Cloud Config) 史上最简单的SpringCloud教程 | 第八篇: 消息总线(Spring Cloud Bus) 史上最简单的SpringCloud教程 | 第九篇: 服务链路追踪(Spring Cloud Sleuth) 史上最简单的SpringCloud教程 | 第十篇: 高可用的服务注册中心 史上最简单的SpringCloud教程 | 第十一篇:docker部署spring cloud项目 史上最简单的SpringCloud教程 | 第十二篇: 断路器监控(Hystrix Dashboard) 史上最简单的SpringCloud教程 | 第十三篇: 断路器聚合监控(Hystrix Turbine) 史上最简单的 SpringCloud 教程 | 第十四篇: 服务注册(consul) 未完。。。 还有很多篇。。。 进阶篇 Spring Cloud Sleuth超详细实战 源码篇: 深入理解Feign之源码解析 深入理解Eureka之源码解析 深入理解Ribbon之源码解析 深入理解Hystrix之文档翻译 深入理解Zuul之源码解析 番外篇: 如何使用MongoDB+Springboot实现分布式ID? 如何在springcloud分布式系统中实现分布式锁? 如何用Redlock实现分布式锁 如何在IDEA启动多个Spring Boot工程实例 JWT如何在Spring Cloud微服务系统中在服务相互调时传递
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值