基于网上学习做了一个提升自己记忆的笔记:
首先聊一下微服务,和分布式,集群的理解

分布式

一个业务分拆多个子业务,部署在不同的服务器上。分布式他是一个具体的部署方式,也就是说他是实现微服务的。即 一个业务已经分拆出很多个子业务,并且部署在不同的服务器上. 也就是具体的一个实现方式

微服务

微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每个微服务仅关注于完成一件任务并很好地完成该任务。在所有情况下,每个任务代表着一个小的业务能力。
通常我们也可以说 微服务=分布式开发+服务治理

集群

同一个业务,部署在多个服务器上。


Eureka-微服务的注册中心

Eureka简介

Eureka 是Netflix的子模块之一,也是一个核心的模块,Eureka 里有2个组件,一个是EurekaServer(一个独立的项目) 这个是用于定位服务以实现中间层服务器的负载平衡和故障转移,另一个便是EurekaClient(我们的微服务) 它是用于与Server交互的,可以使得交互变得非常简单:只需要通过服务标识符即可拿到服务。

与spring-cloud的关系

Spring Cloud 封装了 Netflix 公司开发的 Eureka 模块来实现服务注册和发现(可以对比Zookeeper)。

Eureka 采用了 C-S 的设计架构。Eureka Server 作为服务注册功能的服务器,它是服务注册中心。

而系统中的其他微服务,使用 Eureka 的客户端连接到 Eureka Server并维持心跳连接。这样系统的维护人员就可以通过 Eureka Server 来监控系统中各个微服务是否正常运行。SpringCloud 的一些其他模块(比如Zuul)就可以通过 Eureka Server 来发现系统中的其他微服务,并执行相关的逻辑。

(Eureka Server:1.收集客户端的注册信息。2.定时更新信息看是否还活着,3.服务消费者还会发起远程的调用 )

微服务多个docker 微服务多个注册中心_微服务多个docker

使用Eureka

Eureka服务端:

(充当服务与发现的)

pom依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

项目配置文件里面加入以下配置:

server:
  port: 8761
eureka:
  server:
    enable-self-preservation: false  #关闭自我保护机制
    eviction-interval-timer-in-ms: 4000 #设置清理间隔(单位:毫秒 默认是60*1000)
  instance:
    hostname: localhost
  client:
    registerWithEureka: false #不把自己作为一个客户端注册到自己身上
    fetchRegistry: false  #不需要从服务端获取注册信息(因为在这里自己就是服务端,而且已经禁用自己注册了)
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka

启动类注解:

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

启动服务端程序,看到以下图片则启动成功:

微服务多个docker 微服务多个注册中心_分布式_02

图中这个红色警告只是说你把他的自我保护机制关闭了

THE SELF PRESERVATION MODE IS TURNED OFF. THIS MAY NOT PROTECT INSTANCE EXPIRY IN CASE OF NETWORK/OTHER PROBLEMS.

自动保护机制是一种针对网络异常波动的安全保护措施,使用自我保护模式能使Eureka集群更加的健壮、稳定的运行。

(自我保护机制,用来踢出没有正常上线的服务, 可以满足服务的踢出有两种方式:1.关闭自我保护机制的情况下,只能通过发心跳判断是否正常上线,从而踢除下线或者坏死的服务

2.如果开启了自我保护机制,就需要判断到底是不是这个注册中心服务本身也有可能出现问题,因为基于本机运行Eureka,不需要网络.自我保护机制就是为了防止误杀,有一个计算公式: 服务的总数x每分钟的续约数(发送的心跳)x自我保护的预值 然后才是我们的保护值。 这个保护值也就是说达到了某个量,默认85% 如果低于85%,那就会判断出是自己的问题 这就是自我保护的一个基准,如果不是 还是会通过发心跳的方式来踢出服务. 但是一般都会关掉 因为为了容灾搭集群,我们在单机测试的时候很容易满足心跳失败比例在 15 分钟之内低于 85%,一旦开启了保护机制,则服务注册中心维护的服务实例就不是那么准确了,此时我们可以使用eureka.server.enable-self-preservation=false来关闭保护机制,这样可以确保注册中心中不可用的实例被及时的剔除(不推荐))

Eureka客户端:

pom依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

项目配置文件里面加入以下配置:

server:
  port: 8081
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/ #eureka服务端地址
  instance:
    instance-id: user-1 #此实例注册到eureka服务端的唯一的实例ID
    prefer-ip-address: true #是否显示IP地址
    lease-renewal-interval-in-seconds: 10 #eureka客户需要多长时间发送心跳给eureka服务器,表明它仍然活着,默认为30秒 (与下面配置的单位都是秒)
    lease-expiration-duration-in-seconds: 60 #Eureka服务器在接收到实例的最后一次发出的心跳后,需要等待多久才可以将此实例删除,默认为90秒
spring:
  application:
    name: server-user #此实例注册到eureka服务端的name

启动类注解:

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

启动客户端程序,看到客户端注册信息则启动成功:

微服务多个docker 微服务多个注册中心_微服务_03

这里我们能看见名字叫SERVER-USER的实例ID为user-1的服务注册到Eureka上面来了至此,一个简单的Eureka已经搭建好了。

Eureka集群

Eureka集群原理

服务启动后向Eureka注册,Eureka Server会将注册信息向其他Eureka Server进行同步,当服务消费者要调用服务提供者,则向服务注册 中心获取服务提供者地址,然后会将服务提供者地址缓存在本地,下次再调用时,则直接从本地缓存中取,完成一次调用。

Eureka集群配置

( Eureka 集群配置:最主要配置的地方就是真实注册的地址, Eureka的服务端本身自己可以提供服务,还能把自己给注册上去,所以Eureka实现集群的原理就是通过把自己当成一个服务注册到另一个服务上去.负载均衡的规则也是轮询

Eureka 它有同步的机制,同步的机制不是说马上同时注册到多台地址上去,我们只需要注册其中一台就可以了.这时候注册中心就会主动的发起通信告诉其他的同样是服务端的Eureka的server端,告诉他门注册的队列信息直接传送过去.拿到注册信息后 要进行一个同步. 所以集群就是基于他本身就是注册中心注册到服务端来,还可以通信的方式把我们的注册信息发送给另外的服务器,以此确保信息是同步的)

刚刚我们了解到 Eureka Server会将注册信息向其他Eureka Server进行同步 那么我们s的声明有哪些server呢?

这里假设我们有3个Eureka Server:

eureka-server-1
eureka-server-2
eureka-server-3

现在怎么声明集群环境的server呢? 我们看一张图:

微服务多个docker 微服务多个注册中心_微服务多个docker_04

这里为了方便理解集群,但是又没有真实的环境供我们模拟,所以来做一个域名的映射,修改电脑的hosts文件:

Win10目录:C:\Windows\System32\drivers\etc
127.0.0.1  eureka3000.com
127.0.0.1  eureka3001.com
127.0.0.1  eureka3002.com

我们来看看具体一台的配置:

server:
  port: 3000
eureka:
  server:
    enable-self-preservation: false
    eviction-interval-timer-in-ms: 4000
  instance:
    hostname: eureka3000.com
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://eureka3001.com:3001/eureka,http://eureka3002.com:3002/eureka

三台Eureka服务都配置完成之后,我们的客户端只需要改一个配置即可:

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:3000/eureka/,http://eureka3001.com:3001/eureka,http://eureka3002.com:3002/eureka

配置完成之后,全部启动我们可以看到效果:

微服务多个docker 微服务多个注册中心_Server_05

客户端虽然要配置三个Eureka注册地址,但是不是代表他会注册三次,因为我们EurekaServer的注册信息是同步的,这里只需要注册一次就可以了,但是为什么要写三个地址呢。因为这样就可以做到高可用的配置:打个比方有3台服务器。但是突然宕机了一台, 但是其他2台还健在,依然可以注册我们的服务,换句话来讲, 只要有一台服务还建在,那么就可以注册服务。

CAP

微服务多个docker 微服务多个注册中心_微服务多个docker_06

1998年,加州大学的计算机科学家 Eric Brewer 提出,分布式系统有三个指标。

Consistency 一致性
Availability 可用性
Partition tolerance 分区容错性

他们第一个字母分别是C、A、P。Eric Brewer说,这三个指标不可能同时做到。这个结论就叫做 CAP 定理。

Partition tolerance

中文叫做"分区容错"。

大多数分布式系统都分布在多个子网络。每个子网络就叫做一个区(partition)。分区容错的意思是,区间通信可能失败。比如,一台服务器放在本地,另一台服务器放在外地(可能是外省,甚至是外国),这就是两个区,它们之间可能无法通信。

微服务多个docker 微服务多个注册中心_Server_07

上图中,S1 和 S2 是两台跨区的服务器。S1 向 S2 发送一条消息,S2 可能无法收到。系统设计的时候,必须考虑到这种情况。

一般来说,分区容错无法避免,因此可以认为 CAP 的 P 总是成立。CAP 定理告诉我们,剩下的 C 和 A 无法同时做到。

(分布式必须要把p 考虑进去,不然没办法完成分布式的一个设计,完成分布式的部署 ,说白了分布式最主要就是为了解决容错这个问题)

Consistency

Consistency 中文叫做"一致性"。意思是,写操作之后的读操作,必须返回该值。举例来说,某条记录是 v0,用户向 S1 发起一个写操作,将其改为 v1。

微服务多个docker 微服务多个注册中心_微服务多个docker_08

接下来用户读操作就会得到v1。这就叫一致性。

微服务多个docker 微服务多个注册中心_服务器_09

问题是,用户有可能会向S2发起读取操作,由于S2的值没有发生变化,因此返回的是v0,所以S1和S2的读操作不一致,这就不满足一致性了。

微服务多个docker 微服务多个注册中心_微服务_10

为了让S2的返回值与S1一致,所以我们需要在往S1执行写操作的时候,让S1给S2也发送一条消息,要求S2也变成v1。

微服务多个docker 微服务多个注册中心_Server_11

这样子用户向S2发起读操作,就也能得到v1。

微服务多个docker 微服务多个注册中心_微服务_12

Availability

Availability 中文叫做"可用性",意思是只要收到用户的请求,服务器就必须给出回应。

用户可以选择向 S1 或 S2 发起读操作。不管是哪台服务器,只要收到请求,就必须告诉用户,到底是 v0 还是 v1,否则就不满足可用性。

Consistency 和 Availability 的矛盾

一致性和可用性,为什么不可能同时成立?答案很简单,因为可能通信失败(即出现分区容错)。

如果保证 S2 的一致性,那么 S1 必须在写操作时,锁定 S2 的读操作和写操作。只有数据同步后,才能重新开放读写。锁定期间,S2 不能读写,没有可用性不。

如果保证 S2 的可用性,那么势必不能锁定 S2,所以一致性不成立。

综上所述,S2 无法同时做到一致性和可用性。系统设计时只能选择一个目标。如果追求一致性,那么无法保证所有节点的可用性;如果追求所有节点的可用性,那就没法做到一致性。

Eurka 工作流程

了解完 Eureka 核心概念,自我保护机制,以及集群内的工作原理后,我们来整体梳理一下 Eureka 的工作流程:

1、Eureka Server 启动成功,等待服务端注册。在启动过程中如果配置了集群,集群之间定时通过 Replicate 同步注册表,每个 Eureka Server 都存在独立完整的服务注册表信息

2、Eureka Client 启动时根据配置的 Eureka Server 地址去注册中心注册服务

3、Eureka Client 会默认每 30s 向 Eureka Server 发送一次心跳请求,证明客户端服务正常

4、当 Eureka Server 默认 90s 内没有收到 Eureka Client 的心跳,注册中心则认为该节点失效,会注销该实例

5、单位时间内 Eureka Server 统计到有大量的 Eureka Client 没有上送心跳,则认为可能为网络异常,进入自我保护机制,不再剔除没有上送心跳的客户端

6、当 Eureka Client 心跳请求恢复正常之后,Eureka Server 自动退出自我保护模式

7、Eureka Client 定时全量或者增量从注册中心获取服务注册表,并且将获取到的信息缓存到本地

8、服务调用时,Eureka Client 会先从本地缓存找寻调取的服务。如果获取不到,先从注册中心刷新注册表,再同步到本地缓存

9、Eureka Client 获取到目标服务器信息,发起服务调用

10、Eureka Client 程序关闭时向 Eureka Server 发送取消请求,Eureka Server 将实例从注册表中删除

这就是Eurka基本工作流程