JVM。在Clojure中使用全局atom作为应用程序的缓存存储 - 是否合适?

问题描述 投票:0回答:1

我有一个 高负荷 应用,很多用户用各种GET参数来请求。想象一下,对不同的投票给出不同的答案。保存投票,显示最新投票结果。

为了缓解背压问题,我在考虑创建一个顶层原子来存储所有投票的最新投票结果。

所以工作流程是这样的。

  1. 启动一个应用程序 => 应用程序拉入最新的投票结果并填充原子。

  2. 新的请求进来 => 在该原子中为特定的投票增加投票计数器,将投票有效载荷添加到core.async队列监听器(在一个单独的线程中工作),最终将其持久化到数据库中。

我想实现的目标是

每一个新的请求都能得到最新的投票结果,并且有近乎即时的响应时间(避免网络调用持久化存储)。

这种方法有一个明显的缺点,就是万一我们需要重新部署,会造成一些暂时的数据损失。这不是很关键,部署可能会被推迟。

我之所以对这种棘手的方法感兴趣,而不仅仅是使用RabbitMQKafka,是因为它听起来像一个非常酷和简单的架构,只有很少的 "移动部件"(只有JVM +数据库)来完成工作。

clojure architecture jvm high-load
1个回答
1
投票

更多的数据总是好的。 让我们在原子中增时一个计数器。

(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test)
  (:require
    [criterium.core :as crit]))

(def cum (atom 0))

(defn incr []
  (swap! cum inc))

(defn timer []
  (spy :time
    (crit/quick-bench
      (dotimes [ii 1000] incr))))

(dotest
  (timer))

用结果

-------------------------------
   Clojure 1.10.1    Java 14
-------------------------------

Testing tst.demo.core
Evaluation count : 1629096 in 6 samples of 271516 calls.
             Execution time mean : 328.476758 ns
    Execution time std-deviation : 37.482750 ns
   Execution time lower quantile : 306.738888 ns ( 2.5%)
   Execution time upper quantile : 393.249204 ns (97.5%)
                   Overhead used : 1.534492 ns

所以1000个电话 incr 只需要330 ns左右。 需要多长时间才能ping到 google.com?

PING google.com (172.217.4.174) 56(84) bytes of data.
64 bytes from lax28s01-in-f14.1e100.net (172.217.4.174): icmp_seq=1 ttl=54 time=14.6 ms
64 bytes from lax28s01-in-f14.1e100.net (172.217.4.174): icmp_seq=2 ttl=54 time=14.9 ms
64 bytes from lax28s01-in-f14.1e100.net (172.217.4.174): icmp_seq=3 ttl=54 time=15.0 ms
64 bytes from lax28s01-in-f14.1e100.net (172.217.4.174): icmp_seq=4 ttl=54 time=17.8 ms
64 bytes from lax28s01-in-f14.1e100.net (172.217.4.174): icmp_seq=5 ttl=54 time=16.9 ms

我们称它为15毫秒。 所以比例是。

ratio = 15e-3 / 330e-9  =>  45000x

你对原子的操作会被网络IO时间所淹没 所以在原子中存储应用状态是没有问题的 即使对于大量的用户来说也是如此

你可能也有兴趣知道 Datomic数据库 曾表示,数据库中的并发是由一个原子管理的。

© www.soinside.com 2019 - 2024. All rights reserved.