В поисках эффективного middleware Александр Герасёв, ЛВК 2014
Сокеты
● Установление соединения● Работа с несколькими сокетами
одновременно● Buffer overflow / short message● Обрывы связи и переподключение
Многопоточность
● Семафоры● Разделяемые переменные● Мьютексы● Взаимные блокировки● Безблокировочные алгоритмы
● Ошибки
Message passing
Единственный метод взаимодействия компонентов: передача сообщений через очереди.
● Как сделать эффективно?● Как сделать просто?● Блокировать или нет при отправке?● Как доставлять между разными вычислителями?● Что делать, если нельзя доставить сообщение прямо
сейчас?● Как организовать очереди?● ???
Откуда растут ноги
● RCP● Corba● DCOM● DCOP / Bonobo● RTI
В 2003 JPMorgan Chase заказала разработку и реализацию протокола AMQP компании iMatrix.
В 2007 iMatrix решили сделать свой протокол, без брокера, но с GPL.
В 2011 вышел ZeroMQ 1.0
В 2014 вышел ZeroMQ 4.0
Что будет если
Что получится, если взять обычный TCP-сокет, добавить чуток радиоактивных изотопов, украденных с секретного советского реактора, облучить получившуюся смесь космическими лучами и передать в руки наркомана-художника, днём рисующего комиксы, а по ночам надевающего на себя костюм с накладными мускулами из спандекса.
ØMQ
● ØMQ (also known as ZeroMQ, 0MQ, or zmq) looks like an embeddable networking library but acts like a concurrency framework.
Mesage passing and patterns
● Взаимодействие двух компонентов это всегда обмен сообщениями● Взаимодействие
– 1 to 1
– 1 to many
– many to 1
– many to many
● Шаблоны– Push-Pull
– Request-Reply
– Publish-Subscribe
– Router-Dealer
– ...
● Очереди сообщений
Request-Reply pattern
Клиент:
import zmq
context = zmq.Context()
socket = context.socket(zmq.REQ)socket.connect("tcp://localhost:5555")
socket.send(b"Hello")
message = socket.recv()print("Received: %s" % message)
Сервер:
import zmq
context = zmq.Context()socket = context.socket(zmq.REP)socket.bind("tcp://*:5555")
while True: message = socket.recv() if message == b"Hello": socket.send(b"World") else: socket.send(b"Go away")
Publisher-Subscriber
Клиент:
import zmq
context = zmq.Context()
socket = context.socket(zmq.SUB)socket.connect("tcp://localhost:5555")
while True: message = socket.recv() print("Received: %s" % message)
Сервер:
import zmqimport time
context = zmq.Context()socket = context.socket(zmq.PUB)socket.bind("tcp://*:5555")
while True: socket.send(b"Good news everyone!") time.sleep(5)
zmq_socket
● Тип сокета● Тип транспорта
– In-process
– Inter-process
– TCP
– Multicast
● bind()/connect()– Кто слушает порт?
– Один ко многим и много к одному
Data transmission
● Non-blocking i/o● Zero-copy● HighWater marks● Serialization
● Multi-frame message– Envelopes
– Filtering
HighLevel Patterns
● Smart load-balancing● Heartbeats● Majordomo● Service discovery● Idempotent / non-idempotent services● Reliability / failover
Сколько это всё стоит?
● Открытый LGPL проект● Активное сообщество● Интерфейсы для 40+ языков● Кроссплатформенность