我正在使用 appengine 服务器。我预计会收到许多(数十个)非常接近的请求,这将使我的一些数据处于不一致的状态。该数据的清理可以有效地进行批处理 - 例如,最好在数十个请求全部完成后只运行一次清理代码。我不知道到底会有多少请求,也不知道它们的间隔有多近。清理代码运行多次也可以,但必须在最后一次请求之后运行。
减少清理运行次数的最佳方法是什么?
这是我的想法:
public void handleRequest() {
manipulateData();
if (memCacheHasCleanupToken()) {
return; //yay, a cleanup is already scheduled
} else {
scheduleDeferredCleanup(5 seconds from now);
addCleanupTokenToMemCache();
}
}
...
public void deferredCleanupMethod() {
removeCleanupTokenFromMemcache();
cleanupData();
}
我认为这会失败,因为即使某些请求发现内存缓存中有清理 token (HRD 延迟等),cleanupData
也可能会收到过时的数据,因此可能会丢失一些数据在清理中。
所以,我的问题:
- 这个总体策略会奏效吗?也许我在数据存储实体上使用事务锁?
- 我应该使用什么策略?
最佳答案
您建议的一般策略将会起作用,只要需要清理的数据没有存储在每个实例上(例如,它位于数据存储区或内存缓存中),并且您的 schduleDeferredCleanup
方法使用任务队列。一种优化方法是使用基于任务运行时间间隔的任务名称,以避免在内存缓存 key 过期时安排重复的清理工作。
不过,上述过程中需要注意的一个问题是竞争条件。如上所述,与清理任务同时处理的请求可能会检查内存缓存,观察 token 是否存在,并忽略将清理任务排入队列,而清理任务已经完成,但尚未删除内存缓存 key 。避免这种情况的最简单方法是让内存缓存 key 自行过期,但要在相关任务执行之前。这样,您可以安排重复的清理任务,但决不应该遗漏所需的任务。
关于java - 线程安全的任务批处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7956018/