PHP `Redis Sentinel` / `Redis Cluster` 高可用与数据分片

各位朋友,大家好!我是你们的老朋友,今天咱们聊聊PHP玩转Redis Sentinel和Redis Cluster,让你的数据高可用又快如闪电!准备好了吗?咱们开始!

开场白:单身Redis的烦恼

话说,很久很久以前(其实也没多久),有个单身Redis,它孤零零地处理着所有的请求。一开始还好,访问量不大,它还能应付。但随着业务发展,访问量蹭蹭蹭地往上涨,单身Redis开始吃不消了,CPU爆满,内存告急,甚至偶尔还会罢工!这就好比一个人干十个人的活,不累死才怪!

这时候,我们就需要考虑Redis的高可用和数据分片方案了。 就像结婚生子,让Redis不再孤单,还能分担压力。

第一部分:Redis Sentinel——给Redis找个保镖

单身Redis容易出问题,那我们就给它找几个保镖,时刻盯着它,这就是Redis Sentinel。

1. 什么是Redis Sentinel?

Redis Sentinel是一个高可用解决方案,它主要负责以下三个任务:

  • 监控(Monitoring): Sentinel会不断地检查你的Redis master和slave是否正常运行。
  • 提醒(Notification): 当被监控的某个Redis实例出现问题时,Sentinel可以通过API向管理员或者其他应用程序发送通知。
  • 自动故障转移(Automatic failover): 当一个master不能正常工作时,Sentinel会开始自动故障转移过程,它会将一个slave提升为新的master,并且更新所有其他的slave使用新的master,同时通知应用程序新的master地址。

简单来说,Sentinel就是一群监工,时刻盯着Redis主节点,一旦发现主节点挂了,立刻选出一个备胎上位,保证服务不中断。

2. Sentinel的工作原理

Sentinel集群由多个Sentinel节点组成,它们之间通过Gossip协议进行通信。Sentinel节点会定期向Redis节点发送PING命令,以检测Redis节点的健康状态。

当Sentinel节点发现Redis主节点不可用时,会通过投票选举出一个新的主节点。选举过程遵循以下原则:

  • quorum(法定人数): 只有超过一半的Sentinel节点认为主节点不可用时,才会进行故障转移。
  • 优先级: Sentinel会优先选择优先级较高的slave节点作为新的主节点。
  • 复制偏移量: Sentinel会选择复制偏移量最大的slave节点作为新的主节点,以保证数据完整性。
  • 选举轮次: Sentinel会通过选举轮次来避免脑裂问题。

3. 配置Redis Sentinel

假设我们有三个Sentinel节点,一个Redis master节点和两个Redis slave节点。

  • redis.conf (master)
port 6379
protected-mode no
  • redis.conf (slave1)
port 6380
replicaof 127.0.0.1 6379
protected-mode no
  • redis.conf (slave2)
port 6381
replicaof 127.0.0.1 6379
protected-mode no
  • sentinel.conf (sentinel1)
port 26379
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
protected-mode no
  • sentinel.conf (sentinel2)
port 26380
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
protected-mode no
  • sentinel.conf (sentinel3)
port 26381
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
sentinel parallel-syncs mymaster 1
protected-mode no

配置解释:

  • sentinel monitor mymaster 127.0.0.1 6379 2: 监控名为mymaster的主节点,IP地址为127.0.0.1,端口为63792表示至少需要2个Sentinel节点同意主节点不可用才会进行故障转移。
  • sentinel down-after-milliseconds mymaster 5000: 主节点在5000毫秒内没有响应PING命令,Sentinel会认为主节点不可用。
  • sentinel failover-timeout mymaster 60000: 故障转移超时时间为60000毫秒。
  • sentinel parallel-syncs mymaster 1: 在故障转移后,最多允许1个slave节点同时同步数据。

4. PHP中使用Redis Sentinel

首先,你需要安装Predis库或者phpredis扩展。这里以Predis为例:

composer require predis/predis
<?php

require 'vendor/autoload.php';

use PredisClient;

// Sentinel节点地址
$sentinels = [
    ['host' => '127.0.0.1', 'port' => 26379],
    ['host' => '127.0.0.1', 'port' => 26380],
    ['host' => '127.0.0.1', 'port' => 26381],
];

// Redis master名称
$masterName = 'mymaster';

// 创建Redis Sentinel客户端
$client = new PredisClient([
    'scheme' => 'tcp',
    'host'   => $sentinels,
    'port'   => 26379, //随便一个 Sentinel 端口
    'options' => [
        'replication' => 'sentinel',
        'service' => $masterName,
    ],
]);

try {
    // 连接Redis
    $client->connect();

    // 设置键值对
    $client->set('foo', 'bar');

    // 获取键值对
    $value = $client->get('foo');

    echo "Value of foo: " . $value . PHP_EOL;

} catch (Exception $e) {
    echo "Error: " . $e->getMessage() . PHP_EOL;
} finally {
   // $client->disconnect(); // 别手动断开,Sentinel会帮你管理连接
}

代码解释:

  • $sentinels: Sentinel节点地址数组。
  • $masterName: Redis master名称。
  • 'replication' => 'sentinel': 告诉Predis使用Sentinel模式。
  • 'service' => $masterName: 指定要连接的Redis master名称。

注意: 在使用Sentinel模式时,不需要手动断开连接,Sentinel会自动管理连接。

5. Sentinel的优点和缺点

  • 优点:
    • 高可用性:当主节点挂了,Sentinel会自动进行故障转移。
    • 简单易用:配置简单,容易上手。
  • 缺点:
    • 仍然是单主节点:所有写操作都必须通过主节点,存在单点写入瓶颈。
    • 数据一致性:在故障转移期间,可能会存在数据丢失的风险。

第二部分:Redis Cluster——让Redis组成军团

Sentinel解决了高可用问题,但单主节点的写入瓶颈依然存在。这时候,我们需要Redis Cluster,让Redis组成一个军团,共同承担压力!

1. 什么是Redis Cluster?

Redis Cluster是一个分布式、高可用的Redis解决方案。它将数据分散存储在多个Redis节点上,每个节点负责一部分数据的读写操作。

Redis Cluster的核心特性:

  • 数据分片: 将数据分成多个片段,存储在不同的节点上。
  • 自动故障转移: 当某个节点挂了,Cluster会自动将该节点的数据迁移到其他节点上。
  • 可扩展性: 可以动态地添加或删除节点,从而实现水平扩展。

2. Redis Cluster的工作原理

Redis Cluster使用哈希槽(Hash Slot)来实现数据分片。它将整个数据集划分为16384个槽,每个节点负责一部分槽。

当客户端要读取或写入数据时,Redis会根据键的哈希值计算出对应的槽,然后将请求发送到负责该槽的节点。

哈希槽的计算公式:slot = CRC16(key) % 16384

3. 配置Redis Cluster

至少需要6个节点才能构成一个可用的Cluster,这里我们配置6个节点。

  • redis.conf (node1 – node6)
port 7000 # 7001, 7002, 7003, 7004, 7005
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 15000
appendonly yes
protected-mode no

配置解释:

  • cluster-enabled yes: 启用Cluster模式。
  • cluster-config-file nodes.conf: Cluster配置文件,记录节点信息。
  • cluster-node-timeout 15000: 节点超时时间为15000毫秒。
  • appendonly yes: 开启AOF持久化。

4. 创建Redis Cluster

启动所有Redis节点后,使用redis-cli工具创建Cluster。

redis-cli --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 --cluster-replicas 1

命令解释:

  • --cluster create: 创建Cluster。
  • --cluster-replicas 1: 每个主节点有一个从节点。

执行命令后,redis-cli会提示你输入yes确认创建Cluster。

5. PHP中使用Redis Cluster

同样,你需要安装Predis库或者phpredis扩展。这里以Predis为例:

composer require predis/predis
<?php

require 'vendor/autoload.php';

use PredisClient;

// Redis Cluster节点地址
$clusterNodes = [
    ['host' => '127.0.0.1', 'port' => 7000],
    ['host' => '127.0.0.1', 'port' => 7001],
    ['host' => '127.0.0.1', 'port' => 7002],
    ['host' => '127.0.0.1', 'port' => 7003],
    ['host' => '127.0.0.1', 'port' => 7004],
    ['host' => '127.0.0.1', 'port' => 7005],
];

// 创建Redis Cluster客户端
$client = new PredisClient($clusterNodes, ['cluster' => 'redis']);

try {
    // 连接Redis Cluster
    $client->connect();

    // 设置键值对
    $client->set('foo', 'bar');

    // 获取键值对
    $value = $client->get('foo');

    echo "Value of foo: " . $value . PHP_EOL;

    // 使用哈希标签
    $client->set('{user:1000}:name', 'John');
    $client->set('{user:1000}:age', 30);

    echo "Name: " . $client->get('{user:1000}:name') . PHP_EOL;
    echo "Age: " . $client->get('{user:1000}:age') . PHP_EOL;

} catch (Exception $e) {
    echo "Error: " . $e->getMessage() . PHP_EOL;
} finally {
    $client->disconnect();
}

代码解释:

  • $clusterNodes: Redis Cluster节点地址数组。
  • ['cluster' => 'redis']: 告诉Predis使用Cluster模式。
  • 哈希标签(Hash Tag): 使用{}包裹键的一部分,可以保证具有相同哈希标签的键会被分配到同一个槽,从而存储在同一个节点上。例如,{user:1000}:name{user:1000}:age都会被分配到同一个节点,方便进行原子操作。

6. Redis Cluster的优点和缺点

  • 优点:
    • 高可用性:当某个节点挂了,Cluster会自动进行故障转移。
    • 可扩展性:可以动态地添加或删除节点,从而实现水平扩展。
    • 高性能:数据分散存储在多个节点上,可以并发处理请求。
  • 缺点:
    • 配置复杂:配置和管理比Sentinel复杂。
    • 数据一致性:在故障转移期间,可能会存在数据丢失的风险。
    • 不支持多键操作:不支持跨槽的多键操作,例如MGETMSET

第三部分:Sentinel vs Cluster:选哪个?

选择Sentinel还是Cluster,取决于你的业务需求:

特性 Redis Sentinel Redis Cluster
高可用性 支持 支持
可扩展性 不支持水平扩展 支持水平扩展
性能 单主节点写入,存在瓶颈 多节点并发处理,性能更好
配置复杂度 简单 复杂
数据一致性 存在数据丢失风险 存在数据丢失风险
适用场景 数据量不大,对性能要求不高,配置简单的场景 数据量大,对性能要求高,需要水平扩展的场景
多键操作 支持 不支持跨槽的多键操作

总结:

  • 如果你的数据量不大,对性能要求不高,只需要简单的高可用方案,那么Sentinel是一个不错的选择。
  • 如果你的数据量很大,对性能要求很高,需要水平扩展,那么Cluster是更好的选择。

第四部分:最佳实践

  • 监控: 无论使用Sentinel还是Cluster,都需要进行监控,及时发现和解决问题。
  • 持久化: 开启AOF持久化,防止数据丢失。
  • 备份: 定期备份数据,以防万一。
  • 合理选择数据分片策略: 根据业务需求选择合适的数据分片策略,例如使用哈希标签。
  • 避免大键: 尽量避免存储过大的键值对,以免影响性能。
  • 了解你的数据: 了解你的数据访问模式,根据访问模式选择合适的Redis配置。

结束语:祝你玩转Redis!

好了,今天的分享就到这里。希望通过今天的讲解,大家能够对Redis Sentinel和Redis Cluster有一个更深入的了解,并能够根据自己的业务需求选择合适的方案。记住,技术是为业务服务的,选择最适合自己的才是最好的!

祝大家都能玩转Redis,让你的数据飞起来!谢谢大家!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注