首页 > 代码库 > redis性能测试

redis性能测试

  一 测试目的  

  开发需要为了寻求系统最优的解决方案,但是网上关于性能方面的资料并不是很多,没有很明显的数据说明,只是一般的结论性判断不好说什么,所以这里自己重新测试整理了一番.

  二 测试环境

  主机主机ip为...86,系统为64位win7,4g内存,双核2.93GHz,2.94GHz,从机ip为...59,系统为64位win7,6g内存,双核2.93GHz,2.94GHz.

  双机在同一个局域网,开启了密码验证,主从配置通过配置文件直接配置后,从机配置为不可写入.

  开发工具为Eclipse Indigo Service Release 1,java环境为32位java1.6 .Redis为Redis-x64-3.0.504版本,redis架包为jedis-2.9.0.jar.

  三 开始测试

  3.1 一般测试

  3.1.1 测试方法:

  直接手动操作,针对redis进行各种状况的模拟.主要涉及到的工具有redis,management tool for redis.cmd窗口.

  3.1.2 测试过程:

  主从均关闭,开启主redis导入少量数据到主redis,开启从redis,从redis有一样的数据.
  主从均关闭,开启从redis,删除少量数据到从redis(management tool for redis),开启主redis,主redis数据不变化,刷新从,从redis恢复原来的数据.
  主从均开启,操作部分数据到主redis,从redis有同样的数据,
  主从均开启,删除部分数据(management tool for redis)到从redis,主redis原有数据不会变动,再次刷新从redis发现更改未生效,cmd操作从机发现无法进行写入,
  主从均开启,主导入部分数据之后从有同样数据,关闭主之后再次开启,主的数据恢复.
  主从均开启,主导入部分数据之后从有同样数据,关闭从之后再次开启,从的数据恢复.
  主从均开启,主导入部分数据之后从有同样数据,关闭主之后,删除本地文件dump.rdb,然后主再次开启,主的数据没有,从的数据直接同步为主的没有数据状态,cmd操作从机发现无法进行写入.
  主从均开启,主导入部分数据之后从有同样数据,关闭从之后,删除本地文件dump.rdb,再次开启从,从的数据恢复.

  3.1.3 测试结论:

  主机开启之后,首先从dump文件恢复数据,之后会不定期同步数据到磁盘的dump.rbd文件,关闭之后再起开启会再次直接从dump恢复数据,如果没有这个文件会造成数据清空的状况.

  从开启之后,会从dump文件回复数据,之后查找网络的主机,找到之后进行一个备份编码的对比,如果相同就进行局部同步,不同就进行全同步--即发送全同步请求之后,直接获取到从机的dump文件,之后直接清空从机的数据之后从文件恢复.

  3.2代码测试

  3.2.1 写入数据测试

  3.2.1.1 操作方法

  通过写程序对数据的作进行写入操作并进行分析.

  3.2.1.2 操作代码

  直接通过jedis代码一个个写入数据:

private static void EngineDataCreat() {        Jedis jedis = new Jedis(rip, rport);        jedis.auth(rpassword);        System.out.println("Server is running: " + jedis.ping()                + " Start to write!");        jedis.flushAll();        MyTimeUtil mt = new MyTimeUtil();        for (int j = 0; j < 1; j++) { //写入的次数,多次以求取平均值            mt.start();            for (int i = 0; i < 1000; i++) {                for (PlanProprity e : PlanProprity.values()) {                    jedis.set("China_beijing_plane:" + i + ":" + e,                            " " + mt.getTime());                }            }            for (int i = 0; i < 1000; i++) {                for (CarProprity e : CarProprity.values()) {                    jedis.set("China_hubei_car:" + i + ":" + e,                            " " + mt.getTime());                }            }
       mt.endAndDisp(); } System.out.println(
"Server is running: " + jedis.ping() + "Write finished!"); }

  直接通过jedis管道进行数据的批量写入:

private static void EngineDataCreatByPipe() {        Jedis jedis = new Jedis(rip, rport);        jedis.auth(rpassword);        System.out.println("Server is running: " + jedis.ping()                + " Start to write!");        jedis.flushAll();        MyTimeUtil mt = new MyTimeUtil();                for (int j = 0; j < 1; j++) {            mt.start();            Pipeline pipeline = jedis.pipelined();                        for (int i = 0; i < 1000; i++) {                for (PlanProprity e : PlanProprity.values()) {                    pipeline.set("China_beijing_plane:" + i + ":" + e,                            " " + mt.getTime());                }            }            for (int i = 0; i < 1000; i++) {                for (CarProprity e : CarProprity.values()) {                    pipeline.set("China_hubei_car:" + i + ":" + e,                            " " + mt.getTime());                }            }            pipeline.syncAndReturnAll();            mt.endAndDisp();                    }        System.out.println("Server is running: " + jedis.ping()                + "Write finished!");    }

  上面的那个计时的类是自己写的一个工具,可以参考下:

   http://www.cnblogs.com/wangkun1993/p/7199146.html 自写时间小工具类

  rip就是主机和从机的ip号,rport是端口好,rpassword是验证的密码.

  遍历的两个是两个大小为十的枚举类型:

  

  enum PlanProprity {        PSpeed, PPrice, PLength, PHeight, PWidth, PCapacity, PMore1, PMore2, PMore3, PMore4    };    enum CarProprity {        CSpeed, CPrice, CMOre1, CMOre2, CMOre3, CMOre4, CMOre5, CMOre6, CMOre7, CMOre    }

 

   3.2.1.3 操作结果

  主单个写入10000条数据耗时:  24454ms 28491ms 45811ms 38017ms 22528ms 17845ms 18502ms 18079ms

  主通过管道一次写入10000数据耗时: 388ms 503ms 1288ms 922ms 419ms 341ms 342ms 325ms
  写入20w数据4356ms
  写入200w数据34121ms
  从机无法写入数据.
  从更改为主后测试远程写入数据:
  从单个写入10000条数据耗时 6528ms 26953ms 32541ms 24982ms 22493ms 29789ms 31062ms
  从通过管道一次写入10000数据耗时 227ms 753ms 599ms 387ms 508ms 531ms 507ms

  3.2.1.4 结果分析

  通过对比发现数据的写入速度通过管道实现效率得到了极大的提升,电脑的处理速度和网络的连通率对于远程操作的影响还是比较大的.

  3.2.2 读取数据测试

  3.2.2.1 操作方法

  通过代码对redis进行数据的获取操作.

  3.2.2.2 操作代码

  直接通过get函数单个获取数据操作:

private static void getDate() {        Jedis jedis = new Jedis(rip, rport);        jedis.auth(rpassword);        System.out.println("Server is running: " + jedis.ping());        // jedis.flushAll();        MyTimeUtil mt = new MyTimeUtil();        String strSaveDir = "d:\\edata\\";        String fileName = "BAIHEYUAN_HW_"                + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date())                + ".DJ";        // String fileName="BAIHEYUAN_HW_20161122_0030.DJ";        MyFileUtil mf = new MyFileUtil();        String fileContent = null, tcont = null;        String dateType = "China_beijing_plane";        System.out.println("Start to get data");        for (int j = 0; j < 1; j++) {            fileContent = null;            mt.start();            for (int i = 0; i < 1000; i++) {                for (PlanProprity e : PlanProprity.values()) {                    tcont = jedis.get(dateType + ":" + i + ":" + e);                    // fileContent += dateType+":" + i + ":\t" + e + tcont                    // + "\r\n";                }            }            mt.end();            mt.disp();            // if(mf.existsDictionary(strSaveDir + fileName)){            // mf.createFile(strSaveDir + fileName, fileContent);            // }        }        System.out.println("Get data end!");        System.out.println("Server is running: " + jedis.ping());    }

 

  通过管道进行批量操作:

private static void getDateByPipe() {        Jedis jedis = new Jedis(rip, rport);        jedis.auth(rpassword);        System.out.println("Server is running: " + jedis.ping());        // jedis.flushAll();        MyTimeUtil mt = new MyTimeUtil();        String strSaveDir = "d:\\edata\\";        String fileName = "BAIHEYUAN_HW_"                + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date())                + ".DJ";        // String fileName="BAIHEYUAN_HW_20161122_0030.DJ";        MyFileUtil mf = new MyFileUtil();        String fileContent = null;        Response<String> tcont = null;        String dateType = "China_beijing_plane";        System.out.println("Start to get data");        for (int j = 0; j < 1; j++) {            fileContent = null;            mt.start();            Pipeline pipeline = jedis.pipelined();            for (int i = 0; i < 100; i++) {                for (PlanProprity e : PlanProprity.values()) {                    tcont = pipeline.get("China_beijing_plane:" + i + ":" + e);                    fileContent += dateType + ":" + i + ":\t" + e + tcont                            + "\r\n";                }            }            pipeline.syncAndReturnAll();            mt.end();            mt.disp();            if (mf.existsDictionary(strSaveDir + fileName)) {                mf.createFile(strSaveDir + fileName, fileContent);            }        }        System.out.println("Get data end!");        System.out.println("Server is running: " + jedis.ping());    }

  上面的代码中除了获取数据之外,另外还有一个导出数据到字符串和一个导出到文本的操作,后面发现这两个操作大大影响了时间效率,因此作为对比,进行了注释之后的二次测试.

  如果对于文件类比较感兴趣可以参考下我写的一个工具类: http://www.cnblogs.com/wangkun1993/p/7199326.html 自写文件小工具类

  3.2.2.3 操作结果

  主获取数据测试:
  单个获取10000条数据时间:64704ms
    去掉写数据操作 19356ms 20747ms 17678ms 20170ms
  单个获取1000条数据时间:3202ms 2432ms 1791ms 2857ms 2218ms 2107ms
    去掉写数据操作 1255ms 1267ms 1570ms 1408ms 1137ms
  单个获取100条数据时间:186ms
    去掉写数据操作 169ms 180ms 236ms 218ms
  批量获取10000条数据时间:31367ms 31749ms 23582ms
    去掉写数据操作 367ms 308ms 375ms
  批量获取1000条数据时间:171ms 215ms 208ms 226ms 248ms 199ms 185ms 177ms
    去掉写数据操作 86ms 62ms 45ms


  从获取数据测试:
  单个获取1000条数据时间:1675ms 826ms 691ms 667ms 1112ms 1930ms 614ms
    去掉写数据操作 955ms 818ms 959ms 1007ms 1187ms 338ms 494ms
  单个获取100条数据时间:66ms 44ms 46ms
    去掉写数据操作 121ms 137ms 101ms
  批量个获取10000条数据时间:29965ms 30986ms 22533ms
    去掉写数据操作 363ms 323ms 360ms
  批量获取1000条数据时间:174ms 145ms 135ms
    去掉写数据操作 55ms 27ms 12ms

  3.2.2.4 结果分析

  从上面的数据可以看到,通过管道获取数据想效率比一般获取数据要高的多,因此数据量比较多的时候显然管道操作是比较合适的,如果只是几个数据的操作,一般两种方式都行了.

  对于操作的时候如果进行一些文件的导出操作,可以看到完成的时间是大大增加了,因此如果需要在获取数据之后进行一些其他的操作,最好认真斟酌一下,可以在数据获取完毕之后直接从内存中读取数据,进行一系列的操作.  

  3.2.3 恢复数据测试

   3.2.3.1 操作方法

  通过代码,针对操作之后恢复数据的时间进行一个判断,

  3.2.3.2 操作代码

private static void testRecovery() {        Jedis jedis = new Jedis(rip, rport);        long t = 0;        boolean tag=true;        for (int i = 0; i < 1;) {            try {                                String ttt = null;                if ("OK" .equals(jedis.auth(rpassword))&&tag==true) {                    t = System.currentTimeMillis();                    System.out.println(System.currentTimeMillis() - t+" OK");//break;                    tag=false;                }                if ("PONG".equals(jedis.ping())) {                    System.out.println(System.currentTimeMillis() - t+" PONG");//break;                }                if (jedis.dbSize() >= 20000) {                    System.out.println((System.currentTimeMillis() - t)+" all data");                    break;                }            } catch (Exception e) {                // TODO: handle exception                System.out.println("test");            }        }        System.out.println(System.currentTimeMillis() - t+" all out");    }

  代码没有什么特殊的地方,直接运行就行了,运行之后才打开redis进行恢复操作,从文件恢复的时间太短,不好统计,直接取的它自己显示的数字,主要测试的是远程服务器传输数据需要话费的时间.

  3.2.3.3 操作结果

  主恢复数据测试(2w数据880kb)
    直接dump文件恢复(s) 0.044 0.049 0.047
    测试20w(2.89m)恢复时间) 0.15s
    删除主机备份文件无法恢复.
  从恢复数据测试(2w数据880kb)
    直接dump文件恢复(s) 0.40 0.039 0.040 0.039
    删除从机备份文件之后网络获取文件回复
    2w数据3.35s 3.40s

  3.2.3.4 结果分析 

  从结果来看,影响恢复速度的因素主要是网络的问题,从文件恢复几乎可以在秒级完成,可以忽略不计,当然需要看情况啦,至少我边项目不需要考虑从文件恢复的时间.恢复的速度还是比较满意的,测试数据时候的因为是内部网络,所以这个值不好做评判参考类.

  目前测试就这些,后续可能继续进行其他测试,会继续修改这个博客.

   个人原创,转载请注明出处.

  欢迎指出不足之处以作改进.

 

  

 

redis性能测试