Redis的一些知识点

本地缓存与redis实现的分布式缓存

Java中本地缓存是指将数据存储在应用程序内存中,以便快速访问和提高性能。这种缓存方式适用于小型应用程序或者单机部署的应用程序。Java中本地缓存可以通过使用HashMap、ConcurrentHashMap等数据结构实现。本地缓存的优点是快速读取和写入,但是其容量受限于应用程序内存大小。

实现代码如下:

import java.util.HashMap;
import java.util.Map;

public class LocalCache {
    private Map<String, Object> cache = new HashMap<>();

    public void put(String key, Object value) {
        cache.put(key, value);
    }

    public Object get(String key) {
        return cache.get(key);
    }

    public void remove(String key) {
        cache.remove(key);
    }
}

Redis是一种分布式内存数据库,支持多种数据结构(如字符串、哈希表、列表、集合等),可以作为分布式缓存使用。Redis具有高性能、可扩展性和灵活性等优点,适用于大型分布式系统。在Redis中,数据被保存在内存中,并且可以定期将数据同步到磁盘上以保证持久化。

使用了Jedis客户端连接Redis数据库,实现代码如下

import redis.clients.jedis.Jedis;

public class RedisCache {
    private Jedis jedis;

    public RedisCache() {
        jedis = new Jedis("localhost", 6379);
    }

    public void put(String key, String value) {
        jedis.set(key, value);
    }

    public String get(String key) {
        return jedis.get(key);
    }

    public void remove(String key) {
        jedis.del(key);
    }
}

与本地缓存相比,Redis作为分布式缓存具有以下优点:

  • 可扩展性:Redis支持横向扩展,可以添加更多的节点来增加容量和吞吐量。

  • 高可靠性:由于Redis采用主从复制模式来保证数据的可靠性,在主节点宕机时可以自动切换到从节点继续提供服务。

  • 数据共享:Redis支持多个应用程序共享同一个缓存集群,提高了资源利用率。

  • 高性能:Redis采用内存存储,读写速度非常快。

本地缓存适用于小型应用程序或者单机部署的应用程序,而Redis作为分布式缓存适用于大型分布式系统。选择哪种缓存方式需要根据具体的需求和场景来决定。

缓存会出现的一些经典问题

缓存穿透:高并发查询缓存中没有的数据,高并发会直接查询数据库。解决方案:直接把null结果缓存,并加入短暂的过期时间。

缓存雪崩:相同过期时间的key失效,请求全部来到数据库。解决方案:过期时间加段随机值。

缓存击穿:某些key是热点数据,当过期时请求全部来到数据库。解决方案:加锁,分布式情况需要加分布式锁。

本地锁和Redis实现的分布式锁

本地锁是通过synchronized关键字实现的。synchronized关键字可以用于方法或代码块,它保证了同一时刻只有一个线程能够访问被保护的代码。不过适用于单机环境下的并发控制,因为多个线程在同一台服务器上运行,它们可以共享内存和CPU资源。但是,在分布式系统中使用本地锁会存在问题,因为不同节点之间无法共享内存和CPU资源。

代码如下:

public class LocalLockExample {
    private int count = 0;
    private Object lock = new Object();

    public void increment() {
        synchronized (lock) { // 获取锁
            count++;
        } // 释放锁
    }
}

Redis提供了setnx(SET if Not eXists)命令,可以原子性地将一个值设置到key中,并且如果key不存在,则设置成功;如果key已经存在,则设置失败。

  • 客户端向Redis发送setnx命令请求获取锁;
  • 如果返回值为1,则表示获取到了锁;
  • 如果返回值为0,则表示没有获取到锁;
  • 在获取到锁后,客户端需要在规定时间内释放该锁;
  • 如果在规定时间内未释放该锁,则其他客户端可以重新获取该锁。

注意!还要设置过期时间,避免锁一直占用,在释放锁的时候需要保证原子性的操作,以防如果出现了不可预料的问题,在不是原子性的操作下容易没释放锁就造成了死锁问题,要保证原子性,可以使用官方给出的Lua脚本实现。

if redis.call("get",KEYS[1]) == ARGV[1]
then
    return redis.call("del",KEYS[1])
else
    return 0
end

使用Java代码来进行实现:

RedisScript<Long> script = new DefaultRedisScript<>(
            "if redis.call('setnx', KEYS[1], ARGV[1]) == 1 then return redis.call('expire', KEYS[1], ARGV[2]) else return 0 end",
            Long.class);
Long result = redisTemplate.execute(script, Arrays.asList("lock"), uuid);

redission实现的分布式锁

  • 保证了原子性的执行
  • 看门狗机制,默认设置锁过期时间为30s,每隔10s会重置锁的过期时间,持有锁过久也会续期,当机器宕机key会在30s后过期不会造成死锁
// 锁的名字就等于锁的粒度,分的越细越快
RLock lock = redisson.getLock("lock");
lock.lock();
lock.unlock();

缓存数据一致性的解决方案

  1. 缓存的数据都加上过期时间,在过期的时候触发更新
  2. 读写数据时使用分布式的读写锁,在经常读,不经常写的情况下使用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值