qjs

优质
小牛编辑
137浏览
2023-12-01

但是,自mongols-1.8.0开始,提供一个基于quickjs引擎的新的javascript服务器。性能较之以前,有较大提升。

来看例子:

#include <mongols/qjs_server.hpp>
#include <mongols/util.hpp>

int main(int, char**)
{
    int port = 9090;
    const char* host = "127.0.0.1";
    mongols::qjs_server
        server(host, port, 5000, 8192, 0);
    server.set_root_path("html/qjs");
    server.set_enable_bootstrap(true);
    server.set_enable_lru_cache(false);
    server.set_lru_cache_expires(1);
    //    if (!server.set_openssl("openssl/localhost.crt", "openssl/localhost.key")) {
    //        return -1;
    //    }

    // server.set_shutdown([&]() {
    //     std::cout << "process " << getpid() << " exit.\n";
    // });
    // server.run();

    std::function<void(pthread_mutex_t*, size_t*)> ff = [&](pthread_mutex_t* mtx, size_t* data) {
        server.set_shutdown([&]() {
            std::cout << "process " << getpid() << " exit.\n";
        });
        server.run();
    };

    std::function<bool(int)> g = [&](int status) {
        return false;
    };

    mongols::multi_process main_process;
    main_process.run(ff, g);
}
import * as std from "std";
import * as os from "os";
import * as bjson from "bjson";
import * as mongols from "mongols";

mongols.status(200);
mongols.header('Content-Type', 'text/plain');
mongols.content("hello,world\n");

优化

qjs_server通过三个静态变量调整服务器工作状态。

qjs_server::memory_limit

默认值是1GB。它负责配置quickjs运行时能够使用的最大内存量。因为每一工作进程配有一个运行时,所以配置此值时需要考虑机器的硬件约束。通常默认值即可。

qjs_server::stack_limit

默认值是8MB。它负责配置quickjs运行时能够使用的最大stack量。因为每一工作进程配有一个运行时,所以配置此值时需要考虑机器的硬件约束。通常默认值即可。

qjs_server::ctx_called_limit

默认值是10240。它负责配置每一quickjs运行时上下文被使用的次数。值过小会导致效率下降,值过大则可能导致内存使用上升。通常默认值即可。配置时,需与qjs_server::memory_limit协调。

开启lru缓存机制

调用set_enable_lru_cache方法,参数为true即可。此法甚妙。1秒的过期时间,即可令服务器功力大增。

api

request

  • uri
  • method
  • client
  • param
  • user_agent
  • has_header
  • get_header
  • has_form
  • get_form
  • has_session
  • get_session
  • has_cookie
  • get_cookie
  • has_cache
  • get_cache

    response

  • status
  • content
  • header
  • session
  • cache

模块

quickjs原版内置三个模块:std、os和bjson,并且启用了数学扩展。我为其添加了三个内置模块:hash、crypto和mongols。qjs_server建立在mongols模块之上。hash模块提供md5、sha1、sha256和sha512计算,crypto模块提供AES加密服务。

路由

qjs_server提供一个默认的路由器。使用方法如下:

import * as mongols from "mongols";
import { crypto } from "crypto";
import route from "./lib/route.mjs"

var r = route.get_instance();

r.get('^/$', function (m, param) {
  m.status(200);
  m.header('Content-Type', 'text/plain;charset=utf-8');
  m.content('hello,world\n');
});

r.get('^/(.*)/?$', function (m, param) {
  m.header('Content-Type', 'text/plain;charset=UTF8')
  m.content(m.method() + '\n' + m.uri() + '\n' + param.toString())
  m.status(200)
});

var route_test = function (m) {
  r.run(m)
};


export default route_test;

路由器支持各种HTTP方法,具体可参考example/html/qjs/test/lib/route.mjs

如果有更好的路由器实现,欢迎替换。

压力测试比较

同样开4个工作进程,比较于nodejs(v13)下的fastify框架,qjs_server能够在每工作进程内存消耗仅仅十分之一的优势下,获得近两倍吞吐率:

const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
// Require the framework and instantiate it
const fastify = require('fastify')({ logger: false })



if (cluster.isMaster) {
  console.log(`Master ${process.pid} is running`);

  // Fork workers.
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

} else {

  // Declare a route
  fastify.get('/', async (request, reply) => {
    reply.header('Content-Type', 'text/plain;charset=utf-8')
    return 'hello,world\n';
  })

  // Run the server!
  const start = async () => {
    try {
      await fastify.listen(3000)
      fastify.log.info(`server listening on ${fastify.server.address().port}`)
    } catch (err) {
      fastify.log.error(err)
    }
  }
  start()

}
apib -c30000 -t4 -d30 http://localhost:3000/

(5 / 30) 5311.890 93% cpu
(10 / 30) 35488.653 100% cpu
(15 / 30) 39301.124 99% cpu
(20 / 30) 38975.863 100% cpu
(25 / 30) 40288.632 99% cpu
(30 / 30) 39911.255 100% cpu
Duration:             30.024 seconds
Attempted requests:   997245
Successful requests:  997245
Non-200 results:      0
Connections opened:   29996
Socket errors:        0

Throughput:           33214.740 requests/second
Average latency:      596.694 milliseconds
Minimum latency:      281.847 milliseconds
Maximum latency:      27382.753 milliseconds
Latency std. dev:     488.977 milliseconds
50% latency:          526.840 milliseconds
90% latency:          730.986 milliseconds
98% latency:          1915.567 milliseconds
99% latency:          3387.646 milliseconds

Client CPU average:    99%
Client CPU max:        100%
Client memory usage:    83%

Total bytes sent:      60.74 megabytes
Total bytes received:  144.56 megabytes
Send bandwidth:        16.18 megabits / second
Receive bandwidth:     38.52 megabits / second
apib -c30000 -t4 -d30 http://localhost:9090/

(5 / 30) 45417.124 95% cpu
(10 / 30) 63895.888 100% cpu
(15 / 30) 64130.772 100% cpu
(20 / 30) 64421.669 100% cpu
(25 / 30) 58932.007 100% cpu
(30 / 30) 64635.808 100% cpu
Duration:             30.024 seconds
Attempted requests:   1808772
Successful requests:  1808772
Non-200 results:      0
Connections opened:   29998
Socket errors:        0

Throughput:           60243.352 requests/second
Average latency:      483.053 milliseconds
Minimum latency:      150.099 milliseconds
Maximum latency:      2049.196 milliseconds
Latency std. dev:     131.720 milliseconds
50% latency:          469.488 milliseconds
90% latency:          574.891 milliseconds
98% latency:          804.549 milliseconds
99% latency:          1042.740 milliseconds

Client CPU average:    99%
Client CPU max:        100%
Client memory usage:    74%

Total bytes sent:      108.72 megabytes
Total bytes received:  238.05 megabytes
Send bandwidth:        28.97 megabits / second
Receive bandwidth:     63.43 megabits / second

所以不要轻易说quickjs不够快!