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();
}


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

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

转载请标明出处: http://blog.youkuaiyun.com/forezp/article/details/70148833 本文出自方志朋的博客 错过了这一篇,你可能再也学不会 Spring Cloud 了!Spring Boot做为下一代 web 框架,Spring Cloud 作为最新最火的微服务的翘楚,你还有什么理由拒绝。赶快上船吧,老船长带你飞。终章不是最后一篇,它是一个汇总,未来还会写很多篇。 案例全部采用Spring Boot 1.5.x ,Spring Cloud版本为Dalston.RELEASE 我为什么这些文章?一是巩固自己的知识,二是希望有更加开放和与人分享的心态,三是接受各位大神的批评指教,有任何问题可以联系我: miles02@163.com . 码农下载:https://git.oschina.net/forezp/SpringCloudLearning github下载:https://github.com/forezp/SpringCloudLearning,记得star哦! 欢迎购买我的书《深入理解Spring Cloud与微服务构建》 1.jpg 京东购买 当当购买 亚马逊购买 优快云专栏汇总:史上最简单的 SpringCloud 教程 《史上最简单的 SpringCloud 教程》系列: 史上最简单的 SpringCloud 教程 | 第一篇: 服务的注册与发现(Eureka) 史上最简单的SpringCloud教程 | 第二篇: 服务消费者(rest+ribbon) 史上最简单的SpringCloud教程 | 第三篇: 服务消费者(Feign) 史上最简单的SpringCloud教程 | 第四篇:断路器(Hystrix) 史上最简单的SpringCloud教程 | 第五篇: 路由网关(zuul) 史上最简单的SpringCloud教程 | 第六篇: 分布式配置中心(Spring Cloud Config) 史上最简单的SpringCloud教程 | 第七篇: 高可用的分布式配置中心(Spring Cloud Config) 史上最简单的SpringCloud教程 | 第八篇: 消息总线(Spring Cloud Bus) 史上最简单的SpringCloud教程 | 第九篇: 服务链路追踪(Spring Cloud Sleuth) 史上最简单的SpringCloud教程 | 第十篇: 高可用的服务注册中心 史上最简单的SpringCloud教程 | 第十一篇:docker部署spring cloud项目 史上最简单的SpringCloud教程 | 第十二篇: 断路器监控(Hystrix Dashboard) 史上最简单的SpringCloud教程 | 第十三篇: 断路器聚合监控(Hystrix Turbine) 史上最简单的 SpringCloud 教程 | 第十四篇: 服务注册(consul) 未完。。。 还有很多篇。。。 进阶篇 Spring Cloud Sleuth超详细实战 源码篇: 深入理解Feign之源码解析 深入理解Eureka之源码解析 深入理解Ribbon之源码解析 深入理解Hystrix之文档翻译 深入理解Zuul之源码解析 番外篇: 如何使用MongoDB+Springboot实现分布式ID? 如何在springcloud分布式系统中实现分布式锁? 如何用Redlock实现分布式锁 如何在IDEA启动多个Spring Boot工程实例 JWT如何在Spring Cloud微服务系统中在服务相互调时传递
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值