Redis知识

要在 PHP 中使用 Redis 分布式,需要以下步骤:

安装 Redis 扩展

首先,需要安装 Redis 扩展。在 Ubuntu 或 Debian 系统中,可以使用以下命令进行安装:

1
2
sudo apt-get update
sudo apt-get install php-redis redis-server

连接 Redis 集群

使用 Redis 集群需要连接到多个 Redis 实例。可以使用 Redis 扩展提供的 RedisCluster 类来连接到 Redis 集群。可以在 PHP 代码中使用以下代码连接到 Redis 集群:

1
2
3
4
5
$redis = new RedisCluster(null, [
'redis://127.0.0.1:7000',
'redis://127.0.0.1:7001',
'redis://127.0.0.1:7002',
]);

在这里,我们传递了 Redis 实例的地址和端口号,这些信息是在启动 Redis 集群时配置的。RedisCluster 类会自动将数据分片到 Redis 集群中的不同节点。

使用 Redis 命令

一旦连接到 Redis 集群,就可以使用 Redis 命令来对数据进行操作。例如,可以使用以下代码在 Redis 集群中设置一个键值对:

1
$redis->set('mykey', 'myvalue');

要从 Redis 集群中获取值,请使用以下代码:

1
$value = $redis->get('mykey');

这些命令将自动将数据路由到 Redis 集群中的正确节点。

请注意,在使用 Redis 分布式时,需要考虑数据的一致性和可用性。如果一个 Redis 节点出现故障,需要确保集群中的其他节点可以处理数据并保持数据的一致性。

如何保持数据的一致性?

在 Redis 分布式环境中,保持数据的一致性是非常重要的,因为数据可能会分散在多个 Redis 节点上。以下是一些可以帮助保持数据一致性的建议:

使用 Redis 集群

Redis 集群使用数据分片的方式将数据存储在多个 Redis 节点上。当一个节点出现故障时,集群会自动将数据迁移到其他节点上。这种方式可以确保数据的可用性和一致性。

使用 Redis 哈希槽(Hash Slot)

Redis 哈希槽是一种将数据分片的方式,它将数据分成固定数量的哈希槽。每个 Redis 节点负责处理一部分哈希槽的数据。这种方式可以确保数据在节点之间的均衡分布,并且如果一个节点出现故障,只有它负责的哈希槽会受到影响。

使用 Redis 事务

Redis 事务可以确保一组命令在执行时是原子的,即它们要么全部执行成功,要么全部不执行。使用 Redis 事务可以确保多个命令同时执行,而不会中断或交叉执行,从而保证数据的一致性。

使用 Redis 锁

Redis 锁可以确保在给定的时间内只有一个客户端可以访问给定的数据。使用锁可以防止并发访问同一数据,从而确保数据的一致性。

使用 Redis 主从复制

Redis 主从复制可以确保在一个 Redis 主节点上进行的写操作会被复制到所有的从节点上。这种方式可以确保数据在所有节点之间的一致性,即使某些节点发生故障。

总之,保持数据的一致性需要考虑多个方面,包括数据分片、数据迁移、事务、锁和复制等。在使用 Redis 分布式时,需要根据实际情况选择适合的方法来确保数据的一致性。

redis 锁怎么使用

在 Redis 中使用锁可以避免并发访问同一资源导致的数据不一致问题。Redis 锁可以使用以下几种方式实现:

使用 SETNX 命令

SETNX 命令用于设置一个键值对,如果该键不存在,则设置成功。可以使用 SETNX 命令来实现锁的功能,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$lock_key = 'my_lock';
$lock_timeout = 10;

$lock = $redis->setnx($lock_key, 1);
if ($lock) {
// 获取锁成功,设置过期时间
$redis->expire($lock_key, $lock_timeout);
// 处理业务逻辑
// ...
// 释放锁
$redis->del($lock_key);
} else {
// 获取锁失败,等待一段时间后重试
usleep(10000);
// ...
}

在这里,首先使用 SETNX 命令尝试获取锁。如果 SETNX 返回 1,则表示获取锁成功,可以执行业务逻辑,然后使用 DEL 命令释放锁。如果 SETNX 返回 0,则表示获取锁失败,等待一段时间后重试。

使用 Redis Lua 脚本

Redis Lua 脚本可以在 Redis 服务器端执行,可以确保操作的原子性。可以使用 Redis Lua 脚本来实现锁的功能,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$lock_key = 'my_lock';
$lock_timeout = 10;

$script = "
if redis.call('setnx', KEYS[1], 1) == 1 then
redis.call('expire', KEYS[1], ARGV[1])
return 1
else
return 0
end
";

while (true) {
$result = $redis->eval($script, [$lock_key, $lock_timeout], 1);
if ($result) {
// 获取锁成功,处理业务逻辑
// ...
// 释放锁
$redis->del($lock_key);
break;
} else {
// 获取锁失败,等待一段时间后重试
usleep(10000);
// ...
}
}

在这里,使用 Redis Lua 脚本尝试获取锁。如果脚本返回 1,则表示获取锁成功,可以执行业务逻辑,然后使用 DEL 命令释放锁。如果脚本返回 0,则表示获取锁失败,等待一段时间后重试。

使用 Redis 锁需要注意以下几点:

确保锁的过期时间足够长,以免在执行业务逻辑时锁过期导致的并发问题。

在获取锁失败后,需要等待一段时间后重试,避免一直尝试获取锁导致 Redis 的性能问题。

在使用 SETNX 命令或 Redis Lua 脚本获取锁时,需要确

laravel 如何使用 redis 锁

在 Laravel 中使用 Redis 锁可以通过 Illuminate\Support\Facades\Redis facade 类来实现。

Laravel 的 Redis 锁使用了 predis/predis 包提供的 Predis\Client 类来连接 Redis 服务器。

以下是在 Laravel 中使用 Redis 锁的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
use Illuminate\Support\Facades\Redis;

$lockKey = 'my_lock';
$lockTimeout = 10;

$lock = Redis::set($lockKey, 1, 'NX', 'EX', $lockTimeout);
if ($lock) {
// 获取锁成功,设置过期时间
// 处理业务逻辑
// ...
// 释放锁
Redis::del($lockKey);
} else {
// 获取锁失败,等待一段时间后重试
usleep(10000);
// ...
}

在这里,首先使用 Redis::set() 方法尝试获取锁。如果 Redis::set() 方法返回 true,则表示获取锁成功,可以执行业务逻辑,然后使用 Redis::del() 方法释放锁。如果 Redis::set() 方法返回 false,则表示获取锁失败,等待一段时间后重试。

需要注意的是,在 Redis::set() 方法中,第三个参数 ‘NX’ 表示只有在键不存在时才设置键值对,第四个参数 ‘EX’ 表示设置键的过期时间为 $lockTimeout 秒。

Redis 缓存击穿

Redis 缓存击穿是指缓存中不存在的数据,而对这个数据的请求量很大,导致请求直接打到数据库上,从而造成数据库压力过

设置热点数据永远不过期

热点数据是指访问频率高的数据,可以将其缓存时间设置为永久有效。这样就能够保证即使缓存失效,Redis 也能够从数据库中获取数据并重新放入缓存中。

布隆过滤器

布隆过滤器可以用于快速判断某个数据是否存在于缓存中。如果布隆过滤器判断数据不存在于缓存中,则不会向数据库发出查询请求,从而减轻数据库的压力。如果布隆过滤器判断数据存在于缓存中,则直接返回缓存中的数据。

互斥锁

使用互斥锁可以保证同时只有一个线程去查询数据库,其他线程需要等待查询结果。如果在等待查询结果的过程中缓存中已经存在数据,那么等待的线程就可以直接从缓存中获取数据。

缓存预热

缓存预热是指在系统启动时,将一些常用的数据提前加载到缓存中,这样可以避免在用户请求到来时,缓存中没有数据,需要查询数据库的情况。缓存预热可以通过定时任务或者在系统启动时自动加载的方式实现。

数据库限流

在缓存击穿发生时,数据库会承受大量的请求,可能会导致数据库宕机。为了避免这种情况的发生,可以在数据库层面设置限流,限制每个 IP 的最大请求量,以减轻数据库的压力。

总之,解决 Redis 缓存击穿问题的方法是多种多样的,可以根据具体情况选择合适的方法。

缓存穿透

缓存穿透是指访问缓存中不存在的数据,而这些数据又不存在于数据库中,导致每次请求都会直接打到数据库上,从而造成数据库压力过大。
缓存穿透可能会因为缓存中不存在的数据被频繁请求而导致应用程序的性能下降甚至崩溃。常见的缓存穿透攻击是利用请求中的参数进行攻击,攻击者可以通过恶意构造参数,使得每个请求都不命中缓存,最终导致缓存穿透。

设置缓存空对象

如果查询到某个数据不存在于数据库中,可以将这个数据的缓存设置为空对象,这样在下一次请求时,就能够直接从缓存中获取数据,而不需要查询数据库。

布隆过滤器

布隆过滤器可以用于快速判断某个数据是否存在于缓存中,如果数据不存在于缓存中,则直接返回,不会向数据库发出查询请求。

缓存预热

缓存预热是指在系统启动时,将一些常用的数据提前加载到缓存中,这样可以避免在用户请求到来时,缓存中没有数据,需要查询数据库的情况。缓存预热可以通过定时任务或者在系统启动时自动加载的方式实现。

限制用户请求参数

可以对用户请求的参数进行限制,比如只接受数值类型的参数或者进行数据格式的校验。这样就能够避免攻击者通过恶意构造参数来攻击应用程序。

数据库层面的限流

在缓存穿透发生时,数据库会承受大量的请求,可能会导致数据库宕机。为了避免这种情况的发生,可以在数据库层面设置限流,限制每个 IP 的最大请求量,以减轻数据库的压力。

缓存雪崩

缓存雪崩是指在使用缓存系统时,由于缓存服务器或系统故障或重启等原因,导致缓存中的大量数据失效或者同时失效,导致大量请求直接访问数据库或后端系统,造成数据库或后端系统压力骤增,甚至导致系统崩溃的现象。

缓存雪崩的原因主要有以下几点:

缓存服务器宕机:当缓存服务器宕机时,所有的请求都将直接访问后端系统,导致后端系统压力骤增。

缓存数据过期:当缓存数据的过期时间相同或者相近,且在某一时刻都失效时,会导致大量的请求直接访问后端系统,导致系统压力骤增。

缓存数据集中在某个时间段访问:当某个热点数据集中在某个时间段访问时,会导致大量的请求直接访问后端系统,导致系统压力骤增。

设置合理的缓存过期时间

缓存过期时间应尽量分散,避免出现同时失效的情况,同时应考虑业务数据的实际情况来设置合理的过期时间。

加入缓存预热机制

在系统启动或低峰期,提前将数据加载到缓存中,避免高峰期缓存数据的集中失效。

分布式缓存集群

使用多个缓存服务器组成缓存集群,提高系统的可用性和容错性,避免单点故障。

限流降级

当缓存失效时,可以采用限流降级等机制,避免大量请求直接访问后端系统,导致系统压力骤增。

监控预警

对缓存系统进行监控,及时发现缓存失效或者异常情况,采取相应的应对措施,避免对系统造成影响。

布隆过滤器

布隆过滤器是一种快速判断一个元素是否存在于一个集合中的算法,它的原理是将每个元素通过多个哈希函数映射到一个位图中的多个位上,如果这些位都被设置为 1,则说明这个元素可能存在于集合中,如果任何一个位为 0,则说明这个元素一定不存在于集合中。布隆过滤器可能会出现误判,即判断某个元素存在于集合中,实际上这个元素并不存在于集合中,但误判的概率很小,可以通过适当增加哈希函数的个数和位图的大小来降低误判率。

创建

1
2
3
4
5
use Illuminate\Support\Facades\Redis;

// 创建名为 myfilter 的布隆过滤器,可以容纳 1000 个元素,误判率为 0.01
Redis::command('BF.RESERVE', ['myfilter', '0.01', '1000']);

添加元素

1
2
3
4
use Illuminate\Support\Facades\Redis;

// 向名为 myfilter 的布隆过滤器中添加元素 foo
Redis::command('BF.ADD', ['myfilter', 'foo']);

查询

1
2
3
4
5
6
7
8
9
10
use Illuminate\Support\Facades\Redis;

// 查询元素 foo 是否存在于名为 myfilter 的布隆过滤器中
$isExists = Redis::command('BF.EXISTS', ['myfilter', 'foo']);

if ($isExists) {
// 元素存在于布隆过滤器中
} else {
// 元素不存在于布隆过滤器中
}

删除

需要注意的是,删除布隆过滤器将会清空该过滤器中存储的所有元素,因此需要谨慎操作。

1
2
3
4
use Illuminate\Support\Facades\Redis;

// 删除名为 myfilter 的布隆过滤器
Redis::command('BF.DEL', ['myfilter']);

RDB 持久化

RDB 持久化是将 Redis 数据库快照存储到磁盘中。当执行 RDB 持久化时,Redis 将其数据写入一个快照文件中,快照文件是一个压缩过的二进制文件,包含了 Redis 数据库在某个时间点上的所有数据。快照文件可以用于在 Redis 重启时重新加载数据。

可以通过在 Redis 配置文件中设置 save 指令来配置 RDB 持久化,该指令可以设置 Redis 数据库在指定时间内发生了指定数量的修改,就自动执行一次快照操作。例如,以下配置表示如果 Redis 数据库在 900 秒内发生了至少 1 次修改,则自动执行一次快照操作:

1
save 900 1

AOF 持久化

AOF 持久化是将 Redis 执行的每个写命令记录到磁盘上。当 Redis 重启时,它会读取 AOF 文件中的所有写命令,并重新执行这些命令,从而重新构建数据库状态。AOF 文件是一个文本文件,可以通过查看文件内容来了解 Redis 的写操作历史记录。

可以通过在 Redis 配置文件中设置 appendonly 指令来启用 AOF 持久化。该指令可以设置 AOF 文件的存储方式,包括 appendfsync always、appendfsync everysec 和 appendfsync no 三种模式。例如,以下配置表示 Redis 每秒钟将 AOF 缓冲区中的所有写命令同步到磁盘上:

1
2
appendonly yes
appendfsync everysec

综合来说,RDB 持久化更适合用于数据量较大的 Redis 数据库,而 AOF 持久化更适合用于对数据持久化的要求较高的 Redis 数据库。可以根据实际需求来选择持久化方式。同时,还可以通过使用 AOF 和 RDB 持久化的组合方式,来提高 Redis 的数据可靠性和可用性。

哨兵

Redis 哨兵(Sentinel)是 Redis 的高可用性解决方案,它用于监控 Redis 实例的运行状态,并在 Redis 实例发生故障时自动进行故障转移,从而保证 Redis 的高可用性。

Redis 哨兵主要包括以下几个组件:

Sentinel 进程

Sentinel 进程是 Redis 哨兵的核心组件,用于监控 Redis 实例的运行状态,并在 Redis 实例发生故障时进行故障转移。

Redis 服务器集群

Redis 服务器集群由多个 Redis 实例组成,其中一个实例作为主节点,其他实例作为从节点。

配置文件

Redis 哨兵的配置文件包含了 Redis 实例和 Sentinel 进程的配置信息。

Redis 哨兵的工作流程如下

Sentinel 进程监控 Redis 实例的运行状态,包括主节点和从节点。

如果 Sentinel 进程发现主节点宕机,它会选择一个从节点作为新的主节点,然后将其他从节点切换到新的主节点上。

Sentinel 进程会将新的主节点信息广播给其他 Sentinel 进程,并要求它们也切换到新的主节点上。

当主节点重新启动并重新加入 Redis 集群时,Sentinel 进程会将其作为从节点添加到集群中,从而使其重新成为从节点。

Sentinel 进程还可以执行自动故障转移、客户端重定向和提供 Redis 集群的监控报告等功能。

在配置 Redis 哨兵时,需要指定 Sentinel 进程的配置文件、Redis 实例的地址和端口号等信息。配置完成后,可以通过运行 Sentinel 进程来启动 Redis 哨兵,Sentinel 进程会自动执行 Redis 实例的监控和故障转移等操作。

配置 Redis 哨兵

编辑配置文件:打开 Redis 的配置文件 redis.conf,在其中添加以下配置项
1
2
3
4
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 3000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000

这些配置项指定了要监控的 Redis 实例的名称、IP 地址和端口号,以及 Sentinel 进程在发现 Redis 实例宕机后执行故障转移的时间和方式等信息。

启动 Sentinel 进程:启动 Sentinel 进程需要指定配置文件的路径,例如:
1
redis-sentinel /path/to/sentinel.conf

运行该命令后,Sentinel 进程会根据配置文件的信息自动执行 Redis 实例的监控和故障转移等操作。

检查 Sentinel 进程状态:可以使用以下命令检查 Sentinel 进程的状态:
1
2
3
4
redis-cli -p 26379 sentinel master mymaster
redis-cli -p 26379 sentinel slaves mymaster
redis-cli -p 26379 sentinel get-master-addr-by-name mymaster

测试故障转移:为了测试 Sentinel 进程的故障转移功能,可以手动停止 Redis 实例的主节点,然后查看 Sentinel 进程是否能够自动执行故障转移并将从节点升级为主节点。


Redis知识
https://code-lives.github.io/2023/05/03/redis-doc/
作者
Li Jie
发布于
2023年5月3日
许可协议