按 Enter 键跳转到正文

Redis分布式

Redis分布式

一、 Redis分布式概述

1. 什么是Redis分布式

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

1.2 为什么需要Redis分布式

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

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

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

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

1.3 Redis分布式方案对比

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

二、 Redis分布式方案搭建

2.1 主从复制搭建

配置文件示例

主节点 (master.conf):

1port 6379
2daemonize yes
3pidfile /var/run/redis_6379.pid
4logfile "/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

启动命令

1# 启动主节点
2redis-server master.conf
3
4# 启动从节点
5redis-server slave.conf

2.2 Redis Sentinel搭建

Sentinel配置文件

sentinel.conf:

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

启动Sentinel

1redis-sentinel sentinel.conf

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

集群节点配置

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

node-7000.conf如:

1port 7000
2cluster-enabled yes
3cluster-config-file nodes-7000.conf
4cluster-node-timeout 5000
5appendonly yes

启动集群节点

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

创建集群

1redis-cli --cluster create \
2127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 \
3127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 \
4--cluster-replicas 1

三、 Redis分布式应用场景

3.1 会话存储(Session Storage)

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

3.2 缓存集群

  • 热点数据分布式缓存

  • 缓存击穿防护

  • 多级缓存架构

3.3 分布式锁

 1class RedisDistributedLock {
 2    private $redis;
 3    
 4    public function __construct($redis) {
 5        $this->redis = $redis;
 6    }
 7    
 8    public function lock($key, $timeout = 10) {
 9        $identifier = uniqid();
10        $end = time() + $timeout;
11        
12        while (time() < $end) {
13            if ($this->redis->set($key, $identifier, ['NX', 'EX' => $timeout])) {
14                return $identifier;
15            }
16            usleep(100000); // 100ms
17        }
18        return false;
19    }
20    
21    public function unlock($key, $identifier) {
22        $script = "
23            if redis.call('get', KEYS[1]) == ARGV[1] then
24                return redis.call('del', KEYS[1])
25            else
26                return 0
27            end
28        ";
29        return $this->redis->eval($script, [$key, $identifier], 1);
30    }
31}

3.4 消息队列

 1// 分布式消息队列
 2class RedisMessageQueue {
 3    private $redis;
 4    private $queueName;
 5    
 6    public function __construct($redis, $queueName) {
 7        $this->redis = $redis;
 8        $this->queueName = $queueName;
 9    }
10    
11    public function push($message) {
12        return $this->redis->lpush($this->queueName, json_encode($message));
13    }
14    
15    public function pop($timeout = 0) {
16        $result = $this->redis->brpop($this->queueName, $timeout);
17        return $result ? json_decode($result[1], true) : null;
18    }
19}

四、PHP中的Redis分布式应用

4.1 安装Redis扩展

1# 安装PHP Redis扩展
2pecl install redis

4.2连接Redis Cluster

 1<?php
 2class RedisClusterManager {
 3    private $cluster;
 4    
 5    public function __construct($nodes) {
 6        $this->cluster = new RedisCluster(null, $nodes);
 7    }
 8    
 9    public function set($key, $value, $ttl = null) {
10        return $ttl ? 
11            $this->cluster->setex($key, $ttl, $value) : 
12            $this->cluster->set($key, $value);
13    }
14    
15    public function get($key) {
16        return $this->cluster->get($key);
17    }
18    
19    public function mget($keys) {
20        return $this->cluster->mget($keys);
21    }
22}
23
24// 使用示例
25$nodes = [
26    '127.0.0.1:7000',
27    '127.0.0.1:7001', 
28    '127.0.0.1:7002'
29];
30
31$redisCluster = new RedisClusterManager($nodes);
32$redisCluster->set('user:1001', json_encode(['name' => 'John', 'age' => 25]));

4.3 分布式ID生成器

 1class DistributedIdGenerator {
 2    private $redis;
 3    private $key;
 4    
 5    public function __construct($redis, $key = 'distributed:id') {
 6        $this->redis = $redis;
 7        $this->key = $key;
 8    }
 9    
10    public function generate($step = 1) {
11        return $this->redis->incrby($this->key, $step);
12    }
13    
14    public function generateWithTimestamp($prefix = '') {
15        $timestamp = (int)(microtime(true) * 1000);
16        $sequence = $this->redis->incr($this->key . ':seq');
17        return $prefix . $timestamp . str_pad($sequence % 1000, 3, '0', STR_PAD_LEFT);
18    }
19}

4.4 分布式计数器

 1class DistributedCounter {
 2    private $redis;
 3    
 4    public function __construct($redis) {
 5        $this->redis = $redis;
 6    }
 7    
 8    public function increment($key, $value = 1, $ttl = 3600) {
 9        $script = "
10            local current = redis.call('incrby', KEYS[1], ARGV[1])
11            if current == tonumber(ARGV[1]) then
12                redis.call('expire', KEYS[1], ARGV[2])
13            end
14            return current
15        ";
16        return $this->redis->eval($script, [$key, $value, $ttl], 1);
17    }
18    
19    public function get($key) {
20        return $this->redis->get($key) ?: 0;
21    }
22}

4.5 分布式限流器

 1class DistributedRateLimiter {
 2    private $redis;
 3    
 4    public function __construct($redis) {
 5        $this->redis = $redis;
 6    }
 7    
 8    public function isAllowed($key, $limit, $window) {
 9        $script = "
10            local key = KEYS[1]
11            local limit = tonumber(ARGV[1])
12            local window = tonumber(ARGV[2])
13            local current = redis.call('GET', key) or 0
14            
15            if tonumber(current) >= limit then
16                return 0
17            else
18                redis.call('INCR', key)
19                if tonumber(current) == 0 then
20                    redis.call('EXPIRE', key, window)
21                end
22                return 1
23            end
24        ";
25        
26        return (bool)$this->redis->eval($script, [$key, $limit, $window], 1);
27    }
28}

发表评论