分布式注册中心

服务治理SpringCloud Eureka

什么是服务治理

       在传统rpc远程调用中,服务与服务依赖关系,管理比较复杂,所以需要使用服务治理,管理服务与服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。

服务注册与发现

       在服务注册与发现中,有一个注册中心,当服务器启动的时候,会把当前自己服务器的信息 比如 服务地址通讯地址等以别名方式注册到注册中心上。

       另一方(消费者|服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,然后在实现本地rpc调用远程。

搭建注册中心

1、pom文件引入

<!-- 管理依赖 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.M7</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>


    <dependencies>
        <!--SpringCloud eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>
    <!-- 注意: 这里必须要添加, 否者各种依赖有问题 -->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/libs-milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

2、appliaction.yml配置文件

###eureka 服务端口号
server:
  port: 8100
###服务注册名称
eureka:
  instance:
    ###注册中心ip地址
    hostname: 127.0.0.1
  ###客户端调用地址
  client:
    serviceUrl:
      ###注册地址
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
    ###因为该应用为注册中心,不会注册自己(集群是需要为true)
    register-with-eureka: false
    ###因为自己为注册中心 ,不会去在该应用中的检测服务
    fetch-registry: false

3、启动项

@SpringBootApplication
//开启EurekaServer服务
@EnableEurekaServer
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class, args);
    }
}

4、访问Eureka注册中心

注册服务提供者

1、pom文件引入

<!-- 管理依赖 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.M7</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <!-- SpringBoot整合Web组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- SpringBoot整合eureka客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
    <!-- 注意: 这里必须要添加, 否者各种依赖有问题 -->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/libs-milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

2、配置文件

###会员项目的端口号
server:
  port: 8000
###服务名称(服务注册到eureka名称)
spring:
  application:
    name: app-springCloud-member
###服务注册到eureka地址
eureka:
  client:
    service-url:
      ###当前服务注册到Eureka服务地址
      defaultZone: http://localhost:8100/eureka
    ###需要将会员服务注册到Eureka服务中
    register-with-eureka: true
    ###需要检索服务
    fetch-registry: true

3、启动项

@SpringBootApplication
//将当前服务注册到Eureka上
@EnableEurekaClient
public class AppMember {
    public static void main(String[] args) {
        SpringApplication.run(AppMember.class,args);
    }
}

4、后端相关代码

@RestController
public class MemberApiController {
    @Value("${server.port}")
    private String serverPort;
    @RequestMapping("/getMember")
    public String getMember(){
        return "欢迎来到会员服务:端口号"+serverPort;
    }
}

5、访问Eureka服务

注册服务消费者

1、pom文件引入

<!-- 管理依赖 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.M7</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <!-- SpringBoot整合Web组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- SpringBoot整合eureka客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
    <!-- 注意: 这里必须要添加, 否者各种依赖有问题 -->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/libs-milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

2、配置文件

###服务启动端口号
server:
  port: 8001
###服务名称(服务注册到eureka名称)
spring:
  application:
    name: app-springCloud-order
###服务注册到eureka地址
eureka:
  client:
    service-url:
      ###当前服务注册到Eureka服务地址
      defaultZone: http://localhost:8100/eureka
    ###需要将会员服务注册到Eureka服务中
    register-with-eureka: true
    ###需要检索服务
    fetch-registry: true

3、启动项

@SpringBootApplication
//将当前服务注册到Eureka上
@EnableEurekaClient
public class AppOrder {
    public static void main(String[] args) {
        SpringApplication.run(AppOrder.class,args);
    }
    //Spring默认没有对RestTemplate进行管理,
    // 所以直接使用@Autowired进入不到Springboot容器中
    // 需要手动将RestTemplate注入,通过@Bean注解的方式
    @Bean
    // 如果使用rest方式以别名方式进行调用依赖ribbon负载均衡器 @LoadBalanced
    // @LoadBalanced就能让这个RestTemplate在请求时拥有客户端负载均衡的能力
    @LoadBalanced
    RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

4、后端相关代码

@RestController
public class OrderApiController {
    // RestTemplate 是有SpringBoot Web组件提供 默认整合ribbon负载均衡器
    // rest方式底层是采用httpclient技术
    @Autowired
    private RestTemplate restTemplate;
    // 订单服务调用会员服务
    @RequestMapping("/getOrder")
    public String getOrder() {
        // 有两种方式,一种是采用服务别名方式调用,
        // 另一种是直接调用 使用别名去注册中心上获取对应的服务调用地址
        String url = "http://app-springCloud-member/getMember";
        String result = restTemplate.getForObject(url, String.class);
        System.out.println("订单服务调用会员服务result:" + result);
        return result;
    }
}

5、消费者访问服务者

服务者集群

       只需要修改服务者的配置文件中的端口号即可,将端口号由原来的8000改为8100,再启动新的服务(注意不是重启服务),这样Eureka中心就有两个服务者了。

此时消费者访问服务者就会出现负载均衡效果了。

高可用注册中心

      在微服务中,注册中心非常核心,可以实现服务治理,如果一旦注册出现故障的时候,可能会导致整个微服务无法访问,在这时候就需要对注册中心实现高可用集群模式。

Eureka高可用原理

       Eureka高可用实际上将自己作为服务向其他服务注册中心注册自己,这样就可以形成一组相互注册的服务注册中心,从而实现服务清单的互相同步,达到高可用效果。

       1、创建多个注册服务,过程同上。

       2、唯一需要注意的是修改配置文件,已达到相互注册的效果。

###eureka 服务端口号
server:
  port: 8100
###定义服务注册名称(集群的服务名称一定要相同)
spring:
  application:
    name: app-springCloud-eureka
eureka:
  instance:
    ###注册中心ip地址
    hostname: 127.0.0.1
  ###客户端调用地址
  client:
    serviceUrl:
      ###注册地址
      defaultZone: http://${eureka.instance.hostname}:8200/eureka/
    ###因为是集群,所以需要改为true
    register-with-eureka: true
    ###因为是集群,所以需要改为true
    fetch-registry: true
###eureka 服务端口号
server:
  port: 8200
###定义服务注册名称(集群的服务名称一定要相同)
spring:
  application:
    name: app-springCloud-eureka
eureka:
  instance:
    ###注册中心ip地址
    hostname: 127.0.0.1
  ###客户端调用地址
  client:
    serviceUrl:
      ###注册地址
      defaultZone: http://${eureka.instance.hostname}:8100/eureka/
    ###因为是集群,所以需要改为true
    register-with-eureka: true
    ###因为是集群,所以需要改为true
    fetch-registry: true

注意,如果想要达成集群的效果,服务名称一定要是相同的。

3、访问各自的注册中心

4、修改服务者配置文件

需要将服务注册到Eureka集群中

###会员项目的端口号
server:
  port: 8010
###服务名称(服务注册到eureka名称)
spring:
  application:
    name: app-springCloud-member
###服务注册到eureka地址
eureka:
  client:
    service-url:
      ###当前服务注册到Eureka服务地址
      defaultZone: http://localhost:8100/eureka,http://localhost:8200/eureka
    ###需要将会员服务注册到Eureka服务中
    register-with-eureka: true
    ###需要检索服务
    fetch-registry: true

5、修改消费者配置文件

###服务启动端口号
server:
  port: 8001
###服务名称(服务注册到eureka名称)
spring:
  application:
    name: app-springCloud-order
###服务注册到eureka地址
eureka:
  client:
    service-url:
      ###当前服务注册到Eureka服务地址
      defaultZone: http://localhost:8100/eureka,http://localhost:8200/eureka
    ###需要将会员服务注册到Eureka服务中
    register-with-eureka: true
    ###需要检索服务
    fetch-registry: true

6、访问各自的注册中心 

       因为在注册的过程中,只会保证一台注册中心有对应的服务信息数据(类似于zookeeper),当8200注册中心宕机后,自动启动转移同步数据到8100上去的。

Eureka自我保护机制

        默认情况下,EurekaClient会定时向EurekaServer端发送心跳,如果EurekaServer在一定时间内没有收到EurekaClient发送的心跳,便会把该实例从注册服务列表中剔除(默认是90秒),但是在短时间内丢失大量的实例心跳,这时候EurekaServer会开启自我保护机制,Eureka不会踢出该服务。

关闭自我保护机制

修改Eureka服务端配置文件

 server:
    # 测试时关闭自我保护机制,保证不可用服务及时踢出
    enable-self-preservation: false
    eviction-interval-timer-in-ms: 2000

修改Eureka客户端配置文件

# 心跳检测检测与续约时间
# 测试时将值设置设置小些,保证服务关闭后注册中心能及时踢出服务
  instance:
###Eureka客户端向服务端发送心跳的时间间隔,单位为秒(客户端告诉服务端自己会按照该规则)  
    lease-renewal-interval-in-seconds: 1
####Eureka服务端在收到最后一次心跳之后等待的时间上限,单位为秒,超过则剔除(客户端告诉服务端按照此规则等待自己)
    lease-expiration-duration-in-seconds: 2    

但是,万万不幸的是,Eureka闭源了,我们可以想办法用其他的注册中心替代Eureka:Zookeeper、Consul。

使用Consul来替代Eureka

简介

        Consul 是一套开源的分布式服务发现和配置管理系统,由 HashiCorp 公司用 Go 语言开发。

        它具有很多优点。包括: 基于 raft 协议,比较简洁; 支持健康检查, 同时支持 HTTP 和 DNS 协议 支持跨数据中心的 WAN 集群,提供图形界面 跨平台,支持 Linux、Mac、Windows。

环境搭建

1、下载

       Consul下载地址https://www.consul.io/downloads.html

下载window版,解压得到一个可执行文件。 
2、设置环境变量

      在path后面添加consul所在目录。

3、启动consul命

      让我们直接在cmd里可直接使用consul使命。

consul agent -dev -ui -node=cy

-dev开发服务器模式启动,-node结点名为cy,-ui可以用界面访问,默认能访问。

4、访问Consul

http://localhost:8500

Consul客户端

1、pom文件引入

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.0.1.RELEASE</version>
</parent>
	<!-- 管理依赖 -->
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Finchley.M7</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
	<dependencies>
		<!-- SpringBoot整合Web组件 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!--SpringCloud consul-server -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-consul-discovery</artifactId>
		</dependency>
	</dependencies>
	<!-- 注意: 这里必须要添加, 否者各种依赖有问题 -->
	<repositories>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/libs-milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</repository>
	</repositories>

2、配置文件

###服务端口号
server:
  port: 8502
spring:
### 服务名称
  application:
    name: consul-member
####consul注册中心地址
  cloud:
    consul:
    ### consul地址
      host: localhost
          ###     ### consul端口号
      port: 8500
      discovery:
      ##服务地址直接为ip地址
        hostname: 192.168.18.220
###默认情况下 服务注册到注册中心 地址随机生成英文 pc-yushengjun:

### 换不同注册中心的时候,接口调用方式都不变  无非变化 配置文件和maven依赖信息

3、启动项

@EnableDiscoveryClient 与@EnableEurekaClient区别

  • @EnableDiscoveryClient注解是基于spring-cloud-commons依赖,并且在classpath中实现; 适合于consul、zookeeper注册中心
  • @EnableEurekaClient注解是基于spring-cloud-netflix依赖,只能为eureka作用
@SpringBootApplication
@EnableDiscoveryClient
// @EnableEurekaClient 是Eureka使用的
// @EnableDiscoveryClient 作用是 如果服务使用connsul、zookeeper 使用
// @EnableDiscoveryClient 向注册中心上注册服务
public class ConsulAPP {
	public static void main(String[] args) {
		SpringApplication.run(ConsulAPP.class, args);
	}
}

4、DiscoveryClient用法

discoveryClient接口,可以获取注册中心上的实例信息。

@RequestMapping("/discoveryClientMember")
public List<ServiceInstance> discoveryClientMember() {
	List<ServiceInstance> instances = discoveryClient.getInstances("consul-member");
	for (ServiceInstance serviceInstance : instances) {
		System.out.println("url:" + serviceInstance.getUri());
	}
	return instances;
}

5、订单服务调用会员服务

// springcloud 中使用feign或者rest技术实现调用服务接口
// 订单服务调用会员服务
@RequestMapping("/orderToMember")
public String orderToMember() {
	// 有两种方式,一种是采用服务别名方式调用,
	// 另一种是直接调用 使用别名去注册中心上获取对应的服务调用地址
	//第一种方式:String memberUrl = "http://zk-member/getMember";
	//第二种方式:使用别名
	String serviceUrl = getServiceUrl("consul-member") + "/getMember";
	String result = restTemplate.getForObject(serviceUrl, String.class);
	System.out.println("订单服务调用会员服务result:" + result);
	return result;
}
public String getServiceUrl(String name) {
	List<ServiceInstance> list = discoveryClient.getInstances(name);
	if (list != null && !list.isEmpty()) {
		return list.get(0).getUri().toString();
	}
	return null;
}

使用Zookeeper来替代Eureka

简介

Zookeeper是一个分布式协调工具,可以实现服务注册与发现、注册中心、消息中间件、分布式配置中心等。

ZK客户端

1、启动zk服务器

2、pom文件引入

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.0.1.RELEASE</version>
</parent>
	<!-- 管理依赖 -->
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Finchley.M7</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
	<dependencies>
		<!-- SpringBoot整合Web组件 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<!-- SpringBoot整合eureka客户端 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
		</dependency>

	</dependencies>
	<!-- 注意: 这里必须要添加, 否者各种依赖有问题 -->
	<repositories>
		<repository>
			<id>spring-milestones</id>
			<name>Spring Milestones</name>
			<url>https://repo.spring.io/libs-milestone</url>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</repository>
	</repositories>

3、配置文件

会员配置文件

###服务端口号
server:
  port: 8000
###服务名称
spring:
  application:
    name: zk-member
  cloud:
    zookeeper:
    ###注册到zookeeper地址
      connect-string: 127.0.0.1:2181

订单配置文件

###服务端口号
server:
  port: 8060
###服务名称
spring:
  application:
    name: zk-order
  cloud:
    zookeeper:
    ###注册到zookeeper地址
      connect-string: 127.0.0.1:2181

启动zk-member服务和zk-order服务,可以发现在Zk服务器端上有对应的节点信息。

Zookeeper与Eureka区别

首先,我们需要了解CPA理论。

       CAP:一个分布式系统不可能同时满足C(一致性)A(可用性)P(分区容错性)。由于分区容错性在是分布式系统中必须要保证的,因此我们只能在AC之间进行权衡。在此Zookeeper保证的是CP, Eureka则是AP

Consistency(一致性), 数据一致更新,所有数据变动都是同步的
Availability(可用性), 好的响应性能
Partition tolerance(分区容忍性) 可靠性

1“C”是指一致性,即当一个Process(过程)修改了某个数据后,其他Process读取这是数据是,得到的是更新后的数据,但并不是所有系统都 可以做到这一点。例如,在一些并非严格要求一致性的系统中,后来的Process得到的数据可能还是修改之前的数据,或者需要等待一定时间后才能得到修改 之后的数据,这被成为弱一致性,最经典的应用就是DNS系统。当用户修改了DNS配置后,往往不会马上在全网更新,必定会有一个延迟,这个延迟被称为不一致窗口,它的长度取决于系统的负载、冗余的个数等因素。但对于某些系统而言,一旦写入,后面读取的一定是修改后的数据,如银行账户信息,这被称为强一致性
2“A”是指可用性。即系统总是能够为用户提供连续的服务能力。当用户发出请求是,系统能给出响应(成功或者失败),而且是立即给出响应,而不是等待其他事情完成才响应。如果需要等待某件事情完成才响应,那么可用性就不存在了。
3“P”是指容错性。任何一个分布式计算系统都是由多个节点组成的。在正常情况下,节点与节点之间的通信是正常的。但是在某些情况下,节点之间的通信会 断开,这种断开成为“Partition”。在分布式计算的实现中,Partition是很常见的,因为节点不可能永远不出故障,尤其是对于跨物理地区的 海量存储系统而言,而容错性则可以保证如果只是系统中的部分节点不可用,那么相关的操作仍旧能够正常完成。

Zookeeper是保证CP

       当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。也就是说,服务注册功能对可用性的要求要高于一致性。但是zk会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30 ~ 120s, 且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署的环境下,因网络问题使得zk集群失去master节点是较大概率会发生的事,虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。

Eureka是保证AP

       Eureka看明白了这一点,因此在设计时就优先保证可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册或时如果发现连接失败,则会自动切换至其它节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况: 
1. Eureka
不再从注册列表中移除因为长时间没收到心跳而应该过期的服务 
2. Eureka
仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用
3.
当网络稳定时,当前实例新的注册信息会被同步到其它节点中

因此, Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值