【问题标题】:Neo4j DeadlocksNeo4j 死锁
【发布时间】:2014-02-26 02:43:18
【问题描述】:

我正在为BG benchmark 实现一个 Neo4j 客户端。有 11 个功能,模拟 11 种不同的社交网络动作。这些功能中的每一个都有自己的交易主体。但是当我运行 100 个线程时,有时会抛出死锁检测异常。

我将用户作为节点,将友谊作为关系。我有邀请朋友,拒绝朋友,接受朋友和解冻友谊,它们都有两个用户作为他们的输入。他们的工作方式是获取一个用户节点的所有关系并找到与另一个用户节点的关系。

有人知道 Neo4j 的锁定机制吗?

【问题讨论】:

    标签: database neo4j deadlock


    【解决方案1】:

    您可以在Neo4j documentation 中阅读有关死锁的信息。当您同时修改相同的实体(节点或关系)时,这些可能会出现。请注意,在修改实体时,可能会使用多个锁:例如对于一个关系,该关系连接的两个节点上的锁都会被占用。

    【讨论】:

    • BG 基准测试随机选择两个用户并使用该输入随机调用其中一个操作。但是每次它选择两个用户时,它都会锁定他们,所以其他线程将无法选择那些。我的意思是两个线程没有机会选择两个相同的用户。
    • 描述您在交易中所做的事情会很有帮助。死锁可能来自关系锁:假设您有用户 A 和 B,他们有两个共同的朋友 C 和 D:A--C--B 和 A--D--B。同时删除 A 和 B 可能会导致死锁,因为两者都需要 C 和 D 上的锁。
    • 有一个用户查看好友列表的操作,它会锁定该特定用户的所有友谊关系以计算它们。假设函数 viewFriend(u1) 将锁定所有用户 u2-u10。同时u2可能想邀请u10,需要锁定u2和u10,但是不能!所以我认为这是因为任何对图形的访问都抓住了同一个锁:-?
    • 如果只计算它们,则不应使用任何锁。锁用于写入
    【解决方案2】:

    默认锁定行为:

    1. 在节点或关系上添加、更改或删除属性时,将对特定节点或关系采取写锁定。
    2. 创建或删除节点时,将为特定节点获取写锁定。
    3. 创建或删除关系时,将对特定关系及其两个节点进行写锁定。

    锁将被添加到事务中,并在事务完成时释放。

    1. 设计数据库时应采用最小锁定方式。
    2. 避免使用相同的节点和关系由多个用户在同一实例中使用。保持这些节点和关系的最短交易期限。

    【讨论】:

      【解决方案3】:

      也许序列化并行写入查询会对您的解决方案有所帮助。在您的情况下,您有 11 个功能,模拟 11 种不同的社交网络操作。在您的描述中,我认为某些操作(交易)可能会按顺序执行(例如,您只能在您的朋友发送邀请后接受好友请求)。您可以序列化一些写事务。换句话说,一些查询将被阻止,直到之前的查询完成。 在因果链和书签的帮助下,您可以序列化每个会话的操作。例如,如果您有三个函数,sendInvitationToFriend、 reject friend、acceptFriend。拒绝/接受交易将被阻止,直到 sendInvitationToFriend 交易完成。

      一些代码sn-ps(neo4j-java-driver 4.1):

      
          List<Bookmark> bookmarks = new ArrayList<>();
      
          // Send Invitation.
          try ( Session session = driver.session( builder().withDefaultAccessMode( AccessMode.WRITE ).build())){
              session.writeTransaction( tx -> this.sendInvitationToFriend( tx, "friendId", "yourId"));
              savedBookmarks.add(session.lastBookmark() );
          }
      
          // accept the invitation 
          try (Session session = driver.session( builder().withDefaultAccessMode( AccessMode.WRITE ).withBookmarks( savedBookmarks ).build())){
              session.writeTransaction( tx -> this.acceptFriend(tx, "friendId", "yourId"));
          }
      
          // Create a friendship between the two people created above.
          try (Session session = driver.session(builder().withDefaultAccessMode( AccessMode.WRITE).withBookmarks(savedBookmarks ).build())) {
              session.writeTransaction( tx -> this.rejectFriend( tx, "friendId", "yourId"));
          }
      

      您还提到您的模拟在某种程度上是随机的。我的建议你可以在你的程序中定义一个重试策略,重新尝试查询服务时间,直到它顺利,让主线程在任何两次重试之间休眠一段时间。您可以从link找到更多详细信息

      希望这篇文章对你有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-27
        • 2014-06-08
        • 2013-11-30
        • 2013-12-25
        • 2015-01-29
        相关资源
        最近更新 更多