2. PhxPaxos分析之網(wǎng)絡(luò)基礎(chǔ)部件

目錄
1. PhxPaxos源碼分析之關(guān)于PhxPaxos
2. PhxPaxos分析之網(wǎng)絡(luò)基礎(chǔ)部件
3. PhxPaxos源碼分析之Proposer嫂拴、Acceptor
4. PhxPaxos源碼分析之Learner
5. PhxPaxos源碼分析之狀態(tài)機(jī)
6. PhxPaxos源碼分析之歸檔機(jī)制
7. PhxPaxos源碼分析之整體架構(gòu)


2.1 背景

Paxos 算法解決是一個(gè)分布式系統(tǒng)如何就某個(gè)值(決議)達(dá)成一致恩伺,因此網(wǎng)絡(luò)通信是該算法可正常運(yùn)行的基礎(chǔ)。

在Paxos中惫企,涉及網(wǎng)絡(luò)通信的角色包括:

  • Proposer:Paxos提案發(fā)起者。
  • Acceptor:Paxos提案接收者。
  • Learner:Paxos確定值的學(xué)習(xí)者。

除算法本身角色外智玻,PhxPaxos還設(shè)定了下述角色需要網(wǎng)絡(luò)通信:

  • Follower Node:Paxos集群的跟隨者。
    Follower指定一個(gè)運(yùn)行Paxos協(xié)議的節(jié)點(diǎn)用于數(shù)據(jù)同步芙代,它不參與Paxos算法吊奢。Follower更像傳統(tǒng)意義上的同步備,當(dāng)Paxos算法節(jié)點(diǎn)確定一個(gè)值后纹烹,將數(shù)據(jù)同步到Follower節(jié)點(diǎn)页滚。但若follow的節(jié)點(diǎn)無法同步數(shù)據(jù),F(xiàn)ollower可以向整個(gè)Paxos集群發(fā)起learn請求铺呵。
  • CheckpointMgr:鏡像數(shù)據(jù)管理者裹驰。
    指引業(yè)務(wù)生成鏡像數(shù)據(jù),一旦指定instance id之前的鏡像數(shù)據(jù)產(chǎn)生片挂,理論上就可以移除該instance id之前的Paxos Log數(shù)據(jù)幻林,以免空間的無限擴(kuò)展。關(guān)于CheckpointMgr后面將單獨(dú)討論音念。

2.2 網(wǎng)絡(luò)層架構(gòu)

按協(xié)議劃分沪饺,PhxPaxos支持TCP、UDP兩種通信協(xié)議闷愤;按操作劃分整葡,支持網(wǎng)絡(luò)數(shù)據(jù)讀、寫兩種操作讥脐;按角色劃分遭居,分為客戶端、服務(wù)器兩種角色攘烛。在PhxPaxos中魏滚,服務(wù)器只負(fù)責(zé)讀取操作,客戶端只負(fù)責(zé)寫入操作坟漱。因此鼠次,在最簡場景下,我們需要4個(gè)封裝類,分別如下:

  • TCPClient:TCP客戶端腥寇。
  • TCPServer:TCP服務(wù)器成翩。
  • UDPSender:UDP數(shù)據(jù)發(fā)送器。
  • UDPReceiver:UDP數(shù)據(jù)接收器赦役。

而PhxPaxos中的實(shí)際實(shí)現(xiàn)要比這復(fù)雜的多麻敌,來看一組網(wǎng)絡(luò)架構(gòu)圖:


PhxPaxos網(wǎng)絡(luò)架構(gòu)圖

大致分為如下幾部分:

  • UDP封裝層
    UDPRecv:開啟指定端口的UDP通信通道,啟動獨(dú)立線程掂摔、通過poll方式接收網(wǎng)絡(luò)消息术羔,最后將數(shù)據(jù)交給NetWork處理。
    UDPSend:創(chuàng)建UDP Socket乙漓,啟動獨(dú)立線程级历、異步觸發(fā)式發(fā)送消息。提供AddMessage接口接收需發(fā)送的數(shù)據(jù)內(nèi)容叭披,將其放入消息隊(duì)列寥殖,供線程消費(fèi)。
  • TCP封裝層
    包括ServerSocket涩蜘、Socket嚼贡、Event、EventLoop同诫、TcpAcceptor粤策、TcpClient、TcpRead误窖、TcpWrite掐场、TcpIoThread。
    見2.3節(jié)贩猎。
  • 整體網(wǎng)絡(luò)抽象層
    包括NetWork、DfNetWork萍膛、MsgTransport吭服、Communicate。
    見2.4節(jié)蝗罗。

2.3 TCP封裝層

為了清楚了解作者意圖艇棕,來看TCP封裝層類圖:


TCP封裝層類圖

各個(gè)類功能說明如下:

  • Socket
    Socket客戶端通信封裝類,負(fù)責(zé)TCP連接建立串塑,數(shù)據(jù)收發(fā).
  • ServerSocket
    Socket服務(wù)器通信封裝類沼琉,負(fù)責(zé)Tcp服務(wù)器啟動、監(jiān)聽.
  • Event
    網(wǎng)絡(luò)事件接收器(handler)桩匪,負(fù)責(zé)操作Socket讀寫
  • EventLoop
    網(wǎng)絡(luò)事件分發(fā)器(dispatcher)打瘪,支持基于socket的訂閱,每個(gè)socket配對一個(gè)event。當(dāng)前主要分發(fā)兩類網(wǎng)絡(luò)事件:發(fā)送(write)闺骚、接收(read)彩扔。采用epoll實(shí)現(xiàn)網(wǎng)絡(luò)事件監(jiān)聽處理,并對外屏蔽實(shí)現(xiàn)細(xì)節(jié)僻爽。
  • TcpAcceptor
    本節(jié)點(diǎn)TCP服務(wù)器虫碉,負(fù)責(zé)監(jiān)聽其他節(jié)點(diǎn)的客戶端連接。每收到一個(gè)客戶端連接胸梆,配置一個(gè)讀操作的Socket并配對一個(gè)Event
  • TcpClient
    TCP客戶端敦捧,負(fù)責(zé)發(fā)送數(shù)據(jù)到其他節(jié)點(diǎn)。每個(gè)ip碰镜、port配置一個(gè)寫操作的Socket兢卵,并配對一個(gè)Event。
  • TcpRead
    啟動TCP Acceptor線程洋措,接收其他客戶端連接济蝉。啟動EventLoop,接收已連接客戶端的數(shù)據(jù)包菠发。
  • TcpWrite
    啟動EventLoop王滤,發(fā)送TcpClient接收到的數(shù)據(jù)包。
  • TcpIoThread
    對外的TCP操作封裝類滓鸠,其自身并不啟動線程雁乡,僅負(fù)責(zé)整合TcpRead、TcpWrite糜俗,對外提供AddMessage接口踱稍。
    void TcpIOThread :: Stop()
    {
        if (m_bIsStarted)
        {
            m_oTcpRead.Stop();
            m_oTcpWrite.Stop();
        }

        PLHead("TcpIOThread [END]");
    }

    int TcpIOThread :: Init(const std::string& sListenIp, const int iListenPort)
    {
        int ret = m_oTcpRead.Init(sListenIp, iListenPort);

        if (ret == 0)
        {
            return m_oTcpWrite.Init();
        }

        return ret;
    }

    void TcpIOThread :: Start()
    {
        m_oTcpWrite.start();
        m_oTcpRead.start();
        m_bIsStarted = true;
    }

    int TcpIOThread :: AddMessage(const std::string& sIP, const int iPort, const std::string& sMessage)
    {
        return m_oTcpWrite.AddMessage(sIP, iPort, sMessage);
    }

代碼結(jié)構(gòu)還算清晰,但是不是總覺得哪里不對悠抹?沒關(guān)系珠月,先順著作者的思路看完。

2.4 整體網(wǎng)絡(luò)抽象層

相比UDP楔敌、TCP封裝層啤挎,整體網(wǎng)絡(luò)抽象層是更高一級的概念。PhxPaxos中屬于該層的網(wǎng)絡(luò)抽象類如下:

  • NetWork
    整體網(wǎng)絡(luò)抽象類卵凑,對外屏蔽上述所有TCP\UDP實(shí)現(xiàn)庆聘,支持接收、發(fā)送網(wǎng)絡(luò)數(shù)據(jù)勺卢。接收到的網(wǎng)絡(luò)數(shù)據(jù)交由處理器處理(當(dāng)前為Node對象)伙判。
    class NetWork
    {
    public:
        virtual void RunNetWork() = 0;
        virtual void StopNetWork() = 0;

        virtual int SendMessageTCP(const std::string& sIp, const int iPort, const std::string& sMessage) = 0;
        virtual int SendMessageUDP(const std::string& sIp, const int iPort, const std::string& sMessage) = 0;

        int OnReceiveMessage(const char* pcMessage, const int iMessageLen);
    };
  • DfNetWork
    內(nèi)置的網(wǎng)絡(luò)實(shí)現(xiàn)類,負(fù)責(zé)管理UDPRecv黑忱、UDPSend宴抚、TpcIoThread(內(nèi)含TcpRead勒魔、TcpWrite)。
    class DFNetWork : public NetWork
    {
    public:
        int Init(const std::string& sListenIp, const int iListenPort);

        //super interface
        ...
    private:
        UDPRecv m_oUDPRecv;
        UDPSend m_oUDPSend;
        TcpIOThread m_oTcpIOThread;
    };
  • MsgTransport
    網(wǎng)絡(luò)消息發(fā)送器酱塔,接口類沥邻。
    class MsgTransport
    {
    public:
        virtual int SendMessage(const nodeid_t iSendtoNodeID, const std::string& sBuffer,
                                const int iSendType = Message_SendType_UDP) = 0;
        virtual int BroadcastMessage(const std::string& sBuffer,
                                     const int iSendType = Message_SendType_UDP) = 0;
        virtual int BroadcastMessageFollower(const std::string& sBuffer,
                                             const int iSendType = Message_SendType_UDP) = 0;
        virtual int BroadcastMessageTempNode(const std::string& sBuffer,
                                             const int iSendType = Message_SendType_UDP) = 0;
    };
  • Communicate
    網(wǎng)絡(luò)消息發(fā)送器,實(shí)現(xiàn)類羊娃。內(nèi)部讀取配置信息并對NetWork接口的簡單封裝唐全。
    class Communicate : public MsgTransport
    {
    public:
       //super interface 
       ...
    private:
        Config* m_poConfig;
        NetWork* m_poNetwork;

        nodeid_t m_iMyNodeID;
        size_t m_iUDPMaxSize;
    };

其實(shí),這還沒完蕊玷,還有一個(gè)不屬于“整體網(wǎng)絡(luò)抽象層”的網(wǎng)絡(luò)抽象邮利,在base.h中。來看和網(wǎng)絡(luò)相關(guān)的接口定義:

    class Base
    {
    public:
        int PackMsg(const PaxosMsg& oPaxosMsg, std::string& sBuffer);
        int PackCheckpointMsg(const CheckpointMsg& oCheckpointMsg, std::string& sBuffer);
        void PackBaseMsg(const std::string& sBodyBuffer, const int iCmd, std::string& sBuffer);
        static int UnPackBaseMsg(const std::string& sBuffer, Header& oHeader, size_t& iBodyStartPos, size_t& iBodyLen);

    protected:
        virtual int SendMessage(const nodeid_t iSendtoNodeID, const PaxosMsg& oPaxosMsg, const int iSendType = Message_SendType_UDP);
        virtual int BroadcastMessage(
            const PaxosMsg& oPaxosMsg,
            const int bRunSelfFirst = BroadcastMessage_Type_RunSelf_First,
            const int iSendType = Message_SendType_UDP);
        int BroadcastMessageToFollower(
            const PaxosMsg& oPaxosMsg,
            const int iSendType = Message_SendType_TCP);
        int BroadcastMessageToTempNode(
            const PaxosMsg& oPaxosMsg,
            const int iSendType = Message_SendType_UDP);
    protected:
        int SendMessage(const nodeid_t iSendtoNodeID, const CheckpointMsg& oCheckpointMsg,
                        const int iSendType = Message_SendType_TCP);

    protected:
        Config* m_poConfig;
        MsgTransport* m_poMsgTransport;
        Instance* m_poInstance;
    };

base是三個(gè)主要角色(Proposer垃帅、Accepor延届、Learner)的基類,這里網(wǎng)絡(luò)相關(guān)操作主要包括打包和發(fā)送兩種贸诚。和MsgTransport的發(fā)送接口相比有何區(qū)別呢方庭?base中的發(fā)送函數(shù)負(fù)責(zé)打包、發(fā)送以及基于Instance對象的部分特殊處理酱固。以其中的一個(gè)SendMessage為例:

    int Base :: SendMessage(const nodeid_t iSendtoNodeID, const PaxosMsg& oPaxosMsg, const int iSendType)
    {
        if (m_bIsTestMode)
        {
            return 0;
        }

        BP->GetInstanceBP()->SendMessage();
        //本節(jié)點(diǎn)立即處理
        if (iSendtoNodeID == m_poConfig->GetMyNodeID())
        {
            m_poInstance->OnReceivePaxosMsg(oPaxosMsg);
            return 0;
        }
        //打包
        string sBuffer;
        int ret = PackMsg(oPaxosMsg, sBuffer);
        if (ret != 0)
        {
            return ret;
        }
        //發(fā)送
        return m_poMsgTransport->SendMessage(iSendtoNodeID, sBuffer, iSendType);
    }

2.5 架構(gòu)探討

前面將PhxPaxos的網(wǎng)絡(luò)層抽象類全部過了一遍械念,現(xiàn)在我們來窺視下作者的意圖,并進(jìn)一步探討是否存在更合理的架構(gòu)运悲。

PhxPaxos的網(wǎng)絡(luò)抽象層存在一個(gè)明顯的分界點(diǎn):NetWork抽象類龄减。NetWork及其之下抽象是基于純粹網(wǎng)絡(luò)的,業(yè)務(wù)無關(guān)的班眯;NetWork之上的是業(yè)務(wù)相關(guān)的希停。NetWork做為明顯分界點(diǎn)到額另外一個(gè)原因是:允許PhxPaxos的使用者注冊自己的NetWork實(shí)現(xiàn)類,以替換內(nèi)置的DfNetWork署隘。來看NetWork及其之下的抽象:
XXX

按文章中最初提到的觀點(diǎn)宠能,理想中的NetWork應(yīng)該只包含四個(gè)類:TCPClient、TCPServer磁餐、UDPSender棍潘、UDPReceiver。當(dāng)前UDP和預(yù)期一致崖媚,但TCP當(dāng)前一共有9個(gè)類,比預(yù)想的多了7個(gè)恤浪。其中Socket和ServerSocket的抽象是合理的畅哑、粒度恰當(dāng)?shù)模珽vent概念引入及抽象略顯奇怪水由。EventLoop的定位應(yīng)該是一個(gè)Package Dispather(網(wǎng)絡(luò)數(shù)據(jù)分發(fā)器)荠呐,它反向依賴了TcpAcceptor、TcpClient。而且在Phxpaxos場景下讀寫操作是完全隔離的泥张。因此呵恢,Event、EventLoop的功能垂直拆分到TcpClient和TcpServer媚创,薄抽象層TcpRead渗钉、TcpWrite、TcpIoThread移除或許更為合理钞钙。

針對NetWork層說幾點(diǎn):

  • NetWork應(yīng)該是一個(gè)接口鳄橘,而非抽象類。
  • NetWork不應(yīng)該被TcpIOThread芒炼、TcpRead瘫怜、TcpWrite、TcpAcceptor本刽、TcpClient反向依賴鲸湃。
  • NetWork中的OnReceiveMessage應(yīng)該被移除,TCP中收到的消息應(yīng)該提供單獨(dú)的接口抽象(MessageHandler)子寓“堤簦基于PhxPaxos的實(shí)現(xiàn),由Node實(shí)現(xiàn)這個(gè)接口是合適的别瞭。
class MessageHandler
{
    virtual  int OnReceiveMessage(const char* pcMessage, const int iMessageLen) = 0;
}

再來看MsgTransport窿祥、Communicate、base這三個(gè)類蝙寨。因?yàn)镹etWork只做純網(wǎng)絡(luò)的抽象晒衩,直接交由上層使用并不合適,因此基于業(yè)務(wù)抽象的MsgTransport接口確有必要墙歪。但這一層抽象并不徹底听系,進(jìn)而又在base中做了二次封裝。從設(shè)計(jì)上來看虹菲,有如下幾個(gè)缺陷:

  • base是Learner靠胜、Proposer、Accepor的基類毕源,應(yīng)該只包含角色共識邏輯浪漠,網(wǎng)絡(luò)消息處理不屬于其職責(zé)。
  • base中包含CheckpointMsg的消息處理霎褐,但該消息是Checkpoint機(jī)制專有的處理方式址愿,并不適合放到公共的base類中。

個(gè)人認(rèn)為合理的做法應(yīng)該是:

  • base中所有網(wǎng)絡(luò)相關(guān)操作移除冻璃,網(wǎng)絡(luò)發(fā)送部分功能移至Communicate响谓。Communicate做為Phxpaxos的業(yè)務(wù)網(wǎng)絡(luò)抽象層损合。
  • 網(wǎng)絡(luò)數(shù)據(jù)打包、解包部分拆分抽單獨(dú)的PackageUtil類處理娘纷,該類僅被Communicate使用嫁审。

2.6 總結(jié)

Phxpaxos基于socket、poll赖晶、epoll構(gòu)建自己的網(wǎng)絡(luò)層律适,支持UDP、TCP兩種通信方式嬉探。網(wǎng)絡(luò)層一共啟動了如下五個(gè)線程;

  • UDPRecv線程
    處理來自其他節(jié)點(diǎn)的UDP數(shù)據(jù)擦耀。
  • UDPSend線程
    處理本節(jié)點(diǎn)發(fā)往其他節(jié)點(diǎn)的UDP數(shù)據(jù)。
  • TcpAcceptor線程
    處理來自其他節(jié)點(diǎn)的連接請求涩堤。
  • TcpRead線程
    處理來自其他節(jié)點(diǎn)的Tcp數(shù)據(jù)眷蜓。
  • TcpWrite線程
    處理本節(jié)點(diǎn)發(fā)往其他節(jié)點(diǎn)的Tcp數(shù)據(jù)。

NetWork接口對外屏蔽了上述細(xì)節(jié)胎围,并且允許用戶替換為自己的網(wǎng)絡(luò)部件吁系。而Phxpaxos使用的是更上層的MsgTransport,其包含了和Phxpaxos業(yè)務(wù)相關(guān)的一些操作白魂,如打包汽纤、本節(jié)點(diǎn)特殊處理等。

在完成了Communicate之后福荸,我們有了一個(gè)有效的網(wǎng)絡(luò)通信機(jī)制蕴坪,下一步,讓我們真正開始了解PhxPaxos的核心 --- Paxos算法實(shí)現(xiàn)敬锐。


【轉(zhuǎn)載請注明】隨安居士. 2. PhxPaxos分析之網(wǎng)絡(luò)基礎(chǔ)部件. 2017.11.13

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末背传,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子台夺,更是在濱河造成了極大的恐慌径玖,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件颤介,死亡現(xiàn)場離奇詭異梳星,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)滚朵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進(jìn)店門冤灾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人辕近,你說我怎么就攤上這事韵吨。” “怎么了亏推?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵学赛,是天一觀的道長。 經(jīng)常有香客問我吞杭,道長盏浇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任芽狗,我火速辦了婚禮绢掰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘童擎。我一直安慰自己滴劲,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布顾复。 她就那樣靜靜地躺著班挖,像睡著了一般。 火紅的嫁衣襯著肌膚如雪芯砸。 梳的紋絲不亂的頭發(fā)上萧芙,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天,我揣著相機(jī)與錄音假丧,去河邊找鬼双揪。 笑死,一個(gè)胖子當(dāng)著我的面吹牛包帚,可吹牛的內(nèi)容都是我干的渔期。 我是一名探鬼主播,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼渴邦,長吁一口氣:“原來是場噩夢啊……” “哼疯趟!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起几莽,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤迅办,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后章蚣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體站欺,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年纤垂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了矾策。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,789評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡峭沦,死狀恐怖贾虽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吼鱼,我是刑警寧澤蓬豁,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布绰咽,位于F島的核電站,受9級特大地震影響地粪,放射性物質(zhì)發(fā)生泄漏取募。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一蟆技、第九天 我趴在偏房一處隱蔽的房頂上張望玩敏。 院中可真熱鬧,春花似錦质礼、人聲如沸旺聚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽砰粹。三九已至,卻和暖如春妻坝,著一層夾襖步出監(jiān)牢的瞬間伸眶,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工刽宪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留厘贼,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓圣拄,卻偏偏與公主長得像嘴秸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子庇谆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內(nèi)容