栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

在redis中使用管道时,为什么有100,000条记录这么慢?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

在redis中使用管道时,为什么有100,000条记录这么慢?

在编写此类基准测试(尤其是使用JVM的基准测试)之前,需要注意以下几点:

  • 在大多数(物理)机器上,使用流水线操作时,Redis能够处理超过100K ops / s。您的基准测试仅处理10万个项目,因此持续时间不足以产生有意义的结果。此外,JIT的后续阶段没有时间开始。

  • 绝对时间不是一个非常相关的指标。在保持基准至少运行10秒的同时显示吞吐量(即每秒的操作数)将是一个更好,更稳定的指标。

  • 您的内部循环会产生大量垃圾。如果您打算对Jedis + Redis进行基准测试,则需要将自己程序的开销保持在较低水平。

  • 因为您已将所有内容定义到main函数中,所以JIT不会编译您的循环(取决于您使用的JVM)。只能是内部方法调用。如果希望JIT高效,请确保将代码封装到JIT可以编译的方法中。

  • (可选)您可能希望在执行实际测量之前添加一个预热阶段,以避免考虑使用准系统解释器运行第一次迭代的开销以及JIT本身的成本。

现在,关于Redis管道,您的管道太长了。流水线中的100K命令意味着Jedis必须先构建6MB缓冲区,然后再向Redis发送任何内容。这意味着套接字缓冲区(在客户端,甚至在服务器端)将饱和,并且Redis也必须处理6
MB的通信缓冲区。

此外,您的基准测试仍然是同步的(使用管道不会神奇地使其异步)。换句话说,在管道的最后一个查询发送到Redis之前,Jedis不会开始阅读答复。当管道太长时,它有可能阻塞事物。

考虑将管道的大小限制为100-1000个操作。当然,它将产生更多的往返,但是通信堆栈上的压力将降低到可接受的水平。例如,考虑以下程序:

import redis.clients.jedis.*;import java.util.*;public class TestPipeline {        int i = 0;     Map<String, String> map = new HashMap<String, String>();    ShardedJedis jedis;    // Number of iterations    // Use 1000 to test with the pipeline, 100 otherwise    static final int N = 1000;    public TestPipeline() {      JedisShardInfo si = new JedisShardInfo("127.0.0.1", 6379);      List<JedisShardInfo> list = new ArrayList<JedisShardInfo>();      list.add(si);      jedis = new ShardedJedis(list);    }    public void push( int n ) {     ShardedJedisPipeline pipeline = jedis.pipelined();     for ( int k = 0; k < n; k++) {      map.put("id", "" + i);      map.put("name", "lyj" + i);      pipeline.hmset("m" + i, map);      ++i;     }     pipeline.sync();     }    public void push2( int n ) {     for ( int k = 0; k < n; k++) {      map.put("id", "" + i);      map.put("name", "lyj" + i);      jedis.hmset("m" + i, map);      ++i;     }    }    public static void main(String[] args) {      TestPipeline obj = new TestPipeline();      long startTime = System.currentTimeMillis();      for ( int j=0; j<N; j++ ) {       // Use push2 instead to test without pipeline       obj.push(1000);        // Uncomment to see the acceleration       //System.out.println(obj.i);     }     long endTime = System.currentTimeMillis();     double d = 1000.0 * obj.i;     d /= (double)(endTime - startTime);     System.out.println("Throughput: "+d);   } }

使用此程序,您可以进行流水线测试或不进行流水线测试。使用流水线操作时,请确保增加迭代次数(N参数),以使其运行至少10秒钟。如果您在循环中取消注释println,您将意识到该程序在开始时很慢,并且在JIT开始进行优化时会变得更快(这就是为什么程序应该运行至少几秒钟才能得出有意义的结果)。

在我的硬件(旧的Athlon盒)上,使用管道时,吞吐量可以提高8-9倍。通过优化内部循环中的键/值格式并添加预热阶段,可以进一步改善该程序。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/371780.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号