springboot 秒殺系統(二)redis

上一步我們做的秒殺雖然在操作上沒問題,

但性能上能有很大的提升空間。

我們可以先把秒殺數據加載到內存中,考慮到以後服務集羣化,

所以加載的數據不存放在JVM中,而存在放redis

首先,我們都知道,redis在數據存取方面遠遠大於mysql

所以我們第一步優化是:可以將秒殺數據加載至REDIS中,

然後我們在查詢數據的時候,優先從redis裏查找。

注意:這裏redis和MySQL最好在同一個網端,不然,測試出來的效果不一樣

因爲不同的網端網絡消耗是有很大差別的

1,配置REDIS,並配置redis緩存和設置序列化。相關代碼和類

spring:
  redis:
    host: 127.0.0.1
    port: 6379
    database: 0
    lettuce:
      pool:
        # 最大活躍鏈接數 默認8
        max-active: 20
        # 最大空閒連接數 默認8
        max-idle: 20
        # 最小空閒連接數 默認0
        min-idle: 5
import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;

import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

@Configuration
//開啓緩存
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport{

    /**
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        // 使用Jackson2JsonRedisSerialize 替換默認序列化
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        // 設置value的序列化規則和 key的序列化規則
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    /**
     * 這裏主要配置redis緩存的序列化,注意和
     * @return
     */
    @Bean
    public RedisCacheConfiguration redisCacheConfiguration(){
        FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
        RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
        configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer)).entryTtl(Duration.ofDays(1));
        return configuration;
    }
}

 

/**
 * 必須重寫序列化器,放棄用jackjson來做value的序列化,使用FastJson來做。
 * 重寫一些序列化器,並實現RedisSerializer接口
 */
public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

    private Class<T> clazz;

    public FastJsonRedisSerializer(Class<T> clazz) {
        super();
        this.clazz = clazz;
    }

    @Override
    public byte[] serialize(T t) throws SerializationException {
        if (t == null) {
            return new byte[0];
        }
        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
    }

    @Override
    public T deserialize(byte[] bytes) throws SerializationException {
        if (bytes == null || bytes.length <= 0) {
            return null;
        }
        String str = new String(bytes, DEFAULT_CHARSET);
        return (T) JSON.parseObject(str, clazz);
    }
}

第二步,啓動預熱數據至redis(可選)

@Component
@Slf4j
public class InitredisData implements CommandLineRunner {
    @Autowired
    private ProductService productService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public void run(String... args) throws Exception {
        log.info("預熱redis數據");
        initRedis();
    }

    /**
     * 預熱秒殺數據到redis
     */
    public void initRedis(){
        List<JSONObject> list= productService.select();
        Map<String,JSONObject> map = new ConcurrentHashMap<String,JSONObject>();

        list.stream().forEach(jsonObject -> {
            System.out.println(jsonObject.toJSONString());
            redisTemplate.opsForValue().set("productcache::"+jsonObject.getString("seckillId"),jsonObject);
        });
    }
}

第三步,在查詢商品的接口上加緩存配置

@Cacheable(value = "productcache", key = "#p0")
    public JSONObject findById(String seckillId){
        return  productDao.findById(seckillId);
    }

啓動之後,redis會加載數據庫的秒殺數據

OK,這個就是我們2.0版本的優化版,我們還是用上次的jmeter來壓測一下

查詢的QPS爲245   秒殺的QPS爲208,比之前調高了好幾倍。

下一節繼續優化。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章