当前位置: 首页 > 后端技术 > Node.js

对于使用非阻塞运行和阻塞运行的并发压测对比

时间:2023-04-03 14:23:04 Node.js

本文使用源码地址:address为什么会有这个实验?因为一个关于cnode的问题,node.js单线程,难道不用消息队列吗?我当时的回答是举个例子,需要检查数据表中是否有同名的名字,没有同名的就插入。因为node不能以整个请求的sql块为执行单位,而是以sql条为执行单位,那么按照上面的说法,两个select会陆续到达,但是第一个insert没有插入,导致第二个select查询为空,会继续插入用户。(表小的可能不会出现,表大的时候会出现。)消息队列相当于以整个请求的SQL块为执行单元,即对表的select和insert整个请求完成,将执行下一个请求的select和insert。插入。这个答案是基于我以前在node中遇到的坑。看起来很有道理,毕竟我们通常把node作为异步执行的最小单位来执行。但是事后一想,为什么节点块不能作为顺序执行单元呢?没错,确实有可能。于是当晚做了一个简单的block运行时库,简单测试了一下,好像实现了。但是,由于业务繁忙(产品需求激增),没有时间对数据库进行优化和定位。实际测试!这个周末要去测试一下。我已经为数据库实现了三套并发测试。乐观锁抵抗并发事务加乐观锁抵抗并发块执行加上乐观锁抵抗并发主要代码如下乐观锁抵抗并发异步函数sqlCommon(sqlCommonName='sqlCommon'){letconn;试试{conn=awaitgetConn();lettestSelete=awaitqueryPromise(conn,'SELECT*FROM`test`WHERE`name`=?AND`version`=?',[getName(sqlCount),sqlCount]);if(testSelete.length>0){lettestRes=awaitqueryPromise(conn,'UPDATE`test`SET`name`=?,`version`=?+1WHERE`version`=?',[getName(sqlCount+1),sqlCount,sqlCount]);如果(testRes.affectedRows>0){sqlCount++;}else{console.log(`${sqlCommonName}failed:${sqlCount}`)}}else{console.log(`${sqlCommonName}failed:${sqlCount}`)}conn.release();}catch(e){console.log(`${sqlCommonName}失败:${sqlCount}`)conn.release();//console.log(e.stack)}}事务加乐视图锁抗并发asyncfunctionsqlTrans(){letconn;试试{conn=awaitgetConn();awaitqueryPromise(conn,'SETTRANSACTIONISOLATIONLEVELSERIALIZABLE;')beginTransaction(conn);lettestSelete=awaitqueryPromise(conn,'SELECT*FROM`test`WHERE`name`=?AND`version`=?',[getName(sqlCount),sqlCount]);if(testSelete.length>0){lettestRes=awaitqueryPromise(conn,'UPDATE`test`SET`name`=?,`version`=?+1WHERE`version`=?',[getName(sqlCount+1),sqlCount,sqlCount]);如果(testRes.affectedRows>0){sqlCount++;}else{console.log(`sqlTransfailed:${sqlCount}`)rollback(conn);}}else{console.log(`sqlTrans失败:${sqlCount}`)}提交(连接);conn.release();}catch(e){console.log(`sqlTransfailed:${sqlCount}`)//console.log(e.stack);//这里会弹出很多事务锁错误rollback(conn);conn.release();}}块执行加乐观锁反并发(只需要在块执行的一个通道上放乐观锁,改造很简单)需要乐观锁乐观锁函数需要的包地址仓库地址sqlBlock(){returnnewPromise((reslove,rejected)=>{BlockRun.run('sqlBlockChannel1',async()=>{awaitsqlCommon('sqlBlock');reslove(true)},3000);});}主服务入口http.createServer(async(request,response)=>{try{letpathname=url.parse(request.url).pathname;//console.log(`url:http://127.0.0.1:${port}{$pathname}`)letshowText='test';switch(pathname){case'/clear':awaitsqlClear();showText='clear';break;case'/common':awaitsqlCommon();showText='common';break;case'/trans':awaitsql传输();showText='反式';休息;case'/block':awaitsqlBlock();showText='块';休息;}response.writeHead(200,{'Content-Type':'text/html'});响应.write(showText);响应结束();}catch(e){console.log(e.stack)}}).listen(port);其他代码请参考其他代码文件地址。运行结果乐观锁反并发abfailedrestransactionplusoptimisticlockanti-concurrency(几乎和optimism一样,有时候交易结果比一两个还好)abfailedresblockexecutionplusoptimisticlockanti-concurrencyabfailed(看到有一开始没有数据失败,感觉挺神奇的)res(看来神奇是不可避免的,呵呵)这里有人会说,你的ab压力太小了,当然没什么,其实我想说的是,主要是数据和乐观锁结果太丑了,想照顾大家的心思让大家好好看看block执行的牛逼。块执行加乐观锁反并发(并发升级版)ab直接去-n10000-c100failed(怎么还没修改失败?神奇?)res(看来神奇又是必然了,呵呵)在完了,谁还不服气!简直就是并发的小魔法!如果是个人建站抗并发,就够了!不需要事务,还是反并发的,性能很棒!对结果有疑问的同学可以自行测试,注意两点:测试前先curlhttp://127.0.0.1:8088/clear确保数据库没有被之前测试污染。SQL和所有代码都在这里。测试前,npminstallthis本次测试使用的block执行库为block-run1.0.8版本:乐观锁所需的包地址乐观锁所需的仓库地址