购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

4.3 Envoy扩展模型

插件是Envoy扩展性支持的重要方式,通过插件扩展,可以支持不同的网络协议和链路治理特性,也可以对流量进行场景化定制处理。

4.3.1 插件扩展机制

1.插件注册机制

Envoy插件当前采用静态注册的方式,只需要声明Registry::RegisterFactory对应的模板类变量,就可以完成插件的注册。以OriginalDst插件为例,声明如下:


static Registry::RegisterFactory<OriginalDstConfigFactory,
                        Server::Configuration::NamedListenerFilterConfigFactory>
    registered_;               

插件的具体注册通过RegisterFactory类来完成,在RegisterFactory类中,会通过模板参数声明一个类的成员变量,在类的构造函数中,调用registerFactory完成模板参数的实际注册。


template <class T, class Base> class RegisterFactory {
public:
  //通过FactoryRegistry构建模板
  RegisterFactory() { FactoryRegistry<Base>::registerFactory(instance_); }
private:
  T instance_{};
};

在FactoryRegistry<Base>::registerFactory中,直接将插件名和插件实例注册到全局的插件实例map上。


  static void registerFactory(Base& factory) {
    factories().emplace(std::make_pair(factory.name(), &factory));
    ...
  }

插件会通过Config::Utility::getAndCheckFactory函数获取注册的插件实例,getAnd-CheckFactory会调用FactoryRegistry::getFactory函数,查找到相应的插件实例。


  static Base* getFactory(const std::string& name) {
    auto it = factories().find(name);
    if (it == factories().end()) {
      return nullptr;
    }
    return it->second;
  }

2.插件触发机制

Envoy插件的使用方式均比较类似,上面讲述插件注册机制时可以看出,插件静态注册是一个根据插件名称将插件工厂模板注册到全局map的过程。使用插件前需要根据配置文件,使用插件工厂模板获取当前支持的插件工厂列表,示例代码如下:


std::vector<XXXFactoryCb> ret;
for (ssize_t i = 0; i < filters.size(); i++) {
    //获取当前配置的插件名称,以及对应的插件配置
    const auto& proto_config = filters[i];
    const auto& string_name = proto_config.name();
    const auto& filter_config = getJsonObjectFromMessage(proto_config.config());
    //获取插件对应的实例工厂
    auto& factory = getAndCheckFactory<XXXFactory>(string_name);
    //根据插件配置,实例化插件工厂
    auto message = Utility::translateToFactoryConfig(proto_config, factory);
    ret.push_back(factory. createFilterFactoryFromProto (*message, context));
}

上述实例代码最后通过插件工厂模板的createFilterFactoryFromProto方法创建具体的插件工厂,以下面的OriginalDstConfigFactory插件为例,返回的插件工厂采用的是C++11 Lambda表达式(对C++11 Lambda使用方式不太熟悉的读者,可以自行学习下C++11的语法规范,这里不再详述)。


Network::ListenerFilterFactoryCb 
OriginalDstConfigFactory::createFilterFactoryFromProto(
     const Protobuf::Message&, ListenerFactoryContext&) override {
  //返回C++11 Lambda表达式形式的插件工厂
  return [](Network::ListenerFilterManager& filter_manager) -> void {
     filter_manager.addAcceptFilter(std::make_unique<OriginalDstFilter>());
  };
}

使用插件前,根据上述返回的插件工厂列表构造具体的插件实例。下面createListener-FilterChain函数中的listener_filter_factories_就是根据监听器配置得出的监听器工厂列表,遍历每一个工厂方法进行Lambda表达式展开,实际执行的是filter_manager.addAccept-Filter(std::make_unique<OriginalDstFilter>())语句,addAcceptFilter完成真正的插件实例构造OriginalDstFilter,然后将插件挂载到插件管理器中。


bool createListenerFilterChain(ListenerFilterManager& manager) {
  return buildFilterChain(manager, listener_filter_factories_);
}
bool buildFilterChain(FilterManager& filter_manager,
  const std::vector<Network::FilterFactoryCb>& factories) {
  for (const Network::FilterFactoryCb& factory : factories) {
    //这里会对之前返回的C++11 Lambda表达式形式的插件工厂进行Lambda展开
    factory(filter_manager);
  }
  return filter_manager.initializeReadFilters();
}

4.3.2 网络相关插件

Envoy自带一些插件,统一放在/source/extensions目录下,最大的一块在filters 子目录下,负责网络方面的插件实现,当前主要有3部分:分别是监听过滤器、网络过滤器和HTTP过滤器,分别负责连接元数据层面的扩展支持、网络协议方面的扩展支持以及基于协议内容的扩展支持,下面会分别讨论。

1.监听过滤器

监听过滤器在接收到新连接请求,但还未进行实际的新连接创建工作之前触发,通过监听过滤器插件,可以调整连接元数据信息。Envoy当前支持原目的地、原出发地、Proxy Protocol和TLS Inspestor这几种监听过滤器。

Envoy会对Istio集群的所有流量进行透明拦截,通过监听端口号获取拦截层发过来的请求,原目的地监听过滤器用于获取拦截前的目的地址,然后基于该目的地址进行后续的路由和转发操作。

出于问题定位和诊断的考虑,不少场景下下游服务希望上游连接采用的是真实的客户端地址,而不是中间的代理服务器地址。Proxy Protocol监听过滤器就是为了实现这个需求,Proxy Protocol监听过滤器基于Proxy Protocol协议。Proxy Protocol协议是HA Proxy作者Willy Tarreau设计的一个网络协议,通过为TCP添加一个额外头部信息,方便传递一些客户端信息到服务端,比如协议栈、源IP地址等,这对复杂网络场景下需要同步获取客户端真实IP地址非常有用。Proxy Protocol监听过滤器基于Proxy Protocol协议获取客户端真实的IP地址,Envoy和下游建立连接时采用客户端请求的源IP地址,而不是Envoy自身的IP地址,下游感知不到Envoy的存在,以为请求仍然是从真正的客户端发过来的,实现了真正的Envoy透传。需要特别注意的一点,由于Proxy Protocol协议对TCP协议进行了定制扩展,和正常的TCP协议不兼容,因此 使用Proxy Protocol协议时需要上下游均支持Proxy Protocol协议才可以,否则会导致消息解析出错。

2.网络过滤器

网络过滤器主要有两个层面的工作:一是连接相关的,主要是连接相关的控制,比如限流、认证等;二是协议相关的处理,Envoy接收到请求时首先需要知道该请求是什么协议,如何进行解码等,协议处理是网络过滤器的主要工作,也是整个Envoy的工作重心所在,Envoy当前支持HTTP、Thrift、MySQL、Kafka、Dubbo等众多网络协议,下面重点讲一下协议处理中的网络过滤器的原理和大体实现。

网络过滤器的首要工作是协议编解码处理,收到请求消息时对请求消息进行解码处理,获取上游流量路由和转发相关的元数据信息,收到上游的响应消息后,进行编码处理,返回给下游客户端;其次是流量路由和转发,根据当前使用场景和请求元数据信息,决策最合适的Upstream上游,这个也是Envoy的主要价值所在;最后一项工作是Upstream管理,获取与Upstream之间的连接,并建立和Upstream之间的安全通信,同时在Upstream异常时进行完善的容错处理。

3.协议相关过滤器

协议相关过滤器基于协议内容进行过滤和扩展处理,Envoy当前对HTTP协议、Thrift协议等均有过滤器扩展支持,对HTTP协议的支持比较完善些,当前支持路由、限流、Lua扩展等多种扩展方式。

插件扩展需要有相应的扩展点,对于HTTP协议来说,在编解码的不同阶段,均支持相应的扩展点。当前主要的扩展点有对HTTP消息头、消息体、Trailers这几部分的编码和解码。

4.3.3 其他扩展插件

除了网络相关插件之外,Envoy还内置了一些插件支持,大体分为流量管理、可观测性和服务管理这几个部分。

流量管理方面,支持的主要是各个网络协议均会用到的协议无关的一些插件,比如健康检查扩展支持、重试和传输层扩展支持等。

可观测性是Envoy一个很大的亮点,Envoy在可观测性的几个核心维度——Metric、Log和Trace均有相应的框架支持。

此外,Envoy还内置一些服务管理方面的插件支持,比如资源限制等。

除了官方源码自带的插件外,Envoy还支持以自定义方式进行插件扩展。Envoy原生代码中没有Mixer相关的实现,Istio数据平面对Mixer的支持是通过单独的proxy项目来实现。 HBvtK2IrCsovqFTWNRCfhg9MW4JOSP4mPfpGkom78o4L1SHaV8A0LQAN/sLQgwhs

点击中间区域
呼出菜单
上一章
目录
下一章
×