上一步我们做的秒杀虽然在操作上没问题,
但性能上能有很大的提升空间。
我们可以先把秒杀数据加载到内存中,考虑到以后服务集群化,
所以加载的数据不存放在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,比之前调高了好几倍。
下一节继续优化。