redis-对象序列化方案比较

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
简介:

与其他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> 

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
24天前
|
负载均衡 监控 NoSQL
Redis的集群方案有哪些?
Redis集群包括主从复制(基础,手动故障恢复)、哨兵模式(自动高可用)和Redis Cluster(官方分布式解决方案,自动分片和容错)。此外,还有如Codis、Redisson和Twemproxy等第三方工具用于代理和负载均衡。选择方案需考虑应用场景、数据规模和并发需求。
196 2
|
1月前
|
JSON Java API
GSON 泛型对象反序列化解决方案
GSON 泛型对象反序列化解决方案
|
3月前
|
监控 NoSQL Linux
【分布式】Redis的持久化方案解析
【1月更文挑战第25天】【分布式】Redis的持久化方案解析
|
28天前
|
缓存 运维 NoSQL
【Redis故障排查】「连接失败问题排查和解决」带你总体分析和整理Redis的问题故障实战开发指南及方案
【Redis故障排查】「连接失败问题排查和解决」带你总体分析和整理Redis的问题故障实战开发指南及方案
459 0
|
3月前
|
分布式计算 Java 大数据
IO流【Java对象的序列化和反序列化、File类在IO中的作用、装饰器模式构建IO流体系、Apache commons-io工具包的使用】(四)-全面详解(学习总结---从入门到深化)
IO流【Java对象的序列化和反序列化、File类在IO中的作用、装饰器模式构建IO流体系、Apache commons-io工具包的使用】(四)-全面详解(学习总结---从入门到深化)
53 0
|
1月前
|
存储 JSON NoSQL
[Redis]——RedisTemplate的两种序列化方式
[Redis]——RedisTemplate的两种序列化方式
|
1月前
|
JSON Android开发 数据格式
android 使用GSON 序列化对象出现字段被优化问题解决方案
android 使用GSON 序列化对象出现字段被优化问题解决方案
|
2月前
|
vr&ar
MFC序列化及反序列化对象
MFC序列化及反序列化对象
18 0
|
2月前
|
存储 NoSQL Redis
Redis淘汰策略、持久化、主从同步与对象模型
Redis淘汰策略、持久化、主从同步与对象模型
90 0
|
3月前
|
存储 JSON 运维
PowerShell 对象的序列化和反序列化
PowerShell 对象的序列化和反序列化
36 0

热门文章

最新文章