jjzjj

java - 如何在Redis中最有效地调用INCRBY和EXPIRE

coder 2023-07-18 原文

对于Redis中可能存在或可能不存在的聚合对象的集合,我想在它们上调用INCRBY和EXPIRE。根据我的阅读,似乎使用MULTIEVAL是可行的方法。在聚合对象上执行INCRBYEXPIRE操作之后,我需要获取从INCRBY操作返回的每个聚合的更新计数。我正在使用Lettuce客户端,并正在寻找如何最好地执行此操作的示例。为简单起见,假设聚合对象类似于:

public class Aggregate {
  private String id; // key in Redis
  private Long count; // INCRBY operates on
}

最佳答案

好吧,很难给您一个确定的答案,因为结果将在很大程度上取决于多个因素:

  • 网络延迟。数据往返通常比处理本身要长得多。而且,如果您需要n命令,则这些时间会成倍增加。
  • 线程数。它们不会帮助您解决延迟问题,但可以使您的连接饱和,并为您提供大量吞吐量。
  • 需要原子性。当您只调用incrby,然后再调用编写者的expire和读者的get时,最糟糕的事情可能是...什么都没有,我想。但是,如果还有其他修改但未过期的读者,那么您可能会错误地过期(writer1> incrby,writer2> set,writer1> expire)。如果确定只有第一类编写器,则可以节省原子性。

  • 另外,您可能需要针对吞吐量或延迟进行优化。并专门针对您的环境。如您将在后面看到的,在不同的设置中将出现不同的方法。

    竞争者

    原子的
  • EVAL(incrby,到期)。我们发布一个完成任务的Lua脚本。优点:Redis保证Lua的原子性。缺点:我们需要反复发送脚本主体。
  • EVAL(获取,setex)。相同,但是我们可以使用不同的命令来完成工作。在基准测试末尾将用“gs”来称呼它们。
  • EVALSHA。我们可以先加载脚本主体,然后仅发送其摘要。优点:命令中的字节较少。缺点:需要确保没有人突然对您的脚本进行SCRIPT FLUSH编码,而且使用大量脚本的时间可能会增加。我希望这是一个明显的胜利者,但是脚本很小,不会给连接带来负担。
  • MULTI。我们可以在事务中发出命令。这次Redis将上演它们,直到您发出EXEC为止。这是一个很大的开销,并且仅出于完整性考虑而留在这里。

  • 非原子的
  • 天真。我们可以只发出一个命令,然后发出另一个命令。优点:简单的代码。
  • 异步。我们可以利用luttuce的异步API来跳过等待EXPIRE的结果。优点:感觉很聪明。
  • Async_flush。我们可以尝试进一步优化并利用command pipelining。优点:节省带宽,但仅适用于大批量。缺点:您需要专用的连接并进行相应的初始化。

  • 基准

    这是the code

    您确实应该自己运行它以优化您的需求。我注意到代码中定义的某些选项被忽略,因此请使用命令行参数。

    单线

    不过,我将发布结果。我用1个线程为3种不同的连接类型运行了它:本地unix套接字,本地TCP,远程TCP。不幸的是,远程主机的CPU单线程性能要弱得多,因此我必须将其本地结果发布以供引用。不幸的是,此 Remote 上有很多东西正在运行,因此其结果可能会受到影响。
    Benchmark                          (address)   Mode  Cnt      Score      Error  Units
    RedisBatchesBenchmark.async        socket     thrpt   50  39722.167 ±  796.830  ops/s
    RedisBatchesBenchmark.async_flush  socket     thrpt   50  37973.392 ±  239.880  ops/s
    RedisBatchesBenchmark.evalsha      socket     thrpt   50  35697.480 ±  216.258  ops/s
    RedisBatchesBenchmark.eval         socket     thrpt   50  34616.848 ±  238.412  ops/s
    RedisBatchesBenchmark.evalshags    socket     thrpt   50  32642.795 ±  129.305  ops/s
    RedisBatchesBenchmark.evalgs       socket     thrpt   50  31679.147 ±  150.264  ops/s
    RedisBatchesBenchmark.naive        socket     thrpt   50  20935.985 ±  124.092  ops/s
    RedisBatchesBenchmark.multi        socket     thrpt   50  19133.523 ±   72.581  ops/s
    
    RedisBatchesBenchmark.async        localhost  thrpt   50  39179.742 ± 1457.819  ops/s
    RedisBatchesBenchmark.async_flush  localhost  thrpt   50  33647.195 ±  295.427  ops/s
    RedisBatchesBenchmark.evalsha      localhost  thrpt   50  30679.493 ±  109.669  ops/s
    RedisBatchesBenchmark.eval         localhost  thrpt   50  29680.750 ±  161.762  ops/s
    RedisBatchesBenchmark.evalshags    localhost  thrpt   50  28069.431 ±  158.887  ops/s
    RedisBatchesBenchmark.evalgs       localhost  thrpt   50  27142.783 ±   69.314  ops/s
    RedisBatchesBenchmark.naive        localhost  thrpt   50  17934.587 ±  152.859  ops/s
    RedisBatchesBenchmark.multi        localhost  thrpt   50  15220.863 ±   32.219  ops/s
    
    RedisBatchesBenchmark.evalsha      remote     thrpt   50   4001.585 ±   12.200  ops/s
    RedisBatchesBenchmark.evalgs       remote     thrpt   50   3966.271 ±   16.590  ops/s
    RedisBatchesBenchmark.async_flush  remote     thrpt   50   3867.448 ±  153.232  ops/s
    RedisBatchesBenchmark.eval         remote     thrpt   50   3622.256 ±  246.454  ops/s
    RedisBatchesBenchmark.evalshags    remote     thrpt   50   3607.975 ±  251.802  ops/s
    RedisBatchesBenchmark.async        remote     thrpt   50   2681.453 ±   13.451  ops/s
    RedisBatchesBenchmark.naive        remote     thrpt   50   2014.806 ±    5.630  ops/s
    RedisBatchesBenchmark.multi        remote     thrpt   50   1344.477 ±    3.375  ops/s
    ------------
    Remote host:
    Benchmark                          (address)   Mode  Cnt      Score      Error  Units
    RedisCommandPacking.naive          socket     thrpt   25  11605,994 ±  368,055  ops/s
    RedisCommandPacking.naive          localhost  thrpt   25   9477,190 ±  239,817  ops/s
    

    我们在这里看到什么?
  • 不等待过期结果很快,但是当我们添加延迟时(仅
    0.194ms ping)EVALSHA优先。请注意,即使最小延迟也有多少会影响这种快速操作的性能。即使考虑到较慢的CPU,我们也损失了5倍。
  • 两个命令不足以从手动冲洗中获得提升(但
    请注意,我们不等待过期结果。如果我们可能会有所不同
    将)。
  • 该脚本体足够小,可以与摘要竞争。
  • incrby + expire比get + setex更好。
  • Multi位于底部。
  • 异步的错误值非常高,这意味着调用之间的性能差异很大。当您考虑最大延迟时,这不是一件好事。

  • 两个线程
    Benchmark                       (address)      Mode  Cnt      Score      Error  Units
    RedisBatchesBenchmark.async_flush  socket     thrpt   50  97904.168 ± 2497.354  ops/s
    RedisBatchesBenchmark.async        socket     thrpt   50  95156.162 ± 1556.060  ops/s
    RedisBatchesBenchmark.evalsha      socket     thrpt   50  66418.081 ± 1236.815  ops/s
    RedisBatchesBenchmark.eval         socket     thrpt   50  63202.798 ± 1807.753  ops/s
    RedisBatchesBenchmark.evalshags    socket     thrpt   50  55259.215 ± 1771.674  ops/s
    RedisBatchesBenchmark.evalgs       socket     thrpt   50  54047.418 ± 1143.995  ops/s
    RedisBatchesBenchmark.naive        socket     thrpt   50  37771.010 ± 1378.210  ops/s
    
    RedisBatchesBenchmark.async        localhost  thrpt   50  71901.709 ± 1041.603  ops/s
    RedisBatchesBenchmark.async_flush  localhost  thrpt   50  66513.162 ± 1353.913  ops/s
    RedisBatchesBenchmark.evalsha      localhost  thrpt   50  52052.253 ± 1087.449  ops/s
    RedisBatchesBenchmark.eval         localhost  thrpt   50  50806.715 ± 1220.019  ops/s
    RedisBatchesBenchmark.evalshags    localhost  thrpt   50  47248.272 ± 1096.685  ops/s
    RedisBatchesBenchmark.evalgs       localhost  thrpt   50  44633.113 ± 1829.829  ops/s
    RedisBatchesBenchmark.naive        localhost  thrpt   50  35757.586 ± 1455.315  ops/s
    
    RedisBatchesBenchmark.eval         remote     thrpt   50   4030.373 ±   19.535  ops/s
    RedisBatchesBenchmark.async        remote     thrpt   50   4010.730 ±   19.527  ops/s
    RedisBatchesBenchmark.async_flush  remote     thrpt   50   4004.914 ±   25.449  ops/s
    RedisBatchesBenchmark.evalgs       remote     thrpt   50   3983.623 ±   31.027  ops/s
    RedisBatchesBenchmark.evalshags    remote     thrpt   50   3978.253 ±   51.875  ops/s
    RedisBatchesBenchmark.evalsha      remote     thrpt   50   3949.376 ±   52.273  ops/s
    RedisBatchesBenchmark.naive        remote     thrpt   50   2015.643 ±   17.920  ops/s
    

    我们在这里看到什么?
  • 异步特别是在unix套接字上获得了很大的提升。
  • 异步现在与远程上的async_flush非常接近。
  • 考虑到复杂性,
  • Async_flush不能盈利。
  • 远程结果非常接近,尤其是考虑到测量误差。
  • 没有MULTI,因为它不能用于共享连接,应该更改基准以使其包含在内。这将增加更多的开销,因此不会这样做。
  • 关于java - 如何在Redis中最有效地调用INCRBY和EXPIRE,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48359548/

    有关java - 如何在Redis中最有效地调用INCRBY和EXPIRE的更多相关文章

    1. ruby - 如何在 Ruby 中顺序创建 PI - 2

      出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

    2. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

      如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

    3. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

      我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

    4. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

      exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

    5. ruby - 如何在续集中重新加载表模式? - 2

      鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

    6. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

      我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

    7. ruby - 如何在 Lion 上安装 Xcode 4.6,需要用 RVM 升级 ruby - 2

      我实际上是在尝试使用RVM在我的OSX10.7.5上更新ruby,并在输入以下命令后:rvminstallruby我得到了以下回复:Searchingforbinaryrubies,thismighttakesometime.Checkingrequirementsforosx.Installingrequirementsforosx.Updatingsystem.......Errorrunning'requirements_osx_brew_update_systemruby-2.0.0-p247',pleaseread/Users/username/.rvm/log/138121

    8. java - 等价于 Java 中的 Ruby Hash - 2

      我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

    9. ruby - 如何进行排列以有效地定制输出 - 2

      这是一道面试题,我没有答对,但还是很好奇怎么解。你有N个人的大家庭,分别是1,2,3,...,N岁。你想给你的大家庭拍张照片。所有的家庭成员都排成一排。“我是家里的friend,建议家庭成员安排如下:”1岁的家庭成员坐在这一排的最左边。每两个坐在一起的家庭成员的年龄相差不得超过2岁。输入:整数N,1≤N≤55。输出:摄影师可以拍摄的照片数量。示例->输入:4,输出:4符合条件的数组:[1,2,3,4][1,2,4,3][1,3,2,4][1,3,4,2]另一个例子:输入:5输出:6符合条件的数组:[1,2,3,4,5][1,2,3,5,4][1,2,4,3,5][1,2,4,5,3][

    10. ruby-on-rails - 如何在 ruby​​ 交互式 shell 中有多行? - 2

      这可能是个愚蠢的问题。但是,我是一个新手......你怎么能在交互式ruby​​shell中有多行代码?好像你只能有一条长线。按回车键运行代码。无论如何我可以在不运行代码的情况下跳到下一行吗?再次抱歉,如果这是一个愚蠢的问题。谢谢。 最佳答案 这是一个例子:2.1.2:053>a=1=>12.1.2:054>b=2=>22.1.2:055>a+b=>32.1.2:056>ifa>b#Thecode‘if..."startsthedefinitionoftheconditionalstatement.2.1.2:057?>puts"f

    随机推荐