• Eureka 单机部署与集群部署


    一、Eureka单机版搭建

    Eureka已经被Spring Cloud继承在其子项目spring-cloud-netflix中,搭建Eureka Server的方式还是非常简单的。只需要通过一个独立的maven工程即可搭建Eureka Server。pom依赖如下:

    <!-- web 启动器 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- eureka server端 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>

      Eureka Server本身也是一个服务,同时又是一个注册中心。在Spring Cloud中,启动的微服务会自动的搜索注册中心并注册服务,那么在单机版Eureka Server环境中,当前服务注册到当前服务中,明显是不合适的。所以搭建Eureka Server单机版时,需要提供特殊的全局配置,避免回路注册逻辑。
      同理,Eureka Server服务在注册中心中发现服务列表逻辑也是不必要的。毕竟注册中心是一个中立的服务管理平台,如果是单机版Eureka Server环境中,Eureka Server服务再去发现服务列表,明显也是不必要的。也需要通过全局配置,避免回路发现逻辑。

    # 设置spring应用命名,可以自定义,非必要
    spring.application.name=eureka-server
    # 设置Eureka Server WEB控制台端口,自定义
    server.port=8761
    #是否将自己注册到Eureka-Server中,默认的为true
    eureka.client.register-with-eureka=false
    #是否从Eureka-Server中获取服务注册信息,默认为true
    eureka.client.fetch-registry=false

    启动Eureka Server注册中心,和普通的SpringBoot应用的启动没有太大的区别。只需要在启动类上增加@EnableEurekaServer注解,来开启Eureka Server服务即可。

    @EnableEurekaServer
    @SpringBootApplication
    public class EurekaApplication {
        public static void main(String[] args) {
            SpringApplication.run(EurekaApplication.class, args);
        }
    }

    访问Eureka Server WEB控制台:通过IP和端口,使用浏览器访问即可查看Eureka Server中的信息。本例中访问地址为:http://localhost:8761/

    注意:防火墙一定要对外开放8761端口,根据实际情况调整。

    二、Eureka集群版搭建

      注册中心作为微服务架构中的核心功能,其重要性不言而喻。所以单机版的Eureka Server在可靠性上并不符合现在的互联网开发环境。集群版的Eureka Server才是商业开发中的选择。

      Eureka Server注册中心的集群和Dubbo的ZooKeeper注册中心集群在结构上有很大的不同。

      ZooKeeper注册中心集群搭建后,集群中各节点呈现主从关系,集群中只有主节点对外提供服务的注册和发现功能,从节点相当于备份节点,只有主节点宕机时,从节点会选举出一个新的主节点,继续提供服务的注册和发现功能。

      而Eureka Server注册中心集群中每个节点都是平等的,集群中的所有节点同时对外提供服务的发现和注册等功能。同时集群中每个Eureka Server节点又是一个微服务,也就是说,每个节点都可以在集群中的其他节点上注册当前服务。又因为每个节点都是注册中心,所以节点之间又可以相互注册当前节点中已注册的服务,并发现其他节点中已注册的服务。

      在集群搭建过程中,全局配置文件的定义非常重要。其中euraka.client.service-url.defaultZone属性是用于配置集群中其他节点的。如果有多个节点,使用逗号','分隔。

      有部分程序员只配置某一个集群节点信息,通过集群节点间的注册通讯实现节点的全面发现。这种配置形式是不推荐的。因为Eureka Server在服务管理上,会根据连带责任来维护服务列表,如果某集群节点宕机,那么通过这个节点注册过来的服务都会连带删除。

    环境:CentOS 7/JDK1.8

    POM依赖:和单机版Eureka Server相同。

    本例中的两个节点分别会搭建在两个Linux系统中,为这两个Linux系统分别定义域名为eurekaserver1和eurekaserver2。

    #eurekaserver1配置
    server.port=8761
    #eureka服务端的实例名称
    eureka.instance.hostname=eurekaserver1
    #false表示不向注册中心注册自己
    eureka.client.register-with-eureka=false
    #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    eureka.client.fetch-registry=false
    #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址,指向另一个注册中心。
    eureka.client.service-url.defaultZone=http://eurekaserver2:8761/eureka/
    #eurekaserver2配置
    server.port=8761
    #eureka服务端的实例名称
    eureka.instance.hostname=eurekaserver2
    #false表示不向注册中心注册自己
    eureka.client.register-with-eureka=false
    #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    eureka.client.fetch-registry=false
    #设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址,指向另一个注册中心
    eureka.client.service-url.defaultZone=http://eurekaserver1:8761/eureka/

    打包工程形成jar文件,并上传打包后的jar文件到Linux系统。

    1. 设置主机名

    修改/etc/hosts文件,设置主机域名。将主机域名和IP进行绑定。新增内容如下(添加的内容是相同的):

    192.168.178.5 eurekaserver1
    192.168.178.6 eurekaserver2

    重启网络服务后。

    2. 使用命令启动Eureka Server

    可以在Linux终端中,通过java命令来启动Eureka Server。在启动的时候,可以通过启动参数来设置有效的配置环境。具体命令如下:

    java -jar -Dspring.profiles.active=dev sc-eureka-server-cluster-1.0.jar

    其中-Dspring.profiles.active启动参数,用于定义本次启动的Eureka Server应用的有效全局配置命名,也就是全局配置文件的后缀。SpringBOOT在启动的时候,会根据启动参数来决定读取的有效全局配置文件是哪一个。

    也可以定义一个shell文件来简化操作。具体shell内容如下:

    #!/bin/bash
     
    cd `dirname $0`
     
    CUR_SHELL_DIR=`pwd`
    CUR_SHELL_NAME=`basename ${BASH_SOURCE}`
     
    JAR_NAME="项目jar包名称"
    JAR_PATH=$CUR_SHELL_DIR/$JAR_NAME
     
    #JAVA_MEM_OPTS=" -server -Xms1024m -Xmx1024m -XX:PermSize=128m"
    JAVA_MEM_OPTS=""
     
    SPRING_PROFILES_ACTIV="-Dspring.profiles.active=配置文件变量名称"
    #SPRING_PROFILES_ACTIV=""
    LOG_DIR=$CUR_SHELL_DIR/logs
    LOG_PATH=$LOG_DIR/${JAR_NAME%..log
     
    echo_help()
    {
        echo -e "syntax: sh $CUR_SHELL_NAME start|stop"
    }
     
    if [ -z $1 ];then
        echo_help
        exit 1
    fi
     
    if [ ! -d "$LOG_DIR" ];then
        mkdir "$LOG_DIR"
    fi
     
    if [ ! -f "$LOG_PATH" ];then
        touch "$LOG_DIR"
    fi
     
    if [ "$1" == "start" ];then
     
        # check server
        PIDS=`ps --no-heading -C java -f --width 1000 | grep $JAR_NAME | awk '{print $2}'`
        if [ -n "$PIDS" ]; then
            echo -e "ERROR: The $JAR_NAME already started and the PID is ${PIDS}."
            exit 1
        fi
     
        echo "Starting the $JAR_NAME..."
     
        # start
        nohup java $JAVA_MEM_OPTS -jar $SPRING_PROFILES_ACTIV $JAR_PATH >> $LOG_PATH 2>&1 &
     
        COUNT=0
        while [ $COUNT -lt 1 ]; do
            sleep 1
            COUNT=`ps  --no-heading -C java -f --width 1000 | grep "$JAR_NAME" | awk '{print $2}' | wc -l`
            if [ $COUNT -gt 0 ]; then
                break
            fi
        done
        PIDS=`ps  --no-heading -C java -f --width 1000 | grep "$JAR_NAME" | awk '{print $2}'`
        echo "${JAR_NAME} Started and the PID is ${PIDS}."
        echo "You can check the log file in ${LOG_PATH} for details."
     
    elif [ "$1" == "stop" ];then
     
        PIDS=`ps --no-heading -C java -f --width 1000 | grep $JAR_NAME | awk '{print $2}'`
        if [ -z "$PIDS" ]; then
            echo "ERROR:The $JAR_NAME does not started!"
            exit 1
        fi
     
        echo -e "Stopping the $JAR_NAME..."
     
        for PID in $PIDS; do
            kill $PID > /dev/null 2>&1
        done
     
        COUNT=0
        while [ $COUNT -lt 1 ]; do
            sleep 1
            COUNT=1
            for PID in $PIDS ; do
                PID_EXIST=`ps --no-heading -p $PID`
                if [ -n "$PID_EXIST" ]; then
                    COUNT=0
                    break
                fi
            done
        done
     
        echo -e "${JAR_NAME} Stopped and the PID is ${PIDS}."
    else
        echo_help
        exit 1
    fi
    View Code

    设置好shell启动脚本后,需要提供可执行权限:shell脚本文件名自己修改:chmod 755 xxx.sh。

    脚本使用方式为:

    #启动Eureka Server
    ./xxx.sh start
    #关闭Eureka Server
    ./xxx.sh stop

    三、Eureka Server安全认证

    Eureka Server作为Spring Cloud中的服务注册中心,如果可以任意访问的话,那么其安全性太低。所以Spring Cloud中也有为Eureka Server提供安全认证的方式。可以使用spring-boot-starter-security组件来为Eureka Server增加安全认证。

    POM依赖:

    <!-- spring boot security安全认证启动器 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

    修改全局配置文件,在全局配置文件中,开启基于http basic的安全认证。

    #eurekaserver1配置
    server.port=8761
    #eureka服务端的实例名称
    eureka.instance.hostname=eurekaserver1
    #false表示不向注册中心注册自己
    eureka.client.register-with-eureka=false
    #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    eureka.client.fetch-registry=false
    # 使用http basic安全认证语法,在集群通信中增加认证信息。  http://用户名:密码@地址:端口/eureka/, 指向另外的注册中心
    # 这里要特别注意:若有多个地址,则允许逗号,不需要有其他字符,如空格等,否则会解析错误
    eureka.client.service-url.defaultZone=http://${spring.security.user.name}:${spring.security.user.password}@eurekaserver2:8761/eureka/ 
    # 开启基于http basic的安全认证 
    spring.security.user.name=test 
    spring.security.user.password=123456
    #eurekaserver2配置
    server.port=8761
    #eureka服务端的实例名称
    eureka.instance.hostname=eurekaserver2
    #false表示不向注册中心注册自己
    eureka.client.register-with-eureka=false
    #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    eureka.client.fetch-registry=false
    # 使用http basic安全认证语法,在集群通信中增加认证信息。  http://用户名:密码@地址:端口/eureka/, 指向另外的注册中心
    eureka.client.service-url.defaultZone=http://${spring.security.user.name}:${spring.security.user.password}@eurekaserver1:8761/eureka/ 
    # 开启基于http basic的安全认证
    spring.security.user.name=test
    spring.security.user.password
    =123456

    spring boot2.x版本后,Spring Security 默认开启了所有 CSRF 攻击防御,需要禁用 /eureka 的防御,否则无法注册和发现服务(体现为服务启动时报错:registration failed Cannot execute request on any known server),集群之间无法通信,导致无法建立。如果开启了安全验证则需要在eureka-server中手动禁用 csrf 攻击功能:

    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
           //为了访问eureka控制台和/actuator时能做安全控制
            super.configure(http);
               //关闭csrf攻击
            http.csrf().disable().httpBasic();
        }
    }

    四、Eureka控制台参数说明

    1. System Status

    Environment: 环境,默认为test,该参数在实际使用过程中,可以不用更改
    Data center: 数据中心,使用的是默认的是 “MyOwn”
    Current time:当前的系统时间
    Uptime:已经运行了多少时间
    Lease expiration enabled:是否启用租约过期 ,自我保护机制关闭时,该值默认是true, 自我保护机制开启之后为false。
    Renews threshold: 每分钟最少续约数,Eureka Server 期望每分钟收到客户端实例续约的总数。
    Renews (last min): 最后一分钟的续约数量(不含当前,1分钟更新一次),Eureka Server 最后 1 分钟收到客户端实例续约的总数。

    2. 红字提醒

    系统在三种情况下会出现红色加粗的字体提示:

    a.在配置上,自我保护机制关闭
    RENEWALS ARE LESSER THAN THE THRESHOLD. THE SELF PRESERVATION MODE IS TURNED OFF.THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.

    b.自我保护机制开启了
    EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE
    NOT BEING EXPIRED JUST TO BE SAFE.

    c.在配置上,自我保护机制关闭了,但是一分钟内的续约数没有达到85% , 可能发生了网络分区,会有如下提示
    THE SELF PRESERVATION MODE IS TURNED OFF.THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.

    3. DS Replicas

    这个下面的信息是这个Eureka Server相邻节点,互为一个集群。

    再往下面,就是注册到这个服务上的实例信息

    4. General Info

    total-avail-memory : 总共可用的内存

    environment : 环境名称,默认test

    num-of-cpus : CPU的个数

    current-memory-usage : 当前已经使用内存的百分比

    server-uptime : 服务启动时间

    registered-replicas : 相邻集群复制节点

    unavailable-replicas :不可用的集群复制节点,如何确定不可用? 主要是server1 向 server2和server3发送接口查询自身的注册信息,如果查询不到,则默认为不可用,也就是说如果Eureka Server自身不作为客户端注册到上面去,则相邻节点都会显示为不可用。

    available-replicas :可用的相邻集群复制节点

    5. Instance Info

    ipAddr:eureka服务端IP
    status:eureka服务端状态

    五、CAP原理

    CAP原则又称CAP定理,指的是在一个分布式系统中,Consistency(数据一致性)、 Availability(服务可用性)、Partition tolerance(分区容错性),三者不可兼得。CAP由Eric Brewer在2000年PODC会议上提出。该猜想在提出两年后被证明成立,成为我们熟知的CAP定理。

    分布式系统CAP定理

    数据一致性

    (Consistency)

    数据一致性(Consistency)

    也叫做数据原子性系统在执行某项操作后仍然处于一致的状态。在分布式系统中,更新操作执行成功后所有的用户都应该读到最新的值,这样的系统被认为是具有强一致性的。等同于所有节点访问同一份最新的数据副本。

    优点: 数据一致,没有数据错误可能。

    缺点: 相对效率降低。

    服务可用性

    (Availablity)

    每一个操作总是能够在一定的时间内返回结果,这里需要注意的是"一定时间内"和"返回结果"。一定时间内指的是,在可以容忍的范围内返回结果,结果可以是成功或者是失败。

    分区容错性

    (Partition-torlerance)

    在网络分区的情况下,被分隔的节点仍能正常对外提供服务(分布式集群,数据被分布存储在不同的服务器上,无论什么情况,服务器都能正常被访问)
    定律:任何分布式系统只可同时满足二点,没法三者兼顾。
    CA,放弃P 如果想避免分区容错性问题的发生,一种做法是将所有的数据(与事务相关的)/服务都放在一台机器上。虽然无法100%保证系统不会出错,但不会碰到由分区带来的负面效果。当然这个选择会严重的影响系统的扩展性。
    CP,放弃A 相对于放弃"分区容错性"来说,其反面就是放弃可用性。一旦遇到分区容错故障,那么受到影响的服务需要等待一定时间,因此在等待时间内系统无法对外提供服务。
    AP,放弃C 这里所说的放弃一致性,并不是完全放弃数据一致性,而是放弃数据的强一致性,而保留数据的最终一致性。以网络购物为例,对只剩下一件库存的商品,如果同时接受了两个订单,那么较晚的订单将被告知商品告罄

    Eureka和ZooKeeper的特性

    六、服务保护

    1. 服务保护模式

      服务保护模式(自我保护模式):一般情况下,微服务在Eureka上注册后,会每30秒发送心跳包,Eureka通过心跳来判断服务时候健康,同时会定期删除超过90秒没有发送心跳服务。

      导致Eureka Server接收不到心跳包的可能:一是微服务自身的原因,二是微服务与Eureka之间的网络故障。通常微服务的自身的故障只会导致个别服务出现故障,一般不会出现大面积故障,而网络故障通常会导致Eureka Server在短时间内无法收到大批心跳。虑到这个区别,Eureka设置了一个阀值,当判断挂掉的服务的数量超过阀值时,Eureka Server认为很大程度上出现了网络故障,将不再删除心跳过期的服务。

      那么这个阀值是多少呢?Eureka Server在运行期间,会统计心跳失败的比例在15分钟内是否低于85%,如果低于85%,Eureka Server则任务是网络故障,不会删除心跳过期服务。

      这种服务保护算法叫做Eureka Server的服务保护模式。

      这种不删除的,90秒没有心跳的服务,称为无效服务,但是还是保存在服务列表中。如果Consumer到注册中心发现服务,则Eureka Server会将所有好的数据(有效服务数据)和坏的数据(无效服务数据)都返回给Consumer。

    2. 服务保护模式存在的必要性

      因为同时保留"好数据"与"坏数据"总比丢掉任何数据要更好,当网络故障恢复后,Eureka Server会退出"自我保护模式"。

      Eureka还有客户端缓存功能(也就是微服务的缓存功能)。即便Eureka Server集群中所有节点都宕机失效,微服务的Provider和Consumer都能正常通信。

      微服务的负载均衡策略会自动剔除死亡的微服务节点(Robbin)。

      只要Consumer不关闭,缓存始终有效,直到一个应用下的所有Provider访问都无效的时候,才会访问Eureka Server重新获取服务列表。

    3. 关闭服务保护模式

      可以通过全局配置文件来关闭服务保护模式,商业项目中不推荐关闭服务保护,因为网络不可靠很容易造成网络波动、延迟、断线的可能。如果关闭了服务保护,可能导致大量的服务反复注册、删除、再注册。导致效率降低。在商业项目中,服务的数量一般都是几十个,大型的商业项目中服务的数量可能上百、数百,甚至上千:

    # 关闭自我保护:true为开启自我保护,false为关闭自我保护
    eureka.server.enable-self-preservation=false
    # 清理间隔(单位:毫秒,默认是60*1000),当服务心跳失效后多久,删除服务。
    eureka.server.eviction-interval-timer-in-ms=60000

     

    参考:

    https://www.cnblogs.com/jing99/p/11576133.html

    https://www.cnblogs.com/linjiqin/p/10087462.html

  • 相关阅读:
    项目在入口加一个简单的密码验证
    关于APICloud使用心得(原创)
    vue、React Nactive的区别(转载)
    js的Element.scrollIntoView的学习
    立个flag---每天一篇博客
    ACID理解
    CAP原理与最终一致性 强一致性 弱一致性
    事物隔离级别
    分布式事务
    MySQL日志
  • 原文地址:https://www.cnblogs.com/myitnews/p/12398347.html
Copyright © 2020-2023  润新知