Fast DDS之Discovery

转载于: https://blog.csdn.net/u010378559/article/details/133064758?spm=1001.2014.3001.5502
谢谢!!

目录

Fast DDS提供了可以跨DomainParticipants主动发现和匹配DataWriters和DataReaders来共享数据的机制。

内置协议

BuiltinProtocols类是内置协议的主要处理器。BuiltinProtocols包括以下主要数据:

//协议属性字段
BuiltinAttributes m_att;
//服务发现的PDP对象
PDP* mp_PDP;
//WriterLiveness 对象,用于心跳保活
WLP* mp_WLP;
//!Pointer to the TypeLookupManager
fastdds::dds::builtin::TypeLookupManager* tlm_;
//!Locator list for metatraffic
LocatorList_t m_metatrafficMulticastLocatorList;
//!Locator List for metatraffic unicast
LocatorList_t m_metatrafficUnicastLocatorList;
//! Initial peers
LocatorList_t m_initialPeersList;
//! Known discovery and backup server container
std::list<eprosima::fastdds::rtps::RemoteServerAttributes> m_DiscoveryServers;

BuiltinAttributes类用于配置BuiltinProtocols所需要的内容,主要有以下字段:

DiscoverySettings discovery_config;

//是否使用保活协议(WriterLiveliness protocol)
bool use_WriterLivelinessProtocol = true;

//! TypeLookup Service settings
TypeLookupSettings typelookup_config;

//单播地址,这个默认是7410,0.0.0.0,它的作用是什么?
LocatorList_t metatrafficUnicastLocatorList;

//组播地址,默认为7400,239.255.0.1
LocatorList_t metatrafficMulticastLocatorList;

//! The collection of external locators to use for communication on metatraffic topics.
fastdds::rtps::ExternalLocators metatraffic_external_unicast_locators;

//! Initial peers.
LocatorList_t initialPeersList;

//! Memory policy for builtin readers
MemoryManagementPolicy_t readerHistoryMemoryPolicy =
MemoryManagementPolicy_t::PREALLOCATED_WITH_REALLOC_MEMORY_MODE;

//! Maximum payload size for builtin readers
uint32_t readerPayloadSize = BUILTIN_DATA_MAX_SIZE;

//! Memory policy for builtin writers
MemoryManagementPolicy_t writerHistoryMemoryPolicy =
MemoryManagementPolicy_t::PREALLOCATED_WITH_REALLOC_MEMORY_MODE;

//! Maximum payload size for builtin writers
uint32_t writerPayloadSize = BUILTIN_DATA_MAX_SIZE;

//! Mutation tries if the port is being used.
uint32_t mutation_tries = 100u;

BuiltinAttributes对象在什么地方被初始化

这些内置协议包括:

  1. 参与者发现协议(Participant Discovery Protocol):该协议让参与者(即DDS应用)可以发现网络中的其他参与者。
  2. 发布者/订阅者发现协议(Publisher/Subscriber Discovery Protocol):这允许参与者发现网络中其他参与者的发布者和订阅者。
  3. 读写器发现协议(Reader/Writer Discovery Protocol):这使参与者可以发现网络中其他参与者的数据读写器。
  4. WLP保活协议(心跳,WriterLiveliness),主要由类WLP来实现

这些内置协议在Fast DDS中是自动启动并运行的,而BuiltinProtocols类就是用来管理和处理这些内置协议的。总的来说,BuiltinProtocols类的主要作用是管理和处理Fast DDS的内置协议,这些协议使得DDS应用可以在网络中发现和与其他应用交互。

发现阶段

服务发现的创建和发现都是在BuiltinProtocols类中处理。所有的服务发现都可以分为两个阶段:

  1. Participant Discovery Phase(PDP):这个阶段DomainParticipant通过周期性的广播消息获取互相的存在。
  2. Endpoint Discovery Phase (EDP):这个阶段DomainParticipant会广播其publihser和Subscriber的信息,同时也会接收其他DomainPariticipant的Puiblisher和Subscriber信息。对于两个要匹配的端点而言,topic和data type必须要一致。一旦Puiblisher和Subscriber匹配上之后,就可以接收和发送用户数据了。

发现协议

  • Simple:值为SIMPLE,由RTPS标准指定的Simple discovery协议
  • Static:值为STATIC,SPDP和XML文件中手动指定的EDP
  • Discovery Server:
    • SERVER:DomainParticipant作为仓库,接收和发布发信信息
    • CLIENT:在发现过程中DomainParticipant作为client。它给server发送发现信息,并从server只接收与自己相关的发现信息
    • SUPER_CLIENT:在发现过程中DomainParticipant扮演client。它给server发送发现信息,并接收所有从server收到的发现信息
    • BACKUP:创建一个有持久化的sqlite数据库的SERVER DomainParticipant。BACKUP server可以在一开始加载数据库,这种服务可以让服务发现更加有弹性
  • Manual:NONE,没有PDP阶段,因此也就没有EDP阶段,所有匹配只能通过RTPS层的addReaderLocator, addReaderProxy, addWriterProxy方法

服务发现报文

todo

数据结构

ParticipantProxyData

服务发现的对端的信息都存储在ParticipantProxyData中。这个实例在发现过程中被创建,然后填充发现后的信息后,加入到PDP的参与者列表(ResourceLimitedVector<ParticipantProxyData*> participant_proxies_)中。participant_proxies_的第一个成员是其所在的ParticipantProxyData数据。

开发视图

PDP类图
在这里插入图片描述
EDP类图
在这里插入图片描述

PDPEndPoints类图
在这里插入图片描述

服务发现时序
在这里插入图片描述

发现机制

下面以Simple 为主介绍服务发现的PDP和EDP

PDP阶段

简要介绍PDP类中比较重要的数据类型:

BuiltinAttributes m_discovery;  // 主要用于服务发现配置数据
std::unique_ptr<fastdds::rtps::PDPEndpoints> builtin_endpoints_;
EDP* mp_EDP;   // PDP 中指定要使用的EDP对象
ResourceLimitedVector<ParticipantProxyData*> participant_proxies_;  // 注册的RTPSParticipants对象,第一个元素为本地创建的RTPSParticipants,PDP阶段发现的RTPSParticipants都会添加到这个数据中
ResourceLimitedVector<ParticipantProxyData*> participant_proxies_pool_;//!Pool of participant proxy data objects ready for reuse
size_t reader_proxies_number_;//!Number of reader proxy data objects created
 ResourceLimitedVector<ReaderProxyData*> reader_proxies_pool_;//!Pool of reader proxy data objects ready for reuse
size_t writer_proxies_number_;//!Number of writer proxy data objects created
ResourceLimitedVector<WriterProxyData*> writer_proxies_pool_;//!Pool of writer proxy data objects ready for reuse
 std::atomic_bool m_hasChangedLocalPDP;//!Variable to indicate if any parameter has changed.
ReaderListener* mp_listener;//!Listener for the SPDP messages.
ProxyPool<ReaderProxyData> temp_reader_proxies_;//! ProxyPool for temporary reader proxies
ProxyPool<WriterProxyData> temp_writer_proxies_;//! ProxyPool for temporary writer proxies
  1. 创建PDP(PDPSimple)对象,同时创建多个ParticipantProxyData,ReaderProxyData,WriterProxyData用于存储数据
  2. PDP对象初始化,创建PDPEndpoints(SimplePDPEndpoints)对象, 这个对象主要用于存储SPDP的端点信息,这个对象中包含两个成员:PDPreader BuiltinReader<fastrtps::rtps::StatelessReader>和PDPwriter BuiltinWriter<fastrtps::rtps::StatelessWriter>
auto endpoints = new fastdds::rtps::SimplePDPEndpoints();
builtin_endpoints_.reset(endpoints);
  1. 创建PDPListener
  2. 创建RTPSReader:ReaderAttributes对象并赋值,同时创建RTPSReader:StatelessReader对象。这里会配置reader的读取的组播地址为239.255.0.1/7400和0.0.0.0/7410(7410端口会有变动),就是说,其他participant会往这两个地址发送数据(心跳发往哪个端口?)
  1. 创建RTPSWriter:创建WriterAttributes对象,并创建RTPSWriter的子类StatelessWriter对象,并创建SendResource对象用于发送数据
WriterAttributes watt;
// ...
if (mp_RTPSParticipant->createWriter(&wout, watt, endpoints->writer.payload_pool_, endpoints->writer.history_.get(),
    nullptr, c_EntityId_SPDPWriter, true)) {
    endpoints->writer.writer_ = dynamic_cast<StatelessWriter*>(wout);
#if HAVE_SECURITY
        mp_RTPSParticipant->set_endpoint_rtps_protection_supports(wout, false);
#endif // if HAVE_SECURITY
    if (endpoints->writer.writer_ != nullptr) {
        const NetworkFactory& network = mp_RTPSParticipant->network_factory();
        LocatorList_t fixed_locators;
        Locator_t local_locator;
        for (const Locator_t& loc : mp_builtin->m_initialPeersList) {
            if (network.transform_remote_locator(loc, local_locator)) {
                fixed_locators.push_back(local_locator);
            }
            }
            // 在这个创建UDPSendResource对象
            endpoints->writer.writer_->set_fixed_locators(fixed_locators);
        }
    }
  1. 创建EDP对象:完成上述PDP::initPDP后开始创建EDP对象。
  2. EDP对象的初始化,在SEDP的初始化中会创建SEDP对象相关的监听对象:EDPSimplePUBListener和EDPSimpleSUBListener和edp writer(StatefulWriter)和edp reader(StatefulReader)
bool EDPSimple::createSEDPEndpoints()
{
    publications_listener_ = new EDPSimplePUBListener(this);  // pub listener
    subscriptions_listener_ = new EDPSimpleSUBListener(this);  // sub listener

    if (m_discovery.discovery_config.m_simpleEDP.use_PublicationWriterANDSubscriptionReader)
    {
        if (!EDPUtils::create_edp_writer(mp_RTPSParticipant, "DCPSPublications", c_EntityId_SEDPPubWriter,
                writer_history_att, watt, publications_listener_, pub_writer_payload_pool_, publications_writer_))
    
        if (!EDPUtils::create_edp_reader(mp_RTPSParticipant, "DCPSSubscriptions", c_EntityId_SEDPSubReader,
                reader_history_att, ratt, subscriptions_listener_, sub_reader_payload_pool_, subscriptions_reader_))
    }

    if (m_discovery.discovery_config.m_simpleEDP.use_PublicationReaderANDSubscriptionWriter)
    {
        if (!EDPUtils::create_edp_reader(mp_RTPSParticipant, "DCPSPublications", c_EntityId_SEDPPubReader,
                reader_history_att, ratt, publications_listener_, pub_reader_payload_pool_, publications_reader_))
                
        if (!EDPUtils::create_edp_writer(mp_RTPSParticipant, "DCPSSubscriptions", c_EntityId_SEDPSubWriter,
                writer_history_att, watt, subscriptions_listener_, sub_writer_payload_pool_, subscriptions_writer_))
    }
}

此时,第一阶段的PDP和EDP对象的创建和相关联的一些类对象实例的创建工作完成;第二阶段,通过RTPSParticipant的enable函数的调用,开始服务发现阶段

void BuiltinProtocols::enable()
{
    if (nullptr != mp_PDP)
    {
        mp_PDP->enable();
        mp_PDP->announceParticipantState(true);
        mp_PDP->resetParticipantAnnouncement();
    }
}
  1. 分配广播和单播地址:mp_PDP->enable()中会调用builtin_endpoints_->enable_pdp_readers函数,这个函数会调用到RTPSParticipantImpl::assignEndpointListenResources
bool RTPSParticipantImpl::assignEndpointListenResources(
        Endpoint* endp)
{
    //Tag the endpoint with the ReceiverResources
    bool valid = true;
    //UNICAST
    assignEndpoint2LocatorList(endp, endp->getAttributes().unicastLocatorList);
    //MULTICAST
    assignEndpoint2LocatorList(endp, endp->getAttributes().multicastLocatorList);
    return valid;
}
  1. assignEndpoint2LocatorList中继续调用 MessageReceiver::associateEndpoint函数,会将PDP对象的EntityID添加到接收消息的readers中:
oid MessageReceiver::associateEndpoint(
        Endpoint* to_add)
{
    std::lock_guard<eprosima::shared_mutex> guard(mtx_);
    if (to_add->getAttributes().endpointKind == WRITER)
    {
        const auto writer = dynamic_cast<RTPSWriter*>(to_add);
        for (const auto& it : associated_writers_)
        {
            if (it == writer)
            {
                return;
            }
        }

        associated_writers_.push_back(writer);
    }
    else
    {
        const auto reader = dynamic_cast<RTPSReader*>(to_add);
        const auto entityId = reader->getGuid().entityId;
        // search for set of readers by entity ID
        const auto readers = associated_readers_.find(entityId);
        if (readers == associated_readers_.end())
        {
            auto vec = std::vector<RTPSReader*>();
            vec.push_back(reader);
            associated_readers_.emplace(entityId, vec);
        }
        else
        {
            for (const auto& it : readers->second)
            {
                if (it == reader)
                {
                    return;
                }
            }

            readers->second.push_back(reader);
        }
    }
}

{entityid: PDPreader} 添加到associated_readers_用于接收收到其他participant的服务发现消息。
3. PDP::announceParticipantState函数中,发布本端participant的信息

第三个阶段,回调接收到其他participant的消息后的接收代码(截取部分重要代码说明):
MessageReceiver接收到消息并通知PDPReader读取:

template<typename Functor>
void MessageReceiver::findAllReaders(
        const EntityId_t& readerID,
        const Functor& callback) const
{
    if (readerID != c_EntityId_Unknown)
    {
        const auto readers = associated_readers_.find(readerID);
        if (readers != associated_readers_.end())
        {
            for (const auto& it : readers->second)
            {
                callback(it);
            }
        }
    }
    else
    {
        for (const auto& readers : associated_readers_)
        {
            for (const auto& it : readers.second)
            {
                if (it->m_acceptMessagesToUnknownReaders)
                {
                    callback(it);
                }
            }
        }
    }
}

这段代码中,callback会调用StatelessReader::processDataMsg函数,调用到PDP的监听器PDPListener的onNewCacheChangeAdded函数,接着调用到PDPSimple的assignRemoteEndpoints函数:

void PDPSimple::assignRemoteEndpoints( ParticipantProxyData* pdata)
{
EPROSIMA_LOG_INFO(RTPS_PDP, "For RTPSParticipant: " << pdata->m_guid.guidPrefix);
auto endpoints = static_castfastdds::rtps::SimplePDPEndpoints*(builtin_endpoints_.get());

const NetworkFactory& network = mp_RTPSParticipant->network_factory();
uint32_t endp = pdata->m_availableBuiltinEndpoints;
uint32_t auxendp = endp;
bool use_multicast_locators = !mp_RTPSParticipant->getAttributes().builtin.avoid_builtin_multicast ||
pdata->metatraffic_locators.unicast.empty();
auxendp &= DISC_BUILTIN_ENDPOINT_PARTICIPANT_ANNOUNCER;
if (auxendp != 0)
{
auto temp_writer_data = get_temporary_writer_proxies_pool().get();

temp_writer_data->clear();
temp_writer_data->guid().guidPrefix = pdata->m_guid.guidPrefix;
temp_writer_data->guid().entityId = c_EntityId_SPDPWriter;
temp_writer_data->persistence_guid(pdata->get_persistence_guid());
temp_writer_data->set_persistence_entity_id(c_EntityId_SPDPWriter);
temp_writer_data->set_remote_locators(pdata->metatraffic_locators, network, use_multicast_locators);
temp_writer_data->m_qos.m_reliability.kind = RELIABLE_RELIABILITY_QOS;
temp_writer_data->m_qos.m_durability.kind = TRANSIENT_LOCAL_DURABILITY_QOS;
endpoints->reader.reader_->matched_writer_add(*temp_writer_data);

}
auxendp = endp;
auxendp &= DISC_BUILTIN_ENDPOINT_PARTICIPANT_DETECTOR;
if (auxendp != 0)
{
auto temp_reader_data = get_temporary_reader_proxies_pool().get();

temp_reader_data->clear();
temp_reader_data->m_expectsInlineQos = false;
temp_reader_data->guid().guidPrefix = pdata->m_guid.guidPrefix;
temp_reader_data->guid().entityId = c_EntityId_SPDPReader;
temp_reader_data->set_remote_locators(pdata->metatraffic_locators, network, use_multicast_locators);
temp_reader_data->m_qos.m_reliability.kind = BEST_EFFORT_RELIABILITY_QOS;
temp_reader_data->m_qos.m_durability.kind = TRANSIENT_LOCAL_DURABILITY_QOS;
endpoints->writer.writer_->matched_reader_add(*temp_reader_data);

StatelessWriter* pW = endpoints->writer.writer_;

if (pW != nullptr)
{
    pW->unsent_changes_reset();
}
else
{
    EPROSIMA_LOG_ERROR(RTPS_PDP, "Using PDPSimple protocol with a reliable writer");
}

}
#if HAVE_SECURITY
// Validate remote participant
mp_RTPSParticipant->security_manager().discovered_participant(*pdata);
#else
//Inform EDP of new RTPSParticipant data:
notifyAboveRemoteEndpoints(*pdata, true);
#endif // if HAVE_SECURITY
}

这个函数中将收到的writer信息也就是远程端点存储在StatelessReader的ResourceLimitedVector<RemoteWriterInfo_t> matched_writers_中。
在notifyAboveRemoteEndpoints中调用EDPSimple的assignRemoteEndpoints函数。

具体消息回调堆栈如下:

StatefulWriter::update_reader_info
StatefulWriter::matched_reader_add
EDPSimple::assignRemoteEndpoints
PDPSimple::notifyAboveRemoteEndpoints
PDPSimple::assignRemoteEndpoints
PDPListener::onNewCacheChangeAdded
StatelessReader::change_received
StatelessReader::processDataMsg
MessageReceiver::findAllReaders
MessageReceiver::process_data_message_without_security
MessageReceiver::proc_Submsg_Data
MessageReceiver::processCDRMsg
ReceiverResource::OnDataReceived
UDPChannelResource::perform_listen_operation

此外,服务发现的EntityID是标准固定,回调函数中通过固定EntityID来调用不同的监听对象。这些固定的Entity ID定义在EntityId_t.hpp中,主要有以下:

const EntityId_t c_EntityId_Unknown = ENTITYID_UNKNOWN;
const EntityId_t c_EntityId_SPDPReader = ENTITYID_SPDP_BUILTIN_RTPSParticipant_READER;
const EntityId_t c_EntityId_SPDPWriter = ENTITYID_SPDP_BUILTIN_RTPSParticipant_WRITER;

const EntityId_t c_EntityId_SEDPPubWriter = ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER;
const EntityId_t c_EntityId_SEDPPubReader = ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER;
const EntityId_t c_EntityId_SEDPSubWriter = ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER;
const EntityId_t c_EntityId_SEDPSubReader = ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_READER;

const EntityId_t c_EntityId_RTPSParticipant = ENTITYID_RTPSParticipant;

const EntityId_t c_EntityId_WriterLiveliness = ENTITYID_P2P_BUILTIN_RTPSParticipant_MESSAGE_WRITER;
const EntityId_t c_EntityId_ReaderLiveliness = ENTITYID_P2P_BUILTIN_RTPSParticipant_MESSAGE_READER;

const EntityId_t participant_stateless_message_writer_entity_id = ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_WRITER;
const EntityId_t participant_stateless_message_reader_entity_id = ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_READER;

const EntityId_t c_EntityId_TypeLookup_request_writer = ENTITYID_TL_SVC_REQ_WRITER;
const EntityId_t c_EntityId_TypeLookup_request_reader = ENTITYID_TL_SVC_REQ_READER;
const EntityId_t c_EntityId_TypeLookup_reply_writer = ENTITYID_TL_SVC_REPLY_WRITER;
const EntityId_t c_EntityId_TypeLookup_reply_reader = ENTITYID_TL_SVC_REPLY_READER;

EDP阶段

EDP(Endpoint Discovery Protocol)通过比较参与者(Participant)的读者(Reader)和写者(Writer)的主题(Topic)和数据类型(Data Type)进行匹配。

在Fast DDS中,读者和写者是通信的端点,他们通过主题和数据类型进行交互。一个写者会发布一个特定主题的数据,而读者则会订阅这个主题的数据。

当EDP开始时,每个参与者都会公布其读者和写者的信息(包括主题和数据类型),并接收其他参与者的读者和写者的信息。然后,EDP会比较这些信息,如果一个写者的主题和数据类型与一个读者的主题和数据类型相匹配,那么这个写者和读者就会被匹配起来,它们就可以进行数据通信。

域内发现(Simple Endpoint Discovery Protocol),DomainParticipants中不同DDS实体中互相发现的协议机制,如DataWriter和DataReader。

SEDP的发现阶段是在创建DataWriter和DataReader时进行的。

  1. 发送阶段
    发送阶段是创建DataWriter时开始(不在讨论范围的代码省略):
DataWriter* PublisherImpl::create_datawriter(
        Topic* topic,
        DataWriterImpl* impl,
        const StatusMask& mask)
{
    topic->get_impl()->reference();
    DataWriter* writer = new DataWriter(impl, mask);
    impl->user_datawriter_ = writer;
    // ...
    if (user_publisher_->is_enabled() && qos_.entity_factory().autoenable_created_entities)  
    {
        if (ReturnCode_t::RETCODE_OK != writer->enable())  // 这里开始SEDP
        // ...
    }
    return writer;
}

接着在Builti

nProtocols::addLocalWriter函数中调用EDP::newLocalWriterProxyData函数,在processLocalWriterProxyData中发送SEDP数据:

bool EDPSimple::processLocalWriterProxyData(
        RTPSWriter* local_writer,
        WriterProxyData* wdata)
{
    auto* writer = &publications_writer_;
    // ...
    CacheChange_t* change = nullptr;
    bool ret_val = serialize_writer_proxy_data(*wdata, *writer, true, &change);
    if (change != nullptr) {
        writer->second->add_change(change);
    }
    return ret_val;
}

Simple EDP Attributes

NameDescriptionTypeDefault
SIMPLE EDP定义了EDP阶段SIMPLE protocol发现协议的使用,DomainParticipant可能会创建DataWriters, DataReaders,或者都创建和都不创建booltrue
Publication writer and Subscription readerDomainParticipant只实现一个或两个DataWriters,不需要DataReaders,所以只需要创建与DataReader发现相关的EDP端点booltrue
Publication reader and Subscription writerDomainParticipant只实现一个或两个DataReaders,不需要DataWriter,所以只需要创建与DataWriter发现相关的EDP端点booltrue
  1. Initial peers
    根据RTPS标准,每个RTPSParticipant必须用两个不同的端口监听PDP,一个多播地址,一个单播地址。Fast DDS允许配置对端的IP-Port。
优点
  1. 简单易用,只要在同一网络中的节点启动Fast DDS应用,他就能自动发现彼此并建立连接
  2. 自动化,无需手动配置每个节点的网络地址,减轻了配置和维护的工作量
  3. 实时性,可以快速探测和连接节点,适合实时性要求高的系统
缺点
  1. 缺乏灵活性,不支持定制化的发现策略,可能不适合某些特殊需求
  2. 可扩展性问题:在大型复杂的系统中,需要所有节点之间进行广播,当节点数量非常多时可能会导致网络拥塞,所以缺乏可扩展性
  3. 安全性问题:Simple Discovery并未考虑到安全性问题,可能会导致节点攻击
适用场景

Static Discovery

Static Discovery使用SPDP(即上面的Simple Participant Discovery Protocol)作为PDP阶段,但跳过了SEDP,所有参与的节点在启动前必须已知。这些信息定义在XML文件中,即EDP阶段通过静态配置来代替SEDP协议。这在处理有限带宽和已知的DataWrites和DataReaders方面非常有用。如果所有的DataWriters和DataReaders,它们的Topics,data types都是事先已知的,EDP阶段可以用对端的静态配置替换。因此也只有在对端配置的部分才可以通信。

优点
  1. 安全。与Simple Discovery相比,Static Discovery可以更好的控制哪些节点可以连接到系统,从而提高系统的安全性
  2. 可扩展。不依赖于节点之间的广播,所以有较好的扩展性
  3. 灵活性。可以控制哪些节点应该连接在一起,使用更加灵活
缺点
  1. 需要手动配置每个节点的网络地址,增加了配置和维护的工作量;且如果拓扑结构发生变化,也需要手动修改
  2. 启动阶段,因为在系统启动阶段需要保证配置完成,否则可能导致启动失败或部分功能无法使用,导致启动较慢
适用场景
Simple和Static时序

在这里插入图片描述

Discovery Server

这种发现机制使用中心化的策略,基于client-server模式。这种服务模式中,一个或多个DomainParticipants作为server,所有的其他节点作为client,向server注册信息,并从server获取其他节点的信息。
Discovery Server DomainParticipants可以是clients或者servers。分为四种模式:SERVER,CLIENT,BACKUP,SUPPER CLIENT。它们之间的区别主要是节点发现过程中的角色和职责上:

  1. SERVER:SERVER是Discovery Server模式中的中心节点,它负责管理和存储所有节点(包括CLIENT,BACKUP,SUPER CLIENT)的元数据信息。当一个CLIENT节点需要发现其他节点信息时,它会像SERVER请求所需的元数据信息。具体来说,一个SERVER会发布clients和servers的信息,同时一个server可能会连接到另一个serser上来接收它的clients信息。
  2. CLIENT:CLIENT是需要与其他节点进行交互的节点。在Discovery Server模式中,CLIENT节点会连接到一个或多个SERVER,将自己的元数据信息注册到SERVER,并从SERVER获取它需要的,其他节点的元数据信息,以便与其他节点建立连接和进行通信。Clients需要预先知道它要连接的Servers。
  3. BAKCUP:备份是一种特殊的SERVER,它会将发现的信息写入持久化的数据库,用于Server发生故障时提供备份和恢复服务。BACKUP节点会定期从SERVER同步所有节点的元数据信息。如果主SERVER发生故障,CLIENT节点可以从BACKUP节点获取所需要的元数据信息,以便于继续与其他节点通信。
  4. SUPER CLIENT:特殊的CLIENT,可以直接与SERVER进行通信,而不需要通过BACKUP节点。这使得SUPER CLIENT可以在SERVER发生故障时直接从BACKUP节点获取元数据信息,而不需要等待BACKUP节点的同步。这可以提供系统的响应速度和可靠性。
优点
  1. 可扩展:对于大型系统,在Simple Discovery中每个节点都要互相通信,节点数量很大的情况下会造成大量通信从而导致网络拥塞,而在Discovery Server中节点之间的通信减少,大大减少了网络流量和节点处理负载
  2. 效率:点对点发现模式中,节点发现过程的时间通常会随着节点数量的增加而增加,而在Discovery Server模式中,由于所有的元素据都在服务器上,因此节点发现过程的时间基本上上固定的,不会随着节点的增加而增加。
  3. 灵活:Discovery Server提供一种更灵活的方式来管理拓扑结构,例如,节点可以部署到不同的网络子网中,只要可以访问到服务器即可,服务器可以根据需要来控制哪些客户端
缺点
  1. 服务器单点故障:如果发生故障,会导致所有节点无法发现和通信。虽然可以通过备份服务器来提高系统的可靠性,但会增加系统的复杂性和成本。
  2. 依赖服务器:所有节点都依赖服务器进行发现和通信,如果性能不足或者网络连接不稳定,整个系统的性能和稳定性都会受到影响
  3. 配置复杂:相比点到点的发现,需要配置服务器地址,端口,以及节点的角色和权限等信息。
适用场景

适用于大型和复杂的分布式系统

视图:
在这里插入图片描述

Manual Discovery

这种机制只与RTPS层兼容。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值