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,比之前调高了好几倍。

下一节继续优化。

猜你喜欢

转载自blog.csdn.net/shrek11/article/details/103529517