不要使用默认 gcc,会编译安装 web3失败。

1
2
3
4
5
6
7
8
9
10
11
12
13
sudo yum erase -y gcc gcc-c++

sudo yum install -y centos-release-scl

sudo yum install -y devtoolset-3-toolchain

scl enable devtoolset-3 bash

yum remove -y nodejs

curl --silent --location https://rpm.nodesource.com/setup_8.x | sudo bash -

sudo yum -y install nodejs

不能使用全局安装,要尽量本地安装:

1
2
3
4
5
6
mkdir calc-node
npm init
npm install web3

# 照理来说这样也应该 work,但就是不 work
npm install -g web3 --unsafe-perm=true --allow-root

web3 本身是一系列 nodejs 模块的集合,包括但不限于

  1. web3-eth 针对以太坊区块链和智能合约
  2. web3-shh 针对耳语协议在 p2p 网络中的通信和广播
  3. The web3-bzz 针对 swarm 协议,去中心化的存储
  4. The web3-utils 针对 Dapp 的有用的功能

在 nodejs 中引入和初始化 web3 对象:

1
2
3
4
var Web3 = require('web3');
// 用两种端口初始化 web3 对象
var web3 = new Web3(Web3.givenProvider || "ws://localhost:8546");#默认节点只有 ws 才支持发布和订阅
web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

要使用的智能合约:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
pragma solidity ^0.4.15;


contract Calc {

/* 合约的创建者,可以在外部调用 owner() 来获取当前合约的创建者 */
address public owner;

/* 区块链存储 */
uint public count;

/* Event 是基于 log 的,写 event 类似于 写 log,外部的观察者通过过滤日志来读取事件 */
event AddEvent(address indexed from, address transactionSender, uint a, uint b, uint256 result);

event CountEvent(address indexed from, address transactionSender, uint result);

// This contract only defines a modifier but does not use
// it - it will be used in derived contracts.
// The function body is inserted where the special symbol
// "_;" in the definition of a modifier appears.
// This means that if the owner calls this function, the
// function is executed and otherwise, an exception is
// thrown.
modifier onlyOwner {
require(msg.sender == owner);
_;
}

/* 构造函数的写法 */
function Calc() public { owner = msg.sender; }

/* 执行会写入数据,所以需要`transaction`的方式执行。 */
function add(uint a, uint b) public returns (uint) {
count++;
uint c = realAdd(a, b);
AddEvent(
owner,
msg.sender,
a,
b,
c
);
return c;
}

/* 只有高版本的编译器才支持 pure 函数,这个 Vscode 插件不支持 */
function realAdd(uint a, uint b) public pure returns (uint) {
return a + b;
}

/* 执行不会写入数据,所以允许`call`的方式执行。 因为去掉了 constant 修饰符,所以这不再是个会引起警告的 view 方法了。*/
function getCount() public returns (uint) {
// 下一个返回值是给函数之间调用用的,要给外部的接口调用只好用 Event。
CountEvent(owner, msg.sender, count);
return count;
}
}

一些基本操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// 回调和 promise 串联
web3.eth.sendTransaction({from: '0x123...', data: '0x432...'})
.once('transactionHash', function(hash){ ... })
.once('receipt', function(receipt){ ... })
.on('confirmation', function(confNumber, receipt){ ... })
.on('error', function(error){ ... })
.then(function(receipt){
// will be fired once the receipt its mined
});

// 批量操作

new web3.BatchRequest()
new web3.eth.BatchRequest()
new web3.shh.BatchRequest()
new web3.bzz.BatchRequest()

var batch = new web3.BatchRequest();
batch.add(web3.eth.getBalance.request('0x0000000000000000000000000000000000000000', 'latest', callback));
batch.add(contract.methods.balance(address).call.request({from: '0x0000000000000000000000000000000000000000'}, callback2));
batch.execute();

// 获取特定的区块
web3.eth.getBlock("12").then(function(block){console.log(block)})

// 获取所有的账户信息
web3.eth.personal.getAccounts().then(function(a){console.log(a)})

// 获取 coinbase(暂时不 work)
web3.eth.coinbase

// 获取账户里的钱包(暂时不 work)
web3.eth.accounts
web3.eth.accounts.wallet

// 如果缺省的账户不存在,那么发送交易的时候就要显式指定 from 了
web3.eth.defaultAccount;
> undefined

// 用当前钱包的值设给 defaultAccount,这样 sendTransaction 和 call 就有默认的付账地址了
web3.eth.defaultAccount = 'bbb';

// 获取默认的区块
> web3.eth.defaultBlock
'latest'

// 获取当前协议版本
web3.eth.getProtocolVersion().then(console.log);

// 查看当前是否同步了
web3.eth.isSyncing().then(console.log);

// 获得 coinbase
web3.eth.getCoinbase().then(console.log);

// 当前是否挖矿
web3.eth.isMining().then(console.log);

// 获取当前的 gasprice
web3.eth.getGasPrice().then(console.log);

// 获取当前节点控制的所有账户
web3.eth.getAccounts().then(console.log);

// 获取当前的最晚块
web3.eth.getBlockNumber().then(console.log);

// 获取某个账户的余额
web3.eth.getBalance("bbb").then(console.log);

// 获取某个事务的具体信息
web3.eth.getTransaction('0x9fc76417374aa880d4449a1f7f31ec597f00b1f6f3dd2d66f4c9c6c445836d8b§234').then(console.log);

// 使用 call 的方式在当前 VM 下执行代码,但并不写进区块里。
web3.eth.call({
to: "0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe", // contract address
data: "0xc6888fa10000000000000000000000000000000000000000000000000000000000000003"
}).then(console.log);


// 合约相关
var myContract = new web3.eth.Contract([...], '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe', {
from: '0x1234567890123456789012345678901234567891', // default from address
gasPrice: '20000000000' // default gas price in wei, 20 gwei in this case
});

// 修改默认的值
myContract.options.from = '0x1234567890123456789012345678901234567891'; // default from address
myContract.options.gasPrice = '20000000000000'; // default gas price in wei
myContract.options.gas = 5000000; // provide as fallback always 5M gas

Calc 的相关 abi 和地址,并以此产生合约调用 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
var Web3 = require('web3');

var web3 = new Web3(Web3.givenProvider || "ws://localhost:8546");

web3.eth.defaultAccount = 'bbb';

// truffle 生成的 abi 和地址对。这个 abi 生成的 getCount签名是错的,慎用。
var abi = [{"constant":true,"inputs":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256"}],"name":"count","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256"}],"name":"add","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"view","type":"function","constant":true,"name":"owner","outputs":[{"name":"","type":"address"}]},{"anonymous":false,"inputs":[{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"transactionSender","type":"address"},{"indexed":false,"name":"a","type":"uint256"},{"indexed":false,"name":"b","type":"uint256"},{"indexed":false,"name":"result","type":"uint256"}],"name":"getCount","type":"function","constant":true,"outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view"},{"inputs":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function","constant":false,"name":"realAdd","outputs":[{"name":"","type":"uint256"}]},{"anonymous":false,"inputs":[{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"transactionSender","type":"address"},{"indexed":false,"name":"a","type":"uint256"},{"indexed":false,"name":"b","type":"uint256"},{"indexed":false,"name":"result","type":"uint256"}],"name":"EventSendCoin","type":"constructor","payable":false,"stateMutability":"nonpayable"},{"anonymous":false,"inputs":[{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"transactionSender","type":"address"},{"indexed":false,"name":"a","type":"uint256"},{"indexed":false,"name":"b","type":"uint256"},{"indexed":false,"name":"result","type":"uint256"}],"name":"addEvent","type":"event"}]

var address = '"0x46a0efeda982381e8a6d75b9b3d25cabcd6b16e9"';

// solcjs 生成的编译结果
var code = '0x6060604052341561000f57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061038a8061005e6000396000f30060606040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd14610072578063771602f71461009b5780638da5cb5b146100db578063a87d942c14610130578063e752be4e14610159575b600080fd5b341561007d57600080fd5b610085610199565b6040518082815260200191505060405180910390f35b34156100a657600080fd5b6100c5600480803590602001909190803590602001909190505061019f565b6040518082815260200191505060405180910390f35b34156100e657600080fd5b6100ee61027d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561013b57600080fd5b6101436102a2565b6040518082815260200191505060405180910390f35b341561016457600080fd5b6101836004808035906020019091908035906020019091905050610351565b6040518082815260200191505060405180910390f35b60015481565b6000806001600081548092919060010191905055506101be8484610351565b90506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fbcc141744793f7e93083ceb1e4a61664d4a6428dadf6db4d2e8b1a162d0582b233868685604051808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200184815260200183815260200182815260200194505050505060405180910390a28091505092915050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fd54b813e36aaac7612686fa27ef81917785024960e408194ccaeb6b17926cecc33600154604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a2600154905090565b60008183019050929150505600a165627a7a72305820d297e7e10c1b3d3f05cad089467287d5315e1957fe323040bcdea71f4eed65ad0029';
var abi = [{"constant":true,"inputs":[],"name":"count","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256"}],"name":"add","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"getCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256"}],"name":"realAdd","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":false,"name":"transactionSender","type":"address"},{"indexed":false,"name":"a","type":"uint256"},{"indexed":false,"name":"b","type":"uint256"},{"indexed":false,"name":"result","type":"uint256"}],"name":"AddEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":false,"name":"transactionSender","type":"address"},{"indexed":false,"name":"result","type":"uint256"}],"name":"CountEvent","type":"event"}];
// 安装还需要这个,注意,这段不能在 web3里执行。
/*
myContract = eth.contract(abi)
contract = myContract.new({from:eth.accounts[0],data:code,gas:1000000})
*/

// 当前合约的地址
var address = '0x980e5451d2bd9c524e33f543af81b14e787488ef';

// 用这对数据生成合约
var myContract = new web3.eth.Contract(abi, address, {
from: 'bbb',
gasPrice: '1' // default gas price in wei, 20 gwei in this case
});
myContract.options.from = 'bbb';

//调用合约的例子
myContract.methods.add(1, 2).call({ from: web3.eth.defaultAccount}, function(error, result){console.log(error);console.log(result)})
myContract.methods.add(1, 2).send({ from: web3.eth.defaultAccount}, function(error, result){console.log(error);console.log(result)})
myContract.methods.add(1, 2).call({}, function(error, result){console.log(error);console.log(result)})
myContract.methods.owner().call({ from: 'bbb'}, function(error, result){console.log(error);console.log(result)})
myContract.methods.getCount().call({}, function(error, result){console.log(error);console.log(result)})
//所有的 call 都可以变成 send 版本。单纯的 call add 不会增加 count,但 send add 增加的 count 可以被 call getCount 读出来

// 相关的事件监听
myContract.events.AddEvent({
filter: {from: web3.eth.defaultAccount},
fromBlock: 0,
toBlock: 'latest'
}, function(error, e){
if(!error) {
console.log('the error is: ' + error)
}
if(!e) {
console.log('the result is: ' + e.returnValues.result)
}
}).on('data', function(e){
// 这个 e 和前一个回调里的 e 是一样的
console.log('the result is: ' + e.returnValues.result)
}).on('changed', function(e){
console.log('inside the changed callback: ' + e);
}).on('error', console.error);

//打出所有的相关事件和事务处理结果
myContract.methods.add(1, 2).send({ from: web3.eth.defaultAccount}, function(error, result){console.log(result)}).on('transactionHash', function(hash){
console.log('on transactionHash: ' + hash);
}).on('confirmation', function(confirmationNumber, receipt){
//console.log('confirmationNumber: ' + confirmationNumber);
//console.log('receipt: ' + JSON.stringify(receipt));
}).on('receipt', function(receipt){
console.log('receipt: ' + JSON.stringify(receipt));
console.log('result is:' + receipt.events.AddEvent.returnValues.result)
}).on('error', console.error);

//获取所有历史事件
myContract.getPastEvents('AddEvent', {
fromBlock: 0,
toBlock: 'latest'
}, function(error, events){ console.log('events are: ' + events); })
.then(function(events){
console.log("inside then: " + events) // same results as the optional callback above
});

最终版本的 calc-node.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
const Koa = require('koa');
const app = new Koa();

const Web3 = require('web3');
const web3 = new Web3(Web3.givenProvider || "ws://localhost:8546");

web3.eth.defaultAccount = 'bbb';
const code = '0x6060604052341561000f57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555061038a8061005e6000396000f30060606040526004361061006d576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306661abd14610072578063771602f71461009b5780638da5cb5b146100db578063a87d942c14610130578063e752be4e14610159575b600080fd5b341561007d57600080fd5b610085610199565b6040518082815260200191505060405180910390f35b34156100a657600080fd5b6100c5600480803590602001909190803590602001909190505061019f565b6040518082815260200191505060405180910390f35b34156100e657600080fd5b6100ee61027d565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561013b57600080fd5b6101436102a2565b6040518082815260200191505060405180910390f35b341561016457600080fd5b6101836004808035906020019091908035906020019091905050610351565b6040518082815260200191505060405180910390f35b60015481565b6000806001600081548092919060010191905055506101be8484610351565b90506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fbcc141744793f7e93083ceb1e4a61664d4a6428dadf6db4d2e8b1a162d0582b233868685604051808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200184815260200183815260200182815260200194505050505060405180910390a28091505092915050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff167fd54b813e36aaac7612686fa27ef81917785024960e408194ccaeb6b17926cecc33600154604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a2600154905090565b60008183019050929150505600a165627a7a72305820d297e7e10c1b3d3f05cad089467287d5315e1957fe323040bcdea71f4eed65ad0029';
const abi = [{"constant":true,"inputs":[],"name":"count","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256"}],"name":"add","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"getCount","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"a","type":"uint256"},{"name":"b","type":"uint256"}],"name":"realAdd","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"pure","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":false,"name":"transactionSender","type":"address"},{"indexed":false,"name":"a","type":"uint256"},{"indexed":false,"name":"b","type":"uint256"},{"indexed":false,"name":"result","type":"uint256"}],"name":"AddEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"from","type":"address"},{"indexed":false,"name":"transactionSender","type":"address"},{"indexed":false,"name":"result","type":"uint256"}],"name":"CountEvent","type":"event"}];

/*
myContract = eth.contract(abi)
contract = myContract.new({from:eth.accounts[0],data:code,gas:1000000})
*/
const address = '0x980e5451d2bd9c524e33f543af81b14e787488ef';

const myContract = new web3.eth.Contract(abi, address, {
from: web3.eth.defaultAccount,
gasPrice: '1' // default gas price in wei, 20 gwei in this case
});

const log = console.log;
const error = console.error;

// 相关的事件监听。注意,这是个事件扫描器,所以在安装上去的那一刻,它会先把所有历史数据都扫出来。
//myContract.events.AddEvent({
// filter: {from: web3.eth.defaultAccount},
// fromBlock: 0,
// toBlock: 'latest'
//}, function(error, e){
// if(!error) {
// console.log('the error is: ' + error)
// }
// if(!e) {
// console.log('the result is: ' + e.returnValues.result)
// }
// }).on('data', function(e){
// 这个 e 和前一个回调里的 e 是一样的
// console.log('the result is: ' + e.returnValues.result)
//}).on('changed', function(e){
// console.log('inside the changed callback: ' + e);
//}).on('error', console.error);

//myContract.methods.add(1, 2).call({ from: web3.eth.defaultAccount}, function(error, result){console.log(error);console.log(result)});
//myContract.methods.add(1, 2).send({ from: web3.eth.defaultAccount}, function(error, result){console.log(error);console.log(result)});

web3.eth.personal.unlockAccount(web3.eth.defaultAccount, '123456', 0).then(function(){

async function add(a, b) {
const finalResult = await myContract.methods.add(1, 2).send({ from: web3.eth.defaultAccount}).then(function(receipt){
const result = receipt.events.AddEvent.returnValues.result;
log('add result is: ' + result);
return result;
});
return finalResult;
}


async function getCount() {
const finalResult = await myContract.methods.getCount().send({ from: web3.eth.defaultAccount}).then(function(receipt){
const result = receipt.events.CountEvent.returnValues.result;
log('count result is: ' + result);
return result;
});
return finalResult;
}

// x-response-time

app.use(async (ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
ctx.set('X-Response-Time', `${ms}ms`);
});

// logger

app.use(async (ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
log(`${ctx.method} ${ctx.url} - ${ms}`);
});

// response

app.use(async ctx => {
ctx.body = 'Hello World: ' + await add(1, 2) + ', Count is: ' + await getCount();
});

app.listen(3000);

app.on('error', (err, ctx) => {
error('server error', err, ctx)
});
});

用一下命令来nohup 执行脚本:

1
nohup node calc-node.js node.log&

需要使用的 package.json:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"name": "calc-node",
"version": "1.0.0",
"description": "",
"main": "calc-node.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"koa": "^2.4.1",
"web3": "^1.0.0-beta.24"
},
"devDependencies": {
"koa-router": "^7.3.0"
}
}

用 ab 进行 benchmark:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# 并发数量一次发30个请求,一共发100个
ab -c 30 -n 100 http://lan-consul-dev2:3000/

#一个测试结果
$ ab -c 1000 -n 1000 http://lan-consul-dev2:3000/


This is ApacheBench, Version 2.3 <$Revision: 1757674 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking lan-consul-dev2 (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:
Server Hostname: lan-consul-dev2
Server Port: 3000

Document Path: /
Document Length: 14 bytes

Concurrency Level: 1000
Time taken for tests: 55.854 seconds
Complete requests: 1000
Failed requests: 0
Total transferred: 176000 bytes
HTML transferred: 14000 bytes
Requests per second: 17.90 [#/sec] (mean)
Time per request: 55853.763 [ms] (mean)
Time per request: 55.854 [ms] (mean, across all concurrent requests)
Transfer rate: 3.08 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 20 107 55.5 101 209
Processing: 14015 38377 13924.0 41754 55628
Waiting: 14014 38377 13924.1 41753 55628
Total: 14213 38484 13870.7 41842 55677

Percentage of the requests served within a certain time (ms)
50% 41842
66% 49023
75% 49181
80% 52633
90% 52716
95% 55616
98% 55634
99% 55645
100% 55677 (longest request)

运维须知:

要千万小心,重启了 node 节点以后,要重新 unlock account,不然还是连不上。koa 应用程序不需要重启。

1
2
ab -n 3000 -c 3000 http://blockchain-02:3000/api/v1/insurance-order/mobileNo/28
ab -n 3000 -c 3000 http://10.95.178.155:3000/api/v1/insurance-order/mobileNo/28