切换负载平衡动态主机拓扑
Switch load balancing dynamic host topology
下面是在mininet中搭建网络的代码,每台主机运行一个客户端程序(即通过hx.cmd('python pyexample.py')
),每台服务器运行一个服务器程序哪些客户端将连接到。
首先,我把所有的主机都连接到了交换机上,有的是服务器,有的是主机。当 hosts/clients/servers 的数量不固定时,如何让此开关充当 负载平衡器 ?
其次,在多个客户端向单个服务器发送请求的情况下,如何让客户端和服务器相互连接并将结果return发送给单个客户端?
#!/usr/bin/python
from mininet.topo import Topo
from mininet.net import Mininet
from mininet.util import dumpNodeConnections
from mininet.log import setLogLevel
import math
# num_hosts = number of servers + clients
# network with n hosts connected to one switch
class NetworkTopology(Topo, num_hosts, num_servers):
clients = []
servers = []
def build(self, n=num_hosts):
# Switch controlled to act as load balancer
# TODO: Write controller
switch = self.addSwitch('s1')
# Generate 0..n-1 hosts - n = num_hosts
for h in range(n):
s = 0
while s < num_servers:
# Add server to the topology
server = self.addHost('server%s' % (s+1))
self.addLink(server, switch)
servers.append(server)
else:
# Add client to the topology
client = self.addHost('client%s' % ((h-s)+1))
self.addLink(host, switch)
clients.append(client)
def runTest(num_hosts, num_servers, num_levels, num_base_reports):
topo = NetworkTopology(num_hosts, num_servers)
# Main function
if __name__ == '__main__':
setLogLevel('info')
num_base_reports = 100
num_levels = math.log(num_base_reports, 10) # log to base 10
num_hosts = round(4**(math.log(num_base_reports-1, 10)))
num_servers = round(2**(math.log(num_base_reports-1, 10)))
runTest(num_hosts, num_servers num_levels, num_base_reports)
编辑:
下面是我用于客户端和服务器 Java 程序之间的套接字的代码,它们将在拓扑中的相应客户端和服务器主机上 运行。
服务器:
public class Server
{
// Server socket
protected ServerSocket serverSocket;
// Server port
public static final int PORT = 3000;
public Server() throws IOException {
this.serverSocket = new ServerSocket(PORT);
}
public ServerSocket getSocket() {
return serverSocket;
}
public static void main(String[] args) {
try {
Server server = new Server();
while(true) {
// Get client socket
Socket socket = server.getSocket().accept();
new ClientThread(socket, server).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
ClientThread:
public class ClientThread extends Thread
{
private Socket socket;
private static PDP server;
public ClientThread(Socket sock, PDP server) {
this.socket = sock;
this.server = server;
}
public void run() {
InputStream is = null;
BufferedReader br = null;
DataOutputStream dos = null;
try {
is = socket.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
dos = new DataOutputStream(socket.getOutputStream());
String request;
while(true) {
if((request = br.readLine()) != null) {
// Read request
// -- snip --
String response = "Done!";
// Send back response
dos.writeBytes(response + "\n\r");
dos.flush();
} else {
socket.close();
System.out.println("Client Disconnected\n\r");
return;
}
}
} catch (IOException e) {
return;
}
}
}
客户:
public class Client
{
protected static final int PORT = 3000;
public Client() {
}
public static void main(String[] args) {
try {
Socket sock = new Socket("127.0.0.1", PORT);
// Output Stream (sending to server)
OutputStream os = sock.getOutputStream();
PrintWriter pw = new PrintWriter(os, true);
// Input Stream (receiving from server)
InputStream is = sock.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String request, response;
while(true) {
request = "MyRequest!";
pw.println(request);
if((response = br.readLine()) != null) {
System.out.println(response);
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
如您所知,在 SDN 中发生了一些新的事情;是的!数据平面和控制平面分离!所以你必须使用控制器在你的网络中构建负载平衡功能。 SDN 控制器和交换机使用 OpenFlow 或另一个南向 API 来相互连接。防火墙、NATing、负载平衡等网络功能将在控制器软件上实现。
控制器有多种选择,如ONOS、OpenDaylight、Floodlight、RYU等。如果你在python中编写代码很容易,也许你最好选择RYU controller,因为其他提到的控制器都是基于java的。
您可以找到在 RYU 控制器顶部实现简单循环负载平衡应用程序的示例代码:
https://github.com/omi-uulm/openflow-loadbalancer/blob/master/load_balancer.py
您应该在第 131 行和此块中添加您的代码:
您必须在第 131 行之后和以下 elif 块中添加您的代码:
elif ip.proto == 0x06: # Resolve TCP
例如这样的事情:
elif ip.proto == 0x06: # Resolve TCP
if pkt_tcp.src_port == 3000: # Ignore packets from server when creating rule
return
ip_src = ip.src
# if ip of client has been learned (flow installed), no need to process
# helps with burst of traffic that creates duplicate flows
if ip_src in self.ip_to_mac:
return
out_port = self.net.servers[self.rr_counter].port
mac_dest = self.net.servers[self.rr_counter].mac
ip.dst = self.net.lb_ip
# Forward Received TCP Packet to the selected Server
p = packet.Packet()
p.add_protocol(ethernet.ethernet(dst=mac_dest, src=src, ethertype=ether_types.ETH_TYPE_IP))
p.add_protocol(ip)
p.add_protocol(pkt_tcp)
self.send_packet(p, msg, datapath, out_port)
# Add Flow Entry
match = datapath.ofproto_parser.OFPMatch(in_port=msg.in_port, dl_type=0x0800,
nw_proto=0x06, nw_src=ip_src, nw_dst=self.net.lb_ip)
actions = [parser.OFPActionSetDlDst(mac_dest), parser.OFPActionOutput(out_port)]
self.add_flow(match, actions)
# Insert reverse flow
match = datapath.ofproto_parser.OFPMatch(in_port=out_port, dl_type=0x0800,
nw_proto=0x06, nw_src=self.net.lb_ip, nw_dst=ip_src)
actions = [parser.OFPActionSetDlSrc(self.net.lb_mac), parser.OFPActionOutput(msg.in_port)]
self.add_flow(match, actions)
# Update ARP table
self.ip_to_mac.update({ip_src: src})
# Update RR counter
self.rr_counter = (self.rr_counter + 1) % self.net.servers_num
不要忘记在 network_setup.py class.
中添加您的 lb 和服务器 Mac 以及 IP
可能以这种方式帮助您的其他资源:
下面是在mininet中搭建网络的代码,每台主机运行一个客户端程序(即通过hx.cmd('python pyexample.py')
),每台服务器运行一个服务器程序哪些客户端将连接到。
首先,我把所有的主机都连接到了交换机上,有的是服务器,有的是主机。当 hosts/clients/servers 的数量不固定时,如何让此开关充当 负载平衡器 ?
其次,在多个客户端向单个服务器发送请求的情况下,如何让客户端和服务器相互连接并将结果return发送给单个客户端?
#!/usr/bin/python
from mininet.topo import Topo
from mininet.net import Mininet
from mininet.util import dumpNodeConnections
from mininet.log import setLogLevel
import math
# num_hosts = number of servers + clients
# network with n hosts connected to one switch
class NetworkTopology(Topo, num_hosts, num_servers):
clients = []
servers = []
def build(self, n=num_hosts):
# Switch controlled to act as load balancer
# TODO: Write controller
switch = self.addSwitch('s1')
# Generate 0..n-1 hosts - n = num_hosts
for h in range(n):
s = 0
while s < num_servers:
# Add server to the topology
server = self.addHost('server%s' % (s+1))
self.addLink(server, switch)
servers.append(server)
else:
# Add client to the topology
client = self.addHost('client%s' % ((h-s)+1))
self.addLink(host, switch)
clients.append(client)
def runTest(num_hosts, num_servers, num_levels, num_base_reports):
topo = NetworkTopology(num_hosts, num_servers)
# Main function
if __name__ == '__main__':
setLogLevel('info')
num_base_reports = 100
num_levels = math.log(num_base_reports, 10) # log to base 10
num_hosts = round(4**(math.log(num_base_reports-1, 10)))
num_servers = round(2**(math.log(num_base_reports-1, 10)))
runTest(num_hosts, num_servers num_levels, num_base_reports)
编辑:
下面是我用于客户端和服务器 Java 程序之间的套接字的代码,它们将在拓扑中的相应客户端和服务器主机上 运行。
服务器:
public class Server
{
// Server socket
protected ServerSocket serverSocket;
// Server port
public static final int PORT = 3000;
public Server() throws IOException {
this.serverSocket = new ServerSocket(PORT);
}
public ServerSocket getSocket() {
return serverSocket;
}
public static void main(String[] args) {
try {
Server server = new Server();
while(true) {
// Get client socket
Socket socket = server.getSocket().accept();
new ClientThread(socket, server).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
ClientThread:
public class ClientThread extends Thread
{
private Socket socket;
private static PDP server;
public ClientThread(Socket sock, PDP server) {
this.socket = sock;
this.server = server;
}
public void run() {
InputStream is = null;
BufferedReader br = null;
DataOutputStream dos = null;
try {
is = socket.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
dos = new DataOutputStream(socket.getOutputStream());
String request;
while(true) {
if((request = br.readLine()) != null) {
// Read request
// -- snip --
String response = "Done!";
// Send back response
dos.writeBytes(response + "\n\r");
dos.flush();
} else {
socket.close();
System.out.println("Client Disconnected\n\r");
return;
}
}
} catch (IOException e) {
return;
}
}
}
客户:
public class Client
{
protected static final int PORT = 3000;
public Client() {
}
public static void main(String[] args) {
try {
Socket sock = new Socket("127.0.0.1", PORT);
// Output Stream (sending to server)
OutputStream os = sock.getOutputStream();
PrintWriter pw = new PrintWriter(os, true);
// Input Stream (receiving from server)
InputStream is = sock.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String request, response;
while(true) {
request = "MyRequest!";
pw.println(request);
if((response = br.readLine()) != null) {
System.out.println(response);
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
如您所知,在 SDN 中发生了一些新的事情;是的!数据平面和控制平面分离!所以你必须使用控制器在你的网络中构建负载平衡功能。 SDN 控制器和交换机使用 OpenFlow 或另一个南向 API 来相互连接。防火墙、NATing、负载平衡等网络功能将在控制器软件上实现。
控制器有多种选择,如ONOS、OpenDaylight、Floodlight、RYU等。如果你在python中编写代码很容易,也许你最好选择RYU controller,因为其他提到的控制器都是基于java的。
您可以找到在 RYU 控制器顶部实现简单循环负载平衡应用程序的示例代码:
https://github.com/omi-uulm/openflow-loadbalancer/blob/master/load_balancer.py
您应该在第 131 行和此块中添加您的代码:
您必须在第 131 行之后和以下 elif 块中添加您的代码:
elif ip.proto == 0x06: # Resolve TCP
例如这样的事情:
elif ip.proto == 0x06: # Resolve TCP
if pkt_tcp.src_port == 3000: # Ignore packets from server when creating rule
return
ip_src = ip.src
# if ip of client has been learned (flow installed), no need to process
# helps with burst of traffic that creates duplicate flows
if ip_src in self.ip_to_mac:
return
out_port = self.net.servers[self.rr_counter].port
mac_dest = self.net.servers[self.rr_counter].mac
ip.dst = self.net.lb_ip
# Forward Received TCP Packet to the selected Server
p = packet.Packet()
p.add_protocol(ethernet.ethernet(dst=mac_dest, src=src, ethertype=ether_types.ETH_TYPE_IP))
p.add_protocol(ip)
p.add_protocol(pkt_tcp)
self.send_packet(p, msg, datapath, out_port)
# Add Flow Entry
match = datapath.ofproto_parser.OFPMatch(in_port=msg.in_port, dl_type=0x0800,
nw_proto=0x06, nw_src=ip_src, nw_dst=self.net.lb_ip)
actions = [parser.OFPActionSetDlDst(mac_dest), parser.OFPActionOutput(out_port)]
self.add_flow(match, actions)
# Insert reverse flow
match = datapath.ofproto_parser.OFPMatch(in_port=out_port, dl_type=0x0800,
nw_proto=0x06, nw_src=self.net.lb_ip, nw_dst=ip_src)
actions = [parser.OFPActionSetDlSrc(self.net.lb_mac), parser.OFPActionOutput(msg.in_port)]
self.add_flow(match, actions)
# Update ARP table
self.ip_to_mac.update({ip_src: src})
# Update RR counter
self.rr_counter = (self.rr_counter + 1) % self.net.servers_num
不要忘记在 network_setup.py class.
中添加您的 lb 和服务器 Mac 以及 IP可能以这种方式帮助您的其他资源: