本篇文章给大家分享一个Swoole高并发聚合请求实例,介绍在高并发场景下如何通过聚合请求,充分利用数据库的批量处理更高效地实现业务功能。此示例仅用作抛砖引玉,希望能激发大家更深入的思考。
本示例选取的背景是并发下单业务。常规情况下,后端创建订单是逐条insert的操作。在并发较低的时候,数据库的insert操作的确能保持不错的效率,但是当遇到请求数量增多,数据库频繁地单次insert就会让下单业务整体效率变低(本文简单地假设1次下单=1个insert)。
通过上面的描述,其实已经很容易想到需要优化的地方了。类比现实生活中乘坐电梯的场景:一架电梯装满后再上行,可以最快地缓解人流压力。
下面我们就来用代码简单实现一下我们思路:
<?phpSwoole\Runtime::enableCoroutine($flags=SWOOLE_HOOK_ALL);//最大等待次数constMAX_TIMES=10;//按批处理时,每一批的最大请求暂留数量constMAX_REQUEST=3;//服务端最大超时时间,避免客户端一直等待constMAX_TIMEOUT=5;Co\run(function(){//请求传输的channel,原因是不要在swoole的协程环境中,使用多个协程修改同一个全局变量//如果是golang,当然是可以不定义这里的$rqChannel//只需要简单的将下面的$rqQueue和$times定义为全局变量即可达到一样的效果//但是最好的方式任然是是通过channel共享内存$rqChannel=newSwoole\Coroutine\Channel(MAX_REQUEST);//模拟创建订单$createOrder=function()use($rqChannel){//使用数组模拟请求暂留队列$rqQueue=[];//使用等待次数模拟tick效果$times=MAX_TIMES;while(true){$times–;//必须带上timeout参数,否则channel是阻塞的$rq=$rqChannel->pop(1);//保存1个正常的请求数据if(!empty($rq)){$rqQueue[]=$rq;}//请求数量未达上限或者还有等待次数时,提前进入下一次循环if($times>0&&count($rqQueue)<MAX_REQUEST){continue;}//重置等待次数$times=MAX_TIMES;//初始化SQL$sql="INSERTINTOordersVALUES";$inserts=[];//模拟数据验证$validator=function($input):bool{//为了缩减代码,没有真的做数据验证的处理array_filter($input);returntrue;};//$rqQueue在协程上下文是并发安全的,所以遍历时不用担心foreach($rqQueueas$index=>$rq){list($data,$chan)=$rq;//这里可以考虑后置执行,原因是后面可以有一些补救逻辑unset($rqQueue[$index]);//判断$chan是否关闭åif($chan->errCode===SWOOLE_CHANNEL_CLOSED){$data=null;continue;}$bool=$validator($data);if($bool){$inserts[]="({$data['user_name']},{$data['amount']},{$data['mobile']})";$chan->push(['state'=>1]);}else{$chan->push(['state'=>0]);}//unset($rqQueue[$index]);}$sql.=(implode(',',$inserts).';');//模拟创建订单落库的逻辑echo$sql;}};//新手要注意这一句代码的位置,原因是$server->start()之后的代码不会执行go($createOrder);//路由处理器$orderHandler=function($rq,$res)use($rqChannel){$chan=newSwoole\Coroutine\Channel(1);//使用timeout参数模拟超时$bool=$rqChannel->push([$rq->post,$chan],MAX_TIMEOUT);if(!$bool){//关闭$chan$chan->close();$res->end('timeout');}if(!empty($data=$chan->pop())){//关闭$chan$chan->close();//区分成功或失败状态再输出响应if($data['state']===1){$res->end(microtime());}else{$res->end('error');}}};$server=newCo\Http\Server("0.0.0.0",9502,false);$server->handle('/order/create',$orderHandler);//当前协程容器的终点$server->start();});
代码整体上还是很容易理解的,变量$rqQueue就是类比电梯,暂留请求等待一定时间的次数$times就是类比电梯需要等待人流依次进入。当然最在希望读者注意的一点是:在协程环境下,不要使用共享内存而通信,应该使用通信来共享内存。
产品猿社区致力收录更多优质的商业产品,给服务商以及软件采购客户提供更多优质的软件产品,帮助开发者变现来实现多方共赢;
日常运营的过程中我们难免会遇到各种版权纠纷等问题,如果您在社区内发现有您的产品未经您授权而被用户提供下载或使用,您可按照我们投诉流程处理,点我投诉;
本文来自用户发布投稿,不代表产品猿立场 ;若对此文有疑问或内容有严重错误,可联系平台客服反馈;
部分产品是用户投稿,可能本文没有提供官方下下载地址或教程,若您看到的内容没有下载入口,您可以在我们产品园商城搜索看开发者是否有发布商品;若您是开发者,也诚邀您入驻商城平台发布的产品,地址:点我进入;
如若转载,请注明出处:https://www.chanpinyuan.cn/28549.html;