Архитектура производитель-потребитель с Java RealTime

Я работаю над проектированием торговой системы с использованием Java Realtime ( Sun JRTS 2.2 ) и хотел бы задать несколько вопросов о лучших практиках, потому что боюсь изобретать велосипед и почти уверен, что моя задача уже решена.

Итак, у меня есть поток, который постоянно читает сокет, анализирует байты и извлекает сообщения (бинарный протокол). После этого я должен посылать сообщения алгоритму, который, собственно, делает какие-то расчеты и принимает решение, торговать или нет.

Поэтому я думаю, что мне следует спроектировать эту систему, разделив ее на 2 части. Производитель (периодический (?) поток в реальном времени, который извлекает байты из сокета, анализирует его) и потребитель (поток в реальном времени (периодический/спорадический?), который извлекает сообщения от производителя, манипулирует ими и т. д.).

Итак, первый вопрос заключается в том, как спроектировать высокопроизводительную связь между этими двумя потоками (производитель/потребитель)? Также хотелось бы услышать комментарии о существующем опыте проектирования таких систем, советы и т.п.

Спасибо за помощь!


person Egor Lakomkin    schedule 28.11.2011    source источник
comment
Вы в курсе, что Realtime не обязательно означает быстрее?   -  person Thorbjørn Ravn Andersen    schedule 28.11.2011
comment
Да. Но я также должен знать о сборщике мусора, высокой частоте и низкой задержке.   -  person Egor Lakomkin    schedule 28.11.2011


Ответы (2)


Я работаю с аналогичной проблемой, но в другом домене:

Вот как я с этим справился:

public class Producer extends Thread{
   private BlockingQueue<E> consumerQueue = null;
   public setConsumerQueue(BlockingQueue<E> val){
      consumerQueue = val;
   }
   // main method where data is received from socket...
   public void run(){
      while(!interrupted()){
           data = socket.receive();// Receive data
           if(consumerQueue!=null) consumerQueue.offer(data);
      }
   }
}

public class Consumer extends Thread{
   private BlockingQueue<E> consumerQueue = new BlockingQueue<E>();
   public Consumer (Producer val){
      val.setConsumerQueue(consumerQueue);
   }
   public void run(){
      while(!interrupted()){
           data = consumerQueue.take();// block until there is data from producer
           if(data !=null) processData(data);
      }
   }
}
person GETah    schedule 28.11.2011
comment
Спасибо за ваш комментарий. Я думаю, нам нужно взглянуть на библиотеку прерываний и значительно снизить задержку при обмене потоками. - person Egor Lakomkin; 29.11.2011
comment
Зависит от амплитуды задержки, которую может выдержать ваше приложение, но если вы хотите, чтобы все работало быстрее (в реальном времени), то, боюсь, вам придется перейти на более быстрый родной язык, такой как C++ - person GETah; 29.11.2011

При принятии решения о том, как разбить приложение, полезно иметь четкое представление о том, сколько времени занимает каждый этап и какую обработку можно выполнять параллельно. Вы хотите рассчитать время каждого этапа в микросекундах и измерить распределение. Самыми интересными моментами обычно являются 99% (наихудший 1%), 99,9% или 99,99% тайловых задержек.


Я бы взглянул на библиотеку disruptor. Это довольно универсальная библиотека, предназначенная для высокой пропускной способности и низкой задержки.


Если вы хотите что-то более простое, существует ряд шаблонов, которые могут обмениваться данными между потоками за доли микросекунды, однако это точечные решения, которые зависят от вашего конкретного варианта использования.

Эта презентация может показаться вам интересной, хотя в основном она посвящена тестированию компонентов с низкой задержкой, высокой пропускной способностью и связи через сокеты. http://vanillajava.blogspot.com/2011/11/low-latency-slides.html

person Peter Lawrey    schedule 28.11.2011
comment
Питер, спасибо за рекомендацию библиотеки Disrupt. Это определенно одна из вещей, которые я должен принять во внимание. Возможно, вы можете порекомендовать некоторые методы/шаблоны для работы с чтением из сокета с высокой производительностью/низкой задержкой (я разработал простой прототип с Java NIO, но я уверен, что есть некоторые аспекты для настройки). - person Egor Lakomkin; 29.11.2011
comment
Я предлагаю вам настроить вашу систему, как я сделал в презентации. (Поток, выделенный ядрам с использованием привязки) Используйте занятое ожидание, чтобы еще больше снизить задержку. Если можете, используйте сетевой адаптер обхода ядра. например Соларфлэр или Мириком. Попробуйте использовать rdtsc напрямую, чтобы уменьшить стоимость использования временных меток. - person Peter Lawrey; 29.11.2011
comment
Кстати: если вы используете занятое ожидание, используйте простую очередь AtomicReference;) - person Peter Lawrey; 29.11.2011
comment
Кстати 2: эта головоломка может показаться вам интересной vanillajava.blogspot. ком/2011/11/ - person Peter Lawrey; 29.11.2011
comment
Спасибо за ссылки, Петр, подписался на ваш блог :) - person Egor Lakomkin; 29.11.2011
comment
Не могли бы вы также порекомендовать некоторые шаблоны для тестирования производительности? - person Egor Lakomkin; 30.11.2011
comment
Я бы предложил тест пропускной способности; отправляйте реалистичные сообщения как можно быстрее в течение 10 секунд и берите среднюю скорость. и тест на задержку; отправлять сообщения с отметкой времени, например. System.nanoTime() в течение 10 секунд и запишите каждую задержку на приемнике (при условии, что это одна и та же система), отсортируйте результаты и посмотрите на типичную (среднюю) задержку, 99% и 99,9% или 99,99%. - person Peter Lawrey; 30.11.2011