OpenDaylight Lithium-SR2 Cluster集群搭建

目的

希望大家能够通过本教程对OpenDaylight集群的基本概念如shard/基本配置有所了解,感受OpenDaylight的High Availability(HA)(如果你同时运行着多台控制器,其中一台crash掉了,整个系统仍然还可以工作)。

本文主要由三个部分组成,前提条件与配置步骤主要介绍了如何配置OpenDaylight的集群,第二个部分验证High Availbility,主要是通过实验让大家对High Availability有更直观的认识。第三个部分写在最后,简要的指出使用集群的优势,我的偶像导师说了,如何保持数据的一致性在软件定义网络中是非常非常非常重要的!

实验

注:若命令以$ 开头,则代表这条命令是在shell中执行;若命令以karaf> 开头,则代表这条命令是在karaf中执行。

前提条件

1. 下载OpenDaylight Lithium-SR2,链接地址为:https://www.opendaylight.org/downloads,若OpenDaylight出了新版本,可以点击该页面的Release Archives,下载Lithium-SR2。

2. 检查Java版本 执行命令查看Java的版本:

$ java -version
java version "1.7.0_85"
OpenJDK Runtime Environment (rhel-2.6.1.2.el7_1-x86_64 u85-b01)
OpenJDK 64-Bit Server VM (build 24.85-b03, mixed mode)

3. 操作系统:3台Ubuntu 14.04.3 LTS,其IP地址分别为192.168.1.25,192.168.1.24,192.168.1.23

4. 请确保防火墙配置正确,本实验使用firewall-cmd命令来配置的防火墙 查看配置执行:

$ sudo firewall-cmd --list-all

配置结果如下:

public (default)
  interfaces:
  sources:
  services: dhcpv6-client ssh
  ports: 2550/tcp 6633/tcp 2551/tcp 8181/tcp 8181/udp
  masquerade: no
  forward-ports:
  icmp-blocks:
  rich rules:

端口8181用于restconf,端口2550用于cluster-data,端口2551用于cluster-rpc,端口6633用于openflow 可以用sudo firewall-cmd --add-port=端口号/协议名称来添加可访问端口。

5. 请确保在启动控制器之前,上述所列端口没有被其他程序占用

配置步骤

本节以IP地址为192.168.1.25的控制器为例,介绍如何对控制器进行配置 1.解压下载的zip文件,并进入控制器目录 本文的控制器目录为解压distribution-karaf-0.3.2-Lithium-SR2.zip后所得distribution-karaf-0.3.2-Lithium-SR2的目录。

$ unzip distribution-karaf-0.3.2-Lithium-SR2.zip
$ cd distribution-karaf-0.3.2-Lithium-SR2

2.运行控制器

$ ./bin/karaf

3.安装集群组件 安装集群组件,如odl-mdsal-clustering、odl-openflowplugin-flow-services和odl-restconf-all后,在控制器目录中的configuration目录内会有initial目录生成,下文的配置文件均位于该initial目录内,安装odl-openflowplugin-flow-services和odl-restconf-all是为了下文测试。下文会利用restconf向config datastore中写入flow。

karaf> feature:install odl-mdsal-clustering odl-openflowplugin-flow-services odl-restconf-all

注:可以在karaf中执行log:tail来查看控制器安装feature的状态日志,按ctrl+c可以停止查看控制器状态日志显示。

4.安装Jolokia

karaf> feature:install http
karaf> bundle:install -s mvn:org.jolokia/jolokia-osgi/1.1.5

5. 退出控制器

karaf> logout

6. 配置akka.conf,module-shards.conf 这些文件由第三步中生成,位于控制器的/configuration/init/中。 本教程中三个控制器的IP地址如下: controller1_IP = 192.168.1.25 controller2_IP = 192.168.1.24 controller3_IP = 192.168.1.23

6.1 修改akka.conf文件中的信息 6.1.1 修改roles roles相当于某一个控制器的ID,也就是说在这个集群中,每一个控制器的roles是唯一的。 例如,对于192.168.1.25,将其设置为

roles = [
        "member-1"
      ]

以此类推,192.168.1.24设置为member-2,192.168.1.23设置为member-3.

6.1.2 修改hostname(有两处需要修改) 修改之前的结果如下所示:

hostname = "127.0.0.1"

将hostname的值设置为你运行该控制器的IP地址或者hostname,如在IP为192.168.1.25的主机中,设置

hostname ="192.168.1.25"

6.1.3 修改odl-cluster-data中的seed-nodes seeds node是用于告诉刚开启的控制器,你属于哪一个集群

seed-nodes = ["akka.tcp://opendaylight-cluster-data@[controller1_IP]:2550", "akka.tcp://opendaylight-cluster-data@[controller2_IP]:2550", "akka.tcp://opendaylight-cluster-data@[controller3_IP]:2550"]

6.1.4 修改odl-cluster-rpc中的seed-nodes

seed-nodes = ["akka.tcp://odl-cluster-rpc@[controller1_IP]:2551", "akka.tcp://odl-cluster-rpc@[controller2_IP]:2551", "akka.tcp://odl-cluster-rpc@[controller3_IP]:2551"]

重要的话要说三遍!!! 请注意data中是opendaylight-cluster-data,rpc中是odl-cluster-rpc! 请注意data中是opendaylight-cluster-data,rpc中是odl-cluster-rpc! 请注意data中是opendaylight-cluster-data,rpc中是odl-cluster-rpc!

6.2 修改module-shards.conf文件 这里引入shard的概念:The in-memory MD-SAL tree is broken up into a number of smaller sub-trees (inventory, topology, and default),个人理解就是将MD-SAL的树拆分成很多小部分,每一个部分就是一个shard,然后在该文件中指定某个部分需要在哪几个控制器上留有备份replicas,详见https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL:Architecture:Clustering#Shard。将每一个replicas都做如下设置

replicas = [
    "member-1",
    "member-2",
    "member-3"
]

这样设置后,module-shards.conf中的所有shards都会在三台控制器中存在。至此,对于控制器192.168.1.25的配置已经完成,其他两台控制器也需要如上配置步骤,注意修改hostname以及roles。 配置范例:https://github.com/shawlinlovelife/learn_odl_cluster。

7. 分别启动三台控制器 请注意三台的启动时间请稍有间隔,最先启动完成的控制器将成为leader节点,我的启动顺序是192.168.1.25、192.168.1.24、192.168.1.23。

$ JAVA_MAX_MEM=4G JAVA_MAX_PERM_MEM=512m ./karaf
$ JAVA_MAX_MEM=4G JAVA_MAX_PERM_MEM=512m ./karaf
$ JAVA_MAX_MEM=4G JAVA_MAX_PERM_MEM=512m ./karaf

当你在karaf中执行log:tail|grep clustering后,能够见到如下信息,则代表member-1已经被选举为leader

2015-12-14 23:06:36,247 | INFO  | ult-dispatcher-3 | RoleChangeNotifier               | 175 - org.opendaylight.controller.sal-clustering-commons - 1.2.2.Lithium-SR2 | RoleChangeNotifier for member-1-shard-default-config , received role change from Candidate to Leader

当然你也会看到有data等successfully之类的,然后有rpc等successfully之类的信息。

8. 查看member-1的shard的信息 可以向member-1所在的控制器,本例中为192.168.1.25发送HTTP请求:

GET http://:8181/jolokia/read/org.opendaylight.controller:Category=Shards,name=member-1-shard-inventory-config,type=DistributedConfigDatastore

上述URI中的name的结构如下:

<member-name>-shard-<shard-name-as-per-configuration>-<store-type>

其中<shard-name-as-per-configuration>是你在module-shards.conf中设置的name,

<store-type>可以是config或者是operational,URI中的<host IP>应该与<member-name>对应

请将<hostIP>替换为ID为member-1的控制器的IP,发送请求可以使用Postman,若配置成功将会得到如下结果:

{
  "timestamp": 1450151185,
  "status": 200,
  "request": {
    "mbean": "org.opendaylight.controller:Category=Shards,name=member-1-shard-inventory-config,type=DistributedConfigDatastore",
    "type": "read"
  },
  "value": {
    "ReadWriteTransactionCount": 0,
    "SnapshotTerm": -1,
    "LastLogIndex": -1,
    "LastLogTerm": -1,
    "PeerAddresses": "member-2-shard-inventory-config: akka.tcp://opendaylight-cluster-data@192.168.1.24:2550/user/shardmanager-config/member-2-shard-inventory-config, member-3-shard-inventory-config: akka.tcp://opendaylight-cluster-data@192.168.1.23:2550/user/shardmanager-config/member-3-shard-inventory-config",
    "ReplicatedToAllIndex": -1,
    "StatRetrievalError": null,
    "CurrentTerm": 66,
    "LastTerm": -1,
    "SnapshotCaptureInitiated": false,
    "ShardName": "member-1-shard-inventory-config",
    "FailedTransactionsCount": 0,
    "LastIndex": -1,
    "LastApplied": -1,
    "LastCommittedTransactionTime": "1970-01-01 08:00:00.000",
    "InMemoryJournalLogSize": 0,
    "StatRetrievalTime": "4.987 ms",
    "LastLeadershipChangeTime": "2015-12-15 11:45:35.668",
    "ReadOnlyTransactionCount": 0,
    "CommitIndex": -1,
    "VotedFor": "member-1-shard-inventory-config",
    "LeadershipChangeCount": 1,
    "FollowerInitialSyncStatus": true,
    "FailedReadTransactionsCount": 0,
    "SnapshotIndex": -1,
    "Leader": "member-1-shard-inventory-config",
    "CommittedTransactionsCount": 0,
    "AbortTransactionsCount": 0,
    "WriteOnlyTransactionCount": 0,
    "RaftState": "Follower",
    "FollowerInfo": [],
    "InMemoryJournalDataSize": 0,
    "PendingTxCommitQueueSize": 0
  }
}

结论验证

1.连接mininet(可跳过) 注:这步其实没必要,因为其实我们修改config的datastore而不是operational的datastore,这里有一个问题就是我修改config datastore的信息会不会直接反应到operational datastore中,知道的小伙伴请告诉我。 启动mininet,并连接到三台控制器中的任意一个控制器:

$ sudo mn --controller=remote,<某一个控制器IP> --topo=tree,3 --switch=ovsk,protocols=OpenFlow13 --mac

注:--mac 会使得mininet虚拟出来的host的mac地址从00:00:00:00:00:01开始,方便查看。

2. 向某一个控制器添加flow,查看其他两个控制器的data store是否也发生改变 本例利用Postman向IP地址为192.168.1.23的控制发送PUT请求,添加flow信息,其信息结构如下:

With PostMan:
Set headers:
Content-Type: application/xml
Accept: application/xml
Authentication
Use URL: http://192.168.1.23:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:1/table/0/flow/1
PUT
Use Body:


    <priority>2</priority&>
    <flow-name>Foo</flow-name>
    
        
            
                <type>2048</type>
            </ethernet-type>
        </ethernet-match>
        <ipv4-destination>10.0.10.2/24</ipv4-destination>
    </match>
    <id>1</id>
    <table_id>0</table_id>
    <instructions>
        <instruction>
            <order>0</order>
            <apply-actions>
                <action>
                   <order>0</order>
                  <dec-nw-ttl/>
                </action>
            </apply-actions>
        </instruction>
    </instructions>
</flow>

使用Postman向另外两个控制器发送如下所示的GET请求,你将会得到相同的结果:

GET http://:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:1/table/0/

不再需要设置Accept header。

结果实例如下:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<flow xmlns="urn:opendaylight:flow:inventory">
    <priority>2</priority>
    <flow-name>Foo</flow-name>
    <match>
        <ethernet-match>
            <ethernet-type>
                <type>2048</type>
            </ethernet-type>
        </ethernet-match>
        <ipv4-destination>10.0.10.2/24</ipv4-destination>
    </match>
    <id>1</id>
    <table_id>0</table_id>
    <instructions>
        <instruction>
            <order>0</order>
            <apply-actions>
                <action>
                  <order>0</order>
                   <dec-nw-ttl/>
                </action>
            </apply-actions>
        </instruction>
    </instructions>
</flow>

3. 关闭leader控制器,查看系统是否能正常工作(leader将发生转换) 3.1 关闭leader控制器,本例中关闭192.168.1.25的控制器。 3.2 通过向member-2发送GET请求,来查看当前的leader

GET http://:8181/jolokia/read/org.opendaylight.controller:Category=Shards,name=member-2-shard-inventory-config,type=DistributedConfigDatastore

本例中此处host IP可以设置为192.168.1.24,请注意host IP应该与在akka.conf中设置的roles的值相对应 结果示例如下,可以看到leader已经更换成为member-2-shard-inventory-config,也有可能是member-3-shard-inventory-config

{
  "timestamp": 1450155472,
  "status": 200,
  "request": {
    "mbean": "org.opendaylight.controller:Category=Shards,name=member-2-shard-inventory-config,type=DistributedConfigDatastore",
    "type": "read"
  },
  "value": {
    "ReadWriteTransactionCount": 0,
    "SnapshotTerm": 66,
    "LastLogIndex": 8,
    "LastLogTerm": 66,
    "PeerAddresses": "member-3-shard-inventory-config: akka.tcp://opendaylight-cluster-data@192.168.1.23:2550/user/shardmanager-config/member-3-shard-inventory-config, member-1-shard-inventory-config: akka.tcp://opendaylight-cluster-data@192.168.1.25:2550/user/shardmanager-config/member-1-shard-inventory-config",
    "ReplicatedToAllIndex": 7,
    "StatRetrievalError": null,
    "CurrentTerm": 66,
    "SnapshotCaptureInitiated": false,
    "LastTerm": 66,
    "ShardName": "member-2-shard-inventory-config",
    "FailedTransactionsCount": 0,
    "LastIndex": 8,
    "LastApplied": 8,
    "LastCommittedTransactionTime": "2015-12-15 12:52:54.697",
    "InMemoryJournalLogSize": 1,
    "StatRetrievalTime": "6.524 ms",
    "LastLeadershipChangeTime": "2015-12-15 10:57:32.216",
    "ReadOnlyTransactionCount": 0,
    "VotedFor": "member-2-shard-inventory-config",
    "CommitIndex": 8,
    "LeadershipChangeCount": 1,
    "FollowerInitialSyncStatus": false,
    "FailedReadTransactionsCount": 0,
    "SnapshotIndex": 7,
    "Leader": "member-2-shard-inventory-config",
    "CommittedTransactionsCount": 9,
    "AbortTransactionsCount": 0,
    "WriteOnlyTransactionCount": 0,
    "RaftState": "Leader",
    "FollowerInfo": [
      {
        "id": "member-3-shard-inventory-config",
        "timeSinceLastActivity": "0:00:00.206",
        "nextIndex": 9,
        "matchIndex": 8,
        "active": true
      },
      {
        "id": "member-1-shard-inventory-config",
        "timeSinceLastActivity": "0:02:41.409",
        "nextIndex": 9,
        "matchIndex": 8,
        "active": false
      }
    ],
    "InMemoryJournalDataSize": 1248,
    "PendingTxCommitQueueSize": 0
  }
}

4. 插入一条新的flow,本例向member-2中插入

With PostMan:
Set headers:
Content-Type: application/xml
Accept: application/xml
Authentication
Use URL: http://192.168.1.23:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:1/table/0/flow/12
PUT
Use Body:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<flow xmlns="urn:opendaylight:flow:inventory">
    <priority>2</priority>
    <flow-name>Foo2</flow-name>
    <match>
        <ethernet-match>
            <ethernet-type>
                <type>2048</type>
            </ethernet-type>
        </ethernet-match>
        <ipv4-destination>10.0.10.2/24</ipv4-destination>
    </match>
    <id>12</id>
    <table_id>0</table_id>
    <instructions>
        <instruction>
            <order>0</order>
            <apply-actions>
                <action>
                   <order>0</order>
                   <dec-nw-ttl/>
                </action>
            </apply-actions>
        </instruction>
    </instructions>
</flow>

5. 查看member-3中的信息是否也更新了

GET http://192.168.1.23:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:1/table/0/

若正常,则member-3中的信息已经更新

{
  "flow-node-inventory:table": [
    {
      "id": 0,
      "flow": [
        {
          "id": "12",
          "match": {
            "ipv4-destination": "10.0.10.2/24",
            "ethernet-match": {
              "ethernet-type": {
                "type": 2048
              }
            }
          },
          "flow-name": "Foo2",
          "table_id": 0,
          "priority": 2,
          "instructions": {
            "instruction": [
              {
                "order": 0,
                "apply-actions": {
                  "action": [
                    {
                      "order": 0,
                      "dec-nw-ttl": {}
                    }
                  ]
                }
              }
            ]
          }
        },
        {
          "id": "1",
          "match": {
            "ipv4-destination": "10.0.10.2/24",
            "ethernet-match": {
              "ethernet-type": {
                "type": 2048
              }
            }
          },
          "flow-name": "Foo2",
          "table_id": 0,
          "priority": 2,
          "instructions": {
            "instruction": [
              {
                "order": 0,
                "apply-actions": {
                  "action": [
                    {
                      "order": 0,
                      "dec-nw-ttl": {}
                    }
                  ]
                }
              }
            ]
          }
        }
      ]
    }
  ]
}

6. 重新开启在3.1中关闭的控制器,验证在9.2.3中添加的flow,是否存在

GET http://192.168.1.25:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:1/table/0/

若结果正常,则它显示的应该与9.2.4中信息相同。

注:本实验验证了一部分关于OpenDaylight Cluster的功能,事实上一个集群的功能远不止这些。ODL的用户手册中还指出了以下三个: • Scaling: If you have multiple controllers running, you can potentially do more work with or store more data on those controllers if they are clustered. You can also break up your data into smaller chunks (known as shards) and either distribute that data across the cluster or perform certain operations on certain members of the cluster.

• High Availability: If you have multiple controllers running and one of them crashes, you would still have the other instances working and available.

• Data Persistence: You will not lose any data gathered by your controller after a manual restart or a crash.

我近期的另一个目标是对OpenDaylight集群进行性能测试,希望有经验的小伙伴能够给我推荐一些工具。这是我第一篇有一点点技术向的博文,希望能给大家提供点参考与帮助。

原文发布于微信公众号 - SDNLAB(SDNLAB)

原文发表时间:2015-12-17

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏北京马哥教育

ls 命令还能这么玩?看一下这 20 个实用范例

21240
来自专栏张戈的专栏

Linux运维工程师:30道面试题整理

前段时间,我在准备面试的时搜到的一套 Linux 运维工程师面试题,感觉比较全面,一直保存在草稿,刚在整理后台时翻了出来,干脆就发出来好了,以备不时之需。 1....

2.3K50
来自专栏aoho求索

Spring Cloud Bus中的事件的订阅与发布(二)

在之前的文章Spring Cloud Bus中的事件的订阅与发布(一)介绍了消息总线的相关事件。本文主要介绍消息总线的事件监听器以及消息的订阅与发布。 事件监听...

48470
来自专栏happyJared

Elasticsearch 6.3.2版本踩填坑指南

  前端时间利用ES开发一个"附近地理位置+其它信息"查询搜索的功能(据了解,Redis和PostgreSQL也能实现同样的功能),实践中遇到了不少的问题,所以...

1K20
来自专栏草根专栏

用ASP.NET Core 2.0 建立规范的 REST API -- 预备知识 + 项目准备

REST 是 Representational State Transfer 的缩写. 它是一种架构的风格, 这种风格基于一套预定义的规则, 这些规则描述了网络...

1.2K60
来自专栏腾讯云Elasticsearch Service

Elasticsearch 底层系列之分片恢复解析

我们是基础架构部,腾讯云 CES/CTSDB 产品后台服务的支持团队,我们拥有专业的ES开发运维能力,为大家提供稳定、高性能的服务,欢迎有需求的童鞋接入,同时也...

8.5K00
来自专栏编码小白

ofbiz初级教程

本教程是ofbiz 基本应用,它涵盖了OFBiz应用程序开发过程的基本原理。目标是使开发人员熟悉最佳实践,编码惯例,基本控制流程以及开发人员对OFBiz定制所需...

1.9K30
来自专栏时序数据库专栏

Elasticsearch 底层系列之分片恢复解析

    我们是基础架构部,腾讯云 CES/CTSDB 产品后台服务的支持团队,我们拥有专业的ES开发运维能力,为大家提供稳定、高性能的服务,欢迎有需求的童鞋接入...

20950
来自专栏向治洪

Android热插拔事件处理详解

一、Android热插拔事件处理流程图 Android热插拔事件处理流程如下图所示: ? 二、组成 1. NetlinkManager:       ...

87670
来自专栏步履前行

Spring Retry

  在我们的业务场景中,经常要调用其他的API来获取信息,比如我们的业务场景需要依赖个人信息来处理,这个时候调用个人信息服务的API,但是由于可能同一时段多方在...

46130

扫码关注云+社区

领取腾讯云代金券