(五):C++分布式实时应用框架——微服务架构的演进

C++分布式实时应用框架——微服务架构的演进

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

上一篇:(四):C++分布式实时应用框架——状态中心模块程序员

 

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

 

  OCS(online charging system,在线计费系统)在进行云化改造的过程当中,从实用主义角度出发,微服务架构并非咱们的目标。虽然咱们也对系统进行了容器化改造(Docker),并根据业务进程的功能将系统分红了好几类的容器,但这一切可能是出于对系统中的某些处理节点进行动态扩缩容的须要,跟微服务半点关系没有。随着系统改造 的深刻,系统的通信关系复杂程度开始超过咱们以前的估计。若是说数量众多的功能节点还有人能够勉强掌握,这些节点间错综复杂的通信关系连线已超过程序员能够驾驭的范畴。在讨论如何简化程序员实现整个系统各种节点的通信关系的配置过程当中,节点微服务化的理念渐渐进入咱们的脑海之中……架构

  下面先给你们介绍下咱们所面临的困境,下面的图是咱们系统一部分节点的通信关系总图(注意,只是其中一部分):框架

 

  还记得第二篇《基于ZeroMQ的实时通信平台》中那个咱们引觉得傲的通信配置文件吗,就是程序中全部的通信链接关系再也不是写死在代码中,而是经过AppInit.json配置文件进行配置,程序启动的时候再由CDRAF进行实时加载。当初酷炫的功能,如今却成咱们的恶梦。此时AppInit.json这个文件已到达1700多行,你没看错,一个配置文件1700多行,而且还不是所有,还会继续变大。
运维

 

"OLC" : {
      "AUTO_START" : "YES",
      "ENDPOINTS" : [
         {  // 用于与SmartMonitor创建心跳
            "name" : "MonitorSUB",   
            "zmq_socket_action" : "CONNECT",  // ZMQ的链接模式
            "zmq_socket_type" : "ZMQ_SUB"     // ZMQ的通信模式
         },
         { // 下发消息给OCDis,这边存在转发功能,支持业务实现按条件转发
            "downstream" : [ "OCDis2OLC"],
            "name" : "NE2OLC",                // 根据这个名字在业务代码中实现转发
            "zmq_socket_action" : "BIND",
            "zmq_socket_type" : "ZMQ_STREAM" 
         },
         { // OLC到OCDis的链路
            "name" : "OCDis2OLC",
            "statistics_on" : true,
            "zmq_socket_action" : "CONNECT",
            "zmq_socket_type" : "ZMQ_DEALER"
         },
         { // OCDis回OLC的链路,之因此来去分开,主要用于实现优雅启停功能(启停节点保证不丢消息)
            "name" : "OCDis2OLC_Backway",
            "statistics_on" : true,
            "zmq_socket_action" : "CONNECT",
            "zmq_socket_type" : "ZMQ_DEALER",
            "backway_pair" : "OCDis2OLC"
         },
         {  // 用于与SmartMonitor的命令消息链路
            "name" : "OLC2Monitor",
            "zmq_socket_action" : "CONNECT",
            "zmq_socket_type" : "ZMQ_DEALER"
         },
      ],
      "ENDPOINT_TO_MONITOR" : "OLC2Monitor",
      "INSTANCE_GROUP" : [
         {
            "instance_endpoints_address" : [
               {
                  "endpoint_name" : "NE2OLC",
                  "zmq_socket_address" : "tcp://*:6701"
               },
               {
                  "endpoint_name" : "OCDis2OLC",
                  "zmq_socket_address" : [
                     "tcp://127.0.0.1:7201"   // 跨机的IP地址与端口,配合状态中心可实现自动管理,无需人工参与配置
                  ]
               },
               {
                  "endpoint_name" : "OCDis2OLC_Backway",
                  "zmq_socket_address" : [
                     "tcp://127.0.0.1:7202"
                  ]
               },
               {
                  "endpoint_name" : "OLC2Monitor",
                  "zmq_socket_address" : "ipc://Monitor2Business_IPC"
               },
               {
                  "endpoint_name" : "MonitorSUB",
                  "zmq_socket_address" : "ipc://MonitorPUB"
               }
            ],
            "instance_group_name" : "1"
         }
      ]
   },

 

  一个业务程序员若是要调整系统中某个程序的通信链接,必定得盯着上面那副图研究半天,而且要搞明白“CONNECT”、“BIND"、”ZMQ_ROUTER"、“ZMQ_DEALER"等等这些zeromq专业词汇的含义,才可能进行准确配置,咱们隐隐感到这已经是一个mission impossible。如何简化这个配置文件,如何对系统的复杂度进行分层,让不一样层级的人员仅仅只需关注自身层级状况,再经过咱们的CDRAF最终将这些散落的配置、代码组成一个完成可运行的系统才是咱们如今亟需解决的问题。相信这也是每一个系统架构师所面临的问题,当一个系统的复杂度超过单我的可承受能力范围,就要对这个系统进行适当分层,分模块。让每一个人去管理一小部分复杂点,而且你们只需实现好本身的模块,无需去关心别的模块的实现细节。经过事先设计好的接口,各个模块能够相互协做,总体系统是能够依此完美地运行的。这里CDARF正是起这么一个不一样模块的桥梁(接口)的做用。socket

  1、节点间通信模式的统一

  原来节点内的应用程序都是通信全能应用程序,所谓全能是指应用程序既能够跟节点内的进程进行通信也能够跟节点外的任意进程进行通信。这样乍看起来没啥问题,但一旦节点数和进程数变多后,通信关系将是一个指数级增加的过程。以下图,若是再增长一个CDR节点,或者OCS节点,链接数都将增长很是多。tcp

  

  咱们的解决办法是统一节点的通信模式,每一个节点内都有一个Dis进程,统一对外负责跟其余节点进行通信。在收到外部发给节点的消息后,根据功能和负载转发给内部业务处理进程。业务进程若是有消息须要发往别的节点,就直接发给Dis进程,由它进行转发。统一通信模式带来的好处除了在节点和进程增多后,通信关系不会变得太复杂之外。因为模式统一, CDARF能够替业务程序员完成不少工做,直接的好处就是业务程序员再也不须要配置不少与业务无关的配置。最大化的将通信模块的复杂度留给CDRAF去处理,业务程序员将更加专一于自身的业务逻辑。下面的图中其实系统开始已经有微服务的样子,但咱们但愿作到的不只是从系统架构上是微服务架构,在程序员开发程序的时候,也应该是带着微服务思惟的,咱们的CDRAF应该提供这么一种能力来支持这种开发模式。分布式

  

 

  2、配置文件的简化

  通信模式统一后,咱们对通信配置文件进行了一次较大的简化,从原来1700行减小到了200行左右。这当中省去了不少冗余的配置项,通信配置文件再也不是对系统通信简单直接的对应,而更多的是对节点通信能力的一种表述。微服务

  应用程序分为Dis和非Dis两类,Dis类程序主要承担节点间的通信和节点内的消息转发,非Dis类程序就是普通的业务处理进程。从下面的文件中能够看到“OCDis”进程中分为“InterContainerEndpoints”和“InnerContainerEndpoints”两大类,分别表示节点间的通信和节点内的通信。对于节点间的通信,每一个服务端口只要写上相应的“服务名字”就能够以了,配置中的“OCDisCDRDis”表示OCSDis与CDRDis的通信,“OLCDisOLCProxy”、“OCDis_SyDis_SNR”也是相似。当业务侧程序须要对外提供一个服务(或者说与外部进行通信),只须要写一个服务名字,而如:端口、机器的IP地址、服务端仍是客户端、通信模式等等都彻底不须要去关心,这是多大一种便利。配置中的注释部分是不须要业务程序员去填的,而是由CDRAF的状态中心,根据集群节点的实时状况自动生成,并进行链接和维护。

  

{
  "OCDis": {
    "MaxInstanceGroupNum": 3,
    "InterContainerEndpoints": 
    {
      "OCDisCDRDis": 
      {
        //"Port": [6001, 6002, 6003],
        //"Cluster": ["10.45.4.10:6001", "10.45.4.10:6001"]
      },

      "OCDisOLCProxy": 
      {
        //"Port": [6101, 6102, 6103],
        "DownStreams": ["OCDis2IN", "OCDis2PS", "OCDis2SMS", "OCDis2ISMP", "OCDis2IMS"],
        "router": true
      },
      "OCDis_SyDis_SNR": 
      { 
          //"Peer": "ZSmartSyDis.OCDis_SyDis_SNR" 
      }
    },

    "InnerContainerEndpoints": 
    {
      "OCPro_OCDis_CDR": { "DownStreams": ["OCDisCDRDis"] },
      "OCPro_OCDis_SNR": { "DownStreams": ["OCDis_SyDis_SNR"] },
    }
  },

  "OCPro": {
    "Groups": ["IN", "PS", "SMS", "IMS", "ISMP"],
    "InnerContainerEndpoints": {
      "OCPro2OCDis": {
        "PeerMap": [
          "OCDis.OCDis2IN",
          "OCDis.OCDis2PS",
          "OCDis.OCDis2SMS",
          "OCDis.OCDis2ISMP",
          "OCDis.OCDis2IMS"
        ]
      },
      "OCPro_OCDis_SNR": {"Peer": "OCDis.OCPro_OCDis_SNR"},
      "OCPro_OCDis_CDR": {"Peer": "OCDis"}
    }
  },

  "CDRDis": {
    "InterContainerEndpoints": 
    {
      "OCDisCDRDis" : 
      {
        "DownStreams": ["CDRDisCDR"],
        //"Peer": "OCDis"
      }
    }
  },

  "CDR": {
    "InnerContainerEndpoints": 
    {
      "CDRDisCDR" : {"Peer": "CDRDis"}
    }
  }
}

  想像一下,对于每个业务节点,开发人员仅需考虑节点内的业务实现逻辑,并为本节点对外所提供的服务起个名字,而再也不须要关心这个服务究竟是提供给谁,更不用操心谁会来连个人进程,怎么连。这是多么精妙的事情!咱们不只是从架构上作到了微服务架构,程序员在开发业务程序的时候,不须要去关心除了自身模块之外的其它复杂信息,今后能够轻装上阵,而再也不须要负重前行。这应该就是CDRAF对微服务架构提供的最直接、最好的支持了,帮助业务程序员从传统的开发模式转变,进而适应微服务的思惟方式。

 

  3、节点间的通信关系配置

  上面咱们提到配置文件只定义了节点的服务名,那么这么多的微服务节点是如何组合起来工做的?一个业务应用系统会由许多的微服务一块儿协同提供服务,这些服务对于每一个不一样的现场可能功能是不同的,或者说微服务集合是不同的。那么,对这些微服务的组合的过程就像一个“编排”的过程。经过“编排”,选择合适的微服务进行搭配组合提供服务,而编排的过程就是咱们通信创建的过程。下面咱们就来看一下CDRAF是如何作到“编排”功能的。

  

  上面的第一张表,描述了全部的微服务列表,全部节点服务要向外通信都必须到这张表中增长相应的服务名,这里的服务名是与前面配置文件中的服务名相对应的。第二张表描述了这些微服务名之间的通信关系,好比第二条记录表达的是OCDis程序的OCDis2CDRDis到CDRDis的OCDis2CDRDis之间会有一个通信关系。只要经过这个简单的配置,就能够完成两个节点间的通信关系的创建。这样的设计会带来几个好处。

  一、对于一个复杂的系统,可能有几十类微服务节点,运行实例可能有上百个,若是有上面的表二,就能够容器的从上面的数据中画出整个集群的实时拓扑图,这个对于系统的监控是十分重要的。

  二、集群通信关系的设计上升了一个等级,业务程序员只须要根据模块接口设计提供相应的微服务节点,而不须要关心与其它微服务是如何协调工做的。而这些微服务如何“编排”提高到了架构师的工做范围的层级。这显然是对复杂度进行分层隔离很好的一个范例。

  三、运维或者管理人员,经过表二的配置能够很容易地操做集群里的某个微服务下线或者上线。在一个庞大的集群里面,若是某类微服务出故障,而CDARF提供了这么一种手段能够去让这类故障微服务下线,将给系统的稳定性带来极大的可靠保证。

  4.、原来集群全部的通信都配置在一个文件中,在分布式系统中就涉及文件的全局一致性的问题。解决的方案多是,若是要上线一个新类型的配置文件(新增节点、删除节点、通信关系改变等等),就要去更新全部在网节点的配置文件。但此时若是新的配置文件有bug,那么可能致使整个集群的故障,而且为了升级某个功能去升级整个集群全部节点的配置也是极不合理的。在新的方案中,节点的配置只定义节点内的通信和对外提供的微服务名。那么若是要新增某种类型的微服务,再也不须要去更新其它节点的配置,只须要将新节点上线,而后在上面的表一新增微服务名,表二增长链接关系就能够了。真正作到了增量升级!

 

  未完待续……

相关文章
相关标签/搜索