redis-对象序列化方案比较

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容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
相关文章
|
1月前
|
缓存 安全 PHP
PHP中的魔术方法与对象序列化
本文将深入探讨PHP中的魔术方法,特别是与对象序列化和反序列化相关的__sleep()和__wakeup()方法。通过实例解析,帮助读者理解如何在实际应用中有效利用这些魔术方法,提高开发效率和代码质量。
|
29天前
|
存储 安全 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第22天】在Java的世界里,对象序列化和反序列化是数据持久化和网络传输的关键技术。本文将带你了解如何在Java中实现对象的序列化与反序列化,并探讨其背后的原理。通过实际代码示例,我们将一步步展示如何将复杂数据结构转换为字节流,以及如何将这些字节流还原为Java对象。文章还将讨论在使用序列化时应注意的安全性问题,以确保你的应用程序既高效又安全。
|
1月前
|
存储 消息中间件 NoSQL
Redis 数据结构与对象
【10月更文挑战第15天】在实际应用中,需要根据具体的业务需求和数据特点来选择合适的数据结构,并合理地设计数据模型,以充分发挥 Redis 的优势。
55 8
|
1月前
|
JSON 前端开发 数据格式
前端的全栈之路Meteor篇(五):自定义对象序列化的EJSON介绍 - 跨设备的对象传输
EJSON是Meteor框架中扩展了标准JSON的库,支持更多数据类型如`Date`、`Binary`等。它提供了序列化和反序列化功能,使客户端和服务器之间的复杂数据传输更加便捷高效。EJSON还支持自定义对象的定义和传输,通过`EJSON.addType`注册自定义类型,确保数据在两端无缝传递。
|
2月前
|
JSON NoSQL Java
redis的java客户端的使用(Jedis、SpringDataRedis、SpringBoot整合redis、redisTemplate序列化及stringRedisTemplate序列化)
这篇文章介绍了在Java中使用Redis客户端的几种方法,包括Jedis、SpringDataRedis和SpringBoot整合Redis的操作。文章详细解释了Jedis的基本使用步骤,Jedis连接池的创建和使用,以及在SpringBoot项目中如何配置和使用RedisTemplate和StringRedisTemplate。此外,还探讨了RedisTemplate序列化的两种实践方案,包括默认的JDK序列化和自定义的JSON序列化,以及StringRedisTemplate的使用,它要求键和值都必须是String类型。
redis的java客户端的使用(Jedis、SpringDataRedis、SpringBoot整合redis、redisTemplate序列化及stringRedisTemplate序列化)
|
1月前
|
存储 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第9天】在Java的世界里,对象序列化是连接数据持久化与网络通信的桥梁。本文将深入探讨Java对象序列化的机制、实践方法及反序列化过程,通过代码示例揭示其背后的原理。从基础概念到高级应用,我们将一步步揭开序列化技术的神秘面纱,让读者能够掌握这一强大工具,以应对数据存储和传输的挑战。
|
1月前
|
存储 安全 Java
Java编程中的对象序列化与反序列化
【10月更文挑战第3天】在Java编程的世界里,对象序列化与反序列化是实现数据持久化和网络传输的关键技术。本文将深入探讨Java序列化的原理、应用场景以及如何通过代码示例实现对象的序列化与反序列化过程。从基础概念到实践操作,我们将一步步揭示这一技术的魅力所在。
|
1月前
|
存储 NoSQL 大数据
大数据-51 Redis 高可用方案CAP-AP 主从复制 一主一从 全量和增量同步 哨兵模式 docker-compose测试
大数据-51 Redis 高可用方案CAP-AP 主从复制 一主一从 全量和增量同步 哨兵模式 docker-compose测试
35 3
|
1月前
|
JSON 缓存 NoSQL
Redis 在线查看序列化对象技术详解
Redis 在线查看序列化对象技术详解
37 2
|
29天前
|
存储 缓存 NoSQL
一篇搞懂!Java对象序列化与反序列化的底层逻辑
本文介绍了Java中的序列化与反序列化,包括基本概念、应用场景、实现方式及注意事项。序列化是将对象转换为字节流,便于存储和传输;反序列化则是将字节流还原为对象。文中详细讲解了实现序列化的步骤,以及常见的反序列化失败原因和最佳实践。通过实例和代码示例,帮助读者更好地理解和应用这一重要技术。
27 0
下一篇
无影云桌面