天天看點

OpenDaylight搭建叢集目錄

目錄

聲明 摘要 多節點叢集 參考文獻

聲明

官網的文檔一直在變化,可能翻譯時的文檔跟目前文檔有出入,請以官網文檔為準。

摘要

叢集是使多個程序和程式作為一個整體工作的機制。舉例,當在google.com網站上查詢資料時,查詢請求好像隻有一台web伺服器在處理。實際上,查詢請求是被一個叢集中多台互相連接配接的web伺服器處理的。類似地,OpenDaylight也可以有多個執行個體作為一個整體對外提供服務。

叢集的優勢:

- 可伸縮性:如果有多個OpenDaylight執行個體在運作,一般情況下比僅有一台執行個體會做更多的任務和存儲更多的資料。也可以把資料分解成塊(片),然後把資料散布到整個叢集,或者在叢集中的某個執行個體執行某個操作。

  • 高可用性:如果有多個OpenDaylight執行個體在運作,其中一個執行個體當機,其它執行個體仍然可以工作和提供服務。
  • 資料持久化:手動重新開機或者當機,不會丢失存儲在OpenDaylight的任何資料.

下面這部分描述如何搭建叢集。

多節點點叢集

以下部分描述了如何用OpenDaylight搭建多節點叢集。

部署注意事項

實作叢集,需要注意如下事項:

  • 推薦最少3台機子來搭建多節點叢集。也可以搭建隻有兩個節點的叢集。但是,如果2台中有一台當機,則叢集就不可用。
    注意:這是因為OpenDaylight要求大部分節點需要運作,而一個節點顯然不能稱作是大部分節點。
  • 叢集中的每個執行個體都需要有一個辨別符。OpenDaylight通過使用節點role來達到這個目的。當在akka.conf檔案中定義第一個節點的role為member-1時,OpenDaylight就使用member-1來辨別該節點。
  • 資料片(譯注:這個概念對于文章了解很重要,請檢視wiki Share)用于存儲OpenDaylight MD-SAL資料庫所有資料或者某個片段的資料。例如,一個資料片可以存儲所有的inventory資料,而另外一個資料片可以存儲所有的topology資料。

    如果沒有在modules.conf檔案中指定一個module,且在module-shards.conf檔案中也沒有指定一個分片。預設所有的資料存放在default資料片中(該default分片必須在module-shares.conf檔案預先定義好)。每個分片都有一個可配置的replicas。在module-shares.conf中可以指定replicas詳情,replicas表示分片位于哪個節點(譯注:比如memeber-1,memeber-2)。

  • 如果有一個3節點的叢集,想要能夠容忍任意節點的當機,那麼每個資料片的副本必須運作在3節點的叢集上。(譯注:意思是如果想在叢集中某台機子當機的情況下還能正常服務,沒有資料缺失,那麼你必須把每一個資料片複制到3個節點上)
    注意:這是因為OpenDaylight的叢集實作要求大部分資料片都運作才能提供服務。如果隻在叢集中的2個節點定義資料片副本(譯注:即該資料片隻有兩個複制)且其中一個節點當機,相應的該資料片無法運作(譯注:一個資料片無法成為大部分。雖然還有一個節點正常運作,但是也不運作的意思)
  • 如果有3個節點的叢集且某個資料片在所有節點上定義副本,即使該叢集隻剩下兩個節點在運作,該資料片仍然能夠運作。注意如果剩下的兩個節點又當機一個,則該資料片将不可操作。
  • 推薦配置多個節點。叢集中的某個節點啟動,它會發送一個消息給所有的節點。然後該節點會發送一個加入指令給第一個響應它的節點。如果沒有節點回應,該節點重複這個過程直到成功建立一個連接配接或者自己關閉這個過程。
  • 叢集中某個節點持續一段時間(預設10秒,可配置)還是不可達後(譯注:不能連接配接),該節點自動下線。一旦節點下線,你需要重新啟動它才能再次加入叢集。一旦重新啟動的節點加入叢集,它将自動從主節點同步資料。

叢集腳本

OpenDaylight包含一些用于配置叢集的腳本。

注意:腳本是位于OpenDaylight distribution/bin 目錄下,該腳本在倉庫的位置是distribution-karaf/src/main/assembly/bin/

使用叢集腳本

這個腳本被用于設定控制器叢集中某個節點的叢集參數(指akka.conf,module-shares.conf中的參數)。使用者重新開機節點才能生效設定的參數。

注意:這個腳本可以在任意時刻使用,甚至在控制器第一次被啟動之前。

用法:

index:1..N之間的整數,N是節點的數量。這個表示腳本配置的是哪一個控制器節點。

seed_nodes_list:叢集中所有節點組成的ip位址清單,用逗号或者空格分隔。

index指向的IP位址應該是正在執行腳本的節點的ip位址。當在多個節點運作這個腳本時,保證seed_node_list這個參數值一樣,而index在1到N之間改變。

可選,資料片可以通過修改“custom_shard_configs.txt”檔案,在更多粒度進行配置,該檔案和該腳本在同一個目錄下。想要更多資訊可以檢視此檔案。

舉例:

上面的指令将配置節點2(ip位址192.168.0.2),該節點位于由192.168.0.1 192.168.0.2 192.168.0.3三台機子組成的叢集中

搭建多節點叢集

譯注:這裡需要注意一下步驟順序,第10個步驟需要移到第2個步驟的下面進行,不然你将找不到第3步所說的配置檔案。即你需要先啟動karaf,然後運作feature:install odl-mdsal-clustering,退出karaf指令行界面後,在繼續進行下面的步驟。

為了運作3節點叢集的OpenDaylight,執行如下步驟:

首先選擇3台機子用于搭建叢集。之後在每台機子下做如下操作:

  • 1.拷貝OpenDaylight釋出檔案zip(譯注:linux為tar.bz2)到機子上。
  • 2.解壓釋出版本檔案。
  • 3.打開下面的.conf檔案:
    configuration/initial/akka.conf
    configuration/initial/module-shards.conf
               
  • 4.每個配置檔案做如下修改(譯注:這裡說的是akka.conf這個檔案):

    每個檔案找到如下行的情況,然後用該配置檔案所在機子即OpenDaylight運作所在機子的主機名或者ip位址替換127.0.0.1:

    netty.tcp {
      hostname = "127.0.0.1"
               
    注意:對于叢集中的每個節點該值是不一樣的。
  • 5.找到如下所示的行,然後用叢集中的所有節點的機子的主機名或ip位址替換127.0.0.1(譯注:這裡的意思是叢集有幾個節點,數組中就有幾個記錄,隻是ip做相應的修改):
    cluster {
      seed-nodes = ["akka.tcp://[email protected]:2550"]
               
  • 6.找到如下部分,給每一個節點指定一個角色名。這裡我們用member-1指派給第一個節點,第二節點用member-2,第三個節點用member-3:
    roles = [
      "member-1"
    ]
               
    注意:這個步驟,在每個節點應該使用不同的節點名。
  • 7.打開configuration/initial/module-shards.conf檔案,修改replicas屬性,讓每一個資料片複制到所有的節點
    replicas = [
        "member-1",
        "member-2",
        "member-3"
    ]
               
    僅供參考,可以檢視下面給出的==配置檔案示例==
  • 8.切換到/bin目錄下。
  • 9.運作如下指令:
    JAVA_MAX_MEM=G JAVA_MAX_PERM_MEM=m ./karaf
               
  • 10.在karaf指令行中運作如下指令啟用叢集功能(譯注:這步移到第三步)

OpenDaylight此時應該運作在3個節點的叢集上。你可以通過任意的節點通路存儲在資料庫中的資料。

配置檔案示例

==akka.conf== 示例檔案:

odl-cluster-data {
     bounded-mailbox {
       mailbox-type = "org.opendaylight.controller.cluster.common.actor.MeteredBoundedMailbox"
       mailbox-capacity = 
       mailbox-push-timeout-time = ms
     }

     metric-capture-enabled = true

     akka {
       loglevel = "DEBUG"
       loggers = ["akka.event.slf4j.Slf4jLogger"]

       actor {

         provider = "akka.cluster.ClusterActorRefProvider"
         serializers {
                   java = "akka.serialization.JavaSerializer"
                   proto = "akka.remote.serialization.ProtobufSerializer"
                 }

                 serialization-bindings {
                     "com.google.protobuf.Message" = proto

                 }
       }
       remote {
         log-remote-lifecycle-events = off
         netty.tcp {
           hostname = "10.194.189.96"
           port = 
           maximum-frame-size = 
           send-buffer-size = 
           receive-buffer-size = 
         }
       }

       cluster {
         seed-nodes = ["akka.tcp://[email protected]:2550",
                       "akka.tcp://[email protected]:2550",
                       "akka.tcp://[email protected]:2550"]

         auto-down-unreachable-after = s

         roles = [
           "member-2"
         ]

       }
     }
   }

   odl-cluster-rpc {
     bounded-mailbox {
       mailbox-type = "org.opendaylight.controller.cluster.common.actor.MeteredBoundedMailbox"
       mailbox-capacity = 
       mailbox-push-timeout-time = ms
     }

     metric-capture-enabled = true

     akka {
       loglevel = "INFO"
       loggers = ["akka.event.slf4j.Slf4jLogger"]

       actor {
         provider = "akka.cluster.ClusterActorRefProvider"

       }
       remote {
         log-remote-lifecycle-events = off
         netty.tcp {
           hostname = "10.194.189.96"
           port = 
         }
       }

       cluster {
         seed-nodes = ["akka.tcp://[email protected]:2551"]

         auto-down-unreachable-after = s
       }
     }
   }
           

==module-shards.conf== 示例檔案:

module-shards = [
    {
        name = "default"
        shards = [
            {
                name="default"
                replicas = [
                    "member-1",
                    "member-2",
                    "member-3"
                ]
            }
        ]
    },
    {
        name = "topology"
        shards = [
            {
                name="topology"
                replicas = [
                    "member-1",
                    "member-2",
                    "member-3"
                ]
            }
        ]
    },
    {
        name = "inventory"
        shards = [
            {
                name="inventory"
                replicas = [
                    "member-1",
                    "member-2",
                    "member-3"
                ]
            }
        ]
    },
    {
         name = "toaster"
         shards = [
             {
                 name="toaster"
                 replicas = [
                    "member-1",
                    "member-2",
                    "member-3"
                 ]
             }
         ]
    }
]
           

叢集監控

OpenDaylight通過MBeans暴露資料片資訊,可以通過JConsole,VisualVM或者其他JMX用戶端來檢視資料片資訊,也可以通過使用Jolokia的REST API來暴露資料片資訊,該API是安裝karaf feature ==odl-jolokia==元件才有。

列出所有的可用的MBeans方案的URI:

使用下面REST,查詢OpenDaylight執行個體的本地資料片資訊。

比如config資料庫資訊:

比如operational資料庫資訊:

以下輸出顯示了該節點資料片資訊:

{
  "request": {
    "mbean": "org.opendaylight.controller:Category=ShardManager,name=shard-manager-operational,type=DistributedOperationalDatastore",
    "type": "read"
  },
  "value": {
    "LocalShards": [
      "member-1-shard-default-operational",
      "member-1-shard-entity-ownership-operational",
      "member-1-shard-topology-operational",
      "member-1-shard-inventory-operational",
      "member-1-shard-toaster-operational"
    ],
    "SyncStatus": true,
    "MemberName": "member-1"
  },
  "timestamp": ,
  "status": 
}
           

當需要進一步的檢視來自“LocalShards”清單中的某個分片資訊,可以把該分片的完整名稱當作URI的一部分,來查詢該分片的詳細資訊。如下是member-1-shard-default-operational資訊輸出的例子:

{
  "request": {
    "mbean": "org.opendaylight.controller:Category=Shards,name=member-1-shard-default-operational,type=DistributedOperationalDatastore",
    "type": "read"
  },
  "value": {
    "ReadWriteTransactionCount": ,
    "SnapshotIndex": ,
    "InMemoryJournalLogSize": ,
    "ReplicatedToAllIndex": ,
    "Leader": "member-1-shard-default-operational",
    "LastIndex": ,
    "RaftState": "Leader",
    "LastCommittedTransactionTime": "2017-01-06 13:19:00.135",
    "LastApplied": ,
    "LastLeadershipChangeTime": "2017-01-06 13:18:37.605",
    "LastLogIndex": ,
    "PeerAddresses": "member-3-shard-default-operational: akka.tcp://[email protected]:2550/user/shardmanager-operational/member-3-shard-default-operational, member-2-shard-default-operational: akka.tcp://[email protected]:2550/user/shardmanager-operational/member-2-shard-default-operational",
    "WriteOnlyTransactionCount": ,
    "FollowerInitialSyncStatus": false,
    "FollowerInfo": [
      {
        "timeSinceLastActivity": "00:00:00.320",
        "active": true,
        "matchIndex": ,
        "voting": true,
        "id": "member-3-shard-default-operational",
        "nextIndex": 
      },
      {
        "timeSinceLastActivity": "00:00:00.320",
        "active": true,
        "matchIndex": ,
        "voting": true,
        "id": "member-2-shard-default-operational",
        "nextIndex": 
      }
    ],
    "FailedReadTransactionsCount": ,
    "StatRetrievalTime": "810.5 μs",
    "Voting": true,
    "CurrentTerm": ,
    "LastTerm": ,
    "FailedTransactionsCount": ,
    "PendingTxCommitQueueSize": ,
    "VotedFor": "member-1-shard-default-operational",
    "SnapshotCaptureInitiated": false,
    "CommittedTransactionsCount": ,
    "TxCohortCacheSize": ,
    "PeerVotingStates": "member-3-shard-default-operational: true, member-2-shard-default-operational: true",
    "LastLogTerm": ,
    "StatRetrievalError": null,
    "CommitIndex": ,
    "SnapshotTerm": ,
    "AbortTransactionsCount": ,
    "ReadOnlyTransactionCount": ,
    "ShardName": "member-1-shard-default-operational",
    "LeadershipChangeCount": ,
    "InMemoryJournalDataSize": 
  },
  "timestamp": ,
  "status": 
}
           

輸出資訊辨別分片狀态(主/從,投票中/非投票中)、同級節點資訊、從節點資訊,分片是否是主節點、其他統計資訊和計數資訊。

內建團隊正在維護一個基于Python開發的工具,這個工具通過Jolokia元件,使用了上文提到MBeans暴露的接口,且systemmetrics項目也提供了一個基于DLUX UI來顯示相同的資訊。

空間分布式的active/backup設定

節點之間的延遲時間最小的時候OpenDaylight叢集工作在最佳狀态,實踐表明它們應該在同一個資料中心(譯注:指在同一個機房)。但是假設所有節點當機,能夠在不同的資料中心實作故障轉移更滿足需求。為了獲的這種效果,在不影響主資料中心節點(譯注:這裡應該是主資料中心,即同一個機房的所有節點)的延遲時間的方法下,叢集可以通過在不同資料中心擴充節點的方式來達到目的。如果這樣做,備份資料中心節點必須處在“non-voting” 狀态。

在controller項目cluster-admin.yang中定義了一個RPCs,用于修改分片的voting狀态的API;該API已經很好地被文檔化。該API的概要如下:

注意:除非另外指出,下面的POST請求都被發送到叢集中的任意一個節點。

建立一個6個節點叢集的active/backup設定(分别位于兩個機房,3個活躍和3個備份節點)。這裡有一個RPC可以根據給定狀态設定指定節點中的所有分片的投票狀态:

這個RPC需要一個節點清單和期望的投票狀态作為輸入。為了建立備份節點,如下輸入示例可以被使用:

{
  "input": {
    "member-voting-state": [
      {
        "member-name": "member-4",
        "voting": false
      },
      {
        "member-name": "member-5",
        "voting": false
      },
      {
        "member-name": "member-6",
        "voting": false
      }
    ]
  }
}
           

當一個active/backup部署存在時,且備份節點處于non-voting狀态,這些被用于從active子叢集到backup子叢集的故障轉移的分片将翻轉每一個分片(包含每一個節點,活躍和備份)的投票狀态。通過下面的RPC調用可以很容易實作這個過程(無需參數):

如果是主投票節點(譯注:這裡應該指的是active資料中心機房)因意外斷電導緻當機,“flip” RPC請求必須被發送到某個非投票狀态的備份節點(譯注:backup資料中心機房的某個節點)。這種情況下,沒有分片進行投票選舉。但是這裡有一個特例,如果收到RPC請求的這個節點處在non-voting狀态,且即将改變為voting狀态,且沒有主節點,則這個節點将狀态改為voting并嘗試成為主節點。如果成功,該節點儲存狀态并複制這些變動資訊給其餘的節點。

當主中心被修複且你想要自動恢複到之前狀态,你必須謹慎對待主中心的恢複。因為次級中心的投票狀态被翻轉的時候,主中心是處于下線狀态,主中心的資料庫并沒有儲存這些變化。如果主中心在這種狀态被恢複,主中心的節點将仍然處于投票狀态。如果主中心節點連接配接到次級中心,它們找出次級中心的主節點并同步。但是如果沒有發生這種情況,主中心将可能選舉出它們自己的主節點,進而被分割出2個叢集,這種情況會導緻不可預測的結果。是以推薦在恢複主中心時,先清除主中心節點資料庫資料(例如,日志和快照目錄)。另外一種選擇是從次級中心一個最新備份中恢複主中心的資料(詳情查閱Backing Up and Restoring the Datastore)

如果想要從叢集中溫和的移除一個節點也是可以的,檢視如下RPC API:

請求的示例資料:

{
  "input": {
    "member-name": "member-1"
  }
}
           

或者僅僅是移除一個特定的分片:

請求的執行個體資料:

{
  "input": {
    "shard-name": "default",
    "member-name": "member-2",
    "data-store-type": "config"
  }
}
           

注意在運作時某個故障節點被移除,也可以添加一個新的節點,不用修改正常節點的配置檔案(需要重新開機)。

該請求不需要任何請求資料,但是這個RPC需要被發送到新的節點,訓示該節點去叢集中複制所有分片資料。

注意

雖然叢集admin API允許動态地添加和移除分片,但是module-shard.conf和modules.conf檔案仍然使用啟動時定義的初始化配置。使用API修改并不會存儲到這些靜态檔案中,但是會存到journal中。

參考文獻

Shard

Setting Up Clustering

OpenDaylight Lithium-SR2 Cluster叢集搭建

Running and testing an OpenDaylight Cluster

OpenDaylight搭建叢集目錄

繼續閱讀