龙空技术网

Java互联网高并发高性能Spring Boot Redis 序列化方案的选择

来一杯82年的Java 518

前言:

现时同学们对“java bitset序列化”大体比较关怀,看官们都想要了解一些“java bitset序列化”的相关文章。那么小编在网络上收集了一些对于“java bitset序列化””的相关资讯,希望你们能喜欢,大家快快来学习一下吧!

关注公众号领资料

搜索公众号【Java耕耘者】,回复【Java】,即可获取大量优质电子书和一份Java高级架构资料、Spring源码分析、Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式等视频资料

为了感谢支持我的朋友!整理了一份Java高级架构资料、Spring源码分析、Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式等资料,.私信回复:555领取

正文

Redis的使用越来越广泛,当遇见性能瓶颈时,我们应该如何去解决呢?

文章对应的项目见 spring-boot-skill

Redis序列化方案

Spring Boot Redis

Spring Boot Data Redis给我们提供了即插即用的体验,大部分默认配置已经满足了我们的需求,而其中序列化方案选择的是原生的JdkSerializationRedisSerializer

RedisTemplate.java

if (defaultSerializer == null) {	defaultSerializer = new JdkSerializationRedisSerializer(			classLoader != null ? classLoader : this.getClass().getClassLoader());}

当然,我们也可以选择Spring Boot Data Redis的其他序列化方案进行配置。

RedisSerializer的实现

在此基础上,我们可以自定义我们自己的序列化方案。

自定义JSON序列化方案

FastJsonRedisSerializer.java

public class FastJsonRedisSerializer<T> implements RedisSerializer<T> { private FastJsonConfig fastJsonConfig = new FastJsonConfig(); private Class<T> type; public FastJsonRedisSerializer(Class<T> type) { this.type = type; } public FastJsonConfig getFastJsonConfig() { return fastJsonConfig; } public void setFastJsonConfig(FastJsonConfig fastJsonConfig) { this.fastJsonConfig = fastJsonConfig; } @Override public byte[] serialize(T t) throws SerializationException { if (t == null) { return new byte[0]; } try { return JSON.toJSONBytes( fastJsonConfig.getCharset(), t, fastJsonConfig.getSerializeConfig(), fastJsonConfig.getSerializeFilters(), fastJsonConfig.getDateFormat(), JSON.DEFAULT_GENERATE_FEATURE, fastJsonConfig.getSerializerFeatures() ); } catch (Exception ex) { throw new SerializationException("Could not serialize: " + ex.getMessage(), ex); } } @Override public T deserialize(byte[] bytes) throws SerializationException { if (bytes == null || bytes.length == 0) { return null; } try { return (T) JSON.parseObject( bytes, fastJsonConfig.getCharset(), type, fastJsonConfig.getParserConfig(), fastJsonConfig.getParseProcess(), JSON.DEFAULT_PARSER_FEATURE, fastJsonConfig.getFeatures() ); } catch (Exception ex) { throw new SerializationException("Could not deserialize: " + ex.getMessage(), ex); } }}

当然,这个是基于fastjson的序列化方案,不仅提供了相比于JDK序列化更小的体积,序列化和反序列化的速度上也更快。

FST和Kryo序列化方案

这里就粘贴相关代码了,详情可见 redis-serializer-line

性能对比(基准)

JDK、FastJson、FST、Kryo测试结果如下,测试项目可见 redis-serializer-line

原生JDK序列化方案[序列化100000次]耗时:2160 ms, 大小 44000000原生JDK序列化方案[序列化100000次]耗时:1406 ms, 大小 44000000FastJson序列化方案[序列化100000次]耗时:679 ms, 大小 18800000FastJson序列化方案[序列化100000次]耗时:289 ms, 大小 18800000FST序列化方案[序列化100000次]耗时:273 ms, 大小 10400000FST序列化方案[序列化100000次]耗时:130 ms, 大小 10400000Kryo序列化方案[序列化100000次]耗时:498 ms, 大小 14000000Kryo序列化方案[序列化100000次]耗时:215 ms, 大小 14000000

总结

FST和Kryo提供了更小的体积和更快的序列化速度,比Fastjson更有性能优势。但是需要提前将需要序列化的对象进行register,这增加了编码难度。而Kryo线程不安全,更需要进行处理,比如通过KryoPool进行池化处理。

通过更换序列化方案,可以解决Redis IO压力过大的问题,提升性能。

外话

Dubbo的项目中提供了大量的序列化方案,在IO传输中体积小,速度快,所以在微服务领域比Spring Cloud更具有性能优势。我们在实现序列化是可以参考以下Dubbo的源码进行便携,毕竟千锤百炼的代码很有借鉴价值。

比如,Dubbo在FST的创建时,会对需要序列化的对象进行 registerClass, 这会显著的增强性能。而在使用Kryo时,不仅register序列化的对象,还需要针对基本类型进行register。

FST 本身已经对基本类型进行注册了,所以FST在易用性上比Kryo更有优势。

欢迎关注我呀,我会不定期更新开发中的小技巧,小手段。Git地址:gitee.com/SoftMeng/sp…

FstFactory.java

 public FstFactory() { SerializableClassRegistry.getRegisteredClasses().keySet().forEach(conf::registerClass); }

Kryo.java

 public Kryo create() { if (!kryoCreated) { kryoCreated = true; } Kryo kryo = new CompatibleKryo(); // TODO// kryo.setReferences(false); kryo.setRegistrationRequired(registrationRequired); kryo.addDefaultSerializer(Throwable.class, new JavaSerializer()); kryo.register(Arrays.asList("").getClass(), new ArraysAsListSerializer()); kryo.register(GregorianCalendar.class, new GregorianCalendarSerializer()); kryo.register(InvocationHandler.class, new JdkProxySerializer()); kryo.register(BigDecimal.class, new DefaultSerializers.BigDecimalSerializer()); kryo.register(BigInteger.class, new DefaultSerializers.BigIntegerSerializer()); kryo.register(Pattern.class, new RegexSerializer()); kryo.register(BitSet.class, new BitSetSerializer()); kryo.register(URI.class, new URISerializer()); kryo.register(UUID.class, new UUIDSerializer()); UnmodifiableCollectionsSerializer.registerSerializers(kryo); SynchronizedCollectionsSerializer.registerSerializers(kryo); // now just added some very common classes // TODO optimization kryo.register(HashMap.class); kryo.register(ArrayList.class); kryo.register(LinkedList.class); kryo.register(HashSet.class); kryo.register(TreeSet.class); kryo.register(Hashtable.class); kryo.register(Date.class); kryo.register(Calendar.class); kryo.register(ConcurrentHashMap.class); kryo.register(SimpleDateFormat.class); kryo.register(GregorianCalendar.class); kryo.register(Vector.class); kryo.register(BitSet.class); kryo.register(StringBuffer.class); kryo.register(StringBuilder.class); kryo.register(Object.class); kryo.register(Object[].class); kryo.register(String[].class); kryo.register(byte[].class); kryo.register(char[].class); kryo.register(int[].class); kryo.register(float[].class); kryo.register(double[].class); for (Class clazz : registrations) { kryo.register(clazz); } SerializableClassRegistry.getRegisteredClasses().forEach((clazz, ser) -> { if (ser == null) { kryo.register(clazz); } else { kryo.register(clazz, (Serializer) ser); } }); return kryo; }

本文到这里就结束了,喜欢的朋友可以帮忙转发和关注一下,感谢支持!

标签: #java bitset序列化