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


一个微服务架构里面包含哪些东西?
服务注册与发现 、服务调用、服务熔断、负载均衡、服务降级、服务消息队列、配置中心管理、服务网关、服务监控、全链路追踪、自动化构建部署、服务定时任务调度操作。


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

SpringBoot是一种服务开发技术

服务注册与发现:EUREKA

服务负载与调用:NETFLIX OSS RIBBON、NETTFLIX

服务熔断降级:HYSTRIX

服务网关:Zuul

服务分布式配置:SpringCloud Config

服务开发: SPRING BOOT


关于cloud对应boot的使用版本选型问题,springboot官网有这样的规定:

H版本必须使用2.2版本;

如果是G版本,必须对应2.1版本;

跟随视频学习的环境配置要求:

但是我们现在去springcloud官网去看最适配的版本的话,可以看到

Hoxton SR4 目前最适配2.2.5版本的boot。


目前springcloud里面涉及到的知识体系总图:


一、父工程project空间搭建

1)新建一个maven项目


2) 创建好工程后确保编码设置:

3)注解激活生效配置:

4)java编译版本:

5) 父工程的pom文件更改:

添加packing为pom形式,表明是个父工程
并添加下面的依赖

  <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>org.xzq.springcloud</groupId><artifactId>cloud2020</artifactId><version>1.0-SNAPSHOT</version><packaging>pom</packaging><modules><module>cloud-provider-payment8001</module><module>cloud-consumer-order80</module><module>cloud-api-commons</module><module>cloud-eureka-server7001</module><module>cloud-eureka-server7002</module><module>cloud-provider-payment8002</module><module>cloud-provider-payment8004</module><module>cloud-comsumerzk-order80</module><module>cloud-providerconsul-payment8006</module><module>cloud-consumerconsul-order80</module><module>cloud-consumer-feign-order80</module></modules><!--统一管理jar包和版本--><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><log4j.version>1.2.17</log4j.version><lombok.version>1.16.18</lombok.version><mysql.version>8.0.18</mysql.version><druid.verison>1.1.16</druid.verison><mybatis.spring.boot.verison>1.3.0</mybatis.spring.boot.verison></properties><!--  子模块继承之后,提供作用:锁定版本+子module不用写groupId和version--><dependencyManagement><dependencies><!--spring boot 2.2.2--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.2.2.RELEASE</version><type>pom</type><scope>import</scope></dependency><!--spring cloud Hoxton.SR1--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Hoxton.SR1</version><type>pom</type><scope>import</scope></dependency><!--spring cloud alibaba 2.1.0.RELEASE--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2.2.0.RELEASE</version><type>pom</type><scope>import</scope></dependency><!-- MySql --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version></dependency><!-- Druid --><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>${druid.verison}</version></dependency><!-- mybatis-springboot整合 --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>${mybatis.spring.boot.verison}</version></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></dependency><!--junit--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>${junit.version}</version></dependency><!-- log4j --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>${log4j.version}</version></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><fork>true</fork><addResources>true</addResources></configuration></plugin></plugins></build></project>

其中的dependencyManagement作用:子模块继承之后,提供作用:锁定版本+子module不用写groupId和version

6)dependencyManagement说明:

  • maven使用dependencyManagement元素来提供了一种管理依赖版本号的方式。通常会在一个组织或者项目的最顶层的父POM中看到dependencyManagement元素。
  • 使用pom.xml中的dependencyManagement元素能让所有在子项目中引用一个依赖而不用显示的列出版本号。maven会沿着父子层次向上走,直到找到一个拥有dependencyManagement元素的项目,然后它就会使用这个dependencyManagement元素中指定的版本号。
  • 这样做的好处是:如果有多个子项目都引用同一样依赖,则可以避免在每个使用的子项目里面都声明一个版本号,这样想升级或切换到另一个版本时,只需要在顶层父容器里更新,而不需要一个一个子项目的修改;另外如果某个子项目需要另一个版本,只需要声明version即可。
  • dependencyManagement里只是声明依赖,并不实现引入,因此子项目需要显示的声明需要用的依赖。
  • 如果不在子项目中声明依赖,是不会从父项目中继承下来的;只有在子项目写了该依赖项,并没有指定具体版本,才会从父项目中继承该项,并且version和scope都读取自父pom。
  • 如果子项目中制定了版本号,那么会使用子项目中指定的jar版本。

7)maven中跳过单元测试

点击图示按钮,会发现test变灰

以上都完成后,可以选择install,点击run,看看maven与idea是否整合成功。


二、子项目(payment支付工程)的构建

1)创建module子模块(cloud-provider-payment8001)




在创建好该module后,我们来到父工程的pom文件查看发现多了这么一串东西,说明子模块确实搭建完毕了:

而子项目里,groupId和version确实没写,继承的是父项目的:

2)pom文件

<dependencies><!-- 包含了sleuth zipkin 数据链路追踪--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-zipkin</artifactId></dependency><dependency><!-- 引用自己定义的api通用包,可以使用Payment支付Entity --><groupId>com.eiletxie.springcloud</groupId><artifactId>cloud-api-commons</artifactId><version>${project.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--监控和管理Spring Boot应用,比如健康检查、审计、统计和HTTP追踪等--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><!--如果没写版本,从父层面找,找到了就直接用,全局统一--></dependency><!--mysql-connector-java--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--jdbc--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><!--热部署--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>

3)编写子项目的application.yml文件

server:port: 8001 #服务端口
​
spring:application:name: cloud-payment-service #服务名datasource:type: com.alibaba.druid.pool.DruidDataSource  #当前数据源操作类型driver-class-name: com.mysql.cj.jdbc.Driver #数据库驱动包url: jdbc:mysql://localhost:3306/cloud?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true&allowPublicKeyRetrieval=trueusername: rootpassword: 1234
​devtools:restart:enabled: true #是否支持热部署
​
mybatis:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.xzq.springcloud.entities  #所有entity别名所在包
​

4)编写子项目的主启动类

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

5)编写实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Payment implements Serializable {private Long id;private String Serial;
}

Lombok项目是一个Java库,它会自动插入编辑器和构建工具中,Lombok提供了一组有用的注释,用来消除Java类中的大量样板代码。仅五个字符(@Data)就可以替换数百行代码从而产生干净,简洁且易于维护的Java类。

Lombok也存在一定风险,在一些开发工具商店中没有Project Lombok支持选择。 IDE和JDK升级存在破裂的风险,并且围绕项目的目标和实施存在争议。
常用注解:
@Setter :注解在类或字段,注解在类时为所有字段生成setter方法,注解在字段上时只为该字段生成setter方法。
@Getter :使用方法同上,区别在于生成的是getter方法。
@ToString :注解在类,添加toString方法。
@EqualsAndHashCode: 注解在类,生成hashCode和equals方法。
@NoArgsConstructor: 注解在类,生成无参的构造方法。
@RequiredArgsConstructor: 注解在类,为类中需要特殊处理的字段生成构造方法,比如final和被@NonNull注解的字段。
@AllArgsConstructor: 注解在类,生成包含类中所有字段的构造方法。
@Data: 注解在类,生成setter/getter、equals、canEqual、hashCode、toString方法,如为final属性,则不会为该属性生成setter方法。
@Slf4j: 注解在类,生成log变量,严格意义来说是常量。

6)dao层

@Mapper
public interface PaymentDao {public int create(Payment payment);public Payment getPaymentById(@Param("id") Long id);}

7)mapper.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.atguigu.springcloud.dao.PaymentDao"><insert id="create" parameterType="com.atguigu.springcloud.entities.Payment" useGeneratedKeys="true" keyProperty="id">insert into payment(serial) values (#{serial})</insert><resultMap id="BaseResultMap" type="com.atguigu.springcloud.entities.Payment"><id column="id" property="id" jdbcType="BIGINT" /><id column="serial" property="serial" jdbcType="VARCHAR" /></resultMap><select id="getPaymentById" resultMap="BaseResultMap" parameterType="Long">select * from payment where id = #{id}</select></mapper>

8)service层

public interface PaymentService {public int create(Payment payment);public Payment getPaymentById(@Param("id") Long id);
}

9)实现层

@Service
public class PaymentServiceImpl implements PaymentService {@Resourceprivate PaymentDao paymentDao;@Overridepublic int create(Payment payment) {return paymentDao.create(payment);}@Overridepublic Payment getPaymentById(Long id) {return paymentDao.getPaymentById(id);}
}

10)controller层

@RestController
public class PaymentController {@Resourceprivate PaymentService paymentService;@PostMapping("/payment/create")public CommonResult create(Payment payment){int result = paymentService.create(payment);if(result>0){return new CommonResult(200,"插入数据库成功",result);}else{return new CommonResult(444,"插入数据库失败",null);}}@GetMapping("/payment/{id}")public CommonResult getPaymentById(@PathVariable("id") Long id){Payment payment = paymentService.getPaymentById(id);if(payment != null){return new CommonResult(200,"查询成功",payment);}else{return new CommonResult(444,"没有对应记录,查询id:"+id,null);}}
}

11)开启热部署

idea配置

父类pom的maven插件:

<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><fork>true</fork><addResources>true</addResources></configuration></plugin></plugins></build>

按ctrl+shift+alt+/

勾选上这两个:


三、子项目(order支付工程)的构建(cloud-consumer-order80)

同上创建module

1)pom文件依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>cloud2020-version01</artifactId><groupId>com.atguigu.springcloud</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>cloud-consumer-order80</artifactId><dependencies><dependency><!-- 引用自己定义的api通用包,可以使用Payment支付Entity --><groupId>com.atguigu.springcloud</groupId><artifactId>cloud-api-commons</artifactId><version>${project.version}</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><!--热部署--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>
</project>

2)application.yml文件配置

server:port: 80# 注册Eureka服务
eureka:client:# Eureka服务注册中心会将自己作为客户端来尝试注册它自己,必須禁止register-with-eureka: falsefetch-registry: false

不加上面的下班部分会一直报错:
com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server,要阻止其注册

为啥用80端口呢?用户在访问的时候无需关注端口号

3)拷贝过来实体类

4)新增配置类,使用RestTemplete

  • RestTemplete提供了多种便捷访问远程http服务的方法,是一种简单便捷的访问restful服务模板类,是spring提供的用于访问Rest服务的客户端模板工具集。
  • (url、requestMap、ResponseBean.class)这三个参数分别代表Rest请求地址、请求参数、HTTP相应转换被转换成的对象类型。
@Configuration
public class ApplicationContextConfig {@Beanpublic RestTemplate restTemplate(){return new RestTemplate();}
}

5)controller类

package com.atguigu.springcloud.controller;import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;import javax.annotation.Resource;/*** @author pzy* @ClassName OrderController* @Date 2020/5/11 19:28*/
@RestController
@Slf4j
public class OrderController {public static final String PAYMENT_URL="http://localhost:8001";@AutowiredRestTemplate restTemplate;@GetMapping("/consumer/payment/create")public CommonResult create(Payment payment){return restTemplate.postForObject(PAYMENT_URL+"/payment/create",payment,CommonResult.class);}@GetMapping("/consumer/payment/get/{id}")public CommonResult getPayment(@PathVariable("id")Long id){return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);}
}

6)注意点

当我们测试插入功能时,虽然浏览器显示成功,但会发现serial没插入进入数据库,如图:


那是因为payment里面需要加上@RequestBody注解。
所以上方的paymentController需要加上@RequestBody。

 @PostMapping("/payment/create")public CommonResult create(@RequestBody Payment payment){int result = paymentService.create(payment);if(result>0){return new CommonResult(200,"插入数据库成功",result);}else{return new CommonResult(444,"插入数据库失败",null);}}

加上@RequestBody后我们发现就正确了


四、工程重构

将冗余的代码(比如上面两个项目都有一样的实体类)挑选出来,做成一个公共工程。

1)同理创建module(cloud-api-commons)

2)pom.xml依赖

  <dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!--热部署--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.1.0</version></dependency></dependencies>

3)创建一样结构目录的实体

4)maven的clean和install操作


将这个公共类打包到本地

5)引入公共类的依赖

     <dependency><!-- 引用自己定义的api通用包,可以使用Payment支付Entity --><groupId>com.atguigu.springcloud</groupId><artifactId>cloud-api-commons</artifactId><version>${project.version}</version></dependency>

五、eureka相关(开始搭建单机版Eureka)

1)eureka的基础知识

1.什么是服务治理?
springcloud封装了Netflix公司开发的Eureka模块来实现服务治理。

在传统的RPC远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务与服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。

2.什么是服务注册?
Eureka采用了CS的设计架构,Eureka作为注册服务功能的服务器,它是服务注册中心。而系统中的其他微服务,使用Eureka的客户端连接到Eureka Server并维持心跳连接。这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。
在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息,比如服务地址通讯地址等以别名方式注册到注册总欣赏。另一方(消费者|服务站提供者),以该别名的方式去注册中心你上获取到实际的服务通讯地址,然后再实现本地RPC调用。ROC远程调用框架核心涉及思想:在于注册中心,因为使用注册中心管理每个服务与服务之间的依赖关系(服务治理概念)。在任何rpc远程框架中,都会有一个注册中心(存放服务地址相关信息(接口地址))。

3.eureka包含两个组件

  • Eureka Server提供服务注册服务:
    各个微服务节点通过配置启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务街店的信息可以在界面中直观看到。

  • EurekaClient通过注册中心进行访问
    是一个java客户端,用户简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务街店移除(默认90秒)

2)Eureka Server的子项目创建(创建服务端)(cloud-eureka-server7001)

(1)同理创建module
(2)pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>cloud2020-version01</artifactId><groupId>com.atguigu.springcloud</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>cloud-eureka-server7001</artifactId><dependencies><!-- eureka-server --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency><!-- 引用自己定义的api通用包,可以使用Payment支付Entity --><dependency><groupId>com.atguigu.springcloud</groupId><artifactId>cloud-api-commons</artifactId><version>${project.version}</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><!-- 一般通用配置 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies></project>
(3)application.yml
server:port: 7001eureka:instance:hostname: localhsot  #eureka服务端实例名称client:register-with-eureka: false #表示不向注册中心注册自己fetch-registry: false #表示自己就是注册中心,我的职责就是维护服务实例,并不区检索服务service-url:#设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
(4)主启动类

@EnableEurekaServer这边作为eureka的服务端,作为服务中心

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

启动类,访问,配置成功


六、支付微服务8001入驻进EurekaServer

1)添加修改8001的pom文件

加入spring-cloud-starter-netflix-eureka-client依赖,标志其为客户端

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>cloud2020-version01</artifactId><groupId>com.atguigu.springcloud</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>cloud-provider-payment8001</artifactId><dependencies><!--eureka client--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><!-- 引用自己定义的api通用包,可以使用Payment支付Entity --><groupId>com.atguigu.springcloud</groupId><artifactId>cloud-api-commons</artifactId><version>${project.version}</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><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.10</version></dependency><!--mysql-connector-java--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--jdbc--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>
</project>
2)application.yml添加内容

添加eureka的配置

server:port: 8001spring:application:name: cloud-payment-servicedatasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/cloud?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=trueusername: rootpassword: 123456devtools:restart:enabled: trueeureka:client:#表示是否将自己注册进EurekaServer 默认为trueregister-with-eureka: true#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡fetch-registry: trueservice-url:defaultZone: http://localhost:7001/eurekamybatis:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.atguigu.springcloud.entities
3)主启动类添加修改

添加@EnableEurekaClient注解表示是一个客户端

@SpringBootApplication
@EnableEurekaClient
public class PaymentMain8001 {public static void main(String[] args) {SpringApplication.run(PaymentMain8001.class,args);}
}
4)最后我们再去访问eureka服务注册中心,会发现8001已经入驻,且前面的名称就是我们在application.yml中配置的名称:


七、订单微服务80入驻EurekaServer

如同支付微服务入驻一样

1)添加修改80的pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>cloud2020-version01</artifactId><groupId>com.atguigu.springcloud</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>cloud-consumer-order80</artifactId><dependencies><!--eureka client--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><!-- 引用自己定义的api通用包,可以使用Payment支付Entity --><groupId>com.atguigu.springcloud</groupId><artifactId>cloud-api-commons</artifactId><version>${project.version}</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><!--热部署--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>
</project>
2)application.yml添加内容
server:port: 80spring:application:name: cloud-order-serviceeureka:client:#表示是否将自己注册进EurekaServer 默认为trueregister-with-eureka: true#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡fetch-registry: trueservice-url:defaultZone: http://localhost:7001/eureka
3)主启动类添加修改
@SpringBootApplication
@EnableEurekaClient
public class OrderMain80 {public static void main(String[] args) {SpringApplication.run(OrderMain80.class,args);}
}
4)最后查看效果


至此,单机版的eureka已经搭建完毕!


八、Eureka相关内容

1.理论知识

eureka server做的事:

  • 服务注册:将服务信息注册到注册中心
  • 服务发现:从注册中心上获取服务信息
  • 其实质:存key服务名,取value调用地址

eureka server整个工作流程:

  • 1.先启动eureka 注册中心
  • 2.启动服务提供者payment支付服务
  • 3.支付服务自动后会把自身信息(比如服务地址以别名方式注册进eureka)
  • 4.消费者order服务在需要调用接口时,使用服务别名去注册中心获取实际的RPC远程调用地址
  • 5.消费者获得调用地址后,底层实际是利用httpClient技术实现远程调用
  • 6.消费者获得服务地址后会缓存在本地jvm内存中,默认每隔30秒更新一次服务调用地址

问题:微服务RPC远程服务调用最核心的是什么?
高可用,试想你的注册中心只有一个only one,他出故障就呵呵了,会导致整个服务环境不可用;
解决办法:搭建eureka注册中心集群,实现负载均很+故障容错

eureka集群注册原理:
互相注册,互相守望

2.Eureka集群搭建

1)同理新建module(cloud-eureka-server7002)
2)copy 7001的pom文件依赖
3)修改映射配置,本地host文件更改

C:\Windows\System32\drivers\etc的host文件最后加入以下配置:

# springcloud2020
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
127.0.0.1 eureka7003.com
4)application.yml文件配置更改(从单机->集群)

7001更改:
hostname、defaultZone更改

server:port: 7001eureka:instance:hostname: eureka7001.com #eureka服务端实例名称client:register-with-eureka: false #表示不向注册中心注册自己fetch-registry: false #表示自己就是注册中心,我的职责就是维护服务实例,并不区检索服务service-url:#设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址defaultZone: http://eureka7002.com:7002/eureka/

7002:

server:port: 7002eureka:instance:hostname: eureka7002.com #eureka服务端实例名称client:register-with-eureka: false #表示不向注册中心注册自己fetch-registry: false #表示自己就是注册中心,我的职责就是维护服务实例,并不区检索服务service-url:#设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址defaultZone: http://eureka7001.com:7001/eureka/
5)主启动类
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7002 {public static void main(String[] args) {SpringApplication.run(EurekaMain7002.class,args);}
}

最终效果图:

自此eureka的集群搭建成功!


3.订单和支付两个微服务注册进入Eureka集群

修改8001、80的application.yml文件的属性

server:port: 80spring:application:name: cloud-order-serviceeureka:client:#表示是否将自己注册进EurekaServer 默认为trueregister-with-eureka: true#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡fetch-registry: trueservice-url:#defaultZone: http://localhost:7001/eurekadefaultZone: http://eureka7001.com:7001/eureka/, http://eureka7002.com:7002/eureka/

4.支付payment微服务的集群配置

1)参考8001创建8002(cloud-provider-payment8002)
2)pom文件依赖copy
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>cloud2020-version01</artifactId><groupId>com.atguigu.springcloud</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>cloud-provider-payment8002</artifactId><dependencies><!--eureka client--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><!-- 引用自己定义的api通用包,可以使用Payment支付Entity --><groupId>com.atguigu.springcloud</groupId><artifactId>cloud-api-commons</artifactId><version>${project.version}</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><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.10</version></dependency><!--mysql-connector-java--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--jdbc--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies></project>
3)application.yml文件复制,改端口
server:port: 8002spring:application:name: cloud-payment-servicedatasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/cloud?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=trueusername: rootpassword: 123456devtools:restart:enabled: trueeureka:client:#表示是否将自己注册进EurekaServer 默认为trueregister-with-eureka: true#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡fetch-registry: trueservice-url:#defaultZone: http://localhost:7001/eurekadefaultZone: http://eureka7001.com:7001/eureka/, http://eureka7002.com:7002/eureka/mybatis:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.atguigu.springcloud.entities
4)主启动类和业务类

直接从8001复制粘贴,改主启动类名字

5)修改controller类

因为8001和8002的application.yml里面对于应用的名称都是一样的,我们需要在controller里面定义端口serverPort,才能区别他们。

package com.atguigu.springcloud.controller;import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import com.atguigu.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;/*** @author pzy* @ClassName PaymentController* @Date 2020/5/11 18:36*/
@RestController
@Slf4j
public class PaymentController {@Resourceprivate PaymentService paymentService;@Value("${server.port}")private String serverPort;@PostMapping("/payment/create")public CommonResult create(@RequestBody Payment payment){int result = paymentService.create(payment);if(result>0){return new CommonResult(200,"插入数据库成功,端口号:"+serverPort,result);}else{return new CommonResult(444,"插入数据库失败",null);}}@GetMapping("/payment/get/{id}")public CommonResult getPaymentById(@PathVariable("id") Long id){Payment payment = paymentService.getPaymentById(id);System.out.println("插入成功"+payment);if(payment != null){return new CommonResult(200,"查询成功,端口号:"+serverPort,payment);}else{return new CommonResult(444,"没有对应记录,查询id:"+id,null);}}
}

效果图:

但是!这个时候我们用80访问的话,会发现无论访问多少次,用的都是8001的端口:

6)修改80订单的controller

将原先写的单机版的改成eureka里面的微服务名称

   //public static final String PAYMENT_URL="http://localhost:8001";public static final String PAYMENT_URL="http://CLOUD-PAYMENT-SERVICE";

重启order80。然后我们访问,会发现还是有问题!

原因是,我们配置了以服务名的方式访问,但不能确定是哪一个服务。

7)修改config配置类,给RestTemplate加上@LoadBanlance注解

赋予了RestTemplate负载均衡的能力,默认是轮循

@Configuration
public class ApplicationContextConfig {@Bean@LoadBalancedpublic RestTemplate restTemplate(){return new RestTemplate();}
}

5.actuator微服务信息完善

1))主机名称:服务名称修改

加上instance:
instance-id: payment8001,

eureka:client:#表示是否将自己注册进EurekaServer 默认为trueregister-with-eureka: true#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡fetch-registry: trueservice-url:#defaultZone: http://localhost:7001/eurekadefaultZone: http://eureka7001.com:7001/eureka/, http://eureka7002.com:7002/eureka/instance:instance-id: payment8001

效果图:

2))访问信息有ip提示

加上prefer-ip-address属性

  instance:instance-id: payment8002prefer-ip-address: true #访问路径可以显示up地址

当鼠标移至服务名称,左下角会显示ip:

点击payment8001,修改最后一个路径
可查看服务是否正常


6.服务发现discovery

对于注册进eureka里面的服务,可以通过服务发现来获得该服务的消息。

1)修改8001的controller

引入一个新的内容 DiscoveryClient类

@Resourceprivate DiscoveryClient discoveryClient;

测试类代码

 @GetMapping("/payment/discovery")public Object discovery(){List<String> strings = discoveryClient.getServices();for (String str: strings){System.out.println("*******elements"+str);}List<ServiceInstance> list = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");for (ServiceInstance info : list){System.out.println(info.getServiceId()+"\t"+info.getHost()+"\t"+info.getPort()+"\t"+info.getUri());}return discoveryClient;}

效果图:

2)主启动类加上 @EnableDiscoveryClient
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
public class PaymentMain8001 {public static void main(String[] args) {SpringApplication.run(PaymentMain8001.class,args);}
}

7.Eureka自我保护

1)理论知识:

保护迷失主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护。一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据,也就是不会注销任何微服务。

如果在Eureka Server的首页看到以下这段提示,说明Eureka进入了保护模式:

简单的来讲
某事某刻一个微服务不可用了,Eureka不会李克清理,依旧会对该微服务的信息进行保存。
属于CAP里面的AP分支。

为什么会产生Eureka自我保护机制?
为了防止EurekaClient可以正常运行,但是与EurekaServer网络不通的情况下, EurekaServer不会立刻将EurekaClient服务剔除。

什么是自我保护模式?

  • 默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生(延时、卡顿、拥挤)时,微服务与EurekaServer之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。Eureka通过“自我保护模式”来解决这个问题——当EurekaServer节点在短时间内丢失过多客户端是(可能发生了网络分区故障),name这个节点就会进入自我保护模式。
  • 在自我保护模式中,EurekaServer会保护服务注册表中的信息,不再注销任何服务实例。
  • 综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同事保留所有微服务(健康的微服务和不健康的微服务都会保留)也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。
2)怎么禁止自我保护

这个时候我们只启动7001和8001

1)7001的application.yml文件更改
server:port: 7001eureka:instance:hostname: eureka7001.com #eureka服务端实例名称client:register-with-eureka: false #表示不向注册中心注册自己fetch-registry: false #表示自己就是注册中心,我的职责就是维护服务实例,并不区检索服务service-url:#设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址#defaultZone: http://eureka7002.com:7002/eureka/#单机就是自己defaultZone: http://eureka7001.com:7001/eureka/server:#关闭自我保护机制,保证不可用服务被及时剔除enable-self-preservation: falseeviction-interval-timer-in-ms: 2000  #2秒

效果图:

2)8001的application.yml更改
server:port: 8001spring:application:name: cloud-payment-servicedatasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/cloud?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=trueusername: rootpassword: 123456devtools:restart:enabled: trueeureka:client:#表示是否将自己注册进EurekaServer 默认为trueregister-with-eureka: true#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡fetch-registry: trueservice-url:#defaultZone: http://localhost:7001/eurekadefaultZone: http://eureka7001.com:7001/eureka/, http://eureka7002.com:7002/eureka/instance:instance-id: payment8001prefer-ip-address: true #访问路径可以显示up地址#Eureka客户端向服务端发送心跳的时间间隔,默认是30秒lease-renewal-interval-in-seconds: 1#Eureka服务端在收到最后一次心跳后等待的时间上限,默认为90秒,超时将剔除服务lease-expiration-duration-in-seconds: 2mybatis:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.atguigu.springcloud.entities

九、支付服务注册进zookeeper

zookeeper是一个分布式协调工具,可以实现注册中心功能。

1)同理创建8004的payment的module(cloud-provider-payment8004)
2)pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>cloud2020-version01</artifactId><groupId>com.atguigu.springcloud</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>cloud-provider-payment8004</artifactId><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><!-- 引用自己定义的api通用包,可以使用Payment支付Entity --><groupId>com.atguigu.springcloud</groupId><artifactId>cloud-api-commons</artifactId><version>${project.version}</version></dependency><!--监控--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><!--Springboot 整合zookeeper客户端 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-zookeeper-discovery</artifactId></dependency><!--热部署--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>
</project>
3)application.yml
server:port: 8004spring:application:name: cloud-provider-paymentcloud:zookeeper:connect-string: 172.20.10.3:2181
4)启动类和业务类

@EnableDiscoveryClient该注解用于向使用consul或者zookeeper作为注册中心时注册服务

@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain8004 {public static void main(String[] args) {SpringApplication.run(PaymentMain8004.class,args);}
}
@RestController
@Slf4j
public class PaymentController {@Value("${server.port}")private String serverPort;@RequestMapping("/payment/zk")public String getZookeeper(){return "springcloud with zookeeper:"+serverPort+"\t"+ UUID.randomUUID().toString();}}
5)测试验证

因为我这边是在虚拟机上安装了docker,并在docker里面安装了zookeeper,所以需要以下命令才能进入zookeeper,这边做个记录:

1.docker exec -it dk01(zookeeper的别名) bash2.使用命令 ./bin/zkServer.sh status 来查看节点的状态
cd bin
ls
zkServer.sh status3.使用zkCli.sh开启客户端
zkCli.sh4.ls /services 查看现在入驻的服务5.ls /services/cloud-provider-payment查看流水号6.ls /services/cloud-provider-payment/流水号7.get /services/cloud-provider-payment/流水号



可用json格式化工具查看返回出来的json串

6)临时节点还是持久节点

当我们停掉payment8004微服务后,我们在虚拟机上的zookeeper会剔除掉这个微服务么?答案是肯定的,只不过会等待一段时间才会,所以这个服务节点在zookeeper里面是个临时节点。


十、订单服务注册进zookeeper

1)新建cloud-consumerzk-order80的module
2)pom文件,可copy上方的8004
 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><!-- 引用自己定义的api通用包,可以使用Payment支付Entity --><groupId>com.atguigu.springcloud</groupId><artifactId>cloud-api-commons</artifactId><version>${project.version}</version></dependency><!--监控--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><!--Springboot 整合zookeeper客户端 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-zookeeper-discovery</artifactId><exclusions><!--先排除自带的zookeeper3.5.3--><exclusion><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId></exclusion></exclusions></dependency><!--添加zookeeper3.4.14版本--><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.4.14</version></dependency><!--热部署--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>
3)application.yml
server:port: 80spring:application:name: cloud-consumer-ordercloud:zookeeper:connect-string: 172.20.10.3:2181
4)主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class OrderMain80 {public static void main(String[] args) {SpringApplication.run(OrderMain80.class,args);}
}
5)配置类和controller
@Configuration
public class MyApplicationContextConfig {@Bean@LoadBalancedpublic RestTemplate restTemplate(){return new RestTemplate();}
}
@RestController
public class OrderZkController {public static final String INVOKE_URL="http://cloud-provider-payment";@ResourceRestTemplate restTemplate;@GetMapping("/consumer/payment/zk")public String getPaymentInfo(){String result =restTemplate.getForObject(INVOKE_URL+"/payment/zk",String.class);return result;}
}
6)测试

启动后,查看虚拟机


zk80入驻zookeeper成功。

如果想在zookeeper中配置集群:


十一、consul

1.consul的概念和安装

简介:
consul是一套开源的分布式服务发现和配置管理系统,由HashiCorp公司用GO语言开发。
提供了微服务系统中的服务治理、配置中心、控制总线等功能。这些功能中的每一个都可以根据需要单独使用,也可以一起使用以构建全方位的服务网络,总之Consul提供了扬中完整的服务网格解决方案。

能干嘛?

  • 服务发现 提供HTTP和DNS两种发现方式
  • 健康监测 支持多种方式,HTTP、TCP、Docker、Shell脚本定制化
  • KV存储 key、value的存储方式
  • 多数据中心 Consul支持多数据中心
  • 可视化Web界面

进入到安装包的盘符,cmd命令
先配置系统环境变量,在path里面添加包的路径;
consul --version 查看版本
consul agent -dev 使用开发模式启动
然后可以访问 localhost:8500访问可视化界面

2.在consul里面注册服务提供者
1)新建cloud-providerConsul-payment8006支付提供者
2)pom文件
<dependencies><dependency><!-- 引用自己定义的api通用包,可以使用Payment支付Entity --><groupId>com.atguigu.springcloud</groupId><artifactId>cloud-api-commons</artifactId><version>${project.version}</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><!--SpringCloud consul-server--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-consul-discovery</artifactId></dependency><!--热部署--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>
3)application.yml
server:port: 8006spring:application:name: cloud-provider-payment
###consul注册中心地址cloud:consul:host: localhostport: 8500discovery:#hostname:127.0.0.1service-name: ${spring.application.name}
4)主启动类和业务类
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain8006 {public static void main(String[] args) {SpringApplication.run(PaymentMain8006.class,args);}
}
@RestController
public class PaymentController {@Value("${server.port}")private String serverPort;@RequestMapping("/payment/consul")public String getConsul(){return "springcloud with consul:"+serverPort+"\t"+ UUID.randomUUID().toString();}
}
5)测试验证


3.同理在consul里面注册服务消费者
1)新建cloud-consumerConsul-order80
2)pom文件
 <dependencies><dependency><!-- 引用自己定义的api通用包,可以使用Payment支付Entity --><groupId>com.atguigu.springcloud</groupId><artifactId>cloud-api-commons</artifactId><version>${project.version}</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><!--SpringCloud consul-server--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-consul-discovery</artifactId></dependency><!--热部署--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>
3)application.yml
server:port: 80spring:application:name: cloud-consumer-payment###consul注册中心地址cloud:consul:host: localhostport: 8500discovery:#hostname:127.0.0.1service-name: ${spring.application.name}
4)主启动类、配置类、controller
@SpringBootApplication
@EnableDiscoveryClient
public class OrderConsulMain80 {public static void main(String[] args) {SpringApplication.run(OrderConsulMain80.class,args);}
}
@Configuration
public class MyApplicationConfig {@Bean@LoadBalancedpublic RestTemplate restTemplate(){return new RestTemplate();}
}
@RestController
public class OrderConsulController {public static final String INVOKE_URL="http://cloud-provider-payment";@ResourceRestTemplate restTemplate;@GetMapping("/consumer/payment/consul")public String getPaymentInfo(){String result =restTemplate.getForObject(INVOKE_URL+"/payment/consul",String.class);return result;}
}
5)测试验证


4.总结

三个注册中心的异同

所谓的CAP:
C:Consistency(强一致性)
A:Availability(可用性)
P:Partition tolerance(分区错容性)
CAP理论关注粒度是数据,而不是整体系统设计的策略

我们的系统因为要保证分区错容性,所以要么是CP、要么是AP;
AP:高可用
CP:数据一致

CAP理论的核心是:一个分布式系统不可能同同时很好的满足一致性、可用性和分区错容性这三个需求,因此,根据CAP原理将NoSQL数据库分成了满足CA原则、满足CP原则和满足AP原则三大类:

  • CA:单电机群,满足一致性,可用性的系统,通常在可拓展性上不太强大。
  • CP:满足一致性,分区容忍性的系统,通常性能不是特别高。(Zookeeper/Consul)
  • AP:满足可用性,分区容忍性的系统,通常可能对一致性要求低一点。(Eureka)

AP架构:

CP架构:


十二、Ribbon

1.概念

Ribbon概念
Spring Cloud Ribbon是基于Netflix洗Ribbon实现的一套客户端。 负载均衡的工具

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

LB概念
LB负载均衡(Load Balance)是什么?
简单地说就是将用户的请求平摊的分配到多个服务商,从而达到系统的HA(高可用)。常见的负载均很软件有Ngix,LVS,硬件F5等。

Ribbon本地负载均衡客户端VS Nginx服务端负载均衡区别?
Nginx是服务器负载均衡,客户端所有请求都会交给nginx,然后由nginx实现转发请求。即负载均衡是由服务端实现的。属于集中式LB
Ribbon本地负载均衡,在调用微服务接口时候,会在注册中心获取注册信息服务列表之后缓存到JVM本地,从而在本地实现RPC远程服务调用技术。属于进程内LB

2.Ribbon的使用

ribbon其实就是一个软负载均衡的客户端组件,他可以和其他所需请求的客户端结合使用,和Eureka结合只是其中的一个实例。

Ribbon在工作时分成两步

  • 第一步先选择EurekaServer,它优先选择在同一个区域内负载较少的server。
  • 第二步再根据用户指定的政策,在从server取到的服务注册列表中选择一个地址。其中Ribbon提供了多种策略:比如轮询、随机和根据相应时间加权。

我们再回到8001、8002、7001、7002、80,项目,我们发现我们的pom文件里面没有搜到ribbon相关的依赖,这是为什么呢?

因为spring-cloud-starter-netflix-eureka-client这个依赖里面已经包含了ribbon

二讲RestTemplate
getForObject和getForEntity

order添加对getForEntity()测试方法

  @GetMapping("/consumer/payment/getForEntity/{id}")public CommonResult<Payment> getPaymentEntity(@PathVariable("id")Long id){ResponseEntity<CommonResult> resultResponseEntity = restTemplate.getForEntity(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);if(resultResponseEntity.getStatusCode().is2xxSuccessful()){return resultResponseEntity.getBody();}else {return new CommonResult<>("444","操作失败");}}

返回结果跟下面的getForObject一样

  @GetMapping("/consumer/payment/get/{id}")public CommonResult getPayment(@PathVariable("id")Long id){return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);}

3.Ribbon自带的默认负载规则

Ribbon核心组件IRule:根据特定算法从服务列表中选取一个要访问的服务

  • RoundRobinRule —— 轮询
  • RandomRule —— 随机
  • RetryRule —— 先按照RounRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务
  • WeightedResponseTimeRule —— 对RounRobinRule的拓展,响应速度越快的实例选择权重越大,越容易被选择
  • BestAvailableRule —— 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
  • AvailablilityFilteringRule —— 先过滤掉故障实例,再选择并发较小的实例
  • ZoneAvoidanceRule —— 默认规则,复合判断server所在区域的性能和server的可用性选择服务器
4.Ribbon负载规则替换

==这个自定义配置类不能放在@ComponentScan所扫描的当前包下以及子包下!==否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,达不到特殊化定制的目的。

1)所以我们需要新建一个包;

2)新建配置类:

@Configuration
public class MySelfRule {@Beanpublic IRule myrule(){return  new RandomRule();  //定义为随机}
}

3)主启动类加上注解@RibbonClient
告诉启动类指定针对哪个服务 进行负载均衡,然后使用哪个自定义的规则

@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MySelfRule.class)
public class OrderMain80 {public static void main(String[] args) {SpringApplication.run(OrderMain80.class,args);}
}

默认的RoundRobinRule 轮询原理:


十三、OpenFeign

1.概述

OpenFeign是什么?
Feign是一个声明式的WebService客户端。使用Feign能让编写Web Service客户端更加简单。
它的使用方法是定义一个服务接口然后在上面添加注解。Feign也支持可拔插式的编码器和解码器。Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HTTPMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。

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

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

以前的Feign和现在的OpenFeign的区别:

2.OpenFeign服务调用

feign用于消费侧
在这之前我们用的是Ribbon+RestTemplate结合,现在是OpenFeign,如图:

1)新建cloud-consumer-feign-order80项目
2)pom文件
<dependencies><dependency><!-- 引用自己定义的api通用包,可以使用Payment支付Entity --><groupId>com.eiletxie.springcloud</groupId><artifactId>cloud-api-commons</artifactId><version>${project.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- openfeign --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!--监控--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><!--eureka client--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!--热部署--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>

我们可以看到OpenFeign里面就整合了Ribbon,所以就有了Ribbon的负载均衡功能。

3)application.yml
server:port: 80eureka:client:register-with-eureka: falseservice-url:#服务注册中心集群defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
4)主启动类

新的注解@EnableFeignClients:使用feign并开启

@SpringBootApplication
@EnableFeignClients
public class FeignOrderMain80 {public static void main(String[] args) {SpringApplication.run(FeignOrderMain80.class,args);}
}
5)业务类(重点)
@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService {@GetMapping("/payment/get/{id}")public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);
}

@FeignClient标注去eureka上使用什么微服务接口,映射地址实际上为8001的接口对外暴露的接口地址

这边的接口需要用@Component标注,可用@Service替代;

@Component, @Repository, @Service的区别:

在Spring2.0之前的版本中,@Repository注解可以标记在任何的类上,用来表明该类是用来执行与数据库相关的操作(即dao对象),并支持自动处理数据库操作产生的异常

在Spring2.5版本中,引入了更多的Spring类注解:@Component,@Service,@Controller。@Component是一个通用的Spring容器管理的单例bean组件。而@Repository, @Service, @Controller就是针对不同的使用场景所采取的特定功能化的注解组件。

因此,当你的一个类被@Component所注解,那么就意味着同样可以用@Repository, @Service, @Controller来替代它,同时这些注解会具备有更多的功能,而且功能各异。

最后,如果你不知道要在项目的业务层采用@Service还是@Component注解。那么,@Service是一个更好的选择。

6)controller
@RestController
public class OrderFeignController {@ResourcePaymentFeignService paymentFeignService;@GetMapping("/consumer/payment/get/{id}")public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id){return paymentFeignService.getPaymentById(id);}
}

3.OpenFeign的超时控制

如果我们在微服务提供者中故意写一个等待3秒的接口程序,然后消费者来调用,这个时候OpenFeign就会报错:

8001提供者接口代码:

  @GetMapping("/payment/feign/timeout")public String paymentFeignTimeout() throws InterruptedException {TimeUnit.SECONDS.sleep(3);return serverPort;}

报错信息 读取超时:

默认Feign客户端只等待一秒钟,但是服务端处理需要超过1瞄准,导致Feign客户端不想等待了,直接报错。为了避免这样的情况,有时候我们需要设置Feign客户端的超时控制。

这个时候我们只需要增加application.yml里面的配置即可:

server:port: 80eureka:client:register-with-eureka: falseservice-url:#服务注册中心集群defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
#设置feign客户端超时时间(OpenFeign默认支持Ribbon)
ribbon:#指的是建立连接所用的时间,适用于网络正常的情况下,两端连接所用的时间ReadTimeout: 5000#指的是建立连接后从服务器读取到可用资源所用的时间ConnectTimeout: 5000

效果图,在请求转了几圈后等待几秒后,正常:

4.OpenFeign日志增强

Feign提供了日志打印功能,我们可以通过配置来调整日志级别,从而了解Feign中Http请求的细节。
说白了就是对Feign接口的调用情况进行监控和输出

日志级别

  • NONE:默认的,不显示任何日志;
  • BASIC:仅记录请求方法、URL、响应状态码及执行时间;
  • HEADERS:除了BASIC中定义的信息之外,还请求和相应的头信息;
  • FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据。

1)添加一个配置类:

package com.atguigu.springcloud.config;import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;/*** @author pzy* @ClassName FeignConfig* @Date 2020/5/14 16:02*/
@Configuration
public class FeignConfig {@BeanLogger.Level feignLoggerLevel(){return Logger.Level.FULL;}
}2)yml文件配置 添加对日志级别的设置```markup
server:port: 80eureka:client:register-with-eureka: falseservice-url:#服务注册中心集群defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
#设置feign客户端超时时间(OpenFeign默认支持Ribbon)
ribbon:#指的是建立连接所用的时间,适用于网络正常的情况下,两端连接所用的时间ReadTimeout: 5000#指的是建立连接后从服务器读取到可用资源所用的时间ConnectTimeout: 5000logging:level:#feign日志以什么级别监控哪个接口com.atguigu.springcloud.service.PaymentFeignService: debug

在order里面调用了方法后,可以在控制台看到这些信息:

springcloud- cloud Halibaba版本(超详细!第一部分)相关推荐

  1. Windows10+YOLOV3+VisualStudio2017最新版本超详细过程

    最近两天在看yolo项目,所以想着把作者的项目copy一下运行看一下效果,谁知道一不小心,陷入坑中无法自拔.真实感叹作者的厉害之处. 同时也记录了自己Windows10+YOLOV3+VisualSt ...

  2. Burpsuite介绍及2022.8.2版本超详细安装教程(图文版)

    Burpsuite介绍及2022.8.2版本超详细安装教程(图文版) 文章目录 Burpsuite介绍及2022.8.2版本超详细安装教程(图文版) Burpsuite是什么? Burpsuite环境 ...

  3. 一起实现RPC,超详细~~~ 第一篇

    一起实现RPC,超详细!!! 第一篇 一个简单的RPC通信逻辑如下: 服务端暴露其要提供服务的接口 客户端通过动态代理调用服务端的接口方法,通过代理将要传输的信息发送到服务端(代理是为了让客户端不去关 ...

  4. Kafka(八)----Kafka Tool 2.0.7(最新)版本超详细使用指北

    Kafka Tool 2.0.7版本使用指北 本篇博客要点如下: Kafka Tool 2.0.7下载安装 Kafka Tool 2.0.7参数优化及连接Kafka集群 Kafka Tool 2.0. ...

  5. centos7下载elasticsearch7版本(超详细)

    一.下载软件 下载Linux版的Elasticsearch 二.解压软件 # 解压缩 tar -zxvf elasticsearch-7.8.0-linux-x86_64.tar.gz -C /opt ...

  6. 【微服务】之Nacos和SpringCloud无缝衔接【超详细】

  7. SpringCloud从入门到精通(超详细文档二)

    上一篇文档(SpringCloud从入门到精通之超详细文档一)已经对Springboot/SpringCloud做了简单的介绍以及应用讲解,下面将继续为大家介绍SpringCloud后续应用. 第12 ...

  8. SpringBoot与SpringCloud的版本对应详细版

    作者:梦幻朵颜 出处:https://www.cnblogs.com/zhuwenjoyce/你的一个点赞,一句留言,都将是博主的前进动力!!! 版权:本文版权归作者和博客园共有,欢迎转载,但未经作者 ...

  9. Android笔记系列--超详细DownloadManager使用,兼容到版本8.0

    超详细DownloadManager使用,兼容到版本8.0 最近用到了软件更新,感觉自己写更新比较麻烦,还要定义通知栏的进度效果,想了一下还是使用系统自带的DownloadManager好了,但这个坑 ...

  10. 超详细的Spring Cloud全面总结2W字(建议收藏)

    来自:FrancisQ 原文:juejin.im/post/6844904007975043079 首先我给大家看一张图,如果大家对这张图有些地方不太理解的话,我希望你们看完我这篇文章会恍然大悟. 什 ...

最新文章

  1. ppt流程图字体太小_论文答辩PPT攻略,答辩季你准备好了吗?
  2. sizeof 头文件_c/c++基础之sizeof用法
  3. 如何系统性掌握深度学习模型设计和优化
  4. C++ 中const的用法,特别是用在函数前面与后面的区别!
  5. CSS选择器的权重详解
  6. simulink学习笔记(2)
  7. 寻访x86处理器“实模式”和“保护模式”的前世今生
  8. mac 终极教程,最全,最实用的教程
  9. ztree在vue中的使用 使用封装好的vue-giant-tree
  10. 数据清洗第六章—课后操作题
  11. hiber+spring继续找bug
  12. 华为路由器接口编号与接口的对应关系
  13. Windows 10系统时间显示不正确
  14. Matlab之误差分析
  15. STM8S之STVD问题解决47 can't openfile crtsi0.sm8
  16. 市面最经典的中文版需求分析说明书模板 详细讲解各目录含义 分离需求说明和需求分析
  17. 定时任务系列(3)-Quartz动态定时任务
  18. 嵌入式系统设计有哪几个方向
  19. 2021 年中国程序员薪资和生活现状调查报告
  20. 移动机器人技术(9)-- 全向移动机器人Modeling and Control

热门文章

  1. 如何把字符串转化为 List 集合
  2. vue+element(项目中的使用)
  3. 【步兵 经验篇】图片加密之我见
  4. C++中static成员
  5. 爱搞事情:我的黑苹果日记之雷坑真如铁
  6. tarjan 学习总结
  7. python sum函数导入list_sum求和函数怎么在Python中使用
  8. 基于时序特征处理与LSTM结合的雅虎美股数据预测
  9. linux系统查看电脑的核数,linux如何查看cpu核数
  10. 2021年哔哩哔哩Java高级面试题及答案,知识点总结+面试题解析