(五):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,那麼可能致使整個集羣的故障,而且爲了升級某個功能去升級整個集羣全部節點的配置也是極不合理的。在新的方案中,節點的配置只定義節點內的通信和對外提供的微服務名。那麼若是要新增某種類型的微服務,再也不須要去更新其它節點的配置,只須要將新節點上線,而後在上面的表一新增微服務名,表二增長鏈接關係就能夠了。真正作到了增量升級!

 

  未完待續……

相關文章
相關標籤/搜索