springcloud微服务搭建

简单的springcloud(采用的版本为:Finchley.RELEASE  springboot版本为:2.0.3.RELEASE):

1.创建注册中心Eureka-server  

1.1:需要的pom坐标:

   <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>

         </dependency>

        1.2:在启动类上加注解:

         @EnableEurekaServer :标识是一个注册中心

        1.3:添加配置文件  application.yml/application.properties

server:

     port: 8761 #注册中心端口号

eureka:

  instance:

    hostname: localhost

  client:

    #声明自己是一个服务

    registerWithEureka: false

    fetchRegistry: false

    serviceUrl: #注册中心地址

      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

注:注册中心完成

2.创建客户端(消费者,一个简单的客户端):

2.1:需要的pom坐标:

<dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>

        </dependency>

    2.2:启动类添加注解:

     @EnableEurekaClient (注:这个注解可加可不加不影响) 声明这是一个客户端(消费着)

    2.3:修改配置文件:

     server:

  port: 8771 #客户端的端口号

eureka:

  client:

    service-url:

      defaultZone: http://localhost:8761/eureka/ #指定注册中心的地址

spring:

  application:

    name: product-client #客户端的名称,必选项,注册中心需要用到,注册中心使用的就是此名称

3.客户端间的调用:

3.1:选择feign和ribbon feign中已经集成好了ribbon.  所以选择feign

3.1.1:导入feign对应的pom坐标

<dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-openfeign</artifactId>

        </dependency>

        3.1.2:如果是ribbon的话,对应的pom坐标

          <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>

        </dependency>

    3.1.2.1:还需要在启动类中注入一个Bean,用于调用其他服务并开启负载均衡策略

     @Bean

    @LoadBalanced

    public RestTemplate restTemplate(){

        return new RestTemplate();

    }

3.1.2.2:调用方式:

a.注入RestTemplate类。

b.使用RestTemplate调用对应的方法。

注:底层可查看@LoadBalanced。实际使用的是LoadBalancerClient这个类。内部通过这个去注册中心查找到对应的服务的所有节点,然后根据对应的负载均衡策略进行选择节点。然后返回给最外层,也就是选择好某个节点后进行调用,默认的负载均衡策略是轮询策略。可以配置负载均衡策略。配置完成后使用feign同样生效

#自定义负载均衡策略

product-client: #服务名称

  ribbon:

    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule  随机策略可查看IRule类的子类。

注:ribbon的默认超时时间为: 60秒

设置ribbon的超时和重试设置

ribbon:

  ReadTimeout: 3000

  ConnectTimeout: 3000

  MaxAutoRetries: 1 #同一台实例最大重试次数,不包括首次调用

  MaxAutoRetriesNextServer: 1 #重试负载均衡其他的实例最大重试次数,不包括首次调用

  OkToRetryOnAllOperations: false  #是否所有操作都重试  慎用

根据上面的参数计算重试的次数:MaxAutoRetries+MaxAutoRetriesNextServer+(MaxAutoRetries *MaxAutoRetriesNextServer) 即重试3次 则一共产生4次调用

如果在重试期间,时间超过了hystrix的超时时间,便会立即执行熔断,fallback。所以要根据上面配置的参数计算hystrix的超时时间,使得在重试期间不能达到hystrix的超时时间,不然重试机制就会没有意义

 

hystrix超时时间的计算: (1 + MaxAutoRetries + MaxAutoRetriesNextServer) * ReadTimeout 即按照以上的配置 hystrix的超时时间应该配置为 (1+1+1)*3=9秒

 

Hystrix的超时计算规则应该是 Hystrix的超时时间=Ribbon的重试次数(包含首次)*(ribbon.ReadTimeout+ribbon.ConnectTimeout),如果以你的配置为例Hystrix的超时配置应该是=4*(3000+3000)=24000,即24秒。

 

当ribbon超时后且hystrix没有超时,便会采取重试机制。当OkToRetryOnAllOperations设置为false时,只会对get请求进行重试。如果设置为true,便会对所有的请求进行重试,如果是put或post等写操作,如果服务器接口没做幂等性,会产生不好的结果,所以OkToRetryOnAllOperations慎用。

 

如果不配置ribbon的重试次数,默认会重试一次

注意:

默认情况下,GET方式请求无论是连接异常还是读取异常,都会进行重试

非GET方式请求,只有连接异常时,才会进行重试

 

3.1.3:使用feign调用接口(基于接口实现feign);

a.创建一个接口类,在接口类上加注解@FeignClient然后值有name 和 fallback   name:是需要调用的服务的名称

 fallback:失败的回调(熔断处理,相当于家里的用电,当用电到达某一阈值,电路就会自动跳闸,从而保护整个电路。),失败的一个降级处理。写的是一个类。每一个方法对应一个方法,此方法参数类型和返回值必须和接口的一样。如果使用feign调用的接口失败了,则会进入这个方法,可以在内部进行一些操作并且返回一些虚拟数据,保证后续服务不会崩溃(解决雪崩效应)。

b.使用feign调用接口的时候,如果有参数 基本类型传递使用@RequestParm   如果是对象的话,要使用@RequestBody传递。

注:使用Feign调用接口分两层,ribbon的调用和hystrix的调用,所以ribbon的超时时间和Hystrix的超时时间的结合就是Feign的超时时间。一般情况下都是ribbon的超时时间(<)hystrix的超时时间(因为涉及到ribbon的重试机制因为ribbon的重试机制和Feign的重试机制有冲突,所以源码中默认关闭Feign的重试机制。

hystrix的默认超时时间是一秒,配置了hystrix的超时时间必须还要配置ribbon的超时时间,否则会有问题。

在使用 Ribbon 时,只需要配置 Hystrix 的超时时间就可以生效,不需要额外配置 Ribbon 的超时时间

 

记录一个异常,就是第一次启动完成后,调用服务的时候总是在第一次出现超时的情况。这是因为懒加载的特性,在第一次用到的时候才去加载一些东西。而加载这些东西需要耗时,可能耗时的时候就已经出发了熔断/降级处理。

解决办法有两种   1.设置超时时间:全局设置超时时间为60秒

 hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 60000

 # 设置ribbon超时时间

 ribbon:

   ReadTimeout: 20000

   ConnectTimeout: 20000

 2. 配置立即加载。不过还需要配置所有的客户端服务

  ribbon:

    eager-load:

        enabled: true

        clients: distribution, material-product, outer-data  #客户端服务

3.2:引入Hystrix(断路器,熔断)

a.引入所需要的pom坐标文件

<dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>

        </dependency>

    b.启动类开启断路器,加注解//@EnableHystrix

@EnableCircuitBreaker   这两个都可以,上边的注解里包含了下边的注解。标识启用断路器功能。

c.配置文件配置断路器。需要配置表示feign开启hystrix  和  hystrix的超时时间配置。hystrix的默认超时时间时1秒。

feign:

#开启断路器

  hystrix:

    enabled: true

#修改调用超时时间

  client:

    config:

      default:

        connectTimeout: 3000

        readTimeout: 2000

 

#修改hystrix的调用超时时间配置

hystrix:

  command:

    default:

      execution:

        isolation:

          thread:

            timeoutInMilliseconds: 4000

d.使用:

1. 在方法上加注解@HystrixCommand key有fallbackMethod  表示出现异常时要熔断的方法。

ps:访问该接口时报错了或者超时了,会进入fallbackMethod设置的对应的方法内部。进行一些记录操作返回一些给用户的提示等操作。

注:1.feign/ribbon的超时时间一定要大于hystrix的超时时间,因为只要访问到接口,feign/ribbon 和 hystrix 的计时器就会同步启动,去计算。如果没有到达feign/ribbon的超时时间,但是到达了hystrix的超时时间,尽管没有报错,但是还是会进入的hystrix的熔断方法。  

2.设置的fallbackMethod的方法的请求参数和返回结果要和@HystrixCommand标记的接口的一致,否则会出问题。

3.3:引入hystrix仪表盘 hystrix-dashboard。一个健康检查。

hystrix dashboard 仪表盘解释:健康检查监控hystrix的各项指标信息,检查接口调用的成功与失败记录等信息,如果失败率超过50%,会开启熔断,后续请求将不会请求接口。

a:引入pom文件:

<dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>

        </dependency>

        <!-- 此依赖是打开 Actuator 作用 -->

        <dependency>

            <groupId>org.springframework.boot</groupId>

            <artifactId>spring-boot-starter-actuator</artifactId>

        </dependency>

    b.启动类加注解:

     @EnableHystrixDashboard

    c.配置文件增加endpoint,开启所有访问权限,放行了所有端点,(这样貌似不安全,默认 Actuator 只暴露了2个端点,heath 和 info)

management:

  endpoints:

    web:

      exposure:

        include: "*"

注:这个是用来暴露 Actuator 的所有端点的,这一点很重要,不配置你的 Hystrix Dashboard 会出现 Unable to connect to Command Metric Stream 的问题

d.访问入口

     http://localhost:8781/hystrix

 

     Hystrix Dashboard输入: http://localhost:8781/actuator/hystrix.stream

 

3.4:引入链路追踪:seluth,其主要作用是做一个日志的埋点,出现错误时可以根据日志的埋点id找到对应的信息/报错位置。Sleuth可以与日志框架Logback、SLF4J轻松地集成,

a.引入pom文件

<dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-sleuth</artifactId>

        </dependency>

    b.配置文件:

     spring:

  #配置采样百分比,开发环境可以设置为1,表示全部,生产就用默认(比如请求100次我记录百分之多少/多少次。1代表全部,根据实际情况调节)

  sleuth:

    sampler:

      probability: 1

    b. 集成可直接使用,但是需要加log否则控制台不会输出日志,本示例使用的是log4j

     private final Logger log = LoggerFactory.getLogger(getClass());

     log.info("查询商品");

    c.输出的格式

2020-03-26 16:32:08.117  INFO [product-client,1371c3a83b9b13a5,6ac4a8cc3fbbfa12,true] 1812 --- [nio-8772-exec-2] t.o.p.controller.ProductController: findProductById

2020-03-26 16:32:08.117  INFO [product-client,1371c3a83b9b13a5,6ac4a8cc3fbbfa12,true] 1812 --- [nio-8772-exec-2] t.o.product.service.ProductServiceImpl: 查询商品

解释:[]中第一个标识服务的名称,第二个标识本次请求的id唯一标识(一个请求分配的ID号,用来标识一条请求链路。),第三个标识一个工作的基本单元,一个请求可以又多个步骤,而第三个标识每一个步骤。第四个表示  是否要将该信息输出到类似Zipkin这样的聚合器进行收集和展示。

 

3.5:引入zipkin,上边所提到的聚合器,这里用于手机每次请求链路追踪所产生的记录,都在该组件内存在。

a.引入pom文件:

<!--其中已经包含了链路追踪seluth-->

        <dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-zipkin</artifactId>

        </dependency>

    b.配置文件:

     spring:

  #zipkin服务所在地址

  zipkin:

    base-url: http://www.oyygke.top:9411/ #该地址表示zipkin所在地址

c.使用:

集成好sleuth和zipkin之后,进行发送请求,然后访问上边配置的zipkin的地址,就会看到请求记录。点击可查看详情--整个请求的链路是怎么走的。

 

3.6:引入网关zuul

a.引入pom文件

<dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>

        </dependency>

    b.添加注解,开启网关

     @EnableZuulProxy

    c.作用

    使用网关进行过滤和请求转发的作用,经过网关转发到某服务。

    d.配置文件

    zuul:

  routes:

    #相当于oyygke映射到order-client

    order-client: /oyygke/order/**

    product-client: /oyygke/product/**

  #忽略product-client,不经过网关

#  ignored-services: product-client

  #只使用一种方式进行访问,过滤以client结尾的服务

  ignored-patterns: /*-client/**

  #处理http请求头为空的问题

  sensitive-headers:

ribbon: #添加请求超时设置,如果不配置,默认第一次访问会进入到熔断的超时处理机制。因为可能还没有加载到,第一次加载需要时间,所以需要添加超时时间设置。

  ReadTimeout: 6000

  ConnectTimeout: 6000

e.使用过滤

i.新建类继承ZuulFilter,实现其中的方法。相当于一个配置类,记得添加@component。还可以进行限流处理,

//令牌桶  每秒产生多少个令牌   这个需要进行压测确定可以有多少个令牌

    //令牌需要配置到配置文件中更改   多少个网管就是  总数/网关数量

    //guava谷歌的框架 限流

    private static final RateLimiter RATE_LIMITER = RateLimiter.create(100);

工具类:HttpStatus.TOO_MANY_REQUESTS.value()  //表示请求过多。

示例:过滤token,表示   如果访问该接口没有token则过滤掉直接返回对应的错误提示信息。

@Component

public class LoginFilter extends ZuulFilter {

    /**

     * 过滤器的类型   前置还是后置

     * @return

     */

    @Override

    public String filterType() {

        return PRE_TYPE; //表示请求接口前执行

    }

    /**

     * 过滤器的一个级别  越小越先执行

     * @return

     */

    @Override

    public int filterOrder() {

        return 4;

    }

    /**

     * 是否进行过滤

     * @return

     */

    @Override

    public boolean shouldFilter() {

        //全局的上下文对象

        RequestContext context = RequestContext.getCurrentContext();

        HttpServletRequest request = context.getRequest();

        //如果请求路径包含order,则需要进行过滤验证

        if(request.getRequestURI().contains("/order/")){

            return true;

        }

        return false;

    }

    /**

     * 业务逻辑

     * @return

     * @throws ZuulException

     */

    @Override

    public Object run() throws ZuulException {

        RequestContext context = RequestContext.getCurrentContext();

        HttpServletRequest request = context.getRequest();

 

        String token = request.getHeader("token");

        if(StringUtils.isBlank(token)){

            token = request.getParameter("token");

        }

        if(StringUtils.isBlank(token)){

            context.setSendZuulResponse(false);

            context.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());

        }

        return null;

    }

}

 

 

3.7:配置中心  config-server/config-client

a.先搭建配置中心服务,config-server    配置中心可以使用   git、码云等

b.product-client-dev.yml  配置中心的文件名采用  服务名-后缀命名。dev/test等

c.pom文件引入:

<dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-config-server</artifactId>

        </dependency>

    d.@EnableConfigServer  表示这是一个配置服务中心

    e.配置文件

     spring:

  application:

    name: config-server  #服务名称

  cloud:

    config:

      server:

        git:

          uri: https://gitee.com/xc-rong/spring-cloud.git  #码云的项目地址

          username: xxx  #码云账号

          password: xxx #码云密码

          timeout: 5

          default-label: master #使用哪个分支的

f.修改原有服务为配置中心的客户端  config-client

i.引入pom文件

<dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-config-client</artifactId>

        </dependency>

    ii.修改原有的application.yml为bootstrap.yml /bootstrap.properties

    iii.修改配置文件

     spring:

  application:

    name: order-client #服务名称

  cloud:

    config:

      discovery:

        enabled: true #开启通过服务访问config-server的功能

        service-id: CONFIG-SERVER #配置中心的服务名

      #后缀 一个区分  指定环境

      profile: dev

      #分支的区分,指定分支

      label: master

iiii. 将一些配置文件的内容放到填写的码云/git仓库上。项目启动的时候会从仓库拉去配置文件。

注:到此配置完成,可以启动项目进行查看日志

g.配置消息总线,用于动态拉取配置,(表示 在码云/git仓库更改配置文件之后,动态拉取不需要重启项目,但是线下可以这样,线上的话不建议这样,因为没办法观察是否拉取到了最新的配置文件)

i:引入pom文件

<dependency>

            <groupId>org.springframework.cloud</groupId>

            <artifactId>spring-cloud-starter-bus-amqp</artifactId>

        </dependency>

    ii.配置文件添加mq

     spring:

  application:

    name: product-client

  rabbitmq:

    host: www.oyygke.top

    port: 5672

    username: guest

    password: guest

    ii.添加注解,在需要动态更新配置的地方添加注解 @RefreshScope

    iii.至此代码中的内容添加完毕。动态更新的话需要手动的访问一个地址进行拉取最新配置

     http://localhost:2009/refresh    #表示每个服务的ip+端口号+refresh 进行刷新,每次只刷新一个服务,多个服务需要调用多次,而且该接口只支持post请求,get请求不支持。

 

    注:必须要有这个pom

    <!--开启监控功能-->

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-actuator</artifactId>

</dependency>

 

 

4.完成以后可能会出现的小问题。

注册中心每个服务的地址可能不是ip+端口号  可能是一串字母+端口号  这样放到线上是有问题的,需要在配置文件中在加下配置,使注册中心的地址是ip+端口号

解决办法:

eureka:

  client:

    service-url:

      defaultZone: http://localhost:8761/eureka/

  instance:

    instance-id: ${spring.cloud.client.ip-address}:${server.port} #表示每个服务的ip示自定义id,ip+端口号格式

    prefer-ip-address: true #将IP注册到Eureka Server上

 

posted @ 2020-06-16 00:06  筱荣  阅读(299)  评论(0编辑  收藏  举报