1. Redis
Redis 是一个开源的, 先进的键-值存储库. 因其可存储 strings, hashes, lists, sets, 和 sorted sets, 又常常称为数据结构服务器.
Predis 是一个开源的PHP库. 相比phpredis, 虽然性能稍有劣式, 但贵在升级扩展都比较容易(redis还在快速发展中). 目前luckymall的redis类依赖于predis库进行开发,所以不要安装php的redis扩展. 如果想深度玩玩可直接参考Predis文档或Predis Wiki.
注意: redis服务, 需要3.0.x版本
注意: redis服务必须开启持久化存储,持久化策略请参考点击链接
注意: 目前不支持, PECL安装Redis的PHP扩展. 如果安装会因命名冲突, 导致系统问题
1.1. 配置
你的应用的 Redis 默认配置位于 config/redis.php 配置文件中。 在安装时会默认拷贝到 config/production/redis.php中.
例如:
return [
'connections' => [
'default' => [
'servers' => [
'redis://127.0.0.1:6379',
]
],
],
'scenes' => [
'queue' => [
'connection' => 'default',
],
],
];
1.1.1. 存储场景(scenes)
Redis的Cluster策略是根据Key值做一致性hash. 但问题在于不同场景下对于redis的使用频率是不同的, 根据实际业务场景, 单一场景都需要进行cluster. 因此在设计上将场景剥离出来, 不同场景指定自己的 Connection.
return [
//...
'scenes' => [
'queue' => [
'connection' => 'default',
],
],
//...
];
1.1.2. 连接资源(connections)
connections 定义了服务器组, 默认的服务器配置应该足以供开发使用. 你可以依照自己的环境自由地修改这个数组。简单地为每组服务器指定名称,主机地址以及所使用的端口.
return [
//...
'connections' => [
'default' => [
'servers' => [
redis://127.0.0.1:6379',
]
],
],
//...
];
连接参数同时支持[URI字符串]和命名数组两种方式:
return [
//...
'connections' => [
'default' => [
'servers' => [
'redis://username:password@127.0.0.1:6379/?database=0&timeout=5&alias=master',
['scheme' => 'tcp',
'host' => '127.0.0.1,
'port' => '6379',
'user' => 'username',
'password' => 'password',
'timeout' => 5,
'alias' => 'master',
'database' => 0],
]
],
],
//...
];
参数可参见:
alias
string
别名, 主要应用场景是在[Master slave模式](#master-slave)下
weight
权重, 当配置`cluster`配置为`predis`时, 会使用客户端的`一致性hash算法`进行分区. 权重在此时生效
database
string
指定数据库, 不指定时默认为0
persistent
bool
持续连接
read_write_timeout
string
传输的过期时间
timeout
string
连接过期时间
注意: 当系统安装时, 如果在单台机器安装多个BBC, 与mysql的database类似, 可以通过database参数指定不同的redis database.
每组服务器配置可以支持额外的options:
return [
//...
'connections' => [
'default' => [
'servers' => [
redis://127.0.0.1:6379',
'options' => [
'cluster' => 'redis'
]
],
],
//...
];
cluster: 选择用哪种集群方式, 目前支持predis和redis方式. 默认为predis方式, 使用客户端的一致性hash算法进行分区. redis方案依赖redis服务redis-cluster配置.
replication: 设置使用什么方式的主/从方案.
1.2. 长连接
Predis支持持久连接方案. 相关的参数有path, persistent, 同时需要设置options, 指定不同Schema对应的Connection. 目前持久连接方案默认只支持两种Connection, StreamConnection和CompositeStreamConnection, 其中CompositeStreamConnection主要是针对集群诉求.
return [
//...
'connections' => [
'default' => [
'servers' => [
redis://127.0.0.1:6379?path=a1&persistent=1',
'options' => [
'tcp' => 'Predis\Connection\StreamConnection',
'unix' => 'Predis\Connection\StreamConnection',
'redis' => 'Predis\Connection\StreamConnection',
]
],
],
//...
];
1.3. 合并连接(aggregate-connections)
Predis支持集群方案及主/从方案的连接. 默认情况下, 使用客户端的一致性hash算法进行分区, 也可使用Redis服务所提供的方式 redis-cluster.
在主/从方案中, Predis支持一主多从的形式,并且在读取操作时连接从机,写操作时连接到主机。
1.3.1. 主/从方案
客户端连接时可以进行主/从方案的配置. 配置好后, 当执行读取操作时会连接从机; 执行写操作时会连接主机. 实现读写分离.
下面是比较基础的主/从方案配置:
return [
//...
'connections' => [
'default' => [
'servers' => [
// 主节点的参数需要设定`alias=master`
'tcp://127.0.0.1:6379?alias=master',
'tcp://127.0.0.1:6380?alias=slave-01',
],
'options => [
'replication' => true,
],
],
],
//...
];
虽然 Predis 可以识别读/写操作,但 EVAL, EVALSHA 是两个特例。因为客户端不知道 LUA 脚本里是否有写操作,所以通常这两个操作是在 Master 上执行。
虽然这是个默认的行为,但有些 Lua 脚本里如果不包括写操作,客户端还是可能会在 slaves 上执行。可以通过配置来指定。
return [
//...
'connections' => [
'default' => [
'servers' => [
// 主节点的参数需要设定`alias=master`
'tcp://127.0.0.1:6379?alias=master',
'tcp://127.0.0.1:6380?alias=slave-01',
],
'options => [
'replication' => function () {
// 强制指定为 slave 上执行,不切换到 master
$strategy = new Predis\Replication\ReplicationStrategy();
$strategy -> setScriptReadOnly($LUA_SCRIPT);
return new Predis\Connection\Aggregate\MasterSlaveReplication($strategy);
}
],
],
],
//...
];
1.3.2. 集群方案
通过传递简单的和配置就可以实现集群功, 并且是在客户端的一致性hash算法进行分区. 但如果想使用 redis-cluster 功能(Redis 3.0 后的版本中可用). 可以如下配置:
return [
//...
'connections' => [
'default' => [
'servers' => [
'tcp://127.0.0.1:6379',
'tcp://127.0.0.1:6380',
],
'options => [
'cluster' => redis,
],
],
],
//...
];
当使用 redis-cluster 时,不用把集群中所有的节点都在参数中传递进去,只需要传少数几个就可以了。Predis 会自动从某一台服务器上获取所有服务器的哈希映射图。
注意: 目前 Predis 还不支持 redis-cluster 中的 主/从 结构
1.4. 基本用法
你可以通过redis facade调用许多方法来和redis交互. facade支持动态方法, 这意味着你可以通过facade调用任何 Redis命令 Redis命令中文版.
注意: 使用redis时, 必须制定场景(scene).
redis::scene($scene)->get($key);
当然, 正如上面所提及的, 你可在 redis facade 上使用任意 Redis 命令. luckymall 使用魔术方法来向Redis服务器传递命令, 因此也可以简单地为 Redis 命令传递参数:
$values = redis::lrange('names', 5, 10);
1.4.1. 管道命令
当你需要在一个操作中发送许多命令时,应该使用管道。pipeline 方法接受一个参数:一个接收 Redis 实例的 Closure (闭包)。你可向这个Redis实例发布所有的命令,它们会在单一操作中全被执行:
redis::scene($scene)->pipeline(function ($pipe) {
for ($i = 0; $i < 1000; $i++) {
$pipe->set("key:$i", $i);
}
});