首页
学习
活动
专区
圈层
工具
发布
49 篇文章
1
美团面试:如何设计一个RPC框架?
2
美团面试:如何设计一个注册中心?
3
消息队列设计精要
4
Replication(上):常见的复制模型&分布式系统的挑战
5
Replication(下):事务,一致性与共识
6
网易面试:将Bean放入Spring容器中有几种方式?
7
MySQL慢查询之慢 SQL 定位、日志分析与优化方案
8
面试官:MQ 消息丢失、重复、积压问题,如何解决?
9
面试官:Spring中获取Bean有几种方式?
10
面试:你知道Java性能优化有哪些手段?
11
面试官:千万级数据,怎么快速查询?
12
面试官:你会哪些JVM调优参数?
13
面试官:如何设计一个 订单系统?
14
和面试官聊了半小时的MySQL索引!
15
121道分布式面试题和答案
16
数据库分库分表,何时分?怎样分?
17
一个单例模式,被问7个问题,难!
18
在线面试:如何设计一个秒杀系统?
19
Spring 为何需要三级缓存解决循环依赖,而不是二级缓存?
20
面试官:熟悉SQL优化吗?我只知道20种,其实远不止...
21
吐血整理 | Java并发编程 72 卷
22
面试官再问currentHashMap,就将这篇文章甩给他
23
保姆级教程,2万字详解JVM
24
这代码写的跟狗屎一样!怎么优化?19招搞定它
25
P7大佬压箱底的学习笔记
26
6000多字 | 秒杀系统设计注意点
27
动画+原理+代码+优化,解读十大经典排序算法
28
到底什么是重入锁?拜托,一次搞清楚!
29
面试官再问你 ThreadLocal,你就这样“怼”回去!
30
分布式锁:5个案例,附源码
31
美团面试:说说CAP,我的回答方式很特别
32
分布式事务 :可靠消息最终一致性方案
33
美团面试官:讲清楚MySQL结构体系,立马发offer
34
equals方法比较的是内容?谁告诉你的
35
我通过六个 MySQL 死锁案例,终于理解了死锁的原因
36
必知必会 RabbitMQ面试题 33道(附答案)
37
万字总结 MySQL核心知识,赠送25连环炮
38
那些年,面试被虐过的红黑树
39
小老弟用 案列 引出 ReentrantLock实现原理
40
五分钟说清楚 Spring Boot的自动配置原理
41
面试:Zookeeper常见11个连环炮
42
长文干货 | 手写自定义持久层框架!
43
怒肝一夜 | Mybatis源码深度解析
44
美女面试官问我:能说几个常见的Linux性能调优命令吗?
45
吊打面试官系列:final、finally、finalize 有什么区别?
46
面试官问:如何排除GC引起的CPU飙高?我脱口而出5个步骤
47
JVM真香系列:堆内存详解
48
电商项目实战:如何设计站内信
49
72道 并发编程 面试题!
清单首页面试文章详情

美团面试:如何设计一个注册中心?

大家好,我是田哥

在前面,已经跟大家分享过我去美团面试中遇到的一些题目,对此我也把这些题目进行了一系列分析。

今天,给大家分享如何设计一个注册中心

不管是出于面试,还是深入学习注册中心,关于如何设计一个注册中心都是一个很好的话题。

假设现在我们系统有两个小系统:

  • 订单系统
  • 商品系统

单个系统分别部署在不同服务器上,如果我们订单系统需要调用商品系统的某个服务:

怎么调用?

方法1:商品系统开发的朋友告诉你对应的地址。

方法2:商品系统开发的朋友把对应API地址存放到某个地方。

方法3:直接通过Nginx,使用域名进行转发到某个实例上。

这时候,订单系统就可以通过上述方法调用商品系统的API了。

问题来了

实际线上环境中,很少是单体机构的,很多都是做了集群的,也就是说每个服务会有N个实例,少则几个几十个,多则几百上千上万。如果此时我们还用上面三种方法,当我们的商品系统某个服务下线(宕机了),或者新增实例,此时是非常的头疼。

所以,注册中心就来了。

注册中心来了

我们能不能搞一个第三方的节点,这个节点就用来存放我们商品系统的服务信息,这样一来,其他系统需要服务信息,直接去第三方节点上去获取即可。此时,其他系统只要知道这个第三方的节点地址就可以了。这个第三方的节点,我们也称之为注册中心

下面我们用服务提供方(商品系统)称之为provider,服务调用方(订单系统)我们称之为consumer。

如何设计一个注册中心

我们需要解决如下几个问题:

  • 服务如何注册
  • consumer如何知道provider
  • 服务注册中心如何高可用
  • 服务上下线,消费端如何动态感知
服务注册

当我们把服务信息注册上去后,就应该是:

服务列表保存通常有三种方式:本地内存、数据库、第三方缓存系统

注册上去后,consumer需要服务地址的时候,就可以用相应key去注册中心获取对应的服务列表。

同一个服务注册中心,我们可以注册多个服务,比如用户服务、商品服务、订单服务...

服务消费

consumer端通过key获取指定的服务地址列表。

以上的还是蛮简单的吧,简单来说,我们就是引用了一个第三方的服务来存放我们的服务提供者列表。并且以key-value的形式存储,key我们可以理解为服务名称,value就是服务实例列表。

注册中心高可用

高可用无非就是做集群,我们可以对注册中心部署多个节点。在消费端consumer只需要知道一个服务注册中心集群地址cluster-url即可。

动态感知服务上下线

consumer拿到服务列表后,会把服务列表保存起来,保存到本地缓存里。

consumer通过一定的负载均衡算法,选择出一个地址,最后发起远程的调用。

如果我们的服务节点挂掉一个了,怎么办?

此时,服务注册中心的服务列表还是之前的列表,如果consumer调用到过掉的节点上,那岂不是会出问题呀。

所以,我们的服务注册中心需要知道哪个服务节点挂了,然后从对应服务列表里删除。

有种办法叫做心跳检测heartBeat,即就是服务注册中心,每隔一定时间去监测一下provider,如果监测到某个服务挂了,那就把对应服务地址从服务列表中删除。

根据心跳检测,来提出无效服务。

可是不对呀,此时consumer端本地列表里还有过掉的服务地址,怎么办呢?

或者是,在增加一个新的服务节点

对于服务注册中心来说,就是服务列表里增加一个服务地址。

但是在消费端存在同样的问题,就是服务注册中心的服务列表和consumer端的服务列表不一样了。

如何让consumer端也动态感知呢?

其实很简单,此时,我们得思维换一下,因为consumer的服务列表是来自于服务注册中心,我们就可以把consumer理解为消费端,服务注册中心理解为服务端。此时,consumer端就可以去服务端(服务注册中心)拉取provider服务列表。

通常有两种方案:push和pull

  • push:服务注册中心主动推送服务列表给consumer。
  • pull:consumer主动从注册中心拉取服务列表。

不管是push还是pull,都会存在consumer和服务注册中心的通信管道。如果他们之间断开了,那就无法获取服务列表了。

还有就是服务注册中心知道consumer的地址,比如

我得知道你的微信好友,不然我怎么把我手里的资源发给你

我们的网络通信,必然会存在监听的动作。

如果服务注册中心要push到consumer,此时他们之间需要建立一个会话,所以,在服务注册中心会维护一个会话管理的模块。还有一种方式就是consumer提供一个API,这个API给服务注册中心进行回调。

本质是我们是使用HTTP协议还是使用Socket监听

push有个不好点,那就是服务注册中心需要维护大量的会话,而且还需要对每个会话维持一个心跳,一遍知晓这些会话状态,得确保这些consumer能收到数据,

另外就是pull,pull其实就相对push就简单多了。pull和我们前面说的心跳机制是类似的,consumer端启动定时任务,每个多久拉取服务注册中心的服务列表。pull也不需要去维护大量的会话,我只需要每隔多久调用接口拉取服务列表即可。但是这里还是会存在一个问题,因为是定时去拉取,所以会存在一定的数据延迟,比如consumer刚刚拉取服务列表,但就在拉取结束的后,某个服务provider挂了,consumer就要等下次拉取才知道对应服务provider挂了。

如果定时任务是每隔30秒拉去一次,那就是说,延迟最长时间是30秒。

还有一种方式long-pull,也叫长轮询,是上面两种方案的优化方案,consumer发起拉取请求时,先把这个请求hold住,当服务注册中心有发生变化后,consumer端能立马感知。

关于长轮询:

与简单轮询相似,只是在服务端在没有新的返回数据情况下不会立即响应,而会挂起,直到有数据或即将超时 优点:实现也不复杂,同时相对轮询,节约带宽 缺点:还是存在占用服务端资源的问题,虽然及时性比轮询要高,但是会在没有数据的时候在服务端挂起,所以会一直占用服务端资源,处理能力变少 应用:一些早期的对及时性有一些要求的应用:web IM 聊天

这样,我们就搞定了所谓的服务上下线动态感知。

通过上面的服务注册、服务消费、注册中心高可用以及动态感知服务的上下线,这就是我们去实现一个服务注册中心的通用模型。

小总结

关于如何设计一个注册中心,无非重点关以下几点:

  • 服务是如何注册
  • 消费端如何获取服务
  • 如何保证注册中心的高可用
  • 动态感知服务的上下线
下一篇
举报
领券