程序员修神之路--它可能是分布式系统中最重要的枢纽

灵魂拷问

  • 分布式系统为什么需要注册中心呢?

  • 分布式系统注册中心有哪些坑?

  • 分布式系统注册中心怎么来实现呢?

  • 注册中心利用现成的组件很好实现吗?

看到标题你可能会鄙视一下,注册中心有是什么讲的。注册中心作为现在架构中的一个组件来说,确实很常见。微服务作为分布式系统最典型的一种表现形式,是最近几年最流行的概念之一。每个讲微服务的文章中或多或少都会提及注册中心,但也只是一带而过,注册中心作为分布式系统或者微服务架构中最重要的一环,我觉得有必要写一篇单独的文章来详细的介绍一下,这也是有这篇文章的原因。

分布式系统的痛点

注册中心从架构的角度来讲,其实是一个统称的概念,并非现在流行的微服务所有,在很早之前利用Nginx做负载均衡(反向代理)的时候,Nginx会根据配置文件把每个请求根据配置的策略导向后端具体的处理程序,在这个流程中,站在客户端角度,Nginx很像一个网关,站在后端处理程序的角度,Nginx更像是服务的管理中心,它管理着所有可以提供服务的后端处理程序信息,并且还可以利用某些手段来达到服务的健康检查,服务的自动注册和剔除等操作。

当然现在流行微服务,网关和注册中心被分为两个并行的概念和组件。在重要性上来说,我觉得注册中心的权重要大于网关。现在十分流行单体服务拆分操作,但是这里我要强调一点,你的单体服务是否有必要拆分,还要根据很多情况来综合考虑,毕竟拆分成小的微服务并非没有代价。

在很早之前,如果客户端需要请求后端的多个服务,很多情况下后端的服务信息是写在请求方的配置文件中的,类似于这样

{"ServiceA":["http://192.168.100.100","http://192.168.100.101","http://192.168.100.102"]
}

这种方式固然是一种解决方案,但是随着系统的不断升级会遇到很多问题:

  • 在系统需要扩容后端服务器的时候,需要手动修改客户端的配置文件,而且在多数情况下还需要重启客户端进程

  • 当后端的一个服务节点出现故障的时候,需要手动删除客户端配置文件中对应的节点,而且在多数情况下还需要重启客户端进程

  • 每次增加或者删除节点的时候需要人工干预,大大提高了维护成本

鉴于以上几个原因,注册中心应运而生。

注册中心的作用

注册中心不仅仅解决了服务节点的增加删除问题,而且在整个的查找服务可用节点的流程上做了修改,在搭配了服务健康检查的手段之后,更可以做到自动化。目前业界有很多可供选择的注册中心,比如ZooKeeper,ETCD,阿里的微服务注册中心 Nacos、Spring Cloud 的 Eureka 等等,之前菜菜的文章就有写过利用ETCD来实现一个配置中心

为微服务撸一个简约而不简单的配置中心

服务注册发现

服务的注册发现是注册中心提供的最基础也是最主要的功能:

  • 当一个新的服务节点上线的时候,可以通过注册中心的接口进行注册,当一个服务节点发生故障的时候,注册中心会自动删除该服务节点

  • 当注册中心的服务节点发生变化的时候,能够及时通知调用方,服务的调用方可以近乎实时的来更新可用的服务节点信息

image
负载均衡

当客户端在注册中心获取到可用的服务节点之后,就可以根据轮训或者权重等策略来访问服务了,这种场景下注册中心更像一个负载均衡器,把流量导向多个不同的节点。

既然是负载均衡,在某种意义上讲就可以实现服务的横向扩展,说实话这确实没有什么问题,道理和Nginx做负载均衡道理类似。



那些坑

服务中心虽然在整体架构模式上解决了很多问题,但是在使用中我们也要直面它所带来的一些副作用,而且这些副作用有时候会成为整个系统瘫痪的导火线。

数据一致性问题

数据的一致性好像是所有系统都要面对的问题,注册中心也不例外。这里的一致性是指注册中心内存储的可用节点数据和后端真实可用节点以及客户端存储的可用节点之间的差异性问题。举个栗子:假如注册中心中存储了ABC三个服务节点信息,而这个时候节点A由于某种原因下线了,注册中心必须要及时把A节点移除掉,并且通知客户端也把A节点移除。

从理论上来讲,以上过程跨越了注册中心和调用方以及被调用方的交互流程,属于分布式中的事务问题,即:分布式事务问题。在之前菜菜的文章中也说过,分布式的事务要想保证严格的一致性必然会影响可用性

分布式下,我想要一致性

那些分布式事务解决方案

而且从目前主流的注册中心技术来看,注册中心和双方的通信流程属于异步流程,所以做不到实时的事务性要求。

目前注册中心在通知客户端变化的方面可以做到近乎于实时(其实并非实时),但是在监测后端服务节点是否可用的过程中,却很难做到近乎实时。其中的原因一是因为网络的不可靠特性,一次网络通信失败,并非意味着下次网络通信失败,二是监测后端服务可用的方式并非实时的。目前流行的两种探测后端服务可用的方式为:

注册中心主动探测

很多注册中心的组件都支持这种方式,在这种方式下,后端的每个服务需要提供一个可供探测的接口或者端口,注册中心根据配置每隔一段时间去调用一次服务的接口或端口,如果返回正常就认为服务处于正常运行状态,否则则认为服务不可用,不可用的情况下注册中心会主动把当前服务移除列表,并通知客户端。


虽然这种方式看似很完美,其实还是有坑:

  • 注册中心在探测的过程中,可能会由于网络问题而出错,但是服务其实是在正常运行状态,也就是说会产生误判的结果,当然这种问题,我们可以设置通过多次探测结果来确定,而不是通过一次探测结果就草草确定。

  • 如果服务节点比较多,注册中心相当于承受了比较重的探测任务,会对注册中心的性能造成一定损失,影响它的可用性。

  • 如果服务是以端口的形式开放探测接口,在服务较多的情况下可能会产生端口抢占的情况,毕竟这些服务可能会是不同团队开发的。

后端服务主动心跳

相比较注册中心主动探测的模式,我更喜欢使用服务主动上报心跳的模式。采用心跳的模式大体流程是这样的:

  • 后端的每个服务节点都按照配置(这个配置可以修改)每隔固定时间就主动向注册中心发送心跳包,至于心跳包的内容可以协商约定,比如有的系统只发送ping命令,有的会发送比较详细的服务状态,比如cpu使用率,内存使用率等信息,然后注册中心就可以根据这些信息来做更精确的流量分配工作,比如,可以让资源充沛的服务节点承担更多的流量。

  • 注册中心在接收到服务节点的心跳包之后,可以以滑动窗口的形式给服务节点续约时间(存活时间),只要服务节点不停的发送心跳包,注册中心就可以判定这个节点一直在正常运行。

image

当然这个流程中也会有意外情况发生,比如由于网络情况,某个服务节点上报心跳失败,但是服务是在正常运行的,这种场景下,最直接的解决方案是:注册中心判断服务存活的时间窗口大于上报时间间隔即可,比如:心跳上报时间是10秒的话,注册中心判定服务不可用的时间窗口设置为30秒,既:三次心跳时间都没有上报心跳,就判定服务不可用。

当然以上只是注册中心的一个假设而已,其实系统可以结合主动探测的方式来判定服务是否可用,这样的话,结果的正确率会更高。也就是说:当服务的某个节点,超过配置的N次心跳时间仍然没有上报心跳数据,注册中心可以通过主动探测的方式来再次确定服务是否处于正常运行状态,当然,这在设计上增加了一定的复杂度,需要编写更多的代码。

还有一个不太常见的但是我们需要考虑的场景,假如所有的服务节点都因为网络异常情况而发生心跳上报超时,而且主动探测失败的情况,按照约定,注册中心会逐步移除所有的节点信息,这样造成的后果是系统肯定会出问题,有的时候系统设计的同时可以考虑一些保护措施,比如:当节点信息移除的数目大于一定比率的时候,就停止移除操作并且发送报警信息,这在一定程度上可以避免注册中心无节点数据的情况发生,当然客户端也可以有这样的保护策略。

通知风暴

虽然这个问题在多数情况下不算是个问题,但是还是有必要提及一下。当注册中心随着项目的升级承担起越来越多的服务节点的时候,服务间的调用链复杂度也随之上升,伴随而来的是新增一个节点可能要通知数十个客户端,移除一个节点也会有类似情况发生,如果有多个服务同时发生新增或移除节点操作,注册中心推送的消息将会更多。这样的场景下就需要系统设计者控制注册中心服务节点的数量来避免产生网络风暴,这个数量具体多少可以根据服务器的峰值带宽来确定。

更多精彩文章

  • ????分布式大并发系列

  • ????架构设计系列

  • ????趣学算法和数据结构系列

  • ????设计模式系列

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/307407.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用Java刷算法题的常用数据结构(C++转Java)

文章目录一:前言1:为何刷题从C转java2:如何上手呢?二:输入1:常规的输入2:关于其他输入符在nextLine()之前用吃掉回车符的问题解决3:常见输入之我们输入一串数到容器中三:常用的数据结构1:数组2.List3:Map4:Set5.栈6:队列一:前言 1:为何刷题从C转java 平时除了写项…

Magicodes.IE 2.4发布

今天我们发布了2.4版本,这离不开大家对Magicodes.IE的支持,我们也对大家的意见以及需求不断的进行更新迭代,目前我们的发布频率平均在一周一个beta版本,一个月一个正式版本的更新,我们欢迎更多的开发者加入进来&#x…

7-1 简单词法分析

一:题目 二:思路 思路: 1.记得看书;不要一上来就莽;不然莽不过去的 2.这里我从书中了解到 f(0,b) 0; f(0,a) 1;f(1,c)1;f(1,b)3… 那么的话我们只要最终推导出f(1,b)3;那么的话就是一个满足要求的字符串; 注意我们入口部分一定是从 0 开始; 3.接下来就是要判断一些细枝末节 …

Java 生态碎片化 和 .NET生态的一致性

.NET Core是以MIT协议开源, Java是GPL协议开源。Java 8 SDK升级Oracle要收费这件事对于很多小公司是有着重大的影响的,Java生态越发碎片化,有众多的OpenJDK发行版,腾讯云和阿里都有OpenJDK发行版,龙芯也有MIPS版本的Op…

Power Automate Desktop概览

点击蓝字关注我们Microsoft Power Automate使得通过自动化重复性、耗时的任务来提高您的业务效率成为可能。Power Automate提供了一种更好的方法,通过数字和机器人过程自动化(RPA)在整个组织中完成任务。Microsoft Ignite 在线活动小伙伴们都有参加么?重…

超600人!近5小时直播!录屏+彩蛋+PPT…你要的都在这!

2020年9月26日下午,《NCF框架揭秘》直播交流会圆满落幕!由盛派首席架构师苏震巍老师主持、分享,更有各路大咖,在线助力,干货满满!点击视频 ☝ 回顾直播现场友情提示:如果公众号内视频无法显示高…

leetcode226. 翻转二叉树(Java)

一:题目 二:上码(前序解法) /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left,…

Chrome正在启用HTTP/3,支持IETF QUIC

Chromium 官方宣布 Chrome 正在部署到 HTTP/3 与 IETF QUIC。QUIC(Quick UDP Internet Connections)是 Google 推出的一个项目,旨在降低基于 TCP 通讯的 Web 延迟。QUIC 非常类似 TCPTLSSPDY ,但是基于 UDP 实现的。它是 HTTP/3 的…

leetcode101. 对称二叉树

一:题目 二:上码 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …

诊断日志知多少 | DiagnosticSource 在.NET上的应用

1. 引言最近为了解决ABP集成CAP时无法通过拦截器启用工作单元的问题,从小伙伴那里学了一招。借助DiagnossticSource,可以最小改动完成需求。关于DiagnosticSource晓东大佬18年在文章 在 .NET Core 中使用 Diagnostics (Diagnostic Source) 记录跟踪信息就…

leetcode110. 平衡二叉树(java详解)

一:题目 二:上码 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …

IdentityServer4系列 | 常见术语说明

一、前言在上一篇中,我们IdentityServer4的说明,认识到是一个基于OpenID Connect协议标准的身份认证和授权程序,并简单的对基础知识的认识以及区别说明,从OAuth、OpenID、OpenID Connect以及JWT等进行对比区别说明。而在这一篇中&…

网易年薪40W架构师面试题,欢迎自测!

一个月前被拉进了一个微信群,名字叫《明日都是大佬》,群里有20多个人,都是正在跳槽的,目标是年薪30w!投简历、笔试、面试后都相互分享,互通有无你懂的。拉我进群是帮忙解答一些难题,很多题目还是…

leetcode257. 二叉树的所有路径(java递归详解)

一:题目 二:上码 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …

leetcode617. 合并二叉树

一:题目 二:上码 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …

跟我一起学.NetCore之熟悉的接口权限验证不能少(Jwt)

前言权限管控对于一个系统来说是非常重要的,最熟悉不过的是菜单权限和数据权限,上一节通过Jwt实现了认证,接下来用它实现接口权限的验证,为什么不是菜单权限呢?对于前后端分离而言,称其为接口权限感觉比较符…

.NET 云原生架构师训练营(模块一 架构师与云原生)--学习笔记

目录什么是软件架构软件架构的基本思路单体向分布式演进、云原生、技术中台1.1 什么是软件架构1.1.1 什么是架构?Software architecture {Elements, Forms, Rationale/Constraints}元素、形式/模式、基本原理和限制为什么需要软件架构?软件架构的终极目…

leetcode530. 二叉搜索树的最小绝对差

一:题目 二:上码 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …

再分享 5 个 vs 调试技巧

前言 之前在《5 个非常实用的 vs 调试技巧》和《继续分享 5 个实用的 vs 调试技巧》中分享了 10 个我认为非常值得了解的 vs 调试技巧,本周继续分享 5 个很实用的调试技巧。1. 显示下一条语句 在调试时,遇到断点中断后,为了更加清楚的了解程…

leetcode501. 二叉搜索树中的众数

一:题目 二:上码 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …