Swoft-基於swoole2.0的高性能微服務框架
簡介
swoft是基於swoole協程2.x的高性能PHP微服務框架,內置http伺服器。框架全協程實現,性能優於傳統的php-fpm模式。
基於swoole易擴展
內置http協程伺服器
MVC分層設計
高性能路由
全局容器注入
高性能RPC
別名機制
事件機制
國際化(i18n)
服務治理熔斷、降級、負載、註冊與發現
連接池Mysql、Redis、RPC
資料庫ORM
inotify自動reload
強大的日誌系統
Future
連接池等待隊列
restful風格
crontab定時任務
服務監控
日誌統計分析
統一配置中心
更新記錄
......
2017-08-15 重構console命令行
2017-08-24 重寫IOC容器,新增控制器路由註解註冊,不再依賴php-di。使用時,重新composer安裝
2017-08-28 inotify自動reload
2017-09-02 別名機制、事件機制、國際化(i18n),命名空間統一大寫。
2017-09-19 資料庫ORM
系統架構
快速入門
文檔
中文文檔
環境要求
hiredis
composer
PHP7.X
inotify(可選)
Swoole2.x且開啟協程和非同步redis
安裝
手動安裝
clone項目
composer install安裝依賴
composer安裝
composer.phar create-project stelin/swoft swoft(未開代理,會有點慢)
配置
配置base.php
設置啟動參數swoft.ini
啟動
啟動服務支持HTTP和TCP同時啟動,swoft.ini中配置。
常用命令
//啟動服務,是否是守護進程,根據swoft.ini配置
phpswoft.phpstart
//守護進程啟動,覆蓋swoft.ini守護進程配置
phpswoft.phpstart-d
//重啟
phpswoft.phprestart
//重新載入
phpswoft.phpreload
//關閉服務
phpswoft.phpstop
Swoft.ini參數
[swoft]
;;;;;;;;;;;;;;;;;;;;About swoft.ini;;;;;;;;;;;;;;;;;;;;
[server]pfile = /tmp/swoft.pid ;
pname ="php-swf";
[tcp]
enable= 1;
host ="0.0.0.0"
port = 8099
type= SWOOLE_SOCK_TCP[http]host ="0.0.0.0"port = 80model = SWOOLE_PROCESStype= SWOOLE_SOCK_TCP[setting]worker_num = 4max_request = 10000daemonize = 0;dispatch_mode = 2log_file = SWOOLE_LOG_PATH
路由器
路由解析有兩種方式,註冊路由和自動解析,所有路由都在routes.php中配置。建議所有路由都提前註冊,或者通過註解註冊,不建議使用自動路由解析。路由配置參數(base.php):
return[//...
router =>[
class =>swoftwebRouter::class,
ignoreLastSep =>false,
//是否忽略最後一個斜杠,設置false後,/user/index和/user/index/是兩個不同的路由
tmpCacheNumber =>1000,//緩存路由數,最近一1000條
matchAll => ,//匹配所有,所有請求都會匹配到這個uri或閉包],
//...
];
路由註冊實例
//匹配 GET 請求. 處理器是個閉包 Closure
$router->get( / ,function() {
$resposne=App::getResponse();
$resposne->setResponseContent("hello");
$resposne->send();});//匹配參數 test/john
$router->get( /test/ ,function($arg) {
echo$arg;// john },
[ tokens =>[
name => w+ ,//添加參數匹配限制。若不添加對應的限制,將會自動設置為匹配除了 / 外的任何字元
]]);//可選參數支持。匹配 hello hello/john
$router->get( /hello[/] ,function($name= No ) {
echo$name;// john }, [
tokens =>[
name => w+ ,//添加參數匹配限制
]]);//匹配 POST 請求
$router->post( /user/login ,function() {
$request=App::getRequest();
var_dump($request->getGetParameters(),$request->getPostParameters());});
//匹配 GET 或者 POST
$router->map([ get , post ], /user/login ,function() {
$request=App::getRequest();
var_dump($request->getGetParameters(),$request->getPostParameters());});
//允許任何請求方法
$router->any( /home ,function() {
$resposne=RequestContext::getResponse();
$resposne->setResponseContent("hello, you request page is /home");
$resposne->send();});
$router->any( /404 ,function() {
$resposne=App::getResponse();
$resposne->setResponseContent("Sorry,This page not found.");
$resposne->send();});//路由組
$router->group( /user ,function($router) {
$router->get( / ,function() {
$resposne=App::getResponse();
$resposne->setResponseContent("hello. you access: /user/");
$resposne->send();});
$router->get( /index ,function() {
$resposne=App::getResponse();
$resposne->setResponseContent("hello. you access: /user/index");
$resposne->send();});});
//通過@符號連接控制器類和方法名可以指定執行方法
$router->get( / ,appcontrollersHome::class);
$router->get( /index , appcontrollersHome@index );
$router->get( /about , appcontrollersHome@about );
//訪問 /home/test 將會執行 appcontrollersHome::test()
$router->any( /home/ ,appcontrollersHome::class);
//可匹配 /home , /home/test 等
$router->any( /home[/] ,appcontrollersHome::class);
//配置 matchAll 可用於攔截所有請求,目前有如下兩種方式。//路由path
matchAll => /about ,//回調 matchAll =>function() {
$resposne=App::getResponse();
$resposne->setResponseContent("System Maintaining ... ...");
$resposne->send();},
控制器
一個繼承swoftwebController的類既是控制器,控制器有兩種註解自動註冊和手動註冊兩種方式。建議使用註解自動註冊,方便簡潔,維護簡單。多次註冊相同的路由前者會被後者覆蓋。
註解自動註冊
註解自動註冊常用到三個註解@AutoController、@Inject、@RequestMapping.
@AutoController
已經使用@AutoController,不能再使用@Bean註解。
@AutoController註解不需要指定bean名稱,統一類為bean名稱
@AutoController()默認自動解析controller前綴,並且使用駝峰格式。
@AutoController(prefix="/demo2")或@AutoController("/demo2")功能一樣,兩種使用方式。
@Inject
使用和之前的一樣
@RequestMapping
@RequestMapping(route="/index2")或@RequestMapping("/index2")功能一樣兩種方式使用,這種默認是支持get和post方式@RequestMapping(route="/index2", method=RequestMethod::GET)註冊支持的方法
不使用@RequestMapping或RequestMapping()功能一樣,都是默認解析action方法,以駝峰格式,註冊路由。
/*** 控制器demo** @AutoController(prefix="/demo2")**@usesDemoController*@version2017年08月22日*@authorstelin
*@copyrightCopyright 2010-2016 swoft software*@licensePHP Version 7.x {@linkhttp://www.php.net/license/3_0.txt}*/classDemoControllerextendsController{/*** 注入邏輯層** @Inject()*@varIndexLogic*/private$logic;/*** 定義一個route,支持get和post方式,處理uri=/demo2/index** @RequestMapping(route="index", method=)*/publicfunctionactionIndex(){//獲取所有GET參數$get=$this->get();//獲取name參數默認值defaultName$name=$this->get( name , defaultName );//獲取所有POST參數$post=$this->post();//獲取name參數默認值defaultName$name=$this->post( name , defaultName );//獲取所有參,包括GET或POST$request=$this->request();//獲取name參數默認值defaultName$name=$this->request( name , defaultName );//json方式顯示數據$this->outputJson("suc");}/*** 定義一個route,支持get,以"/"開頭的定義,直接是根路徑,處理uri=/index2** @RequestMapping(route="/index2", method=RequestMethod::GET)*/publicfunctionactionIndex2(){//重定向一個URI$this->redirect("/login/index");}/*** 沒有使用註解,自動解析注入,默認支持get和post,處理uri=/demo2/index3*/publicfunctionactionIndex3(){$this->outputJson("suc3");}}
手動註冊
手動註冊常用@Bean、@Inject註解,手動註冊還要多一步就是在routes.php裡面註冊自己的路由規則。
手動註冊@Bean()只能這樣預設方式。並且不能使用@AutoController註解
/*** 控制器demo** @Bean()**@usesDemoController*@version2017年08月22日*@authorstelin
*@copyrightCopyright 2010-2016 swoft software*@licensePHP Version 7.x {@linkhttp://www.php.net/license/3_0.txt}*/classDemoControllerextendsController{/*** 注入邏輯層** @Inject()*@varIndexLogic*/private$logic;/*** uri=/demo2/index*/publicfunctionactionIndex(){//獲取所有GET參數$get=$this->get();//獲取name參數默認值defaultName$name=$this->get( name , defaultName );//獲取所有POST參數$post=$this->post();//獲取name參數默認值defaultName$name=$this->post( name , defaultName );//獲取所有參,包括GET或POST$request=$this->request();//獲取name參數默認值defaultName$name=$this->request( name , defaultName );//json方式顯示數據$this->outputJson("suc");}/*** uri=/index2*/publicfunctionactionIndex2(){//重定向一個URI//$this->redirect("/login/index");$this->outputJson("suc2");}/***/publicfunctionactionIndex3(){$this->outputJson("suc3");}}
routes.php手動註冊路由:
//...$router->map([ get , post ], /demo2/index , appcontrollersDemoController@index );$router->get( /index2 , appcontrollersDemoController@index2 );$router->get( /demo2/index3 , appcontrollersDemoController@index3 );
連接池
連接池使用簡單,只需在base.php裡面配置對應服務連接池即可。
return[//...//RCP打包、解包"packer"=>[ class =>JsonPacker::class],//服務發現bean, 目前系統支持consul,只行實現"consulProvider =>[ class =>swoftserviceConsulProvider::class],//user服務連接池"userPool"=>["class"=>swoftpoolServicePool::class,"uri"=> 127.0.0.1:8099,127.0.0.1:8099 ,//useProvider為false時,從這裡識別配置"maxIdel"=>6,//最大空閑連接數"maxActive"=>10,//最大活躍連接數"maxWait"=>20,//最大的等待連接數"timeout"=> $ ,//引用properties.php配置值"balancer"=> $ ,//連接創建負載"serviceName"=> user ,//服務名稱,對應連接池的名稱格式必須為xxxPool/xxxBreaker"useProvider"=>false, serviceprovider => $ //useProvider為true使用,用於發現服務],//user服務熔斷器"userBreaker"=>[ class =>swoftcircuitCircuitBreaker::class, delaySwithTimer =>8000],//...];
緩存
緩存目前只支持redis,redis使用有兩種方式直接調用和延遲收包調用。
//直接調用RedisClient::set( name , redis client stelin ,180);$name=RedisClient::get( name );RedisClient::get($name);//延遲收包調用$ret=RedisClient::deferCall( get , [ name ]);$ret2=RedisClient::deferCall( get , [ name ]);$result=$ret->getResult();$result2=$ret2->getResult();$data=[ redis =>$name, defer =>$result, defer2 =>$result2,];
RPC調用
RPC及內部服務通過監聽TCP埠實現,通過swoft.ini日誌配置TCP監聽埠信息。RPC調用內部實現連接池、熔斷器、服務註冊與發現等。
//直接調用$result=Service::call("user", User::getUserInfo , [2,6,8]);//並發調用$res=Service::deferCall("user", User::getUserInfo , [3,6,9]);$res2=Service::deferCall("user", User::getUserInfo , [3,6,9]);$users=$res->getResult();$users2=$res2->getResult();$deferRet=$users;$deferRet2=$users2;
HttpClient
系統提供HttpClient來實現HTTP調用,目前有兩種方式,直接調用和延遲收包調用,延遲收包,一般用於並發調用。
//直接調用$requestData=[ name => boy , desc => php ];$result=HttpClient::call("http://127.0.0.1/index/post?a=b",HttpClient::GET,$requestData);$result=$result;//延遲調用方式實現兩個請求並發調用$ret=HttpClient::deferCall("http://127.0.0.1/index/post",HttpClient::POST,$requestData);$ret2=HttpClient::deferCall("http://127.0.0.1/index/post",HttpClient::POST,$requestData);$defRet1=$ret->getResult();$defRet2=$ret->getResult();
日誌
日誌記錄一般用戶問題的問的分析,系統的定位。目前日誌規劃有debug trace error info warning notice等級別。每種不同的級別用戶記錄不同重要程度的信息。系統會為每一個請求生成一條notice,並且一個請求產生的所有日誌都有一個相同的logid,notice裡面記錄該請求的詳細信息,比如uri 總共耗時 緩存或db操作時間等等信息。
//標記開始App::profileStart("tag");//直接輸出異常App::error(newException("error exception"));App::error("this errro log");App::info("this errro log");//數組App::error([ name => boy ]);App::debug("this errro log");//標記結束App::profileEnd("tag");//統計緩存命中率App::counting("cache",1,10);
※一個MySQL 5.7分區表性能下降的案例分析
※代碼質量管控的四個階段
※利用sed批量更改文件名
※PHP與大數據開發實踐
TAG:PHP技術大全 |