2012-09-20 10 views
34

Eksperymentując z typem gniazda ZeroMQ (mam na imię Pipeline), mam trudności ze zrozumieniem użyteczności tego wzorca. Jest to rachunek "równoważenia obciążenia".ZeroMQ Funkcja Push/Pull o użyteczności

Biorąc pod uwagę, że jeden serwer wysyła zadania do wielu pracowników, Push/Pull będzie równo przekazywał zadania między wszystkich klientów. 3 klientów i 30 zadań, każdy klient otrzymuje 10 zadań: klient1 otrzymuje zadania 1, 4, 7, ... klient2, 2, 5, ... i tak dalej. Słusznie. Dosłownie.

Jednak w praktyce często występuje niejednorodna kombinacja złożoności zadania lub zasobów obliczeniowych klienta (lub dostępności), a następnie ten wzór jest nieprawidłowy. Wszystkie zadania wydają się być zaplanowane z wyprzedzeniem, a serwer nie ma wiedzy na temat postępów klientów lub ich dostępności. Jeśli klient1 zostanie wyłączony, pozostałe zadania nie zostaną wysłane do innych klientów, ale pozostaną w kolejce do klienta1. Jeśli klient1 pozostaje wyłączony, zadania te nigdy nie zostaną obsłużone. I odwrotnie, jeśli klient szybciej przetwarza swoje zadania, nie otrzymuje dalszych zadań i pozostaje bezczynny, ponieważ pozostają zaplanowane dla innych klientów.

Używanie REQ/REP jest jednym z możliwych rozwiązań; zadania są następnie przydzielane tylko do dostępnego zasobu.

Więc czegoś mi brakuje? W jaki sposób można efektywnie stosować Push/Pull? Czy istnieje sposób radzenia sobie z asymetrią klientów, zadań itp. Z tym typem gniazda?

Dzięki!

Oto prosty przykład Python:

# server 

import zmq 
import time 

context = zmq.Context() 
socket = context.socket(zmq.PUSH) 
#socket = context.socket(zmq.REP) # uncomment for Req/Rep 

socket.bind("tcp://127.0.0.1:5555") 

i = 0 
time.sleep(1) # naive wait for clients to arrive 

while True: 
    #msg = socket.recv() # uncomment for Req/Rep 
    socket.send(chr(i)) 
    i += 1 
    if i == 100: 
    break 

time.sleep(10) # naive wait for tasks to drain 

.

# client 

import zmq 
import time 
import sys 

context = zmq.Context() 

socket = context.socket(zmq.PULL) 
#socket = context.socket(zmq.REQ) # uncomment for Req/Rep 

socket.connect("tcp://127.0.0.1:5555") 

delay = float(sys.argv[1]) 

while True: 
    #socket.send('')  # uncomment for Req/Rep 
    message = socket.recv() 
    print "recv:", ord(message) 
    time.sleep(delay) 

odpalić 3 klientów z parametrem opóźnienia na linii poleceń (czyli 1, 1 i 0,1), a następnie serwer, i zobaczyć, jak wszystkie zadania są równomiernie rozłożone. Następnie zabij jednego z klientów, aby zobaczyć, że pozostałe zadania nie są obsługiwane.

Odkomentuj wskazane linie, aby przełączyć je na gniazdo typu Req/Rep i obserwuj bardziej efektywny system równoważenia obciążenia.

Odpowiedz

47

To nie jest wyrównywacz obciążenia, było to błędne wyjaśnienie, które przez jakiś czas pozostawało w dokumentach 0MQ. Aby przeprowadzić równoważenie obciążenia, musisz uzyskać od pracowników informacje dotyczące ich dostępności. PUSH, podobnie jak DEALER, jest dystrybutorem typu round-robin. Jest przydatny ze względu na szybkość i prostotę. Nie potrzebujesz żadnego gadania, po prostu przepompuj zadania w dół i są one rozpylane do wszystkich dostępnych pracowników tak szybko, jak sieć może sobie z nimi poradzić.

Wzór jest przydatny, gdy wykonujesz naprawdę dużą liczbę małych zadań i gdy pracownicy przychodzą i odchodzą rzadko. Ten wzorzec nie jest dobry w przypadku większych zadań, które wymagają czasu, ponieważ wtedy potrzebna jest jedna kolejka, która wysyła nowe zadania tylko do dostępnych pracowników. Ma również anty-wzór, w którym jeśli klient wysyła wiele zadań, a następnie pracownicy łączą się, pierwszy pracownik będzie przechwytywał około 1000 wiadomości, podczas gdy inne są nadal zajęte łączeniem.

Możesz tworzyć własne trasy na wyższym poziomie na kilka sposobów. Spójrz na wzorce LRU w Przewodniku: w tym przypadku pracownicy wyraźnie mówią brokerowi, że jest "gotowy". Możesz także sterować przepływem opartym na kredytach, i to jest to, co robiłbym w każdej realnej sytuacji równoważenia obciążenia. Jest to uogólnienie wzoru LRU.Zobacz http://hintjens.com/blog:15

+0

Kiedy pracownik nie powiedzie, czy istnieje mechanizm zarówno wykryć i odzyskać kolejce zadań niż zostały przypisane, ale nie wysłał? Coś jak timeout z redystrybucją zadań. – CNK

+6

Jeśli chcesz wykrywać nieudane pracownikom trzeba dodać to samemu. Jest to stosunkowo łatwe: zebrać wszystkie wyniki, a jeśli ich brakuje, zrestartuj całą partię. Niepowodzenie jest na tyle rzadkie, że to proste brutalne podejście radzi sobie z nim dobrze. –

+2

No to jeszcze w docs prowadzonych tutaj: http://zguide.zeromq.org/page:all – easytiger

Powiązane problemy