【发布时间】:2017-01-12 20:06:49
【问题描述】:
最近一个使用py2neo 包并通过Bolt 协议连接的脚本开始意外失败并出现ProtocolError: Server closed connection,我很难理解为什么。请注意,当使用 HTTP 作为协议时,该脚本有效。
脚本提取 Neo4j 图形,在 Python 中对其进行扩充,然后尝试将相关更改推送回数据库。整个过程大约需要一个小时,并且可靠地工作了相当长的一段时间,但是最近推送阶段开始失败。
如果我创建一个玩具示例,绕过拉取和扩充,然后推送工作,因此我认为服务器由于超时而关闭了连接,但是我在 py2neo 中找不到任何与 Bolt 相关的超时参数.注意我已将 HTTP 套接字超时设置为 9999 秒(~ 2.75 小时),
from py2neo.packages.httpstream import http
http.socket_timeout = 9999
虽然我对此的理解是 i)它与 Bolt 无关,并且 ii)超时处于连接级别,大大超过了脚本运行的时间。
作为参考,我使用的是 Neo4j v3.0.3 和 py2neo v3.1.2。堆栈跟踪是:
File "/usr/local/lib/python2.7/dist-packages/py2neo/database/__init__.py", line 1017, in __exit__
self.commit()
File "/usr/local/lib/python2.7/dist-packages/py2neo/database/__init__.py", line 1059, in commit
self._post(commit=True)
File "/usr/local/lib/python2.7/dist-packages/py2neo/database/__init__.py", line 1291, in _post
self.finish()
File "/usr/local/lib/python2.7/dist-packages/py2neo/database/__init__.py", line 1296, in finish
self._sync()
File "/usr/local/lib/python2.7/dist-packages/py2neo/database/__init__.py", line 1286, in _sync
connection.fetch()
File "/usr/local/lib/python2.7/dist-packages/py2neo/packages/neo4j/v1/bolt.py", line 323, in fetch
raw.writelines(self.channel.chunk_reader())
File "/usr/local/lib/python2.7/dist-packages/py2neo/packages/neo4j/v1/bolt.py", line 174, in chunk_reader
chunk_header = self._recv(2)
File "/usr/local/lib/python2.7/dist-packages/py2neo/packages/neo4j/v1/bolt.py", line 157, in _recv
raise ProtocolError("Server closed connection")
ProtocolError: Server closed connection
精简后的 Python 代码是这样的,
import py2neo
from py2neo.packages.httpstream import http
http.socket_timeout = 3600
graph = py2neo.Graph(
host='localhost',
bolt=True,
bolt_port=4096,
http_port=4095,
)
# Pull the graph from the Neo4j database via graph.run(...) statements,
# augments the graph etc.
# ...
# Exception is thrown when the following push transaction is executed.
with graph.begin() as tx:
statement = """
UNWIND {rows} AS row
WITH row.source AS source, row.target AS target
MATCH (s:Entity)
USING INDEX s:Entity(uuid)
WHERE s.uuid = source
MATCH (t:Entity)
USING INDEX t:Entity(uuid)
WHERE t.uuid = target
MATCH (s)-[r:FAVORITED]->(t)
DELETE r
"""
rows = [{
'source': '8267d7d0-a837-11e6-b841-22000bcec6a9',
'target': 'c6296c97-a837-11e6-b841-22000bcec6a9',
}]
tx.run(statement, rows=rows)
对于如何进一步调试或导致连接关闭的原因,是否有人有任何建议?我查看了_recv 函数,但不清楚为什么套接字没有接收到数据。
查看 Neo4j debug.log 文件唯一可能的相关错误是
java.io.IOException: Connection reset by peer
at sun.nio.ch.FileDispatcherImpl.read0(Native Method)
at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:39)
at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:223)
at sun.nio.ch.IOUtil.read(IOUtil.java:192)
at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:380)
at io.netty.buffer.PooledUnsafeDirectByteBuf.setBytes(PooledUnsafeDirectByteBuf.java:311)
at io.netty.buffer.AbstractByteBuf.writeBytes(AbstractByteBuf.java:881)
at io.netty.channel.socket.nio.NioSocketChannel.doReadBytes(NioSocketChannel.java:242)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:119)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:111)
at java.lang.Thread.run(Thread.java:745)
我还检查了服务的正常运行时间,并确认它在脚本的整个持续时间内都在运行 (HH:MM:SS),
> ps -p "14765" -o etime=
16:55:31
【问题讨论】: