<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>cloud2020artifactId>
<groupId>com.atguigu.springcloudgroupId>
<version>1.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>cloud-eureka-server7001artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
<dependency>
<groupId>com.lun.springcloudgroupId>
<artifactId>cloud-api-commonsartifactId>
<version>${project.version}version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
dependency>
dependencies>
project>
server:
port: 7001
eureka:
instance:
hostname: locathost #eureka服务端的实例名称
client:
#false表示不向注册中心注册自己。
register-with-eureka: false
#false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
fetch-registry: false
service-url:
#设置与Eureka server交互的地址查询服务和注册服务都需要依赖这个地址。
defaultZone: http://${
eureka.instance.hostname}:${
server.port}/eureka/
@SpringBootApplication
@EnableEurekaServer // 表示为EurekaServer
public class EurekaMain7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7001.class, args);
}
}
eureka服务有了,但是没有客户(有server但是client没有注册进去)
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
eureka:
client:
#表示是否将自己注册进Eurekaserver默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
defaultZone: http://localhost:7001/eureka
@EnableEurekaClient // 表明是EurekaClient
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
spring:
application:
name: cloud-order-service
eureka:
client:
#表示是否将自己注册进Eurekaserver默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
defaultZone: http://localhost:7001/eureka
@EnableEurekaClient // 表明是EurekaClient
Eureka 集群
解决办法: 搭建Eureka注册中心集群,实现负载均衡+故障容错
找到C:\Windows\System32\drivers\etc路径下的hosts文件
127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com
通过命令:ipconfig /flushdns 刷新hosts文件
server:
port: 7001
spring:
application:
name: cloud-eureka-service
eureka:
instance:
# eureka服务端的实例名称
hostname: eureka7001.com
client:
# false表示不向注册中心注册自己
register-with-eureka: false
# false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要检索服务
fetch-registry: false
service-url:
# 设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址
defaultZone: http://eureka7002.com:7002/eureka/
server:
port: 7002
spring:
application:
name: cloud-eureka-service2
eureka:
instance:
hostname: eureka7002.com
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/
@SpringBootApplication
@EnableEurekaServer
public class EurekaMain7002 {
public static void main(String[] args) {
SpringApplication.run(EurekaMain7002.class, args);
}
}
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka # 集群版
pom文件的依赖和8001相同
yaml文件除了server-port为8002,其他与8001的都相同
主启动类
业务类也与8001相同
取出yaml中的servre-port,便于测试时的分析
@Value("${server.port}")
private String serverPort;
订单服务的访问地址不能写si,之前是指定的8001,现在支付服务是集群环境,所以需要用服务名进行访问
public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
由于一个集群中有多个服务,所以此时使用客户80访问时,会报错,因为不知道具体访问的是集群中的哪个服务,所以需要在 getRestTemplate上添加一个注解@LoadBalanced均衡负载,循环访问集群中的每个服务
修改yaml文件
eureka:
instance:
instance-id: payment8001 #修改服务名称
prefer-ip-address: true # 访问路径可以显示ip信息
对于注册eureka里面的微服务,可以通过服务发现来获得该服务的信息
注意discoveryClient的包时spring的那个,如果没有.getServices(),可以看看是不是包导错了
// 服务发现 获取服务信息
@Resource
private DiscoveryClient discoveryClient;
@GetMapping("/payment/discover")
public DiscoveryClient discover() {
// 获取注册中心的服务列表
List<String> services = discoveryClient.getServices();
for (String service : services) {
log.info("****服务:" + service);
}
// 获取某个服务的实例
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
for (ServiceInstance instance : instances) {
log.info("服务cloud-payment-service中有: " + "\t" + instance.getServiceId() + "\t" + instance.getInstanceId() + "\t" + instance.getHost());
}
return this.discoveryClient;
}
就用原来的@EnableEurekaClient似乎也是可以的
@SpringBootApplication
// 表明是EurekaClient,且只适用于Eureka注册中心
@EnableEurekaClient
// 二者都是可以让注册中心发现,扫描到该服务,区别在于EnableEurekaClient只适用于Eureka注册中心,而EnableDiscoveryClient可以为其他注册中心
@EnableDiscoveryClient
public class PaymentMain8001 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8001.class, args);
}
}
enable-self-preservation: false # 禁止eureka的自我保护,服务一旦没有"心跳",就会被剔除
lease-renewal-interval-in-seconds: 1 # Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)e
lease-expiration-duration-in-seconds: 2 # Eureka服务端在收到最后一次心跳后等待时间上限 ,单位为秒(默认是90秒),超时剔除服务
可以同时启动 7001(禁用自我保护) 和 7002(默认开启自动保护),然后启动8001,再stop 8001,就可以看到 7001中很快剔除8001,而7002中还有
Zookeeper是一个分布式协调工具,可以实现注册中心功能
Zookeeper服务器 取代 Eureka服务器,zk作为服务注册中心
<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>cloud2020artifactId>
<groupId>com.atguigu.springcloudgroupId>
<version>1.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>cloud-provider-payment8004artifactId>
<dependencies>
<dependency>
<groupId>com.atguigu.springcloudgroupId>
<artifactId>cloud-api-commonartifactId>
<version>${project.version}version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-zookeeper-discoveryartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
project>
server:
port: 8004 # 8004表示注册到zookeeper服务器的支付服务提供者端口号
spring:
application:
name: cloud-provider-payment # 服务别名---注册zookeeper到注册中心的名称
cloud:
zookeeper:
connect-string: 192.168.44.129:2181 # 默认localhost:2181
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain8004 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8004.class, args);
}
}
【 PS: 由于zookeeper的半数机制,最少必须启动三个server,一开始只启动了一个,然后启动了一会儿就一直报错。】
bin/zkServer.sh start
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-zookeeper-discoveryartifactId>
<exclusions>
<exclusion>
<groupId>org.apache.zookeepergroupId>
<artifactId>zookeeperartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.apache.zookeepergroupId>
<artifactId>zookeeperartifactId>
<version>3.4.10version>
dependency>
此时关闭8004后,zookeeper中的节点不在了,由此可见,创建的服务节点是临时节点。
<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>cloud2020artifactId>
<groupId>com.atguigu.springcloudgroupId>
<version>1.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>cloud-consumerzk-order80artifactId>
<dependencies>
<dependency>
<groupId>com.atguigu.springcloudgroupId>
<artifactId>cloud-api-commonartifactId>
<version>${project.version}version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-zookeeper-discoveryartifactId>
<exclusions>
<exclusion>
<groupId>org.apache.zookeepergroupId>
<artifactId>zookeeperartifactId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.apache.zookeepergroupId>
<artifactId>zookeeperartifactId>
<version>3.4.10version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
project>
server:
port: 80
spring:
application:
name: cloud-consumer-order # 服务别名
cloud:
zookeeper:
connect-string: 192.168.44.129:2181 # 注册到zookeeper地址
@SpringBootApplication
@EnableDiscoveryClient
public class OrderZkMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderZkMain80.class, args);
}
}
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
@RestController
@Slf4j
public class OrderZkController {
private String url = "http://cloud-provider-payment";
@Resource
private RestTemplate restTemplate;
@GetMapping("/consumer/payment/zk")
public String paymentInfo() {
return restTemplate.getForObject(url+"payment/zk", String.class);
}
}
https://www.consul.io/intro/index.html
https://www.consul.io/downloads.html
https://www.springcloud.cc/spring-cloud-consul.html
https://learn.hashicorp.com/consul/getting-started/install.html
consul agent -dev
http://localhost:8500/ui/dc1/services
<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>cloud2020artifactId>
<groupId>com.atguigu.springcloudgroupId>
<version>1.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>cloud-providerconsul-payment8006artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-consul-discoveryartifactId>
dependency>
<dependency>
<groupId>com.atguigu.springcloudgroupId>
<artifactId>cloud-api-commonartifactId>
<version>${project.version}version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
project>
server:
port: 8006 # consul服务端口
spring:
application:
name: cloud-provider-payment
cloud:
consul: # consul注册中心地址
host: localhost
port: 8500
discovery:
hostname: 127.0.0.1
service-name: ${
spring.application.name}
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain8006 {
public static void main(String[] args) {
SpringApplication.run(PaymentMain8006.class, args);
}
}
@RestController
@Slf4j
public class PaymentController {
@Value("${server.port}")
private String serverPort;
@RequestMapping("/payment/consul")
public String paymentConsul() {
return "SpringCloud with consul:" + serverPort + "\t" + UUID.randomUUID().toString();
}
}
<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>cloud2020artifactId>
<groupId>com.atguigu.springcloudgroupId>
<version>1.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>cloud-consumerconsul-order80artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-consul-discoveryartifactId>
dependency>
<dependency>
<groupId>com.atguigu.springcloudgroupId>
<artifactId>cloud-api-commonartifactId>
<version>${project.version}version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
project>
server:
port: 80
spring:
application:
name: cloud-consumer-order
cloud:
consul:
host: localhost
port: 8500
discovery:
hostname: 127.0.0.1
service-name: ${
spring.application.name}
@SpringBootApplication
@Slf4j
public class OrderConsulMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderConsulMain80.class, args);
}
}
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
@RestController
@Slf4j
public class OrderConsulController {
@Resource
private RestTemplate restTemplate;
private String INVOKE_URL = "http://cloud-provider-payment";
@GetMapping("/consumer/payment/consul")
public String paymentInfo() {
return restTemplate.getForObject(INVOKE_URL+"/payment/consul", String.class);
}
}
分区容错性要保证, 所以要么是CP, 要么是AP
CP(Zookeeper/Consul)
当网络分区出现后,为了保证一致性,就必须拒绝请求,否则无法保证一致性
结论:违背了可用性A的要求,只满足一致性和分区容错,即CP