• springCloud基本使用


    简介

    SpringCloud是Spring旗下的项目之一,官网地址:http://projects.spring.io/spring-cloud/

    Spring最擅长的就是集成,把世界上最好的框架拿过来,集成到自己的项目中。

    SpringCloud也是一样,它将现在非常流行的一些技术整合到一起,实现了诸如:配置管理,服务发现,智能路由,负载均衡,熔断器,控制总线,集群状态等等功能。其主要涉及的组件包括:

    • Eureka:服务治理组件,包含服务注册中心,服务注册与发现机制的实现。(服务治理,服务注册/发现)
    • Zuul:网关组件,提供智能路由,访问过滤功能
    • Ribbon:客户端负载均衡的服务调用组件(客户端负载)
    • Feign:服务调用,给予Ribbon和Hystrix的声明式服务调用组件 (声明式服务调用)
    • Hystrix:容错管理组件,实现断路器模式,帮助服务依赖中出现的延迟和为故障提供强大的容错能力。(熔断、断路器,容错)

    因为Spring Cloud不同其他独立项目,它拥有很多子项目的大项目。所以它的版本是版本名+版本号 (如Angel.SR6)。

    版本名:是伦敦的地铁名

    版本号:SR(Service Releases)是固定的 ,大概意思是稳定版本。后面会有一个递增的数字。

    所以 Edgware.SR3就是Edgware的第3个Release版本。

    入门

    Eureka注册中心

    首先建立一个提供者 一个调用者 和一个eureka注册中心

    首先搭建eureka注册中心

    pom.xml 文件配置

    
        <properties>
            <java.version>1.8</java.version>
            <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
        </properties>
    
        <dependencies>
            <!--配置eureka服务-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
    
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
                <exclusions>
                    <exclusion>
                        <groupId>org.junit.vintage</groupId>
                        <artifactId>junit-vintage-engine</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring-cloud.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
    

    编写application.properties配置

    # 指定端口号
    server.port=8081
    
    # 指定服务名称
    spring.application.name=ithiem-eureka
    eureka.instance.hostname=127.0.0.1 
    # 指定注入地址
    eureka.client.service-url.defaultZone= http://${eureka.instance.hostname}:8081/eureka/
    # 此应用为注册中心,false:不向注册中心注册自己。
    eureka.client.register-with-eureka=false
    
    # 注册中心职责是维护服务实例,false:不检索服务。
    eureka.client.fetch-registry=false
    

    修改引导类,在类上添加@EnableEurekaServer注解:

    @SpringBootApplication
    @EnableEurekaServer //开启Eureka服务器
    public class ItheimServiceEurekaApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ItheimServiceEurekaApplication.class, args);
        }
    
    }
    

    将提供者和调用者添加到eureka中

    注册服务,就是在服务上添加Eureka的客户端依赖,客户端代码会自动把服务注册到EurekaServer中。

    修改itcast-service-provider工程

    1. 在pom.xml中,添加springcloud的相关依赖。
    2. 在application.yml中,添加springcloud的相关依赖。
    3. 在引导类上添加注解,把服务注入到eureka注册中心。

    具体操作

    pom.xml配置

    <dependency>
         <!--添加springCloud客户端依赖-->
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    
     <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>${spring-cloud.version}</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
     </dependencyManagement>
    
    

    application.properties配置文件

    server.port=8084
    spring.datasource.url=jdbc:mysql://localhost:3306/heim?serverTimezone=GMT
    spring.datasource.username=root
    spring.datasource.password=root
    mybatis.type-aliases-package=com.itheim.service.pojo
    #名称
    spring.application.name=service-provider
    # 服务器位置
    eureka.client.service-url.defaultZone=http://127.0.0.1:8081/eureka
    

    注意:

    • 这里我们添加了spring.application.name属性来指定应用名称,将来会作为应用的id使用。

    客户端引导类

    在引导类上开启Eureka客户端功能

    通过添加@EnableDiscoveryClient来开启Eureka客户端功能

    @SpringBootApplication
    @MapperScan("com.itheim.service.mapper")
    @EnableDiscoveryClient
    public class ItheimServiceProviderApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ItheimServiceProviderApplication.class, args);
        }
    
    }
    

    .从Eureka获取服务

    接下来我们修改itcast-service-consumer,尝试从EurekaServer获取服务。

    方法与消费者类似,只需要在项目中添加EurekaClient依赖,就可以通过服务名称来获取信息了!
    修改UserController代码,用DiscoveryClient类的方法,根据服务名称,获取服务实例:

    @Controller
    @RequestMapping("consumer/user")
    public class UserController {
    
        @Autowired
        private RestTemplate restTemplate;
    
        @Autowired
        private DiscoveryClient discoveryClient; // eureka客户端,可以获取到eureka中服务的信息
    
        @GetMapping
        @ResponseBody
        public User queryUserById(@RequestParam("id") Long id){
            // 根据服务名称,获取服务实例。有可能是集群,所以是service实例集合
            List<ServiceInstance> instances = discoveryClient.getInstances("service-provider");
            // 因为只有一个Service-provider。所以获取第一个实例
            ServiceInstance instance = instances.get(0);
            // 获取ip和端口信息,拼接成服务地址
            String baseUrl = "http://" + instance.getHost() + ":" + instance.getPort() + "/user/" + id;
            User user = this.restTemplate.getForObject(baseUrl, User.class);
            return user;
        }
    
    }
    

    Eureka详解

    接下来我们详细讲解Eureka的原理及配置。

    5.4.1.基础架构

    Eureka架构中的三个核心角色:

    • 服务注册中心

      Eureka的服务端应用,提供服务注册和发现功能,就是刚刚我们建立的itcast-eureka。

    • 服务提供者

      提供服务的应用,可以是SpringBoot应用,也可以是其它任意技术实现,只要对外提供的是Rest风格服务即可。本例中就是我们实现的itcast-service-provider。

    • 服务消费者

      消费应用从注册中心获取服务列表,从而得知每个服务方的信息,知道去哪里调用服务方。本例中就是我们实现的itcast-service-consumer。

    高可用的Eureka Server

    Eureka Server即服务的注册中心,在刚才的案例中,我们只有一个EurekaServer,事实上EurekaServer也可以是一个集群,形成高可用的Eureka中心。

    服务同步

    多个Eureka Server之间也会互相注册为服务,当服务提供者注册到Eureka Server集群中的某个节点时,该节点会把服务的信息同步给集群中的每个节点,从而实现数据同步。因此,无论客户端访问到Eureka Server集群中的任意一个节点,都可以获取到完整的服务列表信息。

    动手搭建高可用的EurekaServer

    我们假设要运行两个EurekaServer的集群,端口分别为:10086和10087。只需要把itcast-eureka启动两次即可。

    1)启动第一个eurekaServer,我们修改原来的EurekaServer配置:

    server:
      port: 10086 # 端口
    spring:
      application:
        name: eureka-server # 应用名称,会在Eureka中显示
    eureka:
      client:
        service-url: # 配置其他Eureka服务的地址,而不是自己,比如10087
          defaultZone: http://127.0.0.1:10087/eureka
    

    所谓的高可用注册中心,其实就是把EurekaServer自己也作为一个服务进行注册,这样多个EurekaServer之间就能互相发现对方,从而形成集群。因此我们做了以下修改:

    • 把service-url的值改成了另外一台EurekaServer的地址,而不是自己

    启动报错,很正常。因为10087服务没有启动

    启动第二个eurekaServer,再次修改itcast-eureka的配置:

    server:
      port: 10087 # 端口
    spring:
      application:
        name: eureka-server # 应用名称,会在Eureka中显示
    eureka:
      client:
        service-url: # 配置其他Eureka服务的地址,而不是自己,比如10087
          defaultZone: http://127.0.0.1:10086/eureka
    

    客户端注册服务到集群

    因为EurekaServer不止一个,因此注册服务的时候,service-url参数需要变化:

    eureka:
      client:
        service-url: # EurekaServer地址,多个地址以','隔开
          defaultZone: http://127.0.0.1:10086/eureka,http://127.0.0.1:10087/eureka
    

    服务提供者

    服务提供者要向EurekaServer注册服务,并且完成服务续约等工作。

    服务注册

    服务提供者在启动时,会检测配置属性中的:eureka.client.register-with-eureka=true参数是否正确,事实上默认就是true。如果值确实为true,则会向EurekaServer发起一个Rest请求,并携带自己的元数据信息,Eureka Server会把这些信息保存到一个双层Map结构中。

    • 第一层Map的Key就是服务id,一般是配置中的spring.application.name属性
    • 第二层Map的key是服务的实例id。一般host+ serviceId + port,例如:locahost:service-provider:8081
    • 值则是服务的实例对象,也就是说一个服务,可以同时启动多个不同实例,形成集群。

    服务续约

    在注册服务完成以后,服务提供者会维持一个心跳(定时向EurekaServer发起Rest请求),告诉EurekaServer:“我还活着”。这个我们称为服务的续约(renew);

    有两个重要参数可以修改服务续约的行为:

    eureka:
      instance:
        lease-expiration-duration-in-seconds: 90
        lease-renewal-interval-in-seconds: 30
    
    • lease-renewal-interval-in-seconds:服务续约(renew)的间隔,默认为30秒
    • lease-expiration-duration-in-seconds:服务失效时间,默认值90秒

    也就是说,默认情况下每个30秒服务会向注册中心发送一次心跳,证明自己还活着。如果超过90秒没有发送心跳,EurekaServer就会认为该服务宕机,会从服务列表中移除,这两个值在生产环境不要修改,默认即可。

    但是在开发时,这个值有点太长了,经常我们关掉一个服务,会发现Eureka依然认为服务在活着。所以我们在开发阶段可以适当调小。

    eureka:
      instance:
        lease-expiration-duration-in-seconds: 10 # 10秒即过期
        lease-renewal-interval-in-seconds: 5 # 5秒一次心跳
    

    5.4.4.服务消费者

    获取服务列表

    当服务消费者启动时,会检测eureka.client.fetch-registry=true参数的值,如果为true,则会拉取Eureka Server服务的列表只读备份,然后缓存在本地。并且每隔30秒会重新获取并更新数据。我们可以通过下面的参数来修改:

    eureka:
      client:
        registry-fetch-interval-seconds: 5
    

    生产环境中,我们不需要修改这个值。

    但是为了开发环境下,能够快速得到服务的最新状态,我们可以将其设置小一点。

    失效剔除和自我保护

    服务下线

    当服务进行正常关闭操作时,它会触发一个服务下线的REST请求给Eureka Server,告诉服务注册中心:“我要下线了”。服务中心接受到请求之后,将该服务置为下线状态。

    失效剔除

    有些时候,我们的服务提供方并不一定会正常下线,可能因为内存溢出、网络故障等原因导致服务无法正常工作。Eureka Server需要将这样的服务剔除出服务列表。因此它会开启一个定时任务,每隔60秒对所有失效的服务(超过90秒未响应)进行剔除。

    可以通过eureka.server.eviction-interval-timer-in-ms参数对其进行修改,单位是毫秒,生产环境不要修改。

    这个会对我们开发带来极大的不变,你对服务重启,隔了60秒Eureka才反应过来。开发阶段可以适当调整,

    我们关停一个服务,就会在Eureka面板看到一条警告

    这是触发了Eureka的自我保护机制。当一个服务未按时进行心跳续约时,Eureka会统计最近15分钟心跳失败的服务实例的比例是否超过了85%。在生产环境下,因为网络延迟等原因,心跳失败实例的比例很有可能超标,但是此时就把服务剔除列表并不妥当,因为服务可能没有宕机。Eureka就会把当前实例的注册信息保护起来,不予剔除。生产环境下这很有效,保证了大多数服务依然可用。

    但是这给我们的开发带来了麻烦, 因此开发阶段我们都会关闭自我保护模式:(itcast-eureka)

    eureka:
      server:
        enable-self-preservation: false # 关闭自我保护模式(缺省为打开)
        eviction-interval-timer-in-ms: 1000 # 扫描失效服务的间隔时间(缺省为60*1000ms)
    

    负载均衡Ribbon

    开启负载均衡

    因为Eureka中已经集成了Ribbon,所以我们无需引入新的依赖,直接修改代码。

    修改itcast-service-consumer的引导类,在RestTemplate的配置方法上添加@LoadBalanced注解:

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
    

    修改调用方式,不再手动获取ip和端口,而是直接通过服务名称调用:

    @Controller
    @RequestMapping("consumer/user")
    public class UserController {
    
        @Autowired
        private RestTemplate restTemplate;
    
        //@Autowired
        //private DiscoveryClient discoveryClient; // 注入discoveryClient,通过该客户端获取服务列表
    
        @GetMapping
        @ResponseBody
        public User queryUserById(@RequestParam("id") Long id){
            // 通过client获取服务提供方的服务列表,这里我们只有一个
            // ServiceInstance instance = discoveryClient.getInstances("service-provider").get(0);
            String baseUrl = "http://service-provider/user/" + id;
            User user = this.restTemplate.getForObject(baseUrl, User.class);
            return user;
        }
    
    }
    

    负载均衡策略

    SpringBoot也帮我们提供了修改负载均衡规则的配置入口,在itcast-service-consumer的application.yml中添加如下配置:

    server:
      port: 80
    spring:
      application:
        name: service-consumer
    eureka:
      client:
        service-url:
          defaultZone: http://127.0.0.1:10086/eureka
    service-provider:
      ribbon:
        NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule     # RandomRole随机获取       RoundRobinRole 轮询获取
    

    格式是:{服务名称}.ribbon.NFLoadBalancerRuleClassName,值就是IRule的实现类。

    总结application配置文件常用配置

    1. server.port 指定端口号
      2.spring.application.name 指定服务名称
      3.eureka.client.service-url.defaultZone 服务器位置
      4.lease-renewal-interval-in-seconds:服务续约(renew)的间隔,默认为30秒
      5.lease-expiration-duration-in-seconds:服务失效时间,默认值90秒
      6.eureka.client.registry-fetch-interval-seconds: 指定时间重新拉取并更新数据 单位为秒
      7.`eureka.server.eviction-interval-timer-in-ms: 间隔多少秒对失效服务进行提出 单位毫秒 1000=1s
      8.eureka.server.enable-self-preservation: 关闭自我保护 服务停止直接剔除
      9.eureka.client.fetch-registry=false 注册中心职责是维护服务实例,false:不检索服务。
      10.eureka.client.register-with-eureka=false 此应用为注册中心,false:不向注册中心注册自己。
  • 相关阅读:
    NOIP2018 复赛提高组一等奖获奖名单
    JZOJ 5222. 【GDOI2018模拟7.12】A(权值线段树)
    NOIP2018 提高组复赛成绩-广东
    NOIP2018 总结
    NOIP 复赛注意事项
    JZOJ 5168. 冲击哥(贪心)
    数据库
    估计理论简介
    KMP
    从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
  • 原文地址:https://www.cnblogs.com/zgrey/p/13654291.html
Copyright © 2020-2023  润新知