总时序图
Envoy的运行入口位于MainCommonBase::run方法中,此时Envoy进程以Server身份启动并执行run方法。
bool MainCommonBase::run() {
switch (options_.mode()) {
case Server::Mode::Serve:
server_->run();
启动worker工作线程
server中startWorkers
在server.cc文件run方法中会创建RunHelper对象来负责工作线程启动前的准备工作,并在准备工作完成后执行startWorkers来启动工作线程。
注意:启动工作线程是在ClusterManager初始化完成后的回调中执行的。
void InstanceImpl::run() {
// RunHelper exists primarily to facilitate testing of how we respond to early shutdown during
// startup (see RunHelperTest in server_test.cc).
const auto run_helper = RunHelper(*this, options_, *dispatcher_, clusterManager(),
access_log_manager_, init_manager_, overloadManager(), [this] {
notifyCallbacksForStage(Stage::PostInit);
startWorkers();
});
在server.cc文件startWorkers调用了listenerManager的startWorkers方法。
void InstanceImpl::startWorkers() {
// The callback will be called after workers are started.
listener_manager_->startWorkers(*worker_guard_dog_, [this]() {
if (isShutdown()) {
return;
}
listenerManager启动workers
在listener_manager_impl.cc文件的startWorkers方法中,先遍历所有可立即使用的监听器active_listeners_(理论上是在envoy初始化的时候创建的,还没仔细看,先todo),然后遍历所有的workers_,依次执行addListenerToWorker,将监听器和工作线程绑定。
void ListenerManagerImpl::startWorkers(GuardDog& guard_dog, std::function<void()> callback) {
// 将监听器同工作线程绑定
for (auto listener_it = active_listeners_.begin(); listener_it != active_listeners_.end();) {
for (const auto& worker : workers_) {
addListenerToWorker(...);
}
}
// 启动工作线程
for (const auto& worker : workers_) {
ENVOY_LOG(debug, "starting worker {}", i);
worker->start(guard_dog, worker_started_running);
if (enable_dispatcher_stats_) {
worker->initializeStats(*scope_);
}
i++;
}
将监听器同worker绑定
在listener_manager_impl.cc文件的addListenerToWorker方法调用WorkerImpl::addListener方法,给目标线程添加监听器。
void ListenerManagerImpl::addListenerToWorker(Worker& worker,
absl::optional<uint64_t> overridden_listener,
ListenerImpl& listener,
ListenerCompletionCallback completion_callback) {
worker.addListener(...);
}
在worker_impl.cc文件的addListener方法调用目标线程的Dispatcher的post方法,将连接管理器ConnectionHandler与监听器进行绑定。
void WorkerImpl::addListener(absl::optional<uint64_t> overridden_listener,
Network::ListenerConfig& listener, AddListenerCompletion completion) {
dispatcher_->post([this, overridden_listener, &listener, completion]() -> void {
// 详情见下一节:监听器的加载
handler_->addListener(overridden_listener, listener);
hooks_.onWorkerListenerAdded();
completion();
});
}
启动线程
在listener_manager_impl.cc文件的addListenerToWorker之后,轮询工作线程列表workers_,并运行WorkerImpl:start方法启动每个工作线程。
for (const auto& worker : workers_) {
ENVOY_LOG(debug, "starting worker {}", i);
worker->start(guard_dog, worker_started_running);
if (enable_dispatcher_stats_) {
worker->initializeStats(*scope_);
}
i++;
}
在worker_impl.cc文件的start方法中,调用系统方法createThread创建系统线程,并将threadRoutine方法作为工作线程的入口方法。
void WorkerImpl::start(GuardDog& guard_dog, const Event::PostCb& cb) {
thread_ = api_.threadFactory().createThread(
[this, &guard_dog, cb]() -> void { threadRoutine(guard_dog, cb); }, options);
}
在worker_impl.cc文件的threadRoutine方法中,首先发送post异步任务到目标工作线程任务调度队列,创建工作线程自己的watchdog,最后执行线程的dispatcher中的run方法来等待处理新事件。
void WorkerImpl::threadRoutine(GuardDog& guard_dog, const Event::PostCb& cb) {
dispatcher_->post([this, &guard_dog, cb]() {
cb();
watch_dog_ = guard_dog.createWatchDog(api_.threadFactory().currentThreadId(),
dispatcher_->name(), *dispatcher_);
});
dispatcher_->run(Event::Dispatcher::RunType::Block); // 阻塞等待
}
监听器的加载
在上一节中的将监听器同worker线程绑定里面讲到,最终是将连接管理器ConnectionHandler与监听器进行绑定。
在
connection_handler_impl.cc文件的addListener方法中,将根据各个监听器支持的协议类型创建监听器对象,比如对于tcp协议,将创建ActiveTcpListener实例。
void ConnectionHandlerImpl::addListener(absl::optional<uint64_t> overridden_listener,
Network::ListenerConfig& config) {
ActiveListenerDetails details;
} else if (config.listenSocketFactory().socketType() == Network::Socket::Type::Stream) { // tcp 类型
auto tcp_listener = std::make_unique<ActiveTcpListener>(
*this, config, worker_index_.has_value() ? *worker_index_ : 0);
details.typed_listener_ = *tcp_listener;
在active_tcp_listener.cc文件中,ActiveTcpListener构造方法中指定线程中的Dispatcher,调用createListener方法创建网络监听器NetWork:TcpListenerImpl,同时还将自己注册到全局连接均衡选择器中,用于新连接到达时决定是否执行连接均衡分配策略。
ActiveTcpListener::ActiveTcpListener(Network::TcpConnectionHandler& parent,
Network::ListenerConfig& config, uint32_t worker_index)
: OwnedActiveStreamListenerBase(parent, parent.dispatcher(),
parent.dispatcher().createListener(
config.listenSocketFactory().getListenSocket(worker_index),
*this, config.bindToPort(), config.ignoreGlobalConnLimit()),
config),
tcp_conn_handler_(parent) {
config.connectionBalancer().registerHandler(*this);
}
在dispatcher_impl.cc文件中,createListener方法创建TcpListenerImpl。
Network::ListenerPtr DispatcherImpl::createListener(Network::SocketSharedPtr&& socket,
Network::TcpListenerCallbacks& cb,
bool bind_to_port,
bool ignore_global_conn_limit) {
return std::make_unique<Network::TcpListenerImpl>(
*this, api_.randomGenerator(), std::move(socket), cb, bind_to_port, ignore_global_conn_limit);
}
在tcp_listener_impl.cc文件中,TcpListenerImpl构造方法中调用socket的initializeFileEvent方法向操作系统注册监听器,并设置回调方法onSocketEvent,其中参数中的Event::FileTriggerType::Level表示边沿触发模式,减少网络事件的通知数量,bind_to_port表示是否真正启动网络监听。
TcpListenerImpl::TcpListenerImpl(Event::DispatcherImpl& dispatcher, Random::RandomGenerator& random,
SocketSharedPtr socket, TcpListenerCallbacks& cb,
bool bind_to_port, bool ignore_global_conn_limit)
: BaseListenerImpl(dispatcher, std::move(socket)), cb_(cb), random_(random),
bind_to_port_(bind_to_port), reject_fraction_(0.0),
ignore_global_conn_limit_(ignore_global_conn_limit) {
if (bind_to_port) {
socket_->ioHandle().initializeFileEvent(
dispatcher, [this](uint32_t events) -> void { onSocketEvent(events); },
Event::FileTriggerType::Level, Event::FileReadyType::Read);
}
}
在id_socket_handle_impl.cc文件中,initializeFileEvent方法使用dispatcher的createFileEvent方法向下层libevent库注册socket描述符fd。
void IoSocketHandleImpl::initializeFileEvent(Event::Dispatcher& dispatcher, Event::FileReadyCb cb,
Event::FileTriggerType trigger, uint32_t events) {
file_event_ = dispatcher.createFileEvent(fd_, cb, trigger, events);
}
在dispatcher_impl.cc文件中,createFileEvent方法,当网络事件触发时,将回调cb方法,在此场景中,cb就是onSocketEvent方法,即为tcp_listener_impl.cc文件中的onSocketEvent方法。
FileEventPtr DispatcherImpl::createFileEvent(os_fd_t fd, FileReadyCb cb, FileTriggerType trigger,
uint32_t events) {
return FileEventPtr{new FileEventImpl(
*this, fd,
[this, cb](uint32_t events) {
touchWatchdog(); // 设置当前线程watchdog为正常状态。
cb(events); // 调用回调方法,对于网络监听器场景,cb为onSocketEvent方法。
},
trigger, events)};
}
在file_event_impl.cc文件中,FileEventImpl构造方法调用libevent库接口event_assign、event_add来注册网络监听事件。
FileEventImpl::FileEventImpl(DispatcherImpl& dispatcher, os_fd_t fd, FileReadyCb cb,
FileTriggerType trigger, uint32_t events)
: dispatcher_(dispatcher), cb_(cb), fd_(fd), trigger_(trigger), enabled_events_(events),
activation_cb_(dispatcher.createSchedulableCallback([this]() {
...
assignEvents(events, &dispatcher.base());
event_add(&raw_event_, nullptr);
}
在file_event_impl.cc文件中,进一步看assignEvents方法,事件触发时执行mergeInjectedEventsAndRunCb方法,在合并事件后继续执行注册回调方法。
void FileEventImpl::assignEvents(uint32_t events, event_base* base) {
event_assign(
&raw_event_, base, fd_,
ASSERT(events != 0);
event->mergeInjectedEventsAndRunCb(events);
},
this);
当新连接事件发生时,mergeInjectedEventsAndRunCb方法将回调TcpListenerImpl::onSocketEvent方法,onSocketEvent回调方法将执行系统的accept方法来接收新连接Socket对象,并获取Socket上的本地地址local_address以及远端地址remote_address,然后onSocketEvent方法执行ActiveTcpListener::onAccept回调方法进入新连接接收阶段。
void TcpListenerImpl::onSocketEvent(short flags) {
const Address::InstanceConstSharedPtr& local_address =
local_address_ ? local_address_ : io_handle->localAddress();
const Address::InstanceConstSharedPtr remote_address =
(remote_addr.ss_family == AF_UNIX)
? io_handle->peerAddress()
: Address::addressFromSockAddrOrThrow(remote_addr, remote_addr_len,
local_address->ip()->version() ==
Address::IpVersion::v6);
cb_.onAccept(
std::make_unique<AcceptedSocketImpl>(std::move(io_handle), local_address, remote_address));
}
}
接收连接
当接收到新连接的fd之后,将进入Envoy进程连接接收流程。从上文中可以知道,FileEventImpl中注册了libevent回调,会触发TcpListenerImpl::onSocketEvent,进一步会回调到ActiveTcpListener的onAccept方法。
在active_tcp_listener.cc文件中,onAccept方法首先判断连接数量是否达到阈值,如果达到阈值则直接close socket,同时更新统计指标。
void ActiveTcpListener::onAccept(Network::ConnectionSocketPtr&& socket) {
if (listenerConnectionLimitReached()) {
socket->close();
stats_.downstream_cx_overflow_.inc();
return;
}
onAcceptWorker(std::move(socket), config_->handOffRestoredDestinationConnections(), false);
}
在active_tcp_listener.cc文件中,进一步会调用到ActiveTcpListener::onAcceptWorker方法,该方法进行连接均衡,如果连接均衡决策结果由其他工作线程内的连接处理器ConnectionHandler处理当前连接,则执行post方法将当前线程接收到的连接转移给其他工作线程处理。(注:监听器创建阶段会执行registerHandler,里面涉及到了connectionBalancer,目前有两个实现:NopConnectionBalancer和ExactConnectionBalancer,其中NopConnectionBalancer是默认实现,即不做处理)。
将socket封装为ActiveTcpSocket,继续调用onSocketAccepted方法。
void ActiveTcpListener::onAcceptWorker(Network::ConnectionSocketPtr&& socket,
bool hand_off_restored_destination_connections,
bool rebalanced) {
if (!rebalanced) {
Network::BalancedConnectionHandler& target_handler =
config_->connectionBalancer().pickTargetHandler(*this);
if (&target_handler != this) {
target_handler.post(std::move(socket));
return;
}
}
auto active_socket = std::make_unique<ActiveTcpSocket>(*this, std::move(socket),
hand_off_restored_destination_connections);
onSocketAccepted(std::move(active_socket));
}
在active_tcp_listener.cc文件中,对新连接调用createListenerFilterChain方法,该方法根据监听器的配置config_创建监听过滤器filterChain,并调用continueFilterChain方法执行监听过滤器filterChain内的各个回调方法,处理连接建立过程,如:original_dst监听过滤器等。
void onSocketAccepted(std::unique_ptr<ActiveTcpSocket> active_socket) {
// Create and run the filters
config_->filterChainFactory().createListenerFilterChain(*active_socket);
active_socket->continueFilterChain(true);
...
}
在active_tcp_socket.cc文件中,具体看下continueFilterChain方法是如何调用监听器filterChain的onAccept方法的:
void ActiveTcpSocket::continueFilterChain(bool success) {
if (success) {
for (; iter_ != accept_filters_.end(); iter_++) {
// 当前socket上注册的listenerFilterChain列表,listenerFilterChain需要实现onAccept方法
Network::FilterStatus status = (*iter_)->onAccept(*this);
...
// Successfully ran all the accept filters.
if (no_error) {
newConnection();
} else {
}
在active_tcp_socket.cc文件中,下一步就是调用newConnection创建连接,注意此处已经通过original_dst监听过滤器还原了真实的地址信息,所以创建真实地址的listener进行连接创建。
void ActiveTcpSocket::newConnection() {
// Check if the socket may need to be redirected to another listener.
Network::BalancedConnectionHandlerOptRef new_listener;
if (hand_off_restored_destination_connections_ &&
socket_->connectionInfoProvider().localAddressRestored()) {
// Find a listener associated with the original destination address.
new_listener =
listener_.getBalancedHandlerByAddress(*socket_->connectionInfoProvider().localAddress());
}
if (new_listener.has_value()) {
// Hands off connections redirected by iptables to the listener associated with the
// original destination address. Pass 'hand_off_restored_destination_connections' as false to
// prevent further redirection.
// Leave the new listener to decide whether to execute re-balance.
// Note also that we must account for the number of connections properly across both listeners.
// TODO(mattklein123): See note in ~ActiveTcpSocket() related to making this accounting better.
listener_.decNumConnections();
new_listener.value().get().onAcceptWorker(std::move(socket_), false, false);
} else {
...
// Create a new connection on this listener.
listener_.newConnection(std::move(socket_), std::move(stream_info_));
}
}
此处较为关键,可以看出new_listener第一次被创建出来之后,需要重新根据真实地址信息创建ListenerFilterChain,又重新回调到了ActiveTcpListener:onAcceptWorker进行监听过滤器的创建。最后又会重新进入该方法内的else: listener_.newConnection(std::move(socket_), std::move(stream_info_));在该服务监听器上创建连接。
在active_stream_listener_base.cc文件中,newConnection方法将真正创建连接的对象。
// Find matching filter chain.
const auto filter_chain = config_->filterChainManager().findFilterChain(*socket);
if (filter_chain == nullptr) {
// 若未匹配到L4过滤器,则断开连接
}
...
// (1)建立跟下游的连接(更准确的描述是跟对端的连接)
auto server_conn_ptr = dispatcher().createServerConnection(
std::move(socket), std::move(transport_socket), *stream_info);
// (2)创建四层网络过滤器
const bool empty_filter_chain = !config_->filterChainFactory().createNetworkFilterChain(
*server_conn_ptr, filter_chain->networkFilterFactories());
// (3)将连接跟监听器关联起来,如果监听器配置发生变化,为了保证现有的连接的过滤器同步更新,会重建过滤器。
newActiveConnection(*filter_chain, std::move(server_conn_ptr), std::move(stream_info));
从上面代码片段可以看出newConnection主要3个主要步骤:
(1)createServerConnection方法。创建下游连接对象,在ServerConnectionImpl构造方法中继承了ConnectionImpl,其构造方法中执行initializeFileEvent方法来注册网络IO事件,并设置回调方法onFileEvent,同时注册了write和read相关的buffer。在connection_impl.cc文件中。
ConnectionImpl::ConnectionImpl(Event::Dispatcher& dispatcher, ConnectionSocketPtr&& socket,
TransportSocketPtr&& transport_socket,
StreamInfo::StreamInfo& stream_info, bool connected)
: ConnectionImplBase(dispatcher, next_global_id_++),
write_buffer_(dispatcher.getWatermarkFactory().createBuffer(
[this]() -> void { this->onWriteBufferLowWatermark(); },
[this]() -> void { this->onWriteBufferHighWatermark(); },
[]() -> void { /* TODO(adisuissa): Handle overflow watermark */ })),
read_buffer_(dispatcher.getWatermarkFactory().createBuffer(
[this]() -> void { this->onReadBufferLowWatermark(); },
[this]() -> void { this->onReadBufferHighWatermark(); },
[]() -> void { /* TODO(adisuissa): Handle overflow watermark */ })),
// We never ask for both early close and read at the same time. If we are reading, we want to
// consume all available data.
socket_->ioHandle().initializeFileEvent(
dispatcher_, [this](uint32_t events) -> void { onFileEvent(events); }, trigger,
Event::FileReadyType::Read | Event::FileReadyType::Write);
}
(2) 创建四层过滤器。在listener_impl.cc文件中,createNetworkFilterChain方法用于创建L4网络过滤器,通过Configuration::FilterChainUtility::buildFilterChain -> filter_manager.initializeReadFilters(),最后通过FilterManagerImpl的initializeReadFilter进行读过滤器的初始化。具体是通过调用FilterManagerImpl::onContinueReading()方法实现的。初始化过程通过调用四层过滤器的onNewConnection回调方法。该函数是后续会复用的,对于收到数据时,就调用四层过滤器的onData回调方法。
for (; entry != upstream_filters_.end(); entry++) {
if (!(*entry)->initialized_) {
(*entry)->initialized_ = true;
FilterStatus status = (*entry)->filter_->onNewConnection();
}
StreamBuffer read_buffer = buffer_source.getReadBuffer();
if (read_buffer.buffer.length() > 0 || read_buffer.end_stream) {
FilterStatus status = (*entry)->filter_->onData(read_buffer.buffer, read_buffer.end_stream);
}
}
(3) newActiveConnection方法,将新L4连接对象保存到当前过监听器的上下文中。该方法实际上调用了实现子类active_tcp_listener.cc文件中的newActiveConnection方法。
服务监听器通过newConnection方法同接收的网络连接建立关联关系,当监听器配置(主要就是相关过滤器啥的呗)发生变更时,为了保证新接收的连接和已有连接在过滤器处理路径上保持一致,通常情况下需要通过销毁当前监听器并重新创建监听器的方式实现。此时当前监听器上关联的已有连接将会被延迟关闭(处理完成现有的请求?)。
void ActiveTcpListener::newActiveConnection(const Network::FilterChain& filter_chain,
Network::ServerConnectionPtr server_conn_ptr,
std::unique_ptr<StreamInfo::StreamInfo> stream_info) {
auto& active_connections = getOrCreateActiveConnections(filter_chain);
auto active_connection =
std::make_unique<ActiveTcpConnection>(active_connections, std::move(server_conn_ptr),
dispatcher().timeSource(), std::move(stream_info));
// If the connection is already closed, we can just let this connection immediately die.
if (active_connection->connection_->state() != Network::Connection::State::Closed) {
LinkedList::moveIntoList(std::move(active_connection), active_connections.connections_);
}
}
其中getOrCreateActiveConnections在activce_stream_listener_base.cc文件中,方法中的connections_by_context_散列表将跟踪当前监听器内过滤器处理的所有活跃连接。
ActiveConnections& OwnedActiveStreamListenerBase::getOrCreateActiveConnections(
const Network::FilterChain& filter_chain) {
ActiveConnectionCollectionPtr& connections = connections_by_context_[&filter_chain];
if (connections == nullptr) {
connections = std::make_unique<ActiveConnections>(*this, filter_chain);
}
return *connections;
}
相应的,当监听器配置更新时,将断开所有已建立连接。在active_tcp_listener.cc文件的ActiveTcpListener析构函数中。此处没看懂是怎么延迟释放的,这不是直接close了么??
ActiveTcpListener::~ActiveTcpListener() {
is_deleting_ = true;
config_->connectionBalancer().unregisterHandler(*this);
// Purge sockets that have not progressed to connections. This should only happen when
// a listener filter stops iteration and never resumes.
while (!sockets_.empty()) {
auto removed = sockets_.front()->removeFromList(sockets_);
dispatcher().deferredDelete(std::move(removed));
}
for (auto& [chain, active_connections] : connections_by_context_) {
auto& connections = active_connections->connections_;
while (!connections.empty()) {
connections.front()->connection_->close(Network::ConnectionCloseType::NoFlush);
}
}
dispatcher().clearDeferredDeleteList();
}