什麼是 Swoft ? Swoft 是一款基於 Swoole 擴展實現的 PHP 微服務協程框架。Swoft 能像 Go 一樣,內置協程網路伺服器及常用的協程客戶端且常駐記憶體,不依賴傳統的 PHP-FPM。有類似 Go 語言的協程操作方式,有類似 Spring Cloud 框架靈活的註解、強大的 ...

什麼是 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 = Swoole\Coroutine\Scheduler();
$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 = Swoole\Coroutine\Scheduler();
$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