我们目前使用Cassandra作为NoSQL数据库,使用GemFire作为内存数据库。我们一直在使用GemFire CacheWriter在Cassandra中插入记录。我希望您对使用CacheWriter中的Concurrent线程插入/更新记录是否是一个好的工程实践提出反馈。您的意见将不胜感激。
public class GenericWriter<K, V> extends CacheWriterAdapter<K, V> implements Declarable {
private static Logger log = LoggerFactory.getLogger(GenericWriter.class);
@Autowired
private CassandraOperations cassandraOperations;
ExecutorService executor = null;
@Override
public void beforeCreate(EntryEvent<K, V> e) {
executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
if (eventOperation.equals("CREATE") || eventOperation.equalsIgnoreCase("PUTALL_CREATE")) {
try {
cassandraOperations.insert(e.getNewValue());
} catch (CassandraConnectionFailureException | CassandraWriteTimeoutException
| CassandraInternalException cassException) {
} catch (Exception ex) {
log.error("Exception in GenericCacheWriter->" + ExceptionUtils.getStackTrace(ex));
throw ex;
}
}
});
executor.shutdown();
}
@Override
public void init(Properties arg0) {
// TODO Auto-generated method stub
}
}
答案 0 :(得分:3)
同步调用CacheWriter
处理程序,因此在处理程序返回之前应用程序不会继续。因此,不建议在此侦听器中执行长时间运行的操作。如果需要长时间运行的操作,请考虑通过AsyncEventListener
异步处理操作。
使用ExecutorService
将执行委托给不同的线程是可能的,但它是反模式的,因为它不再实现fail-fast属性,并且事件的处理不再是同步的,所以相对于应用程序完成事件,它的时间安排不会得到保证。
您可以在Geode Wiki中详细了解此主题,特别是CacheWrite and CacheListener Best Practices。
希望这有帮助。
最好的问候。
答案 1 :(得分:1)
是的,它是一个很好的模式,但是删除Executor并对数据进行分区,以便GemFire的所有更新都转到一个且只有一个节点。以同样的方式对Cassandra进行分区。在Cassandra更新周围写一个写锁。仅在吞吐量较低时使用此选项。
如果您需要高吞吐量,请使用AsyncEventListener并保证用户的最终一致性。如果必须在AEL中使用Executors,请以某种方式使用它们,以便在主线程中引发异常。如果在多次尝试后更新失败,则将失败的条目写入其他区域,并在几秒或一分钟到期。当该过期时,重试该操作。继续这样做直到成功然后才会删除过期的条目。
如果更新顺序对您不重要,您将需要跟踪版本号以及您正在更新观看旧值/新值的内容。