Pull to refresh

Comments 35

Вопрос «зачем» не раскрыт, но написано хорошо, за это плюс.
Я так понимаю, тут код не асинхронный получается. Так что сравнивать с NodeJS смысла нету.
В каком плане не асинхронный? Работу по вызову servlet-ов берет на себя Jetty. Если нужно, можно создавать новые thread-ы.
NodeJS для обработки клиентов не пораждает thread'ы. Он работает на так называемой EventBased моедли. 1 thread может обрабатывать сотни запросов. Так что тут не корректно сравнивать именно такое решение с NodeJS, так как никакой ивентбейсд модели тут нет (на сколько я понял).

Можно почитать тут blog.mixu.net/2011/02/01/understanding-the-node-js-event-loop/
Я предлагаю сравнивать их по возможностям и удобству разработки для наиболее распространенных задач, а модель обработки запросов — отдельный вопрос и преимущества event-based тут весьма спорные.
Добавлю, что тот же Jetty умеет асинхронные сервлеты, т.е. обрабатывать запросы в режиме «один запрос — отдельный тред» необязательно.
А еще есть java.util.concurrent, позволяющий выполнять асинхронно и многие другие операции. Также можно взглянуть в сторону Ringo, это действительно серьезный конкурент Node.js
вы про SelectChannelConnector? С ним все криво: там действительно используется NIO но потом вроде бы просто блокировочкой с wait-ом эмулируются сихронный ответ сервлета, т.е. костыль и в итоге все равно по потоку на запрос.

В жавадоке пишут что через Continuation вроде бы можно нормальный асинхронн сделать, т… е как netty
Спасибо за ссылку! Очень интересный материал.

Хочу обратить внимание на один нюанс из сабжа:
...Internally, node.js relies on libev to provide the event loop, which is supplemented by libeio which uses pooled threads to provide asynchronous I/O...

Внутренний механизм ноды полагается на пул POSIX потоков, для того чтобы эмулировать асинхронный I/O. Соответственно не совсем корректно утверждать что
1 thread может обрабатывать сотни запросов

Конечно, для node.js программиста высокоуровневая абстракция выглядит имеено таким образом. Но есть ли у вас возможность конфигурировать подлежащий пул потоков (например изменять количество потоков)? (если вопрос выглядит слишком по дилетантски — заранее прошу извинения, т.к. с node.js на практике не работал).

В этом плане решения на основе Java выглядят привлекательней, т.к. во всех серверных технологиях (будь то jetty, tomcat или даже комплексные application сервера, типа jboss) — есть возможность конфигурировать пул потоков, запускать потоки-демоны для фоновых задач и т.п. Относительно механизма реализации потоков в Java — можно сказать что он зависит от виртуальной машины, и в случае *nix — это могут быть те же pthreads.
— Но есть ли у вас возможность конфигурировать подлежащий пул потоков…

Есть встроенная библиотека, cluster. Можно запустить 1 местер поток, и несколько воркеров. Всё это повесить на 1 порт и кластер будет балансировать клиентов. Мастер в данном случае должен следить за воркерами (чтобы в случае падаения, запускать новых и т.д.).

Есть также child_process. Но это немного уже не туда.

Мы на проекте просто запускаем количество воркеров равное количеству ядер + мастер.
Для тех кто НЕ знает — cluster по сути представляет собой возможность спавна доп инстанцев которые НЕ могут иметь общую память и т.д. — Java Threads & Concurence на порядок лучше. Node.js использует разделяемые сокеты — тоже-самое можно и на Java. Балансировка идет силами НЕ node.js, а средствами OS. Child_process это как php::exec
P.S. от себя лично — количество воркеров должно быть несколько больше чем ядер — поскольку например на Xeon только так можно выжать максимальную производительность. (говорю за RHEL)
— Java Threads & Concurence на порядок лучше

Оно прекрасно, на вертикально маштабируемых решениях. так что заявление, мягко говоря — некорректно. У нас архитектура горизонтально расширяемая. Имеется десятки виртуалок (на api штук 40-50). Общая память там может помочь, только в рамках инстанса. У нас есть 1 сервис на каждом инстансе (https://github.com/romulka/nodejs-light_rpc), как локальный кеш, который сбрасывтся по подписке. С ним общаются все воркеры.

Про child_process я так и написал. Оно про другое. но возможность порождать процессы и общатся с ними есть.

Про воркеров, точно не могу сказать. Тесты не проводили. И у нас виртуальный хостинг, а там есть зависимость от соседей.
Тут не стоит задачи оптимизировать высоконагруженный сервер, к тому же в связке с Rhino все преимущества Netty могут легко потеряться. А вот Hello World на Netty может легко отпугнуть.

(В ответ на этот комментарий)
Я тоже хотел такую штуку попробовать :)
Есть даже идея делать свой веб-сервер на Java, чтобы в качестве скриптов можно было использовать всё что угодно: javascript, jruby, и.т.п., и API самые стандартные: из ноды, из рельс. Даёшь полную независимость от языков и API! Все на JVM!
Собственно говоря, ничто не мешает реализовать примеры из статьи на JRuby или Jython
Шел в надежде прочитать
Хоть Node.js и обзавелся с момента своего появления множеством модулей, он все еще существенно уступает по возможностям мощному набору библиотек Java.

А в итоге: «смотрите, вот хелловорд, свой сервер, шаблоны, майскл».

Тезисы не совпадают с содержимым и выводами. Смените заголовок.
Извините, по вашим коментам видно, что вы гнались не за производительностью, а за удобством.

Так вот, не понял где удобство. У вас не используется никакого удобного mvc-фреймворка. Для разработки используется весьма экзотическая реализация JS.

То есть вы считаете сервлеты на JS, удобнее, чем SpringMVC котнроллеры на Java?

Тоже самое и про работу с базой. Вместо удобного тула, у вас JDBC. И да, ResultSet и конекшны нужно закрывать. Перепешить код правильно и вся простота улетучится…

Если хочется чего-то удобного на JVM, я бы смотрел на Play! или Grails. Или на SpringMVC + Groovy.
И да, ResultSet и конекшны нужно закрывать

Согласен, досадная ошибка, исправил.
Так тоже не годится. Если у вас случится эксепшне до закрытия, то будут утекшие конекшны. Нужно в try / catch завернуть.
Хотел ускользнуть от этого неприятного момента :) Моя задача — предложить интересный концепт.
Так, мы все таки вымучаем правильную версию :) Вот этот код } catch(e) {} finally { для Connection-а очень плох. Ошибки конфигурации базы мы будем глотать. А еще соединение не пулированное. И нет обработки транзакции. Если вы все это напишете, то увидите насколько громоздко получается.
Вот этот код } catch(e) {} finally { для Connection-а очень плох. Ошибки конфигурации базы мы будем глотать.

Это же все-таки тестовый пример. Он либо работает, либо не работает, да и auto-commit тут вполне уместен. Конечно, в реальном проекте лучше пользоваться каким-нибудь DbUtils. Думаю, в ближайшее время напишу менее надуманный пример, с в том числе нормальной обработкой ошибок, тогда и можно будет вынести окончательный приговор этой связке библиотек.
Я понимаю, что это тестовый пример. Но тут получается некий обман. Вы хотите показать удобство выбранных вами технологий, хотя некоторые из них совсем не удобны, я имею в виду JDBC и Servets. Если написать все как в реальном приложении, получается каша.
Боюсь, автор гнался не за удобством, а за модой. Node.js ведь модно. Ни в коем случае не принижаю JavaScript, по писать на нем под JVM — это перебор, особенно если учесть наличие Groovy, JRuby, Scala, Clojure.
Как человек, очень плотно работающий с Rhino, не могу не отметить одну гадскую особенность — ошибку
«generated bytecode for method exceeds 64K limit»
которая упирается в ограничение Java на размер одного метода. Так что большие скрипты придется выполнять в интерпритируемом режиме
Можно бить на модули и по мере надобности компилировать части
Например, если модифицировать dbServlet.js так:
Скрытый текст
importPackage(java.sql);

function doGet(request, response) {
  try {
    var connection = DriverManager.getConnection('jdbc:mysql://localhost/?', 'root', '');
    try {    
      var resultSet = connection
        .createStatement()
        .executeQuery('show databases;');

      response.setContentType('text/html;charset=UTF-8');
      var writer = response.getWriter();
      writer.println('<h1>Databases</h1>');
      while (resultSet.next()) {
        writer.println(resultSet.getString('Database') + '<br />');
      }
    } catch(e) {} finally {
      resultSet.close();
    }
  } catch(e) {} finally {
    if(connection)
      connection.close();
  }  
};

if(this['exports'])
  exports.doGet = doGet;


И собрать так:
java -Djava.ext.dirs=./lib org.mozilla.javascript.tools.jsc.Main -extends javax.servlet.http.HttpServlet modules/dbServlet.js

То можно вызывать его так:
contextHandler.addServlet(
  new ServletHolder(new Packages.dbServlet()),
 '/db'
);


Естественно, добавив опцию -cp .:./modules
Не совсем понятна реализация многопоточности. Допустим:

var flag = false,
     runnable = new java.lang.Runnable({
     run: function() {
        print("I'm running!"); 
         flag = true;
    }
});
new java.lang.Thread(runnable).start();

while (!flag){}

print("Done"); 


Такое возможно?
Вполне. Правда, лучше пользоваться sync, примеры есть тут.
UFO just landed and posted this here
Главный вопрос: зачем юзать js на jvm когда есть scala, clojure, etc? если мы говорим об аналоге ноды?
Sign up to leave a comment.

Articles