2019SDN大作业——负载均衡
2019SDN大作业——负载均衡
一、小组成员及贡献比例
学号 | 姓名 | 贡献比例 | 分工 |
---|---|---|---|
031702423 | 李欣凯 | 22% | 负责大纲规划,代码编写,运行 |
031702430 | 陈友昆 | 24% | 负责代码编写,运行,以及博客撰写 |
031702432 | 翁世豪 | 18% | 负责代码编写,运行 |
031702429 | 陈功贤 | 18% | 负责代码编写,运行 |
031702444 | 李尚佳 | 18% | 负责代码编写,运行 |
二、实验场景
1.负载均衡方法的原理以及目的:
负载均衡(Load Balance)的意思是指将负载(工作任务)进行平衡、分摊到多个操作单元上进行运行,例如FTP服务器、Web服务器、企业核心应用服务器和其它主要任务服务器等,从而协同完成工作任务。如果存在根多的数据包同时通过网络连向一台服务器, 也就是网络的速度比网络所连接的设备速度快的情况下,负载均衡技术是解决这个问题的有效方式。负载均衡是一种扩展现有网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性的技术。
2.负载均衡场景:
拓扑结构如下所示:
在此拓扑结构中,h1是客户端,服务器端h2 ,h3,h4上各自有不同的服务。我们要实现一个负载均衡的北向程序,当h2,h1,h3向h1传输数据时,北向应用根据链路的使用状况动态的调整路由规则。例如:s1-s4链路带宽充足情况下应默认s4-s1的传输路径,当剩余带宽不足的情况下应动态调整路由,使链路负载达到平衡。
搭建拓扑的代码MyTopo.py如下所示:
from mininet.topo import Topo
class MyTopo( Topo ):
def __init__( self ):
# initilaize 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(host1,switch1)
self.addLink(switch1,switch2)
self.addLink(switch1,switch3)
self.addLink(switch1,switch4)
self.addLink(switch2,switch4)
self.addLink(switch3,switch4)
self.addLink(switch4,host2)
self.addLink(switch4,host3)
self.addLink(switch4,host4)
topos = { 'mytopo': ( lambda: MyTopo() ) }
三、实验具体操作
下发的流表项代码:
h1h4body1 ='{"flow": [{"id": "1","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.4/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "4"},"order": "0"}]}}]},'
'"priority": "101","cookie": "1","table_id": "0"}]}'
mh1h4body1 ='{"flow": [{"id": "1","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.4/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "4"},"order": "0"}]}}]},'
'"priority": "102","cookie": "1","table_id": "0"}]}'
h1h4body2 ='{"flow": [{"id": "5","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.4/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "2"},"order": "0"}]}}]},'
'"priority": "100","cookie": "5","table_id": "0"}]}'
mh1h4body2 ='{"flow": [{"id": "5","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.4/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "2"},"order": "0"}]}}]},'
'"priority": "102","cookie": "5","table_id": "0"}]}'
h1h4body3 ='{"flow": [{"id": "6","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.4/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "3"},"order": "0"}]}}]},'
'"priority": "99","cookie": "6","table_id": "0"}]}'
mh1h4body3 ='{"flow": [{"id": "6","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.4/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "3"},"order": "0"}]}}]},'
'"priority": "102","cookie": "6","table_id": "0"}]}'
h1h2body1 ='{"flow": [{"id": "1","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.2/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "4"},"order": "0"}]}}]},'
'"priority": "101","cookie": "1","table_id": "0"}]}'
mh1h2body1 ='{"flow": [{"id": "1","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.2/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "4"},"order": "0"}]}}]},'
'"priority": "102","cookie": "1","table_id": "0"}]}'
h1h2body2 ='{"flow": [{"id": "5","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.2/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "2"},"order": "0"}]}}]},'
'"priority": "100","cookie": "5","table_id": "0"}]}'
mh1h2body2 ='{"flow": [{"id": "5","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.2/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "2"},"order": "0"}]}}]},'
'"priority": "102","cookie": "5","table_id": "0"}]}'
h1h2body3 ='{"flow": [{"id": "6","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.2/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "3"},"order": "0"}]}}]},'
'"priority": "99","cookie": "6","table_id": "0"}]}'
mh1h2body3 ='{"flow": [{"id": "6","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.2/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "3"},"order": "0"}]}}]},'
'"priority": "102","cookie": "6","table_id": "0"}]}'
h1h3body1 ='{"flow": [{"id": "1","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.3/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "4"},"order": "0"}]}}]},'
'"priority": "101","cookie": "1","table_id": "0"}]}'
mh1h3body1 ='{"flow": [{"id": "1","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.3/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "4"},"order": "0"}]}}]},'
'"priority": "102","cookie": "1","table_id": "0"}]}'
h1h3body2 ='{"flow": [{"id": "5","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.3/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "2"},"order": "0"}]}}]},'
'"priority": "100","cookie": "5","table_id": "0"}]}'
mh1h3body2 ='{"flow": [{"id": "5","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.3/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "2"},"order": "0"}]}}]},'
'"priority": "102","cookie": "5","table_id": "0"}]}'
h1h3body3 ='{"flow": [{"id": "6","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.3/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "3"},"order": "0"}]}}]},'
'"priority": "99","cookie": "6","table_id": "0"}]}'
mh1h3body3 ='{"flow": [{"id": "6","match": {"ethernet-match":'
'{"ethernet-type": {"type": "2048"}},'
'"ipv4-source":"10.0.0.1/32","ipv4-destination": "10.0.0.3/32"},'
'"instructions": {"instruction": [{"order": "0",'
'"apply-actions": {"action": [{"output-action": {'
'"output-node-connector": "3"},"order": "0"}]}}]},'
'"priority": "102","cookie": "6","table_id": "0"}]}'
实现负载均衡的核心代码:
num=0
response, content = http.request(uri='http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:1/flow-node-inventory:table/0/flow/0', body=s1_2To1, method='PUT',headers=headers)
response, content = http.request(uri='http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:1/flow-node-inventory:table/0/flow/1', body=s1_3To1, method='PUT',headers=headers)
response, content = http.request(uri='http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:3/flow-node-inventory:table/0/flow/0', body=s3_1, method='PUT',headers=headers)
response, content = http.request(uri='http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:3/flow-node-inventory:table/0/flow/0', body=s3_2, method='PUT',headers=headers)
response, content = http.request(uri='http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:2/flow-node-inventory:table/0/flow/0', body=h2_to_s2_1, method='PUT',headers=headers)
while num < 4 :
s1_uri = 'http://127.0.0.1:8181/restconf/operational/opendaylight-inventory:nodes/node/openflow:1/node-connector/openflow:1:2'
s2_uri = 'http://127.0.0.1:8181/restconf/operational/opendaylight-inventory:nodes/node/openflow:2/node-connector/openflow:2:1'
response, content = http.request(uri=s1_uri, method='GET')
content = json.loads(content.decode())
statistics = content['node-connector'][0]['opendaylight-port-statistics:flow-capable-node-connector-statistics']
s1_bytes1 = statistics['bytes']['transmitted']
time.sleep(0.5)
response, content = http.request(uri=s1_uri, method='GET')
content = json.loads(content.decode())
statistics = content['node-connector'][0]['opendaylight-port-statistics:flow-capable-node-connector-statistics']
s1_bytes2 = statistics['bytes']['transmitted']
s1_speed=float(s1_bytes2-s1_bytes1)/0.5
if s1_speed !=0 :
print ('s1端口2速度:')
print (s1_speed)
if s1_speed < 1000 :
print(' s1端口2空闲,h1数据包改为往s1端口2通过')
response, content = http.request(uri='http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:1/flow-node-inventory:table/0/flow/2', body=h1_to_s1_2, method='PUT',headers=headers)
response, content = http.request(uri='http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:1/flow-node-inventory:table/0/flow/3', body=mh1_to_s1_2, method='PUT',headers=headers)
else :
print(' s1端口2满载,h1数据包改为往s1端口3通过')
response, content = http.request(uri='http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:1/flow-node-inventory:table/0/flow/2', body=h1_to_s1_3, method='PUT',headers=headers)
response, content = http.request(uri='http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:1/flow-node-inventory:table/0/flow/3', body=mh1_to_s1_3, method='PUT',headers=headers)
response, content = http.request(uri=s2_uri, method='GET')
content = json.loads(content.decode())
statistics = content['node-connector'][0]['opendaylight-port-statistics:flow-capable-node-connector-statistics']
s2_bytes1 = statistics['bytes']['transmitted']
time.sleep(0.5)
response, content = http.request(uri=s2_uri, method='GET')
content = json.loads(content.decode())
statistics = content['node-connector'][0]['opendaylight-port-statistics:flow-capable-node-connector-statistics']
s2_bytes2 = statistics['bytes']['transmitted']
s2_speed=float(s2_bytes2-s2_bytes1)/0.5
if s2_speed !=0 :
print ('s2端口1速度:')
print (s2_speed)
if s2_speed < 1000 :
print(' s2端口1空闲,h3数据包改为往s2端口1通过')
response, content = http.request(uri='http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:2/flow-node-inventory:table/0/flow/1', body=h3_to_s2_1, method='PUT',headers=headers)
response, content = http.request(uri='http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:2/flow-node-inventory:table/0/flow/2', body=mh3_to_s2_2, method='PUT',headers=headers)
else :
print(' s2端口1满载,h3数据包改为往s2端口2通过')
response, content = http.request(uri='http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:2/flow-node-inventory:table/0/flow/1', body=mh3_to_s2_1, method='PUT',headers=headers)
response, content = http.request(uri='http://127.0.0.1:8181/restconf/config/opendaylight-inventory:nodes/node/openflow:2/flow-node-inventory:table/0/flow/2', body=h3_to_s2_2, method='PUT',headers=headers)
具体操作步骤:
(1)在创建拓扑前,先打开opendaylight控制器:
(2)执行MyTopo.py脚本,创建拓扑,并查看拓扑结构:
(3)测试主机之间的连通性:
(4)使用iperf命令测试带宽,查看拥塞状况:
(5)调用负载均衡程序controller1.py,并执行:
(6)调用负载均衡后的结果如下所示:
(7)查看交换机s1、s2、s3、s4的流表项:
四、实验感悟:
陈友昆:通过本学期SDN的课程学习,让我收获了很多新的知识,尤其是通过SDN的实践课,我更是掌握了不少新的技术,比如mininet的使用、如何编写py脚本创建具体的拓扑结构、opendaylight控制器、ryu控制器的基本原理及使用方法、p4语言的使用等等,从每次安装时的焦头烂额,到完成实验任务的喜悦与自豪,让我有了很大的成就感。在学习SDN这门课之前,我对网络编程真的是一窍不通,但通过这学期的学习,虽然我对SDN的掌握还不够完全和深入,但是我对它有了一个总体的清晰的框架,为我日后的学习提供了很大的帮助。
陈功贤:通过本学期SDN的课程学习,让我收获了很多新的知识, 包括Openflow、mininet、floodlight、opendaylight,学会了如何使用openflow的北向接口进行应用场景的实现。用mininet来通过python脚本来建立拓扑结构,用ovs-ofctl来管理流表项。学会了使用floodlight和odl控制器,虽然只是整个SDN的冰山一角,但也感受到了sdn对于网络控制的便捷性和灵活性。虽然以后不一定会走网络编程这条路,但通过这次课程让我们了解到这些前沿的内容,对将来无疑是有极大的帮助。
李欣凯:在本学期的SDN学习中,我学习到了许多在从前学习生活中未学习到的软件定义网络技术,比如mininet的使用、如何编写py脚本创建具体的拓扑结构、opendaylight控制器、ryu控制器的基本原理及使用方法、p4语言的使用等等,我深感自己能力上的不足,仍需努力学习,虚心向老师请教SDN方面的内容,为今后的学业而奋斗。
翁世豪:本学期SDN的学习包括了每周一节的理论课部分,每周一节的实践课部分,还有最后的负载均衡实践大作业,这样的配合我觉得非常好,理论结合实际,并让我们灵活运行所学习的知识,在这门课上,我学习到了关于SDN的这些先进的技术和工具,这些都是我以前几乎没有接触过的,在安装使用这些工具的时候,总是会遇到各种各样的困难,好在都有老师助教同学们的帮助,我才最终一个个完成了这个工具的使用,完成实验的时候总数充满了喜悦,这个掌握新知识新技术的感觉非常好。通过这门课的学习我觉得我有了巨大的收获并且它将助力我今后的学习。
李尚佳:通过本学期SDN的课程学习,接触到了比较前沿的与SDN相关的新概念和新知识,而且通过实践加深了对它们的理解。在课程事件中,熟悉了mininet的使用、编写py脚本创建具体的拓扑结构、ODL控制器的基本原理和使用方法、 通过Postman用json通过ODL的北向接口下发流表以及查看流表 、 使用wireshark抓包以及获取有用的数据、 ryu控制器的基本原理及使用技巧、数据平面可编程p4语言的使用等等。虽然大部分都是简单了解,但是学习到了SDN的前沿知识,受益匪浅。