基于多线程的一个Node补环境框架(踩坑1)

背景

原本想统一使用vm2沙箱取执行算法/补环境,但是上线后,遇到了这样一个工作量证明算法,是一个CPU密集型任务,很容易把cpu打满,导致服务崩溃无法接收任务

工作量证明算法:找到一个数值,使得该数值与特定数据组合后的哈希值满足特定条件(这个数值一般当成sign);但是这个算法是一个cpu密集型任务。

案例

Node执行脚本以及结果验证

=== 开始执行 ===
初始内存使用: { rss: '25 MB', heapUsed: '4 MB', heapTotal: '4 MB' }
=== Node执行完成 ===
执行时间: 456.38 ms
最终内存使用: { rss: '33 MB', heapUsed: '5 MB', heapTotal: '6 MB', external: '2 MB' }
内存变化: { rss: '8 MB', heapUsed: '1 MB', heapTotal: '2 MB', external: '0 MB' }
CPU 使用时间: { user: '438.00 ms', system: '110.00 ms' }
Result: W3siand0IjoiZXlKaGJHY2lPaUpJVXpJMU5pSjkuZXlKd2RYcDZiR1VpT2lKQlFVRkJRVUZDYW5wSWRubzVlUzh6YUVORlMwRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZDUkV0WFowdDRjMDlaYUN0VU5tMXFSR001WTI0eGRXOXdUblpPZUVrMGEwOTJVekpzSzI1dllsTlRRVDA5SWl3aWFXRjBJam94TnpZek5UVTVPRGM0TENKbGVIQWlPakUzTmpNMU5UazVNemg5LmlzUncyTFZnVlQxYzBpMUZ0a2RCWTZYb2p3NjdLS2E3aEQtbHEtNnhqUFEiLCJzb2x1dGlvbiI6IlFnRUFBQUFBQUFBPSJ9LHsiand0IjoiZXlKaGJHY2lPaUpJVXpJMU5pSjkuZXlKd2RYcDZiR1VpT2lKQlFVRkJRVUZDY0hwR2JGRlVjM1p4Wm5sRlMwRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZDUkV0WFowdDRjMDlaYUN0VU5tMXFSR001WTI0eGRXOXdUblpPZUVrMGEwOTJVekpzSzI1dllsTlRRVDA5SWl3aWFXRjBJam94TnpZek5UVTVPRGM0TENKbGVIQWlPakUzTmpNMU5UazVNemg5LkxCc0VBem1yZ2ktZTk2Zk1lVEctTU1wY0p2QVgyU0VXdTlDdUJ0eGRCZzgiLCJzb2x1dGlvbiI6IjNnOEFBQUFBQUFBPSJ9LHsiand0IjoiZXlKaGJHY2lPaUpJVXpJMU5pSjkuZXlKd2RYcDZiR1VpT2lKQlFVRkJRVUZFTjNOa1MyaHBUMDQwZFdsRlMwRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZDUkV0WFowdDRjMDlaYUN0VU5tMXFSR001WTI0eGRXOXdUblpPZUVrMGEwOTJVekpzSzI1dllsTlRRVDA5SWl3aWFXRjBJam94TnpZek5UVTVPRGM0TENKbGVIQWlPakUzTmpNMU5UazVNemg5Lm5OUm00WEdtdGRGTDNmQ0RhMC1WbVcxSVgwSXFBQ3ctVzBSeE80Z3dvTFkiLCJzb2x1dGlvbiI6Ilcza0FBQUFBQUFBPSJ9XQ==
Performance: {
  executionTime: '456.38 ms',
  memoryUsage: {
    rss: '8 MB',
    heapUsed: '1 MB',
    heapTotal: '2 MB',
    external: '0 MB'
  },
  cpuUsage: { user: '438.00 ms', system: '110.00 ms' }
}
const crypto = require('crypto');

//#region 改写 sha256 方法, 原方法使用的浏览器 sha256 方法在 node 不适用
async function sha256(input) {
    const hash = crypto.createHash('sha256');
    const buffer = input instanceof Buffer ? input : Buffer.from(input);
    hash.update(buffer);
    return hash.digest();
}
//#endregion

//#region 原始加密代码
async function t(t) {
    const e = function (t, n) {
        const r = BigInt(8 * (t - 3))
            , e = BigInt(2);
        let o = e;
        for (let t = 1; t < r; t++)
            o *= e;
        return BigInt(n) * o
    }(t[13], t[14]);

    return o = await async function (t, e) {
        let o = 0;
        const startTime = Date.now();
        const MAX_ITERATIONS = 50000;
        const MAX_TIME = 8000;
        
        do {
            const a = r(o);
            if (await n(a, t) < e)
                return a
                
            if (o % 1000 === 0) {
                if (o > MAX_ITERATIONS) {
                    break;
                }
                if (Date.now() - startTime > MAX_TIME) {
                    break;
                }
                await new Promise(resolve => setTimeout(resolve, 0));
            }
        } while (++o <= Number.MAX_VALUE);
        
        return new Int8Array(0)
    }(t, e),
        btoa(String.fromCharCode(...new Uint8Array(o)));
    var o
}

async function n(t, n) {
    const r = function (t, n) {
        const r = new Int8Array(40);
        for (let n = 0; n < 32; n++)
            r[n] = t[n];
        for (let t = 32; t < 40; t++)
            r[t] = n[t - 32];
        return r
    }(n, t)
        , e = await sha256(Buffer.from(r))
        , o = await sha256(Buffer.from(e));
    return function (t) {
        let n = BigInt(0);
        for (let r = t.length - 1; r >= 0; r--)
            n = BigInt(n) * BigInt(256),
                n += BigInt(t[r]);
        return n
    }
    (new Uint8Array(o))
}

function r(t) {
    const n = new Int8Array(8);
    for (let r = 0; r < n.length; r++) {
        const e = 255 & t;
        n[r] = e,
            t = (t - e) / 256
    }
    return n
}
//#endregion

//#region 封装输出
async function execute(body) {
    const b = await Promise.all(atob(body).split(",").map(s => {
        const m = JSON.parse(atob(s.split(".")[1]));
        return {
            jwt: s,
            puzzle: Int8Array.from(atob(m.puzzle), F => F.charCodeAt(0))
        }
    }).map(async (s) => { return { jwt: s.jwt, solution: await t(s.puzzle) } }))
    return btoa(JSON.stringify(b))
}
//#endregion

// Node.js 性能监控
async function measurePerformance(body) {
    const startTime = process.hrtime.bigint();
    const initialMemory = process.memoryUsage();
    const initialCpuUsage = process.cpuUsage();
    
    console.log('=== 开始执行 ===');
    console.log('初始内存使用:', {
        rss: Math.round(initialMemory.rss / 1024 / 1024) + ' MB',
        heapUsed: Math.round(initialMemory.heapUsed / 1024 / 1024) + ' MB',
        heapTotal: Math.round(initialMemory.heapTotal / 1024 / 1024) + ' MB'
    });
    
    const result = await execute(body);
    
    const endTime = process.hrtime.bigint();
    const finalMemory = process.memoryUsage();
    const finalCpuUsage = process.cpuUsage(initialCpuUsage);
    
    const executionTime = Number(endTime - startTime) / 1000000; // 转换为毫秒
    
    console.log('=== Node执行完成 ===');
    console.log('执行时间:', executionTime.toFixed(2) + ' ms');
    console.log('最终内存使用:', {
        rss: Math.round(finalMemory.rss / 1024 / 1024) + ' MB',
        heapUsed: Math.round(finalMemory.heapUsed / 1024 / 1024) + ' MB',
        heapTotal: Math.round(finalMemory.heapTotal / 1024 / 1024) + ' MB',
        external: Math.round(finalMemory.external / 1024 / 1024) + ' MB'
    });
    console.log('内存变化:', {
        rss: Math.round((finalMemory.rss - initialMemory.rss) / 1024 / 1024) + ' MB',
        heapUsed: Math.round((finalMemory.heapUsed - initialMemory.heapUsed) / 1024 / 1024) + ' MB',
        heapTotal: Math.round((finalMemory.heapTotal - initialMemory.heapTotal) / 1024 / 1024) + ' MB',
        external: Math.round((finalMemory.external - initialMemory.external) / 1024 / 1024) + ' MB'
    });
    console.log('CPU 使用时间:', {
        user: (finalCpuUsage.user / 1000).toFixed(2) + ' ms',
        system: (finalCpuUsage.system / 1000).toFixed(2) + ' ms'
    });
    
    return {
        result: result,
        performance: {
            executionTime: executionTime.toFixed(2) + ' ms',
            memoryUsage: {
                rss: Math.round((finalMemory.rss - initialMemory.rss) / 1024 / 1024) + ' MB',
                heapUsed: Math.round((finalMemory.heapUsed - initialMemory.heapUsed) / 1024 / 1024) + ' MB',
                heapTotal: Math.round((finalMemory.heapTotal - initialMemory.heapTotal) / 1024 / 1024) + ' MB',
                external: Math.round((finalMemory.external - initialMemory.external) / 1024 / 1024) + ' MB'
            },
            cpuUsage: {
                user: (finalCpuUsage.user / 1000).toFixed(2) + ' ms',
                system: (finalCpuUsage.system / 1000).toFixed(2) + ' ms'
            }
        }
    };
}

// 测试数据
const bbb = 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuZXlKd2RYcDZiR1VpT2lKQlFVRkJRVUZDYW5wSWRubzVlUzh6YUVORlMwRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZDUkV0WFowdDRjMDlaYUN0VU5tMXFSR001WTI0eGRXOXdUblpPZUVrMGEwOTJVekpzSzI1dllsTlRRVDA5SWl3aWFXRjBJam94TnpZek5UVTVPRGM0TENKbGVIQWlPakUzTmpNMU5UazVNemg5LmlzUncyTFZnVlQxYzBpMUZ0a2RCWTZYb2p3NjdLS2E3aEQtbHEtNnhqUFEsZXlKaGJHY2lPaUpJVXpJMU5pSjkuZXlKd2RYcDZiR1VpT2lKQlFVRkJRVUZDY0hwR2JGRlVjM1p4Wm5sRlMwRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZDUkV0WFowdDRjMDlaYUN0VU5tMXFSR001WTI0eGRXOXdUblpPZUVrMGEwOTJVekpzSzI1dllsTlRRVDA5SWl3aWFXRjBJam94TnpZek5UVTVPRGM0TENKbGVIQWlPakUzTmpNMU5UazVNemg5LkxCc0VBem1yZ2ktZTk2Zk1lVEctTU1wY0p2QVgyU0VXdTlDdUJ0eGRCZzgsZXlKaGJHY2lPaUpJVXpJMU5pSjkuZXlKd2RYcDZiR1VpT2lKQlFVRkJRVUZFTjNOa1MyaHBUMDQwZFdsRlMwRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZDUkV0WFowdDRjMDlaYUN0VU5tMXFSR001WTI0eGRXOXdUblpPZUVrMGEwOTJVekpzSzI1dllsTlRRVDA5SWl3aWFXRjBJam94TnpZek5UVTVPRGM0TENKbGVIQWlPakUzTmpNMU5UazVNemg5Lm5OUm00WEdtdGRGTDNmQ0RhMC1WbVcxSVgwSXFBQ3ctVzBSeE80Z3dvTFk=';

measurePerformance(bbb).then(result => {
    console.log('Result:', result.result);
    console.log('Performance:', result.performance);
}).catch(error => {
    console.error('执行错误:', error);
});

VM执行脚本以及结果验证

=== VM执行完成 ===
执行时间: 699.10 ms
最终内存使用: { rss: '32 MB', heapUsed: '4 MB', heapTotal: '6 MB', external: '1 MB' }
内存变化: { rss: '7 MB', heapUsed: '0 MB', heapTotal: '2 MB', external: '0 MB' }
CPU 使用时间: { user: '563.00 ms', system: '47.00 ms' }
Result: W3siand0IjoiZXlKaGJHY2lPaUpJVXpJMU5pSjkuZXlKd2RYcDZiR1VpT2lKQlFVRkJRVUZDYW5wSWRubzVlUzh6YUVORlMwRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZDUkV0WFowdDRjMDlaYUN0VU5tMXFSR001WTI0eGRXOXdUblpPZUVrMGEwOTJVekpzSzI1dllsTlRRVDA5SWl3aWFXRjBJam94TnpZek5UVTVPRGM0TENKbGVIQWlPakUzTmpNMU5UazVNemg5LmlzUncyTFZnVlQxYzBpMUZ0a2RCWTZYb2p3NjdLS2E3aEQtbHEtNnhqUFEiLCJzb2x1dGlvbiI6IlFnRUFBQUFBQUFBPSJ9LHsiand0IjoiZXlKaGJHY2lPaUpJVXpJMU5pSjkuZXlKd2RYcDZiR1VpT2lKQlFVRkJRVUZDY0hwR2JGRlVjM1p4Wm5sRlMwRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZDUkV0WFowdDRjMDlaYUN0VU5tMXFSR001WTI0eGRXOXdUblpPZUVrMGEwOTJVekpzSzI1dllsTlRRVDA5SWl3aWFXRjBJam94TnpZek5UVTVPRGM0TENKbGVIQWlPakUzTmpNMU5UazVNemg5LkxCc0VBem1yZ2ktZTk2Zk1lVEctTU1wY0p2QVgyU0VXdTlDdUJ0eGRCZzgiLCJzb2x1dGlvbiI6IjNnOEFBQUFBQUFBPSJ9LHsiand0IjoiZXlKaGJHY2lPaUpJVXpJMU5pSjkuZXlKd2RYcDZiR1VpT2lKQlFVRkJRVUZFTjNOa1MyaHBUMDQwZFdsRlMwRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZDUkV0WFowdDRjMDlaYUN0VU5tMXFSR001WTI0eGRXOXdUblpPZUVrMGEwOTJVekpzSzI1dllsTlRRVDA5SWl3aWFXRjBJam94TnpZek5UVTVPRGM0TENKbGVIQWlPakUzTmpNMU5UazVNemg5Lm5OUm00WEdtdGRGTDNmQ0RhMC1WbVcxSVgwSXFBQ3ctVzBSeE80Z3dvTFkiLCJzb2x1dGlvbiI6Ilcza0FBQUFBQUFBPSJ9XQ==
Performance: {
  executionTime: '699.10 ms',
  memoryUsage: {
    rss: '7 MB',
    heapUsed: '0 MB',
    heapTotal: '2 MB',
    external: '0 MB'
  },
  cpuUsage: { user: '563.00 ms', system: '47.00 ms' }
}
const vm = require('vm');
const crypto = require('crypto');

// 监控函数
async function measurePerformance(body, timeout = 30000) {
    const startTime = process.hrtime.bigint();
    const startMemory = process.memoryUsage();
    const startCpuUsage = process.cpuUsage();
    
    // 创建沙盒环境
    const sandbox = {
        crypto,
        console,
        Buffer,
        Promise,
        setTimeout,
        Date,
        BigInt,
        Int8Array,
        Uint8Array,
        atob: (str) => Buffer.from(str, 'base64').toString('binary'),
        btoa: (str) => Buffer.from(str, 'binary').toString('base64'),
        JSON,
        process: {
            hrtime: process.hrtime,
            memoryUsage: process.memoryUsage,
            cpuUsage: process.cpuUsage
        },
        __result: null
    };
    
    const context = vm.createContext(sandbox);

    const code = `
        //#region 改写 sha256 方法, 原方法使用的浏览器 sha256 方法在 node 不适用
        async function sha256(input) {
            const hash = crypto.createHash('sha256');
            const buffer = input instanceof Buffer ? input : Buffer.from(input);
            hash.update(buffer);
            return hash.digest();
        }

        //#endregion

        //#region 原始加密代码
        async function t(t) {
            const e = function (t, n) {
                const r = BigInt(8 * (t - 3))
                    , e = BigInt(2);
                let o = e;
                for (let t = 1; t < r; t++)
                    o *= e;
                return BigInt(n) * o
            }(t[13], t[14]);

            return o = await async function (t, e) {
                let o = 0;
                const startTime = Date.now();
                const MAX_ITERATIONS = 50000;
                const MAX_TIME = 8000;
                
                do {
                    const a = r(o);
                    if (await n(a, t) < e)
                        return a
                        
                    if (o % 1000 === 0) {
                        if (o > MAX_ITERATIONS) {
                            break;
                        }
                        if (Date.now() - startTime > MAX_TIME) {
                            break;
                        }
                        await new Promise(resolve => setTimeout(resolve, 0));
                    }
                } while (++o <= Number.MAX_VALUE);
                
                return new Int8Array(0)
            }(t, e),
                btoa(String.fromCharCode(...new Uint8Array(o)));
            var o
        }

        async function n(t, n) {
            const r = function (t, n) {
                const r = new Int8Array(40);
                for (let n = 0; n < 32; n++)
                    r[n] = t[n];
                for (let t = 32; t < 40; t++)
                    r[t] = n[t - 32];
                return r
            }(n, t)
                , e = await sha256(Buffer.from(r))
                , o = await sha256(Buffer.from(e));
            return function (t) {
                let n = BigInt(0);
                for (let r = t.length - 1; r >= 0; r--)
                    n = BigInt(n) * BigInt(256),
                        n += BigInt(t[r]);
                return n
            }
            (new Uint8Array(o))
        }

        function r(t) {
            const n = new Int8Array(8);
            for (let r = 0; r < n.length; r++) {
                const e = 255 & t;
                n[r] = e,
                    t = (t - e) / 256
            }
            return n
        }

        //#endregion

        //#region 封装输出
        async function execute(body) {
            const b = await Promise.all(atob(body).split(",").map(s => {
                const m = JSON.parse(atob(s.split(".")[1]));
                return {
                    jwt: s,
                    puzzle: Int8Array.from(atob(m.puzzle), F => F.charCodeAt(0))
                }
            }).map(async (s) => { return { jwt: s.jwt, solution: await t(s.puzzle) } }))
            return btoa(JSON.stringify(b))
        }

        //#endregion

        (async () => {
            return await execute('${body}');
        })();
    `;

    
    try {
        // 执行代码并等待完成
        const result = await vm.runInContext(code, context, { timeout });
        
        // 计算性能指标
        const endTime = process.hrtime.bigint();
        const endMemory = process.memoryUsage();
        const endCpuUsage = process.cpuUsage(startCpuUsage);
        
        const executionTime = Number(endTime - startTime) / 1000000; // 转换为毫秒
        const memoryDelta = {
            rss: endMemory.rss - startMemory.rss,
            heapUsed: endMemory.heapUsed - startMemory.heapUsed,
            heapTotal: endMemory.heapTotal - startMemory.heapTotal,
            external: endMemory.external - startMemory.external
        };
        
        console.log('=== VM执行完成 ===');
        console.log('执行时间:', executionTime.toFixed(2) + ' ms');
        console.log('最终内存使用:', {
            rss: Math.round(endMemory.rss / 1024 / 1024) + ' MB',
            heapUsed: Math.round(endMemory.heapUsed / 1024 / 1024) + ' MB',
            heapTotal: Math.round(endMemory.heapTotal / 1024 / 1024) + ' MB',
            external: Math.round(endMemory.external / 1024 / 1024) + ' MB'
        });
        console.log('内存变化:', {
            rss: Math.round(memoryDelta.rss / 1024 / 1024) + ' MB',
            heapUsed: Math.round(memoryDelta.heapUsed / 1024 / 1024) + ' MB',
            heapTotal: Math.round(memoryDelta.heapTotal / 1024 / 1024) + ' MB',
            external: Math.round(memoryDelta.external / 1024 / 1024) + ' MB'
        });
        console.log('CPU 使用时间:', {
            user: (endCpuUsage.user / 1000).toFixed(2) + ' ms',
            system: (endCpuUsage.system / 1000).toFixed(2) + ' ms'
        });
        
        return {
            result: result,
            performance: {
                executionTime: executionTime.toFixed(2) + ' ms',
                memoryUsage: {
                    rss: Math.round(memoryDelta.rss / 1024 / 1024) + ' MB',
                    heapUsed: Math.round(memoryDelta.heapUsed / 1024 / 1024) + ' MB',
                    heapTotal: Math.round(memoryDelta.heapTotal / 1024 / 1024) + ' MB',
                    external: Math.round(memoryDelta.external / 1024 / 1024) + ' MB'
                },
                cpuUsage: {
                    user: (endCpuUsage.user / 1000).toFixed(2) + ' ms',
                    system: (endCpuUsage.system / 1000).toFixed(2) + ' ms'
                }
            }
        };
        
    } catch (error) {
        console.error('VM执行错误:', error.message);
        return {
            error: error.message,
            performance: {
                executionTime: `${Number(process.hrtime.bigint() - startTime) / 1000000}ms`,
                memoryUsage: process.memoryUsage(),
                cpuUsage: process.cpuUsage(startCpuUsage)
            }
        };
    }
}

// 使用示例
const bbb = 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuZXlKd2RYcDZiR1VpT2lKQlFVRkJRVUZDYW5wSWRubzVlUzh6YUVORlMwRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZDUkV0WFowdDRjMDlaYUN0VU5tMXFSR001WTI0eGRXOXdUblpPZUVrMGEwOTJVekpzSzI1dllsTlRRVDA5SWl3aWFXRjBJam94TnpZek5UVTVPRGM0TENKbGVIQWlPakUzTmpNMU5UazVNemg5LmlzUncyTFZnVlQxYzBpMUZ0a2RCWTZYb2p3NjdLS2E3aEQtbHEtNnhqUFEsZXlKaGJHY2lPaUpJVXpJMU5pSjkuZXlKd2RYcDZiR1VpT2lKQlFVRkJRVUZDY0hwR2JGRlVjM1p4Wm5sRlMwRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZDUkV0WFowdDRjMDlaYUN0VU5tMXFSR001WTI0eGRXOXdUblpPZUVrMGEwOTJVekpzSzI1dllsTlRRVDA5SWl3aWFXRjBJam94TnpZek5UVTVPRGM0TENKbGVIQWlPakUzTmpNMU5UazVNemg5LkxCc0VBem1yZ2ktZTk2Zk1lVEctTU1wY0p2QVgyU0VXdTlDdUJ0eGRCZzgsZXlKaGJHY2lPaUpJVXpJMU5pSjkuZXlKd2RYcDZiR1VpT2lKQlFVRkJRVUZFTjNOa1MyaHBUMDQwZFdsRlMwRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZDUkV0WFowdDRjMDlaYUN0VU5tMXFSR001WTI0eGRXOXdUblpPZUVrMGEwOTJVekpzSzI1dllsTlRRVDA5SWl3aWFXRjBJam94TnpZek5UVTVPRGM0TENKbGVIQWlPakUzTmpNMU5UazVNemg5Lm5OUm00WEdtdGRGTDNmQ0RhMC1WbVcxSVgwSXFBQ3ctVzBSeE80Z3dvTFk=';

measurePerformance(bbb).then(result => {
    console.log('Result:', result.result);
    console.log('Performance:', result.performance);
});

VM2执行脚本以及结果验证

=== 开始执行 ===
初始内存使用: { rss: '31 MB', heapUsed: '5 MB', heapTotal: '6 MB' }
=== VM2执行完成 ===
执行时间: 5334.72 ms
最终内存使用: {
  rss: '116 MB',
  heapUsed: '48 MB',
  heapTotal: '75 MB',
  external: '3 MB'
}
内存变化: {
  rss: '86 MB',
  heapUsed: '42 MB',
  heapTotal: '69 MB',
  external: '1 MB'
}
CPU 使用时间: { user: '5281.00 ms', system: '219.00 ms' }
Result: W3siand0IjoiZXlKaGJHY2lPaUpJVXpJMU5pSjkuZXlKd2RYcDZiR1VpT2lKQlFVRkJRVUZDYW5wSWRubzVlUzh6YUVORlMwRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZDUkV0WFowdDRjMDlaYUN0VU5tMXFSR001WTI0eGRXOXdUblpPZUVrMGEwOTJVekpzSzI1dllsTlRRVDA5SWl3aWFXRjBJam94TnpZek5UVTVPRGM0TENKbGVIQWlPakUzTmpNMU5UazVNemg5LmlzUncyTFZnVlQxYzBpMUZ0a2RCWTZYb2p3NjdLS2E3aEQtbHEtNnhqUFEiLCJzb2x1dGlvbiI6IlFnRUFBQUFBQUFBPSJ9LHsiand0IjoiZXlKaGJHY2lPaUpJVXpJMU5pSjkuZXlKd2RYcDZiR1VpT2lKQlFVRkJRVUZDY0hwR2JGRlVjM1p4Wm5sRlMwRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZDUkV0WFowdDRjMDlaYUN0VU5tMXFSR001WTI0eGRXOXdUblpPZUVrMGEwOTJVekpzSzI1dllsTlRRVDA5SWl3aWFXRjBJam94TnpZek5UVTVPRGM0TENKbGVIQWlPakUzTmpNMU5UazVNemg5LkxCc0VBem1yZ2ktZTk2Zk1lVEctTU1wY0p2QVgyU0VXdTlDdUJ0eGRCZzgiLCJzb2x1dGlvbiI6IjNnOEFBQUFBQUFBPSJ9LHsiand0IjoiZXlKaGJHY2lPaUpJVXpJMU5pSjkuZXlKd2RYcDZiR1VpT2lKQlFVRkJRVUZFTjNOa1MyaHBUMDQwZFdsRlMwRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZDUkV0WFowdDRjMDlaYUN0VU5tMXFSR001WTI0eGRXOXdUblpPZUVrMGEwOTJVekpzSzI1dllsTlRRVDA5SWl3aWFXRjBJam94TnpZek5UVTVPRGM0TENKbGVIQWlPakUzTmpNMU5UazVNemg5Lm5OUm00WEdtdGRGTDNmQ0RhMC1WbVcxSVgwSXFBQ3ctVzBSeE80Z3dvTFkiLCJzb2x1dGlvbiI6Ilcza0FBQUFBQUFBPSJ9XQ==
Performance: {
  executionTime: '5334.72 ms',
  memoryUsage: {
    rss: '86 MB',
    heapUsed: '42 MB',
    heapTotal: '69 MB',
    external: '1 MB'
  },
  cpuUsage: { user: '5281.00 ms', system: '219.00 ms' }
}
      
const { VM } = require('vm2');
const crypto = require('crypto');

async function measurePerformance(body) {
    const startTime = process.hrtime.bigint();
    const initialMemory = process.memoryUsage();
    const initialCpuUsage = process.cpuUsage();
    
    console.log('=== 开始执行 ===');
    console.log('初始内存使用:', {
        rss: Math.round(initialMemory.rss / 1024 / 1024) + ' MB',
        heapUsed: Math.round(initialMemory.heapUsed / 1024 / 1024) + ' MB',
        heapTotal: Math.round(initialMemory.heapTotal / 1024 / 1024) + ' MB'
    });
    
    const vm = new VM({
        timeout: 20000,
        sandbox: {
            crypto: crypto,
            console: console,
            Buffer: Buffer,
            btoa: (str) => Buffer.from(str, 'binary').toString('base64'),
            atob: (str) => Buffer.from(str, 'base64').toString('binary'),
            setTimeout: setTimeout,
            Promise: Promise,
            Date: Date,
            JSON: JSON,
            Int8Array: Int8Array,
            Uint8Array: Uint8Array,
            BigInt: BigInt,
            Number: Number,
            String: String
        }
    });

    const code = `
        //#region 改写 sha256 方法, 原方法使用的浏览器 sha256 方法在 node 不适用
        async function sha256(input) {
            const hash = crypto.createHash('sha256');
            const buffer = input instanceof Buffer ? input : Buffer.from(input);
            hash.update(buffer);
            return hash.digest();
        }

        //#endregion

        //#region 原始加密代码
        async function t(t) {
            const e = function (t, n) {
                const r = BigInt(8 * (t - 3))
                    , e = BigInt(2);
                let o = e;
                for (let t = 1; t < r; t++)
                    o *= e;
                return BigInt(n) * o
            }(t[13], t[14]);

            return o = await async function (t, e) {
                let o = 0;
                const startTime = Date.now();
                const MAX_ITERATIONS = 50000;
                const MAX_TIME = 8000;
                
                do {
                    const a = r(o);
                    if (await n(a, t) < e)
                        return a
                        
                    if (o % 1000 === 0) {
                        if (o > MAX_ITERATIONS) {
                            break;
                        }
                        if (Date.now() - startTime > MAX_TIME) {
                            break;
                        }
                        await new Promise(resolve => setTimeout(resolve, 0));
                    }
                } while (++o <= Number.MAX_VALUE);
                
                return new Int8Array(0)
            }(t, e),
                btoa(String.fromCharCode(...new Uint8Array(o)));
            var o
        }

        async function n(t, n) {
            const r = function (t, n) {
                const r = new Int8Array(40);
                for (let n = 0; n < 32; n++)
                    r[n] = t[n];
                for (let t = 32; t < 40; t++)
                    r[t] = n[t - 32];
                return r
            }(n, t)
                , e = await sha256(Buffer.from(r))
                , o = await sha256(Buffer.from(e));
            return function (t) {
                let n = BigInt(0);
                for (let r = t.length - 1; r >= 0; r--)
                    n = BigInt(n) * BigInt(256),
                        n += BigInt(t[r]);
                return n
            }
            (new Uint8Array(o))
        }

        function r(t) {
            const n = new Int8Array(8);
            for (let r = 0; r < n.length; r++) {
                const e = 255 & t;
                n[r] = e,
                    t = (t - e) / 256
            }
            return n
        }

        //#endregion

        //#region 封装输出
        async function execute(body) {
            const b = await Promise.all(atob(body).split(",").map(s => {
                const m = JSON.parse(atob(s.split(".")[1]));
                return {
                    jwt: s,
                    puzzle: Int8Array.from(atob(m.puzzle), F => F.charCodeAt(0))
                }
            }).map(async (s) => { return { jwt: s.jwt, solution: await t(s.puzzle) } }))
            return btoa(JSON.stringify(b))
        }

        //#endregion

        (async () => {
            return await execute('${body}');
        })();
    `;

    try {
        const result = await vm.run(code);
        
        const endTime = process.hrtime.bigint();
        const finalMemory = process.memoryUsage();
        const finalCpuUsage = process.cpuUsage(initialCpuUsage);
        
        const executionTime = Number(endTime - startTime) / 1000000; // 转换为毫秒
        const memoryUsed = {
            rss: finalMemory.rss - initialMemory.rss,
            heapUsed: finalMemory.heapUsed - initialMemory.heapUsed,
            heapTotal: finalMemory.heapTotal - initialMemory.heapTotal,
            external: finalMemory.external - initialMemory.external
        };
        
        console.log('=== VM2执行完成 ===');
        console.log('执行时间:', executionTime.toFixed(2) + ' ms');
        console.log('最终内存使用:', {
            rss: Math.round(finalMemory.rss / 1024 / 1024) + ' MB',
            heapUsed: Math.round(finalMemory.heapUsed / 1024 / 1024) + ' MB',
            heapTotal: Math.round(finalMemory.heapTotal / 1024 / 1024) + ' MB',
            external: Math.round(finalMemory.external / 1024 / 1024) + ' MB'
        });
        console.log('内存变化:', {
            rss: Math.round(memoryUsed.rss / 1024 / 1024) + ' MB',
            heapUsed: Math.round(memoryUsed.heapUsed / 1024 / 1024) + ' MB',
            heapTotal: Math.round(memoryUsed.heapTotal / 1024 / 1024) + ' MB',
            external: Math.round(memoryUsed.external / 1024 / 1024) + ' MB'
        });
        console.log('CPU 使用时间:', {
            user: (finalCpuUsage.user / 1000).toFixed(2) + ' ms',
            system: (finalCpuUsage.system / 1000).toFixed(2) + ' ms'
        });

        return {
            result: result,
            performance: {
                executionTime: executionTime.toFixed(2) + ' ms',
                memoryUsage: {
                    rss: Math.round(memoryUsed.rss / 1024 / 1024) + ' MB',
                    heapUsed: Math.round(memoryUsed.heapUsed / 1024 / 1024) + ' MB',
                    heapTotal: Math.round(memoryUsed.heapTotal / 1024 / 1024) + ' MB',
                    external: Math.round(memoryUsed.external / 1024 / 1024) + ' MB'
                },
                cpuUsage: {
                    user: (finalCpuUsage.user / 1000).toFixed(2) + ' ms',
                    system: (finalCpuUsage.system / 1000).toFixed(2) + ' ms'
                }
            }
        };
    } catch (error) {
        const errorTime = Number(process.hrtime.bigint() - startTime) / 1000000;
        console.log('=== VM2执行错误 ===');
        console.log('执行时间:', errorTime.toFixed(2) + ' ms');
        console.log('错误:', error.message);
        
        return {
            error: error.message,
            performance: {
                executionTime: errorTime.toFixed(2) + ' ms',
                memoryUsage: process.memoryUsage(),
                cpuUsage: process.cpuUsage(initialCpuUsage)
            }
        };
    }
}

// 使用示例
const bbb = 'ZXlKaGJHY2lPaUpJVXpJMU5pSjkuZXlKd2RYcDZiR1VpT2lKQlFVRkJRVUZDYW5wSWRubzVlUzh6YUVORlMwRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZDUkV0WFowdDRjMDlaYUN0VU5tMXFSR001WTI0eGRXOXdUblpPZUVrMGEwOTJVekpzSzI1dllsTlRRVDA5SWl3aWFXRjBJam94TnpZek5UVTVPRGM0TENKbGVIQWlPakUzTmpNMU5UazVNemg5LmlzUncyTFZnVlQxYzBpMUZ0a2RCWTZYb2p3NjdLS2E3aEQtbHEtNnhqUFEsZXlKaGJHY2lPaUpJVXpJMU5pSjkuZXlKd2RYcDZiR1VpT2lKQlFVRkJRVUZDY0hwR2JGRlVjM1p4Wm5sRlMwRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZDUkV0WFowdDRjMDlaYUN0VU5tMXFSR001WTI0eGRXOXdUblpPZUVrMGEwOTJVekpzSzI1dllsTlRRVDA5SWl3aWFXRjBJam94TnpZek5UVTVPRGM0TENKbGVIQWlPakUzTmpNMU5UazVNemg5LkxCc0VBem1yZ2ktZTk2Zk1lVEctTU1wY0p2QVgyU0VXdTlDdUJ0eGRCZzgsZXlKaGJHY2lPaUpJVXpJMU5pSjkuZXlKd2RYcDZiR1VpT2lKQlFVRkJRVUZFTjNOa1MyaHBUMDQwZFdsRlMwRkJRVUZCUVVGQlFVRkJRVUZCUVVGQlFVRkJRVUZDUkV0WFowdDRjMDlaYUN0VU5tMXFSR001WTI0eGRXOXdUblpPZUVrMGEwOTJVekpzSzI1dllsTlRRVDA5SWl3aWFXRjBJam94TnpZek5UVTVPRGM0TENKbGVIQWlPakUzTmpNMU5UazVNemg5Lm5OUm00WEdtdGRGTDNmQ0RhMC1WbVcxSVgwSXFBQ3ctVzBSeE80Z3dvTFk=';

measurePerformance(bbb).then(result => {
    console.log('Result:', result.result);
    console.log('Performance:', result.performance);
});

    

总结

所以在做一个通用的补环境框架的时候,尽量不用使用VM2。

执行时间
    Node:  456.38 ms
    VM:    699.10 ms   (+53%)
    VM2:   5334.72 ms  (+1069%)

内存
    环境   RSS增长     Heap增长
    Node   +8 MB      +1 MB
    VM     +7 MB      +0 MB  
    VM2    +86 MB     +42 MB

CPU
    环境   用户CPU     系统CPU
    Node   438 ms     110 ms
    VM     563 ms     47 ms
    VM2    5281 ms    219 ms