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