关于php:聊一聊限流降级熔断

5次阅读

共计 2599 个字符,预计需要花费 7 分钟才能阅读完成。

熔断

小时候村里一到夏天,全村都开空调,村里总闸的保险丝就会因为用电量太大,主动熔断了,间接停服。股市也有一些极其状况开启熔断解决,不到万不得已,不会熔断。在 Web 工程中熔断的最小单元,也不肯定是整个利用,可能只是某个服务。这里不深究学术名词定义。

限流

限流场景咱们常常遇到,有时候地铁里就被保安人员给我限流了,双十一抢购也被爸爸限流了。坐地铁之所以能限流是因为咱们都要安检,有这个对立的地铁入口;浏览网站被限流是因为拜访有对立的域名入口。

当咱们须要依据路由规定进行限流,只有把握好网关就很不便的实现限流了,以下计划均可行

  • 布点在相似于 WAF(Web 利用防火墙)中,具体见 阿里云 WAF 手册
  • 如果不想花钱,也能够装置 nginx 限流插件来做相似的工作,本人部署,总之是在 web 利用后面布点拦挡操作
  • 也能够在 web 利用外面联合路由组件开发一个限流组件,只有代码有对立入口,就能够不便管制

降级

生存中我也是生产降级的小伙,原来天猫,起初淘宝,当初拼多多和淘宝特价版。生产降级真香,话说回来,重点是又不是不能用 。Web 我的项目中降级的案例,比方微博 feed 流中,用户根本信息压力比拟大,而用户的勋章也在该接口中对前端输入,服务降级的 重点是又不是不能用

如果是依照当初微服务的理念,勋章查问可能是一个独立的服务,所以降级对应的颗粒度能够是服务降级。既然是独立的服务单元,申请的拦挡就又回到了和限流一样的场景;
如果不是微服务架构,接口依赖的用户的勋章输入只是一个独立的函数或者办法,如何进行拦挡呢?

计划 1. 紧急公布

如果后端服务是 PHP 的脚本语言,咱们能够疾速的独自公布须要批改的文件,达到疾速降级的目标。
如果后端服务是 JAVA 须要编译的,对于这种简略场景的批改,也是反对热部署,独自公布一个 class 文件,也不须要重启也 OK,比方 arthas 就提供相似的性能。

如果公布零碎不反对热部署,也不反对单文件公布,只反对公布软件包的形式,那么疾速降级就须要 15 ~ 30 分钟(业务简单一点的 Java 利用)能力部署实现,这是互联网利用不能承受的。

计划 2. 限流降级中间件

在 Java 生态目前比拟成熟,出名的产品有 hystrix,我用的比拟多的是 sentinel。反对从路由、办法去做单机的 qps 去限流,只须要在 sentinel 管控台做配置变更,而后公布推送到各个机器,机器则以最初收到的限流规定单机闭环操作,两头不再须要和中间件服务进行交互。

PHP 能不能像 sentinel 一样对用户态的函数和办法进行拦挡管制呢,所以弄了这个 https://github.com/zhoumengka… PHP 7.2.5 线上运行 OK

装置应用

编译装置

$ phpize
$ ./configure --with-php-config=/usr/local/php/bin/php-config
# 如果须要调试
# ./configure --with-php-config=/usr/local/php/bin/php-config --enable-debug
$ make && make install

配置php.ini,在其前面追加

[sentinel]
extension=sentinel.so
sentinel.api_url=https://mengkang.net/sentinel.html
sentinel.api_cache_ttl=120
sentinel.api_cache_file=/tmp/sentinel.rule
sentinel.log_enabled=1
sentinel.log_file=/tmp/sentinel.log
  • sentinel.api_url 限流查问接口
  • sentinel.api_cache_ttl 接口查问后果缓存 2 分钟
  • sentinel.api_cache_file 接口查问缓存门路
  • sentinel.log_enabled 是否开启用户自定义的办法和函数日志记录,能够用日志解决工具收集比方阿里云 SLS
  • sentinel.log_file 日志记录门路

原理

PHP_MINIT阶段,通过 zend_set_user_opcode_handler 注册在 opcode 运行环节,对用户态的办法和函数(ZEND_DO_UCALL)的运行做解决

zend_set_user_opcode_handler(ZEND_DO_UCALL, php_sentinel_call_handler)

PHP_RINIT阶段,获取中间件配置。对于缓存时长内的不发动网络申请

php_sentinel_fetch()

限流策略闭环

php_sentinel_call_handler

当曾经曾经在限流列表中的办法或者函数进行拦挡,同时对通过的办法和函数进行日志记录(当日志性能开启的状况)而后进行相似 sls 上报,而后核心通过剖析 sls 日志再决策是否进行限流,通过接口告诉到各个 web 服务器。

注册自定义的异样类SentinelException,当检测到执行的办法或者函数须要被限流,则抛出该异样

zend_class_entry ce;
INIT_CLASS_ENTRY(ce, "SentinelException", NULL);
php_sentinel_exception_class_entry =  zend_register_internal_class_ex(&ce, zend_ce_exception);
php_sentinel_exception_class_entry->ce_flags |= ZEND_ACC_FINAL;

业务层能够对该异样在最外层进行捕捉,依照业务协定做规范谬误输入。

try{// 我的项目 dispatcher 调度入口}catch (\SentinelException $exception){// 规范的谬误输入 能够是 json 能够 html 页面}

目前的计划更偏差于一个熔断思路,只有运行到指定的办法或者函数就抛出异样,比方(以函数演示,办法也反对)。惋惜 PHP set_exception_handler 不能对运行以后行进行捕捉解决,并且接管异样。所以只能算是熔断,除非被拦挡的办法,在一些逻辑下没有进入。

function demo(){$ res[] = aa();
    
    if (条件 1) {$res[] = bb(); // bb 函数被降级} else {$resp[] = cc();}
    
    return $res;
}
正文完
 0