InstanceStatus 服务状态
-
标识服务的状态,是个枚举
public static enum InstanceStatus { UP, DOWN, STARTING, starting OUT_OF_SERVICE, out_of_service UNKNOWN; }
服务的核心操作
-
服务注册
-
服务下线
-
服务租约
-
服务剔除
public interface LeaseManager<T> {
void register(T r, int leaseDuration, boolean isReplication);
boolean cancel(String appName, String id, boolean isReplication);
boolean renew(String appName, String id, boolean isReplication);
void evict();
}
public interface LookupService<T> {
Application getApplication(String appName);
Applications getApplications();
List<InstanceInfo> getInstancesById(String id);
InstanceInfo getNextServerFromEureka(String virtualHostname, boolean secure);
}
Eureka的设计理念
- 如何注册
- 调用eureka server的 rest api 的 register方法
- spring-cloud-starter-netflix-eureka-client ,自动配置,自动实现注册。
- 符合从服务中心剔除
- 正常关闭应用的时候,通过钩子方法 去调用 de-register方法
- eureka server 要求 client 端点时 进行续约(心跳),如果超过一定时间没有续约,eureka 主动剔除。
- eureka server 采用的就是分布式 的心跳模式
AP 优于 CP
- ZooKeeper 是CP
- Eureka 是AP
Consistency 数据一致性
consist
英 [kən'sɪst] 美 [kən'sɪst]
vi. 组成;在于;符合
consistent
英 [kən'sɪst(ə)nt] 美 [kən'sɪstənt]
adj. 始终如一的,一致的;坚持的
consistency
英 [kən'sɪst(ə)nsɪ] 美 [kən'sɪstənsi]
n. [计] 一致性;稠度;相容性
availability
英 [ə,veɪlə'bɪlətɪ] 美 [ə,velə'bɪləti]
n. 可用性;有效性;实用性
avail
英 [ə'veɪl] 美 [ə'vel]
n. 效用,利益
vt. 有益于,有益于;使对某人有利。
vi. 有益于,有益于;使对某人有利。
available
英 [ə'veɪləb(ə)l] 美 [ə'veləbl]
adj. 可获得的;可购得的;可找到的;有空的
tolerant
英 ['tɒl(ə)r(ə)nt] 美 ['tɑlərənt]
adj. 宽容的;容忍的;有耐药力的
tolerance
英 ['tɒl(ə)r(ə)ns] 美 ['tɑlərəns]
n. 公差;宽容;容忍
-
在任何时候客户端对集群进行读写操作时,请求能够正常的响应。
Partition Tolerance 分区容忍性,发生通信故障的时候,集群仍然可用。
-
eureka, 在生产和实践中,服务注册及发现中心,保留可用及过期的数据,总比丢掉可用的数据好。
客户端能够支持负载均衡及失败重试,ribbon
Peer to peer 架构
分布式系统的数据在多个副本之间的复制方式,
分为主从复制 和 对等复制
peer
英 [pɪə] 美 [pɪr]
n. 贵族;同等的人;同龄人
vi. 凝视,盯着看;窥视
vt. 封为贵族;与…同等
slave
英 [sleɪv] 美 [sleɪv]
n. 奴隶;从动装置
vi. 苦干;拼命工作
主从复制
Mster-Slave模式
一个主副本,其他是从副本。
写操作提交到主副本,读操作从副本。
再有祝福本更新到其他副本。
更新包括:同步更新,异步更新,同步即异步混合
对等复制
即是 Peer to Peer
不分主从,任何副本都可以接受写操作,
然后每个副本之间,相互进行数据更新。
每个副本都可以进行写操作,各个副本之间的数据同步及冲突处理是一个比较棘手的问题。
eureka Sever 采用的就是 对等复制
客户端
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/
服务端
server 本身依赖了 client
启动的时候,先获取注册的应用实例信息。
数据复制冲突问题:两个解决
- lastDirtyTimestamp表示。(类似版本号)
- heartbeat 最终修复
heartbeat
英 ['hɑːtbiːt] 美 ['hɑrtbit]
n. 心跳;情感
sync
英 [sɪŋk] 美 [sɪŋk]
n. 同步,同时
vi. 同时发生
vt. 使同步
asyc
【网络】渐近准则 同步并车控制 高级安全概念
Zone 及 Region设计
- netflix服务 大部分在 amazon
- eureka 基于 Amazon 的 Zone
亚马逊公司(Amazon,简称亚马逊;NASDAQ:AMZN),是美国最大的一家网络电子商务公司,位于华盛顿州的西雅图。是网络上最早开始经营电子商务的公司之一,亚马逊成立于1995年,一开始只经营网络的书籍销售业务,现在则扩及了范围相当广的其他产品,已成为全球商品品种最多的网上零售商和全球第二大互联网企业,
-
Region 代表一个独立的地理区域
-
Eureka server默认了 4个 ,
- us-east-1,美国东部(弗吉尼亚北部)
- us-west-1,美国西部(加利福尼亚北部)
- us-west-2,美国西部(俄勒冈)
- eu-west-1,欧洲(爱尔兰)
-
一个 region 对应多个 availability Zone
-
availability 英 /əˌveɪləˈbɪləti/ 美 /əˌveɪləˈbɪləti/ 全球(澳大利亚) 简明 韦氏 例句 百科 n. 可用性;有效性;实用性
-
-
每个 region 之间相互独立,及隔离的。跨region 之间 不会惊醒资源复制
自我保护模式 self preservation
-
SELF PRESERVATION self preservation 自我保护模式
处理 网络偶尔抖动 或 短暂不可用 时造成的误判 -
client 和 server 有个租约,client 定时发送心跳 来维持这个心跳
server 通过当前注册的实例数,去计算每分钟 应该受到的心跳数。 -
如果最近一分钟接收到的续约的次数,小于等于 指定阀值的话,
则关闭租约失效剔除。禁止定时任务剔除,保护注册信息。
参数调优
-
为什么服务下线了,Eureka Server 上的信息还在?
-
为什么服务上线了,Eureka Client 不能及时获取到。(不能正常使用)
-
server 会保留过时的实例信息因为:
- 1,实例没有告知eureka Server 要下线。这时需要 EvictionTask 去剔除
- 2,告知了,但Server有缓存,要等缓存过期
- 3,server 开户了,SELF PRESERVATION self preservation自我保护模式,导致registry的信息不会因为过期而被剔除
evict
英 [ɪ'vɪkt] 美 [ɪ'vɪkt]
vt. 驱逐;逐出
eviction
英 [ɪ'vɪkʃ(ə)n] 美 [ɪ'vɪkʃən]
n. 逐出;赶出;收回
preserve
英 [prɪ'zɜːv] 美 [prɪ'zɝv]
vt. 保存;保护;维持;腌;禁猎
调整 剔除任务的通知
1,client下线没有通知server,可以调整 EvictionTask的调度频率。
eureka:
server:
eviction-interval-timer-in-ms: 5000
就是剔除任务,从默认的60秒执行一次,改成5秒执行一次。
关闭缓存
2,针对server端有缓存的问题,可以关闭缓存。或者把缓存的保留时间调小(第二个配置)
eureka:
server:
use-read-only-response-cache: false 或者
response-cache-auto-expiration-in-seconds: 60 #默认180
关闭自我保护
3,针对 server端的自我保护,也可以关闭
eureka:
server:
enable-self-preservation: false #关闭自我保护模式
提高服务上线时间
4,服务上线,eureka server端没有及时获取到,client端不能及时使用
提高client端拉取Server注册信息的频率
eureka:
client:
registry-fetch-interval-seconds: 5 //默认30秒,拉取一次。这里应该配置到客户端,如果是多 eureka ,server端也要配置
#生产环境,提供自我保护的门槛
eureka:
server:
renewal-threshold-update-interval-ms:0.49 #默认0.85
instance:
lease-renewal-interval-in-seconds: 10 #默认30秒
client端特殊注意
- 所有引用 server端 记得 开启eureka
- 所有client 记得 开启 客户端。一种是通用的,一种是单开eureka的都行
- 注意:所有的 client 端 记得引用 web包,否则 无法启动
实战:eureka 在线扩容
建立config-server
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
bootstrap.yml 配置:
@EnableConfigServer
bootstrap.yml 配置:
spring:
application:
name: config-server
profiles:
active: native # 使用文件存储配置,默认放在 resource/config目录下
server:
port: 8888
native
英 ['neɪtɪv] 美 ['netɪv]
adj. 本国的;土著的;天然的;与生俱来的;天赋的
n. 本地人;土产;当地居民
resource/config目录下 文件配置
eureka-client.yml
server:
port: 8081
spring:
application:
name: eureka-client1
eureka:
client:
serviceUrl:
# defaultZone: http://localhost:8761/eureka/ # one eureka server
# defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/ # two eureka server
defaultZone: http://localhost:8761/eureka/,http://localhost:8762/eureka/,http://localhost:8763/eureka/ # three eureka server
eureka-server-peer1.yml
server:
port: 8761
spring:
application:
name: eureka-server
eureka:
instance:
hostname: localhost
preferIpAddress: true
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
# defaultZone: http://localhost:8761/eureka/ # one eureka server
# defaultZone: http://localhost:8762/eureka/ # two eureka server
defaultZone: http://localhost:8762/eureka/,http://localhost:8763/eureka/ # three eureka server
server:
waitTimeInMsWhenSyncEmpty: 0
enableSelfPreservation: false
#注意两个 eureka是相互注册的
server 和 client 通用引用
# 引入配置中心的开始
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
server的 action
@RestController
@RequestMapping("/query")
public class QueryController {
//注入 eurekaClientBean的配置类
@Autowired
EurekaClientConfigBean eurekaClientConfigBean;
// 获得 service的URL
@GetMapping("/eureka-server")
public Object getEurekaServerUrl(){
return eurekaClientConfigBean.getServiceUrl();
}
}
//注意这两个注解 一样要加
@EnableEurekaServer
@EnableDiscoveryClient
client和server自己的配置
bootstrap.yml
spring:
application:
name: eureka-client
cloud:
config:
uri: http://localhost:8888
management:
endpoints:
web:
exposure:
include: '*'
application.yml
eureka:
client:
eureka-service-url-poll-interval-seconds: 10 #默认为300秒,这里为了验证改为10秒
spring:
application:
name: eureka-server
cloud:
config:
uri: http://localhost:8888
management:
endpoints:
web:
exposure:
include: '*'
eureka:
server:
peer-eureka-nodes-update-interval-ms: 10000 #默认是10分钟即600000,这里为了验证改为10秒
mvn spring-boot:run -Dspring.profiles.active=peer2 也可用,在pom同目录执行
或者:
java -jar eureka-server-1.0.0.jar --spring.profiles.active=peer1
刷新指定项目的配置:
curl -i -X POST http://localhost:8761/actuator/refresh
构建Multi Zone Eureka Server
- 介绍默认的 ZoneAffinity 特性
- 启动四个 eureka server 实例,配置两个 zonnel:zone1和zone2
- 每个zone有两个 eureka server 实例,两个zone在同一个 region:region-east上
server
- application-zone1a.yml 和 application-zone1b.yml
server:
port: 8761
spring:
application:
name: eureka-server
eureka:
instance:
hostname: localhost
preferIpAddress: true
metadataMap.zone: zone1
client:
register-with-eureka: true
fetch-registry: true
region: region-east
service-url:
zone1: http://localhost:8761/eureka/,http://localhost:8762/eureka/
zone2: http://localhost:8763/eureka/,http://localhost:8764/eureka/
availability-zones:
region-east: zone1,zone2
server:
waitTimeInMsWhenSyncEmpty: 0
enableSelfPreservation: false
- application-zone2a.yml 和 application-zone2b.yml
metadataMap.zone: zone2 #其他不变
- 启动四个文件: mvn spring-boot:run -Dspring.profiles.active=zoone1a
client
- client 暴露所有的 endpoints 方便验证
management:
endpoints:
web:
exposure:
include: '*'
- application-zone1.yml
server:
port: 8081
spring:
application:
name: client
eureka:
instance:
metadataMap.zone: zone1
client:
register-with-eureka: true
fetch-registry: true
region: region-east
service-url:
zone1: http://localhost:8761/eureka/,http://localhost:8762/eureka/
zone2: http://localhost:8763/eureka/,http://localhost:8764/eureka/
availability-zones:
region-east: zone1,zone2
- application-zone2.yml 只是把 metadataMap.zone: zone2
- 启动 zone1 和 zone2
zuu gateway实例
- 演示 eureka 使用 matadataMap的 zone属性时 的 ZoneAffinity 特性
pom和 注解配置
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
@EnableDiscoveryClient
@EnableZuulProxy
-
其他并没有配置,只是有个网关的功能而已
-
application.yml 同样暴露素有的 节点
spring:
application:
name: zuul-gateway
management:
endpoints:
web:
exposure:
include: '*'
-
application-zone1.yml
server: port: 10001 eureka: instance: metadataMap.zone: zone1 client: register-with-eureka: true fetch-registry: true region: region-east service-url: zone1: http://localhost:8761/eureka/,http://localhost:8762/eureka/ zone2: http://localhost:8763/eureka/,http://localhost:8764/eureka/ availability-zones: region-east: zone1,zone2
-
application-zone2.yml 同样是改下 metadataMap.zone: zone2
-
启动这个两个 网关项目
测试
-
验证 zoneAffinity
-
访问 http://localhost:10001/client/actuator/env
-
和 10002 端口 http://localhost:10002/client/actuator/env
-
10002的数据为:
{ "activeProfiles": ["zone2"], "propertySources": [{ "name": "server.ports", "properties": { "local.server.port": { "value": 8082 } } }, { "name": "servletContextInitParams", "properties": {} }, { "name": "systemProperties", "properties": { "java.runtime.name": { "value": "Java(TM) SE Runtime Environment" }, "sun.boot.library.path": { "value": "C:\\MyExe\\Java\\jdk1.8.0_131\\jre\\bin" }, "java.vm.version": { "value": "25.131-b11" }, }
-
访问网关的这个接口,其实是访问的 eureka client实例的 /actuator/env接口
-
处于 zone1的gateway返回 activeProfiles为 zone1
-
gateway路由时 对 client的实例 是 zoneAffinity的
支持 remote Region
- 配置 4个 Eureka server 分为 4个 zone ,属于 region-east,和 region-west
server
-
application-zone1.yml 为 region-east
server: port: 8761 #zone2配置 8762 ,其他配置一样。 spring: application: name: eureka-server eureka: server: waitTimeInMsWhenSyncEmpty: 0 enableSelfPreservation: false remoteRegionUrlsWithName: region-west: http://localhost:8763/eureka/ #远程的region配置为 west client: register-with-eureka: true fetch-registry: true region: region-east service-url: zone1: http://localhost:8761/eureka/ zone2: http://localhost:8762/eureka/ availability-zones: region-east: zone1,zone2 instance: hostname: localhost metadataMap.zone: zone1 #2配置就填zone2
-
application-zone3-region-west.yml
server: port: 8763 #8764 spring: application: name: eureka-server eureka: server: waitTimeInMsWhenSyncEmpty: 0 enableSelfPreservation: false remoteRegionUrlsWithName: region-east: http://localhost:8761/eureka/ #远程配置为 east client: register-with-eureka: true fetch-registry: true region: region-west service-url: zone3: http://localhost:8763/eureka/ zone4: http://localhost:8764/eureka/ availability-zones: region-west: zone3,zone4 instance: hostname: localhost metadataMap.zone: zone3 #zone3
-
源码 EurekaServerConfiguration 的 remonteRegionAppWhitelist默认为null
-
getRemoteRegionAppWhitelist(string regionName方法会直接调用)
-
会报空指针,所以需要初始化此对象
@Configuration
@AutoConfigureBefore(EurekaServerAutoConfiguration.class)
public class RegionConfig {
@Bean
@ConditionalOnMissingBean
public EurekaServerConfig eurekaServerConfig(EurekaClientConfig clientConfig) {
EurekaServerConfigBean server = new EurekaServerConfigBean();
if (clientConfig.shouldRegisterWithEureka()) {
// Set a sensible default if we are supposed to replicate
server.setRegistrySyncRetries(5);
}
server.setRemoteRegionAppWhitelist(new HashMap<>());
return server;
}
}
- mvn spring-boot:run -Dspring.profiles.active=zone4-region-west #3
- mvn spring-boot:run -Dspring.profiles.active=zone1 #2
client
-
配置 4个 eureka client
-
region-east 两个, west两个
-
application-zone1.yml
server: port: 8071 spring: application.name: demo-client eureka: client: prefer-same-zone-eureka: true region: region-east service-url: zone1: http://localhost:8761/eureka/ zone2: http://localhost:8762/eureka/ availability-zones: region-east: zone1,zone2 instance: metadataMap.zone: zone1 #zone2
-
application-zone3.yml
server: port: 8073 spring: application.name: demo-client eureka: client: prefer-same-zone-eureka: true region: region-west #west service-url: zone3: http://localhost:8763/eureka/ zone4: http://localhost:8764/eureka/ availability-zones: region-west: zone3,zone4 instance: metadataMap.zone: zone3
-
启动 4 个 client
- mvn spring-boot:run -Dspring.profiles.active=zone1 #2 ,3 ,4
zuul gateway
-
使用2个 zuul,一个注册到 region-east ,一个注册到 west
-
application-zone1.yml
server: port: 10001 eureka: instance: metadataMap.zone: zone1 client: register-with-eureka: true fetch-registry: true region: region-east service-url: zone1: http://localhost:8761/eureka/ zone2: http://localhost:8762/eureka/ availability-zones: region-east: zone1,zone2
-
application-zone3-region-west.yml
server: port: 10002 eureka: instance: metadataMap.zone: zone3 client: register-with-eureka: true fetch-registry: true region: region-west service-url: zone3: http://localhost:8763/eureka/ zone4: http://localhost:8764/eureka/ availability-zones: region-west: zone3,zone4
-
启动这两个实例
- mvn spring-boot:run -Dspring.profiles.active=zone1
- mvn spring-boot:run -Dspring.profiles.active=zone3-region-west
-
访问
-
curl -i http://localhost:10001/demo-client/actuator/env
-
同理访问 10002端口
-
zone1的gateway访问的是 zone1的 demo-client
-
zone3的gateway访问的是 zone3的 demo-client
-
关闭 zone1 和 zone2 的 client,继续访问 10001 端口
-
经过几次报错之后,会 fallback到 remote-region的 zone3 或 zone4 实例
-
类似:异地多活 自动转移请求的效果。跨域region的fallback
-
开启 http basic 认证
- eurek自己暴露 了 rest api,别人能随意修改,所以 需要 http basic校验的
引入pom和yaml配置
-
引入security
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
-
配置文件配置密码,最好和 配置中心的加密方式配合。
spring: profiles: active: security ---- application-security.yml server: port: 8761 spring: security: basic: enabled: true user: name: admin password: Xk38CNHigBP5jK75 eureka: instance: hostname: localhost client: registerWithEureka: false fetchRegistry: false serviceUrl: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ server: waitTimeInMsWhenSyncEmpty: 0 enableSelfPreservation: false
关闭 csrf校验
-
security 模式是 开户csrf校验的,对于client端 非界面不合适
@EnableWebSecurity //开启配置 public class SecurityConfig extends WebSecurityConfigurerAdapter {//继承适配器 @Override protected void configure(HttpSecurity http) throws Exception { super.configure(http); //使用父类的配置 http.csrf().disable(); //关闭csrf } }
-
测试
-
mvn spring-boot:run -Dspring.profiles.active=security
-
curl -i --basic -u admin:XXXX http://localhost:8761/eureka/apps
<applications> <versions__delta>1</versions__delta> <apps__hashcode/> </applications>
-
eureka client
-
yaml
server: port: 8081 spring: application: name: client1 eureka: client: security: basic: user: admin password: Xk38CNHigBP5jK75 serviceUrl: defaultZone: http://${eureka.client.security.basic.user}:${eureka.client.security.basic.password}@localhost:8761/eureka/
- http://用户名:密码@localhost:8761/eureka/
-
访问 http://localhost:8761/eureka/apps
<applications> <versions__delta>1</versions__delta> <apps__hashcode>UP_1_</apps__hashcode> <application> <name>CLIENT1</name> <instance> <instanceId>LAPTOP-GDF1FAHL:client1:8081</instanceId> <hostName>LAPTOP-GDF1FAHL</hostName> <app>CLIENT1</app> <ipAddr>192.168.31.140</ipAddr> <status>UP</status> <overriddenstatus>UNKNOWN</overriddenstatus> <port enabled="true">8081</port> <securePort enabled="false">443</securePort> <countryId>1</countryId> <dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo"> <name>MyOwn</name> </dataCenterInfo> <leaseInfo> <renewalIntervalInSecs>30</renewalIntervalInSecs> <durationInSecs>90</durationInSecs> <registrationTimestamp>1596936401697</registrationTimestamp> <lastRenewalTimestamp>1596936401697</lastRenewalTimestamp> <evictionTimestamp>0</evictionTimestamp> <serviceUpTimestamp>1596936401698</serviceUpTimestamp> </leaseInfo> <metadata> <management.port>8081</management.port> </metadata> <homePageUrl>http://LAPTOP-GDF1FAHL:8081/</homePageUrl> <statusPageUrl>http://LAPTOP-GDF1FAHL:8081/actuator/info</statusPageUrl> <healthCheckUrl>http://LAPTOP-GDF1FAHL:8081/actuator/health</healthCheckUrl> <vipAddress>client1</vipAddress> <secureVipAddress>client1</secureVipAddress> <isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer> <lastUpdatedTimestamp>1596936401699</lastUpdatedTimestamp> <lastDirtyTimestamp>1596936401584</lastDirtyTimestamp> <actionType>ADDED</actionType> </instance> </application> </applications>
启用https 认证
- base64编码 很容易被 抓包 破解
生成
# 生成
keytool -genkeypair -alias server -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore server.p12 -validity 3650 密码:Spring Cloud
keytool -genkeypair -alias client -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore client.p12 -validity 3650 密码:Client
# 导出这两个文件
keytool -export -alias server -file server.crt --keystore server.p12
keytool -export -alias client -file client.crt --keystore client.p12
# server.crt 导入 client.p12中。是 client信任 server的证书
keytool -import -alias server -file server.crt -keystore client.p12
//输入 client的秘钥 Client 。显示结果如下
输入密钥库口令:
所有者: CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
发布者: CN=Unknown, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown
序列号: 9addab9
有效期开始日期: Sun Aug 09 10:22:43 CST 2020, 截止日期: Wed Aug 07 10:22:43 CST 2030
证书指纹:
MD5: 0D:70:C6:76:C1:57:5C:1E:93:22:2F:29:A8:59:C3:5B
SHA1: 4C:85:90:2B:66:50:2E:C9:BF:5F:68:7E:E2:DE:20:AD:BA:D7:96:E7
SHA256: FD:BB:26:58:7A:8E:73:A1:3F:91:44:88:08:41:1F:6C:22:6E:9A:30:5A:C2:C7:02:F7:29:AC:6A:32:18:93:9D
签名算法名称: SHA256withRSA
版本: 3
扩展:
#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: A0 17 F8 44 AC A8 0C CB EF 00 55 AB FE 12 20 C0 ...D......U... .
0010: 20 58 0F FC X..
]
]
是否信任此证书? [否]: y
证书已添加到密钥库中
//将 client.crt 导入 server.p12中,使得server信任 client证书
keytool -import -alias client -file client.crt -keystore server.p12
使用
-
server.p12 放在 server项目的 resources下
server: port: 8761 ssl: enabled: true key-store: classpath:server.p12 #配置 server 端 key-store-password: springcloud key-store-type: PKCS12 key-alias: server eureka: instance: hostname: localhost securePort: ${server.port} securePortEnabled: true nonSecurePortEnabled: false homePageUrl: https://${eureka.instance.hostname}:${server.port}/ statusPageUrl: https://${eureka.instance.hostname}:${server.port}/ client: registerWithEureka: false fetchRegistry: false serviceUrl: defaultZone: https://${eureka.instance.hostname}:${server.port}/eureka/ server: waitTimeInMsWhenSyncEmpty: 0 enableSelfPreservation: false
-
把 client.p12放入 client项目的 resources目录下
---- application.yml spring: profiles: active: https ---- application-https.yml server: port: 8081 spring: application: name: client1 #配置cloud端 eureka: client: securePortEnabled: true ssl: key-store: client.p12 #client的秘钥文件 key-store-password: client serviceUrl: defaultZone: https://localhost:8761/eureka/
client的其他配置
-
没有整个应用 都启用https,只是eureka server的https
-
key-store key-store-password 指定 server的 sslContext配置
-
还需要在代码 指定 DiscoverClient.DiscoveryClientOptionalArgs
@Profile({"https"}) @Configuration public class EurekaHttpsClientConfig { //注入 client.p12 @Value("${eureka.client.ssl.key-store}") String keyStoreFileName; //注入 client @Value("${eureka.client.ssl.key-store-password}") String keyStorePassword; @Bean public DiscoveryClient.DiscoveryClientOptionalArgs discoveryClientOptionalArgs() throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException, KeyManagementException { //构建Eureka builder对象 EurekaJerseyClientImpl.EurekaJerseyClientBuilder builder = new EurekaJerseyClientImpl.EurekaJerseyClientBuilder(); //指定 客户端的名字 builder.withClientName("eureka-https-client"); //构建 ssL 上下文 SSLContext sslContext = new SSLContextBuilder() .loadTrustMaterial( //两个参数,一个是名字,一个是密码的的 数组 this.getClass().getClassLoader().getResource(keyStoreFileName),keyStorePassword.toCharArray() ) .build(); builder.withCustomSSL(sslContext); builder.withMaxTotalConnections(10);//最大连接 builder.withMaxConnectionsPerHost(10);//最大统一连接 DiscoveryClient.DiscoveryClientOptionalArgs args = new DiscoveryClient.DiscoveryClientOptionalArgs(); args.setEurekaJerseyClient(builder.build()); return args; } }
-
curl --insecure https://localhost:8761/eureka/apps
Eureka admin
- spring cloud 开发了 eureka server
- 地址为:http://eureka.sprinigcloud.cn
- https://github.com/springcloud/eureka-admin
- Eureka Admin 管控平台是Spring Cloud中国社区为Eureka注册中心开源的一个节点监控、服务动态启停的项目
- 通过界面 对 服务实例 进行 上线 下线 停止,省的自己再去调用 eureka server的 rest api
基于 metadata路由实例
-
通过 metadata属性,灰度控制 或 不宕机升级,结合 ribbon
-
ILoadBalancer接口
public interface ILoadBalancer { void addServers(List<Server> var1); Server chooseServer(Object var1); void markServerDown(Server var1); /** @deprecated */ @Deprecated List<Server> getServerList(boolean var1); List<Server> getReachableServers(); List<Server> getAllServers(); }
- chooseServer方法,从一堆 服务实例 列表过滤,选取一个server出来,给客户端请求用。
- 选取的逻辑 是 根据 IRule 来实现的。
-
IRule接口
public interface IRule { Server choose(Object var1); void setLoadBalancer(ILoadBalancer var1); ILoadBalancer getLoadBalancer(); }
- 最常见 RoundRobinRule,采用轮询调度算法规则 选取 Server
eureka 的故障演练
-
client先启动
- 报: request execution error
- eureka.client.backup-registry-impl属性,从这个 registry 读取服务注册信息
-
应用服务运行不可用
- client 在本地内存中有个 AtomicReference类型的 localRegionApps变量,来维护 Eureka Server拉取回来的注册信息。
- client 端 有个 定时任务 CacheRefreshThread 定时拉取 注册信息更新到本地
- 如果server 挂掉,本地 CacheRefreshThread 就会抛异常
-
eureka server 部分不可用
-
client端
-
有个定时任务 AsyncResolver.updateTask 去拉取serviceUrl变更,可以动态变更
-
client 会随机化 server的list
eureka: client: serviceUrl: defaultZone: https://localhost:8761/eureka/,https://localhost:8762/eureka/
-
client端 请求 server的时候,维护了一个不可用的 eureka server 列表(quarantineSet)
-
连接错误,或者 500 都会加入这个列表
-
-
server端
- 相互构成 peer node
- PeerEurekaNodes有个定时任务 (peersUpdateTask),会去从配置文件拉取 availabilityZones以及serviceUrl信息,然后更新。人工介入更新
- 目前没有 peerEurekaNodes进行健康检查,可以看到 eureka.server.peer-eureka-status-refresh-time-interval-ms配置,不过未使用。
-
eureka 高可用原理
-
eureka 部署在 amazon的背景下设计下,
-
原生 支持了 amazon的 region 以及 availability zone
-
region
- 默认情况下 region之前不会复制的
- fetch-remote-regions-registry配置,拉取region的注册信息到本地
-
availabilityZone
-
默认 eureka.client.prefer-same-zone-eureka配置为true
-
拉取serviceUrl ,优先选取 与 应用实例 处于 同一个zone的 eureka server列表
eureka: instance: metadataMap.zone: zone1 client: register-with-eureka: true fetch-registry: true region: region-east service-url: zone1: http://localhost:8761/eureka/ zone2: http://localhost:8762/eureka/ availability-zones: region-east: zone1,zone2 region 英 /ˈriːdʒən/ 美 /ˈriːdʒən/ 全球(美国) 简明 牛津 新牛津 韦氏 柯林斯 例句 百科 n. 地区;范围;部位 zone 英 /zəʊn/ 美 /zoʊn/ 全球(美国) 简明 牛津 新牛津 韦氏 柯林斯 例句 百科 n. 地带;地区;联防 vi. 分成区 vt. 使分成地带;环绕 n. (Zone)人名;(塞)佐内
- client端配置了一个region,该region下面有两个zone,分别是 zone1 和 zone2
- 该实例的metadataMap.zone 中 为 zone1
- 即:该应用实例 会选取 service-url.zone1 这个 server 列表 来进行 注册 以及查询等操作。
- eureka.client.prefer-same-zone-eureka配置为false,则默认返回 ZoneOffset为0,取第一个。
-
-
client启动之后,server全部挂掉:
- 本地内存有localRegiono之前获取的数据
- 从server端定时拉取注册信息回来更新的线程 CacheRrfreshThread会执行失败
- 本地localRegion信息不回被更新
-
一分钟接收到的续约次数小于 指定 阀值的话,则关闭租约剔除(进入 自我保护)