2013-02-22 4 views
2

Я хотел бы получить 0,5-1 000 удаленных вызовов функций в секунду. Предположим, у нас есть один компьютер Central, на котором начинается вычисление, и один компьютер Worker, который выполняет вычисления. В реальной конфигурации будет много компьютеров Worker.1 миллион удаленных вызовов функций в секунду

Давайте предположим на минуту, что наша задача заключается в расчете sum of [(random int from 0 to MAX_VAL)*2], PROBLEM_SIZE times Очень наивная прототип

Worker:

//The real function takes 0.070ms to compute. 
int compute(int input) { 
    return input * 2; 
} 

void go() { 
    try { 
     ServerSocket ss = new ServerSocket(socketNum); 

     Socket s = ss.accept(); 
     System.out.println("Listening for " + socketNum); 

     DataInput di = new DataInputStream(s.getInputStream()); 
     OutputStream os = s.getOutputStream(); 
     byte[] arr = new byte[4]; 
     ByteBuffer wrap = ByteBuffer.wrap(arr); 

     for (; ;) { 
      wrap.clear(); 

      di.readFully(arr); 
      int value = wrap.getInt(); 
      int output = compute(value); 

      wrap.clear(); 
      byte[] bytes = wrap.putInt(output).array(); 
      os.write(bytes); 
     } 

    } catch (IOException e) { 
     System.err.println("Exception at " + socketNum); 
     e.printStackTrace(); 
    } 
} 

Central:

void go(){  
    try { 

     Socket s = new Socket(ip, socketNum); 
     s.setSoTimeout(2000); 
     OutputStream os = s.getOutputStream(); 
     DataInput di = new DataInputStream(s.getInputStream()); 

     System.out.println("Central socket starting for " + socketNum); 

     Random r = new Random(); 

     byte[] buf = new byte[4]; 
     ByteBuffer wrap = ByteBuffer.wrap(buf); 

     long start = System.currentTimeMillis(); 
     long sum = 0; 

     for(int i = 0; i < n; i++) { 
      wrap.clear(); 
      int value = r.nextInt(10000); 

      os.write(wrap.putInt(value).array()); 

      di.readFully(buf); 
      wrap.clear(); 

      int answer = wrap.getInt(); 
      sum += answer; 
     } 

     System.out.println(n + " calls in " + (System.currentTimeMillis() - start) + " ms"); 
    } catch(SocketTimeoutException ste) { 
     System.err.println("Socket timeout at " + socketNum); 
    } 

    catch (Exception e) { 
     e.printStackTrace(); 
    } 

Если пинг 0.150ms и мы запускаем 1-threaded Worker и 1-threaded Central, каждая итерация займет ~ 0.150ms. Чтобы повысить производительность, я запускаю потоки N как на рабочем, так и на центральном, n-й поток прослушивает порт 2000+n. После завершения каждого потока мы суммируем результат.

Бенчмарки

Во-первых, я запустил программу выше в школьной сети моего стипендиата. Во-вторых, я запускал его на двух экземплярах Amazon EC2 Cluster. Разрыв в результатах был очень большим.

CHUNK_SIZE = 100_000 во всех пробегах. Сеть

стипендиата:

Я думаю, что 3 года назад это была конфигурация верхней доступна (Xeon E5645). Я считаю, что он сильно оптимизирован для параллельных вычислений и имеет простую топологию LAN, так как он имеет всего 20 машин.

ОС: Ubuntu

Средний пинг: ~ 0.165ms

N=1 total time=6 seconds 
N=10 total time=9 seconds 
N=20 total time=11 seconds 
N=32 total time=14 seconds 
N=100 total time=21 seconds 
N=500 total time=54 seconds 

Amazon сети:

Я запустил программу на два кластера Compute Eight Extra Large Instance (cc2.8xlarge) начали в той же Группе размещения.

ОС некоторых амазонских Linux

Средний пинг: ~ 0.170ms.

результаты были немного разочаровывает:

N=1 total time=16 seconds 
N=10 total time=36 seconds 
N=20 total time=55 seconds 
N=32 total time=82 seconds 
N=100 total time=250 seconds 
N=500 total time=1200 seconds 

Я побежал каждой конфигурации в 2-4 раза, результаты были сходными, в основном + -5%

Амазонка N = 1 результат имеет смысл, так как 0.170ms на вызов функции = 6000 вызовов в секунду = 100_000 звонков за 16 секунд. 6 секунд для сети Fellow на самом деле удивительны.

Я думаю, что максимальные TCP-пакеты в секунду с современными сетями составляют около 40-70 тыс. В секунду. Он соответствует N = 100, время = 250 секунд: N * CHUNK_SIZE/time = 100 * 100_000packets/250sec = 10_000_000packets/250sec = 40_000packets/second.

Вопрос:, как мне удалось настроить конфигурацию сети/компьютера моего коллеги, особенно с высокими значениями N?

Мое предположение: расточительно ставить каждый запрос 4 байта и ответ 4 байта на отдельный пакет, так как накладные расходы ~ 40 байт. Было бы разумно объединить все эти крошечные запросы, скажем, 0,010 мс и поместить их в один большой пакет, а затем перераспределить запросы на соответствующие сокеты. Возможно реализовать объединение на уровне приложений, но, похоже, что сеть/ОС Fellow настроена для этого.

Обновление: Я играл с java.net.Socket.setTcpNoDelay(), он ничего не менял.

Конечная цель: Я приближаю уравнение с миллионами переменных, используя очень большое дерево. В настоящее время дерево с 200_000 узлами помещается в ОЗУ. Однако меня интересует аппроксимация уравнения, которое требует дерева с миллионами узлов. Это потребует нескольких терабайт ОЗУ. Основная идея алгоритма - случайный путь от узла к листу, а также встроенные значения вдоль него. В настоящее время программа 32-потоковая, каждый поток выполняет 15000 итераций в секунду. Я хотел бы переместить его в кластер с одинаковыми номерами итераций в секунду.

+0

Это не вопрос программирования, не так ли? –

+0

Может быть, это (тогда, пожалуйста, дайте мне подсказку, где я должен искать ответ о конфигурации сети OS), или, может быть, текущий подход ошибочен, или я ДОЛЖЕН реализовать объединение, или есть готовое решение/инфраструктура для таких высокочастотных удаленные вызовы функций – 2013-02-22 14:40:35

+0

Некоторые другие соображения включают в себя обеспечение количества потоков примерно равным числу процессоров и гарантируя, что конфликт блокировки отсутствует. – pamphlet

ответ

1

Возможно, вы захотите включить алгоритм Нагле: wikipedia entry.

Вот ссылка об отключении его, что может быть полезно: Disabling Nagle's Algorithm in linux

+0

Спасибо, на первый взгляд, похоже, что это вариант, который мне нужен. – 2013-02-22 15:04:45

+0

Я пытался саботировать производительность сети Fellow, используя java.net.Socket.setTcpNoDelay (true), но общее время не изменилось. – 2013-02-22 15:26:48

+0

.getTcpNoDelay() на компьютерах amazon возвратил false. Может ли алгоритм Нэгла реализоваться как на уровне Java, так и на уровне ОС? Или, может быть, я просто смотрю в неправильном направлении. – 2013-02-22 15:39:14

Смежные вопросы