(一) 緩存
1、 記憶體緩存的利與弊
可以使用google guava cache或則caffie,作為記憶體緩存性能之王。但是隻能基于記憶體,不具備分布式的能力,并且想讓記憶體緩存失效再外部控制比較難實作。如果需要實作,則通過接口或則其他方式進行記憶體緩存的失效管理。例如通過MQ等消息中間件,維護開發較難。
2、 分布式緩存redis
a) 單機
b) 叢集模式
(一) Redis 6.X Sentinel 哨兵叢集搭建
https://mp.weixin.qq.com/s/iy2y135EirDig87NZ-Xeqwc) 用戶端
(一) 可視化工具AnotherRedisDesktopManager
https://mp.weixin.qq.com/s/_YgvMn1GKCwrJkB9-KQxJg
d) 分布式鎖 Redission
(一)
https://mp.weixin.qq.com/s/CbnPRfvq4m1sqo2uKI6qQwe) Springboot整合實作

package com.manlitech.cloudboot.basebootconfig.redis;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.manlitech.cloudboot.common.enums.ResultEnums;
import com.manlitech.cloudboot.basebootconfig.exception.MyException;
import io.lettuce.core.ReadFrom;
import io.lettuce.core.cluster.ClusterClientOptions;
import io.lettuce.core.cluster.ClusterTopologyRefreshOptions;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
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.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
/**
* redis叢集配置
* @author shensg
* @date 2019/3/21
*
* 增加
* @EnableCaching
* extends CachingConfigurerSupport
* 兩處即可實作@Cacheable @CachePut @CacheEvict 使用
*/
@Configuration
public class RedisConfiguration {
@Autowired
private RedisProperties redisProperties;
@Value("${redis.maxRedirects:3}")
private int maxRedirects;
@Value("${redis.refreshTime:5}")
private int refreshTime;
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
//單機版
if(redisProperties.getCluster() == null) {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setDatabase(redisProperties.getDatabase());
redisStandaloneConfiguration.setHostName(redisProperties.getHost());
redisStandaloneConfiguration.setPassword(redisProperties.getPassword());
redisStandaloneConfiguration.setPort(redisProperties.getPort());
return new LettuceConnectionFactory(redisStandaloneConfiguration);
}
//叢集版本
if(redisProperties.getCluster() != null) {
RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(redisProperties.getCluster().getNodes());
redisClusterConfiguration.setMaxRedirects(maxRedirects);
//支援自适應叢集拓撲重新整理和靜态重新整理源
ClusterTopologyRefreshOptions clusterTopologyRefreshOptions = ClusterTopologyRefreshOptions.builder()
.enablePeriodicRefresh()
.enableAllAdaptiveRefreshTriggers()
.refreshPeriod(Duration.ofSeconds(refreshTime))
.build();
ClusterClientOptions clusterClientOptions = ClusterClientOptions.builder()
.topologyRefreshOptions(clusterTopologyRefreshOptions).build();
//從優先,讀寫分離,讀從可能存在不一緻,最終一緻性CP
LettuceClientConfiguration lettuceClientConfiguration = LettuceClientConfiguration.builder()
.readFrom(ReadFrom.SLAVE_PREFERRED)
.clientOptions(clusterClientOptions).build();
return new LettuceConnectionFactory(redisClusterConfiguration, lettuceClientConfiguration);
throw new MyException(ResultEnums.UNKONW_REDIS_TYPE);
}
public RedisTemplate<Object, Object> redisTemplate(LettuceConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(DateTime.class,new JodaDateTimeJsonSerializer());
simpleModule.addDeserializer(DateTime.class,new JodaDateTimeJsonDeserializer());
om.registerModule(simpleModule);
om.setVisibility(PropertyAccessor.ALL,JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
public class JodaDateTimeJsonSerializer extends JsonSerializer<DateTime> {
@Override
public void serialize(DateTime dateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeString(dateTime.toString("yyyy-MM-dd HH:mm:ss"));
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
public class JodaDateTimeJsonDeserializer extends JsonDeserializer<DateTime> {
public DateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
String dateString =jsonParser.readValueAs(String.class);
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
return DateTime.parse(dateString,formatter);