使用AWS Elasticache Redis集群和Predis时需要注意的事项

这是关于Redis的随笔。最近我在接触它,如果有任何错误,请告诉我。

内容太长,不过只要一种选项

    1. 使用 AWS Elasticache 来构建 Redis 集群

 

    1. PHP 中有两个著名的 Redis 客户端实现

 

    1. 集群有一些注意事项

 

    1. 集群和数据库编号有限制

 

    1. 在集群中无法执行 SCAN 操作,感到困扰

 

    使用 Predis 时遇到 MOVED 1234 123.456.789:1111 Predis\Response\ServerException,感到困扰

亚马逊云计算(AWS)弹性缓存

在AWS Elasticache上创建Redis实例时,可以选择启用集群选项。

ElastiCache_Management_Console.png

如果不启用集群,则主要端点和领导者端点将被激活。

如果启用了集群,则会启用“设置终节点”。

从外观上看,主要的终点是数据库里的主节点,而读取终点类似于从节点。在写入和读取操作中使用不同的终点。

在这方面,设定终端是可以方便地进行读写操作的,因为服务器端已经进行了集群化设置,所以客户端无需特别关注。

PHP有两个Redis客户端的实现。

在处理Redis时,使用PHP的情况下,一般常见的选择是使用phpredis或Predis中的一种。

由于phpredis是一个用C实现的PHP扩展,因此可以期望它具有较快的速度。

在一方面,Predis是一个PHP的实现,所以速度可能不如本地代码,但它不需要安装扩展,因此更加便携。

Laravel 的 Redis 门面似乎默认使用 Predis 实现。但是,根据配置可以更改为 phpredis 实现。

集群的注意事项

我在聚类中遇到了困难。

如果要组成集群,与普通的独立实例(Standalone)相比,可能存在一些不同之处。

顺便说一下,这些是我在使用Predis时遇到的问题。

数据库编号

1 つ目は データベースを変更できない こと.

Redis はデータベース番号というものを持っていて,0〜15 の 16 個のデータベースを切り替えられる.

MySQL でいうとデータベースともいえそうだが,テーブルのほうが単位としては近いかもしれない.

で,クラスタを組むとデータベース番号を変更すること (SELECT) ができない.SELECT するとエラー (Predis だと例外) が出てしまい,クラスタモードだとデータベース指定ができないと言われてしまう.

未捕获的Predis\Connection\ConnectionException: SELECT操作失败: ERR SELECT在集群模式下不允许使用

因此,DB编号将被固定为0。

以下是一个例子:
参考:

Redis 集群不支持像独立版Redis那样的多个数据库。 只有一个数据库0,不允许使用SELECT命令。

Redis集群规范——https://redis.io/topics/cluster-spec#implemented-subset

扫描

这是一个可疑的问题,即使用某个条件来缩小范围并获取键值的 SCAN 功能无法使用。

不支持预设异常:无法在redis-cluster中使用“SCAN”

为什么会有疑问,因为在GUI客户端中,通常可以轻松地使用SCAN功能,无法使用SCAN功能实在是不方便且难以接受。

所以,有很大可能我的实现有问题。看来还需要再深入调查一下。

使用`scan`命令时,它仅适用于单个Redis节点。如果想在集群中使用该命令,首先获取集群中的节点列表,然后对每个节点运行`scan`命令。

在这个StackOverflow的帖子中,SCAN是针对一个节点的操作,因此需要扫描整个集群内的所有节点。

如果在服务器集群中没有人来照顾,那么是否需要获取节点列表呢……需要进行调查。

顺便提一下,Predis 的 Predis\ClientInterface 接口有一个 scan 方法,可以用该方法发出 SCAN 命令。但是,需要管理游标并循环遍历,所以在获取一定量的数据时使用迭代器会很方便(例如Predis\Collection\Iterator\KeySpace)。

→ 使用示例: https://github.com/nrk/predis/blob/v1.1.1/examples/redis_collections_iterators.php#L43-L47

当出现MOVED <端口号> <IP地址>:<端口> 的异常时

在操作时指定了集群的配置终端点,偶尔会出现 Predis\Response\ServerException 的异常,例如 MOVED 1234 123.456.789:1111。 “偶尔” 指的是每3次中有2次会出现错误,而1次成功是一种大致的频率。

总的来说,这是因为我在 Predis 的集群模式下错误地指定了连接地址。

通常情况下,当创建 Predis\Client 实例时,可以按照以下方式使用:

<?php 

use Predis\Client;

function provideClient(): Client 
{
    $parameters = [
        'host'     => '<エンドポイント>',
        'port'     => '<ポート番号>',
        'database' => 0,
    ];

    return new Client($parameters);
}

如果在独立模式下指定一个节点,则可以使用这个,但是如果在集群模式下连接,必须在构造函数的第二个参数中指定选项关联数组。

<?php 

use Predis\Client;

function provideClient(): Client 
{
    $parameters = [
        'host'     => '<エンドポイント>',
        'port'     => '<ポート番号>',
        'database' => 0,
    ];
    $options = [
        'cluster' => 'redis',
    ];

    return new Client($parameters, $options);
}

我原以为可以用这个来指定服务器端的集群,但事实证明这是不行的。

实际上,在集群的情况下,参数$parameters需要指定一个包含多个连接目标的数组。无论是AWS Elasticache的Redis集群还是服务器端的一个托管的端点。

<?php 

use Predis\Client;

function provideClient(): Client 
{
    $parameters = [
        [
            'host'     => '<エンドポイント>',
            'port'     => '<ポート番号>',
            'database' => 0,
        ]
    ];
    $options = [
        'cluster' => 'redis',
    ];

    return new Client($parameters, $options);
}

こうすることで,MOVED … もクライアント側で正しく処理されてエラーが出なくなった.

ちなみにこの原因には Laravel の Redis ファサードの実装を GitHub で確認して気づいた.Laravel さまさまである.

→ https://github.com/illuminate/redis/blob/5.1/Database.php#L31-L35

→ https://github.com/illuminate/redis/blob/5.1/Database.php的31-35行

广告
将在 10 秒后关闭
bannerAds