为什么80%的码农都做不了架构师?>>>   

编者按:本文介绍的是如何在RYU上通过使用select group 来实现multipath,从而实现流量的调度,完成简单的负载均衡Demo。在OpenFlow13中有group table,可用于实现组播和冗余容灾等功能。实验中还使用了OpenvSwitch的队列queue完成了对链路带宽的保障。

要完成多径传输,那么网络拓扑必然有loop,所以首先要解决由于loop而可能产生的storm,解决方案在《基于SDN的RYU应用开发之ARP代理》文中已经提出。

网络拓扑:

"""Custom loop topo example

There are two paths between host1 and host2.

|--------switch2 --------|

|                        |

host1 --- switch1                   switch4 -----host2

|                        |   |------host3

-------- switch3 ---------

|

host4

Adding the 'topos' dict with a key/value pair to generate our newly defined

topology enables one to pass in '--topo=mytopo' from the command line.

"""

from mininet.topo import Topo

class MyTopo(Topo):

"Simple loop topology example."

def __init__(self):

"Create custom loop topo."

# Initialize topology

Topo.__init__(self)

# Add hosts and switches

host1 = self.addHost('h1')

host2 = self.addHost('h2')

host3 = self.addHost('h3')

#host4 = self.addHost('h4')

switch1 = self.addSwitch("s1")

switch2 = self.addSwitch("s2")

switch3 = self.addSwitch("s3")

switch4 = self.addSwitch("s4")

# Add links

self.addLink(switch1, host1, 1)

self.addLink(switch1, switch2, 2, 1)

self.addLink(switch1, switch3, 3, 1)

self.addLink(switch2, switch4, 2, 1)

self.addLink(switch3, switch4, 2, 2)

self.addLink(switch4, host2, 3)

self.addLink(switch4, host3, 4)

#self.addLink(switch3, host4, 3)

topos = {'mytopo': (lambda: MyTopo())}

Multipath:

解决网络可能形成风暴的问题之后,可以使用select类型的group_table来实现多径功能。

def send_group_mod(self, datapath):

ofp = datapath.ofproto

ofp_parser = datapath.ofproto_parser

port_1 = 3

actions_1 = [ofp_parser.OFPActionOutput(port_1)]

port_2 = 2

actions_2 = [ofp_parser.OFPActionOutput(port_2)]

weight_1 = 50

weight_2 = 50

watch_port = ofproto_v1_3.OFPP_ANY

watch_group = ofproto_v1_3.OFPQ_ALL

buckets = [

ofp_parser.OFPBucket(weight_1, watch_port, watch_group, actions_1),

ofp_parser.OFPBucket(weight_2, watch_port, watch_group, actions_2)]

group_id = 50

req = ofp_parser.OFPGroupMod(

datapath, ofp.OFPFC_ADD,

ofp.OFPGT_SELECT, group_id, buckets)

datapath.send_msg(req)

不知道现在OVS的select的key是否已经改变,原先的key为dl_dst。匹配成功的flow,在执行select时,是以dl_dst为key,进行判断,从而从buckets中选择一个action_list。

查看组表信息:

sudo ovs-ofctl dump-groups s1 -O OpenFlow13

查看流表信息:

sudo ovs-ofctl dump-flows s1 -O OpenFlow13

QoS:

首先我们知道OpenFlow无法创建队列。所以我们可以通过ovsdb来配置队列,也可以直接使用ovs命令配置:

ovs-vsctl -- set Port s1-eth2 qos=@newqos \

-- --id=@newqos create QoS type=linux-htb other-config:max-rate=250000000 queues=0=@q0\

-- --id=@q0 create Queue other-config:min-rate=8000000 other-config:max-rate=150000000\

ovs-vsctl -- set Port s1-eth3 qos=@defaultqos\

-- --id=@defaultqos create QoS type=linux-htb other-config:max-rate=300000000 queues=1=@q1\

-- --id=@q1 create Queue other-config:min-rate=5000000 other-config:max-rate=200000000

ovs-vsctl list queue

以上代码在s1-eth2上创建了queue 0,在s1-eth3上创建了queue 0和queue 1。并配置了max_rate和min_rate。

查看queue的信息可以使用:

sudo ovs-ofctl queue-stats s1 2  -O OpenFlow13

列举port查看qos:

ovs-vsctl list port

列举queue:

ovs-vsctl list queue

删除QOS:

sudo ovs-vsctl --all destroy qos

sudo ovs-vsctl --all destroy queue

区别于OpenFlow1.0, OpenFlow1.3中的入队操作只有一个queue_id,需要额外指定port。即指定数据如某一个队列的话需要如下的actions:

actions_2 = [ofp_parser.OFPActionSetQueue(0), ofp_parser.OFPActionOutput(port_2)]

所以使用group的情况下,完成QoS功能函数如下:

def send_group_mod(self, datapath):

ofp = datapath.ofproto

ofp_parser = datapath.ofproto_parser

port_1 = 3

queue_1 = ofp_parser.OFPActionSetQueue(0)

actions_1 = [queue_1, ofp_parser.OFPActionOutput(port_1)]

port_2 = 2

queue_2 = ofp_parser.OFPActionSetQueue(0)

actions_2 = [queue_2, ofp_parser.OFPActionOutput(port_2)]

weight_1 = 50

weight_2 = 50

watch_port = ofproto_v1_3.OFPP_ANY

watch_group = ofproto_v1_3.OFPQ_ALL

buckets = [

ofp_parser.OFPBucket(weight_1, watch_port, watch_group, actions_1),

ofp_parser.OFPBucket(weight_2, watch_port, watch_group, actions_2)]

group_id = 50

req = ofp_parser.OFPGroupMod(

datapath, ofp.OFPFC_ADD,

ofp.OFPGT_SELECT, group_id, buckets)

datapath.send_msg(req)

负载均衡:

从图中我们可以看到,pingall连通性没有问题。第一个iperf是在没有设置队列的情况下,由于找不到队列,所以不如队,只转发,此时带宽为26.4Gbits/sec。之后的测试数据为设置队列之后的数据。可以看出h1到h2之间的带宽是300Mbits/sec,而h1到h3的带宽是150Mbits/sec。

原因在于我们将h1到h2的数据流在组表中选择了s1-eth3的queue 0,而该队列的最大带宽是300M。

同时另一个从h1到h3的数据流,在hash过程中,选择了s1-eth2端口的queue 0,该队列的最大速度为150M。

下图为queue information:

可以看到,port 2 queue 0和port 3 queue 0有数据,而port 3 queue 1没有数据:

上图为s1和s4的组表和流表信息,从s4的流表信息(后部分流表)可知,同样是s1到s4的数据,dl_dst为h2的数据从port 2进入,而dl_dst为h3的数据从port 1进入,验证了数据传输过程使用了多径传输,合理利用了带宽空间。多径传输可以充分利用链路带宽,提高链路利用率。同时这个实验简单粗暴地完成了两条链路的负载均衡(将不同的数据流平均地分摊到了两条path上,由于对不同Path限制了不同的带宽,所以,流量并不是平均的)。根据拓扑及流量情况,添加算法计算合理流量路径,可以完成更灵活有效的负载均衡功能。

后语

这其实是简单的实验,但是由于在安装OVS的过程中遇到了很多的问题,所以过程比较痛苦,写下来,以备不时之需,也有可能帮助到别人吧。提供一个纯从OVS上配置的方案,相比之下比开发控制要简单一些。之前的博文的名字是:Multipath and QoS Application on RYU,但是后来导师提醒Multipath 和QoS不是一个层面的,才发现自己学识粗浅。需要努力的地方还太多。所以本篇博文被我生生改成Load balance的题目,虽然很牵强,但是相比之下,犯的错误更少一些。源码没有全部贴出来是因为我写的APP也可以出售的。后续应该会上传Github。详情可以邮件沟通。

折叠版代码如下:

# Author:muzixing

# Time:2014/10/19

#

from ryu.base import app_manager

from ryu.controller import ofp_event

from ryu.controller.handler import CONFIG_DISPATCHER

from ryu.controller.handler import MAIN_DISPATCHER, HANDSHAKE_DISPATCHER

from ryu.controller.handler import set_ev_cls

from ryu.ofproto import ofproto_v1_3

from ryu.lib.packet import packet

from ryu.lib.packet import ethernet

from ryu.lib.packet import arp

from ryu.lib.packet import ipv4

from ryu.lib.packet import icmp

from ryu import utils

from ryu.lib import addrconv

import struct

import socket

ETHERNET = ethernet.ethernet.__name__

ETHERNET_MULTICAST = "ff:ff:ff:ff:ff:ff"

ARP = arp.arp.__name__

ICMP = icmp.icmp.__name__

IPV4 = ipv4.ipv4.__name__

def ip2long(ip):

return struct.unpack("!I", socket.inet_aton(ip))[0]

class MULTIPATH_13(app_manager.RyuApp):

OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]

def __init__(self, *args, **kwargs):

super(MULTIPATH_13, self).__init__(*args, **kwargs)

self.mac_to_port = {}

self.arp_table = {}

self.sw = {}

@set_ev_cls(ofp_event.EventOFPSwitchFeatures, CONFIG_DISPATCHER)

def switch_features_handler(self, ev):

datapath = ev.msg.datapath

ofproto = datapath.ofproto

parser = datapath.ofproto_parser

# install table-miss flow entry

#

# We specify NO BUFFER to max_len of the output action due to

# OVS bug. At this moment, if we specify a lesser number, e.g.,

# 128, OVS will send Packet-In with invalid buffer_id and

# truncated packet data. In that case, we cannot output packets

# correctly.

match = parser.OFPMatch()

actions = [parser.OFPActionOutput(ofproto.OFPP_CONTROLLER,

ofproto.OFPCML_NO_BUFFER)]

self.add_flow(datapath, 1, 0, match, actions)

def add_flow(self, datapath, hard_timeout, priority, match, actions):

ofproto = datapath.ofproto

parser = datapath.ofproto_parser

inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,

actions)]

mod = parser.OFPFlowMod(datapath=datapath, priority=priority,

hard_timeout=hard_timeout,

match=match, instructions=inst)

#print mod.__dict__

datapath.send_msg(mod)

@set_ev_cls(

ofp_event.EventOFPErrorMsg,

[HANDSHAKE_DISPATCHER, CONFIG_DISPATCHER, MAIN_DISPATCHER])

def error_msg_handler(self, ev):

msg = ev.msg

self.logger.debug(

'OFPErrorMsg received: type=0x%02x code=0x%02x '

'message=%s', msg.type, msg.code, utils.hex_array(msg.data))

@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)

def _packet_in_handler(self, ev):

...

def send_packet_out(self, msg, actions):

datapath = msg.datapath

ofproto = datapath.ofproto

parser = datapath.ofproto_parser

in_port = msg.match['in_port']

data = None

if msg.buffer_id == ofproto.OFP_NO_BUFFER:

data = msg.data

out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id,

in_port=in_port, actions=actions, data=data)

datapath.send_msg(out)

def arp_handler(self, header_list, datapath, in_port, msg_buffer_id)

...

def send_group_mod(self, datapath):

ofp = datapath.ofproto

ofp_parser = datapath.ofproto_parser

port_1 = 3

queue_1 = ofp_parser.OFPActionSetQueue(0)

actions_1 = [queue_1, ofp_parser.OFPActionOutput(port_1)]

port_2 = 2

queue_2 = ofp_parser.OFPActionSetQueue(0)

actions_2 = [queue_2, ofp_parser.OFPActionOutput(port_2)]

weight_1 = 50

weight_2 = 50

watch_port = ofproto_v1_3.OFPP_ANY

watch_group = ofproto_v1_3.OFPQ_ALL

buckets = [

ofp_parser.OFPBucket(weight_1, watch_port, watch_group, actions_1),

ofp_parser.OFPBucket(weight_2, watch_port, watch_group, actions_2)]

group_id = 50

req = ofp_parser.OFPGroupMod(

datapath, ofp.OFPFC_ADD,

ofp.OFPGT_SELECT, group_id, buckets)

datapath.send_msg(req)

注:基于RYU应用开发之负载均衡的代码已经放在github上,感兴趣的可以到github上获取应用。

作者简介:

李呈,2014/09-至今,北京邮电大学网络技术研究院 网络与交换技术国家重点实验室攻读硕士研究生

点击可以阅读原文

转载于:https://my.oschina.net/sdnlab/blog/397976

基于RYU应用开发之负载均衡(源码开放)相关推荐

  1. springcloud ribbon @LoadBalance负载均衡源码流程分析

    一.编写示例 1.服务端 pom.xml <properties><java.version>1.8</java.version><spring-cloud. ...

  2. CentOS 6.5 + Nginx 1.8.0 + PHP 5.6(with PHP-FPM) 负载均衡源码安装 之 (三)Nginx负载均衡配置...

    Nginx反向代理到单个PHP-FPM(PHP-FPM可位于不同机器) 0.首先,创建我们的网站根目录[注:须在PHP-FPM所在的那台机器创建](以后网站的代码放到此目录下): mkdir /opt ...

  3. 基于C#+SQLServer开发的餐饮管理系统源码

    淘源码:国内知名的免费源码下载平台 源码免费分享,需要源码学习可私信我. 技术框架:C# winFrom SQLServer 一.系统简介: 餐饮管理系统 使用C#+SqlServer数据库编写开发 ...

  4. 基于springBoot框架开发短视频去水印源码项目+IntelliJ IDEA运行测试+本地实现功能

    一:创建一个springboot的maven项目包 新建:File–new–project 下载1.8jdk 以及 Maven 我这里下载的是 Maven 3.6.1 GroupID是项目组织唯一的标 ...

  5. LVS详解及基于LVS实现web服务器负载均衡

    前言 LVS(Linux Virtual Server)Linux虚拟服务器,是一个虚拟的服务器集群系统.本项目在1998年5月由章文嵩博士成立,是中国国内最早出现的自由软件项目之一.通过LVS提供的 ...

  6. NGINX配置基于Node.js服务的负载均衡服务器

    NGINX配置基于Node.js服务的负载均衡服务器 本部署指南说明了如何使用NGINX开源和NGINX Plus在Node.js应用程序服务器池之间平衡HTTP和HTTPS通信.本指南中的详细说明适 ...

  7. 基于Nginx反向代理及负载均衡

    基于Nginx反向代理及负载均衡 参考:http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass 只要没有被启用,默认就是 ...

  8. 基于Zookeeper实现简易的负载均衡

    基于Zookeeper实现简易的负载均衡 完整代码在这里基于Zookeeper实现简易的负载均衡 以下是讲解 一. 要求 1. 编程题一: 在基于Netty的自定义RPC的案例基础上,进行改造.基于Z ...

  9. PHP开发的资产管理系统源码基于layuimini框架

    PHP开发的资产管理系统源码基于layuimini框架开发/用户管理/资产录入/资产查询源码说明:PHP开发的资产管理系统源码基于layuimini框架开发/用户管理/资产录入/资产查询,本源码全开源 ...

最新文章

  1. python3读取excel数据-Python3操作Excel文件(读写)的简单实例
  2. 物联网的发展之—Vecloud微云
  3. 华为手机截屏怎么截长图_华为手机竟然有6种截屏方法,你用过几种?3种以上的手机没白买...
  4. 精通移动端布局 - 概念篇 -
  5. linux关于防火墙的一些知识
  6. 钉钉微应用怎么进入_蓝凌携手钉钉走进越秀地产,零距离热聊企业数字化转型...
  7. linux网络编程(一)网络基础传输知识
  8. 企业实战(Jenkins+GitLab+SonarQube)_12_Jenkins+soanr服务器搭建和代码检查
  9. 收藏 | 在算法工程师的道路上,你掌握了什么概念或技术使你感觉自我提升突飞猛进?...
  10. C++ 实现把非静态成员函数作为回调函数(非static)
  11. java字符替换函数示例_Java字符串替换函数replace()用法解析
  12. matplotlib使用参考地址
  13. 小高考计算机知识点,小高考政治知识点总结.pdf
  14. postgresql 执行计划理解
  15. WSL2之gdb通过qemu调试ARM汇编(五)
  16. 【路径规划】基于matalb遗传算法机器人栅格地图避障路径规划【含Matlab源码 027期】
  17. TcaplusDB X 光与夜之恋|春暖花开之际与你相遇
  18. Unable to load DLL 'xxx.dll': 找不到指定的模块。 (Exception from HRESULT: 0x8007007E)
  19. 新冠免疫细胞培养、转染、核酸分析整合解决方案
  20. ES性能优化之查询优化笔记(一)

热门文章

  1. Android 4.0中振动控制
  2. 客户区和非客户区指的什么?窗口客户区和视图客户区的区别
  3. 数码管字体属于什么字体_photoshop里这方法就能知道图片上文字使用的是什么字体...
  4. Spring框架学习day_03:对于读取文件方式的补充/关于spring框架知识点的学习方式
  5. 直接操作游戏对象C#游戏开发
  6. android的文本框内容居中显示图片,DIV+CSS中让布局居中_背景图片居中_文字内容居中...
  7. android 按钮 叠加,android - 叠加层按钮在Android 4.3中不起作用 - 堆栈内存溢出
  8. abp angular 和mvc_使用.net core ABP和Angular模板构建博客管理系统(实现自己的业务逻辑)...
  9. 一级二级标题_考二级造价师有啥要求?
  10. 运营商线路细分_电信运营行业细分领域分析