当前位置: 首页 > 后端技术 > PHP

一个极简的基于swoole的常驻内存框架

时间:2023-03-29 22:09:00 PHP

背景我用过laravel框架,发现它的路由和数据库ORM确实好用,但是整体确实有点慢,大概需要60ms左右才能执行到控制器更大。所以打算做一个非常简单的框架,路由和orm都非常好用。所以你会发现onebox的路由和ORM有laravel的影子。但它也有自己的特点,比如ORM支持自动缓存(自动读、写、刷新)与数据库保持同步,外部使用无感知。one框架也支持在fpm下运行。fpm下,框架本身整体耗时1ms左右。helloworldinstallcomposercreate-projectlizhichao/one-appappcdappphpApp/swoole.phptestcurlhttp://127.0.0.1:8081/主要功能RESTful路由中间件websocket/tcp/http...任意协议路由ORM模型统一session处理mysql连接池redis连接池tcp连接池HTTP/TCP/WEBOSCKET/UDPservercache进程间内存共享RPC(http,tcp,udp)logRequestIdtraceroutingRouter::get('/',\App\Controllers\IndexController::class.'@index');//带参数的路由Router::get('/user/{id}',\App\Controllers\IndexController::class.'@user');//路由分组Router::group(['namespace'=>'App\\Test\\WebSocket'],function(){//websocket路由Router::set('ws','/a','TestController@abc');Router::set('ws','/b','TestController@bbb');});//中间件Router::group(['middle'=>[\App\Test\MixPro\TestMiddle::class.'@checkSession']],function(){Router::get('/mix/ws',HttpController::class.'@ws');Router::get('/mix/http',HttpControl勒::类。'@http');Router::post('/mix/http/loop',HttpController::class.'@httpLoop');Router::post('/mix/http/send',HttpController::类。'@httpSend');});ormmodeldefinitionmodelnamespaceApp\Model;useOne\Database\Mysql\Model;//模型中不需要指定主键,框架会缓存数据库结构//自动匹配主键,自动过滤非表结构中的字段classUserextendsModel{//定义模型对应的表名CONSTTABLE='users';//定义关系publicfunctionarticles(){return$this->hasMany('id',Article::class,'user_id');}//定义事件//是否开启自动缓存//...}使用模型,fpm下数据库连接为单列,swoole模式下数据库连接自动切换为连接池//查询一个record$user=User::find(1);//关联查询$user_list=User::whereIn('id',[1,2,3])->with('articles')->findAll()->toArray();//更新$r=$user->update(['name'=>'aaa']);//或$r=user::where('id',1)->update(['name'=>'aaa']);//$r缓存受影响的记录数//setcacheCache::set('ccc',1);//getCache::get('ccc');//或tag1下缓存ccc过期10sCache::get('ccc',function(){return'cachedinformation';},10,['tag1']);//刷新tag1下所有缓存Cache::冲洗('tag1');HTTP/TCP/WEBOSCKET/UDP服务器启动一个websocket服务器,添加http服务监控,添加tcp服务监控[//mainserver'server'=>['server_type'=>\One\Swoole\OneServer::SWOOLE_WEBSOCKET_SERVER,'port'=>8082,//事件回调'action'=>\One\Swoole\Server\WsServer::class,'mode'=>SWOOLE_PROCESS,'sock_type'=>SWOOLE_SOCK_TCP,'ip'=>'0.0.0.0',//swooleserver设置参数'set'=>['worker_num'=>5]],//添加监听'add_listener'=>[['port'=>8081,//事件回调'action'=>\App\Server\AppHttpPort::class,'type'=>SWOOLE_SOCK_TCP,'ip'=>'0.0.0.0',//设置监控参数'set'=>['open_http_protocol'=>true,'open_websocket_protocol'=>false]],['port'=>8083,//打包和解包协议'pack_protocol'=>\One\Protocol\Text::class,//事件回调'action'=>\App\Test\MixPro\TcpPort::class,'type'=>SWOOLE_SOCK_TCP,'ip'=>'0.0.0.0',//设置监控参数'set'=>['open_http_protocol'=>false,'open_websocket_protocol'=>false]]]];RPClikecall本项目的方法与跨语言、跨机器调用远程服务器的方法相同。服务端启动rpc服务,框架内置了各种协议的rpc服务,在上面的配置文件中的action中添加即可。比如:支持http调用,也支持tpc调用。//http协议rpc服务['port'=>8082,'action'=>\App\Server\RpcHttpPort::class,'type'=>SWOOLE_SOCK_TCP,'ip'=>'0.0.0.0','set'=>['open_http_protocol'=>true,'open_websocket_protocol'=>false]],//tpc协议rpc服务['port'=>8083,'action'=>\App\Server\RpcTcpPort::class,'type'=>SWOOLE_SOCK_TCP,'pack_protocol'=>\One\Protocol\Frame::class,//tcp打包和解包协议'ip'=>'0.0.0.0','set'=>['open_http_protocol'=>false,'open_websocket_protocol'=>false,'open_length_check'=>1,'package_length_func'=>'\One\Protocol\Frame::length','package_body_offset'=>\One\Protocol\Frame::HEAD_LEN,]]添加具体服务到rpc,比如有一个classAbcclassAbc{private$a;//初始值publicfunction__construct($a=0){$this->a=$a;}//添加publicfunctionadd($a,$b){return$this->a+$a+$b;}publicfunctiontime(){returndate('Y-m-dH:i:s');}//重置初始值publicfunctionsetA($a){$this->a=$a;返回$这个;}}AddAbctorpcservice//AddAbctorpcserviceRpcServer::add(Abc::class);//如果不想把Abc下的所有方法都添加到rpc服务中,也可以指定为add//未指定的方法不能被客户端调用。//RpcServer::add(Abc::class,'add');//分组添加//RpcServer::group([////这里的中间件可以做授权验证数据加解密等//'middle'=>[//TestMiddle::class.'@aa'//],////如果设置了缓存,同参数调用时会返回缓存信息,实际调用的unit不会be:seconds//'cache'=>10//],function(){//RpcServer::add(Abc::class);//RpcServer::add(User::class);//});客户端调用为了方便调用,我们创建一个映射类(一帧可以自动生成)classClientAbcextendsRpcClientHttp{//rpcserveraddressprotected$_rpc_server='http://127.0.0.1:8082/';//远程类默认不设置为当前类名protected$_remote_class_name='Abc';}调用rpc服务的远程方法,和调用本项目的方法相同。你可以在你的项目中想象这个方法。$abc=newClientAbc(5);//$res===10$res=$abc->add(2,3);//链调用$res===105$res=$abc->setA(100)->add(2,3);//如果将上面模型的用户添加到rpc//RpcServer::add(User::class);//下面操作的结果同上//$user_list=User::whereIn('id',[1,2,3])->with('articles')->findAll()->toArray();以上是通过http协议调用的。您也可以通过其他协议调用。例如Tpc协议类ClientAbcextendsRpcClientTcp{//rpcserveraddressprotected$_rpc_server='tcp://127.0.0.1:8083/';//远程类默认不设置为当前类名protected$_remote_class_name='Abc';其中,类RpcClientHttp和RpcClientTcp在框架中。您也可以在其他任何地方复制和使用。githubQQ交流群:731475644