Simulátor distribuované sítě

Užitečné odkazy

Distribuovaná síť

Distribuovaná síť obsahuje několik uzlů a komunikačních kanálů, které propojují jednotlivé uzly. Pomoci komunikačních kanálů mají uzly možnost zasílat a přijímat zprávy.

Distribuovaná síť o třech uzlech může vypadat následovně:

Topologii takové sítě můžeme zapsat stejně jako orientovaný graf:

1
2
3
4
5
TOPOLOGY = [
    [False, True, False],
    [False, False, True],
    [True, False, False]
]

Pokud se podíváme na uzel N1 vidíme, že obsahuje jeden vstupní a jeden výstupní kanál.

Každému uzlu je možné předat zdrojový kód, který má uzel vykonávat. V rámci tohoto zdrojového kódu jsou přístupny všechny komunikační kanály a název daného uzlu. Volitelně by mělo být možné zjistit název procesu z/do kterého komunikační kanál vede.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from multiprocessing import current_process

def function():
    """Function for node"""

    node = current_process()

    for connection in node.out_pipes:
        connection.send("Msg from node {}".format(node.name))

    for connection in node.in_pipes:
        connection.recv()

    time.sleep(2)

V prvním stádiu by měla knihovna fungovat následovně:

1
2
3
4
5
6
7
8
9
10
TOPOLOGY = [[False, True, False],
            [False, False, True],
            [True, False, False]]

# functions - pole funkci pro uzly, delky rovné počtu uzlů

NETWORK = Network(functions, TOPOLOGY)

NETWORK.start()
NETWORK.join()

Třída Network obsahuje následující metody:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Network():
    """Represents distributed network"""

    def __init__(self, functions, topology):
        pass

    def start(self):
        """Starts all nodes in the network"""
        pass

    def terminate(self):
        """Terminate all nodes in the network"""
        pass

    def kill(self):
        """Kill all nodes in the network"""
        pass

    def join(self):
        """Join all nodes in the network"""
        pass

Třída multiprocessing.Process

Reprezentuje aktivitu, která běží v samostatném procesu. Pro reprezentaci použijeme třídu Process s upravenou funkcionalitou. Více informací naleznete zde.

1
2
3
4
5
6
7
from multiprocessing import Process

class Node(Process):

    def __init__(self, name, function):
        Process.__init__(self, name=name, target=function)
        ...

Třída multiprocessing.Pipe

Komunikační kanál mezi dvěma procesy. Po vytvoření objektu Pipe je vrácena dvojice objektu Connection. První reprezentuje cílový uzel (můžeme pouze přijímat), druhý počáteční (může pouze odesílat). Objekt budeme vytvářet s parametrem duplex=False, ten zařídí, že komunikační kanál je jednosměrný. Více informací naleznete zde.

1
2
3
4
5
6
7
8
9
10
11
reciever, sender = Pipe(duplex=False)

...

# Odešleme zprávu
sender.send("Test")

...

# Příjmeme zprávu na druhém konci
reciever.recv()

Třída Node obsahuje následující metody:

1
2
3
4
5
6
7
8
9
10
11
12
class Node(Process):
    """Represents one node in the distributed network"""

    def __init__(self, name, function):
        Process.__init__(self, name=name, target=function)
        pass

    def add_in_pipe(self, pipe):
        pass

    def add_out_pipe(self, pipe):
        pass

Logování

V rámci multiprocessingu je možné používat globální logger. Použítí je vidět na příkladu:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import logging
import multiprocessing

LOGGER = multiprocessing.log_to_stderr()
LOGGER.setLevel(logging.INFO)

def function():
    """Function for node"""

    node = current_process()

    for output_node in node.out_pipes:
        output_node.send("Msg from node {}".format(node.name))

    for input_node in node.in_pipes:
        LOGGER.info("Node: {}, Msg: {}".format(node.name,
                                               input_node.recv()))

    time.sleep(2)

V pozdější verzi by měla knihovna umět logovat do souborů, názvy těchto souborů budou korespondovat s názvy uzlů. Více informací o logování v knihovně multiprocessing naleznete zde

Úkol
Naprogramujte základní verzi knihovny, která umožňí vytvořit distribuovaný systém na základně předané topologie. Knihovnu otestujte na jednoduchém příkladu, kdy každý uzel pošle informační zprávu sousedu.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
TOPOLOGY = [[False, True, False],
            [False, False, True],
            [True, False, False]]

Ukázkový log:

[INFO/0] child process calling self.run()
[INFO/1] child process calling self.run()
[INFO/0] Node: 0, Msg: Msg from node 1
[INFO/2] child process calling self.run()
[INFO/2] Node: 2, Msg: Msg from node 0
[INFO/1] Node: 1, Msg: Msg from node 2
[INFO/0] process shutting down
[INFO/0] process exiting with exitcode 0
[INFO/1] process shutting down
[INFO/2] process shutting down
[INFO/1] process exiting with exitcode 0
[INFO/2] process exiting with exitcode 0
[INFO/MainProcess] process shutting down