博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
swoft-基于swoole协程2.x的高性能PHP微服务框架
阅读量:5862 次
发布时间:2019-06-19

本文共 10282 字,大约阅读时间需要 34 分钟。

hot3.png

   

https://github.com/swoft-cloud/swoft

swoft是基于swoole协程2.x的高性能PHP微服务框架,内置http服务器。框架全协程实现,性能优于传统的php-fpm模式。

  • 基于swoole易扩展
  • 内置http协程服务器
  • MVC分层设计
  • 高性能路由
  • 全局容器注入
  • 高性能RPC
  • 服务治理熔断、降级、负载、注册与发现
  • RPC服务
  • 连接池Mysql、Redis、RPC
  • inotify自动reload
  • 强大的日志系统

Future

  • 事件机制
  • 连接池等待队列
  • 别名机制
  • 国际化i18n
  • restful风格
  • 数据库ORM(自动验证、模型、db)
  • crontab定时任务
  • 服务监控
  • 日志统计分析
  • 统一配置中心

更新记录

  • ......
  • 2017-08-15 重构console命令行
  • 2017-08-24 重写IOC容器,新增控制器路由注解注册,不再依赖php-di。使用时,重新composer安装
  • 2017-08-28 inotify自动reload

快速入门

文档

QQ交流群:548173319

环境要求

  1. hiredis
  2. composer
  3. PHP7.X
  4. inotify(可选)
  5. Swoole2.x且开启协程和异步redis

安装

  • clone项目
  • composer install安装依赖
  • 配置base.php
  • 设置启动参数swoft.ini

启动

启动服务支持HTTP和TCP同时启动,swoft.ini中配置。

常用命令

//启动服务,是否是守护进程,根据swoft.ini配置php swoft.php start//守护进程启动,覆盖swoft.ini守护进程配置php swoft.php start -d// 重启php swoft.php restart// 重新加载php swoft.php reload// 关闭服务php swoft.php stop

Swoft.ini参数

[swoft];;;;;;;;;;;;;;;;;;;; About swoft.ini   ;;;;;;;;;;;;;;;;;;;;[server]pfile = '/tmp/swoft.pid';pname = "php-swf";[tcp]enable = 1;host = "0.0.0.0"port = 8099type = 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'  => \swoft\web\Router::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/{name}', function ($arg) {    echo $arg; // 'john'}, [    'tokens' => [        'name' => '\w+', // 添加参数匹配限制。若不添加对应的限制,将会自动设置为匹配除了'/'外的任何字符    ]]);// 可选参数支持。匹配 'hello' 'hello/john'$router->get('/hello[/{name}]', 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('/', app\controllers\Home::class);$router->get('/index', 'app\controllers\Home@index');$router->get('/about', 'app\controllers\Home@about');// 访问 '/home/test' 将会执行 'app\controllers\Home::test()'$router->any('/home/{any}', app\controllers\Home::class);// 可匹配 '/home', '/home/test' 等$router->any('/home[/{name}]', app\controllers\Home::class);// 配置 matchAll 可用于拦截所有请求,目前有如下两种方式。//路由path'matchAll' => '/about',//回调'matchAll' => function () {    $resposne = App::getResponse();    $resposne->setResponseContent("System Maintaining ... ...");    $resposne->send();},

控制器

一个继承\swoft\web\Controller的类既是控制器,控制器有两种注解自动注册和手动注册两种方式。建议使用注解自动注册,方便简洁,维护简单。多次注册相同的路由前者会被后者覆盖。

注解自动注册

注解自动注册常用到三个注解@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") * * @uses      DemoController * @version   2017年08月22日 * @author    stelin 
* @copyright Copyright 2010-2016 swoft software * @license PHP Version 7.x {@link http://www.php.net/license/3_0.txt} */class DemoController extends Controller{ /** * 注入逻辑层 * * @Inject() * @var IndexLogic */ private $logic; /** * 定义一个route,支持get和post方式,处理uri=/demo2/index * * @RequestMapping(route="index", method={RequestMethod::GET, RequestMethod::POST}) */ public function actionIndex() { // 获取所有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) */ public function actionIndex2() { // 重定向一个URI $this->redirect("/login/index"); } /** * 没有使用注解,自动解析注入,默认支持get和post,处理uri=/demo2/index3 */ public function actionIndex3() { $this->outputJson("suc3"); }}

手动注册

手动注册常用@Bean、@Inject注解,手动注册还要多一步就是在routes.php里面注册自己的路由规则。

手动注册@Bean()只能这样缺省方式。并且不能使用@AutoController注解

/** * 控制器demo * * @Bean() * * @uses      DemoController * @version   2017年08月22日 * @author    stelin 
* @copyright Copyright 2010-2016 swoft software * @license PHP Version 7.x {@link http://www.php.net/license/3_0.txt} */class DemoController extends Controller{ /** * 注入逻辑层 * * @Inject() * @var IndexLogic */ private $logic; /** * uri=/demo2/index */ public function actionIndex() { // 获取所有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 */ public function actionIndex2() { // 重定向一个URI // $this->redirect("/login/index"); $this->outputJson("suc2"); } /** */ public function actionIndex3() { $this->outputJson("suc3"); }}

routes.php手动注册路由:

// ...$router->map(['get', 'post'], '/demo2/index', 'app\controllers\DemoController@index');$router->get('/index2', 'app\controllers\DemoController@index2');$router->get('/demo2/index3', 'app\controllers\DemoController@index3');

连接池

连接池使用简单,只需在base.php里面配置对应服务连接池即可。

return [    // ...    // RCP打包、解包    "packer"          => [        'class' => JsonPacker::class    ],    // 服务发现bean, 目前系统支持consul,只行实现    'consulProvider'       => [        'class' => \swoft\service\ConsulProvider::class    ],    // user服务连接池    "userPool"            => [        "class"           => \swoft\pool\ServicePool::class,        "uri"             => '127.0.0.1:8099,127.0.0.1:8099', // useProvider为false时,从这里识别配置        "maxIdel"         => 6,// 最大空闲连接数        "maxActive"       => 10,// 最大活跃连接数        "maxWait"         => 20,// 最大的等待连接数        "timeout"         => '${config.service.user.timeout}',// 引用properties.php配置值        "balancer"        => '${randomBalancer}',// 连接创建负载        "serviceName"     => 'user',// 服务名称,对应连接池的名称格式必须为xxxPool/xxxBreaker        "useProvider"     => false,        'serviceprovider' => '${consulProvider}' // useProvider为true使用,用于发现服务    ],    // user服务熔断器    "userBreaker" => [        'class'           => \swoft\circuit\CircuitBreaker::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(new \Exception("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);

转载于:https://my.oschina.net/mickelfeng/blog/1549537

你可能感兴趣的文章
【Lolttery】项目开发日志 (一) 微服务框架搭建
查看>>
快速使用七牛云对象存储
查看>>
webapck由浅入深——(Tapable)
查看>>
ButterKnife 原理解析
查看>>
说说Chrome插件从开发调试到打包发布
查看>>
搬运工---工具类(三方库)
查看>>
Android开发 手机开发者模式
查看>>
Paint的用法总结
查看>>
正则:验证一个有效数字
查看>>
如何进行架构方案选型和推进【Docker】
查看>>
一、(基础知识)一个前端程序员的java小白之路
查看>>
手把手教你如何在Android下进行JNI开发(入门)
查看>>
设计模式之AOP
查看>>
Android Studio jni - 入门篇
查看>>
promise,then,setTimeout -- 细致探讨执行流程
查看>>
不断发展的“爸妈游”产品真如表面看起来的那样美好?
查看>>
咖啡再热闹,也逃不出巨头的手掌心
查看>>
直击大圣车服一周年发布会:这个汽车生态平台要放大招!
查看>>
XXL-RPC v1.3.2,分布式服务框架
查看>>
java 集合 2 - LinkedList
查看>>