特使のソースコード解析--LDS
特使LDSは、自動的にリスナーのAPIを取得するために使用されます。特使は変更またはリスナーを削除し、APIによって増加させることができます。
リスナーの更新セマンティクスを要約するとまず、以下のとおりです。
- 各リスナーには一意の名前を持つ必要があります。名前を指定しない場合、特使は、その名のようにUUIDを生成します。動的にリスナーを更新するには、マネージドサービスは、一意の名前を提供する必要があります。
- リスナーが追加されると、トラフィックを受信する前には、最初の「ウォームアップ」フェーズに入ります。
- リスナーが作成されると、それは変更されません。したがって、リスナーの更新、(リスニングソケット付き)新しいリスナーを作成します。新しく追加されたリスナーも「ウォームアップ」プロセスを必要としています。
- 更新またはリスナーを削除すると、リスナーが同じ状態「(除名)を排出」古いに配置され、サービスが再起動されます。リスナーを削除し、接続の残りの部分の前に閉じて、リスナーは(可能であれば)エレガント近くに任意の期間を接続しています。時間によって放出された
--drain-time-s
設定。 - 同じ名前を持つリスナーは、同じ構成のアドレスを持っている必要があります。
次LDSソースコード解析することで、あなたは、ソースコード内のセマンティックな状況の多様性を見ることができます。
初期化
LDSの設定がある場合は、初期化、ブートストラップコンフィギュレーションでは、初期化されます。
// Instruct the listener manager to create the LDS provider if needed. This must be done later
// because various items do not yet exist when the listener manager is created.
if (bootstrap_.dynamic_resources().has_lds_config()) {
listener_manager_->createLdsApi(bootstrap_.dynamic_resources().lds_config());
}
LDSはListenerManagerImplクラスのProdListenerComponentFactory設定クラスによって作成されました。
// Server::ListenerManager
void createLdsApi(const envoy::api::v2::core::ConfigSource& lds_config) override {
ASSERT(lds_api_ == nullptr);
lds_api_ = factory_.createLdsApi(lds_config);
}
// Server::ListenerComponentFactory
LdsApiPtr createLdsApi(const envoy::api::v2::core::ConfigSource& lds_config) override {
return std::make_unique<LdsApiImpl>(lds_config, server_.clusterManager(), server_.dispatcher(),
server_.random(), server_.initManager(),
server_.localInfo(), server_.stats(),
server_.listenerManager(), server_.api());
}
新しいLDSを作成するとき、それは、チャネルを作成します。
LdsApiImpl::LdsApiImpl(const envoy::api::v2::core::ConfigSource& lds_config,
Upstream::ClusterManager& cm, Event::Dispatcher& dispatcher,
Runtime::RandomGenerator& random, Init::Manager& init_manager,
const LocalInfo::LocalInfo& local_info, Stats::Scope& scope,
ListenerManager& lm, Api::Api& api)
: listener_manager_(lm), scope_(scope.createScope("listener_manager.lds.")), cm_(cm),
init_target_("LDS", [this]() { subscription_->start({}, *this); }) {
//创建 subscription 对象
subscription_ = Envoy::Config::SubscriptionFactory::subscriptionFromConfigSource(
lds_config, local_info, dispatcher, cm, random, *scope_,
"envoy.api.v2.ListenerDiscoveryService.FetchListeners",
"envoy.api.v2.ListenerDiscoveryService.StreamListeners",
Grpc::Common::typeUrl(envoy::api::v2::Listener().GetDescriptor()->full_name()), api);
Config::Utility::checkLocalInfo("lds", local_info);
init_manager.add(init_target_);
}
更新
データがある場合に発行され、チャネルは、コールバックトリガーonConfigUpdateを呼び出します。
// the configuration update targets.
callbacks_->onConfigUpdate(resources, version_info);
リスナーの除去であるかを決定するために更新プロセスを構成する方法?。まず、参加する既存のリスナーの除去のリストを作成し、リスナーによって発行されたデータを削除し、残りの部分は、リスナーを削除します。リスナーが印刷されます削除lds: remove listener '{}'
。
// We build the list of listeners to be removed and remove them before
// adding new listeners. This allows adding a new listener with the same
// address as a listener that is to be removed. Do not change the order.
for (const auto& listener : listener_manager_.listeners()) {
listeners_to_remove.emplace(listener.get().name(), listener);
}
for (const auto& listener : listeners) {
listeners_to_remove.erase(listener.name());
}
for (const auto& listener : listeners_to_remove) {
if (listener_manager_.removeListener(listener.first)) {
ENVOY_LOG(info, "lds: remove listener '{}'", listener.first);
}
}
リスナーはオフ時間の期間にわたって、除名を置くことでアクティブになっている場合、それは、リスナー「ウォームアップ」段階で直接削除されている場合、リスナーを削除するとき。
// Destroy a warming listener directly.
if (existing_warming_listener != warming_listeners_.end()) {
(*existing_warming_listener)->debugLog("removing warming listener");
warming_listeners_.erase(existing_warming_listener);
}
// If there is an active listener it needs to be moved to draining.
if (existing_active_listener != active_listeners_.end()) {
drainListener(std::move(*existing_active_listener));
active_listeners_.erase(existing_active_listener);
}
// ListenerManagerImpl::drainListener
// 关闭accept,不再接收新连接
draining_it->listener_->debugLog("draining listener");
for (const auto& worker : workers_) {
worker->stopListener(*draining_it->listener_);
}
// 等待一段时间
draining_it->listener_->localDrainManager().startDrainSequence([this, draining_it]() -> void {
draining_it->listener_->debugLog("removing listener");
for (const auto& worker : workers_) {
// 移除 listener
worker->removeListener(*draining_it->listener_, [this, draining_it]() -> void {
// 通知主线程(移除是在工作线程移除的,主线程无法知道)
server_.dispatcher().post([this, draining_it]() -> void {
if (--draining_it->workers_pending_removal_ == 0) {
draining_it->listener_->debugLog("listener removal complete");
draining_listeners_.erase(draining_it);
stats_.total_listeners_draining_.set(draining_listeners_.size());
}
});
});
}
});
次の設定を追加または更新中にリスナーがあります。印刷ログリスナーを追加または更新しますlds: add/update listener '{}'
。
for (const auto& listener : listeners) {
const std::string& listener_name = listener.name();
try {
if (listener_manager_.addOrUpdateListener(listener, version_info, true)) {
ENVOY_LOG(info, "lds: add/update listener '{}'", listener_name);
} else {
ENVOY_LOG(debug, "lds: add/update listener '{}' skipped", listener_name);
}
} catch (const EnvoyException& e) {
exception_msgs.push_back(fmt::format("{}: {}", listener_name, e.what()));
}
}
名前のない場合は、特使はUUIDを生成し、リスナーを増やします。あなたはリスナー名を更新しないと、特使は、UUIDを生成し、それは名前で関連付けることができないので、名前を付けずに更新する、新しいとなります。
std::string name;
if (!config.name().empty()) {
name = config.name();
} else {
name = server_.random().uuid();
}
増加または更新リスナーが直接新しい、古いリスナーがありますするかどうか「(除名)を排出。」
ListenerImplPtr new_listener(
new ListenerImpl(config, version_info, *this, name, modifiable, workers_started_, hash));
ListenerImpl& new_listener_ref = *new_listener;
同じ名前のリスナーを分析すると、同じアドレスの設定を持っている必要があります。
if ((existing_warming_listener != warming_listeners_.end() &&
*(*existing_warming_listener)->address() != *new_listener->address()) ||
(existing_active_listener != active_listeners_.end() &&
*(*existing_active_listener)->address() != *new_listener->address())) {
const std::string message = fmt::format(
"error updating listener: '{}' has a different address '{}' from existing listener", name,
new_listener->address()->asString());
ENVOY_LOG(warn, "{}", message);
throw EnvoyException(message);
}
あなたはリスナー「ウォームアップ」フェーズでは、リスナー、内部直接交換を更新した場合。
if (existing_warming_listener != warming_listeners_.end()) {
ASSERT(workers_started_);
new_listener->debugLog("update warming listener");
new_listener->setSocket((*existing_warming_listener)->getSocket());
*existing_warming_listener = std::move(new_listener);
}
活動に更新リスナーリスナーの場合。古いリスナーの後継者が「排出(除名)」状態に置かれる一方で、現在のワーカースレッドは、リスナーの「ウォームアップ」フェーズを追加し、開始されています。現在の状態のワーカースレッドは、内部の直接交換を開始しません。
if (existing_active_listener != active_listeners_.end()) {
new_listener->setSocket((*existing_active_listener)->getSocket());
if (workers_started_) {
new_listener->debugLog("add warming listener");
warming_listeners_.emplace_back(std::move(new_listener));
} else {
new_listener->debugLog("update active listener");
*existing_active_listener = std::move(new_listener);
}
}
あなたはリスナーを追加すると、それは同じアドレスリスナーの既存の状態かどうかを確認するには、「排出(除名)」リスナーに行きますが、同じことが再び引っ張っていて、現在の作業スレッドに応じて、対応するリスナーに参加する準備ができています。
Network::SocketSharedPtr draining_listener_socket;
auto existing_draining_listener = std::find_if(
draining_listeners_.cbegin(), draining_listeners_.cend(),
[&new_listener](const DrainingListener& listener) {
return *new_listener->address() == *listener.listener_->socket().localAddress();
});
if (existing_draining_listener != draining_listeners_.cend()) {
draining_listener_socket = existing_draining_listener->listener_->getSocket();
}
new_listener->setSocket(draining_listener_socket
? draining_listener_socket
: factory_.createListenSocket(new_listener->address(),
new_listener->socketType(),
new_listener->listenSocketOptions(),
new_listener->bindToPort()));
if (workers_started_) {
new_listener->debugLog("add warming listener");
warming_listeners_.emplace_back(std::move(new_listener));
} else {
new_listener->debugLog("add active listener");
active_listeners_.emplace_back(std::move(new_listener));
}
最後に、古いリスナーは「水切り(除名)」状態に置きました。
// 调用 initialize()
new_listener_ref.initialize();
void ListenerImpl::initialize() {
last_updated_ = timeSource().systemTime();
if (workers_started_) {
// init_watcher
dynamic_init_manager_.initialize(*init_watcher_);
}
}
// init_watcher 在构造函数时创建
init_watcher_(std::make_unique<Init::WatcherImpl>(
"ListenerImpl", [this] { parent_.onListenerWarmed(*this); })),
void ListenerManagerImpl::onListenerWarmed(ListenerImpl& listener) {
auto existing_active_listener = getListenerByName(active_listeners_, listener.name());
auto existing_warming_listener = getListenerByName(warming_listeners_, listener.name());
(*existing_warming_listener)->debugLog("warm complete. updating active listener");
if (existing_active_listener != active_listeners_.end()) {
// 旧的 listener 置于 “draining(驱逐)” 状态。
drainListener(std::move(*existing_active_listener));
// 预热的 listener 放到活动的 listener
*existing_active_listener = std::move(*existing_warming_listener);
} else {
active_listeners_.emplace_back(std::move(*existing_warming_listener));
}
}