【问题标题】:Processing same concurrent request in REST在 REST 中处理相同的并发请求
【发布时间】:2017-06-16 19:37:15
【问题描述】:

问候 SO 社区! 我有一个基于球衣的 REST 应用程序。此应用程序(由于其客户端的性质)在大致相同的时间(相隔约 2-5 秒)接收相同的 http 请求(其中 3-6 个)。 每个请求大约需要 10 秒来处理并带回大量数据(访问数据库、进行数据按摩等)。 在一个理想的世界中,我希望避免多次处理同一个请求,并且正在考虑编写某种请求过滤器,它只允许唯一请求通过,而其他请求过滤器将被阻止,直到允许的请求返回. 被阻塞的请求也会返回相同的数据给调用者(通过在服务器上查找缓存的响应)

这种方法的优缺点是什么? 除了更改客户端逻辑之外,还有其他更好的解决方案吗?)

【问题讨论】:

    标签: java rest concurrency jersey request


    【解决方案1】:

    您可以为每个“键”创建一个唯一的对象来锁定。其中关键是一些请求参数,在本例中为String。这样,您只需保留请求(因为同步),一旦计算完成,两个客户端几乎同时获得结果。这样客户端就不必发出多个请求,而不是第一个客户端的客户端必须等待第一个客户端填充缓存。

    import java.util.HashMap;
    import java.util.concurrent.ConcurrentHashMap;
    
    public class Hold {
        private ConcurrentHashMap<String, String> holds =
                new ConcurrentHashMap<>(new HashMap<String, String>());
    
        // compose a "hash" for lack of better word, could append a timeout as well
        public String hashString (String string) {
            return string + "wackystuff";
        }
    
        public String doLongComputation () {
            // do crazy computation here
            return new String();
        }
    
    
        public synchronized String getResults (String key) {
            // give us a unique object for this key to lock on
            holds.putIfAbsent(key, hashString(key));
    
            // lock on that key
            synchronized (holds.get(key)) {
                // we have a non lock value so return it
                if (!holds.get(key).equals(hashString(key))) {
                    // could do some timeout here
                    return holds.get(key);
                }
                // the cache is empty so do the long computation
                holds.put(key, doLongComputation());
            }
            return holds.get(key);
        }
    
    }
    

    这只是一种狡猾的方法,Java Concurrency in Practice一书有更强大的方法,它在第 5.19 节中,代码示例可以在 here 找到。

    以下是这种方法的优缺点:

    • 专业人士:客户端只需发出一个请求
    • 专业人士:您不会重新计算结果
    • 专业:没有单​​个客户端的等待时间比串行案例增加了
    • Con:您在计算期间占用了一个 VM 线程,这是针对每个客户端的。鉴于您有查看客户,这应该不是问题。
    • 骗局:想出一个清除缓存的好计划可能很棘手

    【讨论】:

    • 谢谢,但我的问题是关于在服务器端执行此操作的利弊。您认为这种方法有什么问题?
    • 我已经更新了我的答案以显示一些优点和缺点。
    • 感谢@Victory。那讲得通。你能想到这个问题的其他解决方案吗?我能想到 2 个(我都不喜欢其中一个): 1. 添加一个代理以位于客户端和服务器之间 2. 在客户端添加一个过滤器。两者都不能消除服务器端并发请求的风险。
    • 我认为代理会更加棘手,因为它需要相同的逻辑而没有相同的范围。过滤器是一个想法,但随后您会要求客户“表现良好”,这不是一个好的假设。恕我直言,它是良好 API 设计的反模式。
    【解决方案2】:

    在开发与多个 REST 服务的集成时为了避免对服务的不必要调用,我们正在接收响应(JSON 字符串)的数据库中创建 现金

    对于每个这样的现金记录,我们保存用于调用网络服务的 params。如果我们有请求,我们会将参数与数据库中的现有参数进行比较。我们仅针对新参数向 REST 发出真正的请求。这对我们来说也是必要的,因为有些请求不是免费的。

    此外,我们还有一个参数,它以小时(或天)显示每条现金记录的验证日期,以便在一段时间后,如果它是很久以前提出的,我们会自动发出真正的请求接收免费信息。

    这种方法是在使用 REST 服务数年之后创建的,它在我们的解决方案中非常有效。

    【讨论】:

      猜你喜欢
      • 2015-06-29
      • 1970-01-01
      • 2015-08-16
      • 2021-05-01
      • 1970-01-01
      • 2014-07-06
      • 1970-01-01
      • 1970-01-01
      • 2021-12-03
      相关资源
      最近更新 更多