Tag Archives: nodejs

bcrypt в NodeJS в Windows 10 Home и Linux Mint

Я работаю с nodejs в Windows 10 Home (параллельно иногда загружаюсь в Linux Mint, но редко).

Изучаю книгу `Node.JS в действии`, она, к сожалению, в некоторых местах устарела, но в целом даёт представление о теме.

Итак, в главе 9 нам нужен был brcypt, но простой npm install bcrypt –save завершился с ошибкой.
Пошарив инете пару минут, я понял, что просто так его не установить, и я уже думал проверять примеры в Linux Mint‘е своём любимом, но наткнулся здесь: http://stackoverflow.com/questions/14573488/error-compiling-bcrypt-node-js

Оказывается, bcrypt можно заменить bcrypt-nodejs, который у меня установился без проблем за пару секунд.
Далее по теме увидел такую надпись: The performance is a lot slower though, то есть, мол, производительность гораздо ниже, и даётся ссылка на https://github.com/adrianblynch/bcrypt-vs-bcrypt/blob/master/index.js.

Там тестятся следующие bcrypt пакеты для nodejs:

И даётся простенький скрипт-тестирование (его мы дополним и рассмотрим ниже).

Можно запустить, потестить какие результаты даст, сделаю это через какое-то время в Linux Mint’е (т.к. под свою Windows bcrypt я не установил и не буду заморачиваться, время терять).

Но в этом тесте нет bcrypt-nodejs, я его добавлю тогда, ОК, и результаты позже выведу **** обещанного три года ждут. 🙂

Но какова мораль сей басни? Nodejs настолько стремительно развивающийся проект со столькими вовлеченными и увлеченными пользователями, что для любой более-менее известной и популярной либы есть несколько решений под эту удивительную платформу. И если какая-то либа по тем или иным причинам не подойдёт (как например в нашем случае с bcrypt под Windows 10 (8, 8.1, 7 да любой наверное), мы с большой вероятностью можем найти полноценную замену.

Например, для mongodb есть mongoose, и есть monk, для sqlite куча пакетов, и т.д.

А почему стремительно развивающийся? Например, на оф.страничке Express (http://expressjs.com/en/guide/migrating-4.html) есть устаревший уже пример с multer (обработка запросов multipart/form-data) – там приводится пример для работы с “multer”: “^0.1.3”, а сейчас уже есть multer 1.1.0 (на 4 февраля 2016 года – 2016-02-04), который не совместим с указанным multer‘ом, то есть он не может напрямую выступать в качестве middleware теперь, а надо использовать по особому его методы single, array и т.п. (http://stackoverflow.com/questions/31495499/multer-configuration-with-app-use-returns-typeerror/31495796#31495796):

multer({dest:'./uploads/'}).single(...)
multer({dest:'./uploads/'}).array(...)
multer({dest:'./uploads/'}).fields(...)

На сим всё, откланиваюсь – за мной ещё тесты производительности, если не забуду. )))

Тесты производительности различных пакетов bcrypt для NodeJS

Итак, что мы делаем?
Перезагржаемся в LinuxMint, смотрим систему:

$ uname -a
Linux justy 3.13.0-51-generic-tuxonice #84~ppa1-Ubuntu SMP
Wed Apr 29 19:39:16 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux

Создаём папку, в ней nodejs-проект

$ mkdir bcrypt-bench
$ cd bcrypt-bench/
$ npm init
...
... - все параметры можно оставить по умолчанию,
они в принципе не играют большой роли здесь

Инсталлируем нужные пакеты с добавлением в packaje.json (флаг –save)

$ npm install bcrypt bcryptjs twin-bcrypt bcrypt-nodejs commander --save
 
> bcrypt@0.8.5 install /home/justy/nodejs/bcrypt-bench/node_modules/bcrypt
> node-gyp rebuild
 
make: Вход в каталог `/home/justy/nodejs/bcrypt-bench/node_modules/bcrypt/build'
  CXX(target) Release/obj.target/bcrypt_lib/src/blowfish.o
  CXX(target) Release/obj.target/bcrypt_lib/src/bcrypt.o
  CXX(target) Release/obj.target/bcrypt_lib/src/bcrypt_node.o
  SOLINK_MODULE(target) Release/obj.target/bcrypt_lib.node
  COPY Release/bcrypt_lib.node
make: Выход из каталога `/home/justy/nodejs/bcrypt-bench/node_modules/bcrypt/build'
bcrypt-bench@1.0.0 /home/justy/nodejs/bcrypt-bench
├─┬ bcrypt@0.8.5
│ ├── bindings@1.2.1
│ └── nan@2.0.5
├── bcrypt-nodejs@0.0.3
├── bcryptjs@2.3.0
├─┬ commander@2.9.0
│ └── graceful-readlink@1.0.1
└── twin-bcrypt@2.1.1
 
npm WARN EPACKAGEJSON bcrypt-bench@1.0.0 No repository field.

В результате наш package.json будет выглядеть примерно так:

{
  "name": "bcrypt-bench",
  "version": "1.0.0",
  "description": "Simple benchmarking for varios nodejs bcrypt packages",
  "main": "test.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "brcypt",
    "bench",
    "test"
  ],
  "author": "adrianblynch",
  "license": "MIT",
  "dependencies": {
    "bcrypt": "^0.8.5",
    "bcrypt-nodejs": "0.0.3",
    "bcryptjs": "^2.3.0",
    "commander": "^2.9.0",
    "twin-bcrypt": "^2.1.1"
  }
}

Теперь создаём скрипт test.js, скопировав его отсюда: https://github.com/adrianblynch/bcrypt-vs-bcrypt/blob/master/index.js и добавив в него пакет bcrypt-nodejs:

var bcrypt = require('bcrypt');
var bcryptJS = require('bcryptjs');
var twinBcrypt = require('twin-bcrypt');
var bcryptNodeJs = require('bcrypt-nodejs');
 
var commander = require('commander');
 
commander
.option('-r, --rounds [num]', 'Number of rounds to use', parseInt)
.option('-i, --iterations [num]', 'Number of iterations to use', parseInt)
.parse(process.argv);
 
var password = "password";
var rounds = commander.rounds || 12;
var iterations = commander.iterations || 10;
var hash, start, end, i, total;
 
console.log("Bcrypts ready? Fight!");
 
// bcrypt
 
total = 0;
 
for (i = 0; i < iterations; i++) {
	start = new Date();
	hash = bcrypt.hashSync(password, bcrypt.genSaltSync(rounds));
	end = new Date();
	total += (end - start);
}
 
console.log("bcrypt - " + iterations + " iterations took " + total + "ms which is an average of " + parseInt(total / iterations) + "ms each");
 
// bcryptjs
 
total = 0;
 
for (i = 0; i < iterations; i++) {
	start = new Date();
	hash = bcryptJS.hashSync(password, bcryptJS.genSaltSync(rounds));
	end = new Date();
	total += (end - start);
}
 
console.log("bcryptjs - " + iterations + " iterations took " + total + "ms which is an average of " + parseInt(total / iterations) + "ms each");
 
// twin-bcrypt
 
total = 0;
 
for (i = 0; i < iterations; i++) {
	start = new Date();
	hash = twinBcrypt.hashSync(password, twinBcrypt.genSalt(rounds));
	end = new Date();
	total += (end - start);
}
 
console.log("twin-bcrypt - " + iterations + " iterations took " + total + "ms which is an average of " + parseInt(total / iterations) + "ms each");
 
// bcrypt-nodejs
 
total = 0;
 
for (i = 0; i < iterations; i++) {
	start = new Date();
	hash = bcryptNodeJs.hashSync(password, bcryptNodeJs.genSaltSync(rounds));
	end = new Date();
	total += (end - start);
}
 
console.log("bcrypt-nodejs - " + iterations + " iterations took " + total + "ms which is an average of " + parseInt(total / iterations) + "ms each");

Всё готово для запуска тестов:

$ node test.js
Bcrypts ready? Fight!
bcrypt - 10 iterations took 2813ms which is an average of 281ms each
bcryptjs - 10 iterations took 8523ms which is an average of 852ms each
twin-bcrypt - 10 iterations took 8650ms which is an average of 865ms each
bcrypt-nodejs - 10 iterations took 8144ms which is an average of 814ms each

Как видим, стандартный bcrypt практически в 3 раза быстрее своих собратьев,
что не удивительно, так как он использует пре-компилированную версию, в то время как остальные написаны на чистом JavaScript и прогоняются ч/з интерпретатор V8, как бы он быстр не был.

Вторая мораль сей басни такова – если в нашем проекте требуется много и часто хэшировать с помощью алгоритма bcrypt’а, следует предпочесть bcrypt.

Сладкого чая и вкусной слойки на столе! С цукерками в вазочке.