NIO & Erlang
От: Cyberax Марс  
Дата: 14.12.06 15:31
Оценка: 149 (12) +2
Начинаю новый тред, чтобы сообщение не потерялось.

Прежде всего, разберемся для чего нужен NIO (в виде overlapped IO или
Java NIO). Он нужен для обеспечения быстрого IO с минимальным
overhead'ом, не больше и не меньше. Поэтому сравнения Tomcat'а с
NIO-сервером абсолютно бессмысленны и идут лесом. Так как они сравнивают
несравнимое.

Рассмотрим такую задачу — создание сервера, вычисляющего число "пи" (см.
RFC 3091). Клиент соедияется на TCP-порт 314159 и получает знаки числа
PI пока ему не надоест и он не закроет соединение.

Как мы это делаем в Эрланге? Просто на каждого клиента создаем сервер,
который пишет в поток знаки числа "пи" по мере их вычисления. Как только
запись в поток возвращает ошибку — останавливаем поток. При этом
непосредственно операция записи в поток может быть реализована с
помощью NIO
— при выполнении команды 'write' мы создаем запрос на
запись, ставим у текущего легкого потока флаг 'blocked' и говорим
scheduler'у переключится на выполнение другого легкого потока. Когда
'write' сработает — мы это обнаруживаем (например, легкого сервисного
потока) и снимаем у исходного потока флаг блокировки.

Таким образом, на Эрланге будет оптимальная ситуация — никаких
переключений контекстов за исключением системных вызовов и постепенная
деградация качества с ростом нагрузки — чем больше легких потоков, тем
меньше шанс того, что поток для данного клиента получить квант времени,
но это происходит плавно по мере роста нагрузки.

Теперь рассмотрим вариант с NIO. Сначала проверяем вариант однопоточного
сервера. Будет что-то вроде (псевдокод):
socket=слушающий_сокет();
list<sockets> all_sockets; //Список всех открытых сокетов
map<socket,calculator> calculators; //Карта сокет-калькулятор_пи

while(true)
{
    //Обработаем accepted-сокеты
    list<socket> accepted=select_accepted(socket);
    foreach(socket s in accepted)
    {
        all_sockets.add(s);
        calculators.put(s, создать_новый_калькулятор());
    }

    //Обработаем закрытые сокеты
    list<socket> closed=select_closed(all_sockets);
    foreach(socket s in closed)
    {
        all_sockets.remove(s); //Уберем сокет из очереди
        calculators.get(s).notify_finish(); //Уведомим
        //калькулятор о его смерти.
        calculators.remove(s); //Уберем калькулятор из карты
    }

    //Возьмем следующего созревшего клиента
    socket next=select_next_ready_for_write(all_sockets);
    
    //Возьмем калькулятор
    calculator calc=calculators.get(next);
    int digit=calc.get_next_digit(); //(1) вычисляем следующее число
    socket.write_non_blocking(digit); //Отправим число клиенту
}

Этот пример будет так же эффективен как Erlang в том смысле, что
overhead у него будет такой же overhead по системным вызовам.

Но здесь есть проблема. А что если у нас вычисление числа знака займет
10 минут (например, для одного клиента мы уже считаем 10000000000 знак)?
Правильно, остальные клиенты будут при это отваливаться по таймауту.

Надо заметить, что такая стратегия, тем не менее, прекрасно подходит для
случаев, когда нам гарантировано, что у нас вычисление займет
ограниченое время (как в случае сервера, выдающего статический HTML,
например).

Так что мы должны переписать этот пример как-то вот так:
    ....
    //Возьмем калькулятор
    calculator calc=calculators.get(next);
    Потоковый_Выполнитель executor=взятьПотоковогоВыполнителя();
    executor.выполнить_в_потоке(fun() //Анонимная функция
    {
        int digit=calc.get_next_digit();
        socket.write_non_blocking(digit);
    });
    ...

Но этот пример уже значительно хуже Эрланговкого. Во-первых, у нас
появляется overhead на переключение потоков. Во-вторых, у нас время
отклика для клиента будет изменяться неплавно.

Поясню второй пункт. Пусть у нас есть пул из 4 потоков. Вычисления для
обычных клиентов занимают K секунд, так что для среднего вызова будет
время вычисления будет K/процент_доступности_процессора секунд для
случая полной загруженности процессора. Теперь предположим, что один из
потоков из пула у нас занят длительным вычислением. Тогда среднее время
ответов для остальных клиентов будет
K/(процент_доступности_процессора*0.75).

Чтобы преодолеть второй пункт нам нужно запускать по потоку на клиент и
иметь дешовые возможности переключения потоков, но это получится Эрланг
Posted via RSDN NNTP Server 2.1 beta
Sapienti sat!
Re: NIO & Erlang
От: Шахтер Интернет  
Дата: 15.12.06 07:42
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Но здесь есть проблема. А что если у нас вычисление числа знака займет

C>10 минут (например, для одного клиента мы уже считаем 10000000000 знак)?
C>Правильно, остальные клиенты будут при это отваливаться по таймауту.

Тебе нужно разбить вычисление на стадии с ограниченным временем выполнения.
Вся разница с Erlang ом только в том, что тот делает это автоматически, а на C придется поработать руками.
Тогда код будет выглядеть как то так.

    calculator calc=calculators.get(next);

    pair<bool,int> ret=calc.stage();

    if( ret.first )
      socket.write_non_blocking(ret.second); //Отправим число клиенту
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[2]: NIO & Erlang
От: Cyberax Марс  
Дата: 15.12.06 07:55
Оценка: +1
Шахтер wrote:
> C>Но здесь есть проблема. А что если у нас вычисление числа знака займет
> C>10 минут (например, для одного клиента мы уже считаем 10000000000 знак)?
> C>Правильно, остальные клиенты будут при это отваливаться по таймауту.
> Тебе нужно разбить вычисление на стадии с ограниченным временем выполнения.
А как ты это сделаешь? Тут варианта два:
1) Явно вызывать yield()
2) Использовать принудительное переключение.

> Вся разница с Erlang ом только в том, что тот делает это автоматически,

> а на C придется поработать руками.
> Тогда код будет выглядеть как то так.
> calculator calc=calculators.get(next);
> pair<bool,int> ret=calc.stage();
> if( ret.first )
> socket.write_non_blocking(ret.second); //Отправим число клиенту
Это называется "писать в автоматном стиле" — одна из самых худших
напастей. Фактически, ты просто сам реализуешь легкие потоки "наизнанку".
Posted via RSDN NNTP Server 2.1 beta
Sapienti sat!
Re[3]: NIO & Erlang
От: Sinclair Россия https://github.com/evilguest/
Дата: 15.12.06 09:59
Оценка:
Здравствуйте, Cyberax, Вы писали:
C>1) Явно вызывать yield()
Хм, прикольно. Можно сделать апп-сервер на дотнете, который выворачивает всё наизнанку:
public void delegate Action();
public interface ITask
{
  IEnumerable<Action> Actions { get;};
}

public class TestTask : ITask
{
  public IEnumerable<Action> Actions
    {
        get 
        {
          yield return delegate 
            { 
              Console.Write("Hello, ");
            } 
          yield return delegate 
            { 
              Console.Write("world!");
            } 
        }
    }
}

C>2) Использовать принудительное переключение.
1.2.0 alpha rev. 655
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: NIO & Erlang
От: Шахтер Интернет  
Дата: 15.12.06 10:09
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Шахтер wrote:

>> C>Но здесь есть проблема. А что если у нас вычисление числа знака займет
>> C>10 минут (например, для одного клиента мы уже считаем 10000000000 знак)?
>> C>Правильно, остальные клиенты будут при это отваливаться по таймауту.
>> Тебе нужно разбить вычисление на стадии с ограниченным временем выполнения.
C>А как ты это сделаешь? Тут варианта два:
C>1) Явно вызывать yield()
C>2) Использовать принудительное переключение.

>> Вся разница с Erlang ом только в том, что тот делает это автоматически,

>> а на C придется поработать руками.
>> Тогда код будет выглядеть как то так.
>> calculator calc=calculators.get(next);
>> pair<bool,int> ret=calc.stage();
>> if( ret.first )
>> socket.write_non_blocking(ret.second); //Отправим число клиенту
C>Это называется "писать в автоматном стиле" — одна из самых худших
C>напастей. Фактически, ты просто сам реализуешь легкие потоки "наизнанку".

Почему напасть и почему наизнанку?

-----------------------------------------------

На самом деле при работе на C нужна или поддержка среды, или нужно делать всё руками.
Фактически есть три варианта.

1) "писать в автоматном стиле". Я не считаю этот вариант плохим. Например, ядро Windows (точнее WDM её часть), фактически так и написано.

2) Использовать soft-tread библиотеку и руками расставлять yield(). На сегодняшний день -- пожалуй наиболее практическое решение.

3) То же самое, что и 2), но компилятор должен автоматически расставить yield() по коду. Требуется поддержка со стороны кодогенерирующей части компилятора. Кроме того, неплохо бы внедрить compile-time critical sections. К сожалению, нигде не реализовано.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[4]: NIO & Erlang
От: Cyberax Марс  
Дата: 15.12.06 19:50
Оценка:
Шахтер wrote:
> C>Это называется "писать в автоматном стиле" — одна из самых худших
> C>напастей. Фактически, ты просто сам реализуешь легкие потоки "наизнанку".
> Почему напасть и почему наизнанку?
> -----------------------------------------------
> На самом деле при работе на C нужна или поддержка среды, или нужно
> делать всё руками.
Ну про С/С++ — тут все понятно, там просто других вариантов и нет

> Фактически есть три варианта.

> 1) "писать в автоматном стиле". Я не считаю этот вариант плохим.
> Например, ядро Windows (точнее WDM её часть), фактически так и написано.
Очень, очень, очень неудобно в случае сложных протоколов. Логика
переходов становится полностью непонятной.

> 2) Использовать soft-tread библиотеку и руками расставлять yield(). На

> сегодняшний день -- пожалуй наиболее практическое решение.
Erlang, вид сбоку

> 3) То же самое, что и 2), но компилятор должен автоматически расставить

> yield() по коду. Требуется поддержка со стороны кодогенерирующей части
> компилятора. Кроме того, неплохо бы внедрить compile-time critical
> sections. К сожалению, нигде не реализовано.
Не получится, для автоматической расстановки yield'ов не хватает еще
одного компонента — отсутствия разделяемых ресурсов. То есть представь,
что у нас один легкий поток захватывает крит. секцию, его yield()'ят, а
потом другой поток попытается эту же секцию захватить.
Posted via RSDN NNTP Server 2.1 beta
Sapienti sat!
Re[4]: NIO & Erlang
От: Cyberax Марс  
Дата: 15.12.06 20:21
Оценка: +2
Sinclair wrote:
> C>1) Явно вызывать yield()
> Хм, прикольно. Можно сделать апп-сервер на дотнете, который выворачивает
> всё наизнанку:
Можно, но только для достаточо простых случаев.

> public void delegate Action();

> public interface ITask
> {
> IEnumerable<Action> Actions { get;};
> }
> public class TestTask : ITask
> {
> public IEnumerable<Action> Actions
> {
> get
> {
> yield return delegate
> {
> Console.Write("Hello, ");
> }
> yield return delegate
> {
> Console.Write("world!");
> }
> }
> }
> }
А теперь попробуй запустить вместо Console.Write какую-нибудь долгую
функцию и выйти yield()'ом из ее середины
Posted via RSDN NNTP Server 2.1 beta
Sapienti sat!
Re: NIO & Erlang
От: n0name2  
Дата: 16.12.06 12:10
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Таким образом, на Эрланге будет оптимальная ситуация — никаких

C>переключений контекстов за исключением системных вызовов и постепенная
C>деградация качества с ростом нагрузки — чем больше легких потоков, тем
C>меньше шанс того, что поток для данного клиента получить квант времени,
C>но это происходит плавно по мере роста нагрузки.

Предлагаю сразу отойти от однопроцессорного железа и рассматривать только вариант SMP. В этом случае полагаю что процессы в Erlang будут более менее равномерно распределены по всем ядрам CPU. Но, если они все-таки будут вынуждены взаимодействовать друг с другом для передачи сообщений, то им придется как минимум что-то делать с write barrier и вообще пользоватся средствами межпоточного взаимодействия предоставляемого OS.

C>Поясню второй пункт. Пусть у нас есть пул из 4 потоков. Вычисления для

C>обычных клиентов занимают K секунд, так что для среднего вызова будет
C>время вычисления будет K/процент_доступности_процессора секунд для
C>случая полной загруженности процессора. Теперь предположим, что один из
C>потоков из пула у нас занят длительным вычислением. Тогда среднее время
C>ответов для остальных клиентов будет
C>K/(процент_доступности_процессора*0.75).

C>Чтобы преодолеть второй пункт нам нужно запускать по потоку на клиент и

C>иметь дешовые возможности переключения потоков, но это получится Эрланг

При увеличении количества длительных потоков в Эрланг, среднее время ответа будет расти т.к. все меньше и меньше ресурсов будет оставатся для новых потоков, в какой-то момент они сожрут практически все ресурсы, разве нет? Вопрос в том — при каком именно числе длительных процессов Эрлангу уже будет сложно обеспечить требуемый средний отклик. Если это число больше чем разумный размер пула (все-таки современные OS вполне могут оперировать 400-500 потоками без существенного overhead), то я соглашусь, что Эрланг в таких задачах имеет существенное приемущество.

Теперь, допустим, мы решили сделать общий кэш для значений числа пи, ранее расчитаных в других потоках, которые работают на других ядрах CPU. Для этого потокам Эрланг нужно обмениватся сообщениями, причем при SMP это будет уже медленнее чем то что предоставляет в этом плане Java (общая память).

Кстати, кто-нибудь может внятно объяснить почему обмен сообщениями на Эрланг в SMP конфигурации такой медленный?
Re[2]: NIO & Erlang
От: Cyberax Марс  
Дата: 16.12.06 12:23
Оценка:
n0name2 wrote:
> Предлагаю сразу отойти от однопроцессорного железа и рассматривать
> только вариант SMP. В этом случае полагаю что процессы в Erlang будут
> более менее равномерно распределены по всем ядрам CPU. Но, если они
> все-таки будут вынуждены взаимодействовать друг с другом для передачи
> сообщений, то им придется как минимум что-то делать с write barrier и
> вообще пользоватся средствами межпоточного взаимодействия
> предоставляемого OS.
Erlang умеет минимизировать переключения потоков.

Использование блокировок там вообще сведено к минимуму — они нужны,
фактически, только при операции добавления сообщения в очередь другого
потока.

Само сообщение иммутабельно, так что там ничего синхронизировать не надо.

> C>Чтобы преодолеть второй пункт нам нужно запускать по потоку на клиент и

> C>иметь дешовые возможности переключения потоков, но это получится Эрланг
> При увеличении количества длительных потоков в Эрланг, среднее время
> ответа будет расти т.к. все меньше и меньше ресурсов будет оставатся для
> новых потоков, в какой-то момент они сожрут практически все ресурсы,
> разве нет?
Смысл в том, что при этом среднее время ответа будет плавно расти. То
есть, несколько плохих клиентов не создадут заметных проблем для остальных.

> Вопрос в том — при каком именно числе длительных процессов

> Эрлангу уже будет сложно обеспечить требуемый средний отклик. Если это
> число больше чем разумный размер пула (все-таки современные OS вполне
> могут оперировать 400-500 потоками без существенного overhead), то я
> соглашусь, что Эрланг в таких задачах имеет существенное приемущество.
Про ejabberd писали, что он держал по 10k соединений.

> Теперь, допустим, мы решили сделать общий кэш для значений числа пи,

> ранее расчитаных в других потоках, которые работают на других ядрах CPU.
> Для этого потокам Эрланг нужно обмениватся сообщениями, причем при SMP
> это будет уже медленнее чем то что предоставляет в этом плане Java
> (общая память).
Ненамного — для Java нужно будет использовать блокировки (или, если
повезет, атомарные структуры).

> Кстати, кто-нибудь может внятно объяснить почему обмен сообщениями на

> Эрланг в SMP конфигурации такой медленный?
Не знаю, может из-за того, что SMP там только недавно появился — пока не
отладили. Раньше люди просто запускали по две копии Erlang'а (каждую на
свой процессор).
Posted via RSDN NNTP Server 2.1 beta
Sapienti sat!
Re[5]: NIO & Erlang
От: Шахтер Интернет  
Дата: 16.12.06 12:33
Оценка:
Здравствуйте, Cyberax, Вы писали:

>> 3) То же самое, что и 2), но компилятор должен автоматически расставить

>> yield() по коду. Требуется поддержка со стороны кодогенерирующей части
>> компилятора. Кроме того, неплохо бы внедрить compile-time critical
>> sections. К сожалению, нигде не реализовано.
C>Не получится, для автоматической расстановки yield'ов не хватает еще
C>одного компонента — отсутствия разделяемых ресурсов. То есть представь,
C>что у нас один легкий поток захватывает крит. секцию, его yield()'ят, а
C>потом другой поток попытается эту же секцию захватить.

Ну почему же "не получится".
Захват критической секции -- это фактически запрет планировщика.
Этот запрет можно реализовать двумя путями.
Статическим -- когда в коде явно помечен блок, в который нельзя вставлять yield().
Динамически -- парой функций disableYield()/enableYield(). Если yield вызван после disableYield(), то
его фактическое исполнение откладывается до enableYield().
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[3]: NIO & Erlang
От: n0name2  
Дата: 16.12.06 12:40
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Использование блокировок там вообще сведено к минимуму — они нужны,

C>фактически, только при операции добавления сообщения в очередь другого
C>потока.

Зато конец очереди может быть highly contended. Кстати говоря, блокировки практически не нужны и в Java если задачи в пуле независимы друг от друга.

Плюс при переключении потоков в Эрланг все равно может потребоватся инвалидация кэша процессора т.к. новый процесс работает с другим сегментом физической памяти, так что переключение все равно не бесплатно.

C>Само сообщение иммутабельно, так что там ничего синхронизировать не надо.


Все равно его нужно записывать в физическую память (из регистров или стэка процесса), для некоторых архитектур, кэши процессоров синхронизировать и т.д.

C>Смысл в том, что при этом среднее время ответа будет плавно расти. То

C>есть, несколько плохих клиентов не создадут заметных проблем для остальных.

Согласен, но, если это действительно несколько — 50, 100, то пул с этим справится не сильно хуже. А если много, то, тут уже может быть неважно — плавно у нас распределено время отклика или нет. Оно просто может быть неприемлемым.

>> Вопрос в том — при каком именно числе длительных процессов

C>Про ejabberd писали, что он держал по 10k соединений.

Так там не требуется большого времени на обработку сообщения, все задержки в IO, которое у нас Non-blocking и по сути не дает Эрланг приемущества.

C>Ненамного — для Java нужно будет использовать блокировки (или, если

C>повезет, атомарные структуры).

А как вообще в Эрланг это делать? Спрашивать у всех потоков поочередно — а не считали ли вы такую-то цифру числа пи?
В Java можно разбить cache на регионы (как это сделано в ConcurrentHashMap) и все будет вполне достойно.

C>Не знаю, может из-за того, что SMP там только недавно появился — пока не

C>отладили. Раньше люди просто запускали по две копии Erlang'а (каждую на
C>свой процессор).

Мне кажется, скорее потому, что умный SMP scheduler для Эрланга сделать по большому счету также сложно как довести скорость создания и переключения kernel level потоков до уровня Эрланга. Я думаю, что следующий этап развития OS, вообще говоря, по инициативе разработчиков CPU, активно пропагандирующий параллельное программирование, будет существенное снижение накладных расходов на поддержание потоков. Кстати, интересно, как ведет себя Java OS сделанная BEA...
Re[6]: NIO & Erlang
От: Cyberax Марс  
Дата: 16.12.06 12:45
Оценка:
Шахтер wrote:
> C>Не получится, для автоматической расстановки yield'ов не хватает еще
> C>одного компонента — отсутствия разделяемых ресурсов. То есть представь,
> C>что у нас один легкий поток захватывает крит. секцию, его yield()'ят, а
> C>потом другой поток попытается эту же секцию захватить.
> Ну почему же "не получится".
> Захват критической секции -- это фактически запрет планировщика.
> Этот запрет можно реализовать двумя путями.
> Статическим -- когда в коде явно помечен блок, в который нельзя
> вставлять yield().
> Динамически -- парой функций disableYield()/enableYield(). Если yield
> вызван после disableYield(), то
> его фактическое исполнение откладывается до enableYield().
Ну вот так и получится в итоге Erlang.

Кроме того, ручная работа — она подвержена ошибкам и вообще
неэффективна. Особенно, если ты используешь сторонние библиотеки (в них
тоже может yield()'ы придется ставить).
Posted via RSDN NNTP Server 2.1 beta
Sapienti sat!
Re[4]: NIO & Erlang
От: Cyberax Марс  
Дата: 16.12.06 12:59
Оценка:
n0name2 wrote:
> C>Использование блокировок там вообще сведено к минимуму — они нужны,
> C>фактически, только при операции добавления сообщения в очередь другого
> C>потока.
> Зато конец очереди может быть highly contended. Кстати говоря,
> блокировки практически не нужны и в Java если задачи в пуле независимы
> друг от друга.
Не так сильно — у нас всего два соревнующихся потока.

> Плюс при переключении потоков в Эрланг все равно может потребоватся

> инвалидация кэша процессора т.к. новый процесс работает с другим
> сегментом физической памяти, так что переключение все равно не бесплатно.
С чего бы? Легкие процессы работают все в одной shared-памяти. В
идеальной ситуации вообще нет переключений системных контекстов.

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

> C>Само сообщение иммутабельно, так что там ничего синхронизировать не надо.

> Все равно его нужно записывать в физическую память (из регистров или
> стэка процесса), для некоторых архитектур, кэши процессоров
> синхронизировать и т.д.
Ну так и в Java оно точно так же. Кстати, Erlang — он ready for nccNUMA,
так как границы когерентности замечательно проходят по границам отсылки
сообщений в нелокальный поток.

> C>Смысл в том, что при этом среднее время ответа будет плавно расти. То

> C>есть, несколько плохих клиентов не создадут заметных проблем для
> остальных.
> Согласен, но, если это действительно несколько — 50, 100, то пул с этим
> справится не сильно хуже. А если много, то, тут уже может быть неважно —
> плавно у нас распределено время отклика или нет. Оно просто может быть
> неприемлемым.
Вот сейчас тестирую под нагрузкой JBoss HTTP Remoting и JBoss Messaging
over HTTP. Картина удручающая — масштабируемость с ростом конкуррентных
запросов резко падает при наличии примерно 30% тормозных клиентов
(менеджеры, запускающие создание отчетов).

Спасает то, что у меня приложение сделано полностью в духе Erlang'а —
так что я могу просто добавить второй сервер JBoss'а в кластер.

>> > Вопрос в том — при каком именно числе длительных процессов

> C>Про ejabberd писали, что он держал по 10k соединений.
> Так там не требуется большого времени на обработку сообщения, все
> задержки в IO, которое у нас Non-blocking и по сути не дает Эрланг
> приемущества.
Там достаточно сложная логика роутинга сообщений, так что не все так
просто. Java'вый jabberd до такого не масштабируется.

> C>Ненамного — для Java нужно будет использовать блокировки (или, если

> C>повезет, атомарные структуры).
> А как вообще в Эрланг это делать? Спрашивать у всех потоков поочередно —
> а не считали ли вы такую-то цифру числа пи?
Нет, выделяешь сервисный поток, который будет хранить у себя в словаре кэш.

> C>Не знаю, может из-за того, что SMP там только недавно появился — пока не

> C>отладили. Раньше люди просто запускали по две копии Erlang'а (каждую на
> C>свой процессор).
> Мне кажется, скорее потому, что умный SMP scheduler для Эрланга сделать
> по большому счету также сложно как довести скорость создания и
> переключения kernel level потоков до уровня Эрланга.
Почему? Там все не так уж сложно.

> Я думаю, что

> следующий этап развития OS, вообще говоря, по инициативе разработчиков
> CPU, активно пропагандирующий параллельное программирование, будет
> существенное снижение накладных расходов на поддержание потоков.
Уже было — HyperThreading

> Кстати, интересно, как ведет себя Java OS сделанная BEA...

Сдохнет. Автономная ОС вряд ли кому нужна.
Posted via RSDN NNTP Server 2.1 beta
Sapienti sat!
Re[5]: NIO & Erlang
От: n0name2  
Дата: 16.12.06 13:23
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>С чего бы? Легкие процессы работают все в одной shared-памяти. В

C>идеальной ситуации вообще нет переключений системных контекстов.

Ты опять забыл что у нас процессы размазаны по SMP ядрам.

C>Ну так и в Java оно точно так же. Кстати, Erlang — он ready for nccNUMA,

C>так как границы когерентности замечательно проходят по границам отсылки
C>сообщений в нелокальный поток.

О чем и речь, накладные расходы при SMP появляются даже для легких процессов.

C>Вот сейчас тестирую под нагрузкой JBoss HTTP Remoting и JBoss Messaging

C>over HTTP. Картина удручающая — масштабируемость с ростом конкуррентных
C>запросов резко падает при наличии примерно 30% тормозных клиентов
C>(менеджеры, запускающие создание отчетов).

А какой HTTP server используется? Можно попробовать несколько thread poolов с разными приоритетами использовать.

C>Спасает то, что у меня приложение сделано полностью в духе Erlang'а —

C>так что я могу просто добавить второй сервер JBoss'а в кластер.

Я бы просто выделил отчетников отдельно.

C>Там достаточно сложная логика роутинга сообщений, так что не все так

C>просто. Java'вый jabberd до такого не масштабируется.

Скорее всего, просто криво написан. JMS почему-то легко масштабируется, многие HTTP серверы — тоже. Причем, 7к клиентов ИМХО вообще оч мало. А в чем там сложности роутинга?

C>Нет, выделяешь сервисный поток, который будет хранить у себя в словаре кэш.


Ну вот, соот-но, допустим, у нас SMP и есть выделенный поток. Вот там будет highly contended очередь, думаю, такой вариант будет гораздо менее масштабируем чем ConcurrentHashMap.

C>Почему? Там все не так уж сложно.


Когда с SMP будет все в порядке, тогда поверю. Почему тогда thinthreads глючили в JRockit и их оттуда убрали? Кстати говоря, вполне можно достать старую версию JRockit и "наслаждатся" дешевой многопоточностью.

>> Кстати, интересно, как ведет себя Java OS сделанная BEA...

C>Сдохнет. Автономная ОС вряд ли кому нужна.

Почему? Если там у тебя только JBoss крутится и ничего больше нет — зачем тебе OS?
Re[5]: NIO & Erlang
От: aka50 Россия  
Дата: 16.12.06 21:00
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Вот сейчас тестирую под нагрузкой JBoss HTTP Remoting и JBoss Messaging

C>over HTTP. Картина удручающая — масштабируемость с ростом конкуррентных
C>запросов резко падает при наличии примерно 30% тормозных клиентов
C>(менеджеры, запускающие создание отчетов).

Занимаюсь примерно тем же... Тяжелые задачи разделены с легкими,
в особо тяжелых случаях использую отложенные job-ы.
Но есть определенные желания увеличить пропускную способность...


C>Спасает то, что у меня приложение сделано полностью в духе Erlang'а —

C>так что я могу просто добавить второй сервер JBoss'а в кластер.
По этому вопрос:
Что есть "в духе Erlang-a" ?
Re[6]: NIO & Erlang
От: Cyberax Марс  
Дата: 17.12.06 01:19
Оценка:
n0name2 wrote:
> C>С чего бы? Легкие процессы работают все в одной shared-памяти. В
> C>идеальной ситуации вообще нет переключений системных контекстов.
> Ты опять забыл что у нас процессы размазаны по SMP ядрам.
При отправке сообщения Erlang-машина смотрит, что если affinity у
целевого процесса совпадает с текущим — то никаких блокировок не нужно.

> C>Ну так и в Java оно точно так же. Кстати, Erlang — он ready for nccNUMA,

> C>так как границы когерентности замечательно проходят по границам отсылки
> C>сообщений в нелокальный поток.
> О чем и речь, накладные расходы при SMP появляются даже для легких
> процессов.
Их часто можно избежать. Не совсем полностью, естественно, но вполне
достаточно, чтобы легкость параллельного программирования себя окупала.

> C>Вот сейчас тестирую под нагрузкой JBoss HTTP Remoting и JBoss Messaging

> C>over HTTP. Картина удручающая — масштабируемость с ростом конкуррентных
> C>запросов резко падает при наличии примерно 30% тормозных клиентов
> C>(менеджеры, запускающие создание отчетов).
> А какой HTTP server используется? Можно попробовать несколько thread
> poolов с разными приоритетами использовать.
HTTP-сервер — Apache с mod_jk2-коннектором. Он-то не тормозит (так как
работает просто "шлангом").

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

> C>Спасает то, что у меня приложение сделано полностью в духе Erlang'а —

> C>так что я могу просто добавить второй сервер JBoss'а в кластер.
> Я бы просто выделил отчетников отдельно.
Сложно — там кроме отчетов есть еще куча тормозных операций. Ну да это
детали...

> C>Там достаточно сложная логика роутинга сообщений, так что не все так

> C>просто. Java'вый jabberd до такого не масштабируется.
> Скорее всего, просто криво написан. JMS почему-то легко масштабируется,
> многие HTTP серверы — тоже.
Вот про JMS не надо. У нас приложение зависит от JMS для синхронизации
данных между клиентами в реальном времени.

Мы тестировали SonicMQ, ActiveMQ и MQSeries. В среднем на разумном
железе они отваливаются после 300-400 соединений и обеспечивают всего
несколько десятков сообщений в секунду на клиента. А это означало, что
для наших целей пришлось бы ставить кластер — так что мы просто взяли
тормозной JBoss Messaging (раз уж и так делать кластер).

Вот тут сравнение:
http://www.sonicsoftware.com/products/whitepapers/docs/sonic40_vs_mqseries52.pdf

> Причем, 7к клиентов ИМХО вообще оч мало. А в чем там сложности роутинга?

Jabber может иметь сложную топологию сети. То есть могут быть
промежуточные relay'и и т.п. А еще там есть multicast'овые сообщения, и
прочие фичи.

> C>Нет, выделяешь сервисный поток, который будет хранить у себя в словаре

> кэш.
> Ну вот, соот-но, допустим, у нас SMP и есть выделенный поток. Вот там
> будет highly contended очередь, думаю, такой вариант будет гораздо менее
> масштабируем чем ConcurrentHashMap.
Ну так запусти еще парочку сервисных потоков, которые будут кэшировать
результаты локально для каждого процессора.

> C>Почему? Там все не так уж сложно.

> Когда с SMP будет все в порядке, тогда поверю. Почему тогда thinthreads
> глючили в JRockit и их оттуда убрали? Кстати говоря, вполне можно
> достать старую версию JRockit и "наслаждатся" дешевой многопоточностью.
Скорее всего, не справились со сложностью системы.

>> > Кстати, интересно, как ведет себя Java OS сделанная BEA...

> C>Сдохнет. Автономная ОС вряд ли кому нужна.
> Почему? Если там у тебя только JBoss крутится и ничего больше нет —
> зачем тебе OS?
А драйверы для SATA2-чипов, гигабитных контроллеров, I2C-мониторинга там
из воздуха появятся?
Posted via RSDN NNTP Server 2.1 beta
Sapienti sat!
Re[6]: NIO & Erlang
От: Cyberax Марс  
Дата: 17.12.06 02:43
Оценка:
aka50 wrote:
> C>Спасает то, что у меня приложение сделано полностью в духе Erlang'а —
> C>так что я могу просто добавить второй сервер JBoss'а в кластер.
> По этому вопрос:
> Что есть "в духе Erlang-a" ?
Все построено на передаче сообщений, нигде (кроме БД) не хранится
разделяемого состояния.
Posted via RSDN NNTP Server 2.1 beta
Sapienti sat!
Re[7]: NIO & Erlang
От: Тычеблин Китай  
Дата: 17.12.06 06:38
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>aka50 wrote:

>> C>Спасает то, что у меня приложение сделано полностью в духе Erlang'а —
>> C>так что я могу просто добавить второй сервер JBoss'а в кластер.
>> По этому вопрос:
>> Что есть "в духе Erlang-a" ?
C>Все построено на передаче сообщений, нигде (кроме БД) не хранится
C>разделяемого состояния.

с этим, надеюсь, знакомы ?
Message-Driven Thread API
Re[8]: NIO & Erlang
От: Cyberax Марс  
Дата: 17.12.06 06:44
Оценка:
Тычеблин wrote:
> C>Все построено на передаче сообщений, нигде (кроме БД) не хранится
> C>разделяемого состояния.
> с этим, надеюсь, знакомы ?
> Message-Driven Thread API <http://mdthread.org/main/&gt;
Нет Я бы побоялся чем-нибудь с такого жуткого сайта пользоваться.

У меня свой велосипед, который позволяет делать примерно это, да еще и
интегрируется с очередью сообщений AWT.
Posted via RSDN NNTP Server 2.1 beta
Sapienti sat!
Re[7]: NIO & Erlang
От: Шахтер Интернет  
Дата: 17.12.06 09:53
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Шахтер wrote:

>> C>Не получится, для автоматической расстановки yield'ов не хватает еще
>> C>одного компонента — отсутствия разделяемых ресурсов. То есть представь,
>> C>что у нас один легкий поток захватывает крит. секцию, его yield()'ят, а
>> C>потом другой поток попытается эту же секцию захватить.
>> Ну почему же "не получится".
>> Захват критической секции -- это фактически запрет планировщика.
>> Этот запрет можно реализовать двумя путями.
>> Статическим -- когда в коде явно помечен блок, в который нельзя
>> вставлять yield().
>> Динамически -- парой функций disableYield()/enableYield(). Если yield
>> вызван после disableYield(), то
>> его фактическое исполнение откладывается до enableYield().
C>Ну вот так и получится в итоге Erlang.

Ну почему Erlang? Обычный C с поддержкой soft-thread.

C>Кроме того, ручная работа — она подвержена ошибкам и вообще

C>неэффективна. Особенно, если ты используешь сторонние библиотеки (в них
C>тоже может yield()'ы придется ставить).

Да это спорный вопрос. Автоматическая работа выполняется по некоторому алгоритму.
Всё хорошо, пока этот алгоритм устраивает. Как только он перестаёт устраивать -- начинается ручная работа. Нужна гибкость.
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.