Redis分布式

一、 Redis分布式概述

1. 什么是Redis分布式

Redis分布式是指将Redis数据分布到多个Redis节点上,通过集群方式提供更高性能、更大容量和更好可用性的解决方案。

1.2 为什么需要Redis分布式

  • 数据量增长:单机内存容量有限

  • 高并发需求:单机性能瓶颈

  • 高可用性:避免单点故障

  • 可扩展性:支持业务动态扩容

1.3 Redis分布式方案对比

方案优点缺点使用场景
主从复制部署简单,读写分离写操作单点,故障需手动切换读多写少,数据备份
Redis Sentinel自动故障转移,高可用配置复杂,扩容不便生产环境高可用
Redis Cluster数据分片,自动故障转移客户端兼容性要求,迁移复杂大数据量,高并发

二、 Redis分布式方案搭建

2.1 主从复制搭建

配置文件示例

主节点 (master.conf):

port 6379
daemonize yes
pidfile /var/run/redis_6379.pid
logfile "/var/log/redis_6379.log"

从节点 (slave.conf):

port 6380
daemonize yes
pidfile /var/run/redis_6380.pid
logfile "/var/log/redis_6380.log"
slaveof 127.0.0.1 6379

启动命令

# 启动主节点
redis-server master.conf

# 启动从节点
redis-server slave.conf

2.2 Redis Sentinel搭建

Sentinel配置文件

sentinel.conf:

port 26379
daemonize yes
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 15000

启动Sentinel

redis-sentinel sentinel.conf

2.3 Redis Cluster搭建 ( 企业级推荐方案首选)

集群节点配置

创建6个节点配置文件(3主3从),端口7000 7001 7002 7003 7004 7005:

node-7000.conf如:

port 7000
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-node-timeout 5000
appendonly yes

启动集群节点

for port in 7000 7001 7002 7003 7004 7005; do
    redis-server node-${port}.conf &
done

创建集群

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

三、 Redis分布式应用场景

3.1 会话存储(Session Storage)

// 分布式Session存储
$sessionHandler = new RedisSessionHandler($redisCluster);
session_set_save_handler($sessionHandler, true);
session_start();

3.2 缓存集群

  • 热点数据分布式缓存

  • 缓存击穿防护

  • 多级缓存架构

3.3 分布式锁

class RedisDistributedLock {
    private $redis;
    
    public function __construct($redis) {
        $this->redis = $redis;
    }
    
    public function lock($key, $timeout = 10) {
        $identifier = uniqid();
        $end = time() + $timeout;
        
        while (time() < $end) {
            if ($this->redis->set($key, $identifier, ['NX', 'EX' => $timeout])) {
                return $identifier;
            }
            usleep(100000); // 100ms
        }
        return false;
    }
    
    public function unlock($key, $identifier) {
        $script = "
            if redis.call('get', KEYS[1]) == ARGV[1] then
                return redis.call('del', KEYS[1])
            else
                return 0
            end
        ";
        return $this->redis->eval($script, [$key, $identifier], 1);
    }
}

3.4 消息队列

// 分布式消息队列
class RedisMessageQueue {
    private $redis;
    private $queueName;
    
    public function __construct($redis, $queueName) {
        $this->redis = $redis;
        $this->queueName = $queueName;
    }
    
    public function push($message) {
        return $this->redis->lpush($this->queueName, json_encode($message));
    }
    
    public function pop($timeout = 0) {
        $result = $this->redis->brpop($this->queueName, $timeout);
        return $result ? json_decode($result[1], true) : null;
    }
}

四、PHP中的Redis分布式应用

4.1 安装Redis扩展

# 安装PHP Redis扩展
pecl install redis

4.2连接Redis Cluster

<?php
class RedisClusterManager {
    private $cluster;
    
    public function __construct($nodes) {
        $this->cluster = new RedisCluster(null, $nodes);
    }
    
    public function set($key, $value, $ttl = null) {
        return $ttl ? 
            $this->cluster->setex($key, $ttl, $value) : 
            $this->cluster->set($key, $value);
    }
    
    public function get($key) {
        return $this->cluster->get($key);
    }
    
    public function mget($keys) {
        return $this->cluster->mget($keys);
    }
}

// 使用示例
$nodes = [
    '127.0.0.1:7000',
    '127.0.0.1:7001', 
    '127.0.0.1:7002'
];

$redisCluster = new RedisClusterManager($nodes);
$redisCluster->set('user:1001', json_encode(['name' => 'John', 'age' => 25]));

4.3 分布式ID生成器

class DistributedIdGenerator {
    private $redis;
    private $key;
    
    public function __construct($redis, $key = 'distributed:id') {
        $this->redis = $redis;
        $this->key = $key;
    }
    
    public function generate($step = 1) {
        return $this->redis->incrby($this->key, $step);
    }
    
    public function generateWithTimestamp($prefix = '') {
        $timestamp = (int)(microtime(true) * 1000);
        $sequence = $this->redis->incr($this->key . ':seq');
        return $prefix . $timestamp . str_pad($sequence % 1000, 3, '0', STR_PAD_LEFT);
    }
}

4.4 分布式计数器

class DistributedCounter {
    private $redis;
    
    public function __construct($redis) {
        $this->redis = $redis;
    }
    
    public function increment($key, $value = 1, $ttl = 3600) {
        $script = "
            local current = redis.call('incrby', KEYS[1], ARGV[1])
            if current == tonumber(ARGV[1]) then
                redis.call('expire', KEYS[1], ARGV[2])
            end
            return current
        ";
        return $this->redis->eval($script, [$key, $value, $ttl], 1);
    }
    
    public function get($key) {
        return $this->redis->get($key) ?: 0;
    }
}

4.5 分布式限流器

class DistributedRateLimiter {
    private $redis;
    
    public function __construct($redis) {
        $this->redis = $redis;
    }
    
    public function isAllowed($key, $limit, $window) {
        $script = "
            local key = KEYS[1]
            local limit = tonumber(ARGV[1])
            local window = tonumber(ARGV[2])
            local current = redis.call('GET', key) or 0
            
            if tonumber(current) >= limit then
                return 0
            else
                redis.call('INCR', key)
                if tonumber(current) == 0 then
                    redis.call('EXPIRE', key, window)
                end
                return 1
            end
        ";
        
        return (bool)$this->redis->eval($script, [$key, $limit, $window], 1);
    }
}