2024-09-06

问题解释

  1. 缓存穿透:查询不存在的数据,缓存和数据库都没有,导致所有请求都打到数据库上。
  2. 缓存击穿:一个Key过期,大量请求打到数据库。
  3. 缓存雪崩:大量Key同时过期,导致大量请求打到数据库。

解决方案

  1. 缓存穿透:

    • 使用布隆过滤器:在缓存之前加一个布隆过滤器,查询时先检查数据是否存在。
    • 缓存空值:如果数据库查询不到,也缓存一个特殊值,如空字符串或者NULL,并设置较短的过期时间。
  2. 缓存击穿:

    • 加互斥锁:当Key过期时,先加锁,只有一个线程去数据库查询,其他线程等待。
    • 预先载入缓存:定时预先更新缓存,或者在高峰时间预热缓存。
  3. 缓存雪崩:

    • 设置随机过期时间:使得Key不会在同一时间过期。
    • 监控告警:提前预警,在大量Key即将过期时,预热缓存。
    • Redis集群部署:分散Key的存储和访问压力。

示例代码(伪代码):




# 缓存穿透 - 布隆过滤器
def is_key_exist(key):
    # 布隆过滤器判断Key是否存在
    return bloom_filter.is_exist(key)
 
def get_data(key):
    if not is_key_exist(key):
        return None
    data = redis.get(key)
    if data is None:
        data = db.get(key)
        if data is not None:
            redis.set(key, data, ex=3600)
    return data
 
# 缓存击穿 - 互斥锁
def get_data_with_lock(key):
    lock = acquire_lock(key)
    if lock:
        data = redis.get(key)
        if data is None:
            data = db.get(key)
            if data is not None:
                redis.set(key, data, ex=3600)
        release_lock(key)
    else:
        sleep(1)  # 等待1秒,再次尝试获取数据
        get_data_with_lock(key)
    return data
 
# 缓存雪崩 - 随机过期时间
def set_random_expire(key, data, expire_time):
    random_expire = random.randint(expire_time//2, expire_time)
    redis.set(key, data, ex=random_expire)

注意:以上代码仅为示例,实际应用需要根据业务场景和架构进行调整。

2024-09-06

Redis的String数据类型底层使用了一种名为简单动态字符串(Simple Dynamic String,SDS)的结构来实现。SDS是Redis中的基本字符串表示,它是一个结构体,用于存储和管理字符串,并且具有高效的内存管理和字符串长度扩展特性。

以下是SDS的结构体定义(部分):




struct sdshdr {
    // 记录buf数组中已使用字节的数量
    // 等于SDS所保存字符串的长度
    int len;
    // 记录buf数组中未使用字节的数量
    int free;
    // 字节数组,用于保存字符串
    char buf[];
};

其中:

  • len 属性:记录了SDS保存的字符串的长度。
  • free 属性:记录了SDS的剩余空间大小。
  • buf 数组:是一个字符数组,用于保存字符串的每个字符。

这种结构提供了高性能的字符串操作,例如内存分配和释放的次数都被大大减少,并且通过len属性,Redis可以在常数时间内获取字符串长度。

2024-09-06

Redis 是一个开源的使用 C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。

Redis 的命令有很多,这里我们介绍一些常用的通用命令。

  1. DEL:删除一个key



DEL keyname
  1. EXISTS:检查一个key是否存在



EXISTS keyname
  1. EXPIRE:为一个key设置过期时间



EXPIRE keyname 10
  1. TTL:查看一个key的过期时间



TTL keyname
  1. KEYS:查找符合给定模式的key



KEYS pattern
  1. MOVE:将一个key从一个数据库移动到另一个数据库



MOVE keyname 1
  1. PERSIST:移除一个key的过期时间



PERSIST keyname
  1. RENAME:将一个key改名



RENAME oldkeyname newkeyname
  1. TYPE:返回一个key所储存的value的类型



TYPE keyname
  1. RANDOMKEY:返回一个随机key



RANDOMKEY
  1. SLAVEOF:使当前服务器成为另一个服务器的从服务器



SLAVEOF host port
  1. SAVE:保存数据到磁盘



SAVE
  1. SHUTDOWN:关闭服务器



SHUTDOWN
  1. SLAVEOF:改变复制策略设置



SLAVEOF host port
  1. INFO:获取服务器的统计信息



INFO
  1. MONITOR:实时监控所有经过服务器的请求



MONITOR
  1. CONFIG:在运行时配置Redis服务器



CONFIG GET parameter
  1. DEBUG OBJECT:获取key的调试信息



DEBUG OBJECT keyname
  1. DEBUG SEGFAULT:使服务器崩溃



DEBUG SEGFAULT
  1. SYNC:用于复制功能,同步数据



SYNC
  1. PING:测试服务器是否运行



PING
  1. ECHO:打印信息



ECHO message
  1. SELECT:更改当前数据库



SELECT index
  1. QUIT:关闭当前连接



QUIT
  1. AUTH:验证密码



AUTH password
  1. SLOWLOG:慢查询日志



SLOWLOG subcommand [argument]
  1. OBJECT:获取key的value的相关信息



OBJECT subcommand [arguments [arguments...]]
  1. CLIENT LIST:返回连接到服务器的客户端列表



CLIENT LIST
  1. CLIENT KILL:关闭客户端连接



CLIENT KILL ip:port
  1. CLIENT GETNAME:获取连接的客户端名称



CLIENT GETNAME
  1. CLIENT SETNAME:设置连接的客户端名称



CLIENT SETNAME
  1. DBSIZE:返回当前数据库的key的数目
2024-09-06

Redis 是一个开源的使用 C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。

Redis 的数据结构:

  1. 字符串(String)
  2. 列表(List)
  3. 集合(Set)
  4. 有序集合(Sorted Set)
  5. 哈希(Hash)
  6. 位图(Bitmap)
  7. HyperLogLog
  8. Stream

常用的 Redis 命令:

  1. String

    • SET:为一个键设置值
    • GET:获取一个键的值
    • INCR:将键的整数值增加1
    • DECR:将键的整数值减少1
    • INCRBY:将键的整数值增加指定的整数
    • DECRBY:将键的整数值减少指定的整数
    • SETNX:只有键不存在时,设置键的值
    • GETSET:设置键的值并返回旧值
  2. List

    • LPUSH:将一个或多个值插入到列表头部
    • RPUSH:将一个或多个值插入到列表尾部
    • LPOP:移出并获取列表的第一个元素
    • RPOP:移出并获取列表的最后一个元素
    • LLEN:获取列表长度
    • LRANGE:获取列表指定范围内的元素
  3. Set

    • SADD:向集合添加一个或多个成员
    • SMEMBERS:获取集合中的所有成员
    • SISMEMBER:判断成员是否在集合中
    • SCARD:获取集合的成员数
    • SREM:移除集合中的一个或多个成员
  4. Sorted Set

    • ZADD:向有序集合添加一个或多个成员
    • ZCARD:获取有序集合的成员数
    • ZCOUNT:计算在有序集合中指定分数区间内的元素数量
    • ZRANGE:按索引范围返回有序集合成指定区间内的成员
    • ZREM:移除有序集合中的一个或多个成员
  5. Hash

    • HSET:将哈希表中的字段的值设置为
    • HGET:获取存储在哈希表中的字段的值
    • HGETALL:获取在哈希表中指定键的所有字段和值
    • HDEL:删除一个或多个哈希表字段
  6. Bitmap

    • SETBIT:对键的二进制表示的位进行设置
    • GETBIT:对键的二进制表示的位进行获取
    • BITCOUNT:计算给定位区间内的位的数量
  7. HyperLogLog

    • PFADD:添加元素到HyperLogLog
    • PFCOUNT:返回HyperLogLog的基数估算值
    • PFMERGE:将多个HyperLogLog合并为一个
  8. Stream

    • XADD:将消息添加到流
    • XREAD:从流读取消息
    • XDEL:删除流中的一条或多条消息
    • XLEN:获取流中消息的数量
    • XRANGE:根据ID范围获取消息
    • XREVRANGE:根据ID范围,逆向获取消息

以上是 Redis 常用数据结构和命令的简要概述和示例,具体使用时需要根据实际需求选择合适的数据结构和命令。

2024-09-06

在阿里云服务器上安装Redis,可以通过以下步骤进行:

  1. 更新包管理器并安装必要的依赖项:



sudo apt-get update
sudo apt-get install build-essential tcl
  1. 下载Redis源码:



wget http://download.redis.io/releases/redis-6.0.9.tar.gz
  1. 解压源码并进入目录:



tar xzf redis-6.0.9.tar.gz
cd redis-6.0.9
  1. 编译Redis:



make
  1. 运行make test验证编译是否成功:



make test
  1. 安装Redis:



sudo make install
  1. 修改配置文件(可选):

    编辑 redis.conf 文件,根据需要进行配置更改。

  2. 启动Redis服务:



redis-server /path/to/redis.conf

注意:路径 /path/to/redis.conf 需要替换为实际的配置文件路径,如果是使用默认配置则不需要指定配置文件。

以上步骤会安装Redis 6.0.9版本,如果需要安装其他版本,请替换相应的版本号。

2024-09-06

要实现多个Redis连接间指定key的数据同步,可以使用Redis的发布/订阅(pub/sub)功能或者使用Redis Data Migration (RDM) 工具来同步数据。

以下是使用Redis发布/订阅的简单示例:

  1. 在源Redis服务器上发布数据变更。
  2. 在目标Redis服务器上订阅相同的频道。



import redis
 
# 连接到源Redis服务器
source_redis = redis.StrictRedis(host='source_host', port=6379, db=0)
 
# 连接到目标Redis服务器
target_redis = redis.StrictRedis(host='target_host', port=6379, db=0)
 
# 定义一个订阅处理器
def handle_message(message):
    # 当接收到消息时,将数据同步到目标Redis
    target_redis.set(message.get('data'), message.get('channel'))
 
# 创建一个发布/订阅对象
pubsub = source_redis.pubsub()
 
# 订阅指定频道
pubsub.subscribe(**{'mychannel': handle_message})
 
# 开始监听订阅的消息
pubsub.run_in_thread(sleep_time=0.01)

使用RDM工具的话,可以通过配置文件来设置需要同步的key,RDM会自动处理数据的同步。

以下是RDM的基本使用方法:

  1. 安装RDM工具。
  2. 配置RDM的配置文件。
  3. 启动RDM进行数据同步。



# 安装RDM
pip install rdm
 
# 创建配置文件redis.conf
[source]
type: redis
host: source_host
port: 6379
 
[target]
type: redis
host: target_host
port: 6379
 
[rule]
start: __keyevent@0__:set
end: __keyevent@0__:set
 
# 使用RDM进行数据同步
rdm -c redis.conf

RDM会监听源Redis服务器上的set事件,并自动将数据同步到目标Redis服务器。这种方法更为简单和高效,推荐在可能的情况下使用。

2024-09-06

在Redis中,列表是一种常见的数据类型,可以从两端进行插入和删除操作。在Java中,我们可以使用Jedis库来操作Redis中的列表。

以下是使用Jedis操作Redis列表的一些常见方法:

  1. 添加元素到列表中



Jedis jedis = new Jedis("localhost");
jedis.lpush("mylist", "element1"); // 在列表头部添加元素
jedis.rpush("mylist", "element2"); // 在列表尾部添加元素
  1. 获取列表中的元素



Jedis jedis = new Jedis("localhost");
List<String> mylist = jedis.lrange("mylist", 0, -1); // 获取列表所有元素
  1. 从列表中移除元素



Jedis jedis = new Jedis("localhost");
jedis.lpop("mylist"); // 从列表头部移除元素
jedis.rpop("mylist"); // 从列表尾部移除元素
  1. 获取列表长度



Jedis jedis = new Jedis("localhost");
long length = jedis.llen("mylist"); // 获取列表长度
  1. 修剪列表



Jedis jedis = new Jedis("localhost");
jedis.ltrim("mylist", 0, 1); // 保留列表指定范围内的元素
  1. 获取列表指定位置的元素



Jedis jedis = new Jedis("localhost");
String element = jedis.lindex("mylist", 0); // 获取列表指定位置的元素
  1. 在列表中插入元素



Jedis jedis = new Jedis("localhost");
jedis.linsert("mylist", BinaryClient.LIST_POSITION.BEFORE, "element1", "element0"); // 在element1前面插入element0
  1. 更新列表中的元素



Jedis jedis = new Jedis("localhost");
jedis.lset("mylist", 0, "newElement"); // 更新列表指定位置的元素

以上就是使用Jedis操作Redis列表的常见方法。在实际应用中,你可以根据需要选择合适的方法来操作Redis列表。

2024-09-06



@Configuration
public class RedisConfig {
 
    @Value("${spring.redis.host}")
    private String host;
 
    @Value("${spring.redis.port}")
    private int port;
 
    @Value("${spring.redis.timeout}")
    private int timeout;
 
    @Value("${spring.redis.password}")
    private String password;
 
    @Value("${spring.redis.database}")
    private int database;
 
    @Bean
    public JedisPool redisPoolFactory() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout, password, database);
        return jedisPool;
    }
}
 
@Service
public class RedisService {
 
    @Autowired
    private JedisPool jedisPool;
 
    public String get(String key) {
        Jedis jedis = null;
        String value = null;
        try {
            jedis = jedisPool.getResource();
            value = jedis.get(key);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return value;
    }
 
    public String set(String key, String value) {
        Jedis jedis = null;
        try {
            jedis = jedisPool.getResource();
            jedis.set(key, value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return value;
    }
}
 
@Service
public class UserService {
 
    @Autowired
    private RedisService redisService;
 
    @Cacheable(value = "user", key = "#id")
    public User findById(String id) {
        // 模拟从数据库查询用户
        User user = new User();
        user.setId(id);
        user.setName("张三");
        return user;
    }
 
    public void updateUser(User user) {
        // 模拟更新用户信息
        // ...
        // 更新后,清除缓存
        redisService.set(user.getId(), null);
    }
}

在这个代码实例中,我们定义了RedisConfig类来配置Jedis连接池,并创建了redisPoolFactory Bean。RedisService类封装了对Redis的基本操作。在UserService中,我们使用@Cacheable注解来标记findById方法,使其能够使用Redis作为缓存。同时,提供了updateUser方法来模拟更新用户信息,并清除相应的缓存条目。这样,当用户信息被更新后,缓存中的数据会过期,下次查询将从数据库中重新获取数据。

2024-09-06

Redis是一种开源的内存中数据结构存储系统,可以用作数据库、缓存和消息中间件。以下是Redis的一些基础知识和使用示例:

  1. 基础命令:

连接Redis:




redis-cli

设置键值对:




SET key value

获取键对应的值:




GET key

删除键:




DEL key

查看键的类型:




TYPE key
  1. 数据结构:

Redis支持多种数据结构,如字符串、列表、集合、有序集合、哈希表等。

列表操作(添加、获取):




LPUSH list_name value
LRANGE list_name 0 -1

集合操作(添加、获取):




SADD set_name member
SMEMBERS set_name

有序集合操作(添加、获取):




ZADD sorted_set_name score member
ZRANGE sorted_set_name 0 -1 WITHSCORES

哈希表操作(添加、获取):




HSET hash_name field value
HGETALL hash_name
  1. Lua脚本:

Redis支持Lua脚本,可以用来执行一系列命令。




local key = KEYS[1]
local value = ARGV[1]
redis.call('SET', key, value)
  1. 分布式锁:

Redis可以用作分布式锁,确保多个客户端互斥地访问资源。




SETNX lock_key unique_value
EXPIRE lock_key 10
# 获取锁后处理业务逻辑
DEL lock_key

以上是Redis基础知识和使用示例,实际应用中可能需要根据具体场景选择合适的数据结构和命令。

2024-09-06

在宝塔面板上配置Redis服务,你需要执行以下步骤:

  1. 安装Redis:

    • 进入宝塔面板,点击软件管理。
    • 在软件管理页面,找到Redis并点击安装。
  2. 配置Redis:

    • 在宝塔面板的服务菜单中找到Redis。
    • 点击Redis的设置按钮,配置Redis的运行参数,如端口、密码等。
  3. 启动Redis服务:

    • 在宝塔面板的服务菜单中找到Redis。
    • 点击Redis的启动按钮,启动Redis服务。
  4. 测试Redis:

    • 可以通过命令行或者宝塔的在线终端功能运行Redis客户端,测试是否可以连接到Redis服务。

以下是一个示例Redis配置参数(仅为示例,实际根据服务器配置和安全要求进行设置):




# 设置Redis运行的端口,默认为6379
port 6379
 
# 设置Redis监听的地址,默认为127.0.0.1
bind 127.0.0.1
 
# 设置Redis是否需要密码才能连接,如果要求安全,可以设置密码
requirepass your_redis_password
 
# 其他配置...

在宝塔面板中,这些步骤都是通过图形界面完成的,不需要手动编辑配置文件。如果需要手动编辑配置文件,可以通过宝塔的文件编辑器找到Redis的配置文件进行编辑。