上一步我們做的秒殺雖然在操作上沒問題,
但性能上能有很大的提升空間。
我們可以先把秒殺數據加載到內存中,考慮到以後服務集羣化,
所以加載的數據不存放在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,比之前調高了好幾倍。
下一節繼續優化。