导航目录
一、微服务架构概述
1.什么是微服务架构
微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务于服务之间采用轻量级的通信机制互相协作(通常是基于HTTP协议的RESTful API)。每个服务都围绕着具体业务进行构建,并且能够被独立的部署到生产环境、类生产环境等。另外,应当尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建。
2.SpringCloud简介
2.1是什么
SpringCloud是分布式微服务架构的一站式解决方案,是多种微服务架构落地技术的集合体,俗称微服务全家桶。
2.2 SpringCloud技术栈
二、微服务架构编码构建
2.1 创建父工程cloud2020
2.2 设置项目字符编码为UTF-8
2.3 注解生效激活
File–>Build–>Compiler–>Annotation Processors
2.4 Java编译版本选择8
File–>Build–>Compiler–>Java Compiler
2.5 导入父工程依赖
<?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>com.jg.springcloud</groupId>
<artifactId>cloud2020</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 表示是一个pom总的父工程 -->
<packaging>pom</packaging>
<modules>
<module>cloud-provider-payment8001</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>
<lombok.version>1.16.18</lombok.version>
<log4j.version>1.2.17</log4j.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>
<!-- 子模块继承之后,提供作用:锁定版本+子module不用写groupId和version -->
<dependencyManagement>
<dependencies>
<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-->
<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>
<!--mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
<scope>runtime</scope>
</dependency>
<!-- druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<!--mybatis-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.spring.boot.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>
<version>2.2.2.RELEASE</version>
</plugin>
</plugins>
</build>
</project>
2.5.1 dependencyManagement
Maven使用dependencyManagement元素来提供了一种管理依赖版本号的方式
通常会在一个组织或者项目的最顶层的父POM中看到dependencyManagement元素。
使用pom.xml中的dependencyManagement元素能让所有在子项目中引用一个依赖而不用显式的列出版本号。
Maven会沿着父子层次向上走,直到找到一个拥有dependencyManagement元素的项目,然后它就会使用这个dependencyManagement元素中指定的版本号。
这样做的好处就是:如果有多个子项目都引用同一样依赖,则可以避免在每个使用的子项目中都声明一个版本号,这样当想升级或切换到另一个版本时,只需要在顶层容器里更新,而不需要一个一个子项目的修改;另外如果某个子项目需要另外的一个版本,只需要声明version即可。
2.6 支付模块构建
2.6.1 建module
2.6.2 引pom
<dependencies>
<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>
2.6.3 写yml
# 端口号信息
server:
port: 8001
spring:
application:
name: cloud-payment-service
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包
url: jdbc:mysql://localhost:3306/db2019?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 123456
mybatis:
mapperLocations: classpath:mapper/*.xml
type-aliases-package: com.atguigu.springcloud.entities # 所有Entity别名类所在包
2.6.4 主启动
@SpringBootApplication
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class,args);
}
}
2.6.5 创建表
CREATE TABLE `payment`(
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`serial` varchar(200) DEFAULT '',
PRIMARY KEY(`id`)
)ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8
2.6.6 主实体Payment
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Payment {
private Long id;
private String serial;
}
2.6.7 JSON封装体
@Data
@AllArgsConstructor
@NoArgsConstructorpublic class CommonResult<T> {
private Integer code;
private String message;
private T data;
public CommonResult(Integer code,String message){
this(code,message,null);
}
}
2.6.8 Dao
@Mapper
public interface PaymentDao {
int create(Payment payment);
Payment getPaymentByID(@Param("id") Long id);
}
2.6.9 Mapper文件
<?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.jg.springcloud.dao.PaymentDao">
<resultMap id="BaseResultMap" type="com.jg.springcloud.entities.Payment">
<id column="id" property="id" jdbcType="BIGINT"/>
<id column="serial" property="serial" jdbcType="VARCHAR"/>
</resultMap>
<insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
insert into payment(serial) values(#{serial});
</insert>
<select id="getPaymentByID" parameterType="Long" resultMap="BaseResultMap">
select * from payment where id=#{id};
</select>
</mapper>
2.6.10 Service
public interface PaymentService {
int create(Payment payment);
Payment getPaymentByID(Long id);
}
2.6.11 ServiceImpl
@Service
public class PaymentServiceImpl implements PaymentService {
@Autowired
private PaymentDao paymentDao;
@Override
public int create(Payment payment) {
return paymentDao.create(payment);
}
@Override
public Payment getPaymentByID(Long id) {
return paymentDao.getPaymentByID(id);
}
}
2.6.12 Controller
@RestController
@Slf4j
public class PaymentController {
@Autowired
private PaymentService paymentService;
//返回给前端的结果集
@PostMapping(value = "/payment/create")
public CommonResult create(Payment payment) {
Integer result = paymentService.create(payment);
log.info("******插入结果:" + result);
if (result > 0) {
return new CommonResult(200, "插入数据库成功",result);
} else {
return new CommonResult(444, "插入数据库失败", null);
}
}
@GetMapping(value = "/payment/get/{id}")
public CommonResult getPaymentByID(@PathVariable("id") Long id) {
Payment payment = paymentService.getPaymentByID(id);
log.info("******插入结果:" + payment);
if (payment != null) {
return new CommonResult(200, "查询成功", payment);
} else {
return new CommonResult(444, "没有查询记录", null);
}
}
}
2.7 热部署
2.7.1 子工程添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
2.7.2 添加插件到父工程的pom.xml文件中
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<fork>true</fork>
<addResources>true</addResources>
</configuration>
</plugin>
2.7.3 开启自动编译
2.7.4 开启更新值
使用快捷键Ctrl+Alt+Shift+/打开更新值设置
2.7.5 重启IDEA
2.8 RestTemplate
2.8.1 是什么
RestTemplate提供了多种便携访问远程Http服务的方法,是一种简单便携的访问restful服务模板类,是Spring提供的用于访问Rest服务的客户端模板工具集。
2.8.2 客户端使用RestTemplate调用服务端的服务
配置
@Configuration
public class ApplicationContextConfig {
@Bean //@Bean相当于applicationContext.xml文件中的bean标签
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
controller层
@RestController
@Slf4j
public class OrderController {
//定义服务端URL
public static final String PAYMENT_URL = "http://localhost:8001";
//客户端通过RestTemplate调用服务端
@Autowired
private RestTemplate restTemplate;
@GetMapping("/consumer/payment/create")
public CommonResult<Payment> create(Payment payment) {
return restTemplate.postForObject(PAYMENT_URL+"/payment/create",payment,CommonResult.class);
}
@GetMapping("consumer/payment/get/{id}")
public CommonResult<Payment> getPayment(@PathVariable("id") Long id){
return restTemplate.getForObject(PAYMENT_URL+"/payment/get/"+id,CommonResult.class);
}
}
前端返回给后端json类型的数据实体在接收的时候,参数前应该加@RequestBody注解
2.9 工程重构
2.9.1 提取公共模块
把服务间公共部分提取出来抽象成一个公共的模块,这个模块不对外暴露接口
在cloud-provider-payment8001和cloud-consumer-order80服务里面均用到了CommonResult和Payment,所以把它们提取出来,放在一个公共模块中,这个模块不对外暴露端口号。
2.9.2 把这个公共模块做成依赖被其他模块导入
maven-clean AND maven-install
2.9.3 在要用到的模块中引入
<dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<groupId>com.jg.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>${project.version}</version>
</dependency>
三、Eureka服务注册和发现
3.1 Eureka基础知识
3.1.1 什么是服务治理
Spring Cloud封装了Netflix公司开发的Eureka模块来实现服务治理
在传统的rpc远程调用框架中,管理每个服务于服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务与服务之间的依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。
3.1.2 什么是服务注册与发现
Eureka采用了CS的设计架构,Eureka Server作为服务注册功能的服务器,它是服务注册中心。而系统中的其它微服务,使用Eureka的客户端连接到Eureka Server并维持心跳连接。这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。
在服务注册与发现中,有一个注册中心。当服务器启动的时候,会把当前自己服务器的信息,比如服务地址通讯地址等以别名方式注册到注册中心上。另一方(消费者|服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后再实现本地RPC调用RPC远程调用框架核心设计思想:在于注册中心,因为使用注册中心管理每个服务于服务之间的一个依赖关系(服务治理概念)。在任何RPC远程框架中,都会有一个注册中心(存放服务地址相关信息(接口地址))。
3.1.3 Eureka两组件
3.2 单机Eureka构建步骤
3.2.1 IDEA生成eurekaServer端服务注册中心
经典五步
建module
改pom
<dependencies> <!-- eureka-server--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> <version>2.2.2.RELEASE</version> </dependency> <!-- 引入自己定义的api通用包,可以使用Payment支付Entity --> <dependency> <groupId>com.jg.springcloud</groupId> <artifactId>cloud-api-commons</artifactId> <version>${project.version}</version> </dependency> <!--boot web actuator--> <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> </dependency> <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>
写yml
server: port: 7001 eureka: instance: hostname: localhost #eureka服务端的实例名称 client: # false表示不向注册中心注册自己 register-with-eureka: false # false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务 fetch-registry: false service-url: # 设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址 defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
主启动
@SpringBootApplication //表示这个服务是Eureka的注册中心 @EnableEurekaServer public class EurekaMain7001{ public static void main(String[] args) { SpringApplication.run(EurekaMain7001.class,args); } }
业务类
Eureka注册中心Web页面
3.2.2 EurekaClient端cloud-provider-payment8001将注册进EurekaServer成为服务提供者provider,对外提供服务
导入依赖
<!-- EurekaClient作为服务提供者需要引入的jar包-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
application.xml修改配置
#Eureka配置
eureka:
client:
# 表示是否将自己注册进EurekaServer,默认为true
register-with-eureka: true
# 是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetch-registry: true
# EurekaServer的地址
service-url:
defaultZone: http://localhost:7001/eureka
修改主启动类
@EnabkeEurekaClient //在主启动类上添加注解
如此配置,启动服务,该服务就可以注册到EurekaServer中
3.2.3 EurekaClient端cloud-consumer-order80将注册进EurekaServer成为服务消费者consumer,类似消费者
跟上面步骤相同
3.3 集群Eureka构建步骤
3.3.1 Eureka集群原理
微服务RPC远程服务调用最核心的是什么
高可用,试想你的注册中心只有一个only one,它出故障了那就全都完了,会导致整个微服务环境不可用,所以解决办法是需要搭建Eureka注册中心集群,实现负载均衡和故障容错。
集群注册的原理是互相注册,相互守望
3.3.2 EurekaServer集群环境构建步骤
参考cloud-eureka-server7001,新建一个cloud-eureka-server7002
修改系统的映射文件–>hosts
#SpringCloud 127.0.0.1 eureka7001.com 127.0.0.1 eureka7002.com
集群环境下,EurekaServer的配置
server: port: 7001 eureka: instance: hostname: eureka7001.com #eureka服务端的实例名称 client: # false表示不向注册中心注册自己 register-with-eureka: false # false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务 fetch-registry: false service-url: # 设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址 defaultZone: http://eureka7002.com:7002/eureka/
把服务注册进EurekaServer
修改配置文件
service-url: #defaultZone: http://localhost:7001/eureka defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
支付服务的集群环境搭建
直接复制cloud-provider-payment8001即可,只有一些小的细节需要完善。
3.3.3 服务发现
微服务提供方如果有多节点集群环境,需要配置才能被服务调用方正常发现并调用
具体实现
在配置类对应方法上添加@LoadBalanced注解,用于实现RestTemplate的负载均衡能力
服务调用方在的请求URL不是像以前那样写死,而是直接写服务提供方的应用名(服务提供方已经做了集群环境)
后续可以使用Ribbon整合Eureka实现负载均衡,可以直接调用服务而不用在关心地址和端口号
3.4 actuator微服务信息完善
3.4.1 主机名称:服务名称修改
解决方案:修改cloud-provider-payment8001的application.yml
的中关于Eureka的配置
添加如下内容
instance:
instance-id: payment8002
修改之后的效果**
3.4.2 访问信息有IP信息提示
instance:
instance-id: payment8002
#此配置是为了让访问路径可以显示IP地址
prefer-ip-address: true
3.5 服务发现Discovery
3.5.1 功能
对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息
3.5.2 实现
修改服务提供方的Controller和主启动类
Controller上的修改
主启动类上的修改
主启动类上添加@EnableDiscoveryClient
注解
效果
后台发现的服务
3.6 Eureka自我保护
3.6.1 概述
保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护。一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不在删除服务注册表中的数据,也就是不会注销任何微服务。
如果在Eureka Server的首页看到以下这段提示,则说明Eureka进入了保护模式
3.6.2 导致的原因
某时刻某一个微服务不可用了,Eureka不会立刻清理,依旧会对该微服务的信息进行保存。
为了防止EurekaClient可以正常运行,但是与EurekaServer网络不通情况下,EurekaServer不会立刻将EurekaClient服务剔除。
3.6.3 什么是自我保护模式?
默认情况西,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生(延时、卡顿、拥挤)时,微服务与EurekaServer之间无法正常通信,以上行为可能变得非常危险了-因为微服务本身其实是健康的,此时本不应该注销这个微服务。Eureka通过“自我保护模式”来解决这个问题----当EurekaServer节点在短时间内丢失过多客户端是(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。
3.6.4 怎么关闭自我保护机制
在EurekaServer服务端的application.yml
中配置
server:
#关闭自我保护机制,保证不可用服务被及时剔除
enable-self-preservation: false
eviction-interval-timer-in-ms: 2000
在服务端设置心跳检测和续约时间application.yml
#心跳检测与续约时间
#开发时设置小些,保证服务关闭后注册中心及时剔除服务
instance:
#Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
lease-renewal-interval-in-seconds: 1
#Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务
lease-expiration-duration-in-seconds: 2
3.7 Eureka停更说明
SpringCloud整合Zookeeper代替Eureka
四、Zookeeper服务注册与发现
4.1 Zookeeper的安装
- 解压Zookeeper的安装包到指定目录
- 创建Zookeeper的存放数据的文件夹(一般在解压之后的目录下)
- 修改Zookeeper的配置文件,加上刚才创建的文件夹的路径
- 安装完毕,启动
4.2 使用Zookeeper进行服务注册的步骤
经典五步
建module
引pom
<dependencies> <groupId>com.jg.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> <!-- SpringBoot整合zookeeper客户端,这里不再使用Eureka进行服务注册,所以这里导入的是Zookeeper的相关依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId> <!--先排除自带的zookeeper3.5.3--> <exclusions> <exclusion> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> </exclusion> </exclusions> </dependency> <!--添加zookeeper3.4.10版本--> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.10</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>
写yml
#8004表示注册到Zookeeper服务器的支付服务提供者端口号 server: port: 8004 #服务别名----注册到Zookeeper到注册中心名称 spring: application: name: cloud-provider-payment cloud: zookeeper: #Zookeeper的地址 connect-string: 192.168.170.132:2181
主启动
@SpringBootApplication //该注解用于使用Consul或者Zookeeper作为注册中心是注册服务 @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(value = "/payment/zk") public String paymentZK(){ return "springcloud with zookeeper:"+serverPort+"\t"+ UUID.randomUUID().toString(); } }
如上配置,启动服务,进入zookeeper的服务中心页面bin/zkCli.sh
,就可以看到刚才启动的服务已经注册成功。
zookeeper上服务信息
4.3 一些细节
Zookeeper上面的服务节点是临时的
可以看到,当我们把注册进Zookeeper的服务关掉之后,过了一段时间,注册进Zookeeper中的服务就会被Zookeeper从节点中移除。而并不是说服务挂掉,Zookeeper还会保证这个服务一直存活在Zookeeper的节点上。
五、Consul服务注册与发现
5.1 简介
5.1.1 是什么
Consul是一套开源的分布式服务发现和配置管理系统,由HashiCorp公司用Go语言开发的。
提供了微服务系统中的服务治理、配置中心、控制总线等功能。这些功能中的每一个都可以根据需要单独使用,也可以一起使用以构建全方位的服务网络,总之Consul提供了一种完整的服务网格解决方案。
它具有很多优点。包括:基于raft协议,比较简洁;支持健康检查,同时支持HTTP和DNS协议,支持跨数据中心的WAN集群,提供图形界面,跨平台,支持Linux、Mac、Windows。
5.1.2 能干嘛
服务发现
提供HTTP和DNS两种发现方式。
健康监测
支持多种方式,HTTP、TCP、Docker、Shell脚本定制化
KV存储
Key、Value的存储方式
多数据中心
Consul支持多数据中心
可视化Web界面
5.1.3 去哪下
5.1.4 怎么玩
5.2 安装并运行
下载完成之后只有一个consul.exe文件
在consul.exe目录下运行cmd命令行窗口,输入
consul --version
可以查看当前安装的consul的版本
使用开发模式启动
consul agent -dev
5.3 服务提供者
新建Module支付服务cloud-providerconsul-payment8006
导入依赖
<dependencies>
<!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
<dependency>
<groupId>com.jg.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--SpringCloud consul-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!-- SpringBoot整合Web组件 -->
<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>
<!--日常通用jar包配置-->
<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>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>RELEASE</version>
<scope>test</scope>
</dependency>
</dependencies>
修改application.yml文件
server:
port: 8006
spring:
application:
name: consul-provider-payment
# Consul注册中心地址
cloud:
consul:
port: 8500
discovery:
service-name: ${spring.application.name}
hostname: 127.0.0.1
主启动
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentConsulMain {
public static void main(String[] args) {
SpringApplication.run(PaymentConsulMain.class,args);
}
}
如此配置,服务启动之后会注册到Consul中
5.4 服务消费者
依旧是好经典五步走
pom
<dependencies>
<!--SpringCloud consul-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!-- SpringBoot整合Web组件 -->
<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>
<!--日常通用jar包配置-->
<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>
###consul服务端口号
server:
port: 80
spring:
application:
name: cloud-consumer-order
####consul注册中心地址
cloud:
consul:
host: localhost
port: 8500
discovery:
#hostname: 127.0.0.1
service-name: ${spring.application.name}
Main
@SpringBootApplication
@EnableDiscoveryClient
public class OrderConsulMain {
public static void main(String[] args) {
SpringApplication.run(OrderConsulMain.class,args);
}
}
Controller
@RestController
@Slf4j
public class OrderConsulController {
public static final String INVOKE_URL = "http://consul-provider-payment";
@Autowired
private RestTemplate restTemplate;
@GetMapping("/consumer/payment/consul")
public String paymentInfo(){
return restTemplate.getForObject(INVOKE_URL+"/payment/consul",String.class);
}
}
5.5 三个注册中心的区别
组件名 | 开发语言 | CAP | 服务健康检查 | 对外暴露接口 | Spring Cloud集成 |
---|---|---|---|---|---|
Eureka | Java | AP | 可配支持 | HTTP | 已集成 |
Consul | GO | CP | 支持 | HTTP/DNS | 已集成 |
Zookeeper | Java | CP | 支持 | 客户端 | 已集成 |