[Ежедневный свежий гриб] Выбор схемы сериализации Spring Boot Redis

Микросервисы
[Ежедневный свежий гриб] Выбор схемы сериализации Spring Boot Redis

Redis используется все шире, и когда мы сталкиваемся с узкими местами в производительности, как их решать?

Смотрите статью, соответствующую проектуspring-boot-skill

Схема сериализации Redis

Spring Boot Redis

Spring Boot Data RedisОн предоставляет нам возможность plug-and-play, большинство конфигураций по умолчанию отвечают нашим потребностям, а схема сериализации является родной.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, 大小 44000000
FastJson序列化方案[序列化100000次]耗时:679 ms, 大小 18800000
FastJson序列化方案[序列化100000次]耗时:289 ms, 大小 18800000
FST序列化方案[序列化100000次]耗时:273 ms, 大小 10400000
FST序列化方案[序列化100000次]耗时:130 ms, 大小 10400000
Kryo序列化方案[序列化100000次]耗时:498 ms, 大小 14000000
Kryo序列化方案[序列化100000次]耗时:215 ms, 大小 14000000

Суммировать

FSTиKryoОбеспечивает меньший размер и более высокую скорость сериализации, чемFastjsonБольше преимуществ производительности. Однако объекты, которые необходимо сериализовать, должны быть обработаны заранее.register, что увеличивает сложность кодирования. иKryoПоток небезопасен и требует дополнительной обработки, например,KryoPoolВыполнить объединение.

Заменив схему сериализации, можно решитьRedis IOПроблема избыточного давления, повышения производительности.

иностранный язык

DubboПроект предоставляет большое количество решений для сериализации, которые имеют небольшой размер и быструю передачу ввода-вывода, поэтому они более эффективны в сфере микросервисов.Spring Cloudбольше преимуществ производительности. Мы можем ссылаться на следующее при реализации сериализацииDubboИсходный код для кодирования, в конце концов, код, который был улучшен и протестирован, очень ценен для справки.

Например,DubboсуществуетFSTКогда объект создан, объект, который необходимо сериализовать, будет обработан.registerClass, что значительно повышает производительность. И при использовании Kryo не толькоregisterСериализованные объекты также необходимо выполнять для базовых типов.register.

FSTБазовый тип был зарегистрирован сам по себе, поэтомуFSTпо сравнению с простотой использованияKryoбольше преимуществ, также обеспечивает@VersionУправление версиями новых полей POJO.

Добро пожаловать, чтобы обратить на меня внимание, я буду время от времени обновлять небольшие навыки и небольшие средства в развитии. Гит-адрес:git ee.com/soft men G/tickets…

Пример сериализации в Dubbo

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;
    }