github.com/hongg-coder…
前言
相信在场各位的泥腿子(如果大佬请跳过这段话)每天工作都是穿梭在curd和curl的爱恨情仇之中,但是本文不对curd过多讲解,让我们看看curl的日常
场景一
某泥腿子程序员A: 某泥腿子程序员B,在吗 你们A接口返回的格式不对啊 B接口返回500了啊
某泥腿子程序员B: 没有啊 我们这里看都是正常的啊
某泥腿子程序员A:?????
场景二
某泥腿子程序员A: 好像隔壁部门的接口挂了,导致我们接口一直超时把fpm占满了,整个系统都挂了
某泥腿子程序员B: 坑比队友,接口天天挂了
。。。。。省略一大堆的吐槽
领导: 为什么我们系统天天挂
某泥腿子程序员A、B:因为我们调用隔壁部门接口 他们挂了,我们也挂了
领导:你们怎么不跟着一起挂,给我解决这个问题
于是乎
秉承着能用就行,看看市面上没有现成的解决方案,泥腿子A打开了某国内搜索引擎 输入了 php服务熔断和过载保护 发现一无所获 只能硬着秃头开始自己撸一个
插曲:可以把php换成任何的语言都有收获,具体原因可以自行学习fpm的工作机制
实现的功能
往往我们在设计一个系统或者bug的时候,都需要明确要实现什么、完成什么,而不是瞎来
需要实现的功能如下:
1.如果服务超时某个次数,则不再访问
2.如果服务频繁挂了,我们需要监控提早处理 ---- 事实上大部分的系统宕机都是后知后觉
3.如果顺带能把每次的请求记录保存下来 那就是更好啦
那么归类为熔断、监控、日志
熔断
熔断在请求某个接口的时候去判断该接口是否能被请求,如果不能请求只能返回对应错误码、或者异常
这里还会涉及怎么算是熔断,我们可以根据每个http请求的开始时间进行判断,如果A接口在**时间内超时**秒以上的达到**次数认为这段时间该接口不稳定需要熔断保护自身的系统
日志
目前使用了guzzle的http请求的库 可参照里面的middleware
guzzle-cn.readthedocs.io/zh_CN/lates…
注册两个中间件
请求开始中间件
记录请求的开始时间、请求url、请求参数、请求头
请求结束中间件
记录请求返回的response、status、结束时间
类似于
$stack = HandlerStack::create();
$this->result = new Result();
$stack->push(Middleware::mapRequest(function (RequestInterface $request) {
$this->result->setRequest($request);
$this->result->setStartTime(microtime(true));
return $request;
}));
$stack->push(Middleware::mapResponse(function (ResponseInterface $response) {
$this->result->setResponse($response);
$this->result->setEndTime(microtime(true));
// 把result对象传入日志类处理
return $response;
}));
监控
我们可以计算下什么时候需要监控
1.服务出现非正常状态返回 (400~500)
2.服务超时
3.对某个服务进行熔断
那么整个流程我们可以归类为
talk is cheap, show me the code
约束说明
监控 约束Interface
|
requestExceptionReport
触发条件:http请求出发了Guzzle RequestException 异常
监控目的:需要告诉大群 这个接口发生了异常 一般都是第三方服务的崩溃
推荐实现:将异常信息和request对象信息组装成消息发到微信报警群
curlErrorReport
触发条件:http请求的失败次数(response的code 认为失败)在一定期间(UrlRule.$errorInterval)那达到设置的次数(UrlRule.$errorLimit)
监控目的:需要告诉大群 这个接口 一直在失败 一般都是第三方服务故障
推荐实现: ****接口在***事件那失败次数达到****次数 发送到微信报警群
不做熔断处理
lockReport
触发条件:http请求超时超过了(UrlRule.$timeoutLimit)秒 的次数(UrlRule.$timeoutInterval)在一定期间内(UrlRule.$timeoutInterval)
监控目的:因为接口大幅度的超时会影响自己业务的稳定性,需要暂时屏蔽接口 让我们业务保持稳定 一般都是第三方服务出现压力 超时导致
推荐实现:****接口在***事件那超时超过***秒达到****次数 发送到微信报警群
熔断根据UrlRule.$isNeedLock判断 熔断与监控不冲突 可以不熔断 但是能触发监控
日志LoggerInterface
|
info
触发条件:每次http请求结束后
日志目的: 保存每条http的日志 扔到elk上
参数解析:Result.Request := Guzzle.RequestIntefece ,Result.Response := Guzzle.ResponseInterface ,请求间隔 :=Resule.endTime - Result.startTime
推荐实现:{"request":{"method":"","params","","url":""},"response":{"code":"","return":""},"excute_time":""}
强烈推荐后者统一规范
Error
触发条件:http请求出发了Guzzle RequestException 异常
日志目的:保存每条异常的日志 可以 elk分析 or 分析当时的上下文 进行数据修复
参数解析:Guzzle RequestException
推荐实现:{"request":"*****","exception":{"message":"","file":"","line:""}}
缓存约束CacheInterface
|
这段代码用各自项目的缓存驱动去实现对应内容 可以各个框架
url监控配置
|
如何配置每个url的规则?
|
异常
LockException (接口熔断异常)
|
RequestException (Guzzle 请求异常)
1.dns解析失败
2.超时异常 超过 config.timeout
3.网络包异常
.....具体参照guzzle-cn.readthedocs.io/zh_CN/lates…
事件说明
时间依赖event-dispatch设计
事件列表
HttpExceptionEvent - http请求异常事件
HttpLockEvent - http接口锁住事件
HttpResponseEvent - http接口结束事件
监听列表
|
事件管理
有人会问:泥腿子你写的compose代码太垃圾 我不想用你的事件代码 我可以自己复写吗?
当然可以的 还是可以非入侵复写
增加事件
|
删除事件
|
如何引入该包
初始化
|
http调用
你可以用到guzzle所有的特性 我并没有去更改guzzle的功能 完全依赖
|