领导、路由和负载均衡
选举和领导权
集群中的服务器使用 Raft 协议来确保一致性和安全性。Raft 的一个实现细节是它使用一个*领导者*角色来对底层日志施加排序,其他实例则充当*跟随者*,复制领导者的状态。具体到 Neo4j 中,这意味着对数据库的写入操作由当前扮演相应数据库*领导者*角色的服务器进行排序。
只有以主模式托管数据库的服务器才能被选举为该数据库的领导者,前提是集群中包含多个主服务器。如果 Neo4j DBMS 集群包含多个数据库,那么这些数据库中的每一个都在逻辑上独立的 Raft 组中运行,因此每个数据库都有一个单独的领导者。这意味着一个服务器可能同时充当某些数据库的*领导者*和另一些数据库的*跟随者*。
如果跟随者一段时间内没有收到领导者的消息,它就可以发起选举,尝试成为新的领导者。跟随者将自己设为*候选者*,并请求其他服务器投票。如果它能获得多数票,它就担任领导者角色。服务器不会投票给比自己更新程度低的候选者。每个数据库在任何时候只能有一个领导者,并且该领导者保证拥有最新的日志。
选举在集群正常运行时是预期会发生的,它们本身并不构成问题。如果您正在经历频繁的重新选举,并且它们扰乱了集群的运行,那么您应该尝试找出导致它们的原因。一些常见的原因是环境问题(例如不稳定的网络)和工作过载情况(例如比硬件能处理的并发查询和事务更多)。
领导权均衡
写入事务始终路由到相应数据库的领导者。因此,不均匀分布的领导权可能导致写入查询不成比例地导向一部分服务器。默认情况下,Neo4j 通过自动转移数据库领导权来避免这种情况,使其在整个集群中均匀分布。此外,Neo4j 会自动将数据库领导权从那些使用 server.databases.read_only 或类似方式配置为只读的实例上转移。
客户端路由
客户端路由是指数据库客户端控制将特定请求发送到哪个集群成员。通常,这是为了确保写入操作发送到可以写入目标数据库的服务器,而读取操作发送到其他服务器。
客户端路由基于从集群成员获取路由表,然后使用该信息做出路由决策。路由表包含特定数据库的*写入器*、*读取器*和*路由器*的信息。通常有一个*写入器*,但如果数据库是只读或不健康的,则可能没有。在默认配置下,所有其他托管该数据库的服务器都被视为*读取器*,即写入器不在读取器列表中。这是为了让它专注于写入负载,而无需管理两种类型的交互。通常,所有托管数据库的服务器都被列为*路由器*,这些服务器可以被联系以获取该数据库的新路由表。
Neo4j 驱动程序在首次尝试连接数据库时会检索路由表,并在配置的生存时间后或路由表似乎已过期时获取新的路由表。例如,如果路由表将 server-3
列为数据库的写入器,但写入请求因无法写入错误而被拒绝,则驱动程序可能会决定获取新的路由表,因为写入器可能是不同的服务器。
有关获取路由表的更底层细节,请参阅 Bolt 协议文档。
路由策略
您可以使用 路由策略 来控制服务器提供的路由表。策略根据您定义的规则,筛选每个类别的所有可能服务器。例如,这可用于优先路由到本地数据中心,或路由到特定的大型机器,具体取决于您的策略。
服务器端路由
服务器端路由是客户端路由的补充。
在 Neo4j 的集群部署中,Cypher 查询可能会被定向到无法运行给定查询的集群成员。启用服务器端路由后,此类查询会在内部重新路由到预期能够运行它们的集群成员。当写入事务查询寻址的数据库,其接收集群成员不是领导者时,可能会发生这种情况。
集群成员的集群角色是基于每个数据库的。因此,如果写入事务查询发送到一个并非指定数据库(通过 Bolt 协议 或 Cypher USE
子句 指定)领导者的集群成员,则在正确配置的情况下会执行服务器端路由。
服务器端路由由 DBMS 启用,通过为每个集群成员设置 dbms.routing.enabled=true
。侦听地址 (server.routing.listen_address
) 和通告地址 (server.routing.advertised_address
) 也需要配置,以实现服务器端路由通信。
客户端连接需要声明应使用服务器端路由,此功能适用于 Neo4j 驱动程序和 HTTP API。
Neo4j 驱动程序只有在使用 在集群端,您必须满足以下先决条件才能使服务器端路由可用:
最后一个先决条件通过向客户端发送一个仅包含一个条目的路由表来强制客户端使用服务器端路由。因此, 每个成员的 HTTP-API 都会自动受益于这些设置。 |