一、 熔断
理解熔断需要理解一下熔断要解决的问题 - 雪崩。
雪崩:分布式系统中经常会出现某个基础服务不可用造成整个系统不可用的情况, 这种现象被称为服务雪崩效应。
系统的调用链如图所示。一旦下游服务C因某些原因变得不可用,积压了大量请求,服务B的请求线程也随之阻塞。线程资源逐渐耗尽,使得服务B也变得不可用。紧接着,服务A也变为不可用,整个调用链路被拖垮,这种调用链路的连锁故障,叫做雪崩。
那么就要思考了,如何解决雪崩呢?
二、 request-termination
function RequestTerminationHandler:access(conf)
RequestTerminationHandler.super.access(self)
local status = conf.status_code
local content = conf.body
if content then
local ctx = ngx.ctx
if ctx.delay_response and not ctx.delayed_response then
ctx.delayed_response = {
status_code = status,
content = content,
content_type = conf.content_type,
}
ctx.delayed_response_callback = flush
return
end
end
return responses.send(status, conf.message)
end
复制代码
上面就是Kongrequest-termination
的核心代码了,从access
的逻辑可以分析:plugin从ctx中校验delay_response
是否为true,如果delay_response
(Boolean类型的标记量)和delayed_response
(map类型)不为空的情况下,设置delayed_response_callback
为flush函数。
ctx.delay_response 这个参数,它的原理就是把要执行的 handler wrap 在一个 coroutine 中,如果执行到一个插件需要 ngx.say 来提前执行 Nginx 的 content handler,那么它就会 yield 当前 coroutine,来延迟 content handler 的执行,并跳过之后需要执行的所有插件。这么做主要基于两点:
- 如果请求被插件拦截就尽快退出「phase」循环。
- 可以在输出 content 前,做一些自定义的操作。
这里没看懂(⊙﹏⊙)b,姑且猜测:熔断插件的access执行之前,会根据ctx中的标记位来决定是否需要继续执行工作,还是被拦截并按照配置的status和content放回response给客户端。
那么这里的标记位ctx.delay_response
会在什么场景下被标记为true?或是ctx.delay_response
初始化时就已经是true了,他的设计就是为了让请求从一个插件中跳出来,然后结束后续插件的执行。
function Kong.access()
kong_global.set_phase(kong, PHASES.access)
local ctx = ngx.ctx
runloop.access.before(ctx)
ctx.delay_response = true
for plugin, plugin_conf in plugins_iterator(loaded_plugins, true) do
if not ctx.delayed_response then
kong_global.set_named_ctx(kong, "plugin", plugin_conf)
kong_global.set_namespaced_log(kong, plugin.name)
local err = coroutine.wrap(plugin.handler.access)(plugin.handler, plugin_conf)
kong_global.reset_log(kong)
if err then
ctx.delay_response = false
return responses.send_HTTP_INTERNAL_SERVER_ERROR(err)
end
end
end
复制代码
参考:
近期评论