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> 

相关文章
|
11月前
|
canal NoSQL 关系型数据库
Redis应用—7.大Value处理方案
本文介绍了一种用于监控Redis大key的方案设计及其实现步骤。主要内容包括:方案设计、安装与配置环境、binlog数据消费者。
448 29
Redis应用—7.大Value处理方案
|
5月前
|
存储 监控 NoSQL
Redis高可用架构全解析:从主从复制到集群方案
Redis高可用确保服务持续稳定,避免单点故障导致数据丢失或业务中断。通过主从复制实现数据冗余,哨兵模式支持自动故障转移,Cluster集群则提供分布式数据分片与水平扩展,三者层层递进,保障读写分离、容灾切换与大规模数据存储,构建高性能、高可靠的Redis架构体系。
|
5月前
|
XML JSON 编解码
从JSON到Protobuf,深入序列化方案的选型与原理
序列化是数据跨边界传输的“翻译官”,将结构化数据转为二进制流。JSON可读性强但冗余大,Protobuf高效紧凑、性能优越,成主流选择。不同场景需权衡标准化与定制优化,选最合适方案。
410 3
|
6月前
|
监控 NoSQL 关系型数据库
保障Redis与MySQL数据一致性的强化方案
在设计时,需要充分考虑到业务场景和系统复杂度,避免为了追求一致性而过度牺牲系统性能。保持简洁但有效的策略往往比采取过于复杂的方案更加实际。同时,各种方案都需要在实际业务场景中经过慎重评估和充分测试才可以投入生产环境。
363 0
|
9月前
|
NoSQL 算法 安全
redis分布式锁在高并发场景下的方案设计与性能提升
本文探讨了Redis分布式锁在主从架构下失效的问题及其解决方案。首先通过CAP理论分析,Redis遵循AP原则,导致锁可能失效。针对此问题,提出两种解决方案:Zookeeper分布式锁(追求CP一致性)和Redlock算法(基于多个Redis实例提升可靠性)。文章还讨论了可能遇到的“坑”,如加从节点引发超卖问题、建议Redis节点数为奇数以及持久化策略对锁的影响。最后,从性能优化角度出发,介绍了减少锁粒度和分段锁的策略,并结合实际场景(如下单重复提交、支付与取消订单冲突)展示了分布式锁的应用方法。
724 3
|
9月前
|
存储 NoSQL 算法
Redis设计与实现——数据结构与对象
Redis 是一个高性能的键值存储系统,其数据结构设计精妙且高效。主要包括以下几种核心数据结构:SDS、链表、字典、跳跃表、整数集合、压缩列表。此外,Redis 对象通过类型和编码方式动态转换,优化内存使用,并支持引用计数、共享对象和淘汰策略(如 LRU/LFU)。这些特性共同确保 Redis 在性能与灵活性之间的平衡。
|
存储 消息中间件 NoSQL
Redis 数据结构与对象
【10月更文挑战第15天】在实际应用中,需要根据具体的业务需求和数据特点来选择合适的数据结构,并合理地设计数据模型,以充分发挥 Redis 的优势。
458 161
|
11月前
|
存储 监控 NoSQL
Redis集群有哪些方案
1. 主从复制集群 : 读写分离, 一主多从 , 解决高并发读的问题 2. 哨兵集群 : 主从集群的结构之上 , 加入了哨兵用于监控集群状态 , 主节点出现故障, 执行主从切换 , 解决高可用问题 3. Cluster分片集群 : 多主多从 , 解决高并发写的问题, 以及海量数据存储问题 , 每个主节点存储一部分集群数据
|
11月前
|
消息中间件 缓存 NoSQL
缓存与数据库的一致性方案,Redis与Mysql一致性方案,大厂P8的终极方案(图解+秒懂+史上最全)
缓存与数据库的一致性方案,Redis与Mysql一致性方案,大厂P8的终极方案(图解+秒懂+史上最全)
|
存储 缓存 NoSQL
云端问道21期方案教学-应对高并发,利用云数据库 Tair(兼容 Redis®*)缓存实现极速响应
云端问道21期方案教学-应对高并发,利用云数据库 Tair(兼容 Redis®*)缓存实现极速响应
375 1