Исследование производительности серверов NODE.JS

  • Вид работы:
    Курсовая работа (т)
  • Предмет:
    Информационное обеспечение, программирование
  • Язык:
    Русский
    ,
    Формат файла:
    MS Word
    2,27 Мб
  • Опубликовано:
    2013-07-07
Вы можете узнать стоимость помощи в написании студенческой работы.
Помощь в написании работы, которую точно примут!

Исследование производительности серверов NODE.JS

Содержание

Введение

Глава 1. История развития Web-платформ    

Глава 2. Площадка для исследования   

Глава 3. Техническое описание процедуры тестирования         

Глава 4. Генерация пустых соединений

Глава 5. Генерация соединений с данными и запись их в файл 

Глава 6. Генерация соединений с данными и запись их в базу данных

Заключение        

Список использованных источников     

Введение

Нам интересно проанализировать поведение сервера Node.js в различных условиях его эксплуатации. Тестирование производительности будет происходить в три этапа, состоящих из двух типов тестов: load testing ("нагрузочное тестирование") и stress testing ("стрессовое тестирование"). Нагрузочное тестирование включает в себя измерение и анализ производительности системы в условиях нормальной предполагаемой загруженности, а стрессовое тестирование исследует поведение системы при максимальных загрузках. Целью стрессового тестирования является выявление слабых мест запущенного на сервере web-приложения и определения способности сервера к сохранению данных в экстремальных условиях.

Наиболее интересные для наблюдения параметры сервера:

Потребление памяти. Необходимо узнать изменение объёма используемой оперативной памяти, в зависимости от времени и количества подключений. В случае с Node.js важно производить наблюдения не только за значениями суммарной оперативной памяти, но и за ее компонентами - RSS (Resident set size - резидентная часть RAM) и JS heap (область динамически распределяемой оперативной памяти, выделенная операционной системой для работы Node.js)

Загрузка процессора. Объектом наблюдения за процессором является общая загрузка CPU, а также данные по загрузке каждого из ядер и каждого из процессов node.js

Отзывчивость сервера. Так называемый Event Loop - конструкция, циклично оперирующая различными событиями. В нашем исследовании важно, сколько раз за единицу времени возможно получить доступ к Event Loop при определённом количестве активных соединений.

Целью данного исследования будет проведение тестирования производительности Node.js сервера, в зависимости от количества и интенсивности подключений, а также анализ полученных данных. Результаты данного исследования будут использованы при планировании требуемых ресурсов и предполагаемой нагрузки в рамках пилотного проекта компании «Цифровая механика» в котором я принимаю участие.

Глава 1. История развития Web-платформ

Эволюция Интернета для Web-разработчиков - это в первую очередь эволюция его Web составляющей, эволюция платформ, языков программирования и разметки, используемых для обработки и предоставления информации пользователям. История сегодняшнего Web началась в 1991 году, с появлением стандарта HTML. Соответственно, Интернет 90-х представлял собой множество статичных, созданных вручную HTML страниц.

-е годы ознаменовались переходом на следующий уровень развития WEB - динамическую генерацию HTML страниц с использованием интерпретаторов, и в первую очередь интерпретатора PHP. Сам по себе PHP появился в 1994 году в качестве небольшого проекта, выводящего динамически генерируемую HTML-страничку резюме его создателя Расмуса Лердорфа. Собственно, отсюда и название PHP (Personal Home Page). Однако зрелости PHP достиг только к 4 версии, объединив большое число разработчиков и пользователей и «захватив» 10% Интернета. Еще одной аббревиатурой, которая олицетворяет «нулевые» можно назвать LAMP (набор серверного программного обеспечения, состоящий из Linux, Apache, MySQL, PHP). В то же время активно развивались все присутствующие сейчас в интернете технологии - ASP, Perl, Python, Ruby on Rails. Но все эти технологии работали по схожим принципам - динамически генерировали на сервере необходимые пользователю страницы и отдавали их в виде HTML файлов.

год можно смело назвать годом начала эры JavaScript. Почему именно 2010? Это оказалось переломным моментом для JavaScript технологий, которые уже несколько лет до этого вели успешное наступление на мир Web. Флагманом JavaScript можно было назвать библиотеку jQuery, которая к 2010 году использовалась на 28% сайтов в Интернет, а к 2013 этот показатель достиг 67% (всего 19 457 328 веб-сайтов).

Еще одной технологией, которую стоит упомянуть в связи с повсеместным использованием JavaScript является AJAX (Asynchronous JavaScript and XML). Точнее, AJAX - группа технологий, используемых на стороне клиента для создания асинхронных Web-приложений. При помощи AJAX приложение может асинхронно передавать и получать данные с сервера (в фоне) не мешая отображению существующей страницы, представленной пользователю. JavaScript, при этом, занимает центральную роль в группе технологий AJAX, связывая вместе все ее компоненты.

К 2010 году JavaScript использовался во многих крупных проектах Интернет: Twitter.com, Wikipedia.org, MLB.com, Amazon.com, Bing.com, Microsoft.com, Bit.ly, ESPN.com, Digg.com, Reddit.com, Netflix.com, WordPress.com, и это только начало списка.

Что же происходит теперь? В основе современных технологий лежит уже событийно-ориентированное программирование. Современные веб-страницы - это управляемые событиями приложения для обмена информацией, а не просто html-файлы. Главный принцип отображения информации в сегодняшнем Интернете - объектная модель документа (DOM) - по-прежнему существует, но это уже структура данных в памяти, генерируемая с использованием JavaScript, а не просто форма представления HTML разметки.

Современные технологии стремятся к большей эффективности, интерактивности, экономии ресурсов, поскольку значительно выросли объемы информации, запрашиваемой пользователями. Интернет слишком велик сегодня, и архитектура LAMP не справляется и оказывается слишком неповоротливой и ресурсоемкой. Сегодня нецелесообразно снова и снова отправлять большие объёмы HTML-разметки в ответ на каждое незначительное действие пользователя. Эффективнее обновлять небольшие фрагменты DOM с помощью асинхронных технологий наподобие AJAX. Главная функция сервера в современном Интернете - не хранение документов (эра HTML) или рендеринг шаблонов (эра LAMP), а доставка данных и функций для их обработки. Сервер должен отдать клиенту код приложения, а затем данные, которые приложение самостоятельно вставит в DOM. Кроме того, сервер должен отслеживать поток событий и рассылать клиентам обновлённые данные в ответ на эти события.

Почему Node.js?

Традиционные Web-приложения используют клиент-серверную программную модель. Клиентом выступает браузер пользователя, а сервером - одна из машин в центре обработки данных (ЦОД) некоторого поставщика услуг хостинга (хостера). Браузер запрашивает какой-то ресурс у сервера, а тот отдает его клиенту. Такой способ общения клиента и сервера называется «client pull». Сервер формирует ответ на запрос клиента и отдает ему его в удобоваримом виде. Такой простейший сервер умеет одновременно общаться лишь с одним пользователем. Если в момент обработки запроса к нему обратится еще один клиент, то ему придется ждать, пока сервер ответит первому. Значит, необходимо найти способ параллельной обработки запросов пользователей. Очевидное решение: обрабатывать запросы пользователей в отдельных потоках или процессах операционной системы. Данного подхода сейчас придерживались и продолжают придерживаются такие серверные платформы, как Apache и IIS.

Проблема состоит в том, что такая модель неспособна эффективно работать, если необходимо обрабатывать тысячи запросов одновременно. Причин для этого несколько. Во-первых, создание и процессов и потоков - ресурсоёмкая операция для любой операционной системы. Вместо этого можно создавать потоки или процессы заранее и использовать их по мере надобности. Такой механизм называется «thread pool» для потоков и «prefork» для процессов. Это помогает не тратить лишний раз ресурсы на создание процессов и потоков, поскольку эта накладная операция может быть выполнена один раз, при запуске сервера. Во-вторых, если все созданные процессы или потоки заняты, нужно создать новые. Но если добавить еще несколько потоков или процессов, то они будут конкурировать за процессорное время с уже исполняющимися потоками и процессами. А значит и те, и другие будут работать еще медленней. Если создавать поток для каждого из тысячи пользователей, то вскоре может оказаться, что памяти на сервере попросту не останется, а процессы будут находиться в состоянии постоянного соревнования за аппаратные ресурсы.

Посмотрев на эту проблему с другой стороны, всё выглядит не так уж безнадёжно. Большинство запущенных процессов всего лишь принимают запрос от клиента, создают ответ и отправляют его обратно клиенту. Самыми медленными частями этих взаимодействий являются прием запроса от клиента и отправка ответа (именно эти факторы напрямую зависят от скорости интернет-соединения). Теоретически, система ввода/вывода может работать в асинхронном режиме и не блокировать процессы. В таком случае, единственное чем занимаются процессы - это генерация ответа для клиента и управление заданиями для подсистемы ввода/вывода. Когда сетевой ввод/вывод делегирован подсистеме ввода/вывода, то один процесс может одновременно обслуживать несколько запросов, например, генерируя ответ для одного клиента, пока ответ для другого отдается подсистемой ввода/вывода. В данной ситуации, сервер может не выделять поток для каждого из пользователей, а может лишь создавать по одному процессу на каждый процессор сервера, предоставляя ему, максимум аппаратных ресурсов.

На практике такое делегирование реализуется с использованием парадигмы событийно-ориентированного программирования. Программы, разработанные согласно данной парадигме, могут быть реализованы как конечный автомат. Определенные события переводят данный автомат из одного состояния в другое.

Именно на этих принципах в 2009 году была создана серверная платформа Node.js, которая представляет собой серверную реализацию языка программирования JavaScript, основанную на движке V8 (та же самая среда исполнения для JavaScript, которую использует разработанный компанией Google браузер Google Chrome). V8 использует JIT-компиляцию и множество других приемов оптимизации. Так как JavaScript используется и клиентом и сервером, становится возможным перенести часть вычислений в браузер, без особых проблем с рассогласованием интерфейсов и без необходимости дважды писать код, делающий одно и то же, на разных языках..js сервер реализован в виде бесконечного цикла, который генерирует ответы для клиентов, опрашивает дескрипторы подсистемы ввода/вывода на предмет их готовности для выполнения той или иной операции, и, в случае успеха, передаёт им новое задание. Процесс опроса дескрипторов подсистемы ввода/вывода называется «polling». Эффективные реализации polling'а на сегодняшний день имеются лишь в *nix-системах, т.к. последние предоставляют очень быстрые системные вызовы c линейным временем исполнения для данных целей. Это очень эффективная модель сервера, т. к. позволяет использовать аппаратные ресурсы по максимуму.

Итак, Node.js - очень молодая и перспективная серверная платформа, которая теоретически может, а фактически сейчас производит революцию в мире веб-разработки. Поэтому, мы выбрали node.js для использования в данной работе.

Глава 2. Площадка для исследования

Описание проекта

На данный момент я трудоустроен в ООО "Цифровая механика", где являюсь JavaScript-разработчиком. Компания осуществляет разработку SaaS системы мониторинга и управления IT-инфраструктуры. Основные компоненты системы разработаны и начат процесс изучения возможностей масштабирования системы и способностей справляться с повышенными нагрузками. Предварительное изучение вопроса и базовые тесты компонентов системы ранее уже производились, но сейчас возникла потребность в получении конкретных численных показателей, описывающих работу системы в условиях эксплуатации, приближенным к рабочим.

Основные компоненты тестовой системы:

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

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

Подобная простая схема полностью аналогична одному из компонентов, который используется в разрабатываемом нами проекте.

Актуальные проблемы

И нагрузочное и стрессовое тестирование в данном случае подразумевают открытие большого количества соединений с сервером node.js. Под большим количеством имеются в виду десятки, или сотни тысяч одновременных сессий. Подобное количество одновременных подключений по умолчанию не поддерживается ни одной доступной нам операционной системой.

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

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

Аппаратные компоненты тестового стенда

В качестве сервера я использовал один из свободных компьютеров нашей компании. Данный компьютер обладает совсем небольшой вычислительной мощностью, которой всё же хватает для поддержания работы серверной части нашего тестового стенда.

Характеристики тестового стенда:: AMD Opteron(tm) Processor 4171 HE (2094.69MHz): 1720MB (210MB использует операционная система

Снимок экрана 1. Состояние компьютера по данным команды top.

В качестве клиентов, генерирующих запросы к серверу, использовались свободные ресурсы некоторых серверов ООО «Цифровая механика» и, в наибольшей степени, мой личный домашний компьютер.

Программные компоненты тестового стенда

На вышеописанном сервере установлена операционная система Ubuntu 12.04 LTS. Выбор был отдан именно этой системе, потому что во все продукты, разрабатываемые в нашей фирме, располагаются именно на Ubuntu.

Для того чтобы проводить тесты с таким большим количеством подключений, как мы запланировали, необходимо произвести некоторые дополнительные настройки в самой операционной системе Ubuntu:

) Во-первых нужно увеличить лимит дескрипторов файлов (на каждое соединение нужно по одному).

Это делается заменой параметра nofile в файле limits.conf :

#/etc/security/limits.conf

* - nofile 1048576

И заменой параметра net.ipv4.netfilter.ip_conntrack_max в файле sysctl.conf:

#/etc/sysctl.conf.ipv4.netfilter.ip_conntrack_max = 1048576

) Во-вторых необходимо изменить системные ограничения на открытые файлы. Это делается путём редактирования параметра «ulimit -n».

В работе используется программное обеспечение сервера Node.js версии 0.8.21. На одно соединение тратится минимум 10.3 Kb оперативной памяти (4.1 Kb Javascript Heap + 2.2 Kb Node.js Native + 4 Kb Kernel).

Глава 3. Техническое описание процедуры тестирования

Соединения между всеми запущенными агентами и сервером будут производиться по протоколу websocket. Websocket - это протокол полнодуплексной связи поверх TCP-соединения, который предназначен для обмена информацией между клиентской частью и сервером. С помощью этого протокола, для каждой связи между клиентом и сервером устанавливается одно TCP-соединение, которое постоянно держится открытым, но не передаёт лишних HTTP заголовков.

Принцип работы протокола websocket

Подключение клиента по протоколу TCP на определённый порт сервера.

Если сервер поддерживает websocket, то установление связи проходит успешно и между клиентом и сервером появляется открытое TCP-соединение.

Теперь по установленному каналу данных между двумя сторонами возможна передача данных формата 0x00, <строка в кодировке UTF-8>, 0xFF. В качестве строки может быть XML, JSON, простой текст и т.д.

Серверная часть приложения для тестирования

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

Создание http-сервера и websocket-сервера:

var server = require('http').createServer();webSocket = require('websocket').server;wsServer = new webSocket({httpServer: server});

Создание обработчиков сокетов

wsServer.on('request', function (request) {

if (request.origin === 'agent') {

// WebSocket-соединение возможно только с нашим клиентом

connection = request.accept('myprotocol', request.origin);.on('message', function (message) {

// Обработка данных при входящем сообщении

});

connection.on('close', function (reasonCode, description) {

// Обработка обрыва связи

});

} else {

// Если соединение приходит не с нашего клиента, то мы его обрываем.reject();;

}

});

Сбор данных о процессоре

fs.readFile("/proc/stat", "utf8", function (err, stats) {(err) return callback(err, {});= stats.split("\n")[0].split(" ").filter(Boolean).slice(1).map(Number);diffStats = [0,0,0,0,0,0,0,0,0,0];(lastCpuStats)= stats.map(function (s, i) {return s - lastCpuStats[i];});= stats;sum = 100;res = {};(var i = 0; i < cpuStatNames.length; i++)[cpuStatNames[i]] = diffStats[i] * 100 / sum;

callback(null, res);

})

Сбор данных об оперативной памяти

fs.readFile("/proc/meminfo", "utf8", function(err, stats) {(err) return callback(err, {});m = {};.split("\n").filter(Boolean).forEach(function(s) {vals = s.split(" ").filter(Boolean);[vals[0].slice(0, -1)] = +vals[1]*1024;

});res = {};(var key in memStatNames) {val = memStatNames[key];[key] = (typeof val === 'function') ? val(m) : m[val];

}(null, res);

});

Сбор данных об отзывчивости сервера

Отзывчивость (responsiveness) процесса - это время, которое нужно будет ждать событию перед тем, как его обработает Event Loop Node.js. Этот параметр принципиален в приложениях, работающих в real-time режиме. Этот параметр очень сложно рассчитать.

Следующим образом я смог получать достаточно верные данные об отзывчивости процесса:

Раз в 10 миллисекунд помещаем в массив текущее время. Функция timeFromLast конвертирует время в удобный для обработки формат.

var ticks = [];(function() {.push(timeFromLast('tick'));

}, 10);

Интервал замера 10мс был выбран как баланс между погрешностью и дополнительной нагрузкой системы. Если выводится 10/10/10ms - это не значит, что на обработку каждого события Node.js тратит по 10мс. Это значит, что при сетке измерения 10мс Event Loop каждый раз свободен и готов обрабатывать сразу любое поступившее событие, что означает, что среднее время обработки событий гораздо ниже. Если же вступает в действие Garbage Collector, или длинные операции, то мы это мгновенно увидим и зафиксируем.

Раз в секунду обрабатываем собранные данные (для вывода на экран и в лог-файл).

Вычисляем промежутки между тиками: ticks[i] = ticks[i+1]-ticks[i]

В полученном массиве ticks вычисляем среднее (tick-avg) и максимум (tick-max).

Выводим в приведенном порядке на экран и в лог.

Запись данных о системе в лог-файл

Я использовал формат CSV RFC4180: строки разделены переносами строки, значения разделены точкой с запятой.

var logStream = fs.createWriteStream("log"+new Date().toISOString().slice(0,19).replace(/:/g,"-")+".csv");logFrame(d) {values = [

// Main block.step,.totals.conns,

// CPU block.cpu.user.toFixed(1),.cpu.sys.toFixed(1),.cpu.idle.toFixed(1),.totals.cpuPercent.toFixed(1),

// Memory block(d.mem.used,0,1,2),(d.mem.caches,0,1,2),(d.totals.rss,0,1,2),(d.totals.mem.heapUsed,0,1,2),(d.totals.mem.heapTotal,0,1,2),

// Ticks block.totals.avgt.toFixed(1),.totals.maxt.toFixed(1),

// Misc block

(d.time-d.startTime).toFixed(),.generationTime.toFixed(),.totals.packets,

];.write(values.join(";") + "\n");

}

Вывод данных о системе на экран (раз в секунду)

Для наглядности тестирования была написана функция, которая выводит все данные в консоль раз в 1 секунду. Выглядит это следующим образом:

тестирование сервер программный протокол

Клиентская часть приложения для тестированиясоединение уникально определяется следующими параметрами:

адрес источника

порт источника

адрес назначения

порт назначения

Поскольку на одном компьютере всего 65536 портов, то мы можем установить порядка 64000 TCP-соединений с одного компьютера. Этого количества вполне достаточно для наших тестов.

Исходный код клиента

var WebSocketClient = require('websocket').client;

var config = {: 10000, // Количество устанавливаемых соединений: 'di-mex2.cloudapp.net', // Адрес сервера: 8080, // Порт сервера: 0, // Текущее количество соединений

};createConnection () {client = new WebSocketClient(); // Создание WebSocket-клиента

// Соединение к серверу.connect( 'ws://' + config.host + ':' + config.port + '/', 'myprotocol', 'agent' ); .on( 'connectFailed', function (error) {

// Действия при отказе в соединении от сервера

});.on( 'connect', function (connection) {

// Действия при успешном соединении

});

}newClient () {.count++; // Увеличиваем количество соединений на 1

createConnection(); // Создание WebSocket-соединения(config.count <= config.n) {

setTimeout(newClient, 5); // Создаём новое соединение каждые 5 миллисекунд

}

}(); // Начальный запуск

Запуск процедуры тестирования

> node server.js

Для запуска клиентской части, необходимо на любом компьютере (с любой операционной системой, на котором установлен node.js) выполнить команду

> node agent.js

Глава 4. Генерация пустых соединений

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

Нагрузочное тестирование

В системе производится генерация 10 000 «пустых» подключений с агента на сервер Node.js, затем в течение 15 минут происходит наблюдение за системой. Поскольку никакие данные через соединения не передаются, то мы наблюдаем значения параметров загрузки системы в начале тестирования (когда сгенерированы 10 000 соединений) и в конце, по истечению 15-ти минутного интервала. Ниже приведено сравнение значений нагрузки сервера в зависимости от времени.


На графике 1 заметно, что среднее значение загрузки процессора на протяжении всего тестирования колеблется около значения 20%. Загрузка оперативной памяти так же ведёт себя достаточно стабильно. Заметим, что график загрузки оперативной памяти имеет «пилообразный» вид. Дело в том, что во время работы нашего приложения происходит сборка мусора, формируя «пилу» в графике суммарной памяти. Судя по графику, сборка мусора происходит примерно 3 раза в минуту.


В графике отзывчивости сервера также наблюдается относительная стабильность.

Стрессовое тестирование


На графике 3 можно видеть, что стабильная высокая (>90%) загрузка процессора начинается после 20000 соединений. Интересно отметить, что частота сборки мусора растёт линейно и пропорциональна количеству соединений.

Отметим, что отзывчивость сервера резко ухудшается всё так же после 20000 соединений, это можно заметить на графике 4.


Глава 5. Генерация соединений с данными и запись их в плоский файл

Генерация соединений к серверу Node.js с передачей типовых сообщений от агента к серверу и записью данных сообщений в плоский файл на сервере. В данном случае мы хотели наблюдать изменение требований к вычислительным ресурсам сервера в зависимости от величины передаваемого сообщения при рабочей и экстремальной нагрузке.

Кроме того, поскольку в нашем рабочем прототипе происходит передача сообщений двух типов - короткие (несколько байт) и длинные (порядка 7КБ), мы используем также 2 типа сообщений для теста и наблюдаем зависимость рабочих параметров сервера от сообщений разной длины.

В качестве коротких строк мы используем примитивный JSON-объект вида

{

'a': 'b'

}

В качестве длинных строк используются JSON-объекты вида

{

'testKeyValue':'veryVeryLongDataValue',

. . .

'testKeyValue':'veryVeryLongDataValue'

}

длиной около 7000 символов (примерно 7КБ).

Для записи данных в файл, необходимо немного дополнить исходный код нашего сервера, который изначально настроен на обработку «пустых» соединений.

var fileStream = fs.createWriteStream('test.txt');.on('message', function (message) {

if (message.type === 'utf8') {

// При получении сообщения от клиента, записываем его в файл test.txt

fileStream.write(message.utf8Data + "\n");

}

});

Некоторые изменения коснулись и клиентской части. Теперь каждый из подключённых клиентов должен с определённой интенсивностью отсылать сообщения серверу. Время между отправкой сообщений выбирается случайным образом от 3 до 6 секунд. Это наиболее точным образом моделирует ситуацию нашего рабочего прототипа.

client.on( 'connect', function (connection) {

socketConnection = connection;

// При успешном соединении запускаем процедуру отправки сообщений

sendJSON();

});sendJSON() {( socketConnection.connected ) { .sendUTF( JSON.stringify( string ));

}

// Отправка строки со случайным периодом от 3 до 6 секунд( sendJSON, rand(3000, 6000) );

}

Нагрузочное тестирование

 

В случае с короткими строками (графики 5 и 6), заметно увеличение загрузки процессора примерно на 40% по сравнению с первой группой тестов. Показания оперативной памяти практически не изменились, за исключением того, что память стала чиститься в два раза чаще. Отзывчивость сервера очень незначительно ухудшилась.

Увеличение длины строк до 7000 символов (графики 7 и 8), дало очень незначительный прирост показателей загрузки системы и отзывчивости.

 

Стрессовое тестирование

 

 

Стрессовое тестирование в случае с «короткими» строками (графики 9 и 10) установило планку максимального количества клиентов на уровне 20000 штук. Заметное «торможение» сервера началось после 13000 подключений. В определённые моменты, после 17000 подключений, время между итерациями могло достигать 3 секунд и более.

В случае с «длинными» строками (графики 11 и 12), обрыв соединений начался при 14500 соединений. Граница резкого ухудшения отзывчивости сервера осталась на прежнем уровне - 13000 клиентов. После преодоления этой планки, время между итерациями порой достигало 5 секунд.

Глава 6. Генерация соединений с данными и запись их в базу данных

В данном случае запись передаваемых агентом сообщений производится не в плоский файл, а в базу данных. Это максимально приближает используемый нами стенд к рабочей системе, параметры нормальной и экстремальной работы которой мы хотели бы оценить. Аналогично второй группе тестов, мы будем использовать короткие и длинные сообщения, для оценки их влияния на параметры работы сервера.

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

var mongo = require("mongodb"),= mongo.Db,= mongo.Server,

_db = new Db("NodejsPerformance", new Server("127.0.0.1", 27017, {}), { w: 0 });

_db.open(function (err, db) {(!err) {testCollection = db.collection('TestCollection');.on('message', function (message) {

if (message.type === 'utf8') {

// При получении сообщения от клиента, записываем его в базу данных

var data = JSON.parse(message.utf8Data);

testCollection.insert(data);

}

});

}

});

Нагрузочное тестирование




Показания нагрузочного тестирования при 10000 клиентов с записью сообщений в базу данных оказались значительно хуже, чем во всех предыдущих тестах. И если показания процессора и памяти увеличились всего на несколько процентов, то отзывчивость сервера совершила резкий скачок вниз. В этой группе тестов мы получили достаточно стабильные временные задержки между итерациями более 5 секунд. Естественно, это является очень плохим показателем и сервер не должен работать на такой производительности. Стрессовое тестирование покажет, после какого количества подключений начинается такой упадок отзывчивости.

Стрессовое тестирование


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



Заключение

В данной работе изучались возможности масштабирования сетевых приложений, использующих программную инфраструктуру Node.js. В первую очередь нас интересовала зависимость системных показателей аппаратного сервера от количества сетевых подключений к серверу Node.js. Нами исследовалось поведение сервера Node.js при трех различных сценариях работы приложения:

Генерация соединений к серверу Node.js без передачи дополнительной информации по созданному подключению. Это позволило нам оценить требования к процессору и памяти сервера и наблюдать его поведение при рабочей и экстремальной нагрузке.

Генерация соединений к серверу Node.js с передачей типовых сообщений от агента к серверу и записью данных сообщений в плоский файл на сервере. В данном случае мы хотели наблюдать изменение требований к вычислительным ресурсам сервера в зависимости от величины передаваемого сообщения при рабочей и экстремальной нагрузке.

Генерация соединений к серверу Node.js с передачей типовых сообщений от агента к серверу и записью данных сообщений в базу данных. Т.к. большая часть создаваемых с использованием Node.js приложений использует в своей работе базу modgodb - нам было интересно проанализировать насколько отличается ситуация при записи в базу и в плоский файл.

В итоге мы получили значения показателей системы для каждой группы тестов. В таблице 1 показаны краткие результаты всех тестов. Значения CPU, RAM и отзывчивости приведены для нагрузочных тестов (при 10000 соединений). Параметр «Максимальное количество соединений» показывает, на каком количестве соединений при стрессовом тестировании происходил резкий упадок отзывчивости.


Пустые соединения

Запись в файл

Запись в БД



Короткие строки

Длинные строки

Короткие строки

Длинные строки

CPU

20%

60%

70%

80%

85%

RAM

25%

25%

25%

30%

30%

Отзывчивость

14мс

16мс

16мс

5500мс

6000мс

Максимальное количество соединений

20000

14000

13000

9000

8000

Таблица 1. Сравнение результатов тестов

Список использованных источников

.js v0.10.10 Manual & Documentation // nodejs.org [сайт]. URL: http://nodejs.org/api/ (дата обращения: 6.3.2013).

LearnBoost/socket.io Wiki GitHub // github.com [сайт]. URL: https://github.com/learnboost/socket.io/wiki (дата обращения: 6.3.2013).

The MongoDB Manual // mongodb.org [сайт]. URL: http://docs.mongodb.org/manual/ (дата обращения: 6.3.2013)..js - использования JavaScript для серверной разработки // microsoft.com [сайт]. http://msdn.microsoft.com/ru-ru/asp.net/hh548232 (дата обращения: 6.3.2013).

// 3rd-eden.com [сайт]. URL: http://blog.3rd-eden.com/post/5809079469/theoretical-node-js-real-time-performance (дата обращения: 20.3.2013).

Benchmarking Node.js - basic performance tests against Apache + PHP // zgadzaj.com [сайт]. http://zgadzaj.com/benchmarking-nodejs-basic-performance-tests-against-apache-php (дата обращения: 20.3.2013).

Миллион одновременных соединений на Node.js // habrahabr.ru [сайт]. http://habrahabr.ru/post/123154/ (дата обращения: 20.3.2013).

Stoyan Stefanov, JavaScript Patterns, O’Reilly Media Inc., 2010.Crockford, JavaScript: The Good Parts, O’Reilly Media Inc., 2008.Stefanov, Object-Oriented JavaScript: Create scalable, reusable high-quality JavaScript applications and libraries, Packt Publishing, 2008

Похожие работы на - Исследование производительности серверов NODE.JS

 

Не нашли материал для своей работы?
Поможем написать уникальную работу
Без плагиата!