swoft 是基于 swoole 协程 2.x 的高性能 PHP 微服务框架,内置 http 服务器。框架全协程实现,性能优于传统的 php-fpm 模式。
中文文档
启动服务支持 HTTP 和 TCP 同时启动,swoft.ini 中配置。
- //启动服务
- php swoft.php start
- // 重启
- php swoft.php restart
- // 重新加载
- php swoft.php reload
- // 关闭服务
- php swoft.php stop
- [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 = 80
- model = SWOOLE_PROCESS
- type = SWOOLE_SOCK_TCP
- [setting]
- worker_num = 4
- max_request = 10000
- daemonize = 0;
- dispatch_mode = 2
- log_file = '../runtime/swoft/swoole.log';
路由解析有两种方式,注册路由和自动解析,所有路由都在 routes.php 中配置。路由配置参数 (base.php):
- return [
- // ...
- 'router' => [
- 'class' => \swoft\web\Router::class,
- 'ignoreLastSep' => false, // 是否忽略最后一个斜杠,设置false后,/user/index和/user/index/是两个不同的路由
- 'tmpCacheNumber' => 1000,// 缓存路由数,最近一1000条
- 'matchAll' => '', // 匹配所有,所有请求都会匹配到这个uri或闭包
- // 自动路由配置
- 'autoRoute' => true,// 是否开启自动匹配路由,默认是false
- 'controllerNamespace' => 'app\\controllers', // 命名空间
- 'controllerSuffix' => 'Controller', // 控制器后缀
- ],
- // ...
- ];
- //匹配 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 控制器定义 controller,@Inject 自动注入 Logic 依赖,Logic 中也可以使用 @Inject 自动注入 dao 层或其它依赖,注入的依赖默认是单列的。
- class IndexController extends Controller
- {
- /**
- * @Inject()
- * @var IndexLogic
- */
- private $logic;
- public function actionDemo()
- {
- // 获取所有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("data", 'suc');
- // 重定向一个URI
- $this->redirect("/login/index");
- }
- }
连接池使用简单,只需在 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 及内部服务通过监听 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 来实现 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);
来源: http://www.tuicool.com/articles/ayaiyq6