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.
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
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. –
No to jeszcze w docs prowadzonych tutaj: http://zguide.zeromq.org/page:all – easytiger