• 高并发系统设计(十九)【注册中心】:微服务架构结合RPC框架如何做到分布式系统寻址?


    通过RPC框架,能够解决服务之间,跨网络通信的问题,这就完成了微服务化改造的基础。
    但是在服务拆分之后,需要维护更多的细粒度的服务,面对的第一个问题就是,如何让RPC客户端知道服务端部署的地址,服务注册与发现的问题。

    你所知道的服务发现
    服务注册和发现不是一个新的概念,比如说,Nginx是一个反向代理组件,那么Nginx需要知道,应用服务器的地址是什么,这样才能够将流量透传到应用服务器上,这就是服务发现的过程。

    那么Nginx是怎么实现的呢?它是把应用服务器的地址配置在了文件中。
    这固然是一种解决的思路,实际上,RPC服务端的地址,就是配置在了客户端的代码中,不过,这样做之后出现了几个问题:

    • 首先在紧急扩容的时候,就需要修改客户端配置后,重启所有的客户端进程,操作时间比较长;
    • 其次,一旦某一个服务器出现故障时,也需要修改所有客户端配置后重启,无法快速修复,更无法做到自动恢复;
    • 最后,RPC服务端上线无法做到提前摘除流量,这样在重启服务端的时候,客户端发往被重启服务端的请求还没有返回,会造成慢请求甚至请求失败。

    因此,考虑使用注册中心来解决这些问题
    目前业界有很多可供你来选择的注册中心组件,比如说老派的ZooKeeper,Kubernetes使用的ETCD,阿里的微服务注册中心Nacos,Spring Cloud的Eureka等等。
    这些注册中心的基本功能有两点:

    • 其一是提供了服务地址的存储;
    • 其二是当存储内容发生变化时,可以将变更的内容推送给客户端。

    第二个功能是使用注册中心的主要原因。因为无论是需要紧急扩容,还是在服务器发生故障时,需要快速摘除节点,都不用重启服务器就可以实现了。使用了注册中心组件之后,RPC的通信过程就变成了下面这个样子:

    从图中可以看到一个完整的,服务注册和发现的过程:

    • 客户端会与注册中心建立连接,并且告诉注册中心,它对哪一组服务感兴趣;
    • 服务端向注册中心注册服务后,注册中心会将最新的服务注册信息通知给客户端;
    • 客户端拿到服务端的地址之后就可以向服务端发起调用请求了。

    从这个过程中可以看出,有了注册中心之后,服务节点的增加和减少对于客户端就是透明的。这样,除了可以实现不重启客户端,就能动态地变更服务节点以外,还可以实现优雅关闭的功能。

    优雅关闭是你在系统研发过程中,必须要考虑的问题。因为如果暴力地停止服务,那么已经发送给服务端的请求,来不及处理服务就被杀掉了,就会造成这部分请求失败,服务就会有波动。所以,服务在退出的时候,都需要先停掉流量,再停止服务,这样服务的关闭才会更平滑,比如说,消息队列处理器就是要将所有,已经从消息队列中读出的消息,处理完之后才能退出。

    对于RPC服务来说,可以先将RPC服务从注册中心的服务列表中删除掉,然后观察RPC服务端没有流量之后,再将服务端停掉。有了优雅关闭,RPC服务端再重启的时候,会减少对客户端的影响。
    在这个过程中,服务的上线和下线是由服务端主动向注册中心注册、和取消注册来实现的,这在正常的流程中是没有问题的。但如果某一个服务端意外故障,比如说机器掉电,网络不通等情况,服务端就没有办法向注册中心通信,将自己从服务列表中删除,那么客户端也就不会得到通知,它就会继续向一个故障的服务端发起请求,也就会有错误发生了。那这种情况如何来避免呢?其实,这种情况是一个服务状态管理的问题。

    服务状态管理如何来做
    针对上面我提到的问题,一般会有两种解决思路。
    第一种思路是主动探测,方法是这样的:
    RPC服务要打开一个端口,然后由注册中心每隔一段时间(比如30秒)探测这些端口是否可用,如果可用就认为服务仍然是正常的,否则就可以认为服务不可用,那么注册中心就可以把服务从列表里面删除了。

    微博早期的注册中心就是采用这种方式,但是后面出现的两个问题,不得不对它做改造。
    第一个问题是:所有的RPC服务端都需要,开放一个统一的端口给注册中心探测,那时候还没有容器化,一台物理机上会混合部署很多的服务,需要开放的端口很可能已经被占用,这样会造成RPC服务启动失败。
    还有一个问题是:如果RPC服务端部署的实例比较多,那么每次探测的成本也会比较高,探测的时间也比较长,这样当一个服务不可用时,可能会有一段时间的延迟,才会被注册中心探测到。
    因此,后面把它改造成了心跳模式。

    这也是大部分注册中心提供的,检测连接上来的RPC服务端是否存活的方式,比如Eureka、ZooKeeper,在我来看,这种心跳机制可以这样实现:
    注册中心为每一个连接上来的RPC服务节点,记录最近续约的时间,RPC服务节点在启动注册到注册中心后,就按照一定的时间间隔(比如30秒),向注册中心发送心跳包。注册中心在接受到心跳包之后,会更新这个节点的最近续约时间。然后,注册中心会启动一个定时器,定期检测当前时间和节点,最近续约时间的差值,如果达到一个阈值(比如说90秒),那么认为这个服务节点不可用。

    在实际的使用中,心跳机制相比主动探测的机制,适用范围更广,如果你的服务也需要检测是否存活,那么也可以考虑使用心跳机制来检测。

    注册中心增加保护的策略:如果摘除的节点占到了服务集群节点数的40%,就停止摘除服务节点,并且给服务的开发同学和,运维同学报警处理(这个阈值百分比可以调整,保证了一定的灵活性)。

     
  • 相关阅读:
    ASP.NET ZERO 学习 JTable的ChildTable用法
    ASP.NET ZERO Core Application 学习笔记
    uploadify ASP.net 使用笔记
    金额的加减乘除运算
    利用autoit自动关闭指定标题窗口
    Struts2源代码解读之Action调用
    利用btrace工具监控在线运行java程序
    自己实现的简单MVC框架(类似Struts2+Spring)
    简单实用后台任务执行框架(Struts2+Spring+AJAX前端web界面可以获取进度)
    mybatis源代码分析:mybatis延迟加载机制改进
  • 原文地址:https://www.cnblogs.com/yszr/p/14096236.html
Copyright © 2020-2023  润新知