Swoft 2.0.3 重大更新,发布优雅的微服务治理
什么是 Swoft ?
Swoft 是一款基于 Swoole 扩展实现的 PHP 微服务协程框架。Swoft 能像 Go 一样,内置协程网络服务器及常用的协程客户端且常驻内存,不依赖传统的 PHP-FPM。有类似 Go 语言的协程操作方式,有类似 Spring Cloud 框架灵活的注解、强大的全局依赖注入容器、完善的服务治理、灵活强大的 AOP、标准的 PSR 规范实现等等。
Swoft 通过长达三年的积累和方向的探索,把 Swoft 打造成 PHP 界的 Spring Cloud, 它是 PHP 高性能框架和微服务治理的最佳选择。
优雅的服务治理
Swoft 官方建议开发者使用 Service mesh 模式,比如 Istio/Envoy 框架,把业务和服务治理分开,但是 Swoft 也为中小型企业快速构建微服务提供了一套微服务组件。
- 服务注册与发现
- 服务熔断
- 服务限流
- 配置中心
服务注册与发现
服务注册与发现,需要用到 Swoft 官方提供的 swoft-consul 组件,如果其它第三方也类似。
注册与取消服务
监听 SwooleEvent::START
事件,注册服务
/**
* Class RegisterServiceListener
*
* @since 2.0
*
* @Listener(event=SwooleEvent::START)
*/
class RegisterServiceListener implements EventHandlerInterface
{
/**
* @Inject()
*
* @var Agent
*/
private $agent;
/**
* @param EventInterface $event
*/
public function handle(EventInterface $event): void
{
/* @var HttpServer $httpServer */
$httpServer = $event->getTarget();
$service = [
// ....
];
$scheduler = SwooleCoroutineScheduler();
$scheduler->add(function () use ($service) {
// Register
$this->agent->registerService($service);
CLog::info('Swoft http register service success by consul!');
});
$scheduler->start();
}
}
监听 SwooleEvent::SHUTDOWN
事件,取消服务
/**
* Class DeregisterServiceListener
*
* @since 2.0
*
* @Listener(SwooleEvent::SHUTDOWN)
*/
class DeregisterServiceListener implements EventHandlerInterface
{
/**
* @Inject()
*
* @var Agent
*/
private $agent;
/**
* @param EventInterface $event
*/
public function handle(EventInterface $event): void
{
/* @var HttpServer $httpServer */
$httpServer = $event->getTarget();
$scheduler = SwooleCoroutineScheduler();
$scheduler->add(function () use ($httpServer) {
$this->agent->deregisterService('swoft');
});
$scheduler->start();
}
}
服务发现
定义服务提供者
/**
* Class RpcProvider
*
* @since 2.0
*
* @Bean()
*/
class RpcProvider implements ProviderInterface
{
/**
* @Inject()
*
* @var Agent
*/
private $agent;
/**
* @param Client $client
*
* @return array
* @example
* [
* 'host:port'
* ]
*/
public function getList(Client $client): array
{
// Get health service from consul
$services = $this->agent->services();
$services = [
];
return $services;
}
}
配置服务提供者
return [
'user' => [
'class' => ServiceClient::class,
'provider' => bean(RpcProvider::class)
// ...
]
];
Swoft 使用 @Breaker
注解实现熔断,可以在任何方法上面进行熔断操作。
/**
* Class BreakerLogic
*
* @since 2.0
*
* @Bean()
*/
class BreakerLogic
{
/**
* @Breaker(fallback="funcFallback")
*
* @return string
* @throws Exception
*/
public function func(): string
{
// Do something
throw new Exception('Breaker exception');
}
/**
* @return string
*/
public function funcFallback(): string
{
return 'funcFallback';
}
}
服务限流
Swoft 中使用 @RateLimiter
注解实现服务限流,可以在任何方法上面限流,不仅仅是控制器,且 KEY 还支持 symfony/expression-language 表达式。
/**
* Class LimiterController
*
* @since 2.0
*
* @Controller(prefix="limiter")
*/
class LimiterController
{
/**
* @RequestMapping()
* @RateLimiter(key="request.getUriPath()", fallback="limiterFallback")
*
* @param Request $request
*
* @return array
*/
public function requestLimiter(Request $request): array
{
$uri = $request->getUriPath();
return ['requestLimiter', $uri];
}
/**
* @param Request $request
*
* @return array
*/
public function limiterFallback(Request $request): array
{
$uri = $request->getUriPath();
return ['limiterFallback', $uri];
}
}
配置中心
配置中心,需要用到 Swoft 官方提供的 Swoft-apollo 组件,如果其它第三方也类似。
声明Agent
/**
* Class AgentCommand
*
* @since 2.0
*
* @Command("agent")
*/
class AgentCommand
{
/**
* @Inject()
*
* @var Config
*/
private $config;
/**
* @CommandMapping(name="index")
*/
public function index(): void
{
$namespaces = [
'application'
];
while (true) {
try {
$this->config->listen($namespaces, [$this, 'updateConfigFile']);
} catch (Throwable $e) {
CLog::error('Config agent fail(%s %s %d)!', $e->getMessage(), $e->getFile(), $e->getLine());
}
}
}
/**
* @param array $data
*
* @throws ContainerException
* @throws ReflectionException
*/
public function updateConfigFile(array $data): void
{
foreach ($data as $namespace => $namespaceData) {
$configFile = sprintf('@config/%s.php', $namespace);
$configKVs = $namespaceData['configurations'] ?? '';
$content = '<?php return ' . var_export($configKVs, true) . ';';
Co::writeFile(alias($configFile), $content, FILE_NO_DEFAULT_CONTEXT);
CLog::info('Apollo update success!');
/** @var HttpServer $server */
$server = bean('httpServer');
$server->restart();
}
}
}
启动Agent
Agent 只需要在服务(Http/RPC/Websocket)启动前,运行即可。
php bin/swoft agent:index
更新内容
移除(Remove)
- 移除
request->json()
方法(c9e8f04)
新增(Enhancement):
- 新增接口依赖注入(6169f84)
- 新增
getFile
方法获取文件上传保存之后的信息(fe7e3a6) - 新增
restart()
服务新增重启方法(2ffec37) - 新增调用 1.x RPC 服务支持(30d73c3)
- 新增 AOP 类名匹配支持正则表达式(bc5e479)
- 新增 RPC Server /Http Server 中间件命名空间
use
错误提示(b1cec04) - 新增 验证器排除属性字段
unfields
(b1bf44f) - 新增 自动写入时间戳(dc58011)
- 新增 模型动作事件(dc58011)
- 新增 数据库迁移(26bb464)
- 新增 实体自动与 json 和数组互转(dc58011)
- 新增 模型批量更新方法
batchUpdateByIds
(dc58011)
修复(Fixed):
- 修复 cookies 设置时的一些问题,增加一些 withCookie 相关方法(b05afbb01)
- 修复 在console使用协程方式运行命令时,没有捕获处理错误(8a5418bf)
- 修复 websocket server 重启命令没有先停止旧server问题(db2d935)
- 修复任务返回值为
null
问题(a69347c) - 修复 RPC Server 只有类中间件无法使用问题()204bc7f
- 修复 RPC Server 返回值为
null
问题(4d091be) - 修复 Logger 和 CLog 日志等级无法覆盖和无效问题(8eb8aba)
- 修复 模型里面的属性不支持自定义表达式(dc58011)
更新(Update):
- 验证器优化,支持自定义验证规则(d959a4f)
- 重命名错误处理管理类
ErrorHanlders
为ErrorManager
(f3a8f04b) - console组件的异常处理改为由error组件提供的统一处理风格 (4f47204)
- console组件允许设置禁用命令组(c5a0269)
- 在默认的错误处理中,允许设置错误捕获级别。默认级别是
E_ALL|E_STRICT
(afff9029) - 优化 启动ws server时同时启用了http处理功能,信息面板添加提示(83a81170)
- 优化 启动ws server 并同时添加rpc server启动,信息面板没有显示 rpc server信息(3d1d0d848)
扩展(Extra):
- 文档添加支持通过google进行搜索
- 新增 apollo 组件
- 新增 consul 组件
- 新增 breaker 组件
- 新增 limter 组件
资源
- Gitee: https://gitee.com/swoft/swoft
- GitHub: https://github.com/swoft-cloud/swoft
- 官网:https://www.swoft.org
- 文档:https://www.swoft.org/docs
- MongoDB 客户端 MongoVue
- HttpClient介绍
- 10个使用 Foundation 框架开发的WordPress 主题推荐
- jQuery 效果使用
- 几款更换WordPress 后台UI 的插件推荐
- 入门:构建简单的Web API
- WordPress 编辑器快捷键——让写作来得更方便些吧!
- ASP.NET Web API: 宿主(Hosting)
- 在 Windows Phone上使用QQConnect OAuth2
- WordPress 开发之使用WordPress 3.8+后台图标(dashicons)
- 基础(二)
- Ionic:高级的 HTML5 移动APP(Web App)开发框架
- 为WordPress 评论框添加HTML5 表单验证
- Sass 基础(一)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【作者解读】ERNIE-GEN : 原来你是这样的生成预训练框架!
- Python中那些低调有趣的模块
- 01背包问题讲解(动态规划)
- python实现随机森林
- 在mysql中order by是怎样工作的?
- 多线程应用 - 阻塞队列ArrayBlockingQueue详解
- Java虚拟机 - 超级详细的类加载说明
- ReentrantLock
- 多线程应用 - 阻塞队列LinkedBlockingDeque详解
- AtomicInteger详解
- 多线程应用 - 阻塞队列LinkedBlockingQueue详解
- 多线程应用 - 超详细的AQS详情
- 多线程应用 - 基于AQS的Condition
- HashMap源码分析 - jdk8
- HashMap源码分析 - JDK7和JDK8有什么区别