当我们谈注册中心时我们谈什么

捉虫大师 等级 645 0 0

本文已收录 https://github.com/lkxiaolou/lkxiaolou 欢迎star。

最近工作重心转向了注册中心,于是想来写一篇关于注册中心的文章

概念

什么是注册中心,以大多数人熟悉的RPC框架来说,通常RPC中有三种角色:

  • provider 服务提供者
  • consumer 服务消费者,即调用方
  • registry 注册中心,让consumer能发现provider的关键

注册中心对于服务提供者需要具备服务注册、注销的能力,对于服务消费者需要提供查询服务、感知服务变化的功能。当然还需要解决一些其他问题才能成为一个优秀的注册中心,如高可用、高性能、水平扩展能力、服务探活能力、路由功能、多机房(多活)能力等。

特性详解

存储

可以将注册中心理解为一个存储系统,存储着服务名与服务提供方的映射表。由此可见DNS是目前使用最广泛的注册中心。一般注册中心对存储没有什么要求,甚至你可以基于数据库来实现一个注册中心。

高可用

在聊高可用前,假定你了解分布式CAP理论,如果不知道可以稍微网上查一下,这里就不赘述。

其中对注册中心的高可用要求尤其高,它有如下几层含义,首先肯定是集群部署,无单点问题,其次就算整个集群挂掉了,也不能影响现有服务的调用,只不过现有的调用关系无法及时改变而已。

在分布式理论CAP中,注册中心更理想的应该是AP模式。(此结论更多讨论参考文末的《阿里巴巴为什么不用ZooKeeper做服务发现》),可以简单的从以下两个场景来理解:

  • 注册中心挂掉一个节点无任何影响,如果注册中心是CP模式(强一致),像ZAB、raft协议,它们存在一个“选主”的过程,通常选主时集群是不可写的
  • 如果集群出现“脑裂”的情况,假设5个的节点脑裂为3+2,CP模式下2个节点将完全不可用,如果牺牲一致性,至少保证节点都可访问,对服务的影响应该比完全不可用要小很多

水平扩展

水平扩展说的是如果规模上去后,能否通过加机器的方式来解决性能问题,从这点来说,AP模式也比CP模式更容易扩展,CP模式一般写发生在主节点,所以扩展变得很麻烦,如果写能分散到不同节点,就是可扩展的,以最简单的数据库实现来说,就可以认为是可以水平扩展的,毕竟数据库的写可以通过分库分表或者分布式数据库来解决。

服务探活

在说服务探活前需要介绍一下服务注册的维度,维度影响到探活。一般来说,服务注册的维度有两个:服务维度和应用维度。

  • 服务维度:注册的是接口到ip、port的映射关系,如dubbo(dubbo新版本也支持应用级服务发现,但大多数还是在以服务维度的服务发现在使用),优点是注册信息跟应用无关,可以方便地拆分服务,缺点是粒度太细,注册数据量大。

  • 应用维度:注册的是应用到ip、port的映射关系,如spring cloud,优点是注册数据量小,缺点是拆分服务困难

通常探活也有两种方式,一种是服务端主动探活,另一种是客户端上报心跳。对于应用级的服务探活很简单,只要确定端口是否存活就可以判断应用的存活,所以服务端主动探活即可解决;但服务维度就不行,一般没有现有的方法知道服务是否存活,所以如果想要服务端主动探活,需要RPC框架暴露接口来告知服务端存活的服务,要么就是采取客户端主动上报心跳来告知有哪些服务是存活的。

通常客户端主动上报可以很明确知道服务是否存活,但服务端主动探活不行,有时候端口在,不一定就代表服务是活的。这又是一个问题,探活探死的问题,探死通常很直接,探活很困难,端口不在就一定是死的,但端口在不一定是活的。

关于探活还要说的是方式的选择,通常不同的业务要求也不一样,检查端口是否存在,尝试建立一次连接,请求一次健康检查接口等等,这块nacos做的比较好,可根据需求扩展探活方式,也内置了很多探活方式。

路由功能

此项不是必选,但有了就会很强。

比如很多公司都有多套环境,如开发、测试,预发,线上环境,通常开发和测试的环境是单独部署,但线上和预发就不一定会单独部署。试想没有路由能力的注册中心,如果想线上只调用线上,预发只调用预发时,是不是必须得部署两套注册中心(以zk为例)。但如果给注册中心增加一个路由功能,线上consumer只消费线上provider,预发consumer只消费预发provider,那这样就只需要部署一套环境。

当然路由能力不仅限于此,还可以解决多机房就近调用问题,甚至可以完成很多更有想象力,更有意思的事情。

多机房支持

其实从上面的描述中已经发现,如果需要支持多机房,CP是更好的选择,最好能用路由能力解决多机房就近调用问题,假设有A、B两个机房,X服务只在A机房部署,Y服务在A、B机房都有部署,如果X调用Y,最好的选择是调用A机房的Y而不是更远的B机房。

多机房是部署一套注册中心,还是每个机房都部署一套注册中心?其实两种方案都可以,部署一套注册中心需要保证每个机房的服务注册都要请求这个注册中心,存储数据是一份,这样的问题是跨机房调用时延高,但如果是专线,这个问题也不是太大。如果每个机房都部署一个注册中心,就没有时延问题,但不可能每个机房都不需要感知其他机房的服务,这样就需要有数据同步的机制,数据同步就意味着注册与发现有时延,而且多中心的数据一致性保证比较复杂。

如何做技术选型

如果选择开源产品,是否符合公司技术栈、能否cover住将是第一选择要点,例如使用dubbo,哪些注册中心对dubbo的支持比较友好?哪些注册中心是java技术栈?

其次是对注册中心特殊能力的需求,如业务在高速发展中,需要考虑下性能和水平扩展能力;如想在注册中心上做一些流量的控制,可以考虑选型的注册中心是否有路由能力;如想快速准确的摘除故障机器,那么需要考虑下注册中心的服务探活能力能否满足需求;如有多机房建设的需求,需要考虑注册中心对多机房的支持是否友好,是否支持“就近调用”等特性。

当然开源产品各有千秋,常见的像zookeeper、nacos、eureka、consul等,大厂遇到的场景通常比较复杂,一般会定制自己的注册中心,如蚂蚁的sofa-registry、饿了么的Huskar、美团的MNS、有赞的Haunt。

这里介绍下zk和nacos来作为结尾。

zookeeper

zk是在dubbo中使用最多的注册中心,但它本身不是为了服务发现而生。

它是一个基于ZAB协议实现的可靠的分布式协调系统,它是强一致(CP)、使用基于TCP的私有协议通信。由于ZAB协议中写入是只能由主节点发起,所以写入只能是在单机上完成,故水平扩展困难,也不支持多机房、路由管理等功能。

zk中的数据类似文件系统的树形结构,节点分为两种,一种是临时节点,一种是永久节点,临时节点不可保存数据,永久节点可以保存数据,临时节点在服务端与客户端的长连接断开后一段时间会被摘除。

一句话总结:dubbo的第一选择,中小企业适用

nacos

nacos是阿里开源的注册中心&配置中心,作为注册中心它使用的是自研的distro协议,一种AP的协议,具体可以看之前的文章《nacos的一致性协议distro介绍》

目前可以使用http和dns协议来访问nacos,未来可能可以通过grpc来访问,可以水平扩展,但目前的性能不高,未来实现长连接后会有所改善,多机房可以通过扩展其CMDB模块来实现,支持权重、保护阈值等负载均衡策略。

社区也提供了nacosSync工具来迁移其他注册中心到nacos注册中心,有关迁移实践可以查看这篇文章《zookeeper到nacos的迁移实践 》

一句话总结:特性比zk丰富,但开源不久,稳定性、性能不够。

参考


搜索关注微信公众号"捉虫大师",后端技术分享,架构设计、性能优化、源码阅读、问题排查、踩坑实践。

当我们谈注册中心时我们谈什么

收藏
评论区

相关推荐

男生学软件开发和女生学软件开发会不会有很大差距?
对于这个问题,我想从教育背景、思维模式、职场现状来谈谈我的观点。 首先说下我个人的看法,我觉得做软件研发和程序员这一职位,都是想法设法通过技术手段进行设计、编码,最终解决问题。那么从这种纸面意义上来说,男女之间学习软件开发不应该会在性别因素上存在很大差距,无非就是努力不努力,能不能投入大量时间钻研而已。 然而这只是纸面上。在开始论述之前,我想先说一句,如
Redis实现分布式锁
一、redis分布式锁的简易实现 用redis实现分布式锁是一个老生常谈的问题了。因为redis单条命令执行的原子性和高性能,当多个客户端执行setnx(相同key)时,最多只有一个获得成功。因此在对可用性要求不是特别高的场景下,redis分布式锁方案不失为一个性价比高的实现。 1. 多个客户端执行setnx lock
Node.js爬虫实战 - 爬你喜欢的
前言 今天没有什么前言,就是想分享些关于爬虫的技术,任性。来吧,各位客官,里边请... 开篇第一问:爬虫是什么嘞? 首先咱们说哈,爬虫不是“虫子”,姑凉们不要害怕。 爬虫 一种通过一定方式按照一定规则抓取数据的操作或方法。 开篇第二问:爬虫能做什么嘞? 来来来,谈谈需求 产品MM: 1. 爱豆的新电影上架了,整体电影评价如何呢? 2. 暗
如果进阿里前端,代码能力得达到什么程度?
笔者身边有很多在阿里不同部门的朋友, 也曾经被面试过阿里, 也面试过很多求职者, 这里笔者通过自身经验, 来谈谈如何面进大厂(比如阿里). 为了保证回答的逻辑性和堵有所获, 我将按照以下3点来谈前端如何才能进大厂(阿里): 阿里不同部门的技术和要求 大厂喜欢的求职者需求具备哪些能力和潜质 如何打造程序员的职场核心竞争力 首先像阿里, 字
深入不可变类 -- 谈谈Java String与包装类的底层实现
深入不可变类——谈谈String与包装类的底层实现 一、走进不可变类 不可变类是指在创建实例后该例变量不可以改变的类。 比如String类和包装类。 定义不可变类需要遵守: 1. 成员变量设置为priavte ,final修饰 2. 提供带参构造器对成员变量进行初始化 3. 只提供getter,
Android 面试官精心整理:"五年面试经验
作者:面试官首先呢!做为一个面试官,这几年面过的中高级 Android 开发工程师已经突破了上百人,Failed 的不敢说,但是 Pass 掉的基本是没有看走眼的;眼看年后春招即将来袭,特此赶在年轻整理完毕,谈谈我对 Android 中高级面试的一些看法和体会。 如果,你有更好的看法,希望能在评论区留言,我们一起讨论。一般来说,大部分面试官在面
Vue面试考点准备02
10\. 谈谈你对keepalive的理解是什么? keepalive是Vue提供的一个抽象组件,用来对组件进行缓存,当组件切换时不会进行销毁,从而节省性能。由于是一个抽象组件,所以在页面渲染完毕后不会被渲染成一个DOM元素。1)include定义缓存白名单,keepalive会缓存命中的组件;2)exclude定义缓存黑名单
浅谈Vue3新特性
Vue3的已发布一段时间了,新的Vue3在语法以及底层都进行了全新的重构,带来了更快的运行速度,更小的构建包,更友好的编程规范,让我们来看看有哪些变化吧。更快传统的虚拟dom算法:组件patch的时候,需要重新创建整个vdom树,然后遍历整棵树进行diff,update...更快的虚拟dom算法,源自编译模板时给予更多的运行时提示:1. 编译模板时对动
浅谈Vue.js
作为一名Vue.js的忠实用户,我想有必要写点文章来歌颂这一门美好的语言了,我给它的总体评价是“简单却不失优雅,小巧而不乏大匠”,下面将围绕这句话给大家介绍Vue.js,希望能够激发你对Vue.js的兴趣。 注:本文介绍的是Vue1.×,目前Vue已经升级至2.×,功能和语法上有一定升级和修改,想了解2.×的请移步:Vue.js简介
浅谈JS中的递归
一、递归递归(英语:Recursion)在数学与计算机科学中,是指在函数的定义中使用函数自身的方法在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数其核心思想是把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解一般来说,递归需要有边界条件、递归前进阶段和递归返回阶段。当边界条件不满足时,递归前进;当边界条件满
【数据结构和算法:简单方法】谈一谈优先队列的实现
【系列文章推荐阅读】 首先回忆一下队列(详细内容移步至),只要记住八个字即可:先进先出(FIFO),后进后出(LILO)。 就像去医院门诊看病排队时一样:先来的先看,看完先走。而优先队列的特性正是“优先”二字,“优先”二字意味着打破了“常规”“规则”。优先队列不再遵守普通队列的先进先出的原则了,如何不遵守呢? 最大优先队列:不管入队顺序如何,
当我们谈注册中心时我们谈什么
本文已收录 https://github.com/lkxiaolou/lkxiaolou 欢迎star。最近工作重心转向了注册中心,于是想来写一篇关于注册中心的文章 概念什么是注册中心,以大多数人熟悉的RPC框架来说,通常RPC中有三种角色: provider 服务提供者 consumer 服务消费者,即调用方 registry 注册中心,让consumer
这些常见的坑,90%的程序猿都踩过,来看看里面有没有你的脚印?
在学习python的过程中,相信大家都有踩过不少的坑,有些坑可能踩了不止一次,感觉就像是在坑与坑之间反复横跳。那么如何避免这些坑呢?看完这篇文章,你就知道了。我们来谈谈我们学习python的过程中,最常见的七大坑:1. 缩进,符号和空格不正确写代码时大家会使用缩进、对齐、空格等,这些是为了提高代码的可读性在python语言中,缩进是十分重要的比如在创建一个新
面试官:谈谈你对geohash的理解和如何实现附近人功能呢?
前言小伙们好,我是阿沐!一个喜欢通过实际项目实践来分享技术点的程序员!你们有没有遇到被面试官嘲讽的场景;之前有位刚毕业的小学弟在上海魔都某某某大公司面试,二面主要是问了关于redis的相关知识点,回答的也是磕磕绊绊的,其中一个问题是如何实现搜索附近人加好友功能;想跟大家一起分享、一起探讨下。如果有不正确的地方,欢迎指正批评,共同进步 面试官的主要考点 考点一
反爬虫策略手把手教你使用FastAPI来限制接口的访问速率
在网络爬虫的过程中,我们都会遇到各种各样的反爬虫,封禁IP和账号,设置验证码,前端加密,浏览器指纹,甚至输出假数据来等等都是可能出现的反爬手段,这些我们今天一个也不会谈及,而是谈谈一种叫访问速率限制的手段。 对于服务端而言,有时候会碰到这么一个场景:某个接口需要在某个时间段内设置最高的访问次数来降低服务器的压力,比如之前用的某度的一些接口,一分钟内访问