redis-对象序列化方案比较

与其他NoSql数据库(例如Memecache)不同,Jedis并没有提供默认的序列化工具,这样开发者需要自己引入序列化工具。将对象序列化到Redis中可以选取多种序列化方案,例如Xml,Json,Protobuf,Thrift等

选取FastJson和protostuff进行效率比对

测试方法

  1. 每次生成1000个POJO对象,每个POJO对象中都包含有1个List,List中也包含了1000个POJO对象。
  2. 将生成的1000个POJO对象序列化并存储到Redis中
  3. 从耗时和Redis内存占用两个维度观察不同序列化方案的表现

测试结果

测试 FastJson Protostuff-runtime
耗时(毫秒) 4566 2098
Redis内存占用(MB) 366.43 273.85

Protostuff在耗时上是FastJson的50%左右。

Protostuff在内存占用上是FastJson的75%左右。

可以看出Protostuff在耗时和内存占用上都优于FastJson,但是使用Protostuff序列化后的数据不具有可读性,在选择序列化方案时还是需要根据需求来选择。

下面给出测试步骤与代码

测试步骤与代码

测试代码

测试使用的POM


        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <maven.compiler.source>1.8</maven.compiler.source>
            <maven.compiler.target>1.8</maven.compiler.target>
            <encoding>UTF-8</encoding>
            <protostuff.version>1.0.11</protostuff.version>
            <jedis.version>2.4.2</jedis.version>
            <fastjson.version>1.1.39</fastjson.version>
        </properties>


        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.18</version>
            <scope>provided</scope>
        </dependency>

         <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>${jedis.version}</version>
        </dependency>

        <dependency>
            <groupId>com.dyuproject.protostuff</groupId>
            <artifactId>protostuff-runtime</artifactId>
            <version>${protostuff.version}</version>
        </dependency>
        <dependency>
            <groupId>com.dyuproject.protostuff</groupId>
            <artifactId>protostuff-core</artifactId>
            <version>${protostuff.version}</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>${fastjson.version}</version> 
        </dependency>

测试用的POJO类



import com.alibaba.fastjson.JSON;
import lombok.Data;
import org.apache.commons.lang.math.RandomUtils;

import java.util.*;

/**
 */
@Data
public class Club {

    public static List<Club> buildMore(int clubNum, int memberNum) {
        List<Club> list = new ArrayList<>();
        while (clubNum-- > 0) {
            list.add(buildOne(memberNum));
        }
        return list;
    }

    public static Club buildOne(int memberNum) {
        int id = RandomUtils.nextInt(100000);
        Club club = new Club();
        club.id = id;
        club.name = UUID.randomUUID().toString();
        club.key = UUID.randomUUID().toString();
        club.info = UUID.randomUUID().toString();
        club.createDate = new Date();
        club.rank = id;
        club.memberList = new ArrayList<>(memberNum);
        while (memberNum-- > 0) {
            club.memberList.add(Member.buildOne());
        }

        return club;
    }

    public Club() {
    }

    public Club(String key, int id, String name, String info, Date createDate, int rank, List<Member> memberList) {
        this.key = key;
        this.id = id;
        this.name = name;
        this.info = info;
        this.createDate = createDate;
        this.rank = rank;
        this.memberList = memberList;
    }

    private String key;
    private int id;
    // id
    private String name;
    // 名称
    private String info;
    // 描述
    private Date createDate;
    // 创建日期
    private int rank;
    // 排名

    private List<Member> memberList;

    @Override
    public String toString() {
        return JSON.toJSONString(this);
    }
}


import lombok.Data;

import java.util.Date;
import java.util.UUID;

/**
 */

@Data
public class Member {

    public static Member buildOne() {
        Member member = new Member();

        member.id = UUID.randomUUID().toString();
        member.url = UUID.randomUUID().toString();
        member.payout = UUID.randomUUID().toString();
        member.testStr1 = UUID.randomUUID().toString();
        member.testStr2 = UUID.randomUUID().toString();
        member.testStr3 = UUID.randomUUID().toString();
        member.testStr4 = UUID.randomUUID().toString();
        Date now = new Date();
        member.date1 = now;
        member.date2 = now;

        return member;

    }


    private String id;
    private String url;
    private String payout;
    private String testStr1;
    private String testStr2;
    private String testStr3;
    private String testStr4;
    private String testStr5;
    private Date date1;
    private Date date2;

}

序列化工具类


import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.runtime.RuntimeSchema;
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 */
public enum ProtostuffUtil {
    INS;

    private static Map<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap<Class<?>, Schema<?>>();

    private static Objenesis objenesis = new ObjenesisStd(true);

    private static <T> Schema<T> getSchema(Class<T> clazz) {
        @SuppressWarnings("unchecked")
        Schema<T> schema = (Schema<T>) cachedSchema.get(clazz);
        if (schema == null) {
            schema = RuntimeSchema.getSchema(clazz);
            if (schema != null) {
                cachedSchema.put(clazz, schema);
            }
        }
        return schema;
    }

    /**
     * 序列化
     *
     * @param obj
     * @return
     */
    public static <T> byte[] serialize(T obj) {
        @SuppressWarnings("unchecked")
        Class<T> clazz = (Class<T>) obj.getClass();
        LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
        try {
            Schema<T> schema = getSchema(clazz);
            return ProtostuffIOUtil.toByteArray(obj, schema, buffer);
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        } finally {
            buffer.clear();
        }
    }

    /**
     * 反序列化
     *
     * @param data
     * @param clazz
     * @return
     */
    public static <T> T deserialize(byte[] data, Class<T> clazz) {
        try {
            Schema<T> schema = getSchema(clazz);
            if (schema == null) {
                return null;
            }
            T obj = schema.newMessage();
            ProtostuffIOUtil.mergeFrom(data, obj, schema);
            return obj;
        } catch (Exception e) {
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

}

测试代码


import com.random.procbuf.util.ProtostuffUtil;
import com.random.procbuf.vo.Club;
import redis.clients.jedis.Jedis;

import java.util.List;

/**
 */
public class SerializeTest {

    static Jedis jedis = new Jedis("127.0.0.1", 6379);


    public static void main(String[] args) {
        List<Club> data = Club.buildMore(1000, 1000);
        jedis.flushDB();
        long start = System.currentTimeMillis();
        //分别测试两种序列话方法
        //saveByFastJson(data);
        //saveByProtostuff(data);
        long end = System.currentTimeMillis();
        System.out.println((end - start));
    }

    private static void saveByFastJson(List<Club> clubs) {
        for (Club club : clubs) {
            String key = club.getKey();
            String value = club.toString();
            jedis.set(key, value);
        }
    }


    private static void saveByProtostuff(List<Club> clubs) {
        for (Club club : clubs) {
            String key = club.getKey();
            byte[] data = ProtostuffUtil.serialize(club);
            jedis.set(key.getBytes(), data);
        }
    }
}

查看两种测试方法的Redis内存占用

#查看FastJson的内存占用
127.0.0.1:6379> info Memory
# Memory
used_memory:384226112
used_memory_human:366.43M
used_memory_rss:389435392
used_memory_peak:384959656
used_memory_peak_human:367.13M
used_memory_lua:35840
mem_fragmentation_ratio:1.01
mem_allocator:libc


#查看Protostuff的内存占用
127.0.0.1:6379> info Memory
# Memory
used_memory:287154216
used_memory_human:273.85M
used_memory_rss:291143680
used_memory_peak:384959656
used_memory_peak_human:367.13M
used_memory_lua:35840
mem_fragmentation_ratio:1.01
mem_allocator:libc
127.0.0.1:6379> 

上一篇:利用pygments实现django模板内的语法高亮


下一篇:基于对象存储 OSS 的智能数据分析处理框架和功能