重新定义cloud 第3章 spring Cloud Eurek下篇

InstanceStatus 服务状态

  • 标识服务的状态,是个枚举

        public static enum InstanceStatus {
            UP,
            DOWN,
            STARTING, starting
            OUT_OF_SERVICE, out_of_service
            UNKNOWN;
    }
    

服务的核心操作

  1. 服务注册

  2. 服务下线

  3. 服务租约

  4. 服务剔除

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的设计理念

  1. 如何注册
    1. 调用eureka server的 rest api 的 register方法
    2. spring-cloud-starter-netflix-eureka-client ,自动配置,自动实现注册。
  2. 符合从服务中心剔除
    1. 正常关闭应用的时候,通过钩子方法 去调用 de-register方法
    2. eureka server 要求 client 端点时 进行续约(心跳),如果超过一定时间没有续约,eureka 主动剔除。
    3. 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

启动的时候,先获取注册的应用实例信息。

数据复制冲突问题:两个解决

  1. lastDirtyTimestamp表示。(类似版本号)
  2. 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信息不回被更新
  • 一分钟接收到的续约次数小于 指定 阀值的话,则关闭租约剔除(进入 自我保护)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值