Envoy源码分析之一--Server初始化(下)
*代码版本:stable/v1.7.1*
这里结合资料及源码仅分析正常场景的主干流程。本系列博文分为四部分,Server初始化,Envoy启动与新连接建立,Envoy对数据的读取、接收和处理,Envoy数据转发到服务端。
Server的初始化,初始化主要分为两部分,一是Envoy进程起来后的入口函数、二是Server的初始化。本章介绍第二部分。
##### 5. Server初始化
回到3和4中
初始化server是在上述构造函数体中的initialize中完成的,
这部分,这部分完成以下部分的server初始化。
###### 5.1 bootstrap
在InstanceImpl::initialize中,
从loadBootstrapConfig函数可知,通过loadFromFile和loadFromYaml读取配置文件路径下的配置,并完成参数校验。
5.2 admin API 初始化
admin初始化通过AdminImpl()实现
AdminImpl其入参,initial_config为Configuration::InitialImpl类型,将5.1中获取的配置文件生成结构化数据对象initial_config,并在初始化admin的时候将其相关参数取出使用。
这部分5.1的内容inital_config盖过不提,AdminImp()函数实现在admin.cc中,
从这里看,Admin API的功能是为管理员提供API管理Envoy。其中handlers_中提供了/certs、/clusters等API,以如下格式提供,
上面的字段对应的结构体为
在handler_对应的MAKE_ADMIN_HANDLER部分,对应的宏定义在server/admin.h中
这里,如果UrlHandler 的prefix字段和请求输入的prefix字段一致,就会执行X(path_and_query, response_headers, data, admin_stream),例如请求的是/config_dumps,则对应上上面/config_dumps那组结构体,那么handlerConfigDump被调用,进行相关解析,如果返回Http::Code:OK,则代表执行成功。具体每个handler函数内部的实现,这次不再分析,放到以后的博文里更新。
###### 5.3 Woker的初始化
Worker的初始化是Server初始化中的一个重要环境,由initialize中的如下代码进行初始化。
在listener_manager_impl.cc中的ListenerManagerImpl构造函数中实现wokrer的创建如下:
调用stl的emplace_back给workers List增加新的若干worker,每个woker由createWorker去实现,createWorker在worker_impl.cc中代码如下:
在createWorker中,初始化dispatcher时,调用api_.allocateDispatcher()获取Event::DispatcherImpl实例,
在DispatcherImpl的构造函数中,开了Buffer去管理Watermark,关于watermark和callback的机制(Envoy的内存管理)后续会单独有博文,这里简单提一下,这种机制主要是提供作为proxy的envoy在代理client和server间数据缓冲如何处理的能力。这里可以尝试搞一些数据面的性能优化,把Istio-proxy(envoy)的内存消耗设法降一降。DispatcherImpl构造函数代码如下:
可以看到,调用了DispatcherImpl方法,将Buffer::WatermarkFactoryPtr{new Buffer::WatermarkBufferFactory}作为入参调用下面带有入参的初始化函数。其中,Buffer::WatermarkFactoryPtr和Buffer::WatermarkBufferFactory的代码实现如下:
Buffer::WatermarkFactoryPtr:
Buffer:WaterBufferFactory:
可以看出,WatermarkBufferFactory 继承了WatermarkFactory,而WatermarkFactoryPtr独享了WatermarkFactory的实例地址。回到最终的函数调用
这里的实现很简单:在初始化列表中将上述提到的那个智能指针赋值给一个指向WatermarkBufferFactory 实例类型的unique_tr( Buffer::WatermarkFactoryPtr buffer_factory_;)智能指针buffer_factory_,而这个buffer_factory智能指针,是DispatcherImpl类的私有成员变量,看下这个类的定义,
这个类是Event::Dispatcher的libevent implementation
至此,本节开头的 listener_manager_.reset函数就完成了worker的初始化工作。
###### 5.4 Cluster Discover Sevice(CDS)的初始化
初始化完成了worker,回到initialize函数中,继续向下,CDS的初始化,
cluster_manager_factory声明是一个指向Upstream::ClusterManagerFactory的unique_ptr类型指针,通过reset操作take ownership of reset里面的unique_ptr指针,详见[# std::[unique_ptr]::reset](http://www.cplusplus.com/reference/memory/unique_ptr/reset/)。
> Reset pointer
Destroys the object currently managed by the [unique_ptr](http://www.cplusplus.com/unique_ptr) (if any) and takes ownership of *p*.
If *p* is a *null pointer* (such as a default-initialized pointer), the [unique_ptr](http://www.cplusplus.com/unique_ptr) becomes empty, managing no object after the call.
To release the ownership of the [stored pointer](http://www.cplusplus.com/unique_ptr::get) without destroying it, use member function [release](http://www.cplusplus.com/unique_ptr::release) instead.
那么cluster_manager_factory接管的ProdClusterManagerFactory对象是谁呢?这是一个ClusterManagerFactory的工厂模式的实现,代码如下:
之后初始化main_config,在main_config->initialize中初始化CDS,其实现在configuration_impl.cc中实现。initialize的核心代码段如下
clusterManagerFromProto的实现在cluster_manager_impl.cc中
在一串初始化列表之后,返回了一个ClusterManagerImpl对象,这个对象的实现也在cluster_manager_impl.cc中,其中创建cds的核心代码如下,当从bootstrap中获取到cds的configuration后,就开始进行cds的创建操作。
createCds实现
**拿到了配置文件,在cds_api_impl.cc中实现CdsApiImpl::create如下,返回一个CdsApiImpl对象,在这个对象的构造函数中,注册了subscription,每当有事件更新时,都会通过subscriptionCallback注册回调,执行cdsApiImpl::onConfigUpdate(),通过ClusterManager实现addOrUpdateCluster或者removeCluster()并且在Envoy日志中打印关于cluster更新操作的日志。**
###### 5.5 Listener Discover Service(LDS)的初始化
Lds初始化和cds类似,流程在Cds初始化之后,核心代码如下:
创建:
createLdsApi:
factory_.createLdsApi
**lds_api.cc中LdsApiImpl的构造函数,其中注册subscription,当有更新事件通过subscriptionCallbacks回调,用LdsApiImpl::onConfigUpdate实现ListenerManager的addOrUpdateListener或者removeListener(),并在Envoy日志中打印记录**
> 监听的是什么listener?
###### 5.6 GuardDog的初始化
GuardDog用于防止死锁
至此,Server初始化完成,下篇文章分析 Envoy是如何启动并建立新连接的。
- 点赞
- 收藏
- 关注作者
评论(0)