1. 集群Eureka的构建(续)
1.1 订单支付两微服务注册进Eureka集群
修改支付模块和订单模块的YML配置启动7001 7002 8001 8200测试 1.2 支付服务提供者集群环境的构建
创建一个相似模块8002修改两个模块的Controller 1.3 负载均衡
修改80模块订单服务访问地址使用@LoadBalanced注解赋予RestTemplate负载均衡的能力启动测试 1.4 actuator微服务信息完善
修改8001 8002主机名称服务名称修改IP地址提示结果 1.5 服务发现Discovery1.6 Eureka自我保护
为什么会产生Eureka自我保护机制?自我保护模式是啥 1.7 怎么禁止自我保护(默认情况下开启)1.8 Eureka已停更 2. Zookeeper
1. Linux下的安装2. 支付服务注册进Zookeeper
首先在Linux下启动zookeeper配置模块8004
首先引入依赖时要注意依赖冲突启动类加注解编写controller启动后 3. ZooKeeper的服务节点是临时节点,没有Eureka那含情脉脉。4.订单服务注册进zookeeper
pomymlconfig接口访问结果 3.Consul
3.1 简介与安装3.2 服务提供者注册进Consul
pomyml启动类Controller结果: 3.3 服务消费者进Consul
pomymlconfig、启动类、controller结果: 三个注册中心的异同点
1. 集群Eureka的构建(续) 1.1 订单支付两微服务注册进Eureka集群 修改支付模块和订单模块的YML配置eureka:
client:
#表示是否将自己注册进Eurekaserver默认为true。
register-with-eureka: true
#是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
fetchRegistry: true
service-url:
# defaultZone: http://localhost:7001/
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
启动7001 7002 8001 8200测试
1.2 支付服务提供者集群环境的构建
创建一个相似模块8002
修改两个模块的Controller
添加:
@Value("${server.port}")
private String serverPort;
读取配置文件的属性
1.3 负载均衡 修改80模块订单服务访问地址public static final String PAYMENT_URL="http://localhost:8001"; 将其修改为: public static final String PAYMENT_URL="http://CLOUD-PAYMENT-SERVICE";使用@LoadBalanced注解赋予RestTemplate负载均衡的能力
修改80模块下的 config-下的ApplicationContextConfig
public class ApplicationContextConfig
{
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
为其添加注解@LoadBalanced
启动测试
在YML中添加
eureka:
instance:
instance-id: payment8001
IP地址提示
在修改的基础上再添加一句
instance:
instance-id: payment8001
prefer-ip-address: true
结果
1.5 服务发现Discovery
对于注册进eureka里面的微服务,可以通过服务发现来获得该服务的信息
修改8001的Controller
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping(value = "/payment/discovery")
public Object discovery()
{
List services = discoveryClient.getServices();
for (String element : services) {
log.info("*****element: "+element);
}
List instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
for (ServiceInstance instance : instances) {
log.info(instance.getServiceId()+"t"+instance.getHost()+"t"+instance.getPort()+"t"+instance.getUri());
}
return this.discoveryClient;
}
修改启动类
添加注解 @EnableDiscoveryClient//添加该注解
访问对应的接口即可
1.6 Eureka自我保护为什么会产生Eureka自我保护机制?保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护。一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据,也就是不会注销任何微服务。
如果在Eureka Server的首页看到以下这段提示,则说明Eureka进入了保护模式:
EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY’RE NOT. RENEWALS ARE LESSER THANTHRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUSTTO BE SAFE
即:某时刻某一个微服务不可用了,Eureka不会立刻清理,依旧会对该微服务的信息进行保存。
自我保护模式是啥为了EurekaClient可以正常运行,防止与EurekaServer网络不通情况下,EurekaServer不会立刻将EurekaClient服务剔除
1.7 怎么禁止自我保护(默认情况下开启)默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销该实例(默认90秒)。但是当网络分区故障发生(延时、卡顿、拥挤)时,微服务与EurekaServer之间无法正常通信,以上行为可能变得非常危险了——因为微服务本身其实是健康的,此时本不应该注销这个微服务。Eureka通过“自我保护模式”来解决这个问题——当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式。默认情况下EurekaClient定时向EurekaServer端发送心跳包。
如果Eureka在server端在一定时间内(默认90秒)没有收到EurekaClient发送心跳包,便会直接从服务注册列表中剔除该服务,但是在短时间( 90秒中)内丢失了大量的服务实例心跳,这时候Eurekaserver会开启自我保护机制,不会剔除该服务(该现象可能出现在如果网络不通但是EurekaClient为出现宕机,此时如果换做别的注册中心如果一定时间内没有收到心跳会将剔除该服务,这样就出现了严重失误,因为客户端还能正常发送心跳,只是网络延迟问题,而保护机制是为了解决此问题而产生的)。
在自我保护模式中,Eureka Server会保护服务注册表中的信息,不再注销任何服务实例。
它的设计哲学就是宁可保留错误的服务注册信息,也不盲目注销任何可能健康的服务实例。一句话讲解:好死不如赖活着。
综上,自我保护模式是一种应对网络异常的安全保护措施。它的架构哲学是宁可同时保留所有微服务(健康的微服务和不健康的微服务都会保留)也不盲目注销任何健康的微服务。使用自我保护模式,可以让Eureka集群更加的健壮、稳定。
以8001和7001为例
在7001中的yml
eureka:
...
server:
#关闭自我保护机制,保证不可用服务被及时踢除
enable-self-preservation: false
eviction-interval-timer-in-ms: 2000
在8001的yml
eureka:
...
instance:
instance-id: payment8001
prefer-ip-address: true
#心跳检测与续约时间
#开发时没置小些,保证服务关闭后注册中心能即使剔除服务
#Eureka客户端向服务端发送心跳的时间间隔,单位为秒(默认是30秒)
lease-renewal-interval-in-seconds: 1
#Eureka服务端在收到最后一次心跳后等待时间上限,单位为秒(默认是90秒),超时将剔除服务
lease-expiration-duration-in-seconds: 2
1.8 Eureka已停更结果:两者都启动后,如果关闭8001,那么会被接着删除
https://github.com/Netflix/eureka/wiki
2. Zookeeper 1. Linux下的安装ZooKeeper代替Eureka功能。
安装步骤
修改server端口 默认是8080
2. 支付服务注册进Zookeeper 首先在Linux下启动zookeeper[root@iZwz97bu0gr8vx8z3cjdfrZ ~]# cd /usr/local/zookeeper/bin [root@iZwz97bu0gr8vx8z3cjdfrZ bin]# ll 总用量 56 -rwxr-xr-x 1 root root 232 2月 17 21:37 README.txt -rwxr-xr-x 1 root root 2067 2月 17 21:37 zkCleanup.sh -rwxr-xr-x 1 root root 1158 2月 17 21:37 zkCli.cmd -rwxr-xr-x 1 root root 1621 2月 17 21:37 zkCli.sh -rwxr-xr-x 1 root root 1766 2月 17 21:37 zkEnv.cmd -rwxr-xr-x 1 root root 3690 2月 17 21:37 zkEnv.sh -rwxr-xr-x 1 root root 1286 2月 17 21:37 zkServer.cmd -rwxr-xr-x 1 root root 4573 2月 17 21:37 zkServer-initialize.sh -rwxr-xr-x 1 root root 9386 2月 17 21:37 zkServer.sh -rwxr-xr-x 1 root root 996 2月 17 21:37 zkTxnLogToolkit.cmd -rwxr-xr-x 1 root root 1385 2月 17 21:37 zkTxnLogToolkit.sh [root@iZwz97bu0gr8vx8z3cjdfrZ bin]# ./zkServer.sh start /usr/bin/java ZooKeeper JMX enabled by default Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg Starting zookeeper ... already running as process 2810142. [root@iZwz97bu0gr8vx8z3cjdfrZ bin]# ./zkCli.sh /usr/bin/java Connecting to localhost:2181 2022-02-18 13:16:46,489 [myid:] - INFO [main:Environment@109] - Client environment:zookeeper.version=3.5.8-f439ca583e70862c3068a1f2a7d4d068eec33315, built on 05/04/2020 15:07 GMT 2022-02-18 13:16:46,496 [myid:] - INFO [main:Environment@109] - Client environment:host.name=iZwz97bu0gr8vx8z3cjdfrZ 2022-02-18 13:16:46,496 [myid:] - INFO [main:Environment@109] - Client environment:java.version=1.8.0_121 2022-02-18 13:16:46,498 [myid:] - INFO [main:Environment@109] - Client environment:java.vendor=Oracle Corporation 2022-02-18 13:16:46,498 [myid:] - INFO [main:Environment@109] - Client environment:java.home=/usr/java/jdk1.8.0_121/jre 2022-02-18 13:16:46,499 [myid:] - INFO [main:Environment@109] - Client environment:java.class.path=/usr/local/zookeeper/bin/../zookeeper-server/target/classes:/usr/local/zookeeper/bin/../build/classes:/usr/local/zookeeper/bin/../zookeeper-server/target/lib/*.jar:/usr/local/zookeeper/bin/../build/lib/*.jar:/usr/local/zookeeper/bin/../lib/zookeeper-jute-3.5.8.jar:/usr/local/zookeeper/bin/../lib/zookeeper-3.5.8.jar:/usr/local/zookeeper/bin/../lib/slf4j-log4j12-1.7.25.jar:/usr/local/zookeeper/bin/../lib/slf4j-api-1.7.25.jar:/usr/local/zookeeper/bin/../lib/netty-transport-native-unix-common-4.1.48.Final.jar:/usr/local/zookeeper/bin/../lib/netty-transport-native-epoll-4.1.48.Final.jar:/usr/local/zookeeper/bin/../lib/netty-transport-4.1.48.Final.jar:/usr/local/zookeeper/bin/../lib/netty-resolver-4.1.48.Final.jar:/usr/local/zookeeper/bin/../lib/netty-handler-4.1.48.Final.jar:/usr/local/zookeeper/bin/../lib/netty-common-4.1.48.Final.jar:/usr/local/zookeeper/bin/../lib/netty-codec-4.1.48.Final.jar:/usr/local/zookeeper/bin/../lib/netty-buffer-4.1.48.Final.jar:/usr/local/zookeeper/bin/../lib/log4j-1.2.17.jar:/usr/local/zookeeper/bin/../lib/json-simple-1.1.1.jar:/usr/local/zookeeper/bin/../lib/jline-2.11.jar:/usr/local/zookeeper/bin/../lib/jetty-util-9.4.24.v20191120.jar:/usr/local/zookeeper/bin/../lib/jetty-servlet-9.4.24.v20191120.jar:/usr/local/zookeeper/bin/../lib/jetty-server-9.4.24.v20191120.jar:/usr/local/zookeeper/bin/../lib/jetty-security-9.4.24.v20191120.jar:/usr/local/zookeeper/bin/../lib/jetty-io-9.4.24.v20191120.jar:/usr/local/zookeeper/bin/../lib/jetty-http-9.4.24.v20191120.jar:/usr/local/zookeeper/bin/../lib/javax.servlet-api-3.1.0.jar:/usr/local/zookeeper/bin/../lib/jackson-databind-2.10.3.jar:/usr/local/zookeeper/bin/../lib/jackson-core-2.10.3.jar:/usr/local/zookeeper/bin/../lib/jackson-annotations-2.10.3.jar:/usr/local/zookeeper/bin/../lib/commons-cli-1.2.jar:/usr/local/zookeeper/bin/../lib/audience-annotations-0.5.0.jar:/usr/local/zookeeper/bin/../zookeeper-*.jar:/usr/local/zookeeper/bin/../zookeeper-server/src/main/resources/lib/*.jar:/usr/local/zookeeper/bin/../conf: 2022-02-18 13:16:46,499 [myid:] - INFO [main:Environment@109] - Client environment:java.library.path=/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib 2022-02-18 13:16:46,499 [myid:] - INFO [main:Environment@109] - Client environment:java.io.tmpdir=/tmp 2022-02-18 13:16:46,499 [myid:] - INFO [main:Environment@109] - Client environment:java.compiler=配置模块8004 首先引入依赖时要注意依赖冲突2022-02-18 13:16:46,499 [myid:] - INFO [main:Environment@109] - Client environment:os.name=Linux 2022-02-18 13:16:46,499 [myid:] - INFO [main:Environment@109] - Client environment:os.arch=amd64 2022-02-18 13:16:46,499 [myid:] - INFO [main:Environment@109] - Client environment:os.version=4.18.0-193.14.2.el8_2.x86_64 2022-02-18 13:16:46,499 [myid:] - INFO [main:Environment@109] - Client environment:user.name=root 2022-02-18 13:16:46,499 [myid:] - INFO [main:Environment@109] - Client environment:user.home=/root 2022-02-18 13:16:46,499 [myid:] - INFO [main:Environment@109] - Client environment:user.dir=/usr/local/zookeeper/bin 2022-02-18 13:16:46,499 [myid:] - INFO [main:Environment@109] - Client environment:os.memory.free=50MB 2022-02-18 13:16:46,502 [myid:] - INFO [main:Environment@109] - Client environment:os.memory.max=228MB 2022-02-18 13:16:46,502 [myid:] - INFO [main:Environment@109] - Client environment:os.memory.total=56MB 2022-02-18 13:16:46,513 [myid:] - INFO [main:ZooKeeper@868] - Initiating client connection, connectString=localhost:2181 sessionTimeout=30000 watcher=org.apache.zookeeper.ZooKeeperMain$MyWatcher@ee7d9f1 2022-02-18 13:16:46,527 [myid:] - INFO [main:X509Util@79] - Setting -D jdk.tls.rejectClientInitiatedRenegotiation=true to disable client-initiated TLS renegotiation 2022-02-18 13:16:46,540 [myid:] - INFO [main:ClientCnxnSocket@237] - jute.maxbuffer value is 4194304 Bytes 2022-02-18 13:16:46,553 [myid:] - INFO [main:ClientCnxn@1653] - zookeeper.request.timeout value is 0. feature enabled= Welcome to ZooKeeper! 2022-02-18 13:16:46,565 [myid:localhost:2181] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@1112] - Opening socket connection to server localhost/0:0:0:0:0:0:0:1:2181. Will not attempt to authenticate using SASL (unknown error) JLine support is enabled 2022-02-18 13:16:46,672 [myid:localhost:2181] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@959] - Socket connection established, initiating session, client: /0:0:0:0:0:0:0:1:44916, server: localhost/0:0:0:0:0:0:0:1:2181 2022-02-18 13:16:46,689 [myid:localhost:2181] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@1394] - Session establishment complete on server localhost/0:0:0:0:0:0:0:1:2181, sessionid = 0x101baaec9250001, negotiated timeout = 30000 WATCHER:: WatchedEvent state:SyncConnected type:None path:null [zk: localhost:2181(CONNECTED) 0]
org.springframework.cloud
spring-cloud-starter-zookeeper-discovery
org.apache.zookeeper
zookeeper
org.apache.zookeeper
zookeeper
3.5.8
启动类加注解
@EnableDiscoveryClient//该注解用于向使用consul或者zookeeper作为注册中心时注册服务编写controller
@Controller
@Slf4j
public class PaymentController
{
@Value("${server.port}")
private String serverPort;
@RequestMapping(value = "/payment/zk")
@ResponseBody
public String paymentzk()
{
return "springcloud with zookeeper: "+serverPort+"t"+ UUID.randomUUID().toString();
}
}
启动后
访问接口
在Linux操作
{
"name": "cloud-provider-payment",
"id": "81f8bf18-d691-46eb-a039-f0502ee288be",
"address": "localhost",
"port": 8004,
"sslPort": null,
"payload": {
"@class": "org.springframework.cloud.zookeeper.discovery.ZookeeperInstance",
"id": "application-1",
"name": "cloud-provider-payment",
"metadata": {}
},
"registrationTimeUTC": 1645161984023,
"serviceType": "DYNAMIC",
"uriSpec": {
"parts": [{
"value": "scheme",
"variable": true
}, {
"value": "://",
"variable": false
}, {
"value": "address",
"variable": true
}, {
"value": ":",
"variable": false
}, {
"value": "port",
"variable": true
}]
}
}
3. ZooKeeper的服务节点是临时节点,没有Eureka那含情脉脉。
4.订单服务注册进zookeeper
pom
ymlcloud2020 org.ys.springcloud 1.0-SNAPSHOT 4.0.0 cloud-consumerzk-order80 org.springframework.boot spring-boot-starter-web org.ys.springcloud cloud-api-commons 1.0-SNAPSHOT org.springframework.cloud spring-cloud-starter-zookeeper-discovery org.apache.zookeeper zookeeper org.apache.zookeeper zookeeper 3.5.8 org.springframework.boot spring-boot-devtools runtime true org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test
server:
port: 8200
#用8200替代80
#服务别名----注册zookeeper到注册中心名称
spring:
application:
name: cloud-provider-payment
cloud:
zookeeper:
connect-string: 47.106.78.230:2181
config
@Configuration
public class ApplicationContextConfig
{
@Bean
@LoadBalanced
public RestTemplate getRestTemplate()
{
return new RestTemplate();
}
}
接口
@RestController
public class OrderZKController
{
public static final String INVOKE_URL = "http://cloud-provider-payment";
@Autowired
private RestTemplate restTemplate;
@GetMapping(value = "/consumer/payment/zk")
public String paymentInfo()
{
String result = restTemplate.getForObject(INVOKE_URL+"/payment/zk",String.class);
return result;
}
}
访问结果
3.Consul
3.1 简介与安装
官网
中文文档
Consul是一套开源的分布式服务发现和配置管理系统,由HashiCorp 公司用Go语言开发。提供了微服务系统中的服务治理、配置中心、控制总线等功能。这些功能中的每一个都可以根据需要单独使用,也可以一起使用以构建全方位的服务网格,总之Consul提供了一种完整的服务网格解决方案。
它具有很多优点。包括:基于raft协议,比较简洁;支持健康检查,同时支持HTTP和DNS协议支持跨数据中心的WAN集群提供图形界面跨平台,支持Linux、Mac、Windows。
作用:服务发现 - 提供HTTP和DNS两种发现方式。
健康监测 - 支持多种方式,HTTP、TCP、Docker、Shell脚本定制化
KV存储 - Key、Value的存储方式
多数据中心 - Consul支持多数据中心
可视化Web界面
输入consul agent -dev 启动
访问8500端口
ymlcloud2020 org.ys.springcloud 1.0-SNAPSHOT 4.0.0 cloud-providerconsul-payment8006 org.springframework.boot spring-boot-starter-web org.ys.springcloud cloud-api-commons 1.0-SNAPSHOT org.springframework.boot spring-boot-devtools runtime true org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test org.springframework.cloud spring-cloud-starter-consul-discovery cn.hutool hutool-all RELEASE test
server:
port: 8006
spring:
application:
name: consul-provider-payment
####consul注册中心地址
cloud:
consul:
host: localhost
port: 8500
discovery:
service-name: ${spring.application.name}
heartbeat:
enabled: true
启动类
@SpringBootApplication
@EnableDiscoveryClient
public class PaymentMain8006
{
public static void main(String[] args) {
SpringApplication.run(PaymentMain8006.class,args);
}
}
Controller
@RestController
public class PaymentController
{
@Value("${server.port}")
private String serverPort;
@RequestMapping(value = "/payment/consul")
public String paymentConsul()
{
return "springcloud with consul: "+serverPort+"t "+ UUID.randomUUID().toString();
}
}
结果:
3.3 服务消费者进Consul
pom
ymlcloud2020 org.ys.springcloud 1.0-SNAPSHOT 4.0.0 cloud-consumerconsul-order80 org.springframework.boot spring-boot-starter-web org.ys.springcloud cloud-api-commons 1.0-SNAPSHOT org.springframework.boot spring-boot-devtools runtime true org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test org.springframework.cloud spring-cloud-starter-consul-discovery cn.hutool hutool-all RELEASE test
server:
port: 8200
spring:
application:
name: cloud-consumer-order
####consul注册中心地址
cloud:
consul:
host: localhost
port: 8500
discovery:
service-name: ${spring.application.name}
heartbeat:
enabled: true
config、启动类、controller
@Configuration
public class ApplicationContextConfig
{
@Bean
@LoadBalanced
public RestTemplate getRestTemplate()
{
return new RestTemplate();
}
}
@SpringBootApplication
@EnableDiscoveryClient
public class OrderConsulMain80
{
public static void main(String[] args) {
SpringApplication.run(OrderConsulMain80.class,args);
}
}
@RestController
public class OrderConsulController
{
public static final String INVOKE_URL = "http://consul-provider-payment";
@Resource
private RestTemplate restTemplate;
@GetMapping(value = "/consumer/payment/consul")
public String paymentInfo()
{
String result = restTemplate.getForObject(INVOKE_URL+"/payment/consul",String.class);
return result;
}
}
结果:
最多只能同时较好的满足两个。
CAP理论的核心是:一个分布式系统不可能同时很好的满足一致性,可用性和分区容错性这三个需求。
因此,根据CAP原理将NoSQL数据库分成了满足CA原则、满足CP原则和满足AP原则三大类:
CA - 单点集群,满足—致性,可用性的系统,通常在可扩展性上不太强大。
CP - 满足一致性,分区容忍必的系统,通常性能不是特别高。
AP - 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。
AP架构(Eureka)
当网络分区出现后,为了保证可用性,系统B可以返回旧值,保证系统的可用性。
结论:违背了一致性C的要求,只满足可用性和分区容错,即AP
CP架构(ZooKeeper/Consul)
当网络分区出现后,为了保证一致性,就必须拒接请求,否则无法保证一致性。
结论:违背了可用性A的要求,只满足一致性和分区容错,即CP。



