ONOS:负载均衡路由算法及应用开发(二)

本文将为大家讲述应用的实现,并进行必要的代码分析。

本应用暂时以Maven作为项目的构建工具,并采用最简单的single bundle的项目组织形式[1]。如果进行大项目的开发,推荐仿照onos.faultmanagement应用进行模块划分和项目feature组织。

虽然ONOS在最新的1.8.0-SNAPSHOT版本中强制引入了BUCK项目构建工具,但本应用开发时尚未有这个要求。大家在开发自己的应用时仍可使用Maven,但如果想要贡献代码,则必须添加兼容BUCK构建工具的配置信息。

一、Maven项目POM文件

为了便于各位理解,必要的讲解已经写在了注释中。

1.App属性信息

<!-- Mao: Application Identifier -->
    <groupId>org.mao</groupId>
    <artifactId>onos-app-mao-load-balance</artifactId>
    <packaging>bundle</packaging>

    <!-- Mao: Application Readable Info -->
    <description>Mao Load Balance Routing</description>
    <url>http://maojianwei.github.io/</url>

    <properties>
        <!-- Mao: ONOS App Info for Jersey REST API & Swagger UI -->
        <web.context>/onos</web.context>
        <api.version>1.0.0</api.version>
        <api.title>Mao Load Balance Routing REST API</api.title>
        <api.description>
            APIs for interacting with the Mao Load Balance application.
        </api.description>
        <api.package>org.fnl.rest</api.package>

        <!-- Mao: ONOS App Info for maven packaging -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <onos.version>1.8.0-SNAPSHOT</onos.version>
        <onos.app.name>org.onosproject.mao.loadbalance</onos.app.name>
        <onos.app.title>Mao Load Balance Routing</onos.app.title>
        <onos.app.origin>Mao Jianwei, FNLab, BUPT</onos.app.origin>
        <onos.app.category>Traffic Steering</onos.app.category>
        <onos.app.url>http://maojianwei.github.io/</onos.app.url>
        <onos.app.readme>Mao Load Balance Routing</onos.app.readme>
</properties>

2.App依赖

<dependencies>
        <!-- REST API -->
        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet-core</artifactId>
            <!--<version>2.22.2</version>-->
        </dependency>

        <!-- PortStatisticsService -->
        <dependency>
            <groupId>org.onosproject</groupId>
            <artifactId>onos-incubator-api</artifactId>
        </dependency>

        <!-- DefaultTopology -->
        <dependency>
            <groupId>org.onosproject</groupId>
            <artifactId>onos-core-common</artifactId>
            <version>1.8.0-SNAPSHOT</version>
        </dependency>
</dependencies>

二、代码分析

1.源码目录总览


主要包含如下两个部分:

  • MaoRoutingManager:负载均衡Reactive Routing核心模块
  • MaoRoutingService:预留供引用的模块服务接口

2. 负载均衡核心模块MaoRoutingManager

使用ONOS提供的基础服务,加粗的是本应用重点使用的服务:


服 务


用 途


CoreService


注册应用模块,获取ApplicationId


IntentService


下发/撤销数据流的路由决策


TopologyService


获取网络当前拓扑


HostService


获取客户机的抽象对象Host


DeviceService


获取设备端口的抽象对象Port,从中获取端口的工作速率


PortStatisticsService


获取链路连接点ConnectPoint的当前发送速率


PacketService


添加/移除数据包处理器;

注册/撤销网络应上报的数据包的特征

从主模块MaoRoutingManager的角度看,模块内部设计和功能划分如下:

整体上划分为两个重要部分:

  • BandwidthLinkWeight:链路带宽度量值计算器。符合ONOS选路算法的设计规范。
  • InternalPacketProcessor:数据包处理器。包含流量处理的入口函数,以及本文路由算法所需的函数

a) BandwidthLinkWeight
这是一个工具类,实现了ONOS定义的LinkWeight接口,主要服务于选路算法函数,作用是计算指定链路的权值(Weight)。LinkWeight接口定义如下:

BandwidthLinkWeight的具体功能是计算链路当前剩余带宽所占的百分比,以此作为链路的权值。计算过程中需要获取链路的工作速率和当前速率。如果链路失效或链路容量已满,则返回最大值100%,意指链路满载。其实现如下:

/**
* Tool for calculating weight value for each Link(TopologyEdge).
*
* @author Mao.
*/
private class BandwidthLinkWeight implements LinkWeight {

    private static final double LINK_WEIGHT_DOWN = 100.0;
    private static final double LINK_WEIGHT_FULL = 100.0;

    @Override
    public double weight(TopologyEdge edge) {

        if (edge.link().state() == Link.State.INACTIVE) {
            return LINK_WEIGHT_DOWN;
        }

        long linkWireSpeed = getLinkWireSpeed(edge.link());

        long interLinkRestBandwidth = linkWireSpeed - getLinkLoadSpeed(edge.link());

        if (interLinkRestBandwidth <= 0) {
            return LINK_WEIGHT_FULL;
        }

        // 当前剩余带宽百分比
        return 100 - interLinkRestBandwidth * 1.0 / linkWireSpeed * 100;
    }

    ...

}

其中使用到以下四个辅助函数:

  • getLinkWireSpeed:返回链路的工作速率;暂定以两端工作速率的最小值作为链路工作速率。
  • getLinkLoadSpeed:返回链路的当前速率;暂定以两端发送速率的最大值作为链路当前速率。
  • getPortWireSpeed:获取端口的工作速率;
  • getPortLoadSpeed:获取端口的当前发送速率。
private long getLinkWireSpeed(Link link) {

    long srcSpeed = getPortWireSpeed(link.src());
    long dstSpeed = getPortWireSpeed(link.dst());

    return min(srcSpeed, dstSpeed);
}

private long getLinkLoadSpeed(Link link) {

    long srcSpeed = getPortLoadSpeed(link.src());
    long dstSpeed = getPortLoadSpeed(link.dst());

    return max(srcSpeed, dstSpeed);
}

/**
* Unit: bps
*/
private long getPortLoadSpeed(ConnectPoint port) {

//data source: Bps
    return portStatisticsService.load(port).rate() * 8;
}

/**
* Unit bps
*/
private long getPortWireSpeed(ConnectPoint port) {
    assert port.elementId() instanceof DeviceId;

    //data source: Mbps
    return deviceService.getPort(port.deviceId(), port.port()).portSpeed() * 1000000;
}

b)InternalPacketProcessor
为了便于展示,暂时将负载均衡路由算法的入口函数和算法四步骤的相关函数[2]都移到了数据包处理器中。源码库中的包处理器只保留了process主函数,其余的都移到了主模块中。由于本算法可以作为独立的路由算法使用,因此可将负载均衡路由功能独立出来,作为本应用对外提供的一项服务,即添加相应的API在预留的MaoRoutingService模块服务接口中。

包处理器内部分为两部分。第一部分是流量处理的入口,以下省略了数据检查和并发同步的部分,只保留了关键逻辑的代码,完整源码可浏览Github仓库。

@Override
public void process(PacketContext context) {
    Ethernet pkt = context.inPacket().parsed();
    if (pkt.getEtherType() == Ethernet.TYPE_IPV4) {

        // 根据MAC生成主机标识ID
        HostId srcHostId = HostId.hostId(pkt.getSourceMAC());
        HostId dstHostId = HostId.hostId(pkt.getDestinationMAC());

        // 为两个主机的该条流量选择一条路由路径
        Set<Path> paths = getLoadBalancePaths(srcHostId, dstHostId);

        // 构造流量匹配域
        IPv4 ipPkt = (IPv4) pkt.getPayload();
        TrafficSelector selector = DefaultTrafficSelector.builder()
                .matchEthType(Ethernet.TYPE_IPV4)
                .matchIPSrc(IpPrefix.valueOf(ipPkt.getSourceAddress(), 32))
                .matchIPDst(IpPrefix.valueOf(ipPkt.getDestinationAddress(), 32))
                .build();

        // 使用任意一条路径结果
        Path result = paths.iterator().next();

        // 构造PathIntent路径意图
        PathIntent pathIntent = PathIntent.builder()
                .path(result)
                .appId(appId)
                .priority(40123)
                .selector(selector)
                .treatment(DefaultTrafficTreatment.emptyTreatment())
                .build();

        // 提交流量路径决策
        intentService.submit(pathIntent);
    }
}

第二部分是路由算法实现部分。以下是算法实现中所有函数的调用关系和算法流程图,请先关注右上方的图例。

图 1负载均衡路由算法的函数调用关系及算法流程图

先回忆一下在上一篇文章(见上文链接)中,笔者提到算法过程中几种结果集的名称:

可选路由路径 → 优选路由路径 → 最优路由路径

首先,本实现提供了两个便利的算法入口,可默认采用ONOS感知的实时拓扑进行路由计算,也可根据自定义的拓扑进行计算。

其次,在第一步的探路过程中,暂时使用DFS深度优先查找算法,进行递归查找,同时在算法实现中考虑了路由环路的预防。此处使用到ONOS对拓扑图的三个抽象TopologyGragh、TopologyEdge和TopologyVertex,分别表示图、边和顶点。

第二步,算权值。借助BandwidthLinkWeight计算路径中每一条链路的权值,然后以最大的链路权值作为该条路径的权值。利用表征链路的各个TopologyEdge对象和算出的路径权值,生成ONOS中的路由路径抽象对象Path。

第三步,选路。如下图,首先通过getMinCostPath选出“优选路由路径”,再通过getMinHopPath选出“最优路由路径”。

图 2选路过程中的“优选” 和“选定”

第四步,铺路。在buildEdgeToEdgePath中将源点的第一跳链路与目的的第一跳链路分别接在最优路由路径的前后两端,并更新其路径权值。

参考文献

[1]ONOS 实战分享(一):项目建立、调试到热部署【http://www.sdnlab.com/15197.html

注:本项目开源在笔者的

时间: 2024-08-25 04:02:56

ONOS:负载均衡路由算法及应用开发(二)的相关文章

ONOS:负载均衡路由算法及应用开发(一)

一.应用介绍 当新流量发起时,本应用将为其选择一条路由路径,这条路径具有全局负载均衡意义上的最小权值(Weight/Cost).本应用即将开源在笔者的Github[https://github.com/MaoJianwei/ONOS_LoadBalance_Routing_Forward]本系列文章后续也将同步在笔者的博客Blog[http://maojianwei.github.io/] 为负载均衡举一个简单的例子,在一个三节点的环形网络中,Host2想要访问Host1,此时网络中已经有了一些

web服务器负载均衡与集群基本概念二

前面已经说过负载均衡的作用是在多个节点之间按照一定的策略(算法)分发网络或计算处理负载.负载均衡可以采用软件和硬件来实现.一般的框架结构可以参考下图.    后台的多个Web节点上面有相同的Web应用,用户的访问请求首先进入负载均衡分配节点(可能是软件或者硬件),由它根据负载均衡策略(算法)合理地分配给某个Web应用节点.每个Web节点相同的内容做起来不难,所以选择负载均衡策略(算法)是个关键问题.下面会专门介绍均衡算法. web负载均衡的作用就是把请求均匀的分配给各个节点,它是一种动态均衡,通

负载均衡各个算法JAVA诠释版

00 前言 首先给大家介绍下什么是负载均衡(来自百科) 负载均衡建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展 网络设备和 服务器的带宽.增加 吞吐量.加强网络数据处理能力.提高网络的灵活性和可用性. 负载均衡,英文名称为Load Balance,其意思就是分摊到多个操作单元上进行执行,例如Web 服务器. FTP服务器. 企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务. 本文讲述的是"将外部发送来的请求均匀分配到对称结构中的某一台服务器上"的各种算法,并以

关于haproxy负载均衡的算法整理

目前haproxy支持的负载均衡算法有如下8种 1.roundrobin 表示简单的轮询,每个服务器根据权重轮流使用,在服务器的处理时间平均分配的情况下这是最流畅和公平的算法.该算法是动态的,对于实例启动慢的服务器权重会在运行中调整. 2.leastconn 连接数最少的服务器优先接收连接.leastconn建议用于长会话服务,例如LDAP.SQL.TSE等,而不适合短会话协议.如HTTP.该算法是动态的,对于实例启动慢的服务器权重会在运行中调整. 3.static-rr 每个服务器根据权重轮流

使用Nginx负载均衡搭建高性能.NETweb应用程序二

在文章<使用Nginx负载均衡搭建高性能.NETweb应用程序一>中,让我们对Nginx有了一个初步认识,下面我们将在windows平台下面使用Nginx演示集群部署我们的web应用. 一.下载Nginx部署包 到Nginx官网去下载一个windows平台下面的Nginx部署包,目前我下载的是一个nginx-1.6.2版本的. 二.命令启动服务 启动:start nginx.exe 停止:nginx -s stop 重新加载: nginx -s reload 三.实例搭建 首 选:我们要在我们

那些NB哄哄的负载均衡算法到底是什么样子的?

前言 在软件系统的架构设计中,对集群的负载均衡设计是作为高性能系统优化环节中必不可少的方案.负载均衡本质上是用于将用户流量进行均衡减压的,因此在互联网的大流量项目中,其重要性不言而喻. 一.什么是负载均衡? 早期的互联网应用,由于用户流量比较小,业务逻辑也比较简单,往往一个单服务器就能满足负载需求.随着现在互联网的流量越来越大,稍微好一点的系统,访问量就非常大了,并且系统功能也越来越复杂,那么单台服务器就算将性能优化得再好,也不能支撑这么大用户量的访问压力了,这个时候就需要使用多台机器,设计高性

实现负载均衡的基本算法

平衡算法设计的好坏直接决定了集群在负载均衡上的表现,设计不好的算法,会导致集群的负载失衡.一般的平衡算法主要任务是决定如何选择下一个集群节点,然后将新的服务请求转发给它.有些简单平衡方法可以独立使用,有些必须和其它简单或高级方法组合使用.而一个好的负载均衡算法也并不是万能的,它一般只在某些特殊的应用环境下才能发挥最大效用.因此在考察负载均衡算法的同时,也要注意算法本身的适用面,并在采取集群部署的时候根据集群自身的特点进行综合考虑,把不同的算法和技术结合起来使用. 一.轮转法: 轮转算法是所有调度

负载均衡的那些算法们

上周发了问卷,想了解一下大家对老王有没有什么建议,然后好多朋友都投了票,想了解编程技术和服务器架构的干货,所以接下来会先聊聊编程和架构相关的算法,然后大概在6月下旬会跟大家聊聊面试那些事儿(老王到目前大约参加了几百次的面试,可以从面试官的角度来聊聊不一样的面试).老王聊技术有个特点,就是绝不假大空,只求贴地飞行.所以,聊的东西一定会跟实际有关联,大家在平时也有可能用得着. 今天跟大伙儿聊的是负载均衡相关的一些算法.老王在百度的时候(估计是5-6年前),写过一个通用的基础库(不知道现在还有没有部门

负载均衡基础(经常使用)算法

从这个博客转载: http://blog.csdn.net/u014649204/article/details/25115039 平衡算法设计的好坏直接决定了集群在负载均衡上的表现,设计不好的算法,会导致集群的负载失衡.一般的平衡算法主要任务是决定怎样选择下一个集群节点.然后将新的服务请求转发给它.有些简单平衡方法能够独立使用,有些必须和其他简单或高级方法组合使用.而一个好的负载均衡算法也并非万能的,它一般仅仅在某些特殊的应用环境下才干发挥最大效用.因此在考察负载均衡算法的同一时候.也要注意算