与其他NoSql数据库(例如Memecache)不同,Jedis并没有提供默认的序列化工具,这样开发者需要自己引入序列化工具。将对象序列化到Redis中可以选取多种序列化方案,例如Xml,Json,Protobuf,Thrift等
选取FastJson和protostuff进行效率比对
测试方法
- 每次生成1000个POJO对象,每个POJO对象中都包含有1个List,List中也包含了1000个POJO对象。
- 将生成的1000个POJO对象序列化并存储到Redis中
- 从耗时和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>