(四):C++分布式框架——状态中心模块

时间:2023-03-09 08:23:13
(四):C++分布式框架——状态中心模块

(四):C++分布式框架——状态中心模块

上篇:(三):C++分布式实时应用框架——系统管理模块

技术交流合作QQ群:436466587 欢迎讨论交流

版权声明:本文版权及所用技术归属smartguys团队所有,对于抄袭,非经同意转载等行为保留法律追究的权利!

  状态中心实现了分布式系统中计算节点的管理功能。完善的节点属性数据管理,业务进程间的连接关系管理,以及通过可靠的事件机制根据各节点上的相关模块反馈回的数据实时的对系统进行运行时动态调整管理。在分布式系统中还不得不进行系统的容错处理。状态中心解决了系统因各方面原因而产生的节点失联故障。通过内置独立模块解决了分布式间同步和数据一致性问题。为业务提供了高可用,高可靠的分布式系统节点管理解决方案。

  一、状态中心与数据结构

  1.1 组成部件 
  状态中心主要由两个模块组成。其中一个模块是运行于分布式系统各个节点上的代理进程agent,agent主要负责设置各个计算节点的连接关系,以及实时的收集每个节点运行状态数据并将数据上报给dsc模块。另外每个节点上的agent还要实时监控来自于dsc的消息,每个有效消息都对应一个事件,收到事件消息后,agent回调用户设置好的事件处理函数,完成各类被动操作。另一个模块则是由多台服务器组成的集群中心,在这里为了方便描述将此集群中心称为dsc\footnote{dsc:全称为Distributed status center}。dsc具备的功能有:存储分布式系统各节点的属性数据以及运行时实系统实时状态数据;具备分布式系统高可用,高可靠性保证;分布式同步等功能。

  1.2 事件机制
  agent进程初始化时,做的另一个比较有意义的工作是把来自dsc的事件消息处理函数进行注册。使得agent进入事件循环后接收到dsc的事件消息时能正确的找到所接收到消息所对应的处理函数。在进行设计时,考虑到分布式系统的复杂性,以及功能的多样性。将事件消息处理模块设计为职责链模式,链上的每个节点都应于CDRAF的某一功能。采用这样的设计,极大了方便了CDRAF功能的扩展,在研发CDRAF过程中加入新的功能时,只要定义相关的消息,再写好对应此消息的处理代码即可。所以状态中心事件通知功能,是整个状态中心功能的基石,其贯穿了状态中心的各个功能模块。如:当某个计算节点运行状态发生变化,状态中心中对应于该节点status数据即会发生变化,此时状态中心向关心此事件的状态代理agent进程发出一个状态改变的事件通知消息,消息中携带了status数据变化节点的主机名以及事件类型信息,以供状态代理agent进程获取进行相关处理操作。

  1.3 状态上报
  系统中计算节点启动时,由运行在此节点上的agent进程主动向dsc模块上报本节点的属性数据,这些数据有:节点的IP,对外提供各类服务所对应的端口号,节点的业务类型,主机名(设置于环境变量),业务的运行状态即用户的业务进程是否就绪可以对外提供服务,当前节点的计算能力如cpu性能数据以及内存性能数据等这一系列用来描述当前计算节点的数据。当agent获取到这些数据后,将会上传到dsc中,交由dsc进行保存。在系统运行过程中agent将周期性的计算上述数据列中部分数据用以更新dsc中所保存的数据。以实现将当前节点的实时状态数据展示给关心的模块。

  1.4 服务发现
  对于一个分布式系统而言,系统中的节点数一般是可变的,而且不同一的节点可能对外开放的端口也是可以发生变化的。按传统的做法,为每个服务访问者配置服务地址列表到本地已不再可行。目前docker容器部署技术的火热发展,很多企业的业务应用正在向docker部署转移,已不再是部署在物理机或是虚拟机上。而我们知道docker容器在启动前IP是未知的。基于这一系列的分布式系统特点,为CDRAF提供一个节点运行时服务注册中心与发现功能就成了一个必须要实现的功能了。状态中心dsc模块所具有的内部存储功能,很好的解决了这一问题。外部节点可以方便的从dsc模块中取出其所关心的服务地址,根据节点的类型数据以及服务节点的性能数据,服务请求节点可以方便,透明的实现动态负载均衡。以后对故障节点进行容错处理。

  

  1.5 容错机制
  CDRAF中对于每个节点的健康状态进行了管理,节点与状态中心间通过心跳消息进行健康通知。如果因为主机故障或网络等未原因,节点在一个时间间隔内没有主动上报健康状态,状态中心将把自己内部所存储的该节点状态描述字段数据设置为失活,并向外界关心该节点的其它节点发送失活事件消息。其它节点在收到消息后即将消息中标记的该失活节点所自己的业务链中移出。如果业务链中没有该失活节点的其它同类型节点,那么状态中心将向用户发出故障告警,请求向系统中添加新的处理节点,或处理故障节点。并将该业务链标记为不可用状态。但如果系统中还有该失活节点的同类业务节点,那么状态中心即把失活节点移出系统,并调整节点间的连接关系。保障业务数据的正确处理,不会造成业务消息仍发送给故障节点,最终使得业务出错。

  二、状态中心与框架功能实现

  2.1过载保护与流量控制
  在这里首先应该说明一下,什么是过载保护与流量控制。
所谓过载保护,就是当分布式系统中的某个计算节点消息处理队列中的消息积压到一定程序,cpu或内存使用到一定程序,使得后续到达的消息得不到此计算节点的及时处理。因此造成消息处理响应性能急剧下降。这在一些实时应用中是不能容忍的。所以有必要对各个计算节点进行监控,保证所到达的消息都能够及时的被处理。综上所述,流量控制,就很好理解了。做过载保护的一个比较简单的方案,就是当某计算节点消息队列里的消息数量积压达到某个阀值,亦或是某节点响应消息的时延变长。那么就可以通过减少向此节点发送消息数量,以达到目的。也就是说在这里的流量控制,就是控制到达某个计算节点的消息的数量。在这里熟悉分布式系统或做过集群系统的人可能会有疑问:一般这类系统中都会有动态负载均衡功能。消息或流量,可以分发给不同节点处理,为什么还要做过载保护以及所谓的流量控制呢?其实,只要清楚这些功能的具体定义,就能理解了。因为动态负载均衡只能保证所有流量能够按某一规则分发给一批计算节点。动态负载均衡并不关心节点是否能够处理得了这些流量。而过载保护与流量控制是针对各个节点而做的。是为了保证节点能够及时地,按要求处理好接收到的消息。尤其是对处理时延或响应要求较高的系统,比如电信这类对响应与时延要求苛刻的系统。说完了是什么,下面得讲讲怎么样了。是的,这两功能与状态中心有什么关系呢?状态中心在这个过程里做了什么?在上一节里,我们知道状态中心只是数据存储,以及实现一个事件机制。也就是说状态中心可以把系统状态数据以事件的形式发馈给相关模块,其是一个系统监控与通知的模块。并不能主动发起某类操作。在系统运行过过程中,各个节点实时周期性的向状态中心上报自己的运行时数据。与状态中心同层的系统管理模块,实时的关心着这些数据,如果出现上文所述的某节点过载状况,那么系统管理模块向状态中心中下发进行过载保护操作。状态中心将些消息实时的发送给各个分发数据节点上的agent代理进程。代理进程与通讯平台的通讯监控进程进行本地交互,通讯平台收到过载保护的消息,实时的改变消息分发的策略。以减少该过载节点所能接收到的消息数量。以做到釜底抽薪。

  在这里消息为什么要绕这么一大圈,这是因为在做设计时,考虑到要能让通讯平台能独立运行,并且只做通讯一件事而且能做好这件事。因为通讯本身就是一件很很复杂的事。对于CDRAF的通讯平台来说,只关心节点间的通讯,而节点间的组织关系,以及CDRAF众多的分布式系统功能则分在其它模块就实现。我们这样设计的目的是希望能实现模块间的代码上的解藕。每个模块能做好模块内的事。这样的设计为后期开发以及调试维护带来了很大的便利,以及方便TDD\footnote{TDD:Test Drived Design/Development}的使用。

  2.2优雅启停
  优雅启停功能主要是为了保证系统中某个节点主动退出(从网络中退出,或主动缩减节点)系统时,该节点消息队列里可能还有下在等待处理的消息。如果直接将连接断开,那将很有可能丢失一定数量的未处理消息。虽然某些系统可以接受这样的丢消息故障,只要分发节点在一定时长内没收到响应消息就重新发送丢失的消息即可。但是这样的处理,会对分发节点造成性能问题。所以在CDRAF是我们设计了“优雅启停”这一节点主动退网功能。当节点要进行退网时,状中心会接收到相关的操作命令,状态中心dsc模块将此命令转化成统一的事件,发送给相关的分发节点上的agent代理进程。代理进程收到事件消息后。通知本地的通讯平台的通讯监控程序。这时分了节点上的分发消息的进程将停止向将要退出网络的计算节点发送消息。并断开发送消息的连接。但是此时将要退出网络的计算节点仍在处理消息,并且处理结果通过分发节点的接收连接发送回去。也就是说,在这里关键是在分发节点与计算节点间建立两类网络连接链路。对于分发节点而言,一类链路用于发送消息,别一类链路用于接收消息。当计算节点处理完自己消息队列里所有消息时,计算节点断开剩开的连接。这样就实现了不丢消息的退网功能。此后此节点可以关闭自已,也可以继续做其它操作。

未完待续...