SpringCloud学习笔记

SpringCloud

简介

通常来说微服务架构是一种架构模式,或者说是一种架构风格,它提供将单一的应用程序划分成一组小的服务,每个服务运行在自己独立的进程中,服务之间互相协调,互相配置,为用户提供最终价值,服务之间采用轻量级的通信机制互相沟通,每个服务都围绕着具体的业务进行构建,并且能够独立的部署到生产环境中,另外,应尽量避免统一的,集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言,工具对其进行构建,可以有一个非常轻量级的集中式管理来协调这些服务,可以使用不同的语言来编写服务,也可以使用不同的数据存储。

微服务的核心就是将传统的一站式应用,根据业务分拆一个个的服务,彻底的去耦合,每一个微服务提供单个业务功能的服务,一个服务做一件事情,从技术角度看就是一种小而独立的处理过程,类似进程的概念,能够自行单独启动或销毁,拥有自己独立的数据库。

微服务与微服务架构

微服务

强调的是服务的大小,他关注的是某一个点,是具体解决某一个问题/提供落地对应服务的一个服务应用,狭义的看,可以看作是IDEA的一个个微服务工程,或者moudel;

IDEA工程中使用Maven开发一个个独立的Moudel,它具体是用SpringBoot开发一个小模块,专业的事交给专业的模块去做,一个模块专注做一件事。

微服务架构

一种新的架构形式,Martin Fowler。2014年提出。

微服务架构是一种架构模式,它提倡将单一的应用程序划分成一组小的服务,服务之间互相协调,互相配合,为用户提供最终价值,,每个服务独立运行在进程中,服务之间采用轻量级的通信机制互相协作,每个服务都围绕着具体的业务进行构建,并且能够独立的部署到生产环境中,另外,应尽量避免统一的,集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言,工具对其进行构建。

微服务的的优缺点

优点:

  • 每个服务足够内聚,足够小,代码容易理解,这样可以焦距一个指定的业务功能或业务需求。
  • 开发简单,开发效率高,一个服务专注一件事,单一职责。
  • 微服务是松耦合的,有功能意义的服务,无论在开发阶段还是部署阶段都是独立的。
  • 微服务能够使用不同的语言开发。
  • 易于和第三方集成,微服务允许容易且灵活的方式集成自动部署,通过持续集成工具,如jenkins,Hudson,bamboo。
  • 微服务易于开发人员理解,修改和和维护。
  • 微服务只是业务逻辑代码,不会和 CSS,HTML 或其它界面混合。
  • 每个微服务都有自己的存储能力,可以有自己的数据库,也可以有同一的数据库。

缺点:

  • 开发人员要处理分布式系统的复杂性。
  • 多服务运维难度,随着服务的增加,运维的压力也在增大。
  • 服务间通信成本。
  • 数据一致性。
  • 系统集成测试。
  • 性能监控。

微服务技术栈

微服务条目技术
服务开发SpringBoot,Spring,SpringMVC
服务配置与管理NetFlix公司的 Archaius,阿里的Diamond等
服务注册与发现Eureka,Consul,Zookeeper等
服务调用Rest,RPC,gRPC
服务熔断器Hystrix,Envoy等
负载均衡Ribbon,Nginx等
服务接口调用(客户端调用接口的简化工具)Feign等
消息队列Kafka,RabbitMQ,ActiveMq等
服务配置中心管理SpringCloudConfig,Chef等
服务路由(API网关)Zuui等
服务监控Zabbix,Nagios,Metrics,Specatator等
全链路追踪Zipkin,Brave,Dapper等
服务部署Docker,OpenStack,Kubernetes等
数据流操作开发包SpringCloud Stream(封装与Redis,Kafka等发送接收消息)
事件消息总线SpringCloud Bus

为什么选择SpringCloud作为微服务架构

选型依据

  • 整体解决方案和框架成熟度
  • 社区热度
  • 可维护性
  • 学习曲线

当前各大IT公司的微服务架构有哪些

  • 阿里:dubbo+HFS
  • 京东:JSF
  • 新浪:Motan
  • 当当:DubboX

各微服务框架对比

功能点/服务架构Netflix/SpringCloudMotangRPCThriftDubbo/DubboX
功能定位完整的微服务架构RPC框架。但整合了ZK或Consul,实现了集群环境的基本服务注册/发现RPC框架RPC框架服务框架
支持Rest是,Ribbon支持多种可拔插的序列化选择
支持RPC是(Hession2)
支持多语言是(Rest形式)
负载均衡是(服务端zuul+客户端Ribbon),zuul服务,动态路由,云端负载均衡Eureka(针对中间层服务器)是(客户端)是(客户端)
配置服务Netflix Archaius,SpringCloud Config Server集中配置是(zookeeper提供)
服务调用链监控是(zuul),zuul提供边缘服务,API网关
高可用/容错是(服务器Hystrix+客户端Rubbon)是(客户端)是(客户端)
典型应用案例NetflixSinaGoogleFacebook
社区活跃程度一般一般2017年后重新开始维护,中断了5年
学习难度
文档丰富程度一般一般一般
其它SpringCloud Bus为我们的应用程序带来了更多管理端点支持降级Netflix内部在开发集成gRPCIDL定义实践的公司比较多
  1. Spring Cloud Netflix 一站式解决方案

    api网关,zuul组件

    Feign — HttpClint — Http通信方式,同步,阻塞

    服务注册发现:Eurake

    熔断机制:Hystrix

  2. Apache Dubbo Zookeeper 半自动,需要整合别人的

    api:找第三方插件,或自己实现

    Dubbo

    Zookeeper

    借助Hystrix

    (不完善)

  3. Spring Cloud Alibaba 一站式解决方案

新概念:服务网格–Server Mesh

​ istio

万变不离其宗:

  • API
  • Http,RPC
  • 注册与发现
  • 熔断机制

什么是SpringCloud

SpringCloud基于SpringBoot提供了一套微服务解决方案,包括服务注册与发现,配置中心,全链路监控,服务网关,负载均衡,熔断器等组件,除了基于Netflix开源组件做高度抽象封装之外,还有一些选型中立的开源组件。

SpringCloud利用SpringBoot开发的便利性,巧妙地简化了分布式系统基础设施的开发,SpringCloud为开发人员提供了快速构建分布式系统的一些工具,包括配置管理,服务发现,熔断器。路由,微代理,事件总线,全局锁,决策竞选,分布式会话等等,它们都可以用SpringBoot的开发风格做到一键启动和部署。

SpringBoot没有重复造轮子,它只是将目前各个公司开发的比较成熟的,经得住实际考验的服务框架组合起来,通过SpringBoot的风格进行再封装,屏蔽了复杂的配置和实现原理,最终给开发者留出了一条简单易懂,易部署和易维护的分布式系统开发工具包。

SpringCloud是分布式微服务架构下的一站式解决方案,是各个微服务架构落地技术的集合体,俗称微服务全家桶。

SpringBoot和SpringCloud的关系

  • SpringBoot专注于快速方便的开发单个个体微服务。
  • SpringCloud是关注全局的微服务协调整治治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来,为各个微服务之间提供:配置管理,服务发现,熔断器,路由,微代理,事件总线,全局锁,决策竞选,分布式会话等等集成微服务。
  • SpringBoot可以离开SpringCloud独立使用,开发项目,但是SpringCloud离不开SpringBoot,属于依赖关系。
  • SpringBoot专注于快速,方便地开发单个个体微服务,SpringCloud关注全局的服务治理框架。

Dubbo和SpringCloud技术选型

DubboSpring Cloud
服务注册中心ZookeeperSpring Cloud Netflix Eurake
服务调用方式RPCREST API
服务监控Dubbo-monitorSpring Boot Admin
熔断器不完善Spring Cloud Netflix Hystrix
服务网关Spring Cloud Netflix Zuul
分布式配置Spring Cloud Config
服务跟踪Spring Cloud Sleuth
消息总线Spring Cloud Bus
数据流Spring Cloud Stream
批量任务Spring Cloud Task

最大区别:Spring Cloud抛弃了Dubbo的RPC通信,采用的是基于Http的REST方式

严格来说,这两种方式各有优劣,虽然从一定程度上来说,后者牺牲了服务调用的性能,但也避免了上面提到的原生RPC带来的问题,而且REST相比RPC更为灵活,服务提供方和调用方的依赖只依靠一纸契约,不存在代码级别的强依赖,这在强调快速演化的微服务环境下,显得更加合适。

Dubbo定位的是一款RPC框架,Spring Cloud的目标是微服务架构下的一站式解决方案。

Spring Cloud特性

  • Distributed/versioned configuration(分布式/版本化配置)
  • Service registration and discovery(服务注册和发现)
  • Routing(路由)
  • Service-to-service calls(服务到服务的调用)
  • Load balancing(负载均衡)
  • Circuit Breakers(熔断器)
  • Global locks(全局锁)
  • Distributed messaging(分布式消息传递)

参考学习:

  • Spring官网
  • SpringCloud中文API文档
  • SpringCloud中国社区
  • SpringCloud中文网

SpringCloud学习环境搭建

项目结构目录(eureka是下一节)

在这里插入图片描述

数据库db1

在这里插入图片描述

springcloud下pom.xml

<!--打包方式-->
<packaging>pom</packaging>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <junit.version>4.12</junit.version>
    <lombok.version>1.18.16</lombok.version>
    <log4j.version>1.2.17</log4j.version>
</properties>

<dependencyManagement>
    <dependencies>
        <!--SpringCloud的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Greenwich.SR1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!--springboot依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.1.4.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    <!--    数据库-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>
    <!--    数据源-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.21</version>
        </dependency>
    <!--    spring boot启动器-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.1</version>
        </dependency>
    <!--    junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
        </dependency>
    <!--   lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
        </dependency>
    <!--    log4j-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.2.3</version>
        </dependency>
    </dependencies>
</dependencyManagement>

springcloud-api

Dept

package com.zr.springcloud.pojo;

import java.io.Serializable;
@Data
@NoArgsConstructor
@Accessors(chain = true) //链式写法
public class Dept implements Serializable {
    private Long deptno;
    private String dname;
    //这个数据库存在哪个数据库的字段,,微服务,一个微服务对于一个数据库,同一个信息可能存在不同的数据库
    private String db_source;

    public Dept(String dname) {
        this.dname = dname;
    }
}

pom.xml

<!--当前的moudle自己需要的依赖,如果父依赖中配置了版本,这里就不用写了-->
<dependencies>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

springcloud-provider-dept-8001

结构

在这里插入图片描述

pom.xml

<dependencies>
    <!--要拿到实体类,需要配置api.module-->
    <dependency>
        <groupId>com.zr</groupId>
        <artifactId>springcloud-api</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-test</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-jetty</artifactId>
    </dependency>
<!--    热部署-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>
</dependencies>

application.yml

server:
  port: 8001

mybatis:
  type-aliases-package: com.zr.springcloud.pojo
  config-location: classpath:mybatis/mybatis.config.xml
  mapper-locations: classpath:mybatis/mapper/*.xml

spring:
  application:
    name: springcloud-provider-dept
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: org.gjt.mm.mysql.Driver
    url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8
    username: root
    password: 123456

mybatis.config.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <!--开启二级缓存-->
        <setting name="cacheEnabled" value="true"/>
    </settings>
</configuration>

DeptDao

package com.zr.springcloud.dao;

@Mapper
@Repository
public interface DeptDao {
    public boolean addDept(Dept dept);

    public Dept queryById(Long id);

    public List<Dept> queryAll();

}

DeptMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zr.springcloud.dao.DeptDao">
    <insert id="addDept" parameterType="Dept">
        insert into dept (dname,db_source) values (#{dname},DATABASE());
    </insert>
    <select id="queryById" resultType="Dept" parameterType="Long">
        select * from dept where deptno=#{deptno};
    </select>
    <select id="queryAll" resultType="Dept">
        select * from dept;
    </select>

</mapper>

DeptService

package com.zr.springcloud.service;

public interface DeptService {
    public boolean addDept(Dept dept);

    public Dept queryById(Long id);

    public List<Dept> queryAll();

}

DeptServiceImpl

package com.zr.springcloud.service;

@Service
public class DeptServiceImpl implements DeptService{
    @Autowired
    private DeptDao deptDao;
    @Override
    public boolean addDept(Dept dept) {
        return deptDao.addDept(dept);
    }

    @Override
    public Dept queryById(Long id) {
        return deptDao.queryById(id);
    }

    @Override
    public List<Dept> queryAll() {
        return deptDao.queryAll();
    }
}

DeptController

package com.zr.springcloud.controller;

//提供Restful服务
@RestController
public class DeptController {
    @Autowired
    private DeptService deptService;

    @PostMapping("/dept/add")
    public boolean addDept(Dept dept){
        return deptService.addDept(dept);
    }
    @GetMapping("/dept/get/{id}")
    public Dept queryById(@PathVariable("id") Long id){
        return deptService.queryById(id);
    }
    @GetMapping("/dept/list")
    public List queryAll(){
        return deptService.queryAll();
    }

}

DeptProvider_8001

package com.zr.springcloud;

@SpringBootApplication
public class DeptProvider_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProvider_8001.class,args);
    }
}

springcloud-consumer-dept

pom.xml

<dependencies>
    <dependency>
        <groupId>com.zr</groupId>
        <artifactId>springcloud-api</artifactId>
        <version>1.0-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>
</dependencies>

application.yml

server:
  port: 80

ConfigBean

package com.zr.springcloud.config;

@Configuration
public class ConfigBean {
    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

DeptConsumerController

package com.zr.springcloud.controller;

@RestController
public class DeptConsumerController {

    //消费者 ,不应该有servicer层
    // RestTemplate  供我们直接调用就可以了
    @Autowired
    private RestTemplate restTemplate;  //提供多种便捷访问远程http的方法,简单的restful服务模板

    private static final String REST_URL_PREFIX = "http://localhost:8001";

    @RequestMapping("/consumer/dept/add")
    public boolean add(Dept dept){
        return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",dept,Boolean.class);
    }

    @RequestMapping("/consumer/dept/get/{id}")
    public Dept get(@PathVariable("id") Long id){
        return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/ "+id,Dept.class);
    }

    @RequestMapping("/consumer/dept/list")
    public List<Dept> list(){
        return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list",List.class);
    }
}

DeptConsumer_80

package com.zr.springcloud;

@SpringBootApplication
public class DeptConsumer_80 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer_80.class,args);
    }
}

按顺序启动服务,访问localhost:8080/consumer/dept/list等

Eureka服务注册与发现

Neatflix在设计Eureka时,遵循的是AP原则。

Eureka是Netflix的一个子模块,也是核心模块之一,Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移,服务注册与发现对微服务来说是非常重要的,有了服务注册与发现,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了,功能类似于dubbo的注册中心,比如Zookeeper。

原理讲解

Eureka的基本架构:

  • SpringCloud封装了Netflix公司开发的Eureka模块来实现服务注册与发现(对比Zookeeper)
  • Eureka采用了C-S的架构设计,EurekaServer作为服务注册功能的服务器,它是注册服务中心
  • 而系统中的其他微服务,使用Eureka的客户端连接到EurekaServer并维持心跳连接,这样系统的维护人员就可以通过EurekaServer来监控系统中的各个微服务是否正常运行,SpringCloud的一些其它模块(比如Zuul)就可以通过EurekaServer来发现系统中的其它微服务,并执行相关的逻辑。
  • Eureka包含两个组件:Eureka Server和 Eureka Client
  • Eureka Server提供服务注册服务,各个节点启动后,会在EurekaServer中进行注册,这样Eureka Server中的服务注册表中将会存储所有可用节点服务的信息,服务节点的信息可以在界面中直观的看到。
  • Eureka Client是一个Java客户端,用于简化Eureka Server交互,客户端同时也具备一个内置的,使用轮询负载算法的负载均衡器,在应用启动后,会向Eureka Server发送心跳(默认为30秒),如果Eureka Server在多个心跳内没有收到某个节点的信息,Eureka Server会从服务注册表中将这个服务节点移除(默认周期为90秒)。

Eureka Server:提供服务注册与发现,zookeeper

Server Provider:将自身的服务注册到Eureka中,从而使消费者找到

Server Consumer:服务消费方从Eureka中获取注册服务列表,从而找到消费者

测试:在springcloud项目下创建model:springcloud-eureka-7001

springcloud-eureka-7001

pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka-server</artifactId>
        <version>1.4.6.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>
</dependencies>

application.yml

server:
  port: 7001

eureka:
  instance:
    hostname: localhost  #服务端的实例名称
  client:
    register-with-eureka: false  #表示是否向eureka注册中心注册自己
    fetch-registry: false  #如果为false,则表示自己为注册中心
    service-url:   #监控页面
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

EurekaServer_7001

package com.zr.springcloud;

@SpringBootApplication
@EnableEurekaServer   //服务端的启动类,可以接受别人注册进来
public class EurekaServer_7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServer_7001.class,args);
    }
}

启动,访问http://localhost:7001/ ,如下图所示

在这里插入图片描述

修改springcloud-provider-dept-8001

pom.xml添加

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>
<!--完善监控信息-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

application.yml中增加

#eureka的配置  服务注册到哪里
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka/
  instance:
    instance-id: springcloud-provider-8001  #修改eureka默认的描述信息

info:
  app.name: zhou-springcloud
  company.name: cnblogs.com/zhou-zr

DeptController中增加(可以不加),增加后访问可获取一些信息

@GetMapping("/dept/discovery")
//注册进来的微服务,获取一些信息
public Object discovery(){
    //获得微服务列表的清单
    List<String> services = client.getServices();
    System.out.println("discoveryService"+services);
    //得到一个具体微服务的信息  通过具体的微服务id来取:applicationName
    List<ServiceInstance> instances = client.getInstances("SPRINGCLOUD-PROVIDER-DEPT");
    for (ServiceInstance instance : instances) {
        System.out.println("ServiceInstance"+instance.getHost()+"\t"+
                instance.getPort()+"\t"+
                instance.getUri()+"\t"+
                instance.getServiceId()
        );
    }
    return this.client;
}

DeptProvider_8001中增加两个注解

@SpringBootApplication
@EnableEurekaClient  //在服务启动后自动注册到eureka中
@EnableDiscoveryClient  //服务发现
public class DeptProvider_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProvider_8001.class,args);
    }
}

先启动eureka再启动provider访问http://localhost:7001/,如下所示

在这里插入图片描述

自我保护机制

默认情况下,如果EurekaServer在一定的时间内没有收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒),但是当网络发生故障时,微服务与Eureka之间无法正常通信,此时不应该注销这个服务,Eurake通过自我保护机制来解决这个问题,当EurekaServer在短时间内失去过多客户端时,那么这个节点就会进入自我保护模式。EurekaServer会保护服务注册表中的信息,不在删除服务注册表中的信息,当网络故障恢复后,收到服务心跳后,EurekaServer会自动退出自我保护模式。

自我保护模式是一种应对网络安全的保护措施,把所有的服务保存(健康的和不健康的),使用自我保护机制,是Eureka的集群更加健壮和稳定。

在SpringCloud中,可以使用eureka.server.enable.self.preservation = false 禁用自我保护模式【不建议关闭】。

集群环境配置

进入C:\Windows\System32\drivers\etc\hosts

添加

127.0.0.1 eureka7001.com
127.0.0.1 eureka7003.com
127.0.0.1 eureka7005.com

修改springcloud-eureka-7001

application.yml

server:
  port: 7001

eureka:
  instance:
    hostname: eureka7001.com   #服务端的实例名称
  client:
    register-with-eureka: false  #表示是否向eureka注册中心注册自己
    fetch-registry: false  #如果为false,则表示自己为注册中心
    service-url:   #监控页面
      #单机: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      #关联: http://eureka7003.com:7003/eureka/,http://eureka7005.com:7005/eureka/
      defaultZone: http://eureka7003.com:7003/eureka/,http://eureka7005.com:7005/eureka/

新建springcloud-eureka-7003 Model

pom.xml与7001相同

application.yml

server:
  port: 7003

eureka:
  instance:
    hostname: eureka7003.com  #服务端的实例名称
  client:
    register-with-eureka: false  #表示是否向eureka注册中心注册自己
    fetch-registry: false  #如果为false,则表示自己为注册中心
    service-url:   #监控页面
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7005.com:7005/eureka/

EurekaServer_7003

package com.zr.springcloud;

@SpringBootApplication
@EnableEurekaServer   //服务端的启动类,可以接受别人注册进来
public class EurekaServer_7003 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServer_7003.class,args);
    }
}

新建springcloud-eureka-7005 Model

pom.xml与7001相同

application.yml

server:
  port: 7005

eureka:
  instance:
    hostname: eureka7005.com  #服务端的实例名称
  client:
    register-with-eureka: false  #表示是否向eureka注册中心注册自己
    fetch-registry: false  #如果为false,则表示自己为注册中心
    service-url:   #监控页面
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/

EurekaServer_7005

package com.zr.springcloud;

@SpringBootApplication
@EnableEurekaServer   //服务端的启动类,可以接受别人注册进来
public class EurekaServer_7005 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServer_7005.class,args);
    }
}

更改springcloud-provider-dept-8001的注册地址 defaultZone:

#eureka的配置  服务注册到哪里
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/,http://eureka7005.com:7005/eureka/
  instance:
    instance-id: springcloud-provider-8001  #修改eureka默认的描述信息

先启动7001,7003,7005,再启动springcloud-provider-dept-8001

随意访问7001,7003,7005,

在这里插入图片描述

CAP原则及对比Zookeeper

RDBMS(Mysql,Oracle,sqlServer)===>ACID

NoSQL(redis,mongdb)===>CAP

CAP:

  • C(Consistency):强一致性
  • A(Availability):可用性
  • P(Partition tolerance):分区容错性

CAP的三进二:CA,CP,AP

CAP理论的核心:

  • 一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求。
  • 根据CAP原理:将NoSQl数据库分成了满足CA原则,满足CP原则和满足AP原则三大类。
    • CA:单点集群,满足一致性,可用性的系统,通常可拓展性较差。
    • CP:满足一致性,分区容错性的系统,通常性能不是特别高。
    • AP:满足可用性,分区容错性的系统,通常可能对一致性要求低一些。

作为服务注册中心,Eureka比Zookeeper好在哪里?

一个分布式系统不可能同时满足CAP,由于分区容错性P在分布式系统中是必须要保证的,因此我们只能在A和C之间权衡。

  • Zookeeper保证的是CP
  • Eureka保证的是AP

Zookeeper保证的是CP:

​ 当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接收服务直接Down掉不可用,也就是说,服务注册功能的可用性要求高于一致性,但是Zk会出现这样一种情况,当master节点因网络故障与其它节点失去联系时,剩余节点会重新进行leader选举,问题在于,选举的时间太长,30-120s,且选举期间整个Zk集群是不可用的,这就导致在选举期间注册服务瘫痪,在云部署环境下,因为网络问题使Zk集群失去master节点是大概率的事件,虽然服务器能够恢复,但是在漫长的选举过程导致的注册长期不可用是不能容忍的。

Eureka保证的是AP:

​ Eureka就避开了这一点,因此在设计时就优先保证可用性,Eurake各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点仍然可以提供注册服务和查询服务,而Eureka的客户端在向某个Eureka注册时,如果发生连接失败,则会自动切换至其他节点,只要有一台Eureka还在,就能保证服务注册的可用性,只不过查到的信息可能不是最新的,除此之外,Eureka还有自我保护机制。如果在15分钟内,超过85%的节点都没有正常的心跳,那么Eureka就会认为客户端和注册中心发生了网络故障,会出现以下几种情况:

  1. Eureka不再从注册列表中移除长时间没收到心态而过期的服务
  2. Eureka仍然能够接收新服务的注册和查询功能,但是不会同步到其他节点上(即保证当前节点仍然可用)
  3. 当网络稳定时,当前实例新的注册信息会被被同步到其它节点中

因此:Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像Zookeeper那样使整个注册服务瘫痪。

负载均衡及Ribbon

SpringCloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的工具。

Ribbon是Netflix开发的项目,主要是提供客户端软件的负载均衡算法,将Netflix的中间层服务连接在一起,Ribbon的客户端组件提供一系列的配置项如:连接超时,重试等等,简单的说,就是在配置文件中列出LoadBalancer(简称:LB,负载均衡)后面所有的机器,Ribbon会自动地帮助你基于某种规则(简单轮询,随机查询等)去连接这些机器,我们也很容易实现Ribbon自定义的负载均衡算法。

Ribbon能干嘛

  • LB,即负载均衡(Load Balance),在微服务或分布式集群中经常用的一种应用。
  • 负载均衡简单的说就是将用户的请求平均分配到多个服务上,从而达到系统的HA(高可用)。
  • 常见的负载均衡软件有Nginx,Lvs等
  • dubbo,SpringCloug中都给我们提供了负载均衡,SpringCloud的负载均衡算法可以自定义
  • 负载均衡简单分类:
    • 集中式LB
      • 即在服务的消费方和提供方之间使用独立的LB设施,如Ngnix,由该设施负责把访问请求通过某种策略转发至服务的提供方
    • 进程式LB
      • 将LB逻辑集成到消费方,消费方从服务注册中心获得有哪些地址可用,然后自己从这些地址中选出一个合适的服务器
      • Ribbon就属于进程式LB,它只是一个类库,集成于消费方进程,消费方通过它来获取服务提供方的地址。

服务端集成Ribbon

修改springcloud-consumer-dept

pom.xml中增加

<!--集成Ribbon-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-ribbon</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>
<!--Eureka-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>

application.yml中增加

#Eureka
eureka:
  client:
    register-with-eureka: false  #不向Eureka中注册自己
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/,http://eureka7005.com:7005/eureka/

修改DeptConsumerController

//通过ribbon实现的时候我们这里的地址应该是变量,通过服务名来访问
// private static final String REST_URL_PREFIX = "http://localhost:8001";
private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";

修改ConfigBean

package com.zr.springcloud.config;

@Configuration
public class ConfigBean {
    //配置负载均衡实现RestTemplate
    @Bean
    @LoadBalanced  //Ribbon
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

DeptConsumer_80中增加注解@EnableEurekaClient

package com.zr.springcloud;

//Ribbon和 Eureka整合以后,客户端可以直接调用,不用关心ip地址和端口号
@SpringBootApplication
@EnableEurekaClient
public class DeptConsumer_80 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer_80.class,args);
    }

启动7001,7003,7005三个服务注册中心,再启动springcloud-provider-dept-8001,最后启动springcloud-consumer-dept

访问:http://localhost/consumer/dept/list

使用Ribbon实现负载均衡

创建数据库db02,db03与环境搭建中的db01相同,修改db_source为对应数据库名

项目结构:

在这里插入图片描述

如图,建立三个服务提供者的model,复制springcloud-provider-dept-8001的内容到8003和8005,修改其application.yml的对应端口(三个提供者application.name相同)及其主启动类对应的数据库名。

启动三个Eureka服务注册中心,再启动三个服务提供者,最后启动消费者,访问http://localhost/consumer/dept/list,多次访问,可以发现数据是从db01,db02,db03依次读取的,默认的是轮询算法。

自定义负载均衡算法

可进入IRule接口查看它的实现类,查看定义好的负载均衡算法(默认的是RoundRobinRule,轮询算法)。

自定义负载均衡算法:

在zr下新增myrule包(不能放在主启动类的同级包下,同级包下会被扫描到,具体原因可参考Ribbon文档)

在这里插入图片描述

DiyRule (复制RandomRule修改部分代码,使其满足我们的要求,每个服务访问5次,换下一个服务)

package com.zr.myrule;

public class DiyRule extends AbstractLoadBalancerRule {
    //每个服务访问5次,换下一个服务

    //total=0 默认等于0  如果等于5 指向下一个服务节点
    //index=0  total=5时 index+1

    private int total = 0; //被调用的次数
    private int currentIndex = 0; //当前是谁在提供服务

    public DiyRule() {
    }

    @SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})
    public Server choose(ILoadBalancer lb, Object key) {
        if (lb == null) {
            return null;
        } else {
            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 = this.chooseRandomInt(serverCount); //生成区间随机数
                // server = (Server)upList.get(index); //从活着的服务随机获取一个
                //自定义
                if (total<5){
                    server = upList.get(currentIndex);
                    total++;
                }else {
                    total = 0;
                    currentIndex++;
                    if (currentIndex>upList.size()-1){
                        currentIndex = 0;
                    }
                    server = upList.get(currentIndex); //存活的服务中获取指定的服务来进行操作
                }


                if (server == null) {
                    Thread.yield();
                } else {
                    if (server.isAlive()) {
                        return server;
                    }

                    server = null;
                    Thread.yield();
                }
            }

            return server;
        }
    }

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

    public Server choose(Object key) {
        return this.choose(this.getLoadBalancer(), key);
    }

    public void initWithNiwsConfig(IClientConfig clientConfig) {
    }
}

MyRule(调用自定义算法)

package com.zr.myrule;

@Configuration
public class MyRule {

    @Bean
    public IRule myRule(){
        return new DiyRule();  //自定义的rule
    }
}

DeptConsumer_80增加注解RibbonClient

package com.zr.springcloud;

//Ribbon和 Eureka整合以后,客户端可以直接调用,不用关心ip地址和端口号
@SpringBootApplication
@EnableEurekaClient
//在微服务启动的时候去加载我们自定义的Ribbon类
@RibbonClient(name = "SPRINGCLOUD-PROVIDER-DEPT",configuration = DiyRule.class)
public class DeptConsumer_80 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumer_80.class,args);
    }
}

Feign负载均衡

简介:feign是声明式的 web Service 客户端,它让微服务之间的调用变得更简单了,类似controller调用service。SpringCloud集成了Ribbon和Eureka,可在使用Feign时提供负载均衡的http客户端。

只需要创建一个接口,然后添加注解即可。

Feign:主要是社区,大家都习惯面向接口编程,这个是很多开发人员的规范 ,调用微服务访问两种方法

  1. 微服务名字【Ribbon】
  2. 接口和注解【Feign】

Fegin能干什么?

  • Feign旨在使编写 Java Http客户端变得更容易
  • 前面使用Ribbon+RestTemplate时,利用RestTemplate对Http请求的封装处理,形成了一套模板化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对某个微服务自行封装一些客户端类来包装这些依赖服务的调用,所以,Feign在此基础上做了进一步的封装,由它来帮助我们实现依赖服务接口的定义,**在Feign的实现下,我们只需要创建一个接口并使用注解的方式来配置它(类似于以前Dao接口上标注Mapper注解,现在是一个微服务接口上标注一个Fegin注解即可)。**即可完成对服务提供方的接口绑定,简化了使用SpringCloud Ribbon时,自动封装服务调用客户端的开发量。

Fegin集成了Ribbon

  • 利用Ribbon维护了MicroServiceCloud-Dept的服务列表信息,并且通过轮询实现了客户端的负载均衡,而与Ribbon不同的是,通过Feign只需要定义服务绑定接口且以声明式的方法,优雅而且简单的实现了服务调用。

代码实现:springcloud-api下新增一个包service

在这里插入图片描述

DeptClientService

package com.zr.springcloud.service;

@Component
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT")
public interface DeptClientService {

    @GetMapping("/dept/get/{id}")
    public Dept queryById(@PathVariable("id")Long id);
    @GetMapping("/dept/list")
    public List<Dept> queryAll();
    @PostMapping("/dept/add")
    public boolean add(Dept dept);

}

复制springcloud-consumer-dept到springcloud-consumer-dept-feign(myrule包可以不用复制)

在这里插入图片描述

pom.xml(springcloud-api和springcloud-consumer-dept-feign都增加)

<!--feign-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-feign</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>

修改DeptConsumerController

package com.zr.springcloud.controller;

@RestController
public class DeptConsumerController {

    @Autowired
    private DeptClientService service = null;

    @RequestMapping("/consumer/dept/add")
    public boolean add(Dept dept){
        return this.service.add(dept);
    }

    @RequestMapping("/consumer/dept/get/{id}")
    public Dept get(@PathVariable("id") Long id){
        return this.service.queryById(id);
    }

    @RequestMapping("/consumer/dept/list")
    public List<Dept> list(){
        return this.service.queryAll();
    }
}

FeginDeptConsumer_80

package com.zr.springcloud;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = {"com.zr.springcloud"})
@ComponentScan("com.zr.springcloud")
public class FeginDeptConsumer_80 {
    public static void main(String[] args) {

        SpringApplication.run(FeginDeptConsumer_80.class,args);
    }
}

启动Eureka注册中心,再启动provider服务提供者,最后启动springcloud-consumer-dept-feign测试。

访问http://localhost/consumer/dept/list。

Hystrix

分布式系统的问题:

服务雪崩:多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其它的微服务,这就是所谓的”扇出“,如果扇出的链路上某个微服务调用时间过长或不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,这就是雪崩效应。

对于高流量应用来说,单一的后端依赖可能会导致所有服务器上的所有资源在几秒钟内饱和,比失效更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其它系统资源紧张,导致整个系统发生更多的连级故障,这些都表示需要对故障和延迟进行隔离和管理,以使单个依赖关系的失败,不能取消整个应用程序或系统。

​ Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免地会调用失败,比如超时,异常等。Hystrix能保证在一个依赖出问题的情况下,不会导致整体服务失效,避免级联故障,以提高分布式系统的弹性。

​ ”断路器“本身是一种开关装置,当整个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个服务预期的,可处理的备选响应(FallBack),而不是长时间的等待或弹出调用方法无法处理的异常,这样就保证了服务调用方的线程不会被长时间不必要的占用,从而避免了故障在分布式系统中的蔓延乃至雪崩。

Hystrix:

  • 服务降级
  • 服务熔断
  • 服务限流
  • 接近实时的额监控

服务熔断

熔断机制是对应雪崩效应的一种微服务链路保护机制。

当扇出的某个微服务不可用或响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息,当检测到该节点微服务调用响应正常后恢复调用链路。在SpringCloud框架里熔断机制通过 Hystrix 实现,Hystrix会监控微服务调用的状态,当失效的调用到一定的阈值,缺省是5秒内20次调用失败就会启动熔断机制,熔断机制的注解是 @HystrixCommand。

测试代码:

复制springcloud-provider-dept-8001 到 springcloud-provider-dept-hystrix-8001

在这里插入图片描述

pom.xml添加

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>

修改DeptController

package com.zr.springcloud.controller;

@RestController
public class DeptController {
   @Autowired
    private DeptService deptService;

   @GetMapping("/dept/get/{id}")
   @HystrixCommand(fallbackMethod = "hystrixGet")
   public Dept get(@PathVariable("id") Long id){
       Dept dept = deptService.queryById(id);
       if (dept==null){
           throw new RuntimeException("id==>"+id+"不存在该用户,信息无法找到");
       }
       return dept;
   }

   //备选方法
   public Dept hystrixGet(@PathVariable("id") Long id){

       return new Dept().setDeptno(id)
               .setDname("id==>"+id+"没有对应的信息:null--hystrix")
               .setDb_source("no this database in MySQL");
   }
}

DeptProviderHystrix_8001主启动类添加EnableCircuitBreaker

package com.zr.springcloud;

@SpringBootApplication
@EnableEurekaClient  //在服务启动后自动注册到eureka中
@EnableDiscoveryClient  //服务发现
@EnableCircuitBreaker //添加对熔断的支持
public class DeptProviderHystrix_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProviderHystrix_8001.class,args);
    }
}

启动Eureka服务注册中心,再启动springcloud-provider-dept-hystrix-8001,再启动springcloud-consumer-dept

访问一个数据库中不存在的id,http://localhost/consumer/dept/get/8

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7ElnOsHx-1619101605927)(SpringCloud.assets/image-20201213150128131.png)]

服务降级

springcloud-api中修改

在这里插入图片描述

增加DeptClientServiceFallbackFactory

package com.zr.springcloud.service;

//降级~
@Component
public class DeptClientServiceFallbackFactory implements FallbackFactory {
    @Override
    public DeptClientService create(Throwable throwable) {
        return new DeptClientService() {
            @Override
            public Dept queryById(Long id) {
                return new Dept().setDeptno(id)
                        .setDname("id==>"+id+"没有对应信息,客户端提供了降级的信息,这个服务已经被关闭")
                        .setDb_source("没有数据");
            }

            @Override
            public List<Dept> queryAll() {
                return null;
            }

            @Override
            public boolean add(Dept dept) {
                return false;
            }
        };
    }
}

springcloud-consumer-dept-fegin的application.yml添加配置开启降级

#开启降级fegin.hystrix
feign:
  hystrix:
    enabled: true

启动Eureka服务注册中心,再启动一个服务提供者,如springcloud-provider-dept-8001,最后启动springcloud-consumer-dept-fegin

访问http://localhost/consumer/dept/get/1可得到正确结果,当关闭服务提供者8001,再访问http://localhost/consumer/dept/get/1

在这里插入图片描述

服务熔断:服务器,某个服务超时或者异常,引起熔断,保险丝。

服务降级:客户端,从整体网站请求负载考虑,当某个服务熔断或者关闭后,服务将不被调用,此时在客户端,我们卡哇伊准备一个FallbackFactory,返回一个默认的值(缺省值),整体的服务水平下降了,但是能使用。

Dashboard流监控

新建model , springcloud-consumer-hystrix-dashboard

在这里插入图片描述

复制springcloud-consumer-dept的pom依赖,并增加以下

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>

application.yml

server:
  port: 9001

DeptConsumerDashboard_9001

package com.zr.springcloud;

@SpringBootApplication
@EnableHystrixDashboard //开启监控页面
public class DeptConsumerDashboard_9001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptConsumerDashboard_9001.class,args);
    }
}

修改springcloud-provider-dept-hystrix-8001的启动类,增加一个servlet

package com.zr.springcloud;

@SpringBootApplication
@EnableEurekaClient  //在服务启动后自动注册到eureka中
@EnableDiscoveryClient  //服务发现
@EnableCircuitBreaker //添加对熔断的支持
public class DeptProviderHystrix_8001 {
    public static void main(String[] args) {
        SpringApplication.run(DeptProviderHystrix_8001.class,args);
    }
    //增加一个servlet
    @Bean
    public ServletRegistrationBean hystrixMetricsStreamServlet(){
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
        registrationBean.addUrlMappings("/actuator/hystrix.stream");
        return registrationBean;
    }
}

启动springcloud-consumer-hystrix-dashboard监控,启动服务注册中心,启动springcloud-provider-dept-hystrix-8001

http://localhost:9001/hystrix(/actuator/hystrix.stream 流地址)

在这里插入图片描述

访问http://localhost:8001/dept/get/3,再访问http://localhost:8001/actuator/hystrix.stream,可以看到

在这里插入图片描述

然后在http://localhost:9001/hystrix页面的监控地址填入监控地址http://localhost:8001/actuator/hystrix.stream,如下图

在这里插入图片描述

点击Monitor Stream(此时可一直访问http://localhost:8001/dept/get/3,观察下图的变化)

在这里插入图片描述

实心圆的颜色代表了健康状态,监控程度从绿色,黄色,橙色,红色递减。

实心圆除了颜色变化外,它的大小根据流量的变大而变大,所以可以通过实心圆的展示,在大量的实例中快速发现故障实例和高压力测试。

Zuul路由网关

​ Zuul包含了对请求的路由和过滤两个最主要的功能。

​ 其中路由功能负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础。而过滤功能则负责对请求的处理过程进行干预,是实现请求校验,服务聚合等功能的基础,Zuul和Eureka进行整合,将Zuul自身注册为Eureka服务治理下的应用,同时从Eureka中获取其它微服务的消息,即以后的访问服务都是通过Zuul跳转后获得。

注意:Zuul服务最终还是会注册进Eureka

提供:代理,路由,过滤三大功能

代码测试

系统host配置文件中增加:127.0.0.1 www.zr.com 【注意】

新建model,springcloud-zuul-9527

在这里插入图片描述

复制springcloud-consumer-hystrix-dashboard的pom.xml,并添加zuul依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zuul</artifactId>
    <version>1.4.6.RELEASE</version>
</dependency>

application.yml

server:
  port: 9527

spring:
  application:
    name: springcloud-zuul

eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7003.com:7003/eureka/,http://eureka7005.com:7005/eureka/
  instance:
    instance-id: zuul9527.com
    prefer-ip-address: true  #显示真实ip


info:
  app.name: zr-springcloud
  company.name: www.cnblogs.com/zhou-zr

zuul:
  routes:
    mydept.serviceId: springcloud-provider-dept  #mydept自己定义
    mydept.path: /mydept/**  #使用这个路径访问
  ignored-services: springcloud-provider-dept #不能再使用这个路径访问了
  #ignored-services: "*"  #隐藏全部的
#  prefix: /zr #设置统一的前缀

ZuulApplication_9527

package com.zr.springcloud;

@SpringBootApplication
@EnableZuulProxy //开启
public class ZuulApplication_9527 {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication_9527.class,args);
    }
}

启动Eureka服务注册中心,再启动springcloud-provider-dept-hystrix-8001 和 springcloud-zuul-9527

访问http://localhost:7001/,可以看到注册了两个服务
在这里插入图片描述

当application.yml中未添加zuul的配置时,访问http://www.zr.com:9527/springcloud-provider-dept/dept/get/5,可以查询。

当application.yml中添加zuul的配置后,访问http://www.zr.com:9527/mydept/dept/get/5查询

注意:未配置ignored-services: springcloud-provider-dept这一行时,以上两个路径都可以查询,配置后,只能通过访问http://www.zr.com:9527/mydept/dept/get/5查询。

SpringCloud config分布式配置

分布式系统面临的配置文件问题:

​ 微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务,由于每个服务都需要必要的配置信息才能运行,所以一套集中式的,动态的配置管理设施是必不可少的。SpringCloud提供了CongifServer来解决这个问题,我们每一个微服务自己带着一个application.yml,那上百的配置文件修改起来就非常麻烦。

SpringCloud Config为微服务架构中的微服务提供集中式的外部配置支持,配置服务器为各个不同微服务应用的所有环节提供了一个中心化的外部配置。

SpringCloud Config分为客户端和服务端两部分:

服务端也称为:分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息,加密,解密信息等访问接口。

客户端则是通过指定的配置中心来管理应用资源,以及与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息,配置服务器默认采用git来存储配置信息,这样有助于对环境配置进行版本管理,并且可以通过git客户端工具来方便的管理和访问配置内容。

SpringCloud Config:

  • 集中式管理配置文件
  • 不同环境,不同配置,动态化的配置更新,分环境部署,比如/dev,/test,/prod,/beta,/release
  • 运行期间动态调整配置,不需要在每个服务部署的机器上编写配置文件,服务会向配置中心统一拉取配置自己的信息
  • 当配置发生变动时,服务不需要重启,即可根据配置的变化,重新加载新的配置
  • 将配置信息以Rest接口的形式暴漏

SpringCloud Config分布式配置中心与github整合

​ 由于SpringCloud Config默认使用Git来存储配置文件(也有其它方式,如SVN和本地文件),但最推荐的还是Git,而且使用的是 http/https访问的形式。

Git

本地下载安装 git

# 设置提交代码时的用户信息--global全局生效
$ git config [--global] user.name "[name]"
$ git config [--global] user.email "[email address]"

# 显示当前的Git配置
$ git config --list

# 添加当前目录的所有文件到暂存区
$ git add .

# 提交暂存区到仓库区
$ git commit -m "[message]"
#提交
git push origin master

#生成密钥  在C盘用户下的 .ssh文件中(id_rsa.pub)
ssh-keygen -t rsa -C "这里换上你的邮箱"

复制密钥,在码云上设置SSH,添加密钥

登录gitee(码云),创建一个springcloud-config仓库

在这里插入图片描述

在指定的目录下右击,点击Git Bash Here,下载项目:git clone ssh的地址,

在下载下来的项目中新建application.yml

spring:
  profiles:
    active: dev
    
---
spring:
  profiles: dev
  applicartion:
    name: springcloud-config-dev
    
    
---
spring:
  profiles: test
  applicartion:
    name: springcloud-config-test

cd springcloud-config/

git add . (加到缓冲区)

git status (查看状态)

git commit -m “first commit”(提交,-m 提交的消息,此时本地提交成功)

git push origin master(提交到远程仓库)

微服务连接Git配置

新建springcloud-config-server-3344的model

pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
        <version>2.1.1.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
   
</dependencies>

application.yml

server:
  port: 3344

spring:
  application:
    name: springcloud-config-server
    #连接远程仓库
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/zhouruizr/springcloud-config.git

Config_Server_3344

package com.zr.springcloud;

@SpringBootApplication
@EnableConfigServer
public class Config_Server_3344 {
    public static void main(String[] args) {
        SpringApplication.run(Config_Server_3344.class,args);
    }
}

启动springcloud-config-server-3344

访问http://localhost:3344/application-dev.yml(其它访问方式参考Spring Cloud中文文档)

在这里插入图片描述

客户端连接服务端访问远程

在下载的springcloud-config中,新建config-client.yml,通过git提交上去

spring:
  profiles:
    active: dev
    
---
server:
  port: 8201
spring:
  profiles: dev
  application:
    name: springcloud-provider-dept
  

#eureka的配置  服务注册到哪里
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/
  
  
---
server:
  port: 8202
spring:
  profiles: test
  application:
    name: springcloud-provider-dept
  

#eureka的配置  服务注册到哪里
eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/

新建springcloud-config-client-3355如下

在这里插入图片描述

pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-config</artifactId>
        <version>2.1.1.RELEASE</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--完善监控信息-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
</dependencies>

bootstrap.yml

# 系统级别的配置
spring:
  cloud:
    config:
      name: config-client  #需要从git上读取的资源名称  不需要后缀
      profile: dev  #test
      label: master
      uri: http://localhost:3344

application.yml

#用户级别的配置
spring:
  application:
    name: springcloud-config-client

ConfigClientController

package com.zr.springcloud.controller;

@RestController
public class ConfigClientController {
    @Value("${spring.application.name}")
    private String applicationName;
    @Value("${eureka.client.service-url.defaultZone}")
    private String eurekaServer;
    @Value("${server.port}")
    private String port;

    @RequestMapping("/config")
    public String getConfig(){
        return "applicationName:"+applicationName
                +"eurekaServer:"+eurekaServer
                +"port:"+port;
    }
}

Config_Client_3355

package com.zr.springcloud;

@SpringBootApplication
public class Config_Client_3355 {
    public static void main(String[] args) {
        SpringApplication.run(Config_Client_3355.class,args);
    }
}

先启动springcloud-config-server-3344,再启动springcloud-config-client-3355

访问http://localhost:8201/config(端口是git上配置好的,修改bootstrap.yml中的profiles为test即可更换端口为8202)

在这里插入图片描述

远程配置实战

将Eureka-7001的配置放到git上,参考客户端连接服务端访问远程的方法配置即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值