限制 Bolt 线程 vs 连接
在读/写事务请求量很高的情况下,Neo4j 服务器可能会拒绝某些入站事务,并且 Neo4j debug.log 中可能会报告以下错误
ERROR [o.n.b.r.MetricsReportingBoltConnection] Unable to schedule bolt session <session_id> for execution since there are no available threads to serve it at the moment. You can retry at a later time or consider increasing max thread pool size for bolt connector(s). Task java.util.concurrent.CompletableFuture$AsyncSupply@9bde0657 rejected from org.neo4j.bolt.runtime.CachedThreadPoolExecutorFactory$ThreadPool@95fe540f[Running, pool size = 400, active threads = 400, queued tasks = 0, completed tasks = 197942]
虽然上述建议的 Bolt 线程池大小可在 neo4j.conf 中配置,但人们可能会预期 Bolt 连接总数(即活动连接数 + 空闲连接数,由指标 neo4j.bolt.connections_running 和 neo4j.bolt.connections_idle 报告)始终小于配置值 dbms.connector.bolt.thread_pool_max_size
。然而,这是一种误解,本文旨在解决此问题。
Bolt 线程与 Bolt 连接之间的区别
Bolt 线程是 Neo4j 服务器分配的 CPU 的一部分,用于执行给定任务的进程执行器。Bolt 连接是客户端驱动程序会话向 Neo4j 服务器发出的请求。在 JVM 服务器中,监听套接字上的接受线程接受连接并将其放入连接队列。线程池中的请求处理线程从队列中取出连接并处理请求。在“每请求一线程”模型中,线程仅在请求处理期间关联,即服务需要更少的线程来处理相同数量的客户端连接。由于线程使用大量资源,这意味着服务将更具可伸缩性。
dbms.connector.bolt.thread_pool_max_size
指标报告 Bolt 线程池的最大大小,其中限制线程池不限制连接总数。一个线程可以处理多个连接。Bolt 线程池大小仅限制 Neo4j 服务器可以并发处理的 Bolt 线程数量。如果一个连接处于非活动状态,则没有线程分配给该连接。目前服务器对空闲连接没有限制。但是,连接池大小限制可以在驱动程序创建期间在客户端配置。由于默认情况下连接没有上限,因此驱动程序连接池大小可以增加到机器 CPU 上可用的连接总数。
什么是空闲 Bolt 连接?
指标名称 neo4j.bolt.connections_idle
可能表明空闲 Bolt 连接是由已完成的 Bolt 事务打开的,但一旦事务完成,线程会保持在打开但空闲状态,直到线程池将其关闭。
以上是一种误解,因为在 neo4j.conf 中设置 dbms.connector.bolt.thread_pool_max_size
限制了正在处理的并发线程连接峰值(由 neo4j.bolt.connections_running 指标表示)。然而,未被处理的空闲连接不受此配置的限制。线程池配置(服务器端)不能用于调节连接(客户端)。
为什么空闲连接指标名为 neo4j.bolt.connections_idle?
因为这些连接是由驱动程序建立的,并且驱动程序在驱动程序生命周期内重用连接。Bolt 连接池是驱动程序配置。线程池是服务器配置,用于指定处理来自连接的作业的峰值容量。如果连接没有作业,则它在客户端处于空闲状态。服务器不控制这些空闲连接。只有驱动程序才能关闭它们。此外,服务器没有连接数量的上限,空闲连接不应消耗 CPU 使用率。
如何控制客户端驱动程序打开的最大连接数?
驱动程序连接限制可通过 MaxConnectionPoolSize
、MaxConnectionLifetime 和 ConnectionAcquisitionTimeout 参数进行配置。Neo4j Java 驱动程序的配置示例如下:
Config config = Config.builder()
.withMaxConnectionLifetime( 30, TimeUnit.MINUTES )
.withMaxConnectionPoolSize( 50 )
.withConnectionAcquisitionTimeout( 2, TimeUnit.MINUTES )
.build();
Driver driver = GraphDatabase.driver( uri, AuthTokens.basic( user, password ), config );
参考资料
此页面有帮助吗?