Spring Cloud之服务注册
一、入门
1.1、了解spring微服务
spring微服务文章原文与spring cloud官网与中文文档;
传统的单体架构:将项目写在一起,写完打war包,发布至tomcat或者其它容器中。
微服务架构:将一个单一的服务开发成多个模块,每个模块运行在单独的进程中,各个服务之间通过HTTP调用。
Spring Cloud:微服务工具包,为开发者提供了在分布式系统的配置管理、服务发现、断路器、智能路由、微代理、控制总线等开发工具包。
入门搭建的简单spring微服务架构还没有用到任何spring cloud的东西,后续会一点一点增加。
1.2、搭建spring cloud项目
创建新的maven项目,maven版本选择自己本机安装的maven,创建成功后打开idea设置,设置Java编译版本,设置字符集编码格式,设置忽略文件格式,设置maven版本。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>
<!--maven坐标-->
<groupId>com.atguigu</groupId>
<artifactId>springcloud</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 父工程,pom -->
<packaging>pom</packaging>
<!--版本依赖,统一jar包管理-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.build.outputEncoding>UTF-8</project.build.outputEncoding>
<java.version>1.8</java.version>
<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.7.24</mysql.version>
<druid.version>1.1.16</druid.version>
<mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
</properties>
<name>Maven</name>
<!-- FIXME change it to the project's website -->
<url>http://maven.apache.org/</url>
<inceptionYear>2001</inceptionYear>
<!--用于父工程,子工程直接继承,锁定模块和子模块不用谢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>
</dependencies>
</dependencyManagement>
<distributionManagement>
<site>
<id>website</id>
<url>scp://webhost.company.com/www/website</url>
</site>
</distributionManagement>
<build>
<pluginManagement>
<!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>3.7.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>3.0.0</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<configuration>
<locales>en,fr</locales>
</configuration>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
</plugin>
</plugins>
</reporting>
</project>
dependencyManagement和dependencies区别:dependencyManagement是父类用的,用来规定依赖版本,子模块会自动继承父工程的版本,但是它只是限制规范不引入依赖,真正引入依赖的是GAV。
设置maven跳过单元测试,忽略版本检测,节约大量时间。点击install打包放入仓库,子工程好继承,build success为成功,clean测试整合结果。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-egcUvD16-1584764885660)(F:\Typora\Spring Cloud\基础\QQ截图20200318105341.png)]
1.3、建module子工程模块—服务提供者
建module,改pom,写yml,主启动,业务类,测试。
创建新的模块cloud-provider-payment8001,支付模块8001端口。在父工程右键创建新的模块,选择maven项目。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>springcloud</artifactId>
<groupId>com.atguigu</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<!--不用G和V-->
<artifactId>cloud-provider-payment8001</artifactId>
<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>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<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>
父工程的pom文件多出来两行
<modules>
<module>cloud-provider-payment8001</module>
</modules>
yml文件创建: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/db2019
username: root
password: 123456
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.atguigu.springcloud.entities
创建主启动类
@SpringBootApplication
public class Payment8001 {
public static void main(String[] args) {
SpringApplication.run(Payment8001.class,args);
}
}
controller层 注:service层dao层忽略
@RestController
@Slf4j
public class PaymentController {
@Resource
PaymentServiceImpl paymentService;
@PostMapping("/payment/create")
public CommonResult create(@RequestBody Payment payment){
int result = paymentService.create(payment);
log.info("插入结果:" + result );
if (result >0){
return new CommonResult(200,"插入成功",result);
}else {
return new CommonResult(444,"插入失败",null);
}
}
@GetMapping("/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,"查询失败,根据id:" + id,null);
}
}
}
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="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" parameterType="Long" resultMap="BaseResultMap">
select * from payment where id = #{id};
</select>
</mapper>
开启Run Dashboard空间控制多个模块,新版本是services
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hC4nyvhN-1584764885662)(F:\Typora\Spring Cloud\基础\QQ截图20200318154036.png)]
1.4、建module子工程模块—服务消费者
大致过程与上述差不多,只不过此处controller要通过RestTemplate调用提供者模块,不需要service层和dao层。
注册RestTemplate
@Configuration
public class ApplicationConfigure {
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
controller层:
@RestController
@Slf4j
public class OrderController {
private static final String PAYMENT_URL="http://localhost:8001";
@Resource
private RestTemplate 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<Payment> getPayment(@PathVariable("id") Long id){
return restTemplate.getForObject(PAYMENT_URL + "/payment/get/" + id , CommonResult.class);
}
}
1.5、项目重组
因为消费者、提供者所用的实体类都一样,所以可以抽取出来,新建module,打包放入仓库,然后消费者和提供者模块pom文件中引入。
新建项目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>springcloud</artifactId>
<groupId>com.atguigu</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-api-commons</artifactId>
<dependencies>
<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>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.1.0</version>
</dependency>
</dependencies>
</project>
在模块中引用:
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
最后结构:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Spb3ZjlA-1584764885664)(F:\Typora\Spring Cloud\基础\QQ截图20200318153743.png)]
二、服务注册与发现Eureka、Zookeeper、Consul
服务注册中心是微服务不可分离的一部分,现在能够做服务注册中心的有Eureka、Zookeeper、Consul、Nacos。没有服务注册中心时我们使用httpClient也就是上边用的restTemplate依旧能够实现服务调用,但是他们没有办法做到容错、发现、熔断、负载、降级等。
2.1 单机Eureka
C/S架构,三部分组成
Eureka Server :作为一个独立的部署单元,以 REST API 的形式为服务实例提供了注册、管理和查询等操作。同时,Eureka Server 也为我们提供了可视化的监控页面,可以直观地看到各个 Eureka Server 当前的运行状态和所有已注册服务的情况。
Service Provider:服务提供方,将自身服务注册到Eureka,从而使服务消费方能够找到
Service Consumer:服务消费方,从Eureka获取注册服务列表,从而能够消费服务
2.1.1建模块cloud-eureka-server7001
改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>springcloud</artifactId>
<groupId>com.atguigu</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-eureka-server7001</artifactId>
<dependencies>
<!--自定义jar包-->
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--eureka-server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</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-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>
写yml文件
server:
port: 7001
#配置为Eureka的服务端-服务注册中心
eureka:
instance:
hostname: localhost #eureka注册的服务端实例名
client:
register-with-eureka: false #是否注册自己,false表示不注册
fetch-registry: false #自己就是注册中心,职责就是维护实例不需要检索服务。
#设置uereka交互的地址,查询注册的服务
service-url:
defaultZone: http//${eureka.instance.hostname}:${server.port}/eureka/
主启动
//表示这是eureka server端
@EnableEurekaServer
@SpringBootApplication
public class EurekaMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7001.class,args);
}
}
访问http://localhost:7001/,显示eureka的主页面
2.1.2 Payment8001服务入驻
找到8001模块,添加eureka-client依赖。
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
修改yml文件,,添加如下配置
eureka:
client:
#表示是否将自己注册进eureka,false不入驻
register-with-eureka: true
#表示是否让eureka注册中心抓取自己信息,单点无所谓,集群必须是true
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka/
主启动类添加
@EnableEurekaClient
访问http://localhost:7001/,显示eureka的主页面,发现有服务注册进来。
#入住注册中心的服务名与这个保持一致
spring:
application:
name: cloud-payment-service
2.1.3 Order80服务入驻
细节如上,结果如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-og76QncE-1584764885671)(F:\Typora\Spring Cloud\基础\入驻2.png)]
2.2 集群Eureka,高可用
避免单机版eureka出现宕机情况,eureka server为注册中心,consumer server去取,实际上就是服务端存储K-V键值对。服务调用实际上根据服务名通过RPC进行远程调用。底层就是HTTP client。
集群原理:互相注册,相互守望,对外暴露一个整体。
2.2.1 建模块cloud-eureka-server7002 具体过程同7001
pom同7001,yml文件同7001,但是稍有变化,主启动类省略
改hosts文件加入,假装两台主机
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
yml文件,7001 7002都要改
server:
port: 7002
#配置为Eureka的服务端-服务注册中心
eureka:
instance:
hostname: eureka7002.com #eureka注册的服务端实例名,集群中不能同名为了区分
client:
register-with-eureka: false #是否注册自己,false表示不注册
fetch-registry: false #自己就是注册中心,职责就是维护实例不需要检索服务。
#设置uereka交互的地址,查询注册的服务
service-url:
defaultZone: http://eureka7001.com:7001/eureka/ #相互注册,2入驻1,1入驻2
http://eureka7001.com:7001/ 和http://eureka7002.com:7002/和http://localhost:7001/和http://localhost:7002/都能访问,且2指向1,1指向2
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gcHiLV9q-1584764885677)(F:\Typora\Spring Cloud\基础\集群3.png)]
2.2.2 服务入驻集群
只修改8001和80的yml文件即可
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7001.com:7001/eureka/
2.3 支付服务8001集群创建
注册中心现在已经是集群模式,但是服务模块不是,将微服务模块也建成集群模式,那么高可用会大大加强。
新建cloud-provider-payment8002,建model,改pom,写yml,主启动,业务类
去改controller,便于区分来自哪个模块
@RestController
@Slf4j
public class PaymentController {
@Resource
PaymentServiceImpl paymentService;
@Value("${server.port}")
private String serverPort;
@PostMapping("/payment/create")
public CommonResult create(@RequestBody Payment payment){
int result = paymentService.create(payment);
log.info("插入结果:" + result );
if (result >0){
return new CommonResult(200,"插入成功,端口号:" + serverPort,result);
}else {
return new CommonResult(444,"插入失败,端口号:"+ serverPort,null);
}
}
@GetMapping("/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,"查询成功,端口号:" + serverPort,payment);
}else {
return new CommonResult(444,"查询失败,根据id:" + id,null);
}
}
}
此时去改order80的controller,把写死的url改了
//传统
//private static final String PAYMENT_URL="http://localhost:8001";
//eureka集群时url不能写死,使用eureka中用的服务名
private static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
还要去改80的ApplicationConfigure,开始RestTemplate负载均衡才行
@Configuration
public class ApplicationConfigure {
//使用此注解,开始RestTemplate负载均衡才行
@LoadBalanced
@Bean
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
访问http://localhost/consumer/payment/get/1测试,发现实现了负载均衡
2.4 简单信息完善设置
2.4.1 主机名称修改
修改服务提供者8001 8002yml文件
eureka:
instance:
instance-id: payment01
http://localhost:8001/actuator/health,能查看服务状态
2.4.2 访问信息有IP信息提示
yml文件中添加
eureka:
instance:
#在eureka监控网页鼠标放上去显示IP地址
prefer-ip-address: true
2.4.3 服务发现Discovery
在服务提供者的controller中注入DiscoveryClient
@Resource
DiscoveryClient discoveryClient;
2.5 Eureka的自我保护机制
一行红字就是自我保护信息:EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE. 紧急! 如果不是,EUREKA可能会不正确地提出索赔要求。 续订比阈值要少,因此仅出于安全性考虑,实例不会过期。
就是在eureka中注册的服务就算是不可用,eureka也不会注销服务,会保留你的信息。微服务CAP中的A(高可用)P(分支容错率)分支。高可用设计思想。默认eureka server端会收到eureka client端的心跳,就算是短期没有收到心跳,也不会删除服务的实例,可能因为网络拥堵导致假死。宁可保留所有微服务,也不会盲目删除服务。
怎么关闭自我保护机制,前往eureka的server端的yml文件设置:
eureka:
# 关闭自我保护机制 ,默认为true,是开启的,下边设置超时心跳时间,默认90秒,现在改为2秒
server:
enable-self-preservation: false
eviction-interval-timer-in-ms: 2000
去服务提供模块也就是eureka client端添加yml
#客户端向服务端发送心跳的时间间隔,默认30秒
# lease-renewal-interval-in-seconds: 30
# 服务端等待时间上限,超时将清除服务
# lease-expiration-duration-in-seconds:
3. zookeeper
eureka停止更新了,怎么办?使用zookeeper代替,核心就是将eureka server替换为zookeeper。
关闭防火墙,启动zookeeper,
新建module cloud-provider-payment8004,改pom,写yml,主启动,业务类,
pom文件相比于8001只需要删去eureka client,加上zookeeper
<!--spring boot整合zookeeper-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<exclusions>
<!--排除apache的zookeeper3.5.3-->
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--添加和自己zookeeper版本相符合的jar-->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.5.6</version>
<!--排除sl4j-->
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
application.yml
server:
port: 8004
#入住注册中心的服务名
spring:
application:
name: cloud-payment-service
#配置zookeeper
cloud:
zookeeper:
#zookeeper的IP+端口号
connect-string: 192.168.229.130:2181
主启动类
//必须加这个注解,开启服务发现
@EnableDiscoveryClient
@SpringBootApplication
public class Payment8004 {
public static void main(String[] args) {
SpringApplication.run(Payment8004.class,args);
}
}
controller用于测试
@RestController
@Slf4j
public class PaymentController {
@Value("${server.port}")
private String serverPort;
@RequestMapping("/payment/zk")
public String paymentZk(){
return "spring cloud with zookeeper:" + serverPort + "\t" + UUID.randomUUID().toString();
}
}
启动zookeeper的 server和client
[root@localhost bin]# ./zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /opt/software/myzookeeper/apache-zookeeper-3.5.6-bin/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED
WatchedEvent state:SyncConnected type:None path:null
[zk: localhost:2181(CONNECTED) 0]
查看zookeeper,发现有service成功入驻zookeeper,最后的json串是微服务的信息
[zk: localhost:2181(CONNECTED) 8] ls /
[dubbo, services, zookeeper]
[zk: localhost:2181(CONNECTED) 9] ls /services
[cloud-payment-service]
[zk: localhost:2181(CONNECTED) 10] ls /services/cloud-payment-service
[292ecc2f-177f-4c80-8ba8-29d7e13ac2d2]
[zk: localhost:2181(CONNECTED) 12] get /services/cloud-payment-service/292ecc2f-177f-4c80-8ba8-29d7e13ac2d2
{"name":"cloud-payment-service","id":"292ecc2f-177f-4c80-8ba8-29d7e13ac2d2","address":"localhost","port":8004,"sslPort":null,"payload":{"@class":"org.springframework.cloud.zookeeper.discovery.ZookeeperInstance","id":"application-1","name":"cloud-payment-service","metadata":{}},"registrationTimeUTC":1584613767722,"serviceType":"DYNAMIC","uriSpec":{"parts":[{"value":"scheme","variable":true},{"value":"://","variable":false},{"value":"address","variable":true},{"value":":","variable":false},{"value":"port","variable":true}]}}
json格式化后
{
"name": "cloud-payment-service",
"id": "292ecc2f-177f-4c80-8ba8-29d7e13ac2d2",
"address": "localhost",
"port": 8004,
"sslPort": null,
"payload": {
"@class": "org.springframework.cloud.zookeeper.discovery.ZookeeperInstance",
"id": "application-1",
"name": "cloud-payment-service",
"metadata": {}
},
"registrationTimeUTC": 1584613767722,
"serviceType": "DYNAMIC",
"uriSpec": {
"parts": [{
"value": "scheme",
"variable": true
}, {
"value": "://",
"variable": false
}, {
"value": "address",
"variable": true
}, {
"value": ":",
"variable": false
}, {
"value": "port",
"variable": true
}]
}
}
问题来了,这是临时节点还是永久节点?服务节点是临时节点,如果挂了就没了,重启就再回来,只不过是一个新的了。
3.2订单入驻zookeeper
新建模块cloud-consumerZk-order80,具体如上,注意写RestTemplate配置
constroller
@Slf4j
@RestController
public class OrderController {
@Resource
private RestTemplate restTemplate;
private static final String INVOKE_URL="http://cloud-payment-service" ;
@GetMapping("/consumer/payment/zk")
public String paymentinfo(){
String result = restTemplate.getForObject(INVOKE_URL + "/payment/zk", String.class);
return result;
}
}
访问:http://localhost/consumer/payment/zk测试
4. Consul
4.1什么是consul
Consul能够做服务注册与发现、健康检测、KV存储、多数据中心、可视化界面,如果不是AlibabaNacos的出现,他就是eureka的接班人Consul官网,下载地址,此处使用Windows版64位,下载之后直接解压就一个exe文件,此处1.6.1版本。
What is Consul?
Consul is a service mesh solution providing a full featured control plane with service discovery, configuration, and segmentation functionality. Each of these features can be used individually as needed, or they can be used together to build a full service mesh. Consul requires a data plane and supports both a proxy and native integration model. Consul ships with a simple built-in proxy so that everything works out of the box, but also supports 3rd party proxy integrations such as Envoy.
什么是Consul?
Consul是一种服务网格解决方案,提供具有服务发现,配置和分段功能的全功能控制平面。这些功能中的每一个都可以根据需要单独使用,也可以一起使用以构建完整的服务网格。领事需要数据平面,并支持代理和本机集成模型。Consul附带了一个简单的内置代理,因此一切都可以直接使用,还支持Envoy等第三方代理集成。
consul agent -dev 打开文件夹所在目录cmd窗口,通过命令运行
访问 http://localhost:8500访问
4.2 服务提供者cloud-provider-payment8006注册进去,建module,改pom,写yml,主启动,业务类。
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>springcloud</artifactId>
<groupId>com.atguigu</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-provider-payment8006</artifactId>
<dependencies>
<!--consul-server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!--重组项目,抽取公共部分install仓库的jar包-->
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--web和actuator算是组合jar包-->
<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>
<!-- spring boot热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--Lombok-->
<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>
yml
server:
port: 8006
spring:
application:
name: consul-provider-payment
cloud:
consul:
host: localhost
discovery:
service-name: ${spring.application.name}
port: 8500
主启动
@EnableDiscoveryClient
@SpringBootApplication
public class PaymentMain8006 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8006.class,args);
}
}
访问:http://localhost:8006/payment/consul测试,http://localhost:8500查看
4.3创建消费者cloud-consumerCs-order80,建module,改pom,写yml,主启动,业务类。
pom
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>springcloud</artifactId>
<groupId>com.atguigu</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-consumerCs-order80</artifactId>
<dependencies>
<!--consul-server-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!--重组项目,抽取公共部分install仓库的jar包-->
<dependency>
<groupId>com.atguigu</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--web和actuator算是组合jar包-->
<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>
<!-- spring boot热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--Lombok-->
<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>
yml
server:
port: 80
spring:
application:
name: consul-consumer-order
cloud:
consul:
host: localhost
discovery:
service-name: ${spring.application.name}
port: 8500
主启动
@SpringBootApplication
@EnableDiscoveryClient
public class OrderMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderMain80.class,args);
}
}
controller
@Slf4j
@RestController
public class OrderController {
@Resource
private RestTemplate restTemplate;
private static final String INVOKE_URL="http://consul-provider-payment" ;
@GetMapping("/consumer/payment/consul")
public String paymentinfo(){
String result = restTemplate.getForObject(INVOKE_URL + "/payment/consul", String.class);
return result;
}
}
访问http://localhost/consumer/payment/consul,和http://localhost:8500查看
三个注册中心异同点
组件名 | 语言 | CAP | 服务健康检查 | 对外暴露接口 | spring cloud集成 |
---|---|---|---|---|---|
eureka | Java | AP | 可以配置支持 | HTTP | 已集成 |
zookeeper | Java | CP | 支持 | 客户端 | 已集成 |
consul | Go | CP | 支持 | HTTP/DNS | 已集成 |
CAP原则又称CAP定理,指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。
一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
分区容忍性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
CAP原则的精髓就是要么AP,要么CP,要么AC,但是不存在CAP。如果在某个分布式系统中数据无副本, 那么系统必然满足强一致性条件, 因为只有独一数据,不会出现数据不一致的情况,此时C和P两要素具备,但是如果系统发生了网络分区状况或者宕机,必然导致某些数据不可以访问,此时可用性条件就不能被满足,即在此情况下获得了CP系统,但是CAP不可同时满足 。
访问http://localhost/consumer/payment/consul,和http://localhost:8500查看
三个注册中心异同点
组件名 | 语言 | CAP | 服务健康检查 | 对外暴露接口 | spring cloud集成 |
---|---|---|---|---|---|
eureka | Java | AP | 可以配置支持 | HTTP | 已集成 |
zookeeper | Java | CP | 支持 | 客户端 | 已集成 |
consul | Go | CP | 支持 | HTTP/DNS | 已集成 |
CAP原则又称CAP定理,指的是在一个分布式系统中, Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。
一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
分区容忍性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。
CAP原则的精髓就是要么AP,要么CP,要么AC,但是不存在CAP。如果在某个分布式系统中数据无副本, 那么系统必然满足强一致性条件, 因为只有独一数据,不会出现数据不一致的情况,此时C和P两要素具备,但是如果系统发生了网络分区状况或者宕机,必然导致某些数据不可以访问,此时可用性条件就不能被满足,即在此情况下获得了CP系统,但是CAP不可同时满足 。
CAP关注的粒子颗度是数据,不是架构。