redis 写操作性能测试 (单机)

来源:互联网 发布:怎么选购加湿器知乎 编辑:程序博客网 时间:2024/05/16 11:44

redis 写操作性能测试 (单机版)

测试目的

  • 熟悉jedis操作redis
  • 对redis大量写操作性能指标有个大概认知

测试环境

  • ubuntu
  • 机器双核4G内存普通机
  • 外网流量4M
  • redis版本: 3.2.6
  • redis 和测试服务程序在一台服务器上

redis 配置

  • 添加密码
  • 注释了bind:127.0.0.1,
  • maxmemory 3gb

遇到问题

问题一

再插入300万数据的时候,报错

// redis 日志文件2670:M 13 Dec 17:30:53.061 * 10 changes in 300 seconds. Saving...2670:M 13 Dec 17:30:53.061 # Can't save in background: fork: Cannot allocate memory// redis-cli 127.0.0.1:6379> 127.0.0.1:6379> flushdb(error) MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.127.0.0.1:6379

解决方式

// 引用 http://www.cnblogs.com/qq78292959/p/3994341.html在小内存的进程上做一个fork,不需要太多资源,但当这个进程的内存空间以G为单位时,fork就成为一件很恐怖的操作。何况在16G内存的主机上fork 14G内存的进程呢?肯定会报内存无法分配的。更可气的是,越是改动频繁的主机上fork也越频繁,fork操作本身的代价恐怕也不会比假死好多少。找到原因之后,直接修改内核参数vm.overcommit_memory = 1Linux内核会根据参数vm.overcommit_memory参数的设置决定是否放行。1. 如果 vm.overcommit_memory = 1,直接放行2.vm.overcommit_memory = 0:则比较 此次请求分配的虚拟内存大小和系统当前空闲的物理内存加上swap,决定是否放行。3.vm.overcommit_memory = 2:则会比较 进程所有已分配的虚拟内存加上此次请求分配的虚拟内存和系统当前的空闲物理内存加上swap,决定是否放行。Arch linux设置vm.overcommit_memory 方法永久性修改内核参数在/etc/sysctl.conf文件里面加入或者直接删除也可以,因为它缺省值就是0vm.overcommit_memory = 0运行使之生效#sysctl -p

测试思路

分别对redis 进行100万 200 万 300万数据量的插入,分别统计花费的时间

测试结果

日志信息

====================================================---------开始时间--------------结束时间-------------插入条数-----使用时间(毫秒)-----吞吐量--------测试运行线程数量--------单客户端并发量-------每个消息的大小-2016-12-13 16:56:22---2016-12-13 16:56:44------1000000------21791------45890-----------4-----------11472--------748byte--------------开始时间--------------结束时间-------------插入条数-----使用时间(毫秒)-----吞吐量--------测试运行线程数量--------单客户端并发量-------每个消息的大小-2016-12-13 17:15:23---2016-12-13 17:16:07------2000000------43802------45660-----------4-----------11415--------748byte--------------开始时间--------------结束时间-------------插入条数-----使用时间(毫秒)-----吞吐量--------测试运行线程数量--------单客户端并发量-------每个消息的大小-2016-12-13 18:23:47---2016-12-13 18:24:57------3000000------70256------42700-----------4-----------10675--------748byte-------------开始时间--------------结束时间-------------插入条数-----使用时间(毫秒)-----吞吐量--------测试运行线程数量--------单客户端并发量-------每个消息的大小-2016-12-13 18:33:53---2016-12-13 18:34:21------1000000------28133------35545-----------2-----------17772--------748byte--------------开始时间--------------结束时间-------------插入条数-----使用时间(毫秒)-----吞吐量--------测试运行线程数量--------单客户端并发量-------每个消息的大小-2016-12-13 18:31:34---2016-12-13 18:32:32------2000000------57970------34500-----------2-----------17250--------748byte--------------开始时间--------------结束时间-------------插入条数-----使用时间(毫秒)-----吞吐量--------测试运行线程数量--------单客户端并发量-------每个消息的大小-2016-12-13 18:27:37---2016-12-13 18:29:02------3000000------85097------35253-----------2-----------17626--------748byte--------------开始时间--------------结束时间-------------插入条数-----使用时间(毫秒)-----吞吐量--------测试运行线程数量--------单客户端并发量-------每个消息的大小-2016-12-13 18:36:01---2016-12-13 18:36:21------1000000------20085------49788-----------6-----------8298--------748byte--------------开始时间--------------结束时间-------------插入条数-----使用时间(毫秒)-----吞吐量--------测试运行线程数量--------单客户端并发量-------每个消息的大小-2016-12-13 18:37:43---2016-12-13 18:38:25------2000000------41571------48110-----------6-----------8018--------748byte--------------开始时间--------------结束时间-------------插入条数-----使用时间(毫秒)-----吞吐量--------测试运行线程数量--------单客户端并发量-------每个消息的大小-2016-12-13 18:39:25---2016-12-13 18:40:30------3000000------65840------45565-----------6-----------7594--------748byte-----

结果分析

  • 100万条数据(700M)插入redis只需最少时间20s, 200万条数据最少41秒 300万条数据最少65秒
  • 200万数据一下,数据插入效率相当,300万条效率执行效率下降
  • 最高redis插入吞吐量是 4.9W/S
  • 单线程客户端最高吞吐 1.7W/S

结论

300万条执行的效率下降,跟RDB默认策略有关系.

save 900 1save 300 10save 60 10000
  • 本次测试远没有达到redis性能峰值,但保守插入操作在5W/S的并发吞吐。单客户端线程最低1.7W/S.
  • 结合之前redis读取性能测试对比,redis读取效率是写入的1.4倍。

测试代码

package com.jiazq.jizq.redis.mq;import java.text.SimpleDateFormat;import java.util.Date;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.Semaphore;import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicLong;import org.apache.log4j.Logger;import redis.clients.jedis.Jedis;public class RedisWriteTaskSchudler {    private static Logger logger = Logger.getLogger(RedisWriteTaskSchudler.class);    volatile boolean runState = true;    // 开启时间    long startTime = 0;    long endTime = 0;    // 工作线程    Thread[] workers = null;    // 线程数量    int threadNumber = 0;    AtomicLong writeCount = new AtomicLong(ConfigManager.redis_write_count);    // 测试完成判断    public Semaphore semaphore = new Semaphore(1);    // 定时器    ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);    RedisWriteTaskSchudler (int threadNumber) {        // 默认线程数量为硬件内核数的2倍        this.threadNumber = threadNumber;        workers = new Thread[threadNumber];        for (int i = 0; i < threadNumber; i++) {            workers[i] = new Thread(new RedisWriteTask(JedisManager.instance().getJedis()));            workers[i].setDaemon(true);            workers[i].setName(ConfigManager.read_thread_name + "i");        }        executorService.scheduleAtFixedRate(new PrintTimer(), 2, 15, TimeUnit.SECONDS);    }    class PrintTimer implements Runnable {        @Override        public void run() {            // 结束            if (runState == false) {                JedisManager.instance().shutdown();                executorService.shutdown();            }        }    }    /**     *  启动工作线程     * @throws InterruptedException      */    public void start() throws InterruptedException {        for (int i = 0; i < threadNumber; i++) {            workers[i].start();        }        startTime = System.currentTimeMillis();    }    /**     * 关闭线程     */    public void shutdown() {        runState = false;        executorService.shutdown();    }    public synchronized void log() {        if (endTime == 0) {            endTime = System.currentTimeMillis();        } else {            return;        }        StringBuilder sb = new StringBuilder();        SimpleDateFormat format = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");        long _count = ConfigManager.redis_write_count;        long useTime = endTime - startTime;        long throughput = ((_count * 1000) /useTime);        int strLength = ConfigManager.test_string_value.getBytes().length;        sb.append("\n======================================================\n");        sb.append("---------开始时间--------------结束时间-------------插入条数-----使用时间(毫秒)-----吞吐量--------测试运行线程数量--------单客户端并发量-------每个消息的大小\n");        sb.append("-");        sb.append(format.format(new Date(startTime)));        sb.append("---");        sb.append(format.format(new Date(endTime)));        sb.append("------");        sb.append(_count);        sb.append("------");        sb.append(useTime);        sb.append("------");        sb.append(throughput);        sb.append("-----------");        sb.append(threadNumber);        sb.append("-----------");        sb.append(throughput / threadNumber );        sb.append("--------");        sb.append(strLength);        sb.append("byte-----");        logger.error(sb.toString());        logger.error("\n");        semaphore.release();    }    class RedisWriteTask implements Runnable {        private Jedis jedis = null;        RedisWriteTask (Jedis jedis) {            this.jedis = jedis;        }        @Override        public void run() {            semaphore.tryAcquire();            while (runState) {                try {                    long number = writeCount.decrementAndGet();                    if (number < 0) {                        runState = false;                        log();                        break;                    }                    String writeKey = ConfigManager.test_string_key + number;                    jedis.set(writeKey, ConfigManager.test_string_value);                } catch (Throwable t) {                    logger.error("",t);                    // 连接失败                    if (!jedis.isConnected()) {                        //返回连接池里面                        jedis.close();                        // 重新获取连接                        jedis = JedisManager.instance().getJedis();                    }                }            }            // 返回去jedis pool 里面            jedis.close();        }    }}

详细下载地址:

http://download.csdn.net/detail/jia281460530/9710776

0 0
原创粉丝点击