跳转至
用户认证 - eMac Tech Docs

用户认证

重要提醒

为了您的权益以及学习体验,请不要外借账号!

如果您没有账号或忘记密码,请联系管理员重置密码。

请输入您的登录信息

Redis事务与持久化

事务特性

Syntax error in textmermaid version 11.6.0

事务特点

  1. 批量执行但不保证原子性
  2. 无回滚机制
  3. 执行期间不会被其他命令打断
  4. 使用WATCH实现乐观锁

持久化机制

RDB快照

# redis.conf配置示例
save 900 1      # 900秒内至少1个key变化
save 300 10     # 300秒内至少10个key变化
dbfilename dump.rdb

AOF日志

appendonly yes
appendfsync everysec  # 每秒同步
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

高可用架构

主从复制

# 从节点配置
replicaof 127.0.0.1 6379
replica-read-only yes

哨兵模式

# sentinel.conf配置
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000

Java客户端配置

// 哨兵模式连接
JedisPoolConfig poolConfig = new JedisPoolConfig();
JedisSentinelPool pool = new JedisSentinelPool(
    "mymaster", 
    new HashSet<>(Arrays.asList("sentinel1:26379")),
    poolConfig
);

生产建议

  1. 根据业务选择持久化方式
  2. 主从节点配置合理的内存
  3. 哨兵至少部署3个节点
  4. 监控持久化状态
  5. 定期备份数据

Java 操作 Redis 实战

环境准备

1. 添加依赖

<!-- Spring Boot Starter Data Redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!-- 连接池 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>

2. 配置文件

spring:
  redis:
    host: localhost
    port: 6379
    password: your_password
    database: 0
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: -1ms

基础操作

1. 配置类

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);

        // 设置key的序列化方式
        template.setKeySerializer(new StringRedisSerializer());
        // 设置value的序列化方式
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());

        return template;
    }
}

2. 工具类

@Component
public class RedisUtil {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    // 设置缓存
    public void set(String key, Object value, long time) {
        redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
    }

    // 获取缓存
    public Object get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    // 删除缓存
    public Boolean delete(String key) {
        return redisTemplate.delete(key);
    }

    // 设置过期时间
    public Boolean expire(String key, long time) {
        return redisTemplate.expire(key, time, TimeUnit.SECONDS);
    }
}

实战案例

1. 商品缓存

@Service
public class ProductService {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private ProductMapper productMapper;

    private static final String PRODUCT_KEY = "product:";

    public Product getProduct(Long id) {
        // 1. 查询缓存
        String key = PRODUCT_KEY + id;
        Product product = (Product) redisTemplate.opsForValue().get(key);

        // 2. 缓存未命中,查询数据库
        if (product == null) {
            product = productMapper.selectById(id);
            if (product != null) {
                // 3. 写入缓存
                redisTemplate.opsForValue().set(key, product, 1, TimeUnit.HOURS);
            }
        }
        return product;
    }

    public void updateProduct(Product product) {
        // 1. 更新数据库
        productMapper.updateById(product);
        // 2. 删除缓存
        redisTemplate.delete(PRODUCT_KEY + product.getId());
    }
}

2. 分布式锁

@Service
public class DistributedLock {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public boolean lock(String key, String value, long timeout) {
        return redisTemplate.opsForValue()
            .setIfAbsent(key, value, timeout, TimeUnit.SECONDS);
    }

    public boolean unlock(String key, String value) {
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                       "return redis.call('del', KEYS[1]) else return 0 end";
        return redisTemplate.execute(new DefaultRedisScript<>(script, Boolean.class),
            Collections.singletonList(key), value);
    }
}

3. 限流器

@Service
public class RateLimiter {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public boolean isAllowed(String key, int limit, int period) {
        String script = "local current = redis.call('incr', KEYS[1]) " +
                       "if current == 1 then " +
                       "redis.call('expire', KEYS[1], ARGV[1]) end " +
                       "return current <= tonumber(ARGV[2])";

        return redisTemplate.execute(new DefaultRedisScript<>(script, Boolean.class),
            Collections.singletonList(key), period, limit);
    }
}

4. 排行榜

@Service
public class RankingService {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    private static final String RANKING_KEY = "ranking:";

    public void addScore(String member, double score) {
        redisTemplate.opsForZSet().add(RANKING_KEY, member, score);
    }

    public Set<ZSetOperations.TypedTuple<Object>> getTop(int count) {
        return redisTemplate.opsForZSet().reverseRangeWithScores(RANKING_KEY, 0, count - 1);
    }

    public Long getRank(String member) {
        return redisTemplate.opsForZSet().reverseRank(RANKING_KEY, member);
    }
}

性能优化

1. Pipeline 批量操作

@Service
public class BatchOperation {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    public void batchSet(Map<String, Object> map) {
        redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
            map.forEach((key, value) -> {
                connection.set(
                    key.getBytes(),
                    value.toString().getBytes()
                );
            });
            return null;
        });
    }
}

2. 本地缓存

@Service
public class LocalCache {
    private LoadingCache<String, Object> cache;

    @PostConstruct
    public void init() {
        cache = CacheBuilder.newBuilder()
            .maximumSize(1000)
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .build(new CacheLoader<String, Object>() {
                @Override
                public Object load(String key) {
                    return loadFromRedis(key);
                }
            });
    }

    public Object get(String key) {
        try {
            return cache.get(key);
        } catch (ExecutionException e) {
            return null;
        }
    }
}

最佳实践

1. 异常处理

@Aspect
@Component
public class RedisAspect {
    @Around("execution(* com.example.service.*.*(..))")
    public Object handleRedisException(ProceedingJoinPoint point) {
        try {
            return point.proceed();
        } catch (RedisConnectionFailureException e) {
            // 处理连接异常
            return null;
        } catch (Throwable e) {
            // 处理其他异常
            throw new RuntimeException(e);
        }
    }
}

2. 监控指标

@Component
public class RedisMonitor {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Scheduled(fixedRate = 60000)
    public void monitor() {
        // 监控连接数
        Long clientCount = redisTemplate.execute((RedisCallback<Long>) connection ->
            connection.serverCommands().clientList().stream().count());

        // 监控内存使用
        Properties info = redisTemplate.execute((RedisCallback<Properties>) connection ->
            connection.serverCommands().info());

        // 记录监控数据
        log.info("Redis clients: {}", clientCount);
        log.info("Redis memory: {}", info.getProperty("used_memory"));
    }
}

注意事项

  1. 连接池配置:

    • 根据并发量设置合适的连接数
    • 定期检查连接状态
    • 实现连接重试机制
  2. 序列化选择:

    • 使用高效的序列化方式
    • 考虑序列化大小
    • 注意序列化性能
  3. 异常处理:

    • 实现优雅降级
    • 记录异常日志
    • 设置重试机制
  4. 性能优化:

    • 使用批量操作
    • 实现本地缓存
    • 避免大键
    • 合理设置过期时间