微服务开发

目录

认识微服务

注册中心

Eureka注册中心

Nacos注册中心

配置中心

Feign远程调用

服务网关

微服务保护

流量控制

FeignClient整合Sentinel

线程隔离配置

熔断降级

授权规则


认识微服务

单体架构:将业务的所有功能集中在一个项目中开发,打成一个包部署。架构简单,部署成本低,耦合度高。

分布式架构:根据业务功能对系统进行拆分,每个业务模块作为独立项目开发,称为一个服务。降低服务耦合,有利于服务升级拓展。但服务调用关系错综复杂,运维、监控、部署难度提高。

服务治理:服务拆分粒度如何? 服务集群地址如何维护? 服务之间如何实现远程调用? 服务健康状态如何感知?

微服务架构特征:

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

SpringCloud是目前国内使用最广泛的微服务框架。 SpringCloud集成了各种微服务功能组件,并基于SpringBoot实现了这些组件的自动装配,从而提供了良好的开箱即用体验。

注册中心

Eureka注册中心

eureka的作用:

 无论是消费者还是提供者,引入eureka-client依赖、知道eureka地址后,都可以完成服务注册

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
spring:
  application:
    name: userservice
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka

 在order-service完成服务拉取,要去eureka-server中拉取user-service服务的实例列表,并且实现负载均衡。

#给RestTemplate这个Bean添加一个@LoadBalanced注解
 @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

负载均衡策略

userservice:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule# 负载均衡规则

开启饥饿加载

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

Nacos注册中心

Nacos是阿里巴巴的产品,现在是SpringCloud中的一个组件。相比Eureka功能更加丰富,在国内受欢迎程度较高。

服务注册到Nacos:

在cloud-demo父工程中添加spring-cloud-alilbaba的管理依赖

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.5.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

添加nacos客户端依赖

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

配置服务端地址

spring:
    cloud:
      nacos:
        server-addr: 127.0.0.1:8848 # nacos服务地址

Nacos服务分级存储模型:

一级是服务,例如userservice

二级是集群,例如杭州或上海

三级是实例,例如杭州机房的某台部署了userservice的服务器 

Nacos中服务存储和数据存储的最外层都是一个名为namespace的东西,用来做最外层隔离,例如:dev,sit,不同namespace下的服务互相不可见

nacos注册中心细节

Nacos与Eureka的区别:

  1. Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式
  2. 临时实例心跳不正常会被剔除,非临时实例则不会被剔除
  3. Nacos支持服务列表变更的消息推送模式,服务列表更新更及时
  4. Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式;Eureka采用AP方式

配置中心

将配置交给Nacos管理的步骤:

  1. 在Nacos中添加配置文件
  2. 在微服务中引入nacos的config依赖
             <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            </dependency>

  3. 在微服务中添加bootstrap.yml,配置nacos地址、当前环境、服务名称、文件后缀名。这些决定了程序启动时去nacos读取哪个文件
    spring:
      application:
        name: userservice
      profiles:
        active: dev # 环境
      cloud:
        nacos:
          server-addr: localhost:8848 # nacos地址
          config:
            file-extension: yaml # 文件后缀名

  4. Nacos配置更改后,微服务可以实现热更新,方式: 通过@Value注解注入,结合@RefreshScope来刷新;或通过@ConfigurationProperties注入,自动刷新。注意事项: 不是所有的配置都适合放到配置中心,维护起来比较麻烦,建议将一些关键参数,需要运行时调整的参数放到nacos配置中心,一般都是自定义配置

    @Data
    @Component
    @ConfigurationProperties(prefix = "pattern")
    public class PatternProperties {
        private String dateformat;
    }

 多种配置的优先级

nacos集群搭建步骤:

  • 搭建MySQL集群并初始化数据库表
  • 下载解压nacos
  • 修改集群配置(节点信息)、数据库配置
  • 分别启动多个nacos节点
  • nginx反向代理 

Feign远程调用

Feign是一个声明式的http客户端,官方地址:https://github.com/OpenFeign/feign 其作用就是帮助我们优雅的实现http请求的发送,解决RestTemplate方式调用存在的问题。使用Feign的步骤如下:

1、引入依赖

        <!--feign客户端依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

2、在order-service的启动类添加注解开启Feign的功能

@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
@EnableFeignClients(clients = UserClient.class,defaultConfiguration = DefaultFeignConfiguration.class)
public class OrderApplication {

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

 3、编写Feign客户端

@FeignClient(value = "userservice")
public interface UserClient {

    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id);
}

4、用Feign客户端代替RestTemplate

    @Autowired
    private UserClient userClient;

    public Order queryOrderById(Long orderId) {
        // 1.查询订单
        Order order = orderMapper.findById(orderId);
        // 2.用Feign远程调用
        User user = userClient.findById(order.getUserId());
        // 3.封装user到Order
        order.setUser(user);
        // 4.返回
        return order;
    }

 5、默认不支持连接池,配置Feign添加HttpClient的支持

        <!--引入HttpClient依赖-->
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
        </dependency>
feign:
  httpclient:
    enabled: true # 支持HttpClient的开关
    max-connections: 200 # 最大连接数
    max-connections-per-route: 50 # 单个路径的最大连接数

服务网关

网关功能: 身份认证和权限校验、服务路由、负载均衡、请求限流。

Zuul是基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。搭建网关服务的步骤:

1、引入SpringCloudGateway的依赖和nacos的服务发现依赖

        <!--nacos服务注册发现依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--网关gateway依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>

2、编写路由配置及nacos地址,这里只配置了路径断言,按照路径规则匹配

server:
  port: 10010
spring:
  application:
    name: gateway
  cloud:
    nacos:
      server-addr: http://localhost/nacos # nacos地址
    gateway:
      routes:
        - id: user-service # 路由标示,必须唯一
          uri: lb://userservice # 路由的目标地址
          predicates: # 路由断言,判断请求是否符合规则
            - Path=/user/** # 路径断言,判断路径是否是以/user开头,如果是则符合
        - id: order-service
          uri: lb://orderservice
          predicates:
            - Path=/order/**
      default-filters:# 默认过滤器,会对所有的路由请求都生效
        - AddRequestHeader=Truth,Itcast is freaking awesome!# 添加请求头

 3、GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理。Spring提供了31种不同的路由过滤器工厂。

 4、全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。 区别在于GatewayFilter通过配置定义,处理逻辑是固定的。而GlobalFilter的逻辑需要自己写代码实现。 定义方式是实现GlobalFilter接口。

@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 1.获取请求参数
        ServerHttpRequest request = exchange.getRequest();
        MultiValueMap<String, String> params = request.getQueryParams();
        // 2.获取参数中的 authorization 参数
        String auth = params.getFirst("authorization");
        // 3.判断参数值是否等于 admin
        if ("admin".equals(auth)) {
            // 4.是,放行
            return chain.filter(exchange);
        }
        // 5.否,拦截
        // 5.1.设置状态码
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        // 5.2.拦截请求
        return exchange.getResponse().setComplete();
    }

    @Override
    public int getOrder() {
        return -1;//每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前
    }
}

5、限流过滤器

对应用服务器的请求做限制,避免因过多请求而导致服务器过载甚至宕机。限流算法常见的包括两种:

  • 计数器算法,又包括窗口计数器算法、滑动窗口计数器算法:将时间划分为多个窗口; 在每个窗口内每有一次请求就将计数器加一,当时间到达下一个窗口时,计数器重置。 如果计数器超过了限制数量,则本窗口内所有的请求都被丢弃
  • 漏桶算法(Leaky Bucket):将每个请求视作"水滴"放入"漏桶"进行存储;"漏桶"以固定速率向外"漏"出请求来执行,如果"漏桶"空了则停止"漏水”;如果"漏桶"满了则多余的"水滴"会被直接丢弃
  • 令牌桶算法(Token Bucket) :以固定的速率生成令牌,存入令牌桶中,如果令牌桶满了以后,多余令牌丢弃;请求进入后,必须先尝试从桶中获取令牌,获取到令牌后才可以被处理;如果令牌桶中没有令牌,则请求等待或丢弃

微服务保护

雪崩问题:服务提供者I发生了故障,依赖服务I的业务请求被阻塞,越来越多的用户请求到来,越来越多的tomcat线程会阻塞,会导致服务器资源耗尽,从而导致所有其它服务都不可用,那么当前服务也就不可用了。依赖于当前服务的其它服务随着时间的推移,最终也都会变的不可用,形成级联失败,雪崩就发生了

解决雪崩问题的常见方式有四种:

  • 超时处理:设定超时时间,请求超过一定时间没有响应就返回错误信息,不会无休止等待
  • 仓壁模式:限定每个业务能使用的线程数,避免耗尽整个tomcat的资源,因此也叫线程隔离
  • 断路器模式:由断路器统计业务执行的异常比例,如果超出阈值则会熔断该业务,拦截访问该业务的一切请求。 
  • 流量控制:限制业务访问的QPS,避免服务因流量的突增而故障。

限流是对服务的保护,避免因瞬间高并发流量而导致服务故障,进而避免雪崩。是一种预防措施。超时处理、线程隔离、降级熔断是在部分服务故障时,将故障控制在一定范围,避免雪崩。是一种补救措施。

Sentinel是阿里巴巴开源的一款微服务流量控制组件。

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

先运行java -Dserver.port=8080 -jar sentinel-dashboard-1.8.1.jar ,访问http://localhost:8080页面,就可以看到sentinel的控制台了,账号和密码,默认都是:sentinel,然后在需接入的微服务中引入sentinel依赖和修改yaml配置,访问微服务的任意端点即可触发sentinel的监控

<dependency>
    <groupId>com.alibaba.cloud</groupId> 
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
server:
  port: 8088
spring:
  cloud: 
    sentinel:
      transport:
        dashboard: localhost:8080

流量控制

默认情况下sentinel会监控SpringMVC的每一个端点(Endpoint,也就是controller中的方法),因此SpringMVC的每一个端点(Endpoint)就是调用链路中的一个资源。流控、熔断等都是针对簇点链路中的资源来设置的,因此我们可以点击对应资源后面的按钮来设置规则。

流控模式:

  • 直接:对当前资源限流
  • 关联:高优先级资源触发阈值,对低优先级资源限流。
  • 链路:阈值统计时,只统计从指定资源进入当前资源的请求,是对请求来源的限流

流控效果:

  • 快速失败:达到阈值后,新的请求会被立即拒绝并抛出FlowException异常。是默认的处理方式。
  • warm up:预热模式,对超出阈值的请求同样是拒绝并抛出异常。但这种模式阈值会动态变化,从一个较小值逐渐增加到最大阈值。
  • 排队等待:让所有的请求按照先后次序排队执行,两个请求的间隔不能小于指定时长

 

 

 

FeignClient整合Sentinel

微服务远程调用都是基于Feign来完成的,因此我们需要将Feign与Sentinel整合,在Feign里面实现线程隔离和服务熔断。

Feign整合Sentinel的步骤:

  • 在application.yml中配置:feign.sentienl.enable=true
  • 给FeignClient编写失败降级逻辑FallbackFactory并注册为Bean
  • 将FallbackFactory配置到FeignClient

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

@Slf4j
public class UserClientFallbackFactory implements FallbackFactory<UserClient> {
    @Override
    public UserClient create(Throwable throwable) {
        return new UserClient() {
            @Override
            public User findById(Long id) {
                log.error("查询用户异常", throwable);
                return new User();
            }
        };
    }
}

@Bean
public UserClientFallbackFactory userClientFallbackFactory(){
    return new UserClientFallbackFactory();
}
@FeignClient(value = "userservice", fallbackFactory = UserClientFallbackFactory.class)
public interface UserClient {

    @GetMapping("/user/{id}")
    User findById(@PathVariable("id") Long id);
}

线程隔离配置

 

熔断降级

熔断降级是解决雪崩问题的重要手段。其思路是由断路器统计服务调用的异常比例、慢请求比例,如果超出阈值则会熔断该服务。即拦截访问该服务的一切请求;而当服务恢复时,断路器会放行访问该服务的请求。断路器控制熔断和放行是通过状态机来完成的,断路器熔断策略有三种:慢调用、异常比例、异常数。

状态机包括三个状态:

  • closed:关闭状态,断路器放行所有请求,并开始统计异常比例、慢请求比例。超过阈值则切换到open状态
  • open:打开状态,服务调用被熔断,访问被熔断服务的请求会被拒绝,快速失败,直接走降级逻辑。Open状态5秒后会进入half-open状态
  • half-open:半开状态,放行一次请求,根据执行结果来判断接下来的操作。请求成功:则切换到closed状态,请求失败:则切换到open状态

授权规则

可以对调用方的来源做控制,有白名单和黑名单两种方式。

  • 白名单:来源(origin)在白名单内的调用者允许访问
  • 黑名单:来源(origin)在黑名单内的调用者不允许访问

 

 

规则持久化:

sentinel的所有规则都是内存存储,重启后所有规则都会丢失。在生产环境下,我们必须确保这些规则的持久化,避免丢失。规则是否能持久化,取决于规则管理模式,sentinel支持三种规则管理模式:

  • 原始模式:Sentinel的默认模式,将规则保存在内存,重启服务会丢失。
  • pull模式:控制台将配置的规则推送到Sentinel客户端,而客户端会将配置规则保存在本地文件或数据库中。以后会定时去本地文件或数据库中查询,更新本地规则
  • push模式:控制台将配置规则推送到远程配置中心,例如Nacos。Sentinel客户端监听Nacos,获取配置变更的推送消息,完成本地配置更新

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值