Hyperf方案 灰度发布策略

张开发
2026/4/6 17:35:23 15 分钟阅读

分享文章

Hyperf方案 灰度发布策略
?php/** * 案例标题灰度发布策略 * 说明基于请求头X-Gray-User实现灰度流量路由部分用户走新版本接口 * 需要安装的包 * composer require hyperf/http-server * composer require hyperf/config */declare(strict_types1);// app/Middleware/GrayReleaseMiddleware.php namespaceApp\Middleware;useHyperf\Contract\ConfigInterface;usePsr\Http\Message\ResponseInterface;usePsr\Http\Message\ServerRequestInterface;usePsr\Http\Server\MiddlewareInterface;usePsr\Http\Server\RequestHandlerInterface;usePsr\Log\LoggerInterface;/** * 灰度中间件根据请求头或用户ID决定走新版本还是老版本 * 放在路由中间件链最前面优先判断 */classGrayReleaseMiddlewareimplementsMiddlewareInterface{publicfunction__construct(privateConfigInterface$config,privateLoggerInterface$logger){}publicfunctionprocess(ServerRequestInterface$request,RequestHandlerInterface$handler):ResponseInterface{// 从请求头读灰度标记前端或API网关可以注入这个头$grayHeader$request-getHeaderLine(X-Gray-Release);// 也可以从cookie读适合Web场景$cookies$request-getCookieParams();$grayCookie$cookies[gray_release]??;// 再读用户ID根据用户ID做百分比灰度$userId(int)($request-getHeaderLine(X-User-Id)?:0);$isGray$this-shouldGoGray($grayHeader,$grayCookie,$userId);// 把灰度标记写到请求属性里后续处理器可以读到$request$request-withAttribute(is_gray,$isGray);$request$request-withAttribute(gray_version,$isGray?v2:v1);if($isGray){$this-logger-info(灰度流量,[user_id$userId,path$request-getUri()-getPath()]);}return$handler-handle($request);}/** * 综合多个维度判断是否走灰度 */privatefunctionshouldGoGray(string$grayHeader,string$grayCookie,int$userId):bool{// 1. 请求头明确指定走灰度内部测试用if($grayHeadertrue||$grayHeader1){returntrue;}// 2. Cookie带了灰度标记上次已命中灰度保持一致体验if($grayCookietrue){returntrue;}// 3. 按用户ID取模控制灰度比例$grayPercent(int)$this-config-get(gray.percent,10);// 默认10%的用户走灰度if($userId0($userId%100)$grayPercent){returntrue;// 用户ID末两位小于比例就进灰度}// 4. 白名单用户强制走灰度测试账号$whitelist$this-config-get(gray.whitelist_user_ids,[]);if(in_array($userId,$whitelist)){returntrue;}returnfalse;}}// app/Controller/OrderController.php namespaceApp\Controller;useApp\Service\OrderServiceV1;useApp\Service\OrderServiceV2;useHyperf\HttpServer\Annotation\Controller;useHyperf\HttpServer\Annotation\GetMapping;usePsr\Http\Message\ServerRequestInterface;#[Controller(prefix:/api/order)]classOrderController{publicfunction__construct(privateOrderServiceV1$v1,privateOrderServiceV2$v2,privateServerRequestInterface$request){}/** * GET /api/order/list - 灰度用户走新版本逻辑其余走旧版本 */#[GetMapping(path:/list)]publicfunctionlist():array{$isGray$this-request-getAttribute(is_gray,false);if($isGray){// 灰度用户走V2新版本逻辑比如新的推荐算法$data$this-v2-getOrderList();return[versionv2,data$data];}// 正常用户走V1$data$this-v1-getOrderList();return[versionv1,data$data];}}// app/Service/OrderServiceV1.php namespaceApp\Service;classOrderServiceV1{publicfunctiongetOrderList():array{// 老版本按创建时间倒序return[[id1,statuspaid,algotime_desc]];}}// app/Service/OrderServiceV2.php namespaceApp\Service;classOrderServiceV2{publicfunctiongetOrderList():array{// 新版本加入智能排序灰度测试中return[[id1,statuspaid,algosmart_rank]];}}// config/autoload/gray.php return[percent(int)env(GRAY_PERCENT,10),// 灰度比例可以动态调whitelist_user_ids[1001,1002,9999],// 固定进灰度的测试账号enable_logtrue,// 是否记录灰度命中日志];// config/routes.php 注册中间件 useApp\Middleware\GrayReleaseMiddleware;useHyperf\HttpServer\Router\Router;Router::addGroup(/api,function(){Router::get(/order/list,[\App\Controller\OrderController::class,list]);},[middleware[GrayReleaseMiddleware::class]]);// 对/api路由组启用灰度中间件

更多文章