父工程
依赖版本管理,但实际不引入依赖
pom.xml
<?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.example</groupId>
<artifactId>SpringCloud</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<!-- 统一管理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>5.1.47</mysql.version>
<druid.version>1.1.16</druid.version>
<mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
</properties>
<!-- 子模块继承之后,提供作用:锁定版本+子modlue不用写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.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.spring.boot.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<finalName>cloud</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.2.2.RELEASE</version> <!-- 与Spring Boot版本对应 -->
<configuration>
<fork>true</fork>
<addResources>true</addResources>
</configuration>
</plugin>
</plugins>
</build>
</project>
支付模块
server: port: 8081 spring: application: name: cloud-payment-service datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: org.gjt.mm.mysql.Driver url: jdbc:mysql://xxxx:3306/db2019?useUnicode=true&characterEncoding=utf-8&useSSL=false username: xxxx password: xxxxxxx mybatis: mapperLocations: classpath:mappers/*.xml #这些Java Bean在mapper XML文件中可以使用别名代替全限定类名 type-aliases-package: com.example.commons.pojo logging: level: com: example: pay: mapper: debug #将服务注册到Eureka eureka: client: #表示是否将自己注册进EurekaServer默认为true register-with-eureka: true #是否从EurekaServer抓取已有的注册信息默认true 单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡 fetchRegistry: true service-url: #defaultZone: http:http://eureka7001.com:7001/eureka/ #集群版 defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
模块结构
依赖 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>SpringCloud</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-provider-payment8081</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jdbc -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
</dependencies>
</project>
pojo
映射文件 因后期重构 以移动到commons
<?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.example.pay.mapper.PaymentMapper">
<insert id="createPayment" useGeneratedKeys="true" keyProperty="id">
insert into payment(serial)value(#{serial})
</insert>
<select id="getPaymentById" resultType="com.example.commons.pojo.payment">
select * from payment where id=#{id}
</select>
</mapper>
控制器
订单模块
在父工程下创建moudle
配置RestTemplate
调用支付模块
application.yml
server:
port: 80
spring:
application:
name: cloud-consumer-ord
#将服务注册到Eureka
eureka:
client:
#表示是否将自己注册进EurekaServer默认为true
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息默认true 单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
#defaultZone: http://localhost:7001/eureka
#集群版
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
将支付和订单的pojo单独重构放到commons模块并在支付和订单模块分别引入
Eureka服务治理
SpringCloud封装了Netflix公司的Eureka模块来实现服务治理
Eureka是服务发现与治理的一套解决方案 还有Nacos Zookeeper Sofa Consul Etcd
在传统的RPC远程调用(如Dubbo,RestTemplate不属于RPC调用)框架中,管理每个服务与服务之间依赖关系比较复杂,所以需要服务治理.实现服务发现与注册.Eureka维护一个服务注册表,其他服务可以查询这个注册表来发现和调用其他微服务.
Eureka使得各个微服务之间能够相互发现并进行通信,但它本身不提供远程调用的功能
Eureka采用CS设计架构.Eureka Server做为服务注册功能的服务器.它是服务注册中心,而系统中的其他微服务,使用Eureka的客户端连接到Eureka的Server并通过心跳连接检测.这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行.
在服务注册与发现中,有一个注册中心,当服务器启动的时候,会把当前自己服务器的信息,比如服务器通讯地址等以别名方式注册到注册中心.消费者可通过注册中心获取服务通信地址.然后通过RPC调用.任何RPC远程调用框架都会有一个注册中心(存放服务地址相关信息包括接口地址)
Eureka包含两个组件:Eureka Server和Eureka Client
Eureka Server提供服务注册
各个微服务节点通过配置启动之后,会在EurekaServer进行注册,这样EurekaServer中的服务注册表中将存储可用服务的节点信息.
Eureka Client通过注册中心访问
是一个Java客户端,为了简化EurekaServer的交互,客户端同时也具备一个内置的,使用轮询(round-robin)负载算法的负载均衡器.应用启动后,将会向Eureka Server发送心跳(默认30秒发送一次).如果Eureka Server在多个心跳周期内没有接收到某个节点发送的心跳.EurekaServer将会从服务注册表中将该节点移除(默认90秒)
单机版Eureka服务注册中心构建
@EnableEurekaServer表示我是一个EurekaServer
application.yml
server: port: 7001 eureka: instance: hostname: localhost # eureka服务端的实例名称 client: # 表示不向注册中心注册自己 register-with-eureka: false # 表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务 fetch-registry: false service-url: # 设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址 ${}是上面定义的 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
pom.xml
<?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>SpringCloud</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-eureka-server-7001</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
</project>
支付模块完成服务注册
首先引入依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
启动类加上客户端注解
application.yml
#将服务注册到Eureka eureka: client: #表示是否将自己注册进EurekaServer默认为true register-with-eureka: true #是否从EurekaServer抓取已有的注册信息默认true 单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡 fetchRegistry: true service-url: defaultZone: http://localhost:7001/eureka
订单模块完成服务注册
依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
Eureka服务治理集群构建
目的高可用,如果单个Eureka服务挂了,会导致整个服务环境不可用
搭建Eureka注册中心集群,实现负载均衡+故障容错
比如有两台Eureka服务 7001和7002
那就是相互注册
如果是三台 7001 7002 7003
那么就是7001注册 7002和7003 7002注册7001和7003 7003注册7001和7002
两两相望 相互注册
为了看的清除
C:\Windows\System32\drivers\etc\hosts
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
pom.xml
<dependencies> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> <dependency> <groupId>org.example</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> </dependencies>
主启动类
application.yml配置文件需要相互注册
server: port: 7002 eureka: instance: hostname: eureka7002.com # eureka服务端的实例名称 client: # 表示不向注册中心注册自己 register-with-eureka: false # 表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务 fetch-registry: false service-url: # 设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址 ${}是上面定义的 #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ defaultZone: http://eureka7001.com:7001/eureka/
在原先7001的application里修改配置
互相启动
支付模块和订单模块注册到服务治理集群
修改订单服务的application.yml
修改支付服务的application.yml
支付模块微服务集群搭建
剩下就是个复制过程
注意 对外暴露都是同一个服务名 重要
那么现在就牵扯出另外一件事 到底调用哪个服务 和 负载均衡
完成后
现在调用
那么订单这边也不能写死了
使用服务名
使用Ribbon做负载均衡
@LoadBalanced注解 表示使用Ribbon进行负载均衡
该注解是引入Eureka客户端依赖时引入的 默认轮询
默认是轮询策略 可以修改配置
Ribbon和Eureka整合后Consumer可以直接调用服务而不用再关心地址和端口号,且该服务还有负载功能.
其实就是引入了Eureka客户端依赖 就可以使用@LoadBalanced注解 是Ribbon的功能
actuator微服务信息完成功能
一般来说 web和actuator最好一起导入
原先的
在支付和订单模块
看下修改后的效果
那么原先的显示怎么回事
看下host
localhost:8081/actuator/health
让Eureka界面上有IP显示
服务发现Discovery
就是说Eureka上面很多服务,那么这些服务对应的信息比如 IP什么什么的
可以通过服务发现Discovery来获取该服务的信息
我单在8081里使用
发现不写这个注解也可以 上面没写
Eureka的自我保护
下面这排红字
概述:保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护,一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据,也就是不会注销任何微服务
上面红字就是说Eureka进入了保护模式
在保护模式下,某时刻一个微服务即使不可用,Eureka也不会立即清理,依旧会对该微服务的信息进行保存,属于CAP理论的AP分支
为什么会产生Eureka自我保护机制
为了防止EurekaClient可以正常运行,但是与EurekaServer网络不通情况下,防止错误剔除
什么是自我保护模式:
默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销实例(默认90秒).但是当网络分区故障发生(延时,卡顿,拥挤)时,微服务与EurekaServer之间无法正常通信,以上行为可能变得非常危险---因为微服务本身其实是健康的,此时不应该注销这个服务.Eureka通过自我保护模式来解决这个问题。当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式.