SpringBoot中RedisTemplate的MGET性能测试及解决办法

项目中遇到了MGET获取10000+数据时超时的问题,然后找到网友的测试结果如下(这里就不再重发测试代码,测试结果一致)

结论

  • 一次操作10个key的性能达到一次操作1个key的88%
  • 一次操作20个key的性能达到一次操作1个key的72%
  • 一次操作50个key的性能达到一次操作1个key的59%
  • 一次操作60个key的性能达到一次操作1个key的53%
  • 一次操作80个key的性能达到一次操作1个key的43%
  • 一次操作100个key的性能大道一次操作1个key的41%
  • 一次操作200个key的性能只能达到一次操作1个key的25%,大约是一次处理100个key的60%
  • 一次操作500个key的性能只能达到一次操作1个key的11%,大约是一次处理100个key的28%
  • 一次操作800个key的性能只能达到一次操作1个key的7%,大约是一次处理100个key的17%
  • 当key数目在10以内时,mget性能下降趋势非常小,性能基本上能达到redis实例的极限
  • 当key数目在10~100之间时,mget性能下降明显,需要考虑redis性能衰减对系统吞吐的影响
  • 当key数目在100以上时,mget性能下降幅度趋缓,此时redis性能已经较差,不建议使用在OLTP系统中,或者需要考虑其他手段来提升性能。

解决办法及测试结果(上代码看结果)

 

package cn.hs;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.HashSet;
import java.util.Set;

@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisGetTests {
    private static final String TYPE_NAME = RedisGetTests.class.getTypeName();

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Test
    public void contextLoads() {
        Set<String> keySet = new HashSet<>();
        for (int i = 0; i < 100000; i++) {
            String key = TYPE_NAME + ":" + i;
            keySet.add(key);
        }

        long time = System.currentTimeMillis();
        multiGet(keySet);
        System.out.println("redisTemplate.opsForValue().multiGet \t 耗时:" + (System.currentTimeMillis() - time));

//        排除,太慢了
//        time = System.currentTimeMillis();
//        getData(keySet);
//        System.out.println("redisTemplate.opsForValue().get \t\t 耗时:" + (System.currentTimeMillis() - time));
// 推荐
        time = System.currentTimeMillis();
        getDataByPipelined(keySet);
        System.out.println("redisTemplate.executePipelined \t\t\t 耗时:" + (System.currentTimeMillis() - time));
    }

    private void multiGet(Set<String> keySet) {
        redisTemplate.opsForValue().multiGet(keySet);
    }

    private void getData(Set<String> keySet) {
        for (String key : keySet) {
            redisTemplate.opsForValue().get(key);
        }
    }

    private void getDataByPipelined(Set<String> keySet) {
        redisTemplate.executePipelined((RedisCallback<Object>) redisConnection -> {
            for (String key : keySet) {
                redisConnection.get(key.getBytes(StandardCharsets.UTF_8));
            }
            return null;
        });
    }

}

输出结果

redisTemplate.opsForValue().multiGet      耗时:422
redisTemplate.executePipelined            耗时:177

 

推荐方式

    private void getDataByPipelined(Set<String> keySet) {
        redisTemplate.executePipelined((RedisCallback<Object>) redisConnection -> {
            for (String key : keySet) {
                redisConnection.get(key.getBytes(StandardCharsets.UTF_8));
            }
            return null;
        });
    }

 

posted on 2021-12-15 11:59  小小程序员的梦想  阅读(3251)  评论(0编辑  收藏  举报

导航