Envoy源碼分析之一--Server初始化

代碼版本:stable/v1.7.1
這里結(jié)合資料及源碼僅分析正常場景的主干流程项玛。本系列博文分為四部分新娜,Server初始化推穷,Envoy啟動與新連接建立僧著,Envoy對數(shù)據(jù)的讀取履因、接收和處理,Envoy數(shù)據(jù)轉(zhuǎn)發(fā)到服務(wù)端盹愚。
本章介紹第一部分栅迄,Server的初始化,主要分為兩部分皆怕,一是Envoy進程起來后的入口函數(shù)毅舆、二是Server的初始化。

1. 入口

入口在source/exe/main.cc中


main

聲明并初始化Envoy::MainCommon實例為main_common愈腾,執(zhí)行main_common->run啟動Server憋活。

2. Envoy::MainCommon

main_common.h中Envoy::MainCommon class如下:


class MainCommon

MainCommonBase的實例對象執(zhí)行run函數(shù)。

3. Envoy::MainCommonBase

頭文件中類定義如下:


class MainCommonBase

class MainCommonBase函數(shù)實現(xiàn)方放在main_common.cc中如下:
Envoy::MainCommonBase constructor:

MainCommonBase::MainCommonBase(OptionsImpl& options) : options_(options) {
  ares_library_init(ARES_LIB_INIT_ALL);
  Event::Libevent::Global::initialize();
  RELEASE_ASSERT(Envoy::Server::validateProtoDescriptors());

  Stats::RawStatData::configure(options_);
  switch (options_.mode()) {
  case Server::Mode::InitOnly:
  case Server::Mode::Serve: {
#ifdef ENVOY_HOT_RESTART
    if (!options.hotRestartDisabled()) {
      restarter_.reset(new Server::HotRestartImpl(options_));
    }
#endif
    if (restarter_.get() == nullptr) {
      restarter_.reset(new Server::HotRestartNopImpl());
    }

    tls_.reset(new ThreadLocal::InstanceImpl);
    Thread::BasicLockable& log_lock = restarter_->logLock();
    Thread::BasicLockable& access_log_lock = restarter_->accessLogLock();
    auto local_address = Network::Utility::getLocalAddress(options_.localAddressIpVersion());
    Logger::Registry::initialize(options_.logLevel(), options_.logFormat(), log_lock);

    stats_store_.reset(new Stats::ThreadLocalStoreImpl(restarter_->statsAllocator()));
    server_.reset(new Server::InstanceImpl(
        options_, local_address, default_test_hooks_, *restarter_, *stats_store_, access_log_lock,
        component_factory_, std::make_unique<Runtime::RandomGeneratorImpl>(), *tls_));
    break;
  }
  case Server::Mode::Validate:
    restarter_.reset(new Server::HotRestartNopImpl());
    Logger::Registry::initialize(options_.logLevel(), options_.logFormat(), restarter_->logLock());
    break;
  }
}

在上述構(gòu)造函數(shù)體中虱黄,初始化server

    server_.reset(new Server::InstanceImpl(
        options_, local_address, default_test_hooks_, *restarter_, *stats_store_, access_log_lock,
        component_factory_, std::make_unique<Runtime::RandomGeneratorImpl>(), *tls_));
4. Server::InstanceImpl

Server.h定義InstanceImpl類:


class InstanceImpl

server.cc中實現(xiàn)其構(gòu)造函數(shù)

InstanceImpl::InstanceImpl(Options& options, Network::Address::InstanceConstSharedPtr local_address,
                           TestHooks& hooks, HotRestart& restarter, Stats::StoreRoot& store,
                           Thread::BasicLockable& access_log_lock,
                           ComponentFactory& component_factory,
                           Runtime::RandomGeneratorPtr&& random_generator,
                           ThreadLocal::Instance& tls)
    : options_(options), restarter_(restarter), start_time_(time(nullptr)),
      original_start_time_(start_time_), stats_store_(store), thread_local_(tls),
      api_(new Api::Impl(options.fileFlushIntervalMsec())), dispatcher_(api_->allocateDispatcher()),
      singleton_manager_(new Singleton::ManagerImpl()),
      handler_(new ConnectionHandlerImpl(ENVOY_LOGGER(), *dispatcher_)),
      random_generator_(std::move(random_generator)), listener_component_factory_(*this),
      worker_factory_(thread_local_, *api_, hooks),
      secret_manager_(new Secret::SecretManagerImpl()),
      dns_resolver_(dispatcher_->createDnsResolver({})),
      access_log_manager_(*api_, *dispatcher_, access_log_lock, store), terminated_(false) {

  try {
    if (!options.logPath().empty()) {
      try {
        file_logger_ = std::make_unique<Logger::FileSinkDelegate>(
            options.logPath(), access_log_manager_, Logger::Registry::getSink());
      } catch (const EnvoyException& e) {
        throw EnvoyException(
            fmt::format("Failed to open log-file '{}'. e.what(): {}", options.logPath(), e.what()));
      }
    }

    restarter_.initialize(*dispatcher_, *this);
    drain_manager_ = component_factory.createDrainManager(*this);
    initialize(options, local_address, component_factory);
  } catch (const EnvoyException& e) {
    ENVOY_LOG(critical, "error initializing configuration '{}': {}", options.configPath(),
              e.what());

    terminate();
    throw;
  }
}

其中Server初始化在initialize(options, local_address, component_factory);中進行悦即。
配置文件從InstanceUtil::loadBootstrapConfig中獲取,放到&options中去橱乱。

5. Server初始化

回到3和4中
初始化server是在上述構(gòu)造函數(shù)體中的initialize中完成的辜梳,

    server_.reset(new Server::InstanceImpl(
        options_, local_address, default_test_hooks_, *restarter_, *stats_store_, access_log_lock,
        component_factory_, std::make_unique<Runtime::RandomGeneratorImpl>(), *tls_));

這部分,這部分完成以下部分的server初始化泳叠。


Server Initialize
5.1 bootstrap

在InstanceImpl::initialize中作瞄,

 // Handle configuration that needs to take place prior to the main configuration load.
  InstanceUtil::loadBootstrapConfig(bootstrap_, options);
InstanceUtil::loadBootstrapConfig(envoy::config::bootstrap::v2::Bootstrap& bootstrap,
                                  Options& options) {
  try {
    if (!options.configPath().empty()) {
      MessageUtil::loadFromFile(options.configPath(), bootstrap);
    }
    if (!options.configYaml().empty()) {
      envoy::config::bootstrap::v2::Bootstrap bootstrap_override;
      MessageUtil::loadFromYaml(options.configYaml(), bootstrap_override);
      bootstrap.MergeFrom(bootstrap_override);
    }
    MessageUtil::validate(bootstrap);
    return BootstrapVersion::V2;
  } catch (const EnvoyException& e) {
    if (options.v2ConfigOnly()) {
      throw;
    }
    // TODO(htuch): When v1 is deprecated, make this a warning encouraging config upgrade.
    ENVOY_LOG(debug, "Unable to initialize config as v2, will retry as v1: {}", e.what());
  }
  if (!options.configYaml().empty()) {
    throw EnvoyException("V1 config (detected) with --config-yaml is not supported");
  }
  Json::ObjectSharedPtr config_json = Json::Factory::loadFromFile(options.configPath());
  Config::BootstrapJson::translateBootstrap(*config_json, bootstrap);
  MessageUtil::validate(bootstrap);
  return BootstrapVersion::V1;
}

從loadBootstrapConfig函數(shù)可知,通過loadFromFile和loadFromYaml讀取配置文件路徑下的配置危纫,并完成參數(shù)校驗粉洼。


configLoad

5.2 admin API 初始化
admin初始化通過AdminImpl()實現(xiàn)


admin init

AdminImpl其入?yún)ⅲ琲nitial_config為Configuration::InitialImpl類型叶摄,將5.1中獲取的配置文件生成結(jié)構(gòu)化數(shù)據(jù)對象initial_config属韧,并在初始化admin的時候?qū)⑵湎嚓P(guān)參數(shù)取出使用。

Configuration::InitialImpl initial_config(bootstrap_);

這部分5.1的內(nèi)容inital_config蓋過不提蛤吓,AdminImp()函數(shù)實現(xiàn)在admin.cc中宵喂,

AdminImpl::AdminImpl(const std::string& access_log_path, const std::string& profile_path,
                     const std::string& address_out_path,
                     Network::Address::InstanceConstSharedPtr address, Server::Instance& server,
                     Stats::ScopePtr&& listener_scope)
    : server_(server), profile_path_(profile_path),
      socket_(new Network::TcpListenSocket(address, nullptr, true)),
      stats_(Http::ConnectionManagerImpl::generateStats("http.admin.", server_.stats())),
      tracing_stats_(
          Http::ConnectionManagerImpl::generateTracingStats("http.admin.", no_op_store_)),
      handlers_{
          {"/", "Admin home page", MAKE_ADMIN_HANDLER(handlerAdminHome), false, false},
          {"/certs", "print certs on machine", MAKE_ADMIN_HANDLER(handlerCerts), false, false},
          {"/clusters", "upstream cluster status", MAKE_ADMIN_HANDLER(handlerClusters), false,
           false},
          {"/config_dump", "dump current Envoy configs (experimental)",
           MAKE_ADMIN_HANDLER(handlerConfigDump), false, false},
          {"/cpuprofiler", "enable/disable the CPU profiler",
           MAKE_ADMIN_HANDLER(handlerCpuProfiler), false, true},
          {"/healthcheck/fail", "cause the server to fail health checks",
           MAKE_ADMIN_HANDLER(handlerHealthcheckFail), false, true},
          {"/healthcheck/ok", "cause the server to pass health checks",
           MAKE_ADMIN_HANDLER(handlerHealthcheckOk), false, true},
          {"/help", "print out list of admin commands", MAKE_ADMIN_HANDLER(handlerHelp), false,
           false},
          {"/hot_restart_version", "print the hot restart compatibility version",
           MAKE_ADMIN_HANDLER(handlerHotRestartVersion), false, false},
          {"/logging", "query/change logging levels", MAKE_ADMIN_HANDLER(handlerLogging), false,
           true},
          {"/quitquitquit", "exit the server", MAKE_ADMIN_HANDLER(handlerQuitQuitQuit), false,
           true},
          {"/reset_counters", "reset all counters to zero",
           MAKE_ADMIN_HANDLER(handlerResetCounters), false, true},
          {"/server_info", "print server version/status information",
           MAKE_ADMIN_HANDLER(handlerServerInfo), false, false},
          {"/stats", "print server stats", MAKE_ADMIN_HANDLER(handlerStats), false, false},
          {"/stats/prometheus", "print server stats in prometheus format",
           MAKE_ADMIN_HANDLER(handlerPrometheusStats), false, false},
          {"/listeners", "print listener addresses", MAKE_ADMIN_HANDLER(handlerListenerInfo), false,
           false},
          {"/runtime", "print runtime values", MAKE_ADMIN_HANDLER(handlerRuntime), false, false},
          {"/runtime_modify", "modify runtime values", MAKE_ADMIN_HANDLER(handlerRuntimeModify),
           false, true},
      },

      // TODO(jsedgwick) add /runtime_reset endpoint that removes all admin-set values
      listener_(*this, std::move(listener_scope)),
      admin_filter_chain_(std::make_shared<AdminFilterChain>()) {
   //函數(shù)體從這里開始
  if (!address_out_path.empty()) {
    std::ofstream address_out_file(address_out_path);
    if (!address_out_file) {
      ENVOY_LOG(critical, "cannot open admin address output file {} for writing.",
                address_out_path);
    } else {
      address_out_file << socket_->localAddress()->asString();
    }
  }

  // TODO(mattklein123): Allow admin to use normal access logger extension loading and avoid the
  // hard dependency here.
  access_logs_.emplace_back(new Extensions::AccessLoggers::File::FileAccessLog(
      access_log_path, {}, AccessLog::AccessLogFormatUtils::defaultAccessLogFormatter(),
      server.accessLogManager()));
}

從這里看,Admin API的功能是為管理員提供API管理Envoy会傲。其中handlers_中提供了/certs锅棕、/clusters等API拙泽,以如下格式提供,

 {"/config_dump", "dump current Envoy configs (experimental)",
           MAKE_ADMIN_HANDLER(handlerConfigDump), false, false},

上面的字段對應(yīng)的結(jié)構(gòu)體為

  struct UrlHandler {
    const std::string prefix_;
    const std::string help_text_;
    const HandlerCb handler_;
    const bool removable_;
    const bool mutates_server_state_;
  };

在handler_對應(yīng)的MAKE_ADMIN_HANDLER部分裸燎,對應(yīng)的宏定義在server/admin.h中

/**
 * This macro is used to add handlers to the Admin HTTP Endpoint. It builds
 * a callback that executes X when the specified admin handler is hit. This macro can be
 * used to add static handlers as in source/server/http/admin.cc and also dynamic handlers as
 * done in the RouteConfigProviderManagerImpl constructor in source/common/router/rds_impl.cc.
 */
#define MAKE_ADMIN_HANDLER(X)                                                                      \
  [this](absl::string_view path_and_query, Http::HeaderMap& response_headers,                      \
         Buffer::Instance& data, AdminStream& admin_stream) -> Http::Code {                        \
    return X(path_and_query, response_headers, data, admin_stream);                                \
  }

這里顾瞻,如果UrlHandler 的prefix字段和請求輸入的prefix字段一致,就會執(zhí)行X(path_and_query, response_headers, data, admin_stream)德绿,例如請求的是/config_dumps荷荤,則對應(yīng)上上面/config_dumps那組結(jié)構(gòu)體,那么handlerConfigDump被調(diào)用移稳,進行相關(guān)解析蕴纳,如果返回Http::Code:OK,則代表執(zhí)行成功。具體每個handler函數(shù)內(nèi)部的實現(xiàn)个粱,這次不再分析古毛,放到以后的博文里更新。

5.3 Woker的初始化

Worker的初始化是Server初始化中的一個重要環(huán)境都许,由initialize中的如下代碼進行初始化稻薇。

 // Workers get created first so they register for thread local updates.
  listener_manager_.reset(
      new ListenerManagerImpl(*this, listener_component_factory_, worker_factory_));

在listener_manager_impl.cc中的ListenerManagerImpl構(gòu)造函數(shù)中實現(xiàn)wokrer的創(chuàng)建如下:

ListenerManagerImpl::ListenerManagerImpl(Instance& server,
                                         ListenerComponentFactory& listener_factory,
                                         WorkerFactory& worker_factory)
    : server_(server), factory_(listener_factory), stats_(generateStats(server.stats())),
      config_tracker_entry_(server.admin().getConfigTracker().add(
          "listeners", [this] { return dumpListenerConfigs(); })) {
  for (uint32_t i = 0; i < std::max(1U, server.options().concurrency()); i++) {
    workers_.emplace_back(worker_factory.createWorker());
  }
}

調(diào)用stl的emplace_back給workers List增加新的若干worker,每個woker由createWorker去實現(xiàn)胶征,createWorker在worker_impl.cc中代碼如下:

WorkerPtr ProdWorkerFactory::createWorker() {
  Event::DispatcherPtr dispatcher(api_.allocateDispatcher());
  return WorkerPtr{new WorkerImpl(
      tls_, hooks_, std::move(dispatcher),
      Network::ConnectionHandlerPtr{new ConnectionHandlerImpl(ENVOY_LOGGER(), *dispatcher)})};
}

WorkerImpl::WorkerImpl(ThreadLocal::Instance& tls, TestHooks& hooks,
                       Event::DispatcherPtr&& dispatcher, Network::ConnectionHandlerPtr handler)
    : tls_(tls), hooks_(hooks), dispatcher_(std::move(dispatcher)), handler_(std::move(handler)) {
  tls_.registerThread(*dispatcher_, false);
}

在createWorker中塞椎,初始化dispatcher時,調(diào)用api_.allocateDispatcher()獲取Event::DispatcherImpl實例弧烤,

Event::DispatcherPtr Impl::allocateDispatcher() {
  return Event::DispatcherPtr{new Event::DispatcherImpl()};
}

在DispatcherImpl的構(gòu)造函數(shù)中忱屑,開了Buffer去管理Watermark,關(guān)于watermark和callback的機制(Envoy的內(nèi)存管理)后續(xù)會單獨有博文暇昂,這里簡單提一下莺戒,這種機制主要是提供作為proxy的envoy在代理client和server間數(shù)據(jù)緩沖如何處理的能力。這里可以嘗試搞一些數(shù)據(jù)面的性能優(yōu)化急波,把Istio-proxy(envoy)的內(nèi)存消耗設(shè)法降一降从铲。DispatcherImpl構(gòu)造函數(shù)代碼如下:

DispatcherImpl::DispatcherImpl()
    : DispatcherImpl(Buffer::WatermarkFactoryPtr{new Buffer::WatermarkBufferFactory}) {
  // The dispatcher won't work as expected if libevent hasn't been configured to use threads.
  RELEASE_ASSERT(Libevent::Global::initialized());
}

DispatcherImpl::DispatcherImpl(Buffer::WatermarkFactoryPtr&& factory)
    : buffer_factory_(std::move(factory)), base_(event_base_new()),
      deferred_delete_timer_(createTimer([this]() -> void { clearDeferredDeleteList(); })),
      post_timer_(createTimer([this]() -> void { runPostCallbacks(); })),
      current_to_delete_(&to_delete_1_) {
  RELEASE_ASSERT(Libevent::Global::initialized());
}

可以看到,調(diào)用了DispatcherImpl方法澄暮,將Buffer::WatermarkFactoryPtr{new Buffer::WatermarkBufferFactory}作為入?yún)⒄{(diào)用下面帶有入?yún)⒌某跏蓟瘮?shù)名段。其中,Buffer::WatermarkFactoryPtr和Buffer::WatermarkBufferFactory的代碼實現(xiàn)如下:
Buffer::WatermarkFactoryPtr:

class WatermarkFactory {
public:
  virtual ~WatermarkFactory() {}

  /**
   * Creates and returns a unique pointer to a new buffer.
   * @param below_low_watermark supplies a function to call if the buffer goes under a configured
   *   low watermark.
   * @param above_high_watermark supplies a function to call if the buffer goes over a configured
   *   high watermark.
   * @return a newly created InstancePtr.
   */
  virtual InstancePtr create(std::function<void()> below_low_watermark,
                             std::function<void()> above_high_watermark) PURE;
};

typedef std::unique_ptr<WatermarkFactory> WatermarkFactoryPtr;

Buffer:WaterBufferFactory:

class WatermarkBufferFactory : public WatermarkFactory {
public:
  // Buffer::WatermarkFactory
  InstancePtr create(std::function<void()> below_low_watermark,
                     std::function<void()> above_high_watermark) override {
    return InstancePtr{new WatermarkBuffer(below_low_watermark, above_high_watermark)};
  }
};

可以看出泣懊,WatermarkBufferFactory 繼承了WatermarkFactory伸辟,而WatermarkFactoryPtr獨享了WatermarkFactory的實例地址♀晒危回到最終的函數(shù)調(diào)用

DispatcherImpl::DispatcherImpl(Buffer::WatermarkFactoryPtr&& factory)
    : buffer_factory_(std::move(factory)), base_(event_base_new()),
      deferred_delete_timer_(createTimer([this]() -> void { clearDeferredDeleteList(); })),
      post_timer_(createTimer([this]() -> void { runPostCallbacks(); })),
      current_to_delete_(&to_delete_1_) {
  RELEASE_ASSERT(Libevent::Global::initialized());

這里的實現(xiàn)很簡單:在初始化列表中將上述提到的那個智能指針賦值給一個指向WatermarkBufferFactory 實例類型的unique_tr( Buffer::WatermarkFactoryPtr buffer_factory_;)智能指針buffer_factory_信夫,而這個buffer_factory智能指針,是DispatcherImpl類的私有成員變量,看下這個類的定義静稻,


DispatcherImpl

這個類是Event::Dispatcher的libevent implementation
至此警没,本節(jié)開頭的 listener_manager_.reset函數(shù)就完成了worker的初始化工作。

5.4 Cluster Discover Sevice(CDS)的初始化

初始化完成了worker振湾,回到initialize函數(shù)中杀迹,繼續(xù)向下,CDS的初始化押搪,

  cluster_manager_factory_.reset(new Upstream::ProdClusterManagerFactory(
      runtime(), stats(), threadLocal(), random(), dnsResolver(), sslContextManager(), dispatcher(),
      localInfo(), secretManager()));

  // Now the configuration gets parsed. The configuration may start setting thread local data
  // per above. See MainImpl::initialize() for why we do this pointer dance.
  Configuration::MainImpl* main_config = new Configuration::MainImpl();
  config_.reset(main_config);
  main_config->initialize(bootstrap_, *this, *cluster_manager_factory_);

cluster_manager_factory聲明是一個指向Upstream::ClusterManagerFactory的unique_ptr類型指針搞坝,通過reset操作take ownership of reset里面的unique_ptr指針统刮,詳見# std::[unique_ptr]::reset头滔。

Reset pointer
Destroys the object currently managed by the unique_ptr (if any) and takes ownership of p.
If p is a null pointer (such as a default-initialized pointer), the unique_ptr becomes empty, managing no object after the call.
To release the ownership of the stored pointer without destroying it, use member function release instead.

那么cluster_manager_factory接管的ProdClusterManagerFactory對象是誰呢辣苏?這是一個ClusterManagerFactory的工廠模式的實現(xiàn)及穗,代碼如下:

/**
 * Production implementation of ClusterManagerFactory.
 */
class ProdClusterManagerFactory : public ClusterManagerFactory {
public:
  ProdClusterManagerFactory(Runtime::Loader& runtime, Stats::Store& stats,
                            ThreadLocal::Instance& tls, Runtime::RandomGenerator& random,
                            Network::DnsResolverSharedPtr dns_resolver,
                            Ssl::ContextManager& ssl_context_manager,
                            Event::Dispatcher& main_thread_dispatcher,
                            const LocalInfo::LocalInfo& local_info,
                            Secret::SecretManager& secret_manager)
      : main_thread_dispatcher_(main_thread_dispatcher), runtime_(runtime), stats_(stats),
        tls_(tls), random_(random), dns_resolver_(dns_resolver),
        ssl_context_manager_(ssl_context_manager), local_info_(local_info),
        secret_manager_(secret_manager) {}

  // Upstream::ClusterManagerFactory
  ClusterManagerPtr
  clusterManagerFromProto(const envoy::config::bootstrap::v2::Bootstrap& bootstrap,
                          Stats::Store& stats, ThreadLocal::Instance& tls, Runtime::Loader& runtime,
                          Runtime::RandomGenerator& random, const LocalInfo::LocalInfo& local_info,
                          AccessLog::AccessLogManager& log_manager, Server::Admin& admin) override;
  Http::ConnectionPool::InstancePtr
  allocateConnPool(Event::Dispatcher& dispatcher, HostConstSharedPtr host,
                   ResourcePriority priority, Http::Protocol protocol,
                   const Network::ConnectionSocket::OptionsSharedPtr& options) override;
  ClusterSharedPtr clusterFromProto(const envoy::api::v2::Cluster& cluster, ClusterManager& cm,
                                    Outlier::EventLoggerSharedPtr outlier_event_logger,
                                    bool added_via_api) override;
  CdsApiPtr createCds(const envoy::api::v2::core::ConfigSource& cds_config,
                      const absl::optional<envoy::api::v2::core::ConfigSource>& eds_config,
                      ClusterManager& cm) override;
  Secret::SecretManager& secretManager() override { return secret_manager_; }

protected:
  Event::Dispatcher& main_thread_dispatcher_;

private:
  Runtime::Loader& runtime_;
  Stats::Store& stats_;
  ThreadLocal::Instance& tls_;
  Runtime::RandomGenerator& random_;
  Network::DnsResolverSharedPtr dns_resolver_;
  Ssl::ContextManager& ssl_context_manager_;
  const LocalInfo::LocalInfo& local_info_;
  Secret::SecretManager& secret_manager_;
};

之后初始化main_config摧茴,在main_config->initialize中初始化CDS,其實現(xiàn)在configuration_impl.cc中實現(xiàn)埂陆。initialize的核心代碼段如下

  cluster_manager_ = cluster_manager_factory.clusterManagerFromProto(
      bootstrap, server.stats(), server.threadLocal(), server.runtime(), server.random(),
      server.localInfo(), server.accessLogManager(), server.admin());

clusterManagerFromProto的實現(xiàn)在cluster_manager_impl.cc中

ClusterManagerPtr ProdClusterManagerFactory::clusterManagerFromProto(
    const envoy::config::bootstrap::v2::Bootstrap& bootstrap, Stats::Store& stats,
    ThreadLocal::Instance& tls, Runtime::Loader& runtime, Runtime::RandomGenerator& random,
    const LocalInfo::LocalInfo& local_info, AccessLog::AccessLogManager& log_manager,
    Server::Admin& admin) {
  return ClusterManagerPtr{new ClusterManagerImpl(bootstrap, *this, stats, tls, runtime, random,
                                                  local_info, log_manager, main_thread_dispatcher_,
                                                  admin)};
}

在一串初始化列表之后苛白,返回了一個ClusterManagerImpl對象,這個對象的實現(xiàn)也在cluster_manager_impl.cc中焚虱,其中創(chuàng)建cds的核心代碼如下,當(dāng)從bootstrap中獲取到cds的configuration后购裙,就開始進行cds的創(chuàng)建操作。

cds_api_ = factory_.createCds(bootstrap.dynamic_resources().cds_config(), eds_config_, *this);
    init_helper_.setCds(cds_api_.get());

createCds實現(xiàn)

CdsApiPtr ProdClusterManagerFactory::createCds(
    const envoy::api::v2::core::ConfigSource& cds_config,
    const absl::optional<envoy::api::v2::core::ConfigSource>& eds_config, ClusterManager& cm) {
  return CdsApiImpl::create(cds_config, eds_config, cm, main_thread_dispatcher_, random_,
                            local_info_, stats_);
}

拿到了配置文件鹃栽,在cds_api_impl.cc中實現(xiàn)CdsApiImpl::create如下躏率,返回一個CdsApiImpl對象,在這個對象的構(gòu)造函數(shù)中民鼓,注冊了subscription薇芝,每當(dāng)有事件更新時,都會通過subscriptionCallback注冊回調(diào)丰嘉,執(zhí)行cdsApiImpl::onConfigUpdate(),通過ClusterManager實現(xiàn)addOrUpdateCluster或者removeCluster()并且在Envoy日志中打印關(guān)于cluster更新操作的日志夯到。

CdsApiPtr CdsApiImpl::create(const envoy::api::v2::core::ConfigSource& cds_config,
                             const absl::optional<envoy::api::v2::core::ConfigSource>& eds_config,
                             ClusterManager& cm, Event::Dispatcher& dispatcher,
                             Runtime::RandomGenerator& random,
                             const LocalInfo::LocalInfo& local_info, Stats::Scope& scope) {
  return CdsApiPtr{
      new CdsApiImpl(cds_config, eds_config, cm, dispatcher, random, local_info, scope)};
}

CdsApiImpl::CdsApiImpl(const envoy::api::v2::core::ConfigSource& cds_config,
                       const absl::optional<envoy::api::v2::core::ConfigSource>& eds_config,
                       ClusterManager& cm, Event::Dispatcher& dispatcher,
                       Runtime::RandomGenerator& random, const LocalInfo::LocalInfo& local_info,
                       Stats::Scope& scope)
    : cm_(cm), scope_(scope.createScope("cluster_manager.cds.")) {
  Config::Utility::checkLocalInfo("cds", local_info);

  subscription_ =
      Config::SubscriptionFactory::subscriptionFromConfigSource<envoy::api::v2::Cluster>(
          cds_config, local_info.node(), dispatcher, cm, random, *scope_,
          [this, &cds_config, &eds_config, &cm, &dispatcher, &random,
           &local_info]() -> Config::Subscription<envoy::api::v2::Cluster>* {
            return new CdsSubscription(Config::Utility::generateStats(*scope_), cds_config,
                                       eds_config, cm, dispatcher, random, local_info);
          },
          "envoy.api.v2.ClusterDiscoveryService.FetchClusters",
          "envoy.api.v2.ClusterDiscoveryService.StreamClusters");
}

5.5 Listener Discover Service(LDS)的初始化

Lds初始化和cds類似,流程在Cds初始化之后饮亏,核心代碼如下:
創(chuàng)建:

listener_manager_->createLdsApi(bootstrap_.dynamic_resources().lds_config());

createLdsApi:

  void createLdsApi(const envoy::api::v2::core::ConfigSource& lds_config) override {
    ASSERT(lds_api_ == nullptr);
    lds_api_ = factory_.createLdsApi(lds_config);
  }

factory_.createLdsApi

  // 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());
  }

lds_api.cc中LdsApiImpl的構(gòu)造函數(shù)耍贾,其中注冊subscription,當(dāng)有更新事件通過subscriptionCallbacks回調(diào)路幸,用LdsApiImpl::onConfigUpdate實現(xiàn)ListenerManager的addOrUpdateListener或者removeListener()荐开,并在Envoy日志中打印記錄

監(jiān)聽的是什么listener?

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)
    : listener_manager_(lm), scope_(scope.createScope("listener_manager.lds.")), cm_(cm) {
  subscription_ =
      Envoy::Config::SubscriptionFactory::subscriptionFromConfigSource<envoy::api::v2::Listener>(
          lds_config, local_info.node(), dispatcher, cm, random, *scope_,
          [this, &lds_config, &cm, &dispatcher, &random,
           &local_info]() -> Config::Subscription<envoy::api::v2::Listener>* {
            return new LdsSubscription(Config::Utility::generateStats(*scope_), lds_config, cm,
                                       dispatcher, random, local_info);
          },
          "envoy.api.v2.ListenerDiscoveryService.FetchListeners",
          "envoy.api.v2.ListenerDiscoveryService.StreamListeners");
  Config::Utility::checkLocalInfo("lds", local_info);
  init_manager.registerTarget(*this);
}
5.6 GuardDog的初始化

GuardDog用于防止死鎖

guard_dog_.reset(
      new Server::GuardDogImpl(stats_store_, *config_, ProdMonotonicTimeSource::instance_));

至此简肴,Server初始化完成晃听,下篇文章分析 Envoy是如何啟動并建立新連接的。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市杂伟,隨后出現(xiàn)的幾起案子移层,更是在濱河造成了極大的恐慌,老刑警劉巖赫粥,帶你破解...
    沈念sama閱讀 222,000評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件观话,死亡現(xiàn)場離奇詭異,居然都是意外死亡越平,警方通過查閱死者的電腦和手機频蛔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來秦叛,“玉大人晦溪,你說我怎么就攤上這事≌醢希” “怎么了三圆?”我有些...
    開封第一講書人閱讀 168,561評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長避咆。 經(jīng)常有香客問我舟肉,道長,這世上最難降的妖魔是什么查库? 我笑而不...
    開封第一講書人閱讀 59,782評論 1 298
  • 正文 為了忘掉前任路媚,我火速辦了婚禮,結(jié)果婚禮上樊销,老公的妹妹穿的比我還像新娘整慎。我一直安慰自己,他們只是感情好围苫,可當(dāng)我...
    茶點故事閱讀 68,798評論 6 397
  • 文/花漫 我一把揭開白布裤园。 她就那樣靜靜地躺著,像睡著了一般够吩。 火紅的嫁衣襯著肌膚如雪比然。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,394評論 1 310
  • 那天周循,我揣著相機與錄音强法,去河邊找鬼。 笑死湾笛,一個胖子當(dāng)著我的面吹牛饮怯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播嚎研,決...
    沈念sama閱讀 40,952評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼蓖墅,長吁一口氣:“原來是場噩夢啊……” “哼库倘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起论矾,我...
    開封第一講書人閱讀 39,852評論 0 276
  • 序言:老撾萬榮一對情侶失蹤教翩,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后贪壳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體饱亿,經(jīng)...
    沈念sama閱讀 46,409評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,483評論 3 341
  • 正文 我和宋清朗相戀三年闰靴,在試婚紗的時候發(fā)現(xiàn)自己被綠了彪笼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,615評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡蚂且,死狀恐怖配猫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情杏死,我是刑警寧澤泵肄,帶...
    沈念sama閱讀 36,303評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站识埋,受9級特大地震影響凡伊,放射性物質(zhì)發(fā)生泄漏零渐。R本人自食惡果不足惜窒舟,卻給世界環(huán)境...
    茶點故事閱讀 41,979評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望诵盼。 院中可真熱鬧惠豺,春花似錦、人聲如沸风宁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽戒财。三九已至热监,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間饮寞,已是汗流浹背孝扛。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留幽崩,地道東北人苦始。 一個月前我還...
    沈念sama閱讀 49,041評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像慌申,于是被迫代替她去往敵國和親陌选。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,630評論 2 359

推薦閱讀更多精彩內(nèi)容