springcloud全套教程(学习笔记)

*** springcloud相关maven依赖介绍:
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>*********</artifactId>
    </dependency>
    
    spring-cloud-starter-parent 具备spring-boot-starter-parent同样功能并附加Spring Cloud的依赖  
    spring-cloud-starter-config 默认的配置服务依赖,快速自动引入服务的方式,端口8888 
    spring-cloud-config-server/client 用户自定义配置服务的服务端/客户端依赖  
    spring-cloud-starter-eureka-server 服务发现的Eureka Server依赖  
    spring-cloud-starter-eureka 服务发现的Eureka客户端依赖  
    spring-cloud-starter-hystrix/zuul/feign/ribbon 断路器(Hystrix),智能路有(Zuul),客户端负载均衡(Ribbon)的依赖  
    angular-ui-router 页面分发路由依赖

    
    
*** springcloud相关使用注解:
 
 @EnableEurekaServer ->代表该启动类是一个eureka server端,也就是注册中心
 @EnableEurekaClient ->代表该启动类是一个eureka client端,也就是服务生产者/消费者
 @EnableDiscoveryClient ->代表该服务是一个可被发现的服务提供者
 @LoadBalanced -> 代表ribbon的负载均衡开启
 @RibbonClient -> 代表自定义ribbon的负载均衡规则机制
 @HystrixCommand(fallbackMethod = "deptGetById_GET") -> 服务熔断机制,并指定熔断处理方法
 @EnableCircuitBreaker   -> 表示某客户端开启服务熔断机制

 

***相关概念介绍 :

  1. restTempl调用:springcloud是基于rest风格进行调用的微服务框架,所以,我们可以通过搭建一个生产者工程,提供增删改查的API接口,在消费者中,通过注入restTemplate的bean的方式,调用生产者启动的API接口,来完成消费者与生产者之间的相互调用(并没有使用到eurake注册中心)restTemplate是一个spring提供的用于访问客户端模板工具类
  2. lombok工具的使用: 能够对实体类自动生成get、set等方法,通过注解的方式完成编译

 

目录

一:微服务简介

1. 什么是微服务?

2. 微服务的优缺点?

3. 微服务技术栈

二:eureka注册中心

1. 创建注册中心工程

2. eureka注册中心集群设置

3.  eureka与zookeeper注册中心的区别

三:eurekaClient:(服务注册与发现)

1. 引入主要pom文件

2. 创建application配置文件

3. actuator与注册中心微服务信息完善(spring-boot-starter-actuator(健康监控)配置和使用)

   3.1 打开在注册中心显示服务本身IP及端口

3.2 如何点击服务名,进入详情页? 

4. eureka的自我保护机制

5. 服务的发现Discovery(对外暴露微服务的信息,提供API接口)

四:ribbon负载均衡

1. 负载均衡LB(Load Balance)简介:

2. ribbon初步配置:

3. ribbon的负载均衡调用

4. ribbon负载均衡的服务调用机制(自带七种方式)

5. ribbon的自定义负载均衡机制设置


一:微服务简介

1. 什么是微服务?

拆分系统,一个模块一个微服务,之间通过HTTP的restful风格进行互相调用。

2. 微服务的优缺点?

        优点:降低了系统之间的耦合、增加了系统的高并发可用、减少维护成本、增加了代码的复用性。
        缺点:增加了资源使用成本...

3. 微服务技术栈

一个分布式的微服务架构,应该是由多种维度(技术)组合搭配而成的一个完整的架构,都有哪些维度组成?

springcloud技术维度一览表
服务开发技术 spring、springboot、springMVC...
服务配置与管理 Netflix公司的Archaius、阿里的diamond...
服务注册与发现(z注册中心) Eureka、zookeeper、consul...
服务调用(服务之间通讯方式) restFul风格、RPC、GRPC
服务熔断器(容灾处理) Hystrix、Envoy等
负载均衡     Ribbon、nginx等
服务接口调用(消费者调用生产者的方式) Feign(基于ribbon封装)等
消息队列     kafka、rabbitMQ、activeMQ等
服务配置中心 SpringCloudConfig、Chef等
服务路由网关(通过配置路由访问服务) Zuul等
服务监控中心 zabbix、nagios、metrics、spectator等
全链路追踪(追踪服务之间互相调用等情况) zipkin、brave、dapper等
服务部署     Docket、openStack、kubernetes
事件消息总线 Spring Cloud Bus
数据流操作开发包 Spring Cloud Stream
   

springcloud微服务架构,是一整套的微服务解决方案,通过各个不同的维度功能技术,将一个有一个的springboot服务工程连接起来,互相调用,从而形成带有集群的分布式服务系统。

二:eureka注册中心

1. 创建注册中心工程

      1.1 引入pom文件

            <!--eurekaServer注册中心所需要的依赖jar包-->
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-starter-eureka-server</artifactId>
			</dependency>

      1.2 创建application配置文件

            1.2.1. 设置端口号
            1.2.2. 设置eureka的服务地址以及是否发现该服务
            1.2.3. 设置注册中心地址

      application.yml文件配置:
         

   server:
      port: 8001
   eureka:
      instance:
        hostname: localhost
      client:
        register-with-eureka: false  #false表示不想注册中心注册自己
        fetch-registry: false         #false表示自己就是注册中心,不需要去检索注册中心上的服务
        service-url:
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eurekaServer/   #设置客户端(消费者与生产者)进行注册和查询服务的地址

      1.3  通过@EnableEurekaServer在启动类中标志该服务是一个注册中心,完成启动

2. eureka注册中心集群设置

      设置多个eureka集群,使服务架构变的更加高可用,能够更好的适应高并发的场景,本例设置三个注册中心集群8001/8002/8003

设置方法过程:

      2.1 创建多个eureka子工程,并copy启动类和配置文件。主要修改:

      在8001端口的eurekayml文件中:添加其他集群注册中心地址

       eureka.client.service-url.defaultZone:

            http://localhost:8002/eureka/,http://localhost:8003/eureka/

     在8002端口的eurekayml文件中:添加其他集群注册中心地址

       eureka.client.service-url.defaultZone:

            http://localhost:8001/eureka/,http://localhost:8003/eureka/

     在8003端口的eurekayml文件中:添加其他集群注册中心地址

       eureka.client.service-url.defaultZone:

            http://localhost:8001/eureka/,http://localhost:8002/eureka/

   2.2 客户端访问eureka时。同样defaultZone注册中心地址设置为多个:

      eureka.client.service-url.defaultZone:

        http://localhost:8001/eureka/,http://localhost:8002/eureka/,http://localhost:8003/eureka/

   2.3 注册中心集群设置完成,此时发布一个服务后,三个注册中心均会被注册进去。

3.  eureka与zookeeper注册中心的区别

 3.1 两者之间最大的区别:eureka是AP(可用性,分区容错性)、zookeeper是CP(数据强一致性,分区容错性)

 3.2 分布式架构的设计都围绕着一个原则:C(一致性)A(可用性)P(分区容错性)

三:eurekaClient:(服务注册与发现)

本文将创建一个7001/7002/7003端口的服务提供项目为客户端提供服务,三个端口均为相同项目,设置为不同端口意为将该服务设置为集群。

1. 引入主要pom文件

<!--表示该服务是eureka client的客户端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>

2. 创建application配置文件

      2.1 设置端口;

      2.2 申明注册中心地址

      2.3 业务所需配置(mybatis/jdbc等信息)

      2.4 同样的配置创建三个项目,设置不同端口号,设置不同的eureka.instance.instance-id

            server:
			  port: 7001

			#mybatis的配置文件地址、实体类、映射文件mapper路径
			mybatis:
			  config-location: classpath:mybatis/mybatis.cfg.xml
			  type-aliases-package: com.gugui.PO
			  mapper-locations: classpath:mybatis/mapper/**/*.xml

			spring:
			  datasource:
				url: jdbc:mysql://127.0.0.1:3306/spring_cloud?characterEncoding=UTF-8
				username: root
				password: root
				driver-class-name: org.gjt.mm.mysql.Driver
				type: com.alibaba.druid.pool.DruidDataSource
				dbcp:
				dbcp2:
				  min-idle: 5
				  max-total: 5
				  initial-size: 5
				  max-wait-millis: 2000
			  application:
				name: producer-dept   #服务名
			eureka:
			  client:
				service-url:
				  defaultZone: http://www:8001/eureka/
			  #注册到eureka上时,该服务显示的别名
			  instance:
				instance-id: produck-7001

3. actuator与注册中心微服务信息完善(spring-boot-starter-actuator(健康监控)配置和使用)

本步骤设置该服务在注册中心上的别名以及点击该服务别名后,显示服务提供者的IP以及端口等详细信息,有助于在同一个注册中心,注册了N个服务和集群,方便区分方便定位

在只设置了instance-id时,注册中心截图如下:

   3.1 打开在注册中心显示服务本身IP及端口

      eureka.client.instance.prefer-ip-address=true。此时点击服务名,即可显示IP

3.2 如何点击服务名,进入详情页? 

在不设置时,点击服务名进去会报错。此时就需要(健康监控)配置和使用相关内容了

添加jar包:

<!--spring-boot-starter-actuator(健康监控)配置和使用-->
				<dependency>
					<groupId>org.springframework.boot</groupId>
					<artifactId>spring-boot-starter-actuator</artifactId>
				</dependency>

 在client微服务的yml文件中,添加info信息:

#注册中心页面访问时,点击微服务连接后进行显示的信息
				info:
				  appName: produck-7001
				  companyName: kangce
				  buildArtifactId: $project.artifactId$
				  version: $project.version$

其中$project.artifactId$可以通过maven中pom文件设置build规则设置读取

此时,点击注册中心的链接后,会以json形式显示这些信息

4. eureka的自我保护机制

如果服务在更换 名称或者长时间没有访问时,注册中心页面就会出现如此报错,不用担心,并不是真正的报错了,而是eureka的自我保护机制生效了。并不会影响使用。

Eureka Server 在运行期间会去统计心跳失败比例在 15 分钟之内是否低于 85%,如果低于 85%,Eureka Server 会将这些实例保护起来,
        让这些实例不会过期,但是在保护期内如果服务刚好这个服务提供者非正常下线了,此时服务消费者就会拿到一个无效的服务实例,此时会调用失败,
        对于这个问题需要服务消费者端要有一些容错机制,如重试,断路器等。

        我们在单机测试的时候很容易满足心跳失败比例在 15 分钟之内低于 85%,这个时候就会触发 Eureka 的保护机制,
        一旦开启了保护机制,则服务注册中心维护的服务实例就不是那么准确了,此时我们可以使用eureka.server.enable-self-preservation=false(在注册中心服务eureka-server的yml文件中)来关闭保护机制,这样可以确保注册中心中不可用的实例被及时的剔除(不推荐)。
        
        当eureka在检测服务时,如果超过了心跳检测下限,就会启动自我保护机制,不会强制下线连接失败或者超时的服务,设计原则就是:宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。

 

5. 服务的发现Discovery(对外暴露微服务的信息,提供API接口)

主要使用工具类:DiscoveryClient(org.springframework.cloud.client.discovery.DiscoveryClient)

作用:作用在服务提供者中,表示该 服务可以被发现,调用者可以获取该服务的任何详细信息

用法:

5.1 在需要 被发现的服务中,创建服务发现接口,通过DiscoveryClient来将服务的信息进行接口返回:

@RequestMapping(value = "/dept/discovery", method = RequestMethod.GET)
			public Object discovery() {
				// 获取注册中心中所有的服务名
				List<String> allList = discoveryClient.getServices();
				//获取服务名称是PRODUCER_7001的所有微服务集合
				List<ServiceInstance> list = discoveryClient.getInstances("PRODUCER_7001");
				for (ServiceInstance ser : list) {
					System.out.println(ser.getHost() + "        " + ser.getServiceId() + "        "  + ser.getPort() + "        "  + ser.getUri());
				}
				return this.discoveryClient;
			}

5.2 接口写好之后,在需要被发现的服务启动类中,添加注解:@EnableDiscoveryClient
5.3 访问该服务的该地址,即可访问该服务的详细信息

介绍完springcloud的注册中心创建以及服务提供者的创建之后,就需要进行服务调用了。

两种服务调用的方式:ribbon与feign

 ①:ribbon是通过ribbon+restTemplate的方式完成服务的调用,可通过注册中心直接使用【服务名】+【接口地址】进行访问微服务,类似于面向服务编程,缺点是如果一个服务被多出调用,则我们还需要将这种方式进行进一步自定义封装,
 ②:而feign则直接设置成了面向接口的方式进行微服务的访问,解决了这一问题。

③:ribbon:ribbon+restTempalte

       feign:接口+注解

四:ribbon负载均衡

源码地址:https://github.com/Netflix/ribbon

1. 负载均衡LB(Load Balance)简介:


        ribbon是基于Netflix Ribbon 实现的一套【客户端】的【负载均衡工具】
        1.1 通过一定的负载均衡算法(简单轮询等),来完成服务的调用;
        1.2 负载均衡的方式:
            集中式LB:硬件的方式,在客户端和服务端之间,通过硬件按照一定的策略完成转发,从而达到负载均衡: 客户端  ->  硬件(F5等)  ->  服务端
            进程内LB:将负载均衡逻辑算法集成在消费方,有消费方自主决定调用什么服务。ribbon就是属于进程内LB。


2. ribbon初步配置:


        2.1 修改pom文件添加依赖:
                <!--表示该服务是eureka client的客户端-->
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-starter-eureka</artifactId>
                </dependency>
                <!--此以来是标准依赖-->
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-starter-config</artifactId>
                </dependency>
                <!--ribbon的依赖包-->
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-starter-ribbon</artifactId>
                </dependency>
            
        2.2 修改yml文件,在消费端连接eureka注册中心集群,不再简单的通过restTemplate直接转发访问服务提供者了,而是通过eureka通过负载均衡完成访问。
            eureka:
              client:
                register-with-eureka: false   #不向注册中心注册自己
                fetch-registry: true          #但是需要从注册中心读取查询服务
                service-url:
                  defaultZone: http://eureka.8001.com:8001/eureka/, http://eureka.8001.com:8001/eureka/, http://eureka.8001.com:8001/eureka/
        
        2.3 restTemplate创建Bean时添加注解@LoadBalanced,表示通过负载均衡的方式进行调用
        2.4 启动类通过@EnableEurekaClient表明,该服务是一个客户端(消费者)
        2.5 调用方式:由原来的通过直接明确的IP地址通过restTemplate的方式进行调用,修改为通过微服务的服务名进行调用的方式,从而达到消费端通过注册中心调用提供端

   // public static final String URL_PRX = "http://localhost:7001";
      public static final String URL_PRX = "http://producer-7001";  //通过服务名,来完成服务的调用


        2.6 启动eureka集群,启动服务提供者,启动客户端,进行调用测试

3. ribbon的负载均衡调用


        3.1 当提供者部署了集群之后,ribbon如果没有特别设置,会按照轮询的方式进行负载均衡依次调用。
        3.2 提供者部署多个服务到注册中心之后,消费端会调用ribbon的负载均衡算法,进行轮询访问服务。算法调用机制如下:
        

4. ribbon负载均衡的服务调用机制(自带七种方式)


        ribbon在没有设置的情况下,默认调用轮询方式进行调用服务,可以通过注册bean的方式进行配置ribbon调用服务所使用的机制,设置如下:
        在服务消费端中:调用ribbon时声明机制即可
          

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

            /**
             *ribbon负载均衡调用方式配置
             * 默认是RoundRobinRule
             * 需要什么方式就返回什么对象即可
             * ribbon提供了七中调用方式(当前版本)
             */
            @Bean
            public IRule getIRule() {
                return new RandomRule();  //设置ribbon的负载均衡机制为随机调用服务

            }

5. ribbon的自定义负载均衡机制设置


        5.1 在消费者端启动类中调用注解:@RibbonClient(name = "PRODUCER-DEPT", configuration = MyRule.class)
            表示对于服务名称为PRODUCER-DEPT的微服务,负载均衡调用方式遵循MyRule类中规定的方式
            注意:该注解使用在启动类中,并且该注解所定义的自动以机制类,不能放在ComponentScan所扫描的当前包以及子包下,否则我们自定义的配置类就会被所有的ribbon共享,就不能达到对某一个服务进行特殊配置的目的了。
                   
        5.2 myRule.java(简易版)
            

@Configuration
public class MyRule {
    @Bean
    public IRule getIRule() {
      return new RoundRobinRule();  //设置ribbon的负载均衡机制为轮询调用服务
     }
}


            
            此处配置的IRule返回对象,不会与restTemplate公共ribbon设置的IRule所返回的类型对象所冲入,因为公共配置的(也就是能被@ComponentScan所扫描的)bean,是应用于全局的ribbon适用于所有的微服务,本处配置的bean,仅仅只针对RibbonClient注解所指定的服务,进行负载均衡配置
        
        5.3 自定义ribbon负载均衡机制
        
            我们可以自己写ribbon的负载均衡算法,只需要按照RandomRule类中的方式实现AbstractLoadBalancerRule这个抽象类中的方法,完成自己的算法逻辑,然后再启动类中指定服务的规则类,实例化时,返回自己定义的实体即可。
            步骤如下:
            5.3.1  创建MyStyleRule.java  根据git源码中的 RandomRule类进行修改的,逻辑为随即调用,每次调用五遍
                     

  /**
                 * ribbon负载均衡自定义规则
                 * 规则:随机调用,并且每次随机服务被重复调用5次
                 * 规则可以自定义算法逻辑进行设置
                 * @Date 2019/9/6 13:44
                 **/
                public class MyStyleRule extends AbstractLoadBalancerRule {

                private int index = 0;
                private int times = 0;

                public Server choose(ILoadBalancer lb, Object key) {
                    if (lb == null) {
                        return null;
                    }
                    Server server = null;

                    while (server == null) {
                        if (Thread.interrupted()) {
                            return null;
                        }
                        List<Server> upList = lb.getReachableServers();
                        List<Server> allList = lb.getAllServers();

                        int serverCount = allList.size();
                        if (serverCount == 0) {
                            return null;
                        }

                        /*int index = chooseRandomInt(serverCount);
                        server = upList.get(index);*/

                        if(times < 5) {
                            server = upList.get(index);
                            times++;
                        }else {
                            times = 0;
                            index = chooseRandomInt(serverCount);
                            server = upList.get(index);
                            times++;
                        }

                        if (server == null) {
                            Thread.yield();
                            continue;
                        }

                        if (server.isAlive()) {
                            return (server);
                        }

                        server = null;
                        Thread.yield();
                    }

                    return server;

                }

                protected int chooseRandomInt(int serverCount) {
                    return ThreadLocalRandom.current().nextInt(serverCount);
                }

                @Override
                public Server choose(Object key) {
                    return choose(getLoadBalancer(), key);
                }

                @Override
                public void initWithNiwsConfig(IClientConfig iClientConfig) {

                }
            }

       
              
        5.3.2 在实例化IRule接口时,返回自己创建的规则类
            

@Bean
public IRule getIRule() {
     /**
     * 设置ribbon的负载均衡机制为轮询调用服务
     */
     return new MyStyleRule();
}


        此时,即可完成我们的自定义配置类
        

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章