首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Titan Cassandra多线程事务锁定

Titan Cassandra多线程事务锁定
EN

Stack Overflow用户
提问于 2016-01-18 09:55:37
回答 2查看 1.2K关注 0票数 1

我已经创建了一个类,其中包含了一个Graph。例如:

代码语言:javascript
复制
public class GraphManager(){
    Graph graph;
    public GraphManager(Graph graph){
        this.graph = graph;
    }
    public void commitGraph(){
        graph.commit();
    }
}

这个GraphManager允许我以预定义的方式与图形交互。我使用一个工厂来构造这个GraphManager

代码语言:javascript
复制
public class GraphManagerFactory(){
    public static GraphManager getGraphManager(){
        return new GraphManager(TitanFactory.open("conf/titan-cassandra.properties"));
    }
}

这就是基本框架。现在讨论这个问题,使用rest控制器,我收到一个JSON文件。这将导致实例化一个GraphManager,它将文件转换为一个图形,然后提交它。基本模式如下:

代码语言:javascript
复制
public class Controller(){
    public List<String> handleRequest(){
        GraphManager manager = GraphManagerFactory.getGraphManager();
        //Do some work with graph manager
        synchronised(Controller.class){
            manager.commitGraph();
        }
    }
}

使用上面的代码,我保证在任何时候只有一个线程可以提交到图形。然而,尽管如此,我还是得到了一个PermanentLockingException

代码语言:javascript
复制
com.thinkaurelius.titan.diskstorage.locking.PermanentLockingException: Local lock contention
at com.thinkaurelius.titan.diskstorage.locking.AbstractLocker.writeLock(AbstractLocker.java:313) ~[titan-core-1.0.0.jar:na]
at com.thinkaurelius.titan.diskstorage.locking.consistentkey.ExpectedValueCheckingStore.acquireLock(ExpectedValueCheckingStore.java:89) ~[titan-core-1.0.0.jar:na]
at com.thinkaurelius.titan.diskstorage.keycolumnvalue.KCVSProxy.acquireLock(KCVSProxy.java:40) ~[titan-core-1.0.0.jar:na]
at com.thinkaurelius.titan.diskstorage.BackendTransaction.acquireIndexLock(BackendTransaction.java:240) ~[titan-core-1.0.0.jar:na]
at com.thinkaurelius.titan.graphdb.database.StandardTitanGraph.prepareCommit(StandardTitanGraph.java:554) ~[titan-core-1.0.0.jar:na]
at com.thinkaurelius.titan.graphdb.database.StandardTitanGraph.commit(StandardTitanGraph.java:683) ~[titan-core-1.0.0.jar:na]
at com.thinkaurelius.titan.graphdb.transaction.StandardTitanTx.commit(StandardTitanTx.java:1352) [titan-core-1.0.0.jar:na]
at com.thinkaurelius.titan.graphdb.tinkerpop.TitanBlueprintsGraph$GraphTransaction.doCommit(TitanBlueprintsGraph.java:263) [titan-core-1.0.0.jar:na]
at org.apache.tinkerpop.gremlin.structure.util.AbstractTransaction.commit(AbstractTransaction.java:94) [gremlin-core-3.0.2-incubating.jar:3.0.2-incubating]
at io.mindmaps.core.accessmanager.GraphAccessManagerImpl.commit(GraphAccessManagerImpl.java:811) [mindmaps-core-0.0.5-SNAPSHOT.jar:na]
at io.mindmaps.graphmanager.listener.TransactionController.commitGraph(TransactionController.java:98) [classes/:na]
at io.mindmaps.graphmanager.listener.TransactionController.validateAndCommit(TransactionController.java:84) [classes/:na]
at io.mindmaps.graphmanager.listener.TransactionController.loadData(TransactionController.java:66) [classes/:na]
at io.mindmaps.graphmanager.listener.TransactionController.lambda$postTransaction$0(TransactionController.java:43) [classes/:na]
at io.mindmaps.graphmanager.loader.QueueManager.handleJob(QueueManager.java:76) ~[classes/:na]
at io.mindmaps.graphmanager.loader.QueueManager.lambda$addJob$3(QueueManager.java:24) ~[classes/:na]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_66]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[na:1.8.0_66]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) ~[na:1.8.0_66]
at java.lang.Thread.run(Thread.java:745) ~[na:1.8.0_66]

如果一次只允许一次提交,怎么会发生这种情况?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-01-20 13:02:46

首先,我建议您不要为每个请求创建一个TitanGraph实例(代价高昂)。创建一个TitanGraph并在请求之间共享它。接下来,您需要非常小心web应用程序,使事务不会在请求之间泄漏(事务绑定到当前线程)。您可以通过确保请求在完成时始终发出rollback()commit() (在错误或必要时成功)来确保在其自身之后进行清理。您可以通过在新请求开始时发出rollback()来双重保证这一点。

考虑到这一切,让我们回答你的问题。仅仅因为您将commit()操作限制在单个线程上,并不会阻止其他线程打开事务。另一个由不同线程处理的请求可以很容易地尝试对相同的键进行抓住锁,并在提交时被阻塞,在您看到的锁定异常中结束。

"事务最终将在足够大的系统中失败。PermanentLockingException必须被视为使用锁的预期副作用,处理锁的典型方法是在遇到锁时重新尝试整个事务。你应该在这个前提下设计你的基本架构。

这方面的一些其他建议:

  1. 您应该尽可能限制锁的使用,因为它们可能会成为瓶颈。如果有任何方法你可以没有他们-这样做。
  2. 当您发出一些获取锁的更改时,请保持事务简短。他们开放的时间越长,与另一个请求争论的机会就越大。
票数 2
EN

Stack Overflow用户

发布于 2016-01-27 09:12:08

虽然我接受的答案是百分之百正确的。我想更清楚地强调我为避免锁定争论所做的事情(其中大部分是基于/多亏了公认的答案):

步骤1:推荐的是,而不是包装图形的实例,我在每个GraphManager中包装了一个新事务。我的工厂是这样的:

代码语言:javascript
复制
public class GraphManagerFactory(){
    TitanGraph instance;
    public static GraphManager getGraphManager(){
        if(instance = null){
            instance = TitanFactory.open("conf/titan-cassandra.properties");
        }
        return new GraphManager(instance.newTransaction());
    }
}

这一步导致了许多改进。我仍然有锁的争论,但他们解决得更快。

步骤2:在第一次构建图形时,我还提前提供了模式。具体来说,不是让泰坦隐式地构建顶点属性和边,而是在添加第一个顶点之前显式地构建它们。这是一个简单的问题,使用management.makeEdgeLabel(label).make();作为边缘标签,management.makePropertyKey(label).dataType(String.class).make();用于顶点属性。这样做的另一个好处是我可以更容易地执行批处理加载。这意味着再次将Factory扩展为:

代码语言:javascript
复制
public class GraphManagerFactory(){
    TitanGraph instance;
    public static GraphManager getGraphManager(){
        if(instance = null){
            instance = TitanFactory.open("conf/titan-cassandra.properties");
            TitanManagement management = instance.openManagement();
            //Check if the labels exist before creating explicitly. 
            //If they don't exist do the following:
            management.makeEdgeLabel("EdgeLabel").make();
            management.makePropertyKey("property").dataType(String.class).make();
            management.commit();
        }
        return new GraphManager(instance.newTransaction());
    }
}

步骤3:几乎完全消除了争论的最后一步是将id块大小增加到graph.configuration().setProperty("ids.block-size", 100000);。这最后一步可能只适用于我,虽然我正在执行大型加载操作同时。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34851775

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档