• 高可用服务注册中心(Eureka-Cluster)


    在实际生产中,我们需要高可用的集群方案,本章就是基于SpringBoot1.5.4 Cloud(Dalston.SR2) 的高可用Eureka Cluster,以及生产中需要注意的事项…

    - Eureka Cluster

    本教程用1个项目(battcn-cloud-discovery),多环境方式演示

    - pom.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <dependencies>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka-server</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    </dependency>
    </dependencies>

    - Application.java

    1
    2
    3
    4
    5
    6
    7
    8
    @SpringBootApplication
    @EnableEurekaServer
    public class BattcnCloudDiscoveryApplication {

    public static void main(String[] args) {
    SpringApplication.run(BattcnCloudDiscoveryApplication.class, args);
    }
    }

    - application.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    server:
    port: 8761
    spring:
    profiles:
    active: peer2
    #官方写的就是 8761
    ---
    spring:
    profiles: peer1
    application:
    name: Eureka-Server-1
    eureka:
    instance:
    hostname: peer1
    #配置主机名
    client:
    register-with-eureka: false
    #配置服务注册中心是否以自己为客户端进行注册(配置false)
    fetch-registry: false
    #是否取得注册信息(配置false)
    service-url:
    defaultZone: http://peer2:7002/eureka/
    #defaultZone 一定要按照标准写法,因为service-url的数据类型是Map 这算是个小坑需要注意
    server:
    port: 7001
    ---
    spring:
    profiles: peer2
    application:
    name: Eureka-Server-1
    eureka:
    instance:
    hostname: peer2
    #配置主机名
    client:
    register-with-eureka: false
    #配置服务注册中心是否以自己为客户端进行注册(配置false)
    fetch-registry: false
    #是否取得注册信息(配置false)
    service-url:
    defaultZone: http://peer1:7001/eureka/
    server:
    port: 7002
    #defaultZone 一定要按照标准写法,因为service-url的数据类型是Map 这算是个小坑需要注意

    - 启动集群

    命令:mvn clean package (先打成jar包)

    1
    2
    peer1:java -jar battcn-cloud-discovery.jar --spring.profiles.active=peer1
    peer2:java -jar battcn-cloud-discovery.jar --spring.profiles.active=peer2

    1.点击蓝色加号
    2.点击Spring Boot
    3.填写 Name:peer1 Program arguments:–spring.profiles.active=peer1(启动2个操作2次,记得改名字和激活环境,Eclipse太简单了application.yml 直接修改内容启动就行了)

    启动多个启动多个

    启动成功分别访问

    1
    http://peer1:7001

    peer1peer1

    1
    http://peer2:7002

    peer2peer2

    如出现上图所示,代表我们集群启动成功

    - 高可用测试

    1.创建battcn-cloud-h1 和 battcn-cloud-h2 2个项目,基本大同小异

    就这2个包够了,跟 h1 代码唯一的区别就是 h2 做调用 h1写好接口就行了

    - pom.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <dependencies>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    </dependency>
    </dependencies>

    - application.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    server:	
    port: 7012
    spring:
    application:
    name: battcn-cloud-h2

    eureka:
    instance:
    hostname: localhost #配置主机名
    client:
    service-url:
    defaultZone: http://peer1:7001/eureka/,http://peer2:7002/eureka/ #配置Eureka Server

    - H2Application.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    @SpringBootApplication
    @EnableDiscoveryClient
    @RestController
    public class H2Application {

    static Logger LOGGER = LoggerFactory.getLogger(H2Application.class);

    @Bean
    @LoadBalanced
    RestTemplate restTemplate() {
    return new RestTemplate();
    }

    @RequestMapping("/h2")
    public String home(@RequestParam String email) {
    // 改写法之前有说过是VIP模式
    return restTemplate().getForObject("http://battcn-cloud-h1/h1?email=" + email, String.class);
    }

    public static void main(String[] args) {
    SpringApplication.run(H2Application.class, args);
    }
    }

    - 测试

    分别启动 battcn-cloud-h1 和 battcn-cloud-h2

    服务注册服务注册

    访问:http://localhost:7012/h2?email=1837307557@qq.com

    浏览器:My Name's :battcn-cloud-h1 Email:1837307557@qq.com 代表请求成功,然后我们断掉 peer1 或者 peer2 继续请求依旧可用,只是日志会抛异常,通过日志我们可以发现peer2 time out 因为它被杀掉了,但是这并不影响我们服务调用(高可用),只要在启动peer2 错误就不会在出现,在生产中如果集群都挂了 直接 运维下岗就是了(如果peer1 peer2同时挂掉,在启动服务会自动注册上去.)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    2017-07-31 23:01:03.314 ERROR 14792 --- [-target_peer2-8] c.n.e.cluster.ReplicationTaskProcessor   : Network level connection to peer peer2; retrying after delay

    com.sun.jersey.api.client.ClientHandlerException: org.apache.http.conn.ConnectTimeoutException: Connect to peer2:7002 timed out
    at com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:187) ~[jersey-apache-client4-1.19.1.jar:1.19.1]
    at com.netflix.eureka.cluster.DynamicGZIPContentEncodingFilter.handle(DynamicGZIPContentEncodingFilter.java:48) ~[eureka-core-1.6.2.jar:1.6.2]
    at com.netflix.discovery.EurekaIdentityHeaderFilter.handle(EurekaIdentityHeaderFilter.java:27) ~[eureka-client-1.6.2.jar:1.6.2]
    at com.sun.jersey.api.client.Client.handle(Client.java:652) ~[jersey-client-1.19.1.jar:1.19.1]
    at com.sun.jersey.api.client.WebResource.handle(WebResource.java:682) ~[jersey-client-1.19.1.jar:1.19.1]
    at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74) ~[jersey-client-1.19.1.jar:1.19.1]
    at com.sun.jersey.api.client.WebResource$Builder.post(WebResource.java:570) ~[jersey-client-1.19.1.jar:1.19.1]
    at com.netflix.eureka.transport.JerseyReplicationClient.submitBatchUpdates(JerseyReplicationClient.java:116) ~[eureka-core-1.6.2.jar:1.6.2]
    at com.netflix.eureka.cluster.ReplicationTaskProcessor.process(ReplicationTaskProcessor.java:71) ~[eureka-core-1.6.2.jar:1.6.2]
    at com.netflix.eureka.util.batcher.TaskExecutors$BatchWorkerRunnable.run(TaskExecutors.java:187) [eureka-core-1.6.2.jar:1.6.2]
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_60]
    Caused by: org.apache.http.conn.ConnectTimeoutException: Connect to peer2:7002 timed out
    at org.apache.http.conn.scheme.PlainSocketFactory.connectSocket(PlainSocketFactory.java:123) ~[httpclient-4.5.3.jar:4.5.3]
    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180) ~[httpclient-4.5.3.jar:4.5.3]
    at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:144) ~[httpclient-4.5.3.jar:4.5.3]
    at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:134) ~[httpclient-4.5.3.jar:4.5.3]
    at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:610) ~[httpclient-4.5.3.jar:4.5.3]
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:445) ~[httpclient-4.5.3.jar:4.5.3]
    at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:835) ~[httpclient-4.5.3.jar:4.5.3]
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:118) ~[httpclient-4.5.3.jar:4.5.3]
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56) ~[httpclient-4.5.3.jar:4.5.3]
    at com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:173) ~[jersey-apache-client4-1.19.1.jar:1.19.1]
    ... 10 common frames omitted

    - 注意事项

    EurekaClientConfigBean.java 默认构造方法,如果serviceUrl.defaultZone = null 那么 就注册到 http://localhost:8761/eureka/ 中去(日志会输出改地址,起初我是看的一脸懵逼),所以其他的Key都可以以 杠(-) 或者全大写方式,该处不行,因为人家源码是Map不是对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    public EurekaClientConfigBean() {
    this.serviceUrl.put("defaultZone", "http://localhost:8761/eureka/");
    this.gZipContent = true;
    this.useDnsForFetchingServiceUrls = false;
    this.registerWithEureka = true;
    this.preferSameZoneEureka = true;
    this.availabilityZones = new HashMap();
    this.filterOnlyUpInstances = true;
    this.fetchRegistry = true;
    this.dollarReplacement = "_-";
    this.escapeCharReplacement = "__";
    this.allowRedirects = false;
    this.onDemandUpdateStatusChange = true;
    this.clientDataAccept = EurekaAccept.full.name();
    }

    public String[] getAvailabilityZones(String region) {
    String value = (String)this.availabilityZones.get(region);
    if(value == null) {
    value = "defaultZone";
    }

    return value.split(",");
    }

    public List<String> getEurekaServerServiceUrls(String myZone) {
    String serviceUrls = (String)this.serviceUrl.get(myZone);
    if(serviceUrls == null || serviceUrls.isEmpty()) {
    serviceUrls = (String)this.serviceUrl.get("defaultZone");
    }

    if(!StringUtils.isEmpty(serviceUrls)) {
    String[] serviceUrlsSplit = StringUtils.commaDelimitedListToStringArray(serviceUrls);
    List<String> eurekaServiceUrls = new ArrayList(serviceUrlsSplit.length);
    String[] var5 = serviceUrlsSplit;
    int var6 = serviceUrlsSplit.length;

    for(int var7 = 0; var7 < var6; ++var7) {
    String eurekaServiceUrl = var5[var7];
    if(!this.endsWithSlash(eurekaServiceUrl)) {
    eurekaServiceUrl = eurekaServiceUrl + "/";
    }

    eurekaServiceUrls.add(eurekaServiceUrl);
    }

    return eurekaServiceUrls;
    } else {
    return new ArrayList();
    }
    }

    - 小谈

    其实我是比较倾向于 consul 这种零侵入式的,但是consul 在做高可用比较操蛋,它对外暴露的是 agent 如果你这个 agent挂了,那么后面服务就GG思密达了,cloud service 不允许配置多个agent,个人没找到好的解决方案,有好方案的可以交流…..

  • 相关阅读:
    beforeEach的应用
    小程序
    betterScroll的应用
    前端规划
    vue中下载文件如pdf及图片
    vue cli3.x项目创建及配置
    python读取excel文件中所有sheet表格:openpyxl模块(二)
    python访问excel基本用法:openpyxl模块(一)
    SQL优化:设置执行计划的显示格式
    sql优化实战:把full join改为left join +union all(从5分钟降为10秒)
  • 原文地址:https://www.cnblogs.com/lywJ/p/10715529.html
Copyright © 2020-2023  润新知