zoukankan      html  css  js  c++  java
  • idea搭建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上

  • 相关阅读:
    剑指Offer(Java版)第五十题:牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志, 写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看, 但却读不懂它的意思。例如,“student. a am I”
    剑指Offer(Java版)第四十九题:汇编语言中有一种移位指令叫做循环左移(ROL), 现在有个简单的任务,就是用字符串模拟这个指令的运算结果。 对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。 例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果, 即“XYZdefabc”。是不是很简单?OK,搞定它!
    【转载】Java 内存分配全面浅析
    【记】Linux下安装JDK1.7
    【ZooKeeper】典型应用场景概览
    正则表达式工具RegexBuddy
    【基础】RandomAccess
    【JNDI】Java Naming and Directory Interface
    【AOP】Cglib动态代理实现方式
    【事务】分布式事物原理
  • 原文地址:https://www.cnblogs.com/rrong/p/13138677.html
Copyright © 2011-2022 走看看