乐趣区

关于envoy:Envoy-开发入门搞懂-http-filter-状态码

原文地址:Envoy 开发入门:搞懂 http filter 状态码

对于 http filter,Envoy 提供了一大堆状态码,尽管每个都有不少的正文,然而仍旧很头大,傻傻搞不清楚。

本文记录一下本人的了解,如有谬误,欢送斧正~

http filter 是什么

Envoy 提供的 http 层的扩大机制,开发者能够通过实现 Envoy 约定的接口,在 Envoy 的解决流程中注入逻辑

比方,这两个申请阶段的接口:

Http::FilterHeadersStatus decodeHeaders(Http::RequestHeaderMap& headers, bool end_stream)
Http::FilterDataStatus decodeData(Buffer::Instance& data, bool end_stream)

如果想批改申请头,那就在 decodeHeaders 中批改 headers,如果想批改申请的 body,那就在 decodeData 中批改 data

本文所关注的状态码,就是这些函数的返回值,比方示例中的 FilterHeadersStatusFilterDataStatus

Envoy 为 filter 提供了啥

  1. 流式

    这个从下面的从 API 模式就可以看进去,外围是,http header 以及 http body 的每个 data 块,是一个个解决的。

  2. 异步

    当一个 filter 在处理过程中,如果须要期待内部响应,也能够先反馈给 Envoy 某种状态,等 filter ready 之后再持续。

  3. 并发

    这个其实很天然,因为有流式,所以,从逻辑上来说,不同的 filter 之间是存在并发的。

    然而,又容易被忽视,因为 Envoy 的工作模式中,具体到某个 http 申请是工作在单线程上的,所以容易有误会。

所以,Envoy 外部有一个 filter manager 模块,目标是用于治理 filter 的运行,也能够简略了解为,一个简单的状态机。

状态码

交代完背景,咱们具体看看状态码,以及 filter 和 filter manager 的状态机运行关系

Header 状态码

以 header 的状态码为例,咱们先挨个解读一下,找找感觉

  1. Continue

    这个最简略,示意以后 filter 曾经处理完毕,能够持续交给下一个 filter 解决了

  2. StopIteration

    示意 header 还不能持续交给下一个 filter 来解决

  3. ContinueAndDontEndStream

    示意 header 能够持续交给下一个 fitler 解决,然而下一个 filter 收到的 end_stream = false,也就是标记申请还未完结;以便以后 fitler 再减少 body。

  4. StopAllIterationAndBuffer

    示意 header 不能持续交给下一个 filter,并且以后 filter 也不能收到 body data。

    意思是,申请中的 body data 先 filter manager 缓存起来,如果缓存大小超过了 buffer limit(一个配置值),那就间接返回 413 了。

  5. StopAllIterationAndWatermark
    同上,区别是,当缓存超过了 limit,filter manager 就会启动流控,也就是暂停从连贯上读数据了。

过了一遍之后,有这么几个关键点

  1. StopIteration,只是先不交给下一个 filter 解决,然而并不进行从连贯读数据,持续触发 body data 的解决
  2. header 阶段,也能够对 body data 进行写操作,可想而知,也就是 add 操作了。
  3. filter manager 有一个 data 的缓冲区,帮 filter 长期缓冲数据

data 状态码

再看 data 的状态码,

  1. Continue

    跟 header 相似,示意以后 filter 曾经处理完毕,能够持续交给下一个 filter 解决了。

    只是,如果 header 之前返回的是 StopIteration,且尚未交给下一个 fitler,那么,此时 header 也会被交给下一个 fitler 解决。

  2. StopIterationAndBuffer

    示意以后 data 不能持续交给下一个 filter,由 fitler manager 缓存起来。

    并且,与 header 相似,如果达到 buffer limit,间接返回 413。

  3. StopIterationAndWatermark

    同上,只是达到 buffer limit,只是触发流控。

  4. StopIterationNoBuffer

    示意以后 data 不能持续交给下一个 filter,然而,fitler manager 也不须要缓存 data。

这里也有几个点:

  1. 如果 data 要被交给下一个 filter 解决了,header 是必定也会被交给下一个 fitler 解决了。

    咱们能够把 header 了解为,一个带有非凡语义的首个 data 块,无论怎么流式解决,数据的程序,是必须要保障的。

  2. data 阶段多了一个 NoBuffer 的状态,这又是什么目标呢?

要害解读

有几个容易误会的中央,咱们开展聊聊

异步

为了反对 filter 的异步,fitler 能够返回 Stop 语义的状态码,这样 filter manager 不会持续后续的 filter,然而:

并不意味着整个 filter manager 都进行了,以后 filter 以及之前的 filter,还是会承受到以后申请上的数据

并发

每个 filter 承受到的数据,在解决期间,是独享的,没有并发危险,然而 filter manager 的缓冲区,只有一个,这个是有并发危险的。

因为 filter 是逻辑上并发的,然而 filter manager 只有一个,所以是存在逻辑并发危险的。

举个例子:

filter A => filter B => filter C,这样一个解决链表

先来了第一个 data 块:filter A 和 B 反馈 continue,filter C 返回 StopIterationAndBuffer,此时 buffer 中是 data 1,

再来第二个 data 块,filter A 返回了 StopIterationAndBuffer,此时 buffer 中是 data 1 和 2 了,

而后 filter A 告诉 filter manager 复原解决,那么此时,filter B 看到的数据,就是 data 1 和 2 了。

显然,这并不合乎预期。

也就是说,对于每个 filter 而言,如果在 data continue 之后,再返回 StopIterationAndBuffer 的话,就可能有缓冲区并发危险。

简略的了解,如果要复用 filter manager 的缓冲区,每个 filter 只有首次异步的机会。

如果须要随时异步,那怎么办呢?

解决方案,也就是 StopIterationNoBuffer,filter 本人搞缓冲,也就不存在并发危险了。至于副作用嘛,次要就是本人多实现一些代码。

实践上来说,StopIterationNoBuffer 是最灵便的,不过也是更麻烦的,效率也会略差一点的。

集体领会

Envoy 的状态设计,为大部分常见的场景,提供了比拟不便易用的设计,然而绝对简单的场景,就须要本人多实现一些逻辑了。

只是这么搞了之后,对于新人的上手门槛就高了,如果不搞懂这些状态,闭着眼睛用,也是容易踩坑的。

最初

一个小问题,MOE 作为把 MOSN(Go)塞进 Envoy 的计划,此时的开发语言曾经是 Go 这种人造异步的,MOE 又提供的是什么样的开发体验呢?

MOE 近期会开源第一版,等开源之后,前面能够聊聊~

如果感觉有意思,欢送关注我的公众号「豆浆大叔」~

退出移动版